diff options
351 files changed, 11244 insertions, 6156 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d8adf6c396f..514896161a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -648,8 +648,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") unset(_asan_defaults) if(MSVC) - find_library( - COMPILER_ASAN_LIBRARY NAMES clang_rt.asan-x86_64 + find_library( + COMPILER_ASAN_LIBRARY NAMES clang_rt.asan-x86_64 PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/7.0.0/lib/windows [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\LLVM\\LLVM;]/lib/clang/6.0.0/lib/windows @@ -828,7 +828,7 @@ endif() set_and_warn_dependency(WITH_PUGIXML WITH_OPENIMAGEIO OFF) if(WITH_BOOST AND NOT (WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_INTERNATIONAL OR - WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_USD OR WITH_ALEMBIC)) + WITH_OPENVDB OR WITH_OPENCOLORIO OR WITH_USD OR WITH_ALEMBIC)) message(STATUS "No dependencies need 'WITH_BOOST' forcing WITH_BOOST=OFF") set(WITH_BOOST OFF) endif() @@ -1632,6 +1632,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") "/we4013" # 'function' undefined; assuming extern returning int "/we4133" # incompatible pointer types "/we4431" # missing type specifier - int assumed + "/we4033" # 'function' must return a value ) string(REPLACE ";" " " _WARNINGS "${_WARNINGS}") diff --git a/build_files/build_environment/cmake/dpcpp.cmake b/build_files/build_environment/cmake/dpcpp.cmake index 3c3fe201073..dbba97b8264 100644 --- a/build_files/build_environment/cmake/dpcpp.cmake +++ b/build_files/build_environment/cmake/dpcpp.cmake @@ -68,7 +68,7 @@ set(DPCPP_EXTRA_ARGS ) if(WIN32) - list(APPEND DPCPP_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER) + list(APPEND DPCPP_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER) endif() ExternalProject_Add(external_dpcpp diff --git a/build_files/cmake/Modules/FindSYCL.cmake b/build_files/cmake/Modules/FindSYCL.cmake index ac90cbfbe43..7aead43dd2a 100644 --- a/build_files/cmake/Modules/FindSYCL.cmake +++ b/build_files/cmake/Modules/FindSYCL.cmake @@ -44,7 +44,7 @@ FIND_PROGRAM(SYCL_COMPILER # compiler. if(NOT SYCL_COMPILER) FIND_PROGRAM(SYCL_COMPILER - NAMES + NAMES dpcpp HINTS ${_sycl_search_dirs} diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 27fcaf823e8..04fa1561f88 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -30,16 +30,12 @@ macro(add_bundled_libraries library) list(APPEND PLATFORM_BUNDLED_LIBRARY_DIRS ${_library_dir}) unset(_all_library_versions) unset(_library_dir) - endif() + endif() endmacro() # ------------------------------------------------------------------------ # Find system provided libraries. -# Avoid searching for headers since this would otherwise override our lib -# directory as well as PYTHON_ROOT_DIR. -set(CMAKE_FIND_FRAMEWORK NEVER) - # Find system ZLIB, not the pre-compiled one supplied with OpenCollada. set(ZLIB_ROOT /usr) find_package(ZLIB REQUIRED) @@ -79,6 +75,10 @@ if(NOT EXISTS "${LIBDIR}/") message(FATAL_ERROR "Mac OSX requires pre-compiled libs at: '${LIBDIR}'") endif() +# Avoid searching for headers since this would otherwise override our lib +# directory as well as PYTHON_ROOT_DIR. +set(CMAKE_FIND_FRAMEWORK NEVER) + # Optionally use system Python if PYTHON_ROOT_DIR is specified. if(WITH_PYTHON AND (WITH_PYTHON_MODULE AND PYTHON_ROOT_DIR)) find_package(PythonLibsUnix REQUIRED) @@ -324,7 +324,7 @@ if(WITH_LLVM) if(WITH_CLANG) find_package(Clang) if(NOT CLANG_FOUND) - message(FATAL_ERROR "Clang not found.") + message(FATAL_ERROR "Clang not found.") endif() endif() diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 6ad4547fa00..47410b5f368 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -89,7 +89,7 @@ macro(add_bundled_libraries library) file(GLOB _all_library_versions ${LIBDIR}/${library}/lib/*\.so*) list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_all_library_versions}) unset(_all_library_versions) - endif() + endif() endmacro() # ---------------------------------------------------------------------------- diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 666b0077a72..ceb024ba5e7 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -7,6 +7,7 @@ set(INC ../../mikktspace ../../../source/blender/makesdna ../../../source/blender/makesrna + ../../../source/blender/blenkernel ../../../source/blender/blenlib ../../../source/blender/gpu ../../../source/blender/render diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp index 109408c354d..8a3c1136104 100644 --- a/intern/cycles/blender/object.cpp +++ b/intern/cycles/blender/object.cpp @@ -23,6 +23,8 @@ #include "util/log.h" #include "util/task.h" +#include "BKE_duplilist.h" + CCL_NAMESPACE_BEGIN /* Utilities */ @@ -353,79 +355,26 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, return object; } -/* This function mirrors drw_uniform_property_lookup in draw_instance_data.cpp */ -static bool lookup_property(BL::ID b_id, const string &name, float4 *r_value) -{ - PointerRNA ptr; - PropertyRNA *prop; - - if (!RNA_path_resolve(&b_id.ptr, name.c_str(), &ptr, &prop)) { - return false; - } - - if (prop == NULL) { - return false; - } +extern "C" DupliObject *rna_hack_DepsgraphObjectInstance_dupli_object_get(PointerRNA *ptr); - PropertyType type = RNA_property_type(prop); - int arraylen = RNA_property_array_length(&ptr, prop); - - if (arraylen == 0) { - float value; - - if (type == PROP_FLOAT) - value = RNA_property_float_get(&ptr, prop); - else if (type == PROP_INT) - value = static_cast<float>(RNA_property_int_get(&ptr, prop)); - else - return false; - - *r_value = make_float4(value, value, value, 1.0f); - return true; - } - else if (type == PROP_FLOAT && arraylen <= 4) { - *r_value = make_float4(0.0f, 0.0f, 0.0f, 1.0f); - RNA_property_float_get_array(&ptr, prop, &r_value->x); - return true; - } - - return false; -} - -/* This function mirrors drw_uniform_attribute_lookup in draw_instance_data.cpp */ static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance, const string &name, bool use_instancer) { - string idprop_name = string_printf("[\"%s\"]", name.c_str()); - float4 value; + ::Object *ob = (::Object *)b_instance.object().ptr.data; + ::DupliObject *dupli = nullptr; + ::Object *dupli_parent = nullptr; /* If requesting instance data, check the parent particle system and object. */ if (use_instancer && b_instance.is_instance()) { - BL::ParticleSystem b_psys = b_instance.particle_system(); - - if (b_psys) { - if (lookup_property(b_psys.settings(), idprop_name, &value) || - lookup_property(b_psys.settings(), name, &value)) { - return value; - } - } - if (lookup_property(b_instance.parent(), idprop_name, &value) || - lookup_property(b_instance.parent(), name, &value)) { - return value; - } + dupli = rna_hack_DepsgraphObjectInstance_dupli_object_get(&b_instance.ptr); + dupli_parent = (::Object *)b_instance.parent().ptr.data; } - /* Check the object and mesh. */ - BL::Object b_ob = b_instance.object(); - BL::ID b_data = b_ob.data(); - - if (lookup_property(b_ob, idprop_name, &value) || lookup_property(b_ob, name, &value) || - lookup_property(b_data, idprop_name, &value) || lookup_property(b_data, name, &value)) { - return value; - } + float4 value; + BKE_object_dupli_find_rgba_attribute(ob, dupli, dupli_parent, name.c_str(), &value.x); - return zero_float4(); + return value; } bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object) diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index 184bf7d6ae3..ac508e36965 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -545,7 +545,7 @@ endif() if(CYCLES_STANDALONE_REPOSITORY) if((WITH_CYCLES_STANDALONE AND WITH_CYCLES_STANDALONE_GUI) OR - WITH_CYCLES_HYDRA_RENDER_DELEGATE) + WITH_CYCLES_HYDRA_RENDER_DELEGATE) if(MSVC AND EXISTS ${_cycles_lib_dir}) set(Epoxy_LIBRARIES "${_cycles_lib_dir}/epoxy/lib/epoxy.lib") set(Epoxy_INCLUDE_DIRS "${_cycles_lib_dir}/epoxy/include") diff --git a/intern/cycles/util/math_fast.h b/intern/cycles/util/math_fast.h index 142a664a1d2..fc7eadb112b 100644 --- a/intern/cycles/util/math_fast.h +++ b/intern/cycles/util/math_fast.h @@ -589,7 +589,7 @@ ccl_device_inline float fast_erfcf(float x) ccl_device_inline float fast_ierff(float x) { /* From: Approximating the `erfinv` function by Mike Giles. */ - /* To avoid trouble at the limit, clamp input to 1-eps. */ + /* To avoid trouble at the limit, clamp input to 1-epsilon. */ float a = fabsf(x); if (a > 0.99999994f) { a = 0.99999994f; diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index 33376d36a92..572be30174d 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -14,7 +14,7 @@ #include "../GHOST_Types.h" #include "GHOST_System.h" -// For tablets +/* For tablets. */ #ifdef WITH_X11_XINPUT # include <X11/extensions/XInput.h> diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 200d47e9c61..8d8ce3643f4 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -25,18 +25,18 @@ #include "GHOST_ContextEGL.h" #include "GHOST_ContextGLX.h" -/* for XIWarpPointer */ +/* For #XIWarpPointer. */ #ifdef WITH_X11_XINPUT # include <X11/extensions/XInput2.h> #endif -// For DPI value +/* For DPI value. */ #include <X11/Xresource.h> #include <cstdio> #include <cstring> -/* gethostname */ +/* For `gethostname`. */ #include <unistd.h> #include <algorithm> diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 01af0b5ac86..e9bee43c035 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -11,7 +11,7 @@ #include "GHOST_Window.h" #include <X11/Xlib.h> #include <X11/Xutil.h> -// For tablets +/* For tablets. */ #ifdef WITH_X11_XINPUT # include <X11/extensions/XInput.h> #endif diff --git a/intern/ghost/intern/GHOST_XrControllerModel.cpp b/intern/ghost/intern/GHOST_XrControllerModel.cpp index c841fc0cf46..0a8b0dcb003 100644 --- a/intern/ghost/intern/GHOST_XrControllerModel.cpp +++ b/intern/ghost/intern/GHOST_XrControllerModel.cpp @@ -296,7 +296,7 @@ static void load_node(const tinygltf::Model &gltf_model, float world_transform[4][4]; GHOST_XrControllerModelNode &node = nodes.emplace_back(); - const int32_t node_idx = (int32_t)(nodes.size() - 1); + const int32_t node_idx = int32_t(nodes.size() - 1); node.parent_idx = parent_idx; calc_node_transforms(gltf_node, parent_transform, node.local_transform, world_transform); @@ -496,7 +496,7 @@ void GHOST_XrControllerModel::loadControllerModel(XrSession session) std::vector<XrControllerModelNodePropertiesMSFT> node_properties( model_properties.nodeCountOutput, {XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT}); - model_properties.nodeCapacityInput = (uint32_t)node_properties.size(); + model_properties.nodeCapacityInput = uint32_t(node_properties.size()); model_properties.nodeProperties = node_properties.data(); CHECK_XR(g_xrGetControllerModelPropertiesMSFT(session, m_model_key, &model_properties), "Failed to get controller model node properties."); @@ -583,11 +583,11 @@ void GHOST_XrControllerModel::updateComponents(XrSession session) void GHOST_XrControllerModel::getData(GHOST_XrControllerModelData &r_data) { if (m_data_loaded) { - r_data.count_vertices = (uint32_t)m_vertices.size(); + r_data.count_vertices = uint32_t(m_vertices.size()); r_data.vertices = m_vertices.data(); - r_data.count_indices = (uint32_t)m_indices.size(); + r_data.count_indices = uint32_t(m_indices.size()); r_data.indices = m_indices.data(); - r_data.count_components = (uint32_t)m_components.size(); + r_data.count_components = uint32_t(m_components.size()); r_data.components = m_components.data(); } else { diff --git a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp index 6a7eb25925a..d387b222538 100644 --- a/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp +++ b/intern/ghost/intern/GHOST_XrGraphicsBinding.cpp @@ -85,7 +85,7 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding { XrGraphicsRequirementsOpenGLKHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR}; const XrVersion gl_version = XR_MAKE_VERSION(gl_major_version, gl_minor_version, 0); - /* Although it would seem reasonable that the proc address would not change if the instance was + /* Although it would seem reasonable that the PROC address would not change if the instance was * the same, in testing, repeated calls to #xrGetInstanceProcAddress() with the same instance * can still result in changes so the workaround is to simply set the function pointer every * time (trivializing its 'static' designation). */ @@ -343,7 +343,7 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding { // static XrInstance s_instance = XR_NULL_HANDLE; XrGraphicsRequirementsD3D11KHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR}; - /* Although it would seem reasonable that the proc address would not change if the instance was + /* Although it would seem reasonable that the PROC address would not change if the instance was * the same, in testing, repeated calls to #xrGetInstanceProcAddress() with the same instance * can still result in changes so the workaround is to simply set the function pointer every * time (trivializing its 'static' designation). */ diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp index 0031c1f1278..e8f9b96b15c 100644 --- a/intern/ghost/intern/GHOST_XrSession.cpp +++ b/intern/ghost/intern/GHOST_XrSession.cpp @@ -745,7 +745,7 @@ bool GHOST_XrSession::attachActionSets() for (auto &[profile, bindings] : profile_bindings) { bindings_info.interactionProfile = profile; - bindings_info.countSuggestedBindings = (uint32_t)bindings.size(); + bindings_info.countSuggestedBindings = uint32_t(bindings.size()); bindings_info.suggestedBindings = bindings.data(); CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info), @@ -754,7 +754,7 @@ bool GHOST_XrSession::attachActionSets() /* Attach action sets. */ XrSessionActionSetsAttachInfo attach_info{XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO}; - attach_info.countActionSets = (uint32_t)m_oxr->action_sets.size(); + attach_info.countActionSets = uint32_t(m_oxr->action_sets.size()); /* Create an aligned copy of the action sets to pass to xrAttachSessionActionSets(). */ std::vector<XrActionSet> action_sets(attach_info.countActionSets); @@ -776,7 +776,7 @@ bool GHOST_XrSession::syncActions(const char *action_set_name) XrActionsSyncInfo sync_info{XR_TYPE_ACTIONS_SYNC_INFO}; sync_info.countActiveActionSets = (action_set_name != nullptr) ? 1 : - (uint32_t)action_sets.size(); + uint32_t(action_sets.size()); if (sync_info.countActiveActionSets < 1) { return false; } diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 1b891478f44dd047c3a92fda3ebd17fae1c3acd +Subproject 7be7aff5a18c550465b3f7634539ed4168af7c5 diff --git a/release/scripts/addons b/release/scripts/addons -Subproject 67f1fbca1482d9d9362a4001332e785c3fd5d23 +Subproject 726d08c9036b939f46b59bceb72a61e3102600c diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject 95107484d076bc965239942e857c83433bfa86d +Subproject c43c0b2bcf08c34d933c3b56f096c9a23c8eff6 diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index a1e34731a94..22577dbd1cf 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -358,56 +358,50 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True) :return: script paths. :rtype: list """ - scripts = [] - # Only script paths Blender uses. - # - # This is needed even when `check_all` is enabled. - # NOTE: Use `_script_base_dir` instead of `_bpy_script_paths()[0]` as it's taken from this files path. - base_paths = (_script_base_dir, ) - if use_user: - base_paths += _bpy_script_paths()[1:] + if check_all or use_user: + path_system, path_user = _bpy_script_paths() - # Defined to be (system, user) so we can skip the second if needed. - if not use_user: - base_paths = base_paths[:1] + base_paths = [] if check_all: - # All possible paths, no duplicates, keep order. + # Order: 'LOCAL', 'USER', 'SYSTEM' (where user is optional). + if path_local := resource_path('LOCAL'): + base_paths.append(_os.path.join(path_local, "scripts")) if use_user: - test_paths = ('LOCAL', 'USER', 'SYSTEM') - else: - test_paths = ('LOCAL', 'SYSTEM') - - base_paths = ( - *(path for path in ( - _os.path.join(resource_path(res), "scripts") - for res in test_paths) if path not in base_paths), - *base_paths, - ) - - test_paths = ( - *base_paths, - *((script_path_user(),) if use_user else ()), - *((script_path_pref(),) if user_pref else ()), - ) + base_paths.append(path_user) + base_paths.append(path_system) # Same as: `system_resource('SCRIPTS')`. + + # Note that `_script_base_dir` may be either: + # - `os.path.join(bpy.utils.resource_path('LOCAL'), "scripts")` + # - `bpy.utils.system_resource('SCRIPTS')`. + # When `check_all` is enabled duplicate paths will be added however + # paths are de-duplicated so it wont cause problems. + base_paths.append(_script_base_dir) + + if not check_all: + if use_user: + base_paths.append(path_user) + + if user_pref: + base_paths.append(script_path_pref()) - for path in test_paths: - if path: - path = _os.path.normpath(path) - if path not in scripts and _os.path.isdir(path): - scripts.append(path) + scripts = [] + for path in base_paths: + if not path: + continue - if subdir is None: - return scripts + path = _os.path.normpath(path) + if subdir is not None: + path = _os.path.join(path, subdir) - scripts_subdir = [] - for path in scripts: - path_subdir = _os.path.join(path, subdir) - if _os.path.isdir(path_subdir): - scripts_subdir.append(path_subdir) + if path in scripts: + continue + if not _os.path.isdir(path): + continue + scripts.append(path) - return scripts_subdir + return scripts def refresh_script_paths(): diff --git a/release/scripts/startup/bl_operators/spreadsheet.py b/release/scripts/startup/bl_operators/spreadsheet.py index 1ba7d2db2fd..aef4231d573 100644 --- a/release/scripts/startup/bl_operators/spreadsheet.py +++ b/release/scripts/startup/bl_operators/spreadsheet.py @@ -32,7 +32,6 @@ class SPREADSHEET_OT_toggle_pin(Operator): def unpin(self, context): space = context.space_data space.is_pinned = False - space.context_path.guess() classes = ( diff --git a/release/scripts/startup/bl_ui/node_add_menu_geometry.py b/release/scripts/startup/bl_ui/node_add_menu_geometry.py index b29e607d413..3544c9a4925 100644 --- a/release/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/release/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -11,9 +11,9 @@ class NODE_MT_geometry_node_GEO_ATTRIBUTE(Menu): def draw(self, _context): layout = self.layout + node_add_menu.add_node_type(layout, "GeometryNodeAttributeStatistic") node_add_menu.add_node_type(layout, "GeometryNodeCaptureAttribute") node_add_menu.add_node_type(layout, "GeometryNodeAttributeDomainSize") - node_add_menu.add_node_type(layout, "GeometryNodeAttributeStatistic") node_add_menu.add_node_type(layout, "GeometryNodeRemoveAttribute") node_add_menu.add_node_type(layout, "GeometryNodeStoreNamedAttribute") @@ -24,14 +24,14 @@ class NODE_MT_geometry_node_GEO_COLOR(Menu): def draw(self, _context): layout = self.layout + node_add_menu.add_node_type(layout, "ShaderNodeValToRGB") + node_add_menu.add_node_type(layout, "FunctionNodeCombineColor") props = node_add_menu.add_node_type(layout, "ShaderNodeMix", label=iface_("Mix Color")) ops = props.settings.add() ops.name = "data_type" ops.value = "'RGBA'" node_add_menu.add_node_type(layout, "ShaderNodeRGBCurve") - node_add_menu.add_node_type(layout, "ShaderNodeValToRGB") node_add_menu.add_node_type(layout, "FunctionNodeSeparateColor") - node_add_menu.add_node_type(layout, "FunctionNodeCombineColor") class NODE_MT_geometry_node_GEO_CURVE(Menu): @@ -52,7 +52,6 @@ class NODE_MT_geometry_node_GEO_CURVE(Menu): node_add_menu.add_node_type(layout, "GeometryNodeSubdivideCurve") node_add_menu.add_node_type(layout, "GeometryNodeTrimCurve") layout.separator() - node_add_menu.add_node_type(layout, "GeometryNodeInputControlPointNeighbors") node_add_menu.add_node_type(layout, "GeometryNodeInputCurveHandlePositions") node_add_menu.add_node_type(layout, "GeometryNodeInputTangent") node_add_menu.add_node_type(layout, "GeometryNodeInputCurveTilt") @@ -78,14 +77,25 @@ class NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE(Menu): def draw(self, _context): layout = self.layout - node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveLine") + node_add_menu.add_node_type(layout, "GeometryNodeCurveArc") + node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveBezierSegment") node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveCircle") - node_add_menu.add_node_type(layout, "GeometryNodeCurveStar") + node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveLine") node_add_menu.add_node_type(layout, "GeometryNodeCurveSpiral") - node_add_menu.add_node_type(layout, "GeometryNodeCurveArc") node_add_menu.add_node_type(layout, "GeometryNodeCurveQuadraticBezier") node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveQuadrilateral") - node_add_menu.add_node_type(layout, "GeometryNodeCurvePrimitiveBezierSegment") + node_add_menu.add_node_type(layout, "GeometryNodeCurveStar") + + +class NODE_MT_geometry_node_curve_topology(Menu): + bl_idname = "NODE_MT_geometry_node_curve_topology" + bl_label = "Curve Topology" + + def draw(self, _context): + layout = self.layout + node_add_menu.add_node_type(layout, "GeometryNodeInputControlPointNeighbors") + node_add_menu.add_node_type(layout, "GeometryNodeCurveOfPoint") + node_add_menu.add_node_type(layout, "GeometryNodePointsOfCurve") class NODE_MT_geometry_node_GEO_GEOMETRY(Menu): @@ -215,15 +225,30 @@ class NODE_MT_category_PRIMITIVES_MESH(Menu): def draw(self, _context): layout = self.layout - node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle") node_add_menu.add_node_type(layout, "GeometryNodeMeshCone") node_add_menu.add_node_type(layout, "GeometryNodeMeshCube") node_add_menu.add_node_type(layout, "GeometryNodeMeshCylinder") node_add_menu.add_node_type(layout, "GeometryNodeMeshGrid") node_add_menu.add_node_type(layout, "GeometryNodeMeshIcoSphere") + node_add_menu.add_node_type(layout, "GeometryNodeMeshCircle") node_add_menu.add_node_type(layout, "GeometryNodeMeshLine") +class NODE_MT_geometry_node_mesh_topology(Menu): + bl_idname = "NODE_MT_geometry_node_mesh_topology" + bl_label = "Mesh Topology" + + def draw(self, _context): + layout = self.layout + node_add_menu.add_node_type(layout, "GeometryNodeCornersOfFace"), + node_add_menu.add_node_type(layout, "GeometryNodeCornersOfVertex"), + node_add_menu.add_node_type(layout, "GeometryNodeEdgesOfCorner"), + node_add_menu.add_node_type(layout, "GeometryNodeEdgesOfVertex"), + node_add_menu.add_node_type(layout, "GeometryNodeFaceOfCorner"), + node_add_menu.add_node_type(layout, "GeometryNodeOffsetCornerInFace"), + node_add_menu.add_node_type(layout, "GeometryNodeVertexOfCorner"), + + class NODE_MT_category_GEO_OUTPUT(Menu): bl_idname = "NODE_MT_category_GEO_OUTPUT" bl_label = "Output" @@ -254,12 +279,12 @@ class NODE_MT_category_GEO_TEXT(Menu): def draw(self, _context): layout = self.layout - node_add_menu.add_node_type(layout, "FunctionNodeSliceString") node_add_menu.add_node_type(layout, "GeometryNodeStringJoin") - node_add_menu.add_node_type(layout, "FunctionNodeStringLength") node_add_menu.add_node_type(layout, "FunctionNodeReplaceString") - node_add_menu.add_node_type(layout, "FunctionNodeValueToString") + node_add_menu.add_node_type(layout, "FunctionNodeSliceString") + node_add_menu.add_node_type(layout, "FunctionNodeStringLength") node_add_menu.add_node_type(layout, "GeometryNodeStringToCurves") + node_add_menu.add_node_type(layout, "FunctionNodeValueToString") layout.separator() node_add_menu.add_node_type(layout, "FunctionNodeInputSpecialCharacters") @@ -289,20 +314,20 @@ class NODE_MT_category_GEO_UTILITIES(Menu): def draw(self, _context): layout = self.layout node_add_menu.add_node_type(layout, "GeometryNodeAccumulateField") + node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector") + node_add_menu.add_node_type(layout, "FunctionNodeBooleanMath") + node_add_menu.add_node_type(layout, "ShaderNodeClamp") + node_add_menu.add_node_type(layout, "FunctionNodeCompare") node_add_menu.add_node_type(layout, "GeometryNodeFieldAtIndex") + node_add_menu.add_node_type(layout, "ShaderNodeFloatCurve") + node_add_menu.add_node_type(layout, "FunctionNodeFloatToInt") node_add_menu.add_node_type(layout, "GeometryNodeFieldOnDomain") node_add_menu.add_node_type(layout, "ShaderNodeMapRange") - node_add_menu.add_node_type(layout, "ShaderNodeFloatCurve") - node_add_menu.add_node_type(layout, "ShaderNodeClamp") node_add_menu.add_node_type(layout, "ShaderNodeMath") - node_add_menu.add_node_type(layout, "FunctionNodeBooleanMath") - node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler") - node_add_menu.add_node_type(layout, "FunctionNodeCompare") node_add_menu.add_node_type(layout, "ShaderNodeMix") - node_add_menu.add_node_type(layout, "FunctionNodeFloatToInt") - node_add_menu.add_node_type(layout, "GeometryNodeSwitch") node_add_menu.add_node_type(layout, "FunctionNodeRandomValue") - node_add_menu.add_node_type(layout, "FunctionNodeAlignEulerToVector") + node_add_menu.add_node_type(layout, "FunctionNodeRotateEuler") + node_add_menu.add_node_type(layout, "GeometryNodeSwitch") class NODE_MT_category_GEO_UV(Menu): @@ -367,12 +392,14 @@ class NODE_MT_geometry_node_add_all(Menu): layout.menu("NODE_MT_geometry_node_GEO_COLOR") layout.menu("NODE_MT_geometry_node_GEO_CURVE") layout.menu("NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE") + layout.menu("NODE_MT_geometry_node_curve_topology") layout.menu("NODE_MT_geometry_node_GEO_GEOMETRY") layout.menu("NODE_MT_geometry_node_GEO_INPUT") layout.menu("NODE_MT_geometry_node_GEO_INSTANCE") layout.menu("NODE_MT_geometry_node_GEO_MATERIAL") layout.menu("NODE_MT_geometry_node_GEO_MESH") layout.menu("NODE_MT_category_PRIMITIVES_MESH") + layout.menu("NODE_MT_geometry_node_mesh_topology") layout.menu("NODE_MT_category_GEO_OUTPUT") layout.menu("NODE_MT_category_GEO_POINT") layout.menu("NODE_MT_category_GEO_TEXT") @@ -391,12 +418,14 @@ classes = ( NODE_MT_geometry_node_GEO_COLOR, NODE_MT_geometry_node_GEO_CURVE, NODE_MT_geometry_node_GEO_PRIMITIVES_CURVE, + NODE_MT_geometry_node_curve_topology, NODE_MT_geometry_node_GEO_GEOMETRY, NODE_MT_geometry_node_GEO_INPUT, NODE_MT_geometry_node_GEO_INSTANCE, NODE_MT_geometry_node_GEO_MATERIAL, NODE_MT_geometry_node_GEO_MESH, NODE_MT_category_PRIMITIVES_MESH, + NODE_MT_geometry_node_mesh_topology, NODE_MT_category_GEO_OUTPUT, NODE_MT_category_GEO_POINT, NODE_MT_category_GEO_TEXT, diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 9b1cf11f6e7..72a87703bd5 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -943,8 +943,39 @@ def brush_settings_advanced(layout, context, brush, popover=False): # boundary edges/face sets automasking col.prop(brush, "use_automasking_boundary_edges", text="Mesh Boundary") col.prop(brush, "use_automasking_boundary_face_sets", text="Face Sets Boundary") + col.prop(brush, "use_automasking_cavity", text="Cavity") + col.prop(brush, "use_automasking_cavity_inverted", text="Cavity (Inverted)") + col.prop(brush, "use_automasking_start_normal", text="Area Normal") + col.prop(brush, "use_automasking_view_normal", text="View Normal") + + col.separator() col.prop(brush, "automasking_boundary_edges_propagation_steps") + sculpt = context.tool_settings.sculpt + + if brush.use_automasking_start_normal: + col.separator() + + col.prop(sculpt, "automasking_start_normal_limit") + col.prop(sculpt, "automasking_start_normal_falloff") + + if brush.use_automasking_view_normal: + col.separator() + + col.prop(brush, "use_automasking_view_occlusion", text="Occlusion") + col.prop(sculpt, "automasking_view_normal_limit") + col.prop(sculpt, "automasking_view_normal_falloff") + + if brush.use_automasking_cavity or brush.use_automasking_cavity_inverted: + col.separator() + + col.prop(brush, "automasking_cavity_factor", text="Cavity Factor") + col.prop(brush, "automasking_cavity_blur_steps", text="Cavity Blur") + col.prop(brush, "use_automasking_custom_cavity_curve", text="Use Curve") + + if brush.use_automasking_custom_cavity_curve: + col.template_curve_mapping(brush, "automasking_cavity_curve") + layout.separator() # sculpt plane settings diff --git a/release/scripts/startup/bl_ui/space_spreadsheet.py b/release/scripts/startup/bl_ui/space_spreadsheet.py index 741ad544d67..846582b0142 100644 --- a/release/scripts/startup/bl_ui/space_spreadsheet.py +++ b/release/scripts/startup/bl_ui/space_spreadsheet.py @@ -11,34 +11,37 @@ class SPREADSHEET_HT_header(bpy.types.Header): space = context.space_data layout.template_header() + viewer_path = space.viewer_path.path - if len(space.context_path) == 0: - self.draw_without_context_path(layout) + if len(viewer_path) == 0: + self.draw_without_viewer_path(layout) return - root_context = space.context_path[0] - if root_context.type != 'OBJECT': - self.draw_without_context_path(layout) + root_context = viewer_path[0] + if root_context.type != 'ID': + self.draw_without_viewer_path(layout) return - obj = root_context.object + if not isinstance(root_context.id, bpy.types.Object): + self.draw_without_viewer_path(layout) + return + obj = root_context.id if obj is None: - self.draw_without_context_path(layout) + self.draw_without_viewer_path(layout) return layout.prop(space, "object_eval_state", text="") - context_path = space.context_path if space.object_eval_state == 'ORIGINAL': # Only show first context. - context_path = context_path[:1] - if space.display_context_path_collapsed: - self.draw_collapsed_context_path(context, layout, context_path) + viewer_path = viewer_path[:1] + if space.display_viewer_path_collapsed: + self.draw_collapsed_viewer_path(context, layout, viewer_path) else: - self.draw_full_context_path(context, layout, context_path) + self.draw_full_viewer_path(context, layout, viewer_path) pin_icon = 'PINNED' if space.is_pinned else 'UNPINNED' layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False) - if space.object_eval_state == 'VIEWER_NODE' and len(context_path) < 3: + if space.object_eval_state == 'VIEWER_NODE' and len(viewer_path) < 3: layout.label(text="No active viewer node", icon='INFO') layout.separator_spacer() @@ -49,50 +52,52 @@ class SPREADSHEET_HT_header(bpy.types.Header): sub.prop(space, "show_only_selected", text="") row.prop(space, "use_filter", toggle=True, icon='FILTER', icon_only=True) - def draw_without_context_path(self, layout): + def draw_without_viewer_path(self, layout): layout.label(text="No active context") - def draw_full_context_path(self, context, layout, context_path): + def draw_full_viewer_path(self, context, layout, viewer_path): space = context.space_data row = layout.row() - for ctx in context_path[:-1]: + for ctx in viewer_path[:-1]: subrow = row.row(align=True) self.draw_spreadsheet_context(subrow, ctx) - self.draw_spreadsheet_context_path_icon(subrow, space) + self.draw_spreadsheet_viewer_path_icon(subrow, space) - self.draw_spreadsheet_context(row, context_path[-1]) + self.draw_spreadsheet_context(row, viewer_path[-1]) - def draw_collapsed_context_path(self, context, layout, context_path): + def draw_collapsed_viewer_path(self, context, layout, viewer_path): space = context.space_data row = layout.row(align=True) - self.draw_spreadsheet_context(row, context_path[0]) - if len(context_path) == 1: + self.draw_spreadsheet_context(row, viewer_path[0]) + if len(viewer_path) == 1: return - self.draw_spreadsheet_context_path_icon(row, space) - if len(context_path) > 2: - self.draw_spreadsheet_context_path_icon(row, space, icon='DOT') - self.draw_spreadsheet_context_path_icon(row, space) - self.draw_spreadsheet_context(row, context_path[-1]) + self.draw_spreadsheet_viewer_path_icon(row, space) + if len(viewer_path) > 2: + self.draw_spreadsheet_viewer_path_icon(row, space, icon='DOT') + self.draw_spreadsheet_viewer_path_icon(row, space) + self.draw_spreadsheet_context(row, viewer_path[-1]) def draw_spreadsheet_context(self, layout, ctx): - if ctx.type == 'OBJECT': - if ctx.object is None: - layout.label(text="<no object>", icon='OBJECT_DATA') + if ctx.type == 'ID': + if ctx.id is not None and isinstance(ctx.id, bpy.types.Object): + layout.label(text=ctx.id.name, icon='OBJECT_DATA') else: - layout.label(text=ctx.object.name, icon='OBJECT_DATA') + layout.label(text="Invalid id") elif ctx.type == 'MODIFIER': layout.label(text=ctx.modifier_name, icon='MODIFIER') elif ctx.type == 'NODE': layout.label(text=ctx.node_name, icon='NODE') - def draw_spreadsheet_context_path_icon(self, layout, space, icon='RIGHTARROW_THIN'): - layout.prop(space, "display_context_path_collapsed", icon_only=True, emboss=False, icon=icon) + def draw_spreadsheet_viewer_path_icon(self, layout, space, icon='RIGHTARROW_THIN'): + layout.prop(space, "display_viewer_path_collapsed", icon_only=True, emboss=False, icon=icon) def selection_filter_available(self, space): - root_context = space.context_path[0] - if root_context.type != 'OBJECT': + root_context = space.viewer_path.path[0] + if root_context.type != 'ID': + return False + if not isinstance(root_context.id, bpy.types.Object): return False - obj = root_context.object + obj = root_context.id if obj is None: return False if obj.type == 'MESH': diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index a687f3c937f..ada2993a16f 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1216,6 +1216,7 @@ class VIEW3D_MT_view(Menu): layout.operator("view3d.view_all").center = False layout.operator("view3d.view_persportho", text="Perspective/Orthographic") layout.menu("VIEW3D_MT_view_local") + layout.prop(view, "show_viewer", text="Viewer Node") layout.separator() @@ -3297,7 +3298,8 @@ class VIEW3D_MT_mask(Menu): layout.separator() - props = layout.operator("sculpt.dirty_mask", text='Dirty Mask') + props = layout.operator("sculpt.mask_from_cavity", text="Mask From Cavity") + props.use_automask_settings = False layout.separator() @@ -5493,6 +5495,10 @@ class VIEW3D_MT_sculpt_automasking_pie(Menu): pie.prop(sculpt, "use_automasking_face_sets", text="Face Sets") pie.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary") pie.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary") + pie.prop(sculpt, "use_automasking_cavity", text="Cavity") + pie.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (Inverted)") + pie.prop(sculpt, "use_automasking_start_normal", text="Area Normal") + pie.prop(sculpt, "use_automasking_view_normal", text="View Normal") class VIEW3D_MT_sculpt_face_sets_edit_pie(Menu): @@ -6347,6 +6353,13 @@ class VIEW3D_PT_overlay_geometry(Panel): sub.prop(overlay, "wireframe_opacity", text="Opacity") row = col.row(align=True) + row.active = view.show_viewer + row.prop(overlay, "show_viewer_attribute", text="") + subrow = row.row(align=True) + subrow.active = overlay.show_viewer_attribute + subrow.prop(overlay, "viewer_attribute_opacity", text="Viewer Node") + + row = col.row(align=True) # These properties should be always available in the UI for all modes # other than Object. diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 95185c2a2f5..c1f2bef95e8 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-or-later -from bpy.types import Menu, Panel, UIList +from bpy.types import Menu, Panel, UIList, WindowManager from bl_ui.properties_grease_pencil_common import ( GreasePencilSculptAdvancedPanel, GreasePencilDisplayPanel, @@ -967,10 +967,48 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): col.separator() col = layout.column(heading="Auto-Masking", align=True) + col.prop(sculpt, "use_automasking_topology", text="Topology") col.prop(sculpt, "use_automasking_face_sets", text="Face Sets") col.prop(sculpt, "use_automasking_boundary_edges", text="Mesh Boundary") col.prop(sculpt, "use_automasking_boundary_face_sets", text="Face Sets Boundary") + col.prop(sculpt, "use_automasking_cavity", text="Cavity") + col.prop(sculpt, "use_automasking_cavity_inverted", text="Cavity (Inverted)") + col.prop(sculpt, "use_automasking_start_normal", text="Area Normal") + col.prop(sculpt, "use_automasking_view_normal", text="View Normal") + + if sculpt.use_automasking_start_normal: + col.separator() + + col.prop(sculpt, "automasking_start_normal_limit") + col.prop(sculpt, "automasking_start_normal_falloff") + + if sculpt.use_automasking_view_normal: + col.separator() + + col.prop(sculpt, "use_automasking_view_occlusion", text="Occlusion") + col.prop(sculpt, "automasking_view_normal_limit") + col.prop(sculpt, "automasking_view_normal_falloff") + + col.separator() + col.prop(sculpt.brush, "automasking_boundary_edges_propagation_steps") + + if sculpt.use_automasking_cavity or sculpt.use_automasking_cavity_inverted: + col.separator() + + col2 = col.column() + props = col2.operator("sculpt.mask_from_cavity", text="Mask From Cavity") + props.use_automask_settings = True + + col2 = col.column() + + col2.prop(sculpt, "automasking_cavity_factor", text="Cavity Factor") + col2.prop(sculpt, "automasking_cavity_blur_steps", text="Cavity Blur") + + col2.prop(sculpt, "use_automasking_custom_cavity_curve", text="Use Curve") + + if sculpt.use_automasking_custom_cavity_curve: + col2.template_curve_mapping(sculpt, "automasking_cavity_curve") class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel): @@ -1893,6 +1931,10 @@ class VIEW3D_PT_tools_grease_pencil_brush_gap_closure(View3DPanel, Panel): row = col.row(align=True) row.prop(gp_settings, "show_fill_extend", text="Visual Aids") + if gp_settings.fill_extend_mode == 'EXTEND': + row = col.row(align=True) + row.prop(gp_settings, "use_collide_strokes") + # Grease Pencil stroke sculpting tools class GreasePencilSculptPanel: diff --git a/release/scripts/templates_py/custom_nodes.py b/release/scripts/templates_py/custom_nodes.py index fba94e23d0d..fd2dfe91b39 100644 --- a/release/scripts/templates_py/custom_nodes.py +++ b/release/scripts/templates_py/custom_nodes.py @@ -61,7 +61,7 @@ class MyCustomTreeNode: # Derived from the Node base type. -class MyCustomNode(Node, MyCustomTreeNode): +class MyCustomNode(MyCustomTreeNode, Node): # === Basics === # Description string '''A custom node''' diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 28c15d9224c..4dd596ad93a 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -82,6 +82,7 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view2d_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_enums.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_viewer_path_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_volume_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_workspace_types.h diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 2eed7418220..ac2f2f35ca3 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -37,8 +37,8 @@ typedef struct UnicodeSample { char32_t sample[BLF_SAMPLE_LEN]; - char field; /* ‘OS/2’ table ulUnicodeRangeX field (1-4). */ - long mask; /* ‘OS/2’ table ulUnicodeRangeX bit mask. */ + int field; /* ‘OS/2’ table ulUnicodeRangeX field (1-4). */ + FT_ULong mask; /* ‘OS/2’ table ulUnicodeRangeX bit mask. */ } UnicodeSample; /* The seemingly arbitrary order that follows is to help quickly find the most-likely designed @@ -86,7 +86,7 @@ static const UnicodeSample unicode_samples[] = { {U"\ua188\ua320\ua4bf", 3, TT_UCR_YI}, {U"\u1900\u1901\u1902", 3, TT_UCR_LIMBU}, {U"\u1950\u1951\u1952", 3, TT_UCR_TAI_LE}, - {U"\u1980\u1982\u1986", 3, TT_UCR_NEW_TAI_LUE}, + {U"\u1980\u1982\u1986", 3, (FT_ULong)TT_UCR_NEW_TAI_LUE}, {U"\u1A00\u1A01\u1A02", 4, TT_UCR_BUGINESE}, {U"\u2c01\u2c05\u2c0c", 4, TT_UCR_GLAGOLITIC}, {U"\u2d31\u2d33\u2d37", 4, TT_UCR_TIFINAGH}, @@ -258,16 +258,18 @@ static const char32_t *blf_get_sample_text(FT_Face face) count_bits_i((uint)os2_table->ulUnicodeRange4); for (uint i = 0; i < ARRAY_SIZE(unicode_samples); ++i) { - UnicodeSample s = unicode_samples[i]; - if (os2_table && s.field && s.mask) { + const UnicodeSample *s = &unicode_samples[i]; + if (os2_table && s->field && s->mask) { /* OS/2 Table contains 4 contiguous integers of script coverage bit flags. */ - FT_ULong *field = &(os2_table->ulUnicodeRange1) + (s.field - 1); - if (!(*field & (FT_ULong)s.mask)) { + const FT_ULong *unicode_range = &os2_table->ulUnicodeRange1; + const int index = (s->field - 1); + BLI_assert(index < 4); + if (!(unicode_range[index] & s->mask)) { continue; } } - if (FT_Get_Char_Index(face, s.sample[0]) != 0) { - sample = s.sample; + if (FT_Get_Char_Index(face, s->sample[0]) != 0) { + sample = s->sample; break; } } diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 244c5d4609f..4bbe3ab8596 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 1 +#define BLENDER_FILE_SUBVERSION 2 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h index f5ffd1190b1..2ef81b754cc 100644 --- a/source/blender/blenkernel/BKE_cloth.h +++ b/source/blender/blenkernel/BKE_cloth.h @@ -218,7 +218,7 @@ int cloth_bvh_collision(struct Depsgraph *depsgraph, /* -------------------------------------------------------------------- */ /* cloth.c */ -/* Needed for modifier.c */ +/* Needed for modifier.cc */ /** Frees all. */ void cloth_free_modifier_extern(struct ClothModifierData *clmd); /** Frees all. */ diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index 44c1b2a3cbd..1aaddebed91 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -84,7 +84,7 @@ typedef struct FaceCollPair { ///////////////////////////////////////////////// ///////////////////////////////////////////////// -// used in modifier.c from collision.c +// used in modifier.cc from collision.c ///////////////////////////////////////////////// struct BVHTree *bvhtree_build_from_mvert(const float (*positions)[3], diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 371f6052a76..4c7ff8c1813 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -208,6 +208,8 @@ class CurvesGeometry : public ::CurvesGeometry { IndexMask selection, Vector<int64_t> &r_indices) const; + Array<int> point_to_curve_map() const; + Span<float3> positions() const; MutableSpan<float3> positions_for_write(); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 22e4a2bce87..61f3a0e1d5e 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -457,12 +457,6 @@ const char *CustomData_get_active_layer_name(const struct CustomData *data, int */ const char *CustomData_get_render_layer_name(const struct CustomData *data, int type); -/** - * Copies the data from source to the data element at index in the first layer of type - * no effect if there is no layer of type. - */ -void CustomData_set(const struct CustomData *data, int index, int type, const void *source); - void CustomData_bmesh_set(const struct CustomData *data, void *block, int type, @@ -470,18 +464,6 @@ void CustomData_bmesh_set(const struct CustomData *data, void CustomData_bmesh_set_n( struct CustomData *data, void *block, int type, int n, const void *source); -/** - * Sets the data of the block at physical layer n. - * no real type checking is performed. - */ -void CustomData_bmesh_set_layer_n(struct CustomData *data, void *block, int n, const void *source); - -/** - * Set the pointer of to the first layer of type. the old data is not freed. - * returns the value of `ptr` if the layer is found, NULL otherwise. - */ -void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr); -void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr); /** * Sets the nth layer of type as active. @@ -590,7 +572,6 @@ void CustomData_bmesh_init_pool(struct CustomData *data, int totelem, char htype * \return True if some errors were found. */ bool CustomData_layer_validate(struct CustomDataLayer *layer, uint totitems, bool do_fixes); -void CustomData_layers__print(struct CustomData *data); /* External file storage */ diff --git a/source/blender/blenkernel/BKE_duplilist.h b/source/blender/blenkernel/BKE_duplilist.h index 0648cdde529..79f37d2edde 100644 --- a/source/blender/blenkernel/BKE_duplilist.h +++ b/source/blender/blenkernel/BKE_duplilist.h @@ -16,6 +16,8 @@ struct ListBase; struct Object; struct ParticleSystem; struct Scene; +struct ViewerPath; +struct GeometrySet; /* ---------------------------------------------------- */ /* Dupli-Geometry */ @@ -26,6 +28,13 @@ struct Scene; struct ListBase *object_duplilist(struct Depsgraph *depsgraph, struct Scene *sce, struct Object *ob); +/** + * \return a #ListBase of #DupliObject for the preview geometry referenced by the #ViewerPath. + */ +struct ListBase *object_duplilist_preview(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob, + const struct ViewerPath *viewer_path); void free_object_duplilist(struct ListBase *lb); typedef struct DupliObject { @@ -39,6 +48,10 @@ typedef struct DupliObject { short type; /* from Object.transflag */ char no_draw; + /* If this dupli object is belongs to a preview, this is non-null. */ + const struct GeometrySet *preview_base_geometry; + /* Index of the top-level instance this dupli is part of or -1 when unused. */ + int preview_instance_index; /* Persistent identifier for a dupli object, for inter-frame matching of * objects with motion blur, or inter-update matching for syncing. */ @@ -51,6 +64,14 @@ typedef struct DupliObject { unsigned int random_id; } DupliObject; +/** Look up the RGBA value of a uniform shader attribute. + * \return true if the attribute was found; if not, r_value is also set to zero. */ +bool BKE_object_dupli_find_rgba_attribute(struct Object *ob, + struct DupliObject *dupli, + struct Object *dupli_parent, + const char *name, + float r_value[4]); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 5916e7e83fb..dbfc9fd0799 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -69,7 +69,7 @@ typedef struct BMEditMesh { } BMEditMesh; -/* editmesh.c */ +/* editmesh.cc */ void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, const struct BMeshCalcTessellation_Params *params); diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh index 62aac5a4120..988e0017f04 100644 --- a/source/blender/blenkernel/BKE_geometry_fields.hh +++ b/source/blender/blenkernel/BKE_geometry_fields.hh @@ -145,6 +145,7 @@ class GeometryFieldInput : public fn::FieldInput { ResourceScope &scope) const override; virtual GVArray get_varray_for_context(const GeometryFieldContext &context, IndexMask mask) const = 0; + virtual std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const; }; class MeshFieldInput : public fn::FieldInput { @@ -156,6 +157,7 @@ class MeshFieldInput : public fn::FieldInput { virtual GVArray get_varray_for_context(const Mesh &mesh, eAttrDomain domain, IndexMask mask) const = 0; + virtual std::optional<eAttrDomain> preferred_domain(const Mesh &mesh) const; }; class CurvesFieldInput : public fn::FieldInput { @@ -167,6 +169,7 @@ class CurvesFieldInput : public fn::FieldInput { virtual GVArray get_varray_for_context(const CurvesGeometry &curves, eAttrDomain domain, IndexMask mask) const = 0; + virtual std::optional<eAttrDomain> preferred_domain(const CurvesGeometry &curves) const; }; class PointCloudFieldInput : public fn::FieldInput { @@ -218,6 +221,7 @@ class AttributeFieldInput : public GeometryFieldInput { uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; + std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const override; }; class IDAttributeFieldInput : public GeometryFieldInput { @@ -292,6 +296,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput { uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; + std::optional<eAttrDomain> preferred_domain(const GeometryComponent &component) const override; }; class CurveLengthFieldInput final : public CurvesFieldInput { @@ -304,4 +309,16 @@ class CurveLengthFieldInput final : public CurvesFieldInput { bool is_equal_to(const fn::FieldNode &other) const override; }; +bool try_capture_field_on_geometry(GeometryComponent &component, + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const fn::GField &field); + +/** + * Try to find the geometry domain that the field should be evaluated on. If it is not obvious + * which domain is correct, none is returned. + */ +std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &component, + const fn::GField &field); + } // namespace blender::bke diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index 1ec7cca3042..12badd51dda 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -7,6 +7,10 @@ */ #ifdef __cplusplus +# include "BLI_array.hh" +#endif + +#ifdef __cplusplus extern "C" { #endif @@ -328,3 +332,19 @@ int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge, #ifdef __cplusplus } #endif + +#ifdef __cplusplus +namespace blender::mesh_topology { + +Array<int> build_corner_to_poly_map(Span<MPoly> polys, int loops_num); + +Array<Vector<int>> build_vert_to_edge_map(Span<MEdge> edges, int verts_num); +Array<Vector<int>> build_vert_to_corner_map(Span<MLoop> loops, int verts_num); + +inline int previous_poly_corner(const MPoly &poly, int corner_i) +{ + return corner_i - 1 + (corner_i == poly.loopstart) * poly.totloop; +} + +} // namespace blender::mesh_topology +#endif diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 625c4d87bcd..f79fefcae24 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1532,6 +1532,15 @@ struct TexResult; #define GEO_NODE_SAMPLE_NEAREST 1175 #define GEO_NODE_SAMPLE_NEAREST_SURFACE 1176 #define GEO_NODE_INPUT_CONTROL_POINT_NEIGHBORS 1177 +#define GEO_NODE_CURVE_TOPOLOGY_CURVE_OF_POINT 1178 +#define GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE 1179 +#define GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE 1180 +#define GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE 1181 +#define GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX 1182 +#define GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER 1183 +#define GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX 1184 +#define GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER 1185 +#define GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER 1186 /** \} */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index a8b88b8030e..399b0928ee3 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -51,6 +51,7 @@ struct Palette; struct PaletteColor; struct Scene; struct StrokeCache; +struct Sculpt; struct SubdivCCG; struct Tex; struct ToolSettings; @@ -370,6 +371,7 @@ typedef struct SculptClothSimulation { float (*acceleration)[3]; float (*pos)[3]; float (*init_pos)[3]; + float (*init_no)[3]; float (*softbody_pos)[3]; float (*prev_pos)[3]; float (*last_iteration_pos)[3]; @@ -547,6 +549,9 @@ typedef struct SculptAttributePointers { /* Precomputed auto-mask factor indexed by vertex, owned by the auto-masking system and * initialized in #SCULPT_automasking_cache_init when needed. */ SculptAttribute *automasking_factor; + SculptAttribute *automasking_occlusion; /* CD_PROP_INT8. */ + SculptAttribute *automasking_stroke_id; + SculptAttribute *automasking_cavity; /* BMesh */ SculptAttribute *dyntopo_node_id_vertex; @@ -737,11 +742,16 @@ typedef struct SculptSession { */ bool sticky_shading_color; + uchar stroke_id; + /** * Last used painting canvas key. */ char *last_paint_canvas_key; + float last_normal[3]; + int last_automasking_settings_hash; + uchar last_automask_stroke_id; } SculptSession; void BKE_sculptsession_free(struct Object *ob); @@ -899,6 +909,8 @@ bool BKE_paint_canvas_image_get(struct PaintModeSettings *settings, struct ImageUser **r_image_user); int BKE_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings, struct Object *ob); +void BKE_sculpt_check_cavity_curves(struct Sculpt *sd); +struct CurveMapping *BKE_sculpt_default_cavity_curve(void); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 72e01f1a6c8..9249200b95a 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -16,6 +16,7 @@ /* For embedding CCGKey in iterator. */ #include "BKE_attribute.h" #include "BKE_ccg.h" +#include "DNA_customdata_types.h" #ifdef __cplusplus extern "C" { @@ -27,7 +28,6 @@ struct CCGElem; struct CCGKey; struct CustomData; struct DMFlagMat; -struct GPU_PBVH_Buffers; struct IsectRayPrecalc; struct MLoop; struct MLoopTri; @@ -35,7 +35,9 @@ struct MPoly; struct Mesh; struct MeshElemMap; struct PBVH; +struct PBVHBatches; struct PBVHNode; +struct PBVH_GPU_Args; struct SubdivCCG; struct TaskParallelSettings; struct Image; @@ -97,6 +99,12 @@ typedef struct PBVHPixelsNode { void *node_data; } PBVHPixelsNode; +typedef struct PBVHAttrReq { + char name[MAX_CUSTOMDATA_LAYER_NAME]; + eAttrDomain domain; + eCustomDataType type; +} PBVHAttrReq; + typedef enum { PBVH_Leaf = 1 << 0, @@ -256,7 +264,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats, - unsigned int **grid_hidden); + unsigned int **grid_hidden, + struct Mesh *me); /** * Build a PBVH from a BMesh. */ @@ -347,9 +356,13 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, bool update_only_visible, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, - void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers), + void (*draw_fn)(void *user_data, + struct PBVHBatches *batches, + struct PBVH_GPU_Args *args), void *user_data, - bool full_render); + bool full_render, + PBVHAttrReq *attrs, + int attrs_num); void BKE_pbvh_draw_debug_cb(PBVH *pbvh, void (*draw_fn)(PBVHNode *node, diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 62b04785983..9a7d2bde810 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -108,6 +108,23 @@ typedef struct SpaceType { void (*space_subtype_set)(struct ScrArea *area, int value); void (*space_subtype_item_extend)(struct bContext *C, EnumPropertyItem **item, int *totitem); + /** + * Update pointers for all structs directly owned by this space. + */ + void (*blend_read_data)(struct BlendDataReader *reader, struct SpaceLink *space_link); + + /** + * Update pointers to other id data blocks. + */ + void (*blend_read_lib)(struct BlendLibReader *reader, + struct ID *parent_id, + struct SpaceLink *space_link); + + /** + * Write all structs that should be saved in a .blend file. + */ + void (*blend_write)(struct BlendWriter *writer, struct SpaceLink *space_link); + /* region type definitions */ ListBase regiontypes; diff --git a/source/blender/blenkernel/BKE_viewer_path.h b/source/blender/blenkernel/BKE_viewer_path.h new file mode 100644 index 00000000000..dfba289531f --- /dev/null +++ b/source/blender/blenkernel/BKE_viewer_path.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** + * A #ViewerPath is a path to data that is viewed/debugged by the user. It is a list of + * #ViewerPathElem. + * + * This is only used for geometry nodes currently. When the user activates a viewer node the + * corresponding path contains the following elements: + * - Object the viewer is activated on. + * - Modifier that contains the corresponding geometry node group. + * - Node tree path in case the viewer node is in a nested node group. + * - Viewer node name. + * + * The entire path is necessary (instead of just the combination of node group and viewer name), + * because the same node group may be used in many different places. + * + * This file contains basic functions for creating/deleting a #ViewerPath. For more use-case + * specific functions look in `ED_viewer_path.hh`. + */ + +#include "DNA_viewer_path_types.h" + +struct BlendWriter; +struct BlendDataReader; +struct BlendLibReader; +struct LibraryForeachIDData; +struct Library; +struct IDRemapper; + +#ifdef __cplusplus +extern "C" { +#endif + +void BKE_viewer_path_init(ViewerPath *viewer_path); +void BKE_viewer_path_clear(ViewerPath *viewer_path); +void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src); +bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b); +void BKE_viewer_path_blend_write(struct BlendWriter *writer, const ViewerPath *viewer_path); +void BKE_viewer_path_blend_read_data(struct BlendDataReader *reader, ViewerPath *viewer_path); +void BKE_viewer_path_blend_read_lib(struct BlendLibReader *reader, + struct Library *lib, + ViewerPath *viewer_path); +void BKE_viewer_path_foreach_id(struct LibraryForeachIDData *data, ViewerPath *viewer_path); +void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const struct IDRemapper *mappings); + +ViewerPathElem *BKE_viewer_path_elem_new(ViewerPathElemType type); +IDViewerPathElem *BKE_viewer_path_elem_new_id(void); +ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier(void); +NodeViewerPathElem *BKE_viewer_path_elem_new_node(void); +ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src); +bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b); +void BKE_viewer_path_elem_free(ViewerPathElem *elem); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 877407a644c..d0e2d945c2f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -125,7 +125,7 @@ set(SRC intern/displist.cc intern/dynamicpaint.c intern/editlattice.c - intern/editmesh.c + intern/editmesh.cc intern/editmesh_bvh.c intern/editmesh_cache.cc intern/editmesh_tangent.cc @@ -191,7 +191,7 @@ set(SRC intern/mask_rasterize.c intern/material.c intern/mball.cc - intern/mball_tessellate.c + intern/mball_tessellate.cc intern/mesh.cc intern/mesh_boolean_convert.cc intern/mesh_calc_edges.cc @@ -199,7 +199,7 @@ set(SRC intern/mesh_debug.cc intern/mesh_evaluate.cc intern/mesh_fair.cc - intern/mesh_iterators.c + intern/mesh_iterators.cc intern/mesh_legacy_convert.cc intern/mesh_mapping.cc intern/mesh_merge.c @@ -214,7 +214,7 @@ set(SRC intern/mesh_tessellate.cc intern/mesh_validate.cc intern/mesh_wrapper.cc - intern/modifier.c + intern/modifier.cc intern/movieclip.c intern/multires.c intern/multires_reshape.c @@ -235,7 +235,7 @@ set(SRC intern/object_deform.c intern/object_dupli.cc intern/object_facemap.c - intern/object_update.c + intern/object_update.cc intern/ocean.c intern/ocean_spectrum.c intern/outliner_treehash.cc @@ -297,6 +297,7 @@ set(SRC intern/unit.c intern/vfont.c intern/vfontdata_freetype.c + intern/viewer_path.cc intern/volume.cc intern/volume_render.cc intern/volume_to_mesh.cc @@ -482,6 +483,7 @@ set(SRC BKE_unit.h BKE_vfont.h BKE_vfontdata.h + BKE_viewer_path.h BKE_volume.h BKE_volume_render.h BKE_volume_to_mesh.hh diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index 863a0a2eb91..218f2c58470 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -6,6 +6,10 @@ * \ingroup bke */ +#ifdef __cplusplus +extern "C" { +#endif + typedef void *CCGMeshHDL; typedef void *CCGVertHDL; typedef void *CCGEdgeHDL; @@ -215,3 +219,7 @@ void ccgEdgeIterator_next(CCGEdgeIterator *ei); CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *fi); int ccgFaceIterator_isStopped(CCGFaceIterator *fi); void ccgFaceIterator_next(CCGFaceIterator *fi); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 3708090f8ed..7261e0a5869 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -72,6 +72,8 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c } brush_dst->curve = BKE_curvemapping_copy(brush_src->curve); + brush_dst->automasking_cavity_curve = BKE_curvemapping_copy(brush_src->automasking_cavity_curve); + if (brush_src->gpencil_settings != nullptr) { brush_dst->gpencil_settings = MEM_cnew(__func__, *(brush_src->gpencil_settings)); brush_dst->gpencil_settings->curve_sensitivity = BKE_curvemapping_copy( @@ -109,6 +111,7 @@ static void brush_free_data(ID *id) IMB_freeImBuf(brush->icon_imbuf); } BKE_curvemapping_free(brush->curve); + BKE_curvemapping_free(brush->automasking_cavity_curve); if (brush->gpencil_settings != nullptr) { BKE_curvemapping_free(brush->gpencil_settings->curve_sensitivity); @@ -212,6 +215,10 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres BKE_curvemapping_blend_write(writer, brush->curve); } + if (brush->automasking_cavity_curve) { + BKE_curvemapping_blend_write(writer, brush->automasking_cavity_curve); + } + if (brush->gpencil_settings) { BLO_write_struct(writer, BrushGpencilSettings, brush->gpencil_settings); @@ -267,6 +274,14 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id) BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP); } + BLO_read_data_address(reader, &brush->automasking_cavity_curve); + if (brush->automasking_cavity_curve) { + BKE_curvemapping_blend_read(reader, brush->automasking_cavity_curve); + } + else { + brush->automasking_cavity_curve = BKE_sculpt_default_cavity_curve(); + } + /* grease pencil */ BLO_read_data_address(reader, &brush->gpencil_settings); if (brush->gpencil_settings != nullptr) { @@ -2372,7 +2387,7 @@ void BKE_brush_scale_size(int *r_brush_size, if (old_unprojected_radius != 0) { scale /= new_unprojected_radius; } - (*r_brush_size) = (int)((float)(*r_brush_size) * scale); + (*r_brush_size) = int(float(*r_brush_size) * scale); } void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2]) diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 711b1179bd2..3e53884fd18 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -57,7 +57,7 @@ typedef struct BendSpringRef { /****************************************************************************** * - * External interface called by modifier.c clothModifier functions. + * External interface called by modifier.cc clothModifier functions. * ******************************************************************************/ diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index ddd1f000644..95ef94a6cd5 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -3085,7 +3085,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ make_bevel_list_segment_3D(bl); } else { - make_bevel_list_3D(bl, (int)(resolu * cu->twist_smooth), cu->twist_mode); + make_bevel_list_3D(bl, int(resolu * cu->twist_smooth), cu->twist_mode); } } } diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index 86bf3115c36..f5c845443f1 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -557,6 +557,15 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type, this->curve_types(), this->curve_type_counts(), type, selection, r_indices); } +Array<int> CurvesGeometry::point_to_curve_map() const +{ + Array<int> map(this->points_num()); + for (const int i : this->curves_range()) { + map.as_mutable_span().slice(this->points_for_curve(i)).fill(i); + } + return map; +} + void CurvesGeometry::ensure_nurbs_basis_cache() const { if (!this->runtime->nurbs_basis_cache_dirty) { diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index e630fe75d56..90a163fc7e8 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -3139,7 +3139,6 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, void *CustomData_duplicate_referenced_layer(CustomData *data, const int type, const int totelem) { - /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); return customData_duplicate_referenced_layer_index(data, layer_index, totelem); @@ -3191,7 +3190,6 @@ void CustomData_duplicate_referenced_layers(CustomData *data, const int totelem) bool CustomData_is_referenced_layer(CustomData *data, const int type) { - /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return false; @@ -3519,36 +3517,26 @@ void CustomData_swap(CustomData *data, const int index_a, const int index_b) void *CustomData_get(const CustomData *data, const int index, const int type) { BLI_assert(index >= 0); - - /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_active_layer_index(data, type); - if (layer_index == -1) { + void *layer_data = CustomData_get_layer(data, type); + if (!layer_data) { return nullptr; } - - /* get the offset of the desired element */ - const size_t offset = size_t(index) * layerType_getInfo(type)->size; - - return POINTER_OFFSET(data->layers[layer_index].data, offset); + return POINTER_OFFSET(layer_data, size_t(index) * layerType_getInfo(type)->size); } void *CustomData_get_n(const CustomData *data, const int type, const int index, const int n) { - BLI_assert(index >= 0 && n >= 0); - - /* get the layer index of the first layer of type */ - int layer_index = data->typemap[type]; - if (layer_index == -1) { + BLI_assert(index >= 0); + void *layer_data = CustomData_get_layer_n(data, type, n); + if (!layer_data) { return nullptr; } - const size_t offset = size_t(index) * layerType_getInfo(type)->size; - return POINTER_OFFSET(data->layers[layer_index + n].data, offset); + return POINTER_OFFSET(layer_data, size_t(index) * layerType_getInfo(type)->size); } void *CustomData_get_layer(const CustomData *data, const int type) { - /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return nullptr; @@ -3559,7 +3547,6 @@ void *CustomData_get_layer(const CustomData *data, const int type) void *CustomData_get_layer_n(const CustomData *data, const int type, const int n) { - /* get the layer index of the active layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { return nullptr; @@ -3580,7 +3567,6 @@ void *CustomData_get_layer_named(const CustomData *data, const int type, const c int CustomData_get_offset(const CustomData *data, const int type) { - /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return -1; @@ -3591,7 +3577,6 @@ int CustomData_get_offset(const CustomData *data, const int type) int CustomData_get_n_offset(const CustomData *data, const int type, const int n) { - /* get the layer index of the active layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { return -1; @@ -3612,7 +3597,6 @@ int CustomData_get_offset_named(const CustomData *data, int type, const char *na bool CustomData_set_layer_name(CustomData *data, const int type, const int n, const char *name) { - /* get the layer index of the first layer of type */ const int layer_index = CustomData_get_layer_index_n(data, type, n); if ((layer_index == -1) || !name) { @@ -3631,50 +3615,6 @@ const char *CustomData_get_layer_name(const CustomData *data, const int type, co return (layer_index == -1) ? nullptr : data->layers[layer_index].name; } -void *CustomData_set_layer(const CustomData *data, const int type, void *ptr) -{ - /* get the layer index of the first layer of type */ - int layer_index = CustomData_get_active_layer_index(data, type); - - if (layer_index == -1) { - return nullptr; - } - - data->layers[layer_index].data = ptr; - - return ptr; -} - -void *CustomData_set_layer_n(const CustomData *data, const int type, const int n, void *ptr) -{ - /* get the layer index of the first layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); - if (layer_index == -1) { - return nullptr; - } - - data->layers[layer_index].data = ptr; - - return ptr; -} - -void CustomData_set(const CustomData *data, const int index, const int type, const void *source) -{ - void *dest = CustomData_get(data, index, type); - const LayerTypeInfo *typeInfo = layerType_getInfo(type); - - if (!dest) { - return; - } - - if (typeInfo->copy) { - typeInfo->copy(source, dest, 1); - } - else { - memcpy(dest, source, typeInfo->size); - } -} - /* BMesh functions */ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) @@ -4009,7 +3949,6 @@ void CustomData_bmesh_copy_data(const CustomData *source, void *CustomData_bmesh_get(const CustomData *data, void *block, const int type) { - /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return nullptr; @@ -4020,7 +3959,6 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, const int type) void *CustomData_bmesh_get_n(const CustomData *data, void *block, const int type, const int n) { - /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index(data, type); if (layer_index == -1) { return nullptr; @@ -4224,23 +4162,6 @@ void CustomData_bmesh_set_n( } } -void CustomData_bmesh_set_layer_n(CustomData *data, void *block, const int n, const void *source) -{ - void *dest = CustomData_bmesh_get_layer_n(data, block, n); - const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); - - if (!dest) { - return; - } - - if (typeInfo->copy) { - typeInfo->copy(source, dest, 1); - } - else { - memcpy(dest, source, typeInfo->size); - } -} - void CustomData_bmesh_interp_n(CustomData *data, const void **src_blocks_ofs, const float *weights, @@ -4663,30 +4584,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons return false; } -void CustomData_layers__print(CustomData *data) -{ - printf("{\n"); - - int i; - const CustomDataLayer *layer; - for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) { - const char *name = CustomData_layertype_name(layer->type); - const int size = CustomData_sizeof(layer->type); - const char *structname; - int structnum; - CustomData_file_write_info(layer->type, &structname, &structnum); - printf(" dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, - structname, - layer->type, - (const void *)layer->data, - size, - (int)(MEM_allocN_len(layer->data) / size)); - } - - printf("}\n"); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -5370,7 +5267,7 @@ static void blend_read_mdisps(BlendDataReader *reader, * overwritten with the correct value in * bm_corners_to_loops() */ float gridsize = sqrtf(mdisps[i].totdisp); - mdisps[i].level = (int)(logf(gridsize - 1.0f) / (float)M_LN2) + 1; + mdisps[i].level = int(logf(gridsize - 1.0f) / float(M_LN2)) + 1; } if (BLO_read_requires_endian_switch(reader) && (mdisps[i].disps)) { diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.cc index a952da6fa52..34218abf200 100644 --- a/source/blender/blenkernel/intern/editmesh.c +++ b/source/blender/blenkernel/intern/editmesh.cc @@ -28,14 +28,14 @@ BMEditMesh *BKE_editmesh_create(BMesh *bm) { - BMEditMesh *em = MEM_callocN(sizeof(BMEditMesh), __func__); + BMEditMesh *em = MEM_cnew<BMEditMesh>(__func__); em->bm = bm; return em; } BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) { - BMEditMesh *em_copy = MEM_callocN(sizeof(BMEditMesh), __func__); + BMEditMesh *em_copy = MEM_cnew<BMEditMesh>(__func__); *em_copy = *em; em_copy->bm = BM_mesh_copy(em->bm); @@ -46,7 +46,7 @@ BMEditMesh *BKE_editmesh_copy(BMEditMesh *em) * it in the case of errors in an operation. For performance reasons, * in that case it makes more sense to do the * tessellation only when/if that copy ends up getting used. */ - em_copy->looptris = NULL; + em_copy->looptris = nullptr; /* Copy various settings. */ em_copy->selectmode = em->selectmode; @@ -59,7 +59,7 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob) { BLI_assert(ob->type == OB_MESH); /* sanity check */ -#if 0 /* disable in mutlti-object edit. */ +#if 0 /* disable in multi-object edit. */ # ifndef NDEBUG if (((Mesh *)ob->data)->edit_mesh) { BLI_assert(((Mesh *)ob->data)->edit_mesh->ob == ob); @@ -70,7 +70,7 @@ BMEditMesh *BKE_editmesh_from_object(Object *ob) } static void editmesh_tessface_calc_intern(BMEditMesh *em, - const struct BMeshCalcTessellation_Params *params) + const BMeshCalcTessellation_Params *params) { /* allocating space before calculating the tessellation */ @@ -85,9 +85,9 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em, BMLoop *(*looptris)[3]; - /* this means no reallocs for quad dominant models, for */ - if ((em->looptris != NULL) && - /* (*em->tottri >= looptris_tot)) */ + /* This means no reallocations for quad dominant models. */ + if ((em->looptris != nullptr) && + // (*em->tottri >= looptris_tot)) /* Check against allocated size in case we over allocated a little. */ ((looptris_tot_prev_alloc >= looptris_tot) && (looptris_tot_prev_alloc <= looptris_tot * 2))) { @@ -97,7 +97,8 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em, if (em->looptris) { MEM_freeN(em->looptris); } - looptris = MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__); + looptris = static_cast<BMLoop *(*)[3]>( + MEM_mallocN(sizeof(*looptris) * looptris_tot, __func__)); } em->looptris = looptris; @@ -107,8 +108,7 @@ static void editmesh_tessface_calc_intern(BMEditMesh *em, BM_mesh_calc_tessellation_ex(em->bm, em->looptris, params); } -void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, - const struct BMeshCalcTessellation_Params *params) +void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, const BMeshCalcTessellation_Params *params) { editmesh_tessface_calc_intern(em, params); @@ -126,56 +126,46 @@ void BKE_editmesh_looptri_calc_ex(BMEditMesh *em, void BKE_editmesh_looptri_calc(BMEditMesh *em) { - BKE_editmesh_looptri_calc_ex(em, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = false, - }); + BMeshCalcTessellation_Params params{}; + params.face_normals = false; + BKE_editmesh_looptri_calc_ex(em, ¶ms); } void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em) { - BKE_editmesh_looptri_calc_ex(em, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = true, - }); - BM_mesh_normals_update_ex(em->bm, - &(const struct BMeshNormalsUpdate_Params){ - .face_normals = false, - }); + BMeshCalcTessellation_Params looptri_params{}; + looptri_params.face_normals = true; + BKE_editmesh_looptri_calc_ex(em, &looptri_params); + BMeshNormalsUpdate_Params normals_params{}; + normals_params.face_normals = false; + BM_mesh_normals_update_ex(em->bm, &normals_params); } void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em, - struct BMPartialUpdate *bmpinfo, - const struct BMeshCalcTessellation_Params *params) + BMPartialUpdate *bmpinfo, + const BMeshCalcTessellation_Params *params) { BLI_assert(em->tottri == poly_to_tri_count(em->bm->totface, em->bm->totloop)); - BLI_assert(em->looptris != NULL); + BLI_assert(em->looptris != nullptr); BM_mesh_calc_tessellation_with_partial_ex(em->bm, em->looptris, bmpinfo, params); } -void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, struct BMPartialUpdate *bmpinfo) +void BKE_editmesh_looptri_calc_with_partial(BMEditMesh *em, BMPartialUpdate *bmpinfo) { - BKE_editmesh_looptri_calc_with_partial_ex(em, - bmpinfo, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = false, - }); + BMeshCalcTessellation_Params looptri_params{}; + looptri_params.face_normals = false; + BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, &looptri_params); } -void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, - struct BMPartialUpdate *bmpinfo) +void BKE_editmesh_looptri_and_normals_calc_with_partial(BMEditMesh *em, BMPartialUpdate *bmpinfo) { - BKE_editmesh_looptri_calc_with_partial_ex(em, - bmpinfo, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = true, - }); - BM_mesh_normals_update_with_partial_ex(em->bm, - bmpinfo, - &(const struct BMeshNormalsUpdate_Params){ - .face_normals = false, - }); + BMeshCalcTessellation_Params looptri_params{}; + looptri_params.face_normals = true; + BKE_editmesh_looptri_calc_with_partial_ex(em, bmpinfo, &looptri_params); + BMeshNormalsUpdate_Params normals_params{}; + normals_params.face_normals = false; + BM_mesh_normals_update_with_partial_ex(em->bm, bmpinfo, &normals_params); } void BKE_editmesh_free_data(BMEditMesh *em) @@ -201,7 +191,7 @@ static void cage_mapped_verts_callback(void *userData, const float co[3], const float UNUSED(no[3])) { - struct CageUserData *data = userData; + CageUserData *data = static_cast<CageUserData *>(userData); if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) { BLI_BITMAP_ENABLE(data->visit_bitmap, index); @@ -209,20 +199,18 @@ static void cage_mapped_verts_callback(void *userData, } } -float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, - BMEditMesh *em, - struct Scene *scene, - Object *ob, - int *r_vert_len))[3] +float (*BKE_editmesh_vert_coords_alloc( + Depsgraph *depsgraph, BMEditMesh *em, Scene *scene, Object *ob, int *r_vert_len))[3] { Mesh *cage = editbmesh_get_eval_cage(depsgraph, scene, ob, em, &CD_MASK_BAREMESH); - float(*cos_cage)[3] = MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, "bmbvh cos_cage"); + float(*cos_cage)[3] = static_cast<float(*)[3]>( + MEM_callocN(sizeof(*cos_cage) * em->bm->totvert, __func__)); /* When initializing cage verts, we only want the first cage coordinate for each vertex, * so that e.g. mirror or array use original vertex coordinates and not mirrored or duplicate. */ BLI_bitmap *visit_bitmap = BLI_BITMAP_NEW(em->bm->totvert, __func__); - struct CageUserData data; + CageUserData data; data.totvert = em->bm->totvert; data.cos_cage = cos_cage; data.visit_bitmap = visit_bitmap; @@ -238,27 +226,27 @@ float (*BKE_editmesh_vert_coords_alloc(struct Depsgraph *depsgraph, return cos_cage; } -const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph, +const float (*BKE_editmesh_vert_coords_when_deformed(Depsgraph *depsgraph, BMEditMesh *em, - struct Scene *scene, + Scene *scene, Object *ob, int *r_vert_len, bool *r_is_alloc))[3] { - const float(*coords)[3] = NULL; + const float(*coords)[3] = nullptr; *r_is_alloc = false; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object_eval); - if ((me->runtime.edit_data != NULL) && (me->runtime.edit_data->vertexCos != NULL)) { + if ((me->runtime.edit_data != nullptr) && (me->runtime.edit_data->vertexCos != nullptr)) { /* Deformed, and we have deformed coords already. */ coords = me->runtime.edit_data->vertexCos; } - else if ((editmesh_eval_final != NULL) && + else if ((editmesh_eval_final != nullptr) && (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH)) { - /* If this is an edit-mesh type, leave NULL as we can use the vertex coords. */ + /* If this is an edit-mesh type, leave nullptr as we can use the vertex coords. */ } else { /* Constructive modifiers have been used, we need to allocate coordinates. */ @@ -302,16 +290,16 @@ void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me) } } -BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *UNUSED(em)) +BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh *UNUSED(em)) { - if (object->runtime.editmesh_bb_cage == NULL) { + if (object->runtime.editmesh_bb_cage == nullptr) { float min[3], max[3]; INIT_MINMAX(min, max); if (object->runtime.editmesh_eval_cage) { BKE_mesh_wrapper_minmax(object->runtime.editmesh_eval_cage, min, max); } - object->runtime.editmesh_bb_cage = MEM_callocN(sizeof(BoundBox), "BMEditMesh.bb_cage"); + object->runtime.editmesh_bb_cage = MEM_cnew<BoundBox>("BMEditMesh.bb_cage"); BKE_boundbox_init_from_minmax(object->runtime.editmesh_bb_cage, min, max); } diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc index 56e9e9dcdff..e242154cb5b 100644 --- a/source/blender/blenkernel/intern/geometry_fields.cc +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -157,6 +157,12 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte return {}; } +std::optional<eAttrDomain> GeometryFieldInput::preferred_domain( + const GeometryComponent & /*component*/) const +{ + return std::nullopt; +} + GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context, const IndexMask mask, ResourceScope & /*scope*/) const @@ -173,6 +179,11 @@ GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context, return {}; } +std::optional<eAttrDomain> MeshFieldInput::preferred_domain(const Mesh & /*mesh*/) const +{ + return std::nullopt; +} + GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope & /*scope*/) const @@ -190,6 +201,12 @@ GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context return {}; } +std::optional<eAttrDomain> CurvesFieldInput::preferred_domain( + const CurvesGeometry & /*curves*/) const +{ + return std::nullopt; +} + GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope & /*scope*/) const @@ -254,6 +271,20 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } +std::optional<eAttrDomain> AttributeFieldInput::preferred_domain( + const GeometryComponent &component) const +{ + const std::optional<AttributeAccessor> attributes = component.attributes(); + if (!attributes.has_value()) { + return std::nullopt; + } + const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data(name_); + if (!meta_data.has_value()) { + return std::nullopt; + } + return meta_data->domain; +} + static StringRef get_random_id_attribute_name(const eAttrDomain domain) { switch (domain) { @@ -325,6 +356,21 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return false; } +std::optional<eAttrDomain> AnonymousAttributeFieldInput::preferred_domain( + const GeometryComponent &component) const +{ + const std::optional<AttributeAccessor> attributes = component.attributes(); + if (!attributes.has_value()) { + return std::nullopt; + } + const std::optional<AttributeMetaData> meta_data = attributes->lookup_meta_data( + anonymous_id_.get()); + if (!meta_data.has_value()) { + return std::nullopt; + } + return meta_data->domain; +} + } // namespace blender::bke /* -------------------------------------------------------------------- */ @@ -360,6 +406,131 @@ bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const return dynamic_cast<const NormalFieldInput *>(&other) != nullptr; } +bool try_capture_field_on_geometry(GeometryComponent &component, + const AttributeIDRef &attribute_id, + const eAttrDomain domain, + const fn::GField &field) +{ + MutableAttributeAccessor attributes = *component.attributes_for_write(); + const int domain_size = attributes.domain_size(domain); + const CPPType &type = field.cpp_type(); + const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); + + if (domain_size == 0) { + return attributes.add(attribute_id, domain, data_type, AttributeInitConstruct{}); + } + + bke::GeometryFieldContext field_context{component, domain}; + const IndexMask mask{IndexMask(domain_size)}; + const bke::AttributeValidator validator = attributes.lookup_validator(attribute_id); + + /* Could avoid allocating a new buffer if: + * - We are writing to an attribute that exists already with the correct domain and type. + * - The field does not depend on that attribute (we can't easily check for that yet). */ + void *buffer = MEM_mallocN(type.size() * domain_size, __func__); + + fn::FieldEvaluator evaluator{field_context, &mask}; + evaluator.add_with_destination(validator.validate_field_if_necessary(field), + GMutableSpan{type, buffer, domain_size}); + evaluator.evaluate(); + + if (GAttributeWriter attribute = attributes.lookup_for_write(attribute_id)) { + if (attribute.domain == domain && attribute.varray.type() == type) { + attribute.varray.set_all(buffer); + attribute.finish(); + type.destruct_n(buffer, domain_size); + MEM_freeN(buffer); + return true; + } + } + attributes.remove(attribute_id); + if (attributes.add(attribute_id, domain, data_type, bke::AttributeInitMoveArray{buffer})) { + return true; + } + + /* If the name corresponds to a builtin attribute, removing the attribute might fail if + * it's required, and adding the attribute might fail if the domain or type is incorrect. */ + type.destruct_n(buffer, domain_size); + MEM_freeN(buffer); + return false; +} + +std::optional<eAttrDomain> try_detect_field_domain(const GeometryComponent &component, + const fn::GField &field) +{ + const GeometryComponentType component_type = component.type(); + if (component_type == GEO_COMPONENT_TYPE_POINT_CLOUD) { + return ATTR_DOMAIN_POINT; + } + if (component_type == GEO_COMPONENT_TYPE_INSTANCES) { + return ATTR_DOMAIN_INSTANCE; + } + const std::shared_ptr<const fn::FieldInputs> &field_inputs = field.node().field_inputs(); + if (!field_inputs) { + return std::nullopt; + } + std::optional<eAttrDomain> output_domain; + auto handle_domain = [&](const std::optional<eAttrDomain> domain) { + if (!domain.has_value()) { + return false; + } + if (output_domain.has_value()) { + if (*output_domain != *domain) { + return false; + } + return true; + } + output_domain = domain; + return true; + }; + if (component_type == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return std::nullopt; + } + for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) { + if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) { + if (!handle_domain(geometry_field_input->preferred_domain(component))) { + return std::nullopt; + } + } + else if (auto mesh_field_input = dynamic_cast<const MeshFieldInput *>(&field_input)) { + if (!handle_domain(mesh_field_input->preferred_domain(*mesh))) { + return std::nullopt; + } + } + else { + return std::nullopt; + } + } + } + if (component_type == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const Curves *curves = curve_component.get_for_read(); + if (curves == nullptr) { + return std::nullopt; + } + for (const fn::FieldInput &field_input : field_inputs->deduplicated_nodes) { + if (auto geometry_field_input = dynamic_cast<const GeometryFieldInput *>(&field_input)) { + if (!handle_domain(geometry_field_input->preferred_domain(component))) { + return std::nullopt; + } + } + else if (auto curves_field_input = dynamic_cast<const CurvesFieldInput *>(&field_input)) { + if (!handle_domain( + curves_field_input->preferred_domain(CurvesGeometry::wrap(curves->geometry)))) { + return std::nullopt; + } + } + else { + return std::nullopt; + } + } + } + return output_domain; +} + } // namespace blender::bke /** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index 9738e9bb57b..c9245c5ca2c 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -3856,7 +3856,7 @@ static int generate_arc_from_point_to_point(ListBase *list, /* Number of points is 2^(n+1) + 1 on half a circle (n=subdivisions) * so we multiply by (angle / pi) to get the right amount of * points to insert. */ - int num_points = (int)(((1 << (subdivisions + 1)) - 1) * (angle / M_PI)); + int num_points = int(((1 << (subdivisions + 1)) - 1) * (angle / M_PI)); if (num_points > 0) { float angle_incr = angle / float(num_points); diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.cc index dd10a6f8646..00778ce2d79 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -46,44 +46,52 @@ /* Data types */ -typedef struct corner { /* corner of a cube */ - int i, j, k; /* (i, j, k) is index within lattice */ - float co[3], value; /* location and function value */ +/** Corner of a cube. */ +typedef struct corner { + int i, j, k; /* (i, j, k) is index within lattice */ + float co[3], value; /* location and function value */ struct corner *next; } CORNER; -typedef struct cube { /* partitioning cell (cube) */ +/** Partitioning cell (cube). */ +typedef struct cube { int i, j, k; /* lattice location of cube */ CORNER *corners[8]; /* eight corners */ } CUBE; -typedef struct cubes { /* linked list of cubes acting as stack */ - CUBE cube; /* a single cube */ - struct cubes *next; /* remaining elements */ +/** Linked list of cubes acting as stack. */ +typedef struct cubes { + CUBE cube; /* a single cube */ + struct cubes *next; /* remaining elements */ } CUBES; -typedef struct centerlist { /* list of cube locations */ - int i, j, k; /* cube location */ - struct centerlist *next; /* remaining elements */ +/** List of cube locations. */ +typedef struct centerlist { + int i, j, k; /* cube location */ + struct centerlist *next; /* remaining elements */ } CENTERLIST; -typedef struct edgelist { /* list of edges */ +/** List of edges. */ +typedef struct edgelist { int i1, j1, k1, i2, j2, k2; /* edge corner ids */ int vid; /* vertex id */ struct edgelist *next; /* remaining elements */ } EDGELIST; -typedef struct intlist { /* list of integers */ - int i; /* an integer */ - struct intlist *next; /* remaining elements */ +/** List of integers. */ +typedef struct intlist { + int i; /* an integer */ + struct intlist *next; /* remaining elements */ } INTLIST; -typedef struct intlists { /* list of list of integers */ - INTLIST *list; /* a list of integers */ - struct intlists *next; /* remaining elements */ +/** List of list of integers. */ +typedef struct intlists { + INTLIST *list; /* a list of integers */ + struct intlists *next; /* remaining elements */ } INTLISTS; -typedef struct Box { /* an AABB with pointer to metalelem */ +/** An AABB with pointer to metal-elem. */ +typedef struct Box { float min[3], max[3]; const MetaElem *ml; } Box; @@ -93,16 +101,17 @@ typedef struct MetaballBVHNode { /* BVH node */ struct MetaballBVHNode *child[2]; } MetaballBVHNode; -typedef struct process { /* parameters, storage */ - float thresh, size; /* mball threshold, single cube size */ - float delta; /* small delta for calculating normals */ - uint converge_res; /* converge procedure resolution (more = slower) */ +/** Parameters, storage. */ +typedef struct process { + float thresh, size; /* mball threshold, single cube size */ + float delta; /* small delta for calculating normals */ + uint converge_res; /* converge procedure resolution (more = slower) */ - MetaElem **mainb; /* array of all metaelems */ - uint totelem, mem; /* number of metaelems */ + MetaElem **mainb; /* array of all meta-elems. */ + uint totelem, mem; /* number of meta-elems. */ MetaballBVHNode metaball_bvh; /* The simplest bvh */ - Box allbb; /* Bounding box of all metaelems */ + Box allbb; /* Bounding box of all meta-elems */ MetaballBVHNode **bvh_queue; /* Queue used during bvh traversal */ uint bvh_queue_size; @@ -220,7 +229,8 @@ static void build_bvh_spatial( make_box_union(process->mainb[j]->bb, &node->bb[0], &node->bb[0]); } - node->child[0] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode)); + node->child[0] = static_cast<MetaballBVHNode *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode))); build_bvh_spatial(process, node->child[0], start, part, &node->bb[0]); } @@ -233,7 +243,8 @@ static void build_bvh_spatial( make_box_union(process->mainb[j]->bb, &node->bb[1], &node->bb[1]); } - node->child[1] = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode)); + node->child[1] = static_cast<MetaballBVHNode *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(MetaballBVHNode))); build_bvh_spatial(process, node->child[1], part, end, &node->bb[1]); } } @@ -279,7 +290,7 @@ static void build_bvh_spatial( #define HASHBIT (5) /** Hash table size (32768). */ -#define HASHSIZE (size_t)(1 << (3 * HASHBIT)) +#define HASHSIZE size_t(1 << (3 * HASHBIT)) #define HASH(i, j, k) ((((((i)&31) << 5) | ((j)&31)) << 5) | ((k)&31)) @@ -432,7 +443,8 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) if (UNLIKELY(process->totindex == process->curindex)) { process->totindex = process->totindex ? (process->totindex * 2) : MBALL_ARRAY_LEN_INIT; - process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex); + process->indices = static_cast<int(*)[4]>( + MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex)); } int *cur = process->indices[process->curindex++]; @@ -671,14 +683,14 @@ static CORNER *setcorner(PROCESS *process, int i, int j, int k) } } - c = BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER)); + c = static_cast<CORNER *>(BLI_memarena_alloc(process->pgn_elements, sizeof(CORNER))); c->i = i; - c->co[0] = ((float)i - 0.5f) * process->size; + c->co[0] = (float(i) - 0.5f) * process->size; c->j = j; - c->co[1] = ((float)j - 0.5f) * process->size; + c->co[1] = (float(j) - 0.5f) * process->size; c->k = k; - c->co[2] = ((float)k - 0.5f) * process->size; + c->co[2] = (float(k) - 0.5f) * process->size; c->value = metaball(process, c->co[0], c->co[1], c->co[2]); @@ -754,7 +766,7 @@ static void makecubetable(void) for (e = 0; e < 12; e++) { if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) { INTLIST *ints = NULL; - INTLISTS *lists = MEM_callocN(sizeof(INTLISTS), "mball_intlist"); + INTLISTS *lists = static_cast<INTLISTS *>(MEM_callocN(sizeof(INTLISTS), "mball_intlist")); int start = e, edge = e; /* get face that is to right of edge from pos to neg corner: */ @@ -766,7 +778,7 @@ static void makecubetable(void) if (pos[corner1[edge]] != pos[corner2[edge]]) { INTLIST *tmp = ints; - ints = MEM_callocN(sizeof(INTLIST), "mball_intlist"); + ints = static_cast<INTLIST *>(MEM_callocN(sizeof(INTLIST), "mball_intlist")); ints->i = edge; ints->next = tmp; /* add edge to head of list */ @@ -853,7 +865,7 @@ static int setcenter(PROCESS *process, CENTERLIST *table[], const int i, const i } } - newc = BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST)); + newc = static_cast<CENTERLIST *>(BLI_memarena_alloc(process->pgn_elements, sizeof(CENTERLIST))); newc->i = i; newc->j = j; newc->k = k; @@ -883,7 +895,7 @@ static void setedge(PROCESS *process, int i1, int j1, int k1, int i2, int j2, in k2 = t; } index = HASH(i1, j1, k1) + HASH(i2, j2, k2); - newe = BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST)); + newe = static_cast<EDGELIST *>(BLI_memarena_alloc(process->pgn_elements, sizeof(EDGELIST))); newe->i1 = i1; newe->j1 = j1; @@ -930,8 +942,10 @@ static void addtovertices(PROCESS *process, const float v[3], const float no[3]) { if (UNLIKELY(process->curvertex == process->totvertex)) { process->totvertex = process->totvertex ? process->totvertex * 2 : MBALL_ARRAY_LEN_INIT; - process->co = MEM_reallocN(process->co, process->totvertex * sizeof(float[3])); - process->no = MEM_reallocN(process->no, process->totvertex * sizeof(float[3])); + process->co = static_cast<float(*)[3]>( + MEM_reallocN(process->co, process->totvertex * sizeof(float[3]))); + process->no = static_cast<float(*)[3]>( + MEM_reallocN(process->no, process->totvertex * sizeof(float[3]))); } copy_v3_v3(process->co[process->curvertex], v); @@ -980,7 +994,7 @@ static int vertid(PROCESS *process, const CORNER *c1, const CORNER *c2) #endif addtovertices(process, v, no); /* save vertex */ - vid = (int)process->curvertex - 1; + vid = int(process->curvertex) - 1; setedge(process, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid); return vid; @@ -1037,7 +1051,7 @@ static void add_cube(PROCESS *process, int i, int j, int k) /* test if cube has been found before */ if (setcenter(process, process->centers, i, j, k) == 0) { /* push cube on stack: */ - ncube = BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES)); + ncube = static_cast<CUBES *>(BLI_memarena_alloc(process->pgn_elements, sizeof(CUBES))); ncube->next = process->cubes; process->cubes = ncube; @@ -1055,9 +1069,9 @@ static void add_cube(PROCESS *process, int i, int j, int k) static void next_lattice(int r[3], const float pos[3], const float size) { - r[0] = (int)ceil((pos[0] / size) + 0.5f); - r[1] = (int)ceil((pos[1] / size) + 0.5f); - r[2] = (int)ceil((pos[2] / size) + 0.5f); + r[0] = int(ceil((pos[0] / size) + 0.5f)); + r[1] = int(ceil((pos[1] / size) + 0.5f)); + r[2] = int(ceil((pos[2] / size) + 0.5f)); } static void prev_lattice(int r[3], const float pos[3], const float size) { @@ -1068,9 +1082,9 @@ static void prev_lattice(int r[3], const float pos[3], const float size) } static void closest_latice(int r[3], const float pos[3], const float size) { - r[0] = (int)floorf(pos[0] / size + 1.0f); - r[1] = (int)floorf(pos[1] / size + 1.0f); - r[2] = (int)floorf(pos[2] / size + 1.0f); + r[0] = int(floorf(pos[0] / size + 1.0f)); + r[1] = int(floorf(pos[1] / size + 1.0f)); + r[2] = int(floorf(pos[2] / size + 1.0f)); } /** @@ -1122,8 +1136,8 @@ static void find_first_points(PROCESS *process, const uint em) } /** - * The main polygonization proc. - * Allocates memory, makes cubetable, + * The main polygonization processing function. + * Allocates memory, makes cube-table, * finds starting surface points * and processes cubes on the stack until none left. */ @@ -1131,11 +1145,14 @@ static void polygonize(PROCESS *process) { CUBE c; - process->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers"); - process->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners"); - process->edges = MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges"); - process->bvh_queue = MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, - "Metaball BVH Queue"); + process->centers = static_cast<CENTERLIST **>( + MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers")); + process->corners = static_cast<CORNER **>( + MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners")); + process->edges = static_cast<EDGELIST **>( + MEM_callocN(2 * HASHSIZE * sizeof(EDGELIST *), "mbproc->edges")); + process->bvh_queue = static_cast<MetaballBVHNode **>( + MEM_callocN(sizeof(MetaballBVHNode *) * process->bvh_queue_size, "Metaball BVH Queue")); makecubetable(); @@ -1192,13 +1209,13 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje } if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { - mb = ob->data; + mb = static_cast<MetaBall *>(ob->data); if (mb->editelems) { - ml = mb->editelems->first; + ml = static_cast<const MetaElem *>(mb->editelems->first); } else { - ml = mb->elems.first; + ml = static_cast<const MetaElem *>(mb->elems.first); } } else { @@ -1207,13 +1224,13 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje BLI_split_name_num(name, &nr, bob->id.name + 2, '.'); if (STREQ(obname, name)) { - mb = bob->data; + mb = static_cast<MetaBall *>(bob->data); if (mb->editelems) { - ml = mb->editelems->first; + ml = static_cast<const MetaElem *>(mb->editelems->first); } else { - ml = mb->elems.first; + ml = static_cast<const MetaElem *>(mb->elems.first); } } } @@ -1249,11 +1266,15 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje MetaElem *new_ml; /* make a copy because of duplicates */ - new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)); + new_ml = static_cast<MetaElem *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem))); *(new_ml) = *ml; - new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)); - new_ml->mat = BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])); - new_ml->imat = BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4])); + new_ml->bb = static_cast<BoundBox *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox))); + new_ml->mat = static_cast<float *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4]))); + new_ml->imat = static_cast<float *>( + BLI_memarena_alloc(process->pgn_elements, sizeof(float[4][4]))); /* too big stiffness seems only ugly due to linear interpolation * no need to have possibility for too big stiffness */ @@ -1329,25 +1350,26 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */ - /* transformation of Metalem bb */ + /* Transformation of meta-elem bounding-box. */ for (i = 0; i < 8; i++) { mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]); } - /* find max and min of transformed bb */ + /* Find max and min of transformed bounding-box. */ INIT_MINMAX(tempmin, tempmax); for (i = 0; i < 8; i++) { DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax); } - /* set only point 0 and 6 - AABB of Metaelem */ + /* Set only point 0 and 6 - AABB of meta-elem. */ copy_v3_v3(new_ml->bb->vec[0], tempmin); copy_v3_v3(new_ml->bb->vec[6], tempmax); /* add new_ml to mainb[] */ if (UNLIKELY(process->totelem == process->mem)) { process->mem = process->mem * 2 + 10; - process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); + process->mainb = static_cast<MetaElem **>( + MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem)); } process->mainb[process->totelem++] = new_ml; } @@ -1357,7 +1379,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje } } - /* compute AABB of all Metaelems */ + /* Compute AABB of all meta-elems. */ if (process->totelem > 0) { copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); @@ -1372,7 +1394,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) PROCESS process = {0}; const bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; - MetaBall *mb = ob->data; + MetaBall *mb = static_cast<MetaBall *>(ob->data); process.thresh = mb->thresh; @@ -1419,8 +1441,8 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); - /* Don't polygonize meta-balls with too high resolution (base mball too small) - * NOTE: Eps was 0.0001f but this was giving problems for blood animation for + /* Don't polygonize meta-balls with too high resolution (base meta-ball too small). + * NOTE: Epsilon was 0.0001f but this was giving problems for blood animation for * the open movie "Sintel", using 0.00001f. */ if (ob->scale[0] < 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || ob->scale[1] < 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || @@ -1444,10 +1466,11 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) &mesh->vdata, CD_PROP_FLOAT3, CD_ASSIGN, process.co, mesh->totvert, "position"); process.co = NULL; - mesh->totpoly = (int)process.curindex; - MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, NULL, mesh->totpoly); - MLoop *mloop = CustomData_add_layer( - &mesh->ldata, CD_MLOOP, CD_CONSTRUCT, NULL, mesh->totpoly * 4); + mesh->totpoly = int(process.curindex); + MPoly *mpoly = static_cast<MPoly *>( + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, NULL, mesh->totpoly)); + MLoop *mloop = static_cast<MLoop *>( + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CONSTRUCT, NULL, mesh->totpoly * 4)); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { @@ -1458,11 +1481,11 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) mpoly[i].totloop = count; mpoly[i].flag = ME_SMOOTH; - mloop[loop_offset].v = (uint32_t)indices[0]; - mloop[loop_offset + 1].v = (uint32_t)indices[1]; - mloop[loop_offset + 2].v = (uint32_t)indices[2]; + mloop[loop_offset].v = uint32_t(indices[0]); + mloop[loop_offset + 1].v = uint32_t(indices[1]); + mloop[loop_offset + 2].v = uint32_t(indices[2]); if (count == 4) { - mloop[loop_offset + 3].v = (uint32_t)indices[3]; + mloop[loop_offset + 3].v = uint32_t(indices[3]); } loop_offset += count; diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 2fec68932b0..7095c6232c8 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -499,7 +499,7 @@ static int customdata_compare( } if (layer_count1 != layer_count2) { - /* TODO(@HooglyBoogly): Reenable after tests are updated for material index refactor. */ + /* TODO(@HooglyBoogly): Re-enable after tests are updated for material index refactor. */ // return MESHCMP_CDLAYERS_MISMATCH; } diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index 1a219c0b83e..2647b3b4990 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" #include "eigen_capi.h" +using blender::Array; using blender::float3; using blender::Map; using blender::MutableSpan; @@ -221,12 +222,7 @@ class MeshFairingContext : public FairingContext { } } - loop_to_poly_map_.reserve(mesh->totloop); - for (int i = 0; i < mesh->totpoly; i++) { - for (int l = 0; l < mpoly_[i].totloop; l++) { - loop_to_poly_map_[l + mpoly_[i].loopstart] = i; - } - } + loop_to_poly_map_ = blender::mesh_topology::build_corner_to_poly_map(mpoly_, mloop_.size()); } ~MeshFairingContext() override @@ -260,7 +256,7 @@ class MeshFairingContext : public FairingContext { Span<MLoop> mloop_; Span<MPoly> mpoly_; Span<MEdge> medge_; - Vector<int> loop_to_poly_map_; + Array<int> loop_to_poly_map_; }; class BMeshFairingContext : public FairingContext { diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.cc index 50a27836c74..d983cc440b3 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.c +++ b/source/blender/blenkernel/intern/mesh_iterators.cc @@ -36,13 +36,13 @@ void BKE_mesh_foreach_mapped_vert( void *userData, MeshForeachFlag flag) { - if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) { + if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMVert *eve; int i; - if (mesh->runtime.edit_data->vertexCos != NULL) { + if (mesh->runtime.edit_data->vertexCos != nullptr) { const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; const float(*vertexNos)[3]; if (flag & MESH_FOREACH_USE_NORMAL) { @@ -50,30 +50,30 @@ void BKE_mesh_foreach_mapped_vert( vertexNos = mesh->runtime.edit_data->vertexNos; } else { - vertexNos = NULL; + vertexNos = nullptr; } BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : nullptr; func(userData, i, vertexCos[i], no); } } else { BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : nullptr; func(userData, i, eve->co, no); } } } else { const float(*positions)[3] = BKE_mesh_positions(mesh); - const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)); const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? BKE_mesh_vertex_normals_ensure(mesh) : - NULL; + nullptr; if (index) { for (int i = 0; i < mesh->totvert; i++) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; const int orig = *index++; if (orig == ORIGINDEX_NONE) { continue; @@ -83,7 +83,7 @@ void BKE_mesh_foreach_mapped_vert( } else { for (int i = 0; i < mesh->totvert; i++) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; func(userData, i, positions[i], no); } } @@ -96,13 +96,13 @@ void BKE_mesh_foreach_mapped_edge( void (*func)(void *userData, int index, const float v0co[3], const float v1co[3]), void *userData) { - if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) { + if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; BMEdge *eed; int i; - if (mesh->runtime.edit_data->vertexCos != NULL) { + if (mesh->runtime.edit_data->vertexCos != nullptr) { const float(*vertexCos)[3] = mesh->runtime.edit_data->vertexCos; BM_mesh_elem_index_ensure(bm, BM_VERT); @@ -122,7 +122,7 @@ void BKE_mesh_foreach_mapped_edge( else { const float(*positions)[3] = BKE_mesh_positions(mesh); const MEdge *med = BKE_mesh_edges(mesh); - const int *index = CustomData_get_layer(&mesh->edata, CD_ORIGINDEX); + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->edata, CD_ORIGINDEX)); if (index) { for (int i = 0; i < mesh->totedge; i++, med++) { @@ -151,10 +151,10 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, MeshForeachFlag flag) { - /* We can't use dm->getLoopDataLayout(dm) here, - * we want to always access dm->loopData, EditDerivedBMesh would - * return loop data from bmesh itself. */ - if (mesh->edit_mesh != NULL && mesh->runtime.edit_data) { + /* We can't use `dm->getLoopDataLayout(dm)` here, + * we want to always access `dm->loopData`, `EditDerivedBMesh` would + * return loop data from BMesh itself. */ + if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; BMIter iter; @@ -164,8 +164,9 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, /* XXX: investigate using EditMesh data. */ const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? - CustomData_get_layer(&mesh->ldata, CD_NORMAL) : - NULL; + static_cast<const float(*)[3]>( + CustomData_get_layer(&mesh->ldata, CD_NORMAL)) : + nullptr; int f_idx; @@ -178,21 +179,24 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, do { const BMVert *eve = l_iter->v; const int v_idx = BM_elem_index_get(eve); - const float *no = lnors ? *lnors++ : NULL; + const float *no = lnors ? *lnors++ : nullptr; func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no); } while ((l_iter = l_iter->next) != l_first); } } else { const float(*lnors)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? - CustomData_get_layer(&mesh->ldata, CD_NORMAL) : - NULL; + static_cast<const float(*)[3]>( + CustomData_get_layer(&mesh->ldata, CD_NORMAL)) : + nullptr; const float(*positions)[3] = BKE_mesh_positions(mesh); const MLoop *ml = BKE_mesh_loops(mesh); const MPoly *mp = BKE_mesh_polys(mesh); - const int *v_index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX); - const int *f_index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + const int *v_index = static_cast<const int *>( + CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)); + const int *f_index = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); int p_idx, i; if (v_index || f_index) { @@ -200,7 +204,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, for (i = 0; i < mp->totloop; i++, ml++) { const int v_idx = v_index ? v_index[ml->v] : ml->v; const int f_idx = f_index ? f_index[p_idx] : p_idx; - const float *no = lnors ? *lnors++ : NULL; + const float *no = lnors ? *lnors++ : nullptr; if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { continue; } @@ -213,7 +217,7 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh, for (i = 0; i < mp->totloop; i++, ml++) { const int v_idx = ml->v; const int f_idx = p_idx; - const float *no = lnors ? *lnors++ : NULL; + const float *no = lnors ? *lnors++ : nullptr; func(userData, v_idx, f_idx, positions[ml->v], no); } } @@ -227,7 +231,7 @@ void BKE_mesh_foreach_mapped_face_center( void *userData, MeshForeachFlag flag) { - if (mesh->edit_mesh != NULL && mesh->runtime.edit_data != NULL) { + if (mesh->edit_mesh != nullptr && mesh->runtime.edit_data != nullptr) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; const float(*polyCos)[3]; @@ -241,10 +245,10 @@ void BKE_mesh_foreach_mapped_face_center( if (flag & MESH_FOREACH_USE_NORMAL) { BKE_editmesh_cache_ensure_poly_normals(em, mesh->runtime.edit_data); - polyNos = mesh->runtime.edit_data->polyNos; /* maybe NULL */ + polyNos = mesh->runtime.edit_data->polyNos; /* maybe nullptr */ } else { - polyNos = NULL; + polyNos = nullptr; } if (polyNos) { @@ -255,7 +259,7 @@ void BKE_mesh_foreach_mapped_face_center( } else { BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : NULL; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? efa->no : nullptr; func(userData, i, polyCos[i], no); } } @@ -266,8 +270,8 @@ void BKE_mesh_foreach_mapped_face_center( const MLoop *loops = BKE_mesh_loops(mesh); const MLoop *ml; float _no_buf[3]; - float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL; - const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : nullptr; + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); if (index) { for (int i = 0; i < mesh->totpoly; i++, mp++) { @@ -310,10 +314,10 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( const MLoop *ml; const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? BKE_mesh_vertex_normals_ensure(mesh) : - NULL; - const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX); + nullptr; + const int *index = static_cast<const int *>(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); const BLI_bitmap *facedot_tags = mesh->runtime.subsurf_face_dot_tags; - BLI_assert(facedot_tags != NULL); + BLI_assert(facedot_tags != nullptr); if (index) { for (int i = 0; i < mesh->totpoly; i++, mp++) { @@ -327,7 +331,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( func(userData, orig, positions[ml->v], - (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL); + (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : nullptr); } } } @@ -340,7 +344,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( func(userData, i, positions[ml->v], - (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL); + (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : nullptr); } } } @@ -349,10 +353,10 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( /* Helpers based on above foreach loopers> */ -typedef struct MappedVCosData { +struct MappedVCosData { float (*vertexcos)[3]; BLI_bitmap *vertex_visit; -} MappedVCosData; +}; static void get_vertexcos__mapFunc(void *user_data, int index, diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index df45047af08..310905a7e46 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -16,6 +16,7 @@ #include "BLI_bitmap.h" #include "BLI_buffer.h" #include "BLI_math.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "BKE_customdata.h" @@ -551,6 +552,41 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map, *r_mem = indices; } +namespace blender::mesh_topology { + +Array<int> build_corner_to_poly_map(const Span<MPoly> polys, const int loops_num) +{ + Array<int> map(loops_num); + threading::parallel_for(polys.index_range(), 1024, [&](IndexRange range) { + for (const int64_t poly_i : range) { + const MPoly &poly = polys[poly_i]; + map.as_mutable_span().slice(poly.loopstart, poly.totloop).fill(int(poly_i)); + } + }); + return map; +} + +Array<Vector<int>> build_vert_to_edge_map(const Span<MEdge> edges, const int verts_num) +{ + Array<Vector<int>> map(verts_num); + for (const int64_t i : edges.index_range()) { + map[edges[i].v1].append(int(i)); + map[edges[i].v2].append(int(i)); + } + return map; +} + +Array<Vector<int>> build_vert_to_corner_map(const Span<MLoop> loops, const int verts_num) +{ + Array<Vector<int>> map(verts_num); + for (const int64_t i : loops.index_range()) { + map[loops[i].v].append(int(i)); + } + return map; +} + +} // namespace blender::mesh_topology + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 904ea9eccb9..2607b9ec6a4 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1678,7 +1678,7 @@ void BKE_mesh_normals_loop_split(const float (*positions)[3], size_t(numLoops), sizeof(*loop_to_poly), __func__); /* When using custom loop normals, disable the angle feature! */ - const bool check_angle = (split_angle < (float)M_PI) && (clnors_data == nullptr); + const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); MLoopNorSpaceArray _lnors_spacearr = {nullptr}; @@ -1784,7 +1784,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], /* In this case we always consider split nors as ON, * and do not want to use angle to define smooth fans! */ const bool use_split_normals = true; - const float split_angle = (float)M_PI; + const float split_angle = float(M_PI); BLI_SMALLSTACK_DECLARE(clnors_data, short *); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.cc index 91894930cce..d735d9d1961 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.cc @@ -10,12 +10,12 @@ /* Allow using deprecated functionality for .blend file I/O. */ #define DNA_DEPRECATED_ALLOW -#include <float.h> -#include <math.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> +#include <cfloat> +#include <cmath> +#include <cstdarg> +#include <cstddef> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -73,7 +73,7 @@ #include "CLG_log.h" static CLG_LogRef LOG = {"bke.modifier"}; -static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {NULL}; +static ModifierTypeInfo *modifier_types[NUM_MODIFIER_TYPES] = {nullptr}; static VirtualModifierData virtualModifierCommonData; void BKE_modifier_init(void) @@ -113,7 +113,7 @@ const ModifierTypeInfo *BKE_modifier_get_info(ModifierType type) return modifier_types[type]; } - return NULL; + return nullptr; } void BKE_modifier_type_panel_id(ModifierType type, char *r_idname) @@ -131,10 +131,10 @@ void BKE_modifier_panel_expand(ModifierData *md) /***/ -static ModifierData *modifier_allocate_and_init(int type) +static ModifierData *modifier_allocate_and_init(ModifierType type) { const ModifierTypeInfo *mti = BKE_modifier_get_info(type); - ModifierData *md = MEM_callocN(mti->structSize, mti->structName); + ModifierData *md = static_cast<ModifierData *>(MEM_callocN(mti->structSize, mti->structName)); /* NOTE: this name must be made unique later. */ BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name)); @@ -158,7 +158,7 @@ static ModifierData *modifier_allocate_and_init(int type) ModifierData *BKE_modifier_new(int type) { - ModifierData *md = modifier_allocate_and_init(type); + ModifierData *md = modifier_allocate_and_init(ModifierType(type)); BKE_modifier_session_uuid_generate(md); @@ -171,18 +171,18 @@ static void modifier_free_data_id_us_cb(void *UNUSED(userData), int cb_flag) { ID *id = *idpoin; - if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + if (id != nullptr && (cb_flag & IDWALK_CB_USER) != 0) { id_us_min(id); } } void BKE_modifier_free_ex(ModifierData *md, const int flag) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { if (mti->foreachIDLink) { - mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL); + mti->foreachIDLink(md, nullptr, modifier_free_data_id_us_cb, nullptr); } } @@ -207,10 +207,10 @@ void BKE_modifier_remove_from_list(Object *ob, ModifierData *md) if (md->flag & eModifierFlag_Active) { /* Prefer the previous modifier but use the next if this modifier is the first in the list. */ - if (md->next != NULL) { + if (md->next != nullptr) { BKE_object_modifier_set_active(ob, md->next); } - else if (md->prev != NULL) { + else if (md->prev != nullptr) { BKE_object_modifier_set_active(ob, md->prev); } } @@ -226,7 +226,7 @@ void BKE_modifier_session_uuid_generate(ModifierData *md) bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md) { if (modifiers && md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return BLI_uniquename( modifiers, md, DATA_(mti->name), '.', offsetof(ModifierData, name), sizeof(md->name)); @@ -236,14 +236,14 @@ bool BKE_modifier_unique_name(ListBase *modifiers, ModifierData *md) bool BKE_modifier_depends_ontime(Scene *scene, ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return mti->dependsOnTime && mti->dependsOnTime(scene, md); } bool BKE_modifier_supports_mapping(ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return (mti->type == eModifierTypeType_OnlyDeform || (mti->flags & eModifierTypeFlag_SupportsMapping)); @@ -251,9 +251,9 @@ bool BKE_modifier_supports_mapping(ModifierData *md) bool BKE_modifier_is_preview(ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); - /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */ + /* Constructive modifiers are highly likely to also modify data like vgroups or vertex-colors! */ if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) { return false; @@ -273,12 +273,13 @@ ModifierData *BKE_modifiers_findby_type(const Object *ob, ModifierType type) return md; } } - return NULL; + return nullptr; } ModifierData *BKE_modifiers_findby_name(const Object *ob, const char *name) { - return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name)); + return static_cast<ModifierData *>( + BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name))); } ModifierData *BKE_modifiers_findby_session_uuid(const Object *ob, const SessionUUID *session_uuid) @@ -288,7 +289,7 @@ ModifierData *BKE_modifiers_findby_session_uuid(const Object *ob, const SessionU return md; } } - return NULL; + return nullptr; } void BKE_modifiers_clear_errors(Object *ob) @@ -296,7 +297,7 @@ void BKE_modifiers_clear_errors(Object *ob) LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { if (md->error) { MEM_freeN(md->error); - md->error = NULL; + md->error = nullptr; } } } @@ -304,7 +305,7 @@ void BKE_modifiers_clear_errors(Object *ob) void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *userData) { LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if (mti->foreachIDLink) { mti->foreachIDLink(md, ob, walk, userData); @@ -315,7 +316,7 @@ void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *userData) void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData) { LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if (mti->foreachTexLink) { mti->foreachTexLink(md, ob, walk, userData); @@ -325,7 +326,7 @@ void BKE_modifiers_foreach_tex_link(Object *ob, TexWalkFunc walk, void *userData ModifierData *BKE_modifier_copy_ex(const ModifierData *md, int flag) { - ModifierData *md_dst = modifier_allocate_and_init(md->type); + ModifierData *md_dst = modifier_allocate_and_init(ModifierType(md->type)); BLI_strncpy(md_dst->name, md->name, sizeof(md_dst->name)); BKE_modifier_copydata_ex(md, md_dst, flag); @@ -337,10 +338,10 @@ void BKE_modifier_copydata_generic(const ModifierData *md_src, ModifierData *md_dst, const int UNUSED(flag)) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md_src->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md_src->type)); - /* md_dst may have already be fully initialized with some extra allocated data, - * we need to free it now to avoid memleak. */ + /* `md_dst` may have already be fully initialized with some extra allocated data, + * we need to free it now to avoid a memory leak. */ if (mti->freeData) { mti->freeData(md_dst); } @@ -349,10 +350,10 @@ void BKE_modifier_copydata_generic(const ModifierData *md_src, const char *md_src_data = ((const char *)md_src) + data_size; char *md_dst_data = ((char *)md_dst) + data_size; BLI_assert(data_size <= (size_t)mti->structSize); - memcpy(md_dst_data, md_src_data, (size_t)mti->structSize - data_size); + memcpy(md_dst_data, md_src_data, size_t(mti->structSize) - data_size); /* Runtime fields are never to be preserved. */ - md_dst->runtime = NULL; + md_dst->runtime = nullptr; } static void modifier_copy_data_id_us_cb(void *UNUSED(userData), @@ -361,14 +362,14 @@ static void modifier_copy_data_id_us_cb(void *UNUSED(userData), int cb_flag) { ID *id = *idpoin; - if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + if (id != nullptr && (cb_flag & IDWALK_CB_USER) != 0) { id_us_plus(id); } } void BKE_modifier_copydata_ex(const ModifierData *md, ModifierData *target, const int flag) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); target->mode = md->mode; target->flag = md->flag; @@ -380,7 +381,7 @@ void BKE_modifier_copydata_ex(const ModifierData *md, ModifierData *target, cons if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { if (mti->foreachIDLink) { - mti->foreachIDLink(target, NULL, modifier_copy_data_id_us_cb, NULL); + mti->foreachIDLink(target, nullptr, modifier_copy_data_id_us_cb, nullptr); } } @@ -403,7 +404,7 @@ void BKE_modifier_copydata(const ModifierData *md, ModifierData *target) bool BKE_modifier_supports_cage(struct Scene *scene, ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return ((!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && (mti->flags & eModifierTypeFlag_SupportsEditmode) && BKE_modifier_supports_mapping(md)); @@ -411,7 +412,7 @@ bool BKE_modifier_supports_cage(struct Scene *scene, ModifierData *md) bool BKE_modifier_couldbe_cage(struct Scene *scene, ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return ((md->mode & eModifierMode_Realtime) && (md->mode & eModifierMode_Editmode) && (!mti->isDisabled || !mti->isDisabled(scene, md, 0)) && @@ -420,13 +421,13 @@ bool BKE_modifier_couldbe_cage(struct Scene *scene, ModifierData *md) bool BKE_modifier_is_same_topology(ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return ELEM(mti->type, eModifierTypeType_OnlyDeform, eModifierTypeType_NonGeometrical); } bool BKE_modifier_is_non_geometrical(ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); return (mti->type == eModifierTypeType_NonGeometrical); } @@ -450,7 +451,7 @@ void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *_for #ifndef NDEBUG if ((md->mode & eModifierMode_Virtual) == 0) { /* Ensure correct object is passed in. */ - BLI_assert(BKE_modifier_get_original(ob, md) != NULL); + BLI_assert(BKE_modifier_get_original(ob, md) != nullptr); } #endif @@ -484,7 +485,7 @@ void BKE_modifier_set_warning(const struct Object *ob, #ifndef NDEBUG if ((md->mode & eModifierMode_Virtual) == 0) { /* Ensure correct object is passed in. */ - BLI_assert(BKE_modifier_get_original(ob, md) != NULL); + BLI_assert(BKE_modifier_get_original(ob, md) != nullptr); } #endif @@ -499,7 +500,7 @@ int BKE_modifiers_get_cage_index(const Scene *scene, VirtualModifierData virtualModifierData; ModifierData *md = (is_virtual) ? BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) : - ob->modifiers.first; + static_cast<ModifierData *>(ob->modifiers.first); if (r_lastPossibleCageIndex) { /* ensure the value is initialized */ @@ -509,7 +510,7 @@ int BKE_modifiers_get_cage_index(const Scene *scene, /* Find the last modifier acting on the cage. */ int cageIndex = -1; for (int i = 0; md; i++, md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); bool supports_mapping; if (mti->isDisabled && mti->isDisabled(scene, md, 0)) { @@ -562,7 +563,7 @@ bool BKE_modifiers_is_cloth_enabled(Object *ob) bool BKE_modifiers_is_modifier_enabled(Object *ob, int modifierType) { - ModifierData *md = BKE_modifiers_findby_type(ob, modifierType); + ModifierData *md = BKE_modifiers_findby_type(ob, ModifierType(modifierType)); return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)); } @@ -576,12 +577,12 @@ bool BKE_modifiers_is_particle_enabled(Object *ob) bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int required_mode) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if ((md->mode & required_mode) != required_mode) { return false; } - if (scene != NULL && mti->isDisabled && + if (scene != nullptr && mti->isDisabled && mti->isDisabled(scene, md, required_mode == eModifierMode_Render)) { return false; } @@ -599,7 +600,7 @@ bool BKE_modifier_is_enabled(const struct Scene *scene, ModifierData *md, int re bool BKE_modifier_is_nonlocal_in_liboverride(const Object *ob, const ModifierData *md) { return (ID_IS_OVERRIDE_LIBRARY(ob) && - (md == NULL || (md->flag & eModifierFlag_OverrideLibrary_Local) == 0)); + (md == nullptr || (md->flag & eModifierFlag_OverrideLibrary_Local) == 0)); } CDMaskLink *BKE_modifier_calc_data_masks(const struct Scene *scene, @@ -609,15 +610,15 @@ CDMaskLink *BKE_modifier_calc_data_masks(const struct Scene *scene, ModifierData *previewmd, const CustomData_MeshMasks *previewmask) { - CDMaskLink *dataMasks = NULL; + CDMaskLink *dataMasks = nullptr; CDMaskLink *curr, *prev; bool have_deform_modifier = false; /* build a list of modifier data requirements in reverse order */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); - curr = MEM_callocN(sizeof(CDMaskLink), "CDMaskLink"); + curr = MEM_cnew<CDMaskLink>(__func__); if (BKE_modifier_is_enabled(scene, md, required_mode)) { if (mti->type == eModifierTypeType_OnlyDeform) { @@ -628,7 +629,7 @@ CDMaskLink *BKE_modifier_calc_data_masks(const struct Scene *scene, mti->requiredDataMask(md, &curr->mask); } - if (previewmd == md && previewmask != NULL) { + if (previewmd == md && previewmask != nullptr) { CustomData_MeshMasks_update(&curr->mask, previewmask); } } @@ -654,7 +655,7 @@ CDMaskLink *BKE_modifier_calc_data_masks(const struct Scene *scene, * note the list is currently in reverse order, so "masks that follow it" * actually means "masks that precede it" at the moment */ - for (curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) { + for (curr = dataMasks, prev = nullptr; curr; prev = curr, curr = curr->next) { if (prev) { CustomData_MeshMasks_update(&curr->mask, &prev->mask); } @@ -673,7 +674,7 @@ ModifierData *BKE_modifier_get_last_preview(const struct Scene *scene, ModifierData *md, int required_mode) { - ModifierData *tmp_md = NULL; + ModifierData *tmp_md = nullptr; if ((required_mode & ~eModifierMode_Editmode) != eModifierMode_Realtime) { return tmp_md; @@ -691,7 +692,7 @@ ModifierData *BKE_modifier_get_last_preview(const struct Scene *scene, ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob, VirtualModifierData *virtualModifierData) { - ModifierData *md = ob->modifiers.first; + ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); *virtualModifierData = virtualModifierCommonData; @@ -735,7 +736,7 @@ Object *BKE_modifiers_is_deformed_by_armature(Object *ob) { if (ob->type == OB_GPENCIL) { GpencilVirtualModifierData gpencilvirtualModifierData; - ArmatureGpencilModifierData *agmd = NULL; + ArmatureGpencilModifierData *agmd = nullptr; GpencilModifierData *gmd = BKE_gpencil_modifiers_get_virtual_modifierlist( ob, &gpencilvirtualModifierData); @@ -755,7 +756,7 @@ Object *BKE_modifiers_is_deformed_by_armature(Object *ob) } else { VirtualModifierData virtualModifierData; - ArmatureModifierData *amd = NULL; + ArmatureModifierData *amd = nullptr; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* return the first selected armature, this lets us use multiple armatures */ @@ -773,14 +774,14 @@ Object *BKE_modifiers_is_deformed_by_armature(Object *ob) } } - return NULL; + return nullptr; } Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob) { VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - MeshDeformModifierData *mdmd = NULL; + MeshDeformModifierData *mdmd = nullptr; /* return the first selected armature, this lets us use multiple armatures */ for (; md; md = md->next) { @@ -796,14 +797,14 @@ Object *BKE_modifiers_is_deformed_by_meshdeform(Object *ob) return mdmd->object; } - return NULL; + return nullptr; } Object *BKE_modifiers_is_deformed_by_lattice(Object *ob) { VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - LatticeModifierData *lmd = NULL; + LatticeModifierData *lmd = nullptr; /* return the first selected lattice, this lets us use multiple lattices */ for (; md; md = md->next) { @@ -819,14 +820,14 @@ Object *BKE_modifiers_is_deformed_by_lattice(Object *ob) return lmd->object; } - return NULL; + return nullptr; } Object *BKE_modifiers_is_deformed_by_curve(Object *ob) { VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - CurveModifierData *cmd = NULL; + CurveModifierData *cmd = nullptr; /* return the first selected curve, this lets us use multiple curves */ for (; md; md = md->next) { @@ -842,14 +843,14 @@ Object *BKE_modifiers_is_deformed_by_curve(Object *ob) return cmd->object; } - return NULL; + return nullptr; } bool BKE_modifiers_uses_multires(Object *ob) { VirtualModifierData virtualModifierData; ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); - MultiresModifierData *mmd = NULL; + MultiresModifierData *mmd = nullptr; for (; md; md = md->next) { if (md->type == eModifierType_Multires) { @@ -881,8 +882,8 @@ bool BKE_modifiers_uses_armature(Object *ob, bArmature *arm) bool BKE_modifier_is_correctable_deformed(ModifierData *md) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - return mti->deformMatricesEM != NULL; + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); + return mti->deformMatricesEM != nullptr; } bool BKE_modifiers_is_correctable_deformed(const struct Scene *scene, Object *ob) @@ -916,8 +917,6 @@ void BKE_modifier_free_temporary_data(ModifierData *md) void BKE_modifiers_test_object(Object *ob) { - ModifierData *md; - /* just multires checked for now, since only multires * modifies mesh data */ @@ -925,7 +924,7 @@ void BKE_modifiers_test_object(Object *ob) return; } - for (md = ob->modifiers.first; md; md = md->next) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { if (md->type == eModifierType_Multires) { MultiresModifierData *mmd = (MultiresModifierData *)md; @@ -992,7 +991,7 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, struct Mesh *me) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) { @@ -1012,7 +1011,7 @@ void BKE_modifier_deform_verts(ModifierData *md, float (*vertexCos)[3], int numVerts) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { modwrap_dependsOnNormals(me); } @@ -1026,7 +1025,7 @@ void BKE_modifier_deform_vertsEM(ModifierData *md, float (*vertexCos)[3], int numVerts) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) { modwrap_dependsOnNormals(me); } @@ -1037,17 +1036,17 @@ void BKE_modifier_deform_vertsEM(ModifierData *md, Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval) { - Mesh *me = NULL; + Mesh *me = nullptr; if ((ob_eval->type == OB_MESH) && (ob_eval->mode & OB_MODE_EDIT)) { /* In EditMode, evaluated mesh is stored in BMEditMesh, not the object... */ BMEditMesh *em = BKE_editmesh_from_object(ob_eval); /* 'em' might not exist yet in some cases, just after loading a .blend file, see T57878. */ - if (em != NULL) { + if (em != nullptr) { me = BKE_object_get_editmesh_eval_final(ob_eval); } } - if (me == NULL) { + if (me == nullptr) { me = BKE_object_get_evaluated_mesh(ob_eval); } @@ -1083,7 +1082,7 @@ void BKE_modifier_check_uuids_unique_and_report(const Object *object) continue; } - if (BLI_gset_lookup(used_uuids, session_uuid) != NULL) { + if (BLI_gset_lookup(used_uuids, session_uuid) != nullptr) { printf("Modifier %s -> %s has duplicate UUID generated.\n", object->id.name + 2, md->name); continue; } @@ -1091,23 +1090,23 @@ void BKE_modifier_check_uuids_unique_and_report(const Object *object) BLI_gset_insert(used_uuids, (void *)session_uuid); } - BLI_gset_free(used_uuids, NULL); + BLI_gset_free(used_uuids, nullptr); } void BKE_modifier_blend_write(BlendWriter *writer, const ID *id_owner, ListBase *modbase) { - if (modbase == NULL) { + if (modbase == nullptr) { return; } LISTBASE_FOREACH (ModifierData *, md, modbase) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); - if (mti == NULL) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); + if (mti == nullptr) { continue; } /* If the blendWrite callback is defined, it should handle the whole writing process. */ - if (mti->blendWrite != NULL) { + if (mti->blendWrite != nullptr) { mti->blendWrite(writer, id_owner, md); continue; } @@ -1144,7 +1143,7 @@ void BKE_modifier_blend_write(BlendWriter *writer, const ID *id_owner, ListBase /* cleanup the fake pointcache */ BKE_ptcache_free_list(&fmd->domain->ptcaches[1]); - fmd->domain->point_cache[1] = NULL; + fmd->domain->point_cache[1] = nullptr; BLO_write_struct(writer, EffectorWeights, fmd->domain->effector_weights); } @@ -1230,8 +1229,8 @@ static ModifierData *modifier_replace_with_fluid(BlendDataReader *reader, if (old_modifier_data->type == eModifierType_Fluidsim) { FluidsimModifierData *old_fluidsim_modifier_data = (FluidsimModifierData *)old_modifier_data; - FluidsimSettings *old_fluidsim_settings = BLO_read_get_new_data_address( - reader, old_fluidsim_modifier_data->fss); + FluidsimSettings *old_fluidsim_settings = static_cast<FluidsimSettings *>( + BLO_read_get_new_data_address(reader, old_fluidsim_modifier_data->fss)); switch (old_fluidsim_settings->type) { case OB_FLUIDSIM_ENABLE: modifier_ensure_type(fluid_modifier_data, 0); @@ -1295,10 +1294,10 @@ static ModifierData *modifier_replace_with_fluid(BlendDataReader *reader, /* Replace modifier data in the stack. */ new_modifier_data->next = old_modifier_data->next; new_modifier_data->prev = old_modifier_data->prev; - if (new_modifier_data->prev != NULL) { + if (new_modifier_data->prev != nullptr) { new_modifier_data->prev->next = new_modifier_data; } - if (new_modifier_data->next != NULL) { + if (new_modifier_data->next != nullptr) { new_modifier_data->next->prev = new_modifier_data; } if (modifiers->first == old_modifier_data) { @@ -1321,8 +1320,8 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object LISTBASE_FOREACH (ModifierData *, md, lb) { BKE_modifier_session_uuid_generate(md); - md->error = NULL; - md->runtime = NULL; + md->error = nullptr; + md->runtime = nullptr; /* Modifier data has been allocated as a part of data migration process and * no reading of nested fields from file is needed. */ @@ -1349,10 +1348,10 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object is_allocated = true; } - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(ModifierType(md->type)); /* if modifiers disappear, or for upward compatibility */ - if (mti == NULL) { + if (mti == nullptr) { md->type = eModifierType_None; } @@ -1362,8 +1361,8 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object else if (md->type == eModifierType_Cloth) { ClothModifierData *clmd = (ClothModifierData *)md; - clmd->clothObject = NULL; - clmd->hairdata = NULL; + clmd->clothObject = nullptr; + clmd->hairdata = nullptr; BLO_read_data_address(reader, &clmd->sim_parms); BLO_read_data_address(reader, &clmd->coll_parms); @@ -1380,40 +1379,40 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object BLO_read_data_address(reader, &clmd->sim_parms->effector_weights); if (!clmd->sim_parms->effector_weights) { - clmd->sim_parms->effector_weights = BKE_effector_add_weights(NULL); + clmd->sim_parms->effector_weights = BKE_effector_add_weights(nullptr); } } - clmd->solver_result = NULL; + clmd->solver_result = nullptr; } else if (md->type == eModifierType_Fluid) { FluidModifierData *fmd = (FluidModifierData *)md; if (fmd->type == MOD_FLUID_TYPE_DOMAIN) { - fmd->flow = NULL; - fmd->effector = NULL; + fmd->flow = nullptr; + fmd->effector = nullptr; BLO_read_data_address(reader, &fmd->domain); fmd->domain->fmd = fmd; - fmd->domain->fluid = NULL; + fmd->domain->fluid = nullptr; fmd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - fmd->domain->tex_density = NULL; - fmd->domain->tex_color = NULL; - fmd->domain->tex_shadow = NULL; - fmd->domain->tex_flame = NULL; - fmd->domain->tex_flame_coba = NULL; - fmd->domain->tex_coba = NULL; - fmd->domain->tex_field = NULL; - fmd->domain->tex_velocity_x = NULL; - fmd->domain->tex_velocity_y = NULL; - fmd->domain->tex_velocity_z = NULL; - fmd->domain->tex_wt = NULL; + fmd->domain->tex_density = nullptr; + fmd->domain->tex_color = nullptr; + fmd->domain->tex_shadow = nullptr; + fmd->domain->tex_flame = nullptr; + fmd->domain->tex_flame_coba = nullptr; + fmd->domain->tex_coba = nullptr; + fmd->domain->tex_field = nullptr; + fmd->domain->tex_velocity_x = nullptr; + fmd->domain->tex_velocity_y = nullptr; + fmd->domain->tex_velocity_z = nullptr; + fmd->domain->tex_wt = nullptr; BLO_read_data_address(reader, &fmd->domain->coba); BLO_read_data_address(reader, &fmd->domain->effector_weights); if (!fmd->domain->effector_weights) { - fmd->domain->effector_weights = BKE_effector_add_weights(NULL); + fmd->domain->effector_weights = BKE_effector_add_weights(nullptr); } BKE_ptcache_blend_read_data( @@ -1422,7 +1421,8 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object /* Manta sim uses only one cache from now on, so store pointer convert */ if (fmd->domain->ptcaches[1].first || fmd->domain->point_cache[1]) { if (fmd->domain->point_cache[1]) { - PointCache *cache = BLO_read_get_new_data_address(reader, fmd->domain->point_cache[1]); + PointCache *cache = static_cast<PointCache *>( + BLO_read_get_new_data_address(reader, fmd->domain->point_cache[1])); if (cache->flag & PTCACHE_FAKE_SMOKE) { /* Manta-sim/smoke was already saved in "new format" and this cache is a fake one. */ } @@ -1434,34 +1434,34 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object BKE_ptcache_free(cache); } BLI_listbase_clear(&fmd->domain->ptcaches[1]); - fmd->domain->point_cache[1] = NULL; + fmd->domain->point_cache[1] = nullptr; } } else if (fmd->type == MOD_FLUID_TYPE_FLOW) { - fmd->domain = NULL; - fmd->effector = NULL; + fmd->domain = nullptr; + fmd->effector = nullptr; BLO_read_data_address(reader, &fmd->flow); fmd->flow->fmd = fmd; - fmd->flow->mesh = NULL; - fmd->flow->verts_old = NULL; + fmd->flow->mesh = nullptr; + fmd->flow->verts_old = nullptr; fmd->flow->numverts = 0; BLO_read_data_address(reader, &fmd->flow->psys); } else if (fmd->type == MOD_FLUID_TYPE_EFFEC) { - fmd->flow = NULL; - fmd->domain = NULL; + fmd->flow = nullptr; + fmd->domain = nullptr; BLO_read_data_address(reader, &fmd->effector); if (fmd->effector) { fmd->effector->fmd = fmd; - fmd->effector->verts_old = NULL; + fmd->effector->verts_old = nullptr; fmd->effector->numverts = 0; - fmd->effector->mesh = NULL; + fmd->effector->mesh = nullptr; } else { fmd->type = 0; - fmd->flow = NULL; - fmd->domain = NULL; - fmd->effector = NULL; + fmd->flow = nullptr; + fmd->domain = nullptr; + fmd->effector = nullptr; } } } @@ -1478,12 +1478,12 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object LISTBASE_FOREACH (DynamicPaintSurface *, surface, &pmd->canvas->surfaces) { surface->canvas = pmd->canvas; - surface->data = NULL; + surface->data = nullptr; BKE_ptcache_blend_read_data(reader, &(surface->ptcaches), &(surface->pointcache), 1); BLO_read_data_address(reader, &surface->effector_weights); - if (surface->effector_weights == NULL) { - surface->effector_weights = BKE_effector_add_weights(NULL); + if (surface->effector_weights == nullptr) { + surface->effector_weights = BKE_effector_add_weights(nullptr); } } } @@ -1497,7 +1497,7 @@ void BKE_modifier_blend_read_data(BlendDataReader *reader, ListBase *lb, Object } } - if ((mti != NULL) && (mti->blendRead != NULL)) { + if ((mti != nullptr) && (mti->blendRead != nullptr)) { mti->blendRead(reader, md); } } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 0dcb2aa3139..6413ad4c661 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -3114,7 +3114,7 @@ void ntreeSetOutput(bNodeTree *ntree) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->typeinfo->nclass == NODE_CLASS_OUTPUT) { /* we need a check for which output node should be tagged like this, below an exception */ - if (node->type == CMP_NODE_OUTPUT_FILE) { + if (ELEM(node->type, CMP_NODE_OUTPUT_FILE, GEO_NODE_VIEWER)) { continue; } @@ -3125,8 +3125,8 @@ void ntreeSetOutput(bNodeTree *ntree) if (ntree->type == NTREE_COMPOSIT) { /* same type, exception for viewer */ if (tnode->type == node->type || - (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER) && - ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER))) { + (ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && + ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))) { if (tnode->flag & NODE_DO_OUTPUT) { output++; if (output > 1) { @@ -4728,6 +4728,8 @@ static void registerGeometryNodes() register_node_type_geo_curve_subdivide(); register_node_type_geo_curve_to_mesh(); register_node_type_geo_curve_to_points(); + register_node_type_geo_curve_topology_curve_of_point(); + register_node_type_geo_curve_topology_points_of_curve(); register_node_type_geo_curve_trim(); register_node_type_geo_deform_curves_on_surface(); register_node_type_geo_delete_geometry(); @@ -4792,6 +4794,13 @@ static void registerGeometryNodes() register_node_type_geo_mesh_to_curve(); register_node_type_geo_mesh_to_points(); register_node_type_geo_mesh_to_volume(); + register_node_type_geo_mesh_topology_offset_corner_in_face(); + register_node_type_geo_mesh_topology_corners_of_face(); + register_node_type_geo_mesh_topology_corners_of_vertex(); + register_node_type_geo_mesh_topology_edges_of_corner(); + register_node_type_geo_mesh_topology_edges_of_vertex(); + register_node_type_geo_mesh_topology_face_of_corner(); + register_node_type_geo_mesh_topology_vertex_of_corner(); register_node_type_geo_object_info(); register_node_type_geo_points_to_vertices(); register_node_type_geo_points_to_volume(); diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 44ca2752782..591e710dea2 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -1402,12 +1402,17 @@ class NodeTreeMainUpdater { } Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree, - Span<const bNodeSocket *> sockets) + const Span<const bNodeSocket *> sockets) { BLI_assert(!tree.has_available_link_cycle()); Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size()); Stack<const bNodeSocket *> sockets_to_check = sockets; + auto get_socket_ptr_hash = [&](const bNodeSocket &socket) { + const uint64_t socket_ptr = uintptr_t(&socket); + return noise::hash(socket_ptr, socket_ptr >> 32); + }; + while (!sockets_to_check.is_empty()) { const bNodeSocket &socket = *sockets_to_check.peek(); const bNode &node = socket.owner_node(); @@ -1418,31 +1423,45 @@ class NodeTreeMainUpdater { continue; } + uint32_t socket_hash = 0; if (socket.is_input()) { /* For input sockets, first compute the hashes of all linked sockets. */ bool all_origins_computed = true; - for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { - if (!hash_by_socket_id[origin_socket->index_in_tree()].has_value()) { - sockets_to_check.push(origin_socket); + bool get_value_from_origin = false; + for (const bNodeLink *link : socket.directly_linked_links()) { + if (link->is_muted()) { + continue; + } + if (!link->is_available()) { + continue; + } + const bNodeSocket &origin_socket = *link->fromsock; + const std::optional<uint32_t> origin_hash = + hash_by_socket_id[origin_socket.index_in_tree()]; + if (origin_hash.has_value()) { + if (get_value_from_origin || socket.type != origin_socket.type) { + socket_hash = noise::hash(socket_hash, *origin_hash); + } + else { + /* Copy the socket hash because the link did not change it. */ + socket_hash = *origin_hash; + } + get_value_from_origin = true; + } + else { + sockets_to_check.push(&origin_socket); all_origins_computed = false; } } if (!all_origins_computed) { continue; } - /* When the hashes for the linked sockets are ready, combine them into a hash for the input - * socket. */ - const uint64_t socket_ptr = uintptr_t(&socket); - uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { - const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->index_in_tree()]; - socket_hash = noise::hash(socket_hash, origin_socket_hash); + + if (!get_value_from_origin) { + socket_hash = get_socket_ptr_hash(socket); } - hash_by_socket_id[socket.index_in_tree()] = socket_hash; - sockets_to_check.pop(); } else { - /* For output sockets, first compute the hashes of all available input sockets. */ bool all_available_inputs_computed = true; for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { @@ -1455,29 +1474,48 @@ class NodeTreeMainUpdater { if (!all_available_inputs_computed) { continue; } - /* When all input socket hashes have been computed, combine them into a hash for the output - * socket. */ - const uint64_t socket_ptr = uintptr_t(&socket); - uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const bNodeSocket *input_socket : node.input_sockets()) { - if (input_socket->is_available()) { - const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; - socket_hash = noise::hash(socket_hash, input_socket_hash); + if (node.type == NODE_REROUTE) { + socket_hash = *hash_by_socket_id[node.input_socket(0).index_in_tree()]; + } + else if (node.is_muted()) { + const bNodeSocket *internal_input = socket.internal_link_input(); + if (internal_input == nullptr) { + socket_hash = get_socket_ptr_hash(socket); + } + else { + if (internal_input->type == socket.type) { + socket_hash = *hash_by_socket_id[internal_input->index_in_tree()]; + } + else { + socket_hash = get_socket_ptr_hash(socket); + } } } - /* The Image Texture node has a special case. The behavior of the color output changes - * depending on whether the Alpha output is linked. */ - if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { - BLI_assert(STREQ(socket.name, "Color")); - const bNodeSocket &alpha_socket = node.output_socket(1); - BLI_assert(STREQ(alpha_socket.name, "Alpha")); - if (alpha_socket.is_directly_linked()) { - socket_hash = noise::hash(socket_hash); + else { + socket_hash = get_socket_ptr_hash(socket); + for (const bNodeSocket *input_socket : node.input_sockets()) { + if (input_socket->is_available()) { + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; + socket_hash = noise::hash(socket_hash, input_socket_hash); + } + } + + /* The Image Texture node has a special case. The behavior of the color output changes + * depending on whether the Alpha output is linked. */ + if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { + BLI_assert(STREQ(socket.name, "Color")); + const bNodeSocket &alpha_socket = node.output_socket(1); + BLI_assert(STREQ(alpha_socket.name, "Alpha")); + if (alpha_socket.is_directly_linked()) { + socket_hash = noise::hash(socket_hash); + } } } - hash_by_socket_id[socket.index_in_tree()] = socket_hash; - sockets_to_check.pop(); } + hash_by_socket_id[socket.index_in_tree()] = socket_hash; + /* Check that nothing has been pushed in the meantime. */ + BLI_assert(sockets_to_check.peek() == &socket); + sockets_to_check.pop(); } /* Create output array. */ @@ -1518,7 +1556,7 @@ class NodeTreeMainUpdater { } } if (socket.is_input()) { - for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + for (const bNodeSocket *origin_socket : socket.directly_linked_sockets()) { bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(origin_socket); diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index fa039fe7997..f5852e7edb8 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -24,8 +24,10 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" +#include "DNA_curves_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_vfont_types.h" @@ -44,6 +46,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_iterators.h" #include "BKE_mesh_runtime.h" +#include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_scene.h" @@ -53,13 +56,18 @@ #include "DEG_depsgraph_query.h" #include "BLI_hash.h" -#include "BLI_strict_flags.h" + +#include "NOD_geometry_nodes_log.hh" +#include "RNA_access.h" +#include "RNA_path.h" +#include "RNA_types.h" using blender::Array; using blender::float3; using blender::float4x4; using blender::Span; using blender::Vector; +namespace geo_log = blender::nodes::geo_eval_log; /* -------------------------------------------------------------------- */ /** \name Internal Duplicate Context @@ -75,6 +83,15 @@ struct DupliContext { Scene *scene; Object *object; float space_mat[4][4]; + /** + * Index of the top-level instance that contains this context or -1 when unused. + * This is an index into the instances component of #preview_base_geometry. + */ + int preview_instance_index; + /** + * Top level geometry set that is previewed. + */ + const GeometrySet *preview_base_geometry; /** * A stack that contains all the "parent" objects of a particular instance when recursive @@ -127,6 +144,8 @@ static void init_context(DupliContext *r_ctx, r_ctx->gen = get_dupli_generator(r_ctx); r_ctx->duplilist = nullptr; + r_ctx->preview_instance_index = -1; + r_ctx->preview_base_geometry = nullptr; } /** @@ -139,7 +158,7 @@ static bool copy_dupli_context( /* XXX annoying, previously was done by passing an ID* argument, * this at least is more explicit. */ - if (ctx->gen->type == OB_DUPLICOLLECTION) { + if (ctx->gen && ctx->gen->type == OB_DUPLICOLLECTION) { r_ctx->collection = ctx->object->instance_collection; } @@ -183,7 +202,9 @@ static DupliObject *make_dupli( dob->ob = ob; dob->ob_data = const_cast<ID *>(object_data); mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); - dob->type = ctx->gen->type; + dob->type = ctx->gen == nullptr ? 0 : ctx->gen->type; + dob->preview_base_geometry = ctx->preview_base_geometry; + dob->preview_instance_index = ctx->preview_instance_index; /* Set persistent id, which is an array with a persistent index for each level * (particle number, vertex number, ..). by comparing this we can find the same @@ -784,7 +805,8 @@ static const DupliGenerator gen_dupli_verts_font = { static void make_duplis_geometry_set_impl(const DupliContext *ctx, const GeometrySet &geometry_set, const float parent_transform[4][4], - bool geometry_set_is_instance) + bool geometry_set_is_instance, + bool use_new_curves_type) { int component_index = 0; if (ctx->object->type != OB_MESH || geometry_set_is_instance) { @@ -799,8 +821,15 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, } if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) { if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>()) { - if (const Curve *curve = component->get_curve_for_render()) { - make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++); + if (use_new_curves_type) { + if (const Curves *curves = component->get_for_read()) { + make_dupli(ctx, ctx->object, &curves->id, parent_transform, component_index++); + } + } + else { + if (const Curve *curve = component->get_curve_for_render()) { + make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++); + } } } } @@ -836,17 +865,26 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, const InstanceReference &reference = references[instance_reference_handles[i]]; const int id = almost_unique_ids[i]; + const DupliContext *ctx_for_instance = instances_ctx; + /* Set the #preview_instance_index when necessary. */ + DupliContext tmp_ctx_for_instance; + if (instances_ctx->preview_base_geometry == &geometry_set) { + tmp_ctx_for_instance = *instances_ctx; + tmp_ctx_for_instance.preview_instance_index = i; + ctx_for_instance = &tmp_ctx_for_instance; + } + switch (reference.type()) { case InstanceReference::Type::Object: { Object &object = reference.object(); float matrix[4][4]; mul_m4_m4m4(matrix, parent_transform, instance_offset_matrices[i].values); - make_dupli(instances_ctx, &object, matrix, id); + make_dupli(ctx_for_instance, &object, matrix, id); float space_matrix[4][4]; mul_m4_m4m4(space_matrix, instance_offset_matrices[i].values, object.imat); mul_m4_m4_pre(space_matrix, parent_transform); - make_recursive_duplis(instances_ctx, &object, space_matrix, id); + make_recursive_duplis(ctx_for_instance, &object, space_matrix, id); break; } case InstanceReference::Type::Collection: { @@ -858,14 +896,15 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, mul_m4_m4_pre(collection_matrix, parent_transform); DupliContext sub_ctx; - if (!copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { + if (!copy_dupli_context( + &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) { break; } - eEvaluationMode mode = DEG_get_mode(instances_ctx->depsgraph); + eEvaluationMode mode = DEG_get_mode(ctx_for_instance->depsgraph); int object_id = 0; FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (&collection, object, mode) { - if (object == instances_ctx->object) { + if (object == ctx_for_instance->object) { continue; } @@ -883,8 +922,10 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, mul_m4_m4m4(new_transform, parent_transform, instance_offset_matrices[i].values); DupliContext sub_ctx; - if (copy_dupli_context(&sub_ctx, instances_ctx, instances_ctx->object, nullptr, id)) { - make_duplis_geometry_set_impl(&sub_ctx, reference.geometry_set(), new_transform, true); + if (copy_dupli_context( + &sub_ctx, ctx_for_instance, ctx_for_instance->object, nullptr, id)) { + make_duplis_geometry_set_impl( + &sub_ctx, reference.geometry_set(), new_transform, true, false); } break; } @@ -898,7 +939,7 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, static void make_duplis_geometry_set(const DupliContext *ctx) { const GeometrySet *geometry_set = ctx->object->runtime.geometry_set_eval; - make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false); + make_duplis_geometry_set_impl(ctx, *geometry_set, ctx->object->obmat, false, false); } static const DupliGenerator gen_dupli_geometry_set = { @@ -1642,6 +1683,40 @@ ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) return duplilist; } +ListBase *object_duplilist_preview(Depsgraph *depsgraph, + Scene *sce, + Object *ob_eval, + const ViewerPath *viewer_path) +{ + ListBase *duplilist = MEM_cnew<ListBase>("duplilist"); + DupliContext ctx; + Vector<Object *> instance_stack; + instance_stack.append(ob_eval); + init_context(&ctx, depsgraph, sce, ob_eval, nullptr, instance_stack); + ctx.duplilist = duplilist; + + Object *ob_orig = DEG_get_original_object(ob_eval); + + LISTBASE_FOREACH (ModifierData *, md_orig, &ob_orig->modifiers) { + if (md_orig->type != eModifierType_Nodes) { + continue; + } + NodesModifierData *nmd_orig = reinterpret_cast<NodesModifierData *>(md_orig); + if (nmd_orig->runtime_eval_log == nullptr) { + continue; + } + geo_log::GeoModifierLog *log = static_cast<geo_log::GeoModifierLog *>( + nmd_orig->runtime_eval_log); + if (const geo_log::ViewerNodeLog *viewer_log = log->find_viewer_node_log_for_path( + *viewer_path)) { + ctx.preview_base_geometry = &viewer_log->geometry; + make_duplis_geometry_set_impl( + &ctx, viewer_log->geometry, ob_eval->obmat, true, ob_eval->type == OB_CURVES); + } + } + return duplilist; +} + void free_object_duplilist(ListBase *lb) { BLI_freelistN(lb); @@ -1649,3 +1724,120 @@ void free_object_duplilist(ListBase *lb) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Uniform attribute lookup + * \{ */ + +/** Lookup an arbitrary RNA property and convert it to RGBA if possible. */ +static bool find_rna_property_rgba(PointerRNA *id_ptr, const char *name, float r_data[4]) +{ + if (id_ptr->data == nullptr) { + return false; + } + + /* First, check custom properties. */ + IDProperty *group = RNA_struct_idprops(id_ptr, false); + PropertyRNA *prop = nullptr; + + if (group && group->type == IDP_GROUP) { + prop = (PropertyRNA *)IDP_GetPropertyFromGroup(group, name); + } + + /* If not found, do full path lookup. */ + PointerRNA ptr; + + if (prop != nullptr) { + ptr = *id_ptr; + } + else if (!RNA_path_resolve(id_ptr, name, &ptr, &prop)) { + return false; + } + + if (prop == nullptr) { + return false; + } + + /* Convert the value to RGBA if possible. */ + PropertyType type = RNA_property_type(prop); + int array_len = RNA_property_array_length(&ptr, prop); + + if (array_len == 0) { + float value; + + if (type == PROP_FLOAT) { + value = RNA_property_float_get(&ptr, prop); + } + else if (type == PROP_INT) { + value = static_cast<float>(RNA_property_int_get(&ptr, prop)); + } + else if (type == PROP_BOOLEAN) { + value = RNA_property_boolean_get(&ptr, prop) ? 1.0f : 0.0f; + } + else { + return false; + } + + copy_v4_fl4(r_data, value, value, value, 1); + return true; + } + + if (type == PROP_FLOAT && array_len <= 4) { + copy_v4_fl4(r_data, 0, 0, 0, 1); + RNA_property_float_get_array(&ptr, prop, r_data); + return true; + } + + if (type == PROP_INT && array_len <= 4) { + int tmp[4] = {0, 0, 0, 1}; + RNA_property_int_get_array(&ptr, prop, tmp); + for (int i = 0; i < 4; i++) { + r_data[i] = static_cast<float>(tmp[i]); + } + return true; + } + + return false; +} + +static bool find_rna_property_rgba(ID *id, const char *name, float r_data[4]) +{ + PointerRNA ptr; + RNA_id_pointer_create(id, &ptr); + return find_rna_property_rgba(&ptr, name, r_data); +} + +bool BKE_object_dupli_find_rgba_attribute( + Object *ob, DupliObject *dupli, Object *dupli_parent, const char *name, float r_value[4]) +{ + /* Check the dupli particle system. */ + if (dupli && dupli->particle_system) { + ParticleSettings *settings = dupli->particle_system->part; + + if (find_rna_property_rgba(&settings->id, name, r_value)) { + return true; + } + } + + /* Check the dupli parent object. */ + if (dupli_parent && find_rna_property_rgba(&dupli_parent->id, name, r_value)) { + return true; + } + + /* Check the main object. */ + if (ob) { + if (find_rna_property_rgba(&ob->id, name, r_value)) { + return true; + } + + /* Check the main object data (e.g. mesh). */ + if (ob->data && find_rna_property_rgba((ID *)ob->data, name, r_value)) { + return true; + } + } + + copy_v4_fl(r_value, 0.0f); + return false; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.cc index 3fe8b95e656..19e15a169b9 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.cc @@ -111,7 +111,7 @@ void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob) * * Not sure why, this is from Joshua - sergey */ - cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); + cob = BKE_constraints_make_evalob(depsgraph, scene, ob, nullptr, CONSTRAINT_OBTYPE_OBJECT); BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime); BKE_constraints_clear_evalob(cob); } @@ -205,7 +205,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o const bool use_render_params = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); ParticleSystem *tpsys, *psys; ob->transflag &= ~OB_DUPLIPARTS; - psys = ob->particlesystem.first; + psys = static_cast<ParticleSystem *>(ob->particlesystem.first); while (psys) { if (psys_check_enabled(ob, psys, use_render_params)) { /* check use of dupli objects here */ @@ -240,9 +240,9 @@ static void object_sync_boundbox_to_original(Object *object_orig, Object *object } bb = BKE_object_boundbox_get(object_eval); - if (bb != NULL) { - if (object_orig->runtime.bb == NULL) { - object_orig->runtime.bb = MEM_mallocN(sizeof(*object_orig->runtime.bb), __func__); + if (bb != nullptr) { + if (object_orig->runtime.bb == nullptr) { + object_orig->runtime.bb = MEM_new<BoundBox>(__func__); } *object_orig->runtime.bb = *bb; } @@ -264,12 +264,13 @@ void BKE_object_sync_to_original(Depsgraph *depsgraph, Object *object) object_orig->flag = object->flag; /* Copy back error messages from modifiers. */ - for (ModifierData *md = object->modifiers.first, *md_orig = object_orig->modifiers.first; - md != NULL && md_orig != NULL; + for (ModifierData *md = static_cast<ModifierData *>(object->modifiers.first), + *md_orig = static_cast<ModifierData *>(object_orig->modifiers.first); + md != nullptr && md_orig != nullptr; md = md->next, md_orig = md_orig->next) { BLI_assert(md->type == md_orig->type && STREQ(md->name, md_orig->name)); MEM_SAFE_FREE(md_orig->error); - if (md->error != NULL) { + if (md->error != nullptr) { md_orig->error = BLI_strdup(md->error); } } @@ -338,7 +339,7 @@ void BKE_object_eval_transform_all(Depsgraph *depsgraph, Scene *scene, Object *o { /* This mimics full transform update chain from new depsgraph. */ BKE_object_eval_local_transform(depsgraph, object); - if (object->parent != NULL) { + if (object->parent != nullptr) { BKE_object_eval_parent(depsgraph, object); } if (!BLI_listbase_is_empty(&object->constraints)) { @@ -373,12 +374,12 @@ void BKE_object_select_update(Depsgraph *depsgraph, Object *object) if (object->type == OB_MESH && !object->runtime.is_data_eval_owned) { Mesh *mesh_input = (Mesh *)object->runtime.data_orig; Mesh_Runtime *mesh_runtime = &mesh_input->runtime; - BLI_mutex_lock(mesh_runtime->eval_mutex); - BKE_object_data_select_update(depsgraph, object->data); - BLI_mutex_unlock(mesh_runtime->eval_mutex); + BLI_mutex_lock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex)); + BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data)); + BLI_mutex_unlock(static_cast<ThreadMutex *>(mesh_runtime->eval_mutex)); } else { - BKE_object_data_select_update(depsgraph, object->data); + BKE_object_data_select_update(depsgraph, static_cast<ID *>(object->data)); } } @@ -391,9 +392,10 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, { /* TODO(sergey): Avoid list lookup. */ BLI_assert(view_layer_index >= 0); - ViewLayer *view_layer = BLI_findlink(&scene->view_layers, view_layer_index); - BLI_assert(view_layer != NULL); - BLI_assert(view_layer->object_bases_array != NULL); + ViewLayer *view_layer = static_cast<ViewLayer *>( + BLI_findlink(&scene->view_layers, view_layer_index)); + BLI_assert(view_layer != nullptr); + BLI_assert(view_layer->object_bases_array != nullptr); BLI_assert(base_index >= 0); BLI_assert(base_index < MEM_allocN_len(view_layer->object_bases_array) / sizeof(Base *)); Base *base = view_layer->object_bases_array[base_index]; @@ -425,7 +427,9 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, object->runtime.local_collections_bits = base->local_collections_bits; if (object->mode == OB_MODE_PARTICLE_EDIT) { - for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) { + for (ParticleSystem *psys = static_cast<ParticleSystem *>(object->particlesystem.first); + psys != nullptr; + psys = psys->next) { BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); } } @@ -433,8 +437,8 @@ void BKE_object_eval_eval_base_flags(Depsgraph *depsgraph, /* Copy base flag back to the original view layer for editing. */ if (DEG_is_active(depsgraph) && (view_layer == DEG_get_evaluated_view_layer(depsgraph))) { Base *base_orig = base->base_orig; - BLI_assert(base_orig != NULL); - BLI_assert(base_orig->object != NULL); + BLI_assert(base_orig != nullptr); + BLI_assert(base_orig->object != nullptr); base_orig->flag = base->flag; } } diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 6f8242bab0e..47477d4b057 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -2080,6 +2080,14 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) sd->constant_detail = 3.0f; } + if (!sd->automasking_start_normal_limit) { + sd->automasking_start_normal_limit = 20.0f / 180.0f * M_PI; + sd->automasking_start_normal_falloff = 0.25f; + + sd->automasking_view_normal_limit = 90.0f / 180.0f * M_PI; + sd->automasking_view_normal_falloff = 0.25f; + } + /* Set sane default tiling offsets. */ if (!sd->paint.tile_offset[0]) { sd->paint.tile_offset[0] = 1.0f; @@ -2090,6 +2098,9 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene) if (!sd->paint.tile_offset[2]) { sd->paint.tile_offset[2] = 1.0f; } + if (!sd->automasking_cavity_curve || !sd->automasking_cavity_curve_op) { + BKE_sculpt_check_cavity_curves(sd); + } } static bool check_sculpt_object_deformed(Object *object, const bool for_construction) @@ -2234,7 +2245,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect &key, (void **)subdiv_ccg->grid_faces, subdiv_ccg->grid_flag_mats, - subdiv_ccg->grid_hidden); + subdiv_ccg->grid_hidden, + base_mesh); pbvh_show_mask_set(pbvh, ob->sculpt->show_mask); pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); return pbvh; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 5d90287959d..7a16c6db796 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -25,9 +25,9 @@ #include "BKE_pbvh.h" #include "BKE_subdiv_ccg.h" -#include "PIL_time.h" +#include "DRW_pbvh.h" -#include "GPU_buffers.h" +#include "PIL_time.h" #include "bmesh.h" @@ -513,6 +513,80 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim) build_sub(pbvh, 0, cb, prim_bbc, 0, totprim); } +static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node) +{ + memset((void *)args, 0, sizeof(*args)); + + args->pbvh_type = pbvh->header.type; + args->mesh_verts_num = pbvh->totvert; + args->mesh_grids_num = pbvh->totgrid; + args->node = node; + + BKE_pbvh_node_num_verts(pbvh, node, NULL, &args->node_verts_num); + + args->grid_hidden = pbvh->grid_hidden; + args->face_sets_color_default = pbvh->face_sets_color_default; + args->face_sets_color_seed = pbvh->face_sets_color_seed; + args->mesh_positions = pbvh->mesh_positions; + args->mloop = pbvh->mloop; + args->mpoly = pbvh->mpoly; + args->mlooptri = pbvh->looptri; + + if (ELEM(pbvh->header.type, PBVH_FACES, PBVH_GRIDS)) { + args->hide_poly = pbvh->pdata ? + CustomData_get_layer_named(pbvh->pdata, CD_PROP_BOOL, ".hide_poly") : + NULL; + } + + switch (pbvh->header.type) { + case PBVH_FACES: + args->mesh_faces_num = pbvh->mesh->totpoly; + args->vdata = pbvh->vdata; + args->ldata = pbvh->ldata; + args->pdata = pbvh->pdata; + args->totprim = node->totprim; + args->me = pbvh->mesh; + args->mpoly = pbvh->mpoly; + args->vert_normals = pbvh->vert_normals; + + args->prim_indices = node->prim_indices; + args->face_sets = pbvh->face_sets; + break; + case PBVH_GRIDS: + args->vdata = pbvh->vdata; + args->ldata = pbvh->ldata; + args->pdata = pbvh->pdata; + args->ccg_key = pbvh->gridkey; + args->me = pbvh->mesh; + args->totprim = node->totprim; + args->grid_indices = node->prim_indices; + args->subdiv_ccg = pbvh->subdiv_ccg; + args->face_sets = pbvh->face_sets; + args->mpoly = pbvh->mpoly; + + args->mesh_grids_num = pbvh->totgrid; + args->grids = pbvh->grids; + args->gridfaces = pbvh->gridfaces; + args->grid_flag_mats = pbvh->grid_flag_mats; + args->vert_normals = pbvh->vert_normals; + + args->face_sets = pbvh->face_sets; + break; + case PBVH_BMESH: + args->bm = pbvh->header.bm; + args->vdata = &args->bm->vdata; + args->ldata = &args->bm->ldata; + args->pdata = &args->bm->pdata; + args->bm_faces = node->bm_faces; + args->bm_other_verts = node->bm_other_verts; + args->bm_unique_vert = node->bm_unique_verts; + args->totprim = BLI_gset_len(node->bm_faces); + args->cd_mask_layer = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK); + + break; + } +} + void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh, const MPoly *mpoly, @@ -589,7 +663,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh, CCGKey *key, void **gridfaces, DMFlagMat *flagmats, - BLI_bitmap **grid_hidden) + BLI_bitmap **grid_hidden, + Mesh *me) { const int gridsize = key->grid_size; @@ -602,6 +677,14 @@ void BKE_pbvh_build_grids(PBVH *pbvh, pbvh->grid_hidden = grid_hidden; pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), 1); + /* We need the base mesh attribute layout for PBVH draw. */ + pbvh->vdata = &me->vdata; + pbvh->ldata = &me->ldata; + pbvh->pdata = &me->pdata; + + /* We also need the base mesh for PBVH draw. */ + pbvh->mesh = me; + BB cb; BB_reset(&cb); @@ -645,8 +728,8 @@ void BKE_pbvh_free(PBVH *pbvh) PBVHNode *node = &pbvh->nodes[i]; if (node->flag & PBVH_Leaf) { - if (node->draw_buffers) { - GPU_pbvh_buffers_free(node->draw_buffers); + if (node->draw_batches) { + DRW_pbvh_node_free(node->draw_batches); } if (node->vert_indices) { MEM_freeN((void *)node->vert_indices); @@ -693,10 +776,6 @@ void BKE_pbvh_free(PBVH *pbvh) MEM_SAFE_FREE(pbvh->vert_bitmap); - if (pbvh->vbo_id) { - GPU_pbvh_free_format(pbvh->vbo_id); - } - MEM_freeN(pbvh); } @@ -988,6 +1067,8 @@ typedef struct PBVHUpdateData { float (*vnors)[3]; int flag; bool show_sculpt_face_sets; + PBVHAttrReq *attrs; + int attrs_num; } PBVHUpdateData; static void pbvh_update_normals_clear_task_cb(void *__restrict userdata, @@ -1240,13 +1321,6 @@ void pbvh_update_BB_redraw(PBVH *pbvh, PBVHNode **nodes, int totnode, int flag) BLI_task_parallel_range(0, totnode, &data, pbvh_update_BB_redraw_task_cb, &settings); } -static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh)) -{ - int update_flags = GPU_PBVH_BUFFERS_SHOW_VCOL | GPU_PBVH_BUFFERS_SHOW_MASK | - GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS; - return update_flags; -} - bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr) { CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me); @@ -1283,128 +1357,29 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, PBVHNode *node = data->nodes[n]; if (node->flag & PBVH_RebuildDrawBuffers) { - switch (pbvh->header.type) { - case PBVH_GRIDS: { - bool smooth = node->totprim > 0 ? - pbvh->grid_flag_mats[node->prim_indices[0]].flag & ME_SMOOTH : - false; + PBVH_GPU_Args args; + pbvh_draw_args_init(pbvh, &args, node); - node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden, smooth); - break; - } - case PBVH_FACES: - node->draw_buffers = GPU_pbvh_mesh_buffers_build( - pbvh->mesh, pbvh->looptri, node->prim_indices, node->totprim); - break; - case PBVH_BMESH: - node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags & - PBVH_DYNTOPO_SMOOTH_SHADING); - break; - } + node->draw_batches = DRW_pbvh_node_create(&args); } if (node->flag & PBVH_UpdateDrawBuffers) { node->debug_draw_gen++; - const int update_flags = pbvh_get_buffers_update_flags(pbvh); - switch (pbvh->header.type) { - case PBVH_GRIDS: - GPU_pbvh_grid_buffers_update(pbvh->vbo_id, - node->draw_buffers, - pbvh->subdiv_ccg, - pbvh->grids, - pbvh->grid_flag_mats, - node->prim_indices, - node->totprim, - pbvh->face_sets, - pbvh->face_sets_color_seed, - pbvh->face_sets_color_default, - &pbvh->gridkey, - update_flags); - break; - case PBVH_FACES: { - /* Pass vertices separately because they may be not be the same as the mesh's vertices, - * and pass normals separately because they are managed by the PBVH. */ - GPU_pbvh_mesh_buffers_update( - pbvh->vbo_id, - node->draw_buffers, - pbvh->mesh, - pbvh->mesh_positions, - CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK), - CustomData_get_layer_named(pbvh->pdata, CD_PROP_INT32, ".sculpt_face_set"), - pbvh->face_sets_color_seed, - pbvh->face_sets_color_default, - update_flags, - pbvh->vert_normals); - break; - } - case PBVH_BMESH: - GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id, - node->draw_buffers, - pbvh->header.bm, - node->bm_faces, - node->bm_unique_verts, - node->bm_other_verts, - update_flags); - break; - } - } -} - -void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node) -{ - if (node->draw_buffers) { - pbvh->draw_cache_invalid = true; + if (node->draw_batches) { + PBVH_GPU_Args args; - GPU_pbvh_buffers_free(node->draw_buffers); - node->draw_buffers = NULL; + pbvh_draw_args_init(pbvh, &args, node); + DRW_pbvh_node_update(node->draw_batches, &args); + } } } -static void pbvh_check_draw_layout(PBVH *pbvh) +void pbvh_free_draw_buffers(PBVH *UNUSED(pbvh), PBVHNode *node) { - const CustomData *vdata; - const CustomData *ldata; - - if (!pbvh->vbo_id) { - pbvh->vbo_id = GPU_pbvh_make_format(); - } - - switch (pbvh->header.type) { - case PBVH_BMESH: - if (!pbvh->header.bm) { - /* BMesh hasn't been created yet */ - return; - } - - vdata = &pbvh->header.bm->vdata; - ldata = &pbvh->header.bm->ldata; - break; - case PBVH_FACES: - vdata = pbvh->vdata; - ldata = pbvh->ldata; - break; - case PBVH_GRIDS: - ldata = vdata = NULL; - break; - } - - /* Rebuild all draw buffers if attribute layout changed. - * - * NOTE: The optimization where we only send active attributes - * to the GPU in workbench mode is disabled due to bugs - * (there's no guarantee there isn't another EEVEE viewport which would - * free the draw buffers and corrupt the draw cache). - */ - if (GPU_pbvh_attribute_names_update(pbvh->header.type, pbvh->vbo_id, vdata, ldata, false)) { - /* attribute layout changed; force rebuild */ - for (int i = 0; i < pbvh->totnode; i++) { - PBVHNode *node = pbvh->nodes + i; - - if (node->flag & PBVH_Leaf) { - node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw; - } - } + if (node->draw_batches) { + DRW_pbvh_node_free(node->draw_batches); + node->draw_batches = NULL; } } @@ -1412,10 +1387,6 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, { const CustomData *vdata; - if (!pbvh->vbo_id) { - pbvh->vbo_id = GPU_pbvh_make_format(); - } - switch (pbvh->header.type) { case PBVH_BMESH: if (!pbvh->header.bm) { @@ -1441,14 +1412,11 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, if (node->flag & PBVH_RebuildDrawBuffers) { pbvh_free_draw_buffers(pbvh, node); } - else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { - if (pbvh->header.type == PBVH_GRIDS) { - GPU_pbvh_grid_buffers_update_free( - node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices); - } - else if (pbvh->header.type == PBVH_BMESH) { - GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); - } + else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_batches) { + PBVH_GPU_Args args; + + pbvh_draw_args_init(pbvh, &args, node); + DRW_pbvh_update_pre(node->draw_batches, &args); } } } @@ -1468,7 +1436,10 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, if (node->flag & PBVH_UpdateDrawBuffers) { /* Flush buffers uses OpenGL, so not in parallel. */ - GPU_pbvh_buffers_update_flush(node->draw_buffers); + + if (node->draw_batches) { + DRW_pbvh_node_gpu_flush(node->draw_batches); + } } node->flag &= ~(PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers); @@ -2799,6 +2770,8 @@ void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default) typedef struct PBVHDrawSearchData { PBVHFrustumPlanes *frustum; int accum_update_flag; + PBVHAttrReq *attrs; + int attrs_num; } PBVHDrawSearchData; static bool pbvh_draw_search_cb(PBVHNode *node, void *data_v) @@ -2816,9 +2789,11 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, bool update_only_visible, PBVHFrustumPlanes *update_frustum, PBVHFrustumPlanes *draw_frustum, - void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers), + void (*draw_fn)(void *user_data, PBVHBatches *batches, PBVH_GPU_Args *args), void *user_data, - bool UNUSED(full_render)) + bool UNUSED(full_render), + PBVHAttrReq *attrs, + int attrs_num) { PBVHNode **nodes; int totnode; @@ -2829,7 +2804,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, /* Search for nodes that need updates. */ if (update_only_visible) { /* Get visible nodes with draw updates. */ - PBVHDrawSearchData data = {.frustum = update_frustum, .accum_update_flag = 0}; + PBVHDrawSearchData data = { + .frustum = update_frustum, .accum_update_flag = 0, attrs, attrs_num}; BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &data, &nodes, &totnode); update_flag = data.accum_update_flag; } @@ -2841,8 +2817,6 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers; } - pbvh_check_draw_layout(pbvh); - /* Update draw buffers. */ if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) { pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag); @@ -2853,10 +2827,14 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, PBVHDrawSearchData draw_data = {.frustum = draw_frustum, .accum_update_flag = 0}; BKE_pbvh_search_gather(pbvh, pbvh_draw_search_cb, &draw_data, &nodes, &totnode); + PBVH_GPU_Args args; + for (int i = 0; i < totnode; i++) { PBVHNode *node = nodes[i]; if (!(node->flag & PBVH_FullyHidden)) { - draw_fn(user_data, node->draw_buffers); + pbvh_draw_args_init(pbvh, &args, node); + + draw_fn(user_data, node->draw_batches, &args); } } diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index b2f32a38f23..03382de34db 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -29,8 +29,6 @@ #include "PIL_time.h" -#include "GPU_buffers.h" - #include "bmesh.h" #include "atomic_ops.h" diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 81dbff980d5..de908adac79 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -17,7 +17,7 @@ #include "BKE_ccg.h" #include "BKE_pbvh.h" -#include "GPU_buffers.h" +#include "DRW_pbvh.h" #include "bmesh.h" #include "pbvh_intern.h" @@ -347,8 +347,8 @@ static void pbvh_bmesh_node_split(PBVH *pbvh, const BBC *bbc_array, int node_ind n->bm_other_verts = NULL; n->layer_disp = NULL; - if (n->draw_buffers) { - pbvh_free_draw_buffers(pbvh, n); + if (n->draw_batches) { + DRW_pbvh_node_free(n->draw_batches); } n->flag &= ~PBVH_Leaf; diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index b56eb6cd13c..c863a6c92f9 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -32,7 +32,7 @@ struct MeshElemMap; * union'd structs */ struct PBVHNode { /* Opaque handle for drawing code */ - struct GPU_PBVH_Buffers *draw_buffers; + struct PBVHBatches *draw_batches; /* Voxel bounds */ BB vb; diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index 6d10d31e976..2489c64ba0a 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -114,6 +114,32 @@ #include "bmesh.h" +CurveMapping *BKE_sculpt_default_cavity_curve() + +{ + CurveMapping *cumap = BKE_curvemapping_add(1, 0, 0, 1, 1); + + cumap->flag &= ~CUMA_EXTEND_EXTRAPOLATE; + cumap->preset = CURVE_PRESET_LINE; + + BKE_curvemap_reset(cumap->cm, &cumap->clipr, cumap->preset, CURVEMAP_SLOPE_POSITIVE); + BKE_curvemapping_changed(cumap, false); + BKE_curvemapping_init(cumap); + + return cumap; +} + +void BKE_sculpt_check_cavity_curves(Sculpt *sd) +{ + if (!sd->automasking_cavity_curve) { + sd->automasking_cavity_curve = BKE_sculpt_default_cavity_curve(); + } + + if (!sd->automasking_cavity_curve_op) { + sd->automasking_cavity_curve_op = BKE_sculpt_default_cavity_curve(); + } +} + static void scene_init_data(ID *id) { Scene *scene = (Scene *)id; @@ -940,6 +966,13 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres } if (tos->sculpt) { BLO_write_struct(writer, Sculpt, tos->sculpt); + if (tos->sculpt->automasking_cavity_curve) { + BKE_curvemapping_blend_write(writer, tos->sculpt->automasking_cavity_curve); + } + if (tos->sculpt->automasking_cavity_curve_op) { + BKE_curvemapping_blend_write(writer, tos->sculpt->automasking_cavity_curve_op); + } + BKE_paint_blend_write(writer, &tos->sculpt->paint); } if (tos->uvsculpt) { @@ -1153,6 +1186,24 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) sce->toolsettings->particle.object = nullptr; sce->toolsettings->gp_sculpt.paintcursor = nullptr; + if (sce->toolsettings->sculpt) { + BLO_read_data_address(reader, &sce->toolsettings->sculpt->automasking_cavity_curve); + BLO_read_data_address(reader, &sce->toolsettings->sculpt->automasking_cavity_curve_op); + + if (sce->toolsettings->sculpt->automasking_cavity_curve) { + BKE_curvemapping_blend_read(reader, sce->toolsettings->sculpt->automasking_cavity_curve); + BKE_curvemapping_init(sce->toolsettings->sculpt->automasking_cavity_curve); + } + + if (sce->toolsettings->sculpt->automasking_cavity_curve_op) { + BKE_curvemapping_blend_read(reader, + sce->toolsettings->sculpt->automasking_cavity_curve_op); + BKE_curvemapping_init(sce->toolsettings->sculpt->automasking_cavity_curve_op); + } + + BKE_sculpt_check_cavity_curves(sce->toolsettings->sculpt); + } + /* Relink grease pencil interpolation curves. */ BLO_read_data_address(reader, &sce->toolsettings->gp_interpolate.custom_ipo); if (sce->toolsettings->gp_interpolate.custom_ipo) { @@ -1740,6 +1791,18 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) if (ts->sculpt) { ts->sculpt = static_cast<Sculpt *>(MEM_dupallocN(ts->sculpt)); BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint, flag); + + if (ts->sculpt->automasking_cavity_curve) { + ts->sculpt->automasking_cavity_curve = BKE_curvemapping_copy( + ts->sculpt->automasking_cavity_curve); + BKE_curvemapping_init(ts->sculpt->automasking_cavity_curve); + } + + if (ts->sculpt->automasking_cavity_curve_op) { + ts->sculpt->automasking_cavity_curve_op = BKE_curvemapping_copy( + ts->sculpt->automasking_cavity_curve_op); + BKE_curvemapping_init(ts->sculpt->automasking_cavity_curve_op); + } } if (ts->uvsculpt) { ts->uvsculpt = static_cast<UvSculpt *>(MEM_dupallocN(ts->uvsculpt)); @@ -1797,6 +1860,13 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) MEM_freeN(toolsettings->wpaint); } if (toolsettings->sculpt) { + if (toolsettings->sculpt->automasking_cavity_curve) { + BKE_curvemapping_free(toolsettings->sculpt->automasking_cavity_curve); + } + if (toolsettings->sculpt->automasking_cavity_curve_op) { + BKE_curvemapping_free(toolsettings->sculpt->automasking_cavity_curve_op); + } + BKE_paint_free(&toolsettings->sculpt->paint); MEM_freeN(toolsettings->sculpt); } @@ -2261,7 +2331,7 @@ Object *BKE_scene_camera_switch_find(Scene *scene) return nullptr; } - const int ctime = (int)BKE_scene_ctime_get(scene); + const int ctime = int(BKE_scene_ctime_get(scene)); int frame = -(MAXFRAME + 1); int min_frame = MAXFRAME + 1; Object *camera = nullptr; @@ -2802,10 +2872,10 @@ int get_render_child_particle_number(const RenderData *r, int child_num, bool fo { if (r->mode & R_SIMPLIFY) { if (for_render) { - return (int)(r->simplify_particles_render * child_num); + return int(r->simplify_particles_render * child_num); } - return (int)(r->simplify_particles * child_num); + return int(r->simplify_particles * child_num); } return child_num; diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 03f0c3ff1e9..3e5dbc47c40 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -46,6 +46,7 @@ #include "BKE_lib_query.h" #include "BKE_node.h" #include "BKE_screen.h" +#include "BKE_viewer_path.h" #include "BKE_workspace.h" #include "BLO_read_write.h" @@ -97,6 +98,7 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area if (v3d->localvd) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP); } + BKE_viewer_path_foreach_id(data, &v3d->viewer_path); break; } case SPACE_GRAPH: { @@ -197,12 +199,7 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_SPREADSHEET: { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type == SPREADSHEET_CONTEXT_OBJECT) { - BKE_LIB_FOREACHID_PROCESS_IDSUPER( - data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP); - } - } + BKE_viewer_path_foreach_id(data, &sspreadsheet->viewer_path); break; } default: @@ -1123,59 +1120,6 @@ static void write_uilist(BlendWriter *writer, uiList *ui_list) } } -static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space_outliner) -{ - BLI_mempool *ts = space_outliner->treestore; - - if (ts) { - const int elems = BLI_mempool_len(ts); - /* linearize mempool to array */ - TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL; - - if (data) { - BLO_write_struct(writer, SpaceOutliner, space_outliner); - - /* To store #TreeStore (instead of the mempool), two unique memory addresses are needed, - * which can be used to identify the data on read: - * 1) One for the #TreeStore data itself. - * 2) One for the array of #TreeStoreElem's inside #TreeStore (#TreeStore.data). - * - * For 1) we just use the mempool's address (#SpaceOutliner::treestore). - * For 2) we don't have such a direct choice. We can't just use the array's address from - * above, since that may not be unique over all Outliners. So instead use an address relative - * to 1). - */ - /* TODO the mempool could be moved to #SpaceOutliner_Runtime so that #SpaceOutliner could - * hold the #TreeStore directly. */ - - /* Address relative to the tree-store, as noted above. */ - void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); - /* There should be plenty of memory addresses within the mempool data that we can point into, - * just double-check we don't potentially end up with a memory address that another DNA - * struct might use. Assumes BLI_mempool uses the guarded allocator. */ - BLI_assert(MEM_allocN_len(ts) >= sizeof(void *) * 2); - - TreeStore ts_flat = {0}; - ts_flat.usedelem = elems; - ts_flat.totelem = elems; - ts_flat.data = data_addr; - - BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat); - BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data); - - MEM_freeN(data); - } - else { - SpaceOutliner space_outliner_flat = *space_outliner; - space_outliner_flat.treestore = NULL; - BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat); - } - } - else { - BLO_write_struct(writer, SpaceOutliner, space_outliner); - } -} - static void write_panel_list(BlendWriter *writer, ListBase *lb) { LISTBASE_FOREACH (Panel *, panel, lb) { @@ -1208,146 +1152,9 @@ static void write_area(BlendWriter *writer, ScrArea *area) write_region(writer, region, sl->spacetype); } - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - BLO_write_struct(writer, View3D, v3d); - - if (v3d->localvd) { - BLO_write_struct(writer, View3D, v3d->localvd); - } - - BKE_screen_view3d_shading_blend_write(writer, &v3d->shading); - } - else if (sl->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)sl; - ListBase tmpGhosts = sipo->runtime.ghost_curves; - - /* temporarily disable ghost curves when saving */ - BLI_listbase_clear(&sipo->runtime.ghost_curves); - - BLO_write_struct(writer, SpaceGraph, sl); - if (sipo->ads) { - BLO_write_struct(writer, bDopeSheet, sipo->ads); - } - - /* reenable ghost curves */ - sipo->runtime.ghost_curves = tmpGhosts; - } - else if (sl->spacetype == SPACE_PROPERTIES) { - BLO_write_struct(writer, SpaceProperties, sl); - } - else if (sl->spacetype == SPACE_FILE) { - SpaceFile *sfile = (SpaceFile *)sl; - - BLO_write_struct(writer, SpaceFile, sl); - if (sfile->params) { - BLO_write_struct(writer, FileSelectParams, sfile->params); - } - if (sfile->asset_params) { - BLO_write_struct(writer, FileAssetSelectParams, sfile->asset_params); - } - } - else if (sl->spacetype == SPACE_SEQ) { - BLO_write_struct(writer, SpaceSeq, sl); - } - else if (sl->spacetype == SPACE_OUTLINER) { - SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - write_space_outliner(writer, space_outliner); - } - else if (sl->spacetype == SPACE_IMAGE) { - BLO_write_struct(writer, SpaceImage, sl); - } - else if (sl->spacetype == SPACE_TEXT) { - BLO_write_struct(writer, SpaceText, sl); - } - else if (sl->spacetype == SPACE_SCRIPT) { - SpaceScript *scr = (SpaceScript *)sl; - scr->but_refs = NULL; - BLO_write_struct(writer, SpaceScript, sl); - } - else if (sl->spacetype == SPACE_ACTION) { - BLO_write_struct(writer, SpaceAction, sl); - } - else if (sl->spacetype == SPACE_NLA) { - SpaceNla *snla = (SpaceNla *)sl; - - BLO_write_struct(writer, SpaceNla, snla); - if (snla->ads) { - BLO_write_struct(writer, bDopeSheet, snla->ads); - } - } - else if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - BLO_write_struct(writer, SpaceNode, snode); - - LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { - BLO_write_struct(writer, bNodeTreePath, path); - } - } - else if (sl->spacetype == SPACE_CONSOLE) { - SpaceConsole *con = (SpaceConsole *)sl; - - LISTBASE_FOREACH (ConsoleLine *, cl, &con->history) { - /* 'len_alloc' is invalid on write, set from 'len' on read */ - BLO_write_struct(writer, ConsoleLine, cl); - BLO_write_raw(writer, (size_t)cl->len + 1, cl->line); - } - BLO_write_struct(writer, SpaceConsole, sl); - } - else if (sl->spacetype == SPACE_TOPBAR) { - BLO_write_struct(writer, SpaceTopBar, sl); - } - else if (sl->spacetype == SPACE_STATUSBAR) { - BLO_write_struct(writer, SpaceStatusBar, sl); - } - else if (sl->spacetype == SPACE_USERPREF) { - BLO_write_struct(writer, SpaceUserPref, sl); - } - else if (sl->spacetype == SPACE_CLIP) { - BLO_write_struct(writer, SpaceClip, sl); - } - else if (sl->spacetype == SPACE_INFO) { - BLO_write_struct(writer, SpaceInfo, sl); - } - else if (sl->spacetype == SPACE_SPREADSHEET) { - BLO_write_struct(writer, SpaceSpreadsheet, sl); - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - - LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { - BLO_write_struct(writer, SpreadsheetRowFilter, row_filter); - BLO_write_string(writer, row_filter->value_string); - } - - LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) { - BLO_write_struct(writer, SpreadsheetColumn, column); - BLO_write_struct(writer, SpreadsheetColumnID, column->id); - BLO_write_string(writer, column->id->name); - /* While the display name is technically runtime data, we write it here, otherwise the row - * filters might not now their type if their region draws before the main region. - * This would ideally be cleared here. */ - BLO_write_string(writer, column->display_name); - } - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - switch (context->type) { - case SPREADSHEET_CONTEXT_OBJECT: { - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; - BLO_write_struct(writer, SpreadsheetContextObject, object_context); - break; - } - case SPREADSHEET_CONTEXT_MODIFIER: { - SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context; - BLO_write_struct(writer, SpreadsheetContextModifier, modifier_context); - BLO_write_string(writer, modifier_context->modifier_name); - break; - } - case SPREADSHEET_CONTEXT_NODE: { - SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context; - BLO_write_struct(writer, SpreadsheetContextNode, node_context); - BLO_write_string(writer, node_context->node_name); - break; - } - } - } + SpaceType *space_type = BKE_spacetype_from_id(sl->spacetype); + if (space_type && space_type->blend_write) { + space_type->blend_write(writer, sl); } } } @@ -1523,225 +1330,9 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) direct_link_region(reader, region, sl->spacetype); } - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *)sl; - - memset(&v3d->runtime, 0x0, sizeof(v3d->runtime)); - - if (v3d->gpd) { - BLO_read_data_address(reader, &v3d->gpd); - BKE_gpencil_blend_read_data(reader, v3d->gpd); - } - BLO_read_data_address(reader, &v3d->localvd); - - /* render can be quite heavy, set to solid on load */ - if (v3d->shading.type == OB_RENDER) { - v3d->shading.type = OB_SOLID; - } - v3d->shading.prev_type = OB_SOLID; - - BKE_screen_view3d_shading_blend_read_data(reader, &v3d->shading); - - BKE_screen_view3d_do_versions_250(v3d, &sl->regionbase); - } - else if (sl->spacetype == SPACE_GRAPH) { - SpaceGraph *sipo = (SpaceGraph *)sl; - - BLO_read_data_address(reader, &sipo->ads); - memset(&sipo->runtime, 0x0, sizeof(sipo->runtime)); - } - else if (sl->spacetype == SPACE_NLA) { - SpaceNla *snla = (SpaceNla *)sl; - - BLO_read_data_address(reader, &snla->ads); - } - else if (sl->spacetype == SPACE_OUTLINER) { - SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - - /* use #BLO_read_get_new_data_address_no_us and do not free old memory avoiding double - * frees and use of freed memory. this could happen because of a - * bug fixed in revision 58959 where the treestore memory address - * was not unique */ - TreeStore *ts = BLO_read_get_new_data_address_no_us(reader, space_outliner->treestore); - space_outliner->treestore = NULL; - if (ts) { - TreeStoreElem *elems = BLO_read_get_new_data_address_no_us(reader, ts->data); - - space_outliner->treestore = BLI_mempool_create( - sizeof(TreeStoreElem), ts->usedelem, 512, BLI_MEMPOOL_ALLOW_ITER); - if (ts->usedelem && elems) { - for (int i = 0; i < ts->usedelem; i++) { - TreeStoreElem *new_elem = BLI_mempool_alloc(space_outliner->treestore); - *new_elem = elems[i]; - } - } - /* we only saved what was used */ - space_outliner->storeflag |= SO_TREESTORE_CLEANUP; /* at first draw */ - } - space_outliner->tree.first = space_outliner->tree.last = NULL; - space_outliner->runtime = NULL; - } - else if (sl->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - - sima->iuser.scene = NULL; - sima->scopes.waveform_1 = NULL; - sima->scopes.waveform_2 = NULL; - sima->scopes.waveform_3 = NULL; - sima->scopes.vecscope = NULL; - sima->scopes.ok = 0; - - /* WARNING: gpencil data is no longer stored directly in sima after 2.5 - * so sacrifice a few old files for now to avoid crashes with new files! - * committed: r28002 */ -#if 0 - sima->gpd = newdataadr(fd, sima->gpd); - if (sima->gpd) { - BKE_gpencil_blend_read_data(fd, sima->gpd); - } -#endif - } - else if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - - if (snode->gpd) { - BLO_read_data_address(reader, &snode->gpd); - BKE_gpencil_blend_read_data(reader, snode->gpd); - } - - BLO_read_list(reader, &snode->treepath); - snode->edittree = NULL; - snode->runtime = NULL; - } - else if (sl->spacetype == SPACE_TEXT) { - SpaceText *st = (SpaceText *)sl; - memset(&st->runtime, 0x0, sizeof(st->runtime)); - } - else if (sl->spacetype == SPACE_SEQ) { - SpaceSeq *sseq = (SpaceSeq *)sl; - - /* grease pencil data is not a direct data and can't be linked from direct_link* - * functions, it should be linked from lib_link* functions instead - * - * otherwise it'll lead to lost grease data on open because it'll likely be - * read from file after all other users of grease pencil and newdataadr would - * simple return NULL here (sergey) - */ -#if 0 - if (sseq->gpd) { - sseq->gpd = newdataadr(fd, sseq->gpd); - BKE_gpencil_blend_read_data(fd, sseq->gpd); - } -#endif - sseq->scopes.reference_ibuf = NULL; - sseq->scopes.zebra_ibuf = NULL; - sseq->scopes.waveform_ibuf = NULL; - sseq->scopes.sep_waveform_ibuf = NULL; - sseq->scopes.vector_ibuf = NULL; - sseq->scopes.histogram_ibuf = NULL; - memset(&sseq->runtime, 0x0, sizeof(sseq->runtime)); - } - else if (sl->spacetype == SPACE_PROPERTIES) { - SpaceProperties *sbuts = (SpaceProperties *)sl; - - sbuts->path = NULL; - sbuts->texuser = NULL; - sbuts->mainbo = sbuts->mainb; - sbuts->mainbuser = sbuts->mainb; - sbuts->runtime = NULL; - } - else if (sl->spacetype == SPACE_CONSOLE) { - SpaceConsole *sconsole = (SpaceConsole *)sl; - - BLO_read_list(reader, &sconsole->scrollback); - BLO_read_list(reader, &sconsole->history); - - /* Comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression, - * from left to right. the right-most expression sets the result of the comma - * expression as a whole. */ - LISTBASE_FOREACH_MUTABLE (ConsoleLine *, cl, &sconsole->history) { - BLO_read_data_address(reader, &cl->line); - if (cl->line) { - /* The allocated length is not written, so reset here. */ - cl->len_alloc = cl->len + 1; - } - else { - BLI_remlink(&sconsole->history, cl); - MEM_freeN(cl); - } - } - } - else if (sl->spacetype == SPACE_FILE) { - SpaceFile *sfile = (SpaceFile *)sl; - - /* this sort of info is probably irrelevant for reloading... - * plus, it isn't saved to files yet! - */ - sfile->folders_prev = sfile->folders_next = NULL; - BLI_listbase_clear(&sfile->folder_histories); - sfile->files = NULL; - sfile->layout = NULL; - sfile->op = NULL; - sfile->previews_timer = NULL; - sfile->tags = 0; - sfile->runtime = NULL; - BLO_read_data_address(reader, &sfile->params); - BLO_read_data_address(reader, &sfile->asset_params); - if (sfile->params) { - sfile->params->rename_id = NULL; - } - if (sfile->asset_params) { - sfile->asset_params->base_params.rename_id = NULL; - } - } - else if (sl->spacetype == SPACE_ACTION) { - SpaceAction *saction = (SpaceAction *)sl; - - memset(&saction->runtime, 0x0, sizeof(saction->runtime)); - } - else if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sclip = (SpaceClip *)sl; - - sclip->scopes.track_search = NULL; - sclip->scopes.track_preview = NULL; - sclip->scopes.ok = 0; - } - else if (sl->spacetype == SPACE_SPREADSHEET) { - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - - sspreadsheet->runtime = NULL; - BLO_read_list(reader, &sspreadsheet->row_filters); - LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { - BLO_read_data_address(reader, &row_filter->value_string); - } - BLO_read_list(reader, &sspreadsheet->columns); - LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) { - BLO_read_data_address(reader, &column->id); - BLO_read_data_address(reader, &column->id->name); - /* While the display name is technically runtime data, it is loaded here, otherwise the row - * filters might not now their type if their region draws before the main region. - * This would ideally be cleared here. */ - BLO_read_data_address(reader, &column->display_name); - } - - BLO_read_list(reader, &sspreadsheet->context_path); - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - switch (context->type) { - case SPREADSHEET_CONTEXT_NODE: { - SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context; - BLO_read_data_address(reader, &node_context->node_name); - break; - } - case SPREADSHEET_CONTEXT_MODIFIER: { - SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context; - BLO_read_data_address(reader, &modifier_context->modifier_name); - break; - } - case SPREADSHEET_CONTEXT_OBJECT: { - break; - } - } - } + SpaceType *space_type = BKE_spacetype_from_id(sl->spacetype); + if (space_type && space_type->blend_read_data) { + space_type->blend_read_data(reader, sl); } } @@ -1785,185 +1376,10 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr memset(&area->runtime, 0x0, sizeof(area->runtime)); LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - switch (sl->spacetype) { - case SPACE_VIEW3D: { - View3D *v3d = (View3D *)sl; - - BLO_read_id_address(reader, parent_id->lib, &v3d->camera); - BLO_read_id_address(reader, parent_id->lib, &v3d->ob_center); - - if (v3d->localvd) { - BLO_read_id_address(reader, parent_id->lib, &v3d->localvd->camera); - } - break; - } - case SPACE_GRAPH: { - SpaceGraph *sipo = (SpaceGraph *)sl; - bDopeSheet *ads = sipo->ads; + SpaceType *space_type = BKE_spacetype_from_id(sl->spacetype); - if (ads) { - BLO_read_id_address(reader, parent_id->lib, &ads->source); - BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); - } - break; - } - case SPACE_PROPERTIES: { - SpaceProperties *sbuts = (SpaceProperties *)sl; - BLO_read_id_address(reader, parent_id->lib, &sbuts->pinid); - if (sbuts->pinid == NULL) { - sbuts->flag &= ~SB_PIN_CONTEXT; - } - break; - } - case SPACE_FILE: { - SpaceFile *sfile = (SpaceFile *)sl; - sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES; - break; - } - case SPACE_ACTION: { - SpaceAction *saction = (SpaceAction *)sl; - bDopeSheet *ads = &saction->ads; - - if (ads) { - BLO_read_id_address(reader, parent_id->lib, &ads->source); - BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); - } - - BLO_read_id_address(reader, parent_id->lib, &saction->action); - break; - } - case SPACE_IMAGE: { - SpaceImage *sima = (SpaceImage *)sl; - - BLO_read_id_address(reader, parent_id->lib, &sima->image); - BLO_read_id_address(reader, parent_id->lib, &sima->mask_info.mask); - - /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data - * so fingers crossed this works fine! - */ - BLO_read_id_address(reader, parent_id->lib, &sima->gpd); - break; - } - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - - /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data - * so fingers crossed this works fine! - */ - BLO_read_id_address(reader, parent_id->lib, &sseq->gpd); - break; - } - case SPACE_NLA: { - SpaceNla *snla = (SpaceNla *)sl; - bDopeSheet *ads = snla->ads; - - if (ads) { - BLO_read_id_address(reader, parent_id->lib, &ads->source); - BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); - } - break; - } - case SPACE_TEXT: { - SpaceText *st = (SpaceText *)sl; - - BLO_read_id_address(reader, parent_id->lib, &st->text); - break; - } - case SPACE_SCRIPT: { - SpaceScript *scpt = (SpaceScript *)sl; - /*scpt->script = NULL; - 2.45 set to null, better re-run the script */ - if (scpt->script) { - BLO_read_id_address(reader, parent_id->lib, &scpt->script); - if (scpt->script) { - SCRIPT_SET_NULL(scpt->script); - } - } - break; - } - case SPACE_OUTLINER: { - SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - - if (space_outliner->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - - BLI_mempool_iternew(space_outliner->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - BLO_read_id_address(reader, NULL, &tselem->id); - } - /* rebuild hash table, because it depends on ids too */ - space_outliner->storeflag |= SO_TREESTORE_REBUILD; - } - break; - } - case SPACE_NODE: { - SpaceNode *snode = (SpaceNode *)sl; - - /* node tree can be stored locally in id too, link this first */ - BLO_read_id_address(reader, parent_id->lib, &snode->id); - BLO_read_id_address(reader, parent_id->lib, &snode->from); - - bNodeTree *ntree = snode->id ? ntreeFromID(snode->id) : NULL; - if (ntree) { - snode->nodetree = ntree; - } - else { - BLO_read_id_address(reader, parent_id->lib, &snode->nodetree); - } - - bNodeTreePath *path; - for (path = snode->treepath.first; path; path = path->next) { - if (path == snode->treepath.first) { - /* first nodetree in path is same as snode->nodetree */ - path->nodetree = snode->nodetree; - } - else { - BLO_read_id_address(reader, parent_id->lib, &path->nodetree); - } - - if (!path->nodetree) { - break; - } - } - - /* remaining path entries are invalid, remove */ - bNodeTreePath *path_next; - for (; path; path = path_next) { - path_next = path->next; - - BLI_remlink(&snode->treepath, path); - MEM_freeN(path); - } - - /* edittree is just the last in the path, - * set this directly since the path may have been shortened above */ - if (snode->treepath.last) { - path = snode->treepath.last; - snode->edittree = path->nodetree; - } - else { - snode->edittree = NULL; - } - break; - } - case SPACE_CLIP: { - SpaceClip *sclip = (SpaceClip *)sl; - BLO_read_id_address(reader, parent_id->lib, &sclip->clip); - BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask); - break; - } - case SPACE_SPREADSHEET: { - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type == SPREADSHEET_CONTEXT_OBJECT) { - BLO_read_id_address( - reader, parent_id->lib, &((SpreadsheetContextObject *)context)->object); - } - } - break; - } - default: - break; + if (space_type && space_type->blend_read_lib) { + space_type->blend_read_lib(reader, parent_id, sl); } } } diff --git a/source/blender/blenkernel/intern/viewer_path.cc b/source/blender/blenkernel/intern/viewer_path.cc new file mode 100644 index 00000000000..3074a007af4 --- /dev/null +++ b/source/blender/blenkernel/intern/viewer_path.cc @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_viewer_path.h" + +#include "BLI_index_range.hh" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_ref.hh" + +#include "MEM_guardedalloc.h" + +#include "BLO_read_write.h" + +using blender::IndexRange; +using blender::StringRef; + +void BKE_viewer_path_init(ViewerPath *viewer_path) +{ + BLI_listbase_clear(&viewer_path->path); +} + +void BKE_viewer_path_clear(ViewerPath *viewer_path) +{ + LISTBASE_FOREACH_MUTABLE (ViewerPathElem *, elem, &viewer_path->path) { + BKE_viewer_path_elem_free(elem); + } + BLI_listbase_clear(&viewer_path->path); +} + +void BKE_viewer_path_copy(ViewerPath *dst, const ViewerPath *src) +{ + BKE_viewer_path_init(dst); + LISTBASE_FOREACH (const ViewerPathElem *, src_elem, &src->path) { + ViewerPathElem *new_elem = BKE_viewer_path_elem_copy(src_elem); + BLI_addtail(&dst->path, new_elem); + } +} + +bool BKE_viewer_path_equal(const ViewerPath *a, const ViewerPath *b) +{ + const ViewerPathElem *elem_a = static_cast<const ViewerPathElem *>(a->path.first); + const ViewerPathElem *elem_b = static_cast<const ViewerPathElem *>(b->path.first); + + while (elem_a != nullptr && elem_b != nullptr) { + if (!BKE_viewer_path_elem_equal(elem_a, elem_b)) { + return false; + } + elem_a = elem_a->next; + elem_b = elem_b->next; + } + if (elem_a == nullptr && elem_b == nullptr) { + return true; + } + return false; +} + +void BKE_viewer_path_blend_write(struct BlendWriter *writer, const ViewerPath *viewer_path) +{ + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem); + BLO_write_struct(writer, IDViewerPathElem, typed_elem); + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem); + BLO_write_struct(writer, ModifierViewerPathElem, typed_elem); + BLO_write_string(writer, typed_elem->modifier_name); + break; + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem); + BLO_write_struct(writer, NodeViewerPathElem, typed_elem); + BLO_write_string(writer, typed_elem->node_name); + break; + } + } + } +} + +void BKE_viewer_path_blend_read_data(struct BlendDataReader *reader, ViewerPath *viewer_path) +{ + BLO_read_list(reader, &viewer_path->path); + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem); + BLO_read_data_address(reader, &typed_elem->modifier_name); + break; + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem); + BLO_read_data_address(reader, &typed_elem->node_name); + break; + } + } + } +} + +void BKE_viewer_path_blend_read_lib(BlendLibReader *reader, Library *lib, ViewerPath *viewer_path) +{ + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem); + BLO_read_id_address(reader, lib, &typed_elem->id); + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: + case VIEWER_PATH_ELEM_TYPE_NODE: { + break; + } + } + } +} + +void BKE_viewer_path_foreach_id(LibraryForeachIDData *data, ViewerPath *viewer_path) +{ + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem); + BKE_LIB_FOREACHID_PROCESS_ID(data, typed_elem->id, IDWALK_CB_NOP); + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: + case VIEWER_PATH_ELEM_TYPE_NODE: { + break; + } + } + } +} + +void BKE_viewer_path_id_remap(ViewerPath *viewer_path, const IDRemapper *mappings) +{ + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem); + BKE_id_remapper_apply(mappings, &typed_elem->id, ID_REMAP_APPLY_DEFAULT); + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: + case VIEWER_PATH_ELEM_TYPE_NODE: { + break; + } + } + } +} + +ViewerPathElem *BKE_viewer_path_elem_new(const ViewerPathElemType type) +{ + switch (type) { + case VIEWER_PATH_ELEM_TYPE_ID: { + IDViewerPathElem *elem = MEM_cnew<IDViewerPathElem>(__func__); + elem->base.type = type; + return &elem->base; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + ModifierViewerPathElem *elem = MEM_cnew<ModifierViewerPathElem>(__func__); + elem->base.type = type; + return &elem->base; + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + NodeViewerPathElem *elem = MEM_cnew<NodeViewerPathElem>(__func__); + elem->base.type = type; + return &elem->base; + } + } + BLI_assert_unreachable(); + return nullptr; +} + +IDViewerPathElem *BKE_viewer_path_elem_new_id() +{ + return reinterpret_cast<IDViewerPathElem *>(BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_ID)); +} + +ModifierViewerPathElem *BKE_viewer_path_elem_new_modifier() +{ + return reinterpret_cast<ModifierViewerPathElem *>( + BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_MODIFIER)); +} + +NodeViewerPathElem *BKE_viewer_path_elem_new_node() +{ + return reinterpret_cast<NodeViewerPathElem *>( + BKE_viewer_path_elem_new(VIEWER_PATH_ELEM_TYPE_NODE)); +} + +ViewerPathElem *BKE_viewer_path_elem_copy(const ViewerPathElem *src) +{ + ViewerPathElem *dst = BKE_viewer_path_elem_new(ViewerPathElemType(src->type)); + switch (ViewerPathElemType(src->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto old_elem = reinterpret_cast<const IDViewerPathElem *>(src); + auto new_elem = reinterpret_cast<IDViewerPathElem *>(dst); + new_elem->id = old_elem->id; + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + auto old_elem = reinterpret_cast<const ModifierViewerPathElem *>(src); + auto new_elem = reinterpret_cast<ModifierViewerPathElem *>(dst); + if (old_elem->modifier_name != nullptr) { + new_elem->modifier_name = BLI_strdup(old_elem->modifier_name); + } + break; + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + auto old_elem = reinterpret_cast<const NodeViewerPathElem *>(src); + auto new_elem = reinterpret_cast<NodeViewerPathElem *>(dst); + if (old_elem->node_name != nullptr) { + new_elem->node_name = BLI_strdup(old_elem->node_name); + } + break; + } + } + return dst; +} + +bool BKE_viewer_path_elem_equal(const ViewerPathElem *a, const ViewerPathElem *b) +{ + if (a->type != b->type) { + return false; + } + switch (ViewerPathElemType(a->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + auto a_elem = reinterpret_cast<const IDViewerPathElem *>(a); + auto b_elem = reinterpret_cast<const IDViewerPathElem *>(b); + return a_elem->id == b_elem->id; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + auto a_elem = reinterpret_cast<const ModifierViewerPathElem *>(a); + auto b_elem = reinterpret_cast<const ModifierViewerPathElem *>(b); + return StringRef(a_elem->modifier_name) == StringRef(b_elem->modifier_name); + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + auto a_elem = reinterpret_cast<const NodeViewerPathElem *>(a); + auto b_elem = reinterpret_cast<const NodeViewerPathElem *>(b); + return StringRef(a_elem->node_name) == StringRef(b_elem->node_name); + } + } + return false; +} + +void BKE_viewer_path_elem_free(ViewerPathElem *elem) +{ + switch (ViewerPathElemType(elem->type)) { + case VIEWER_PATH_ELEM_TYPE_ID: { + break; + } + case VIEWER_PATH_ELEM_TYPE_MODIFIER: { + auto typed_elem = reinterpret_cast<ModifierViewerPathElem *>(elem); + MEM_SAFE_FREE(typed_elem->modifier_name); + break; + } + case VIEWER_PATH_ELEM_TYPE_NODE: { + auto typed_elem = reinterpret_cast<NodeViewerPathElem *>(elem); + MEM_SAFE_FREE(typed_elem->node_name); + break; + } + } + MEM_freeN(elem); +} diff --git a/source/blender/blenkernel/intern/workspace.cc b/source/blender/blenkernel/intern/workspace.cc index 8008dacc853..a7fd433b42b 100644 --- a/source/blender/blenkernel/intern/workspace.cc +++ b/source/blender/blenkernel/intern/workspace.cc @@ -24,6 +24,7 @@ #include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" +#include "BKE_viewer_path.h" #include "BKE_workspace.h" #include "DNA_object_types.h" @@ -61,6 +62,7 @@ static void workspace_free_data(ID *id) } MEM_SAFE_FREE(workspace->status_text); + BKE_viewer_path_clear(&workspace->viewer_path); } static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) @@ -72,6 +74,8 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER); } + + BKE_viewer_path_foreach_id(data, &workspace->viewer_path); } static void workspace_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -89,6 +93,8 @@ static void workspace_blend_write(BlendWriter *writer, ID *id, const void *id_ad IDP_BlendWrite(writer, tref->properties); } } + + BKE_viewer_path_blend_write(writer, &workspace->viewer_path); } static void workspace_blend_read_data(BlendDataReader *reader, ID *id) @@ -115,6 +121,8 @@ static void workspace_blend_read_data(BlendDataReader *reader, ID *id) workspace->status_text = nullptr; id_us_ensure_real(&workspace->id); + + BKE_viewer_path_blend_read_data(reader, &workspace->viewer_path); } static void workspace_blend_read_lib(BlendLibReader *reader, ID *id) @@ -164,6 +172,8 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id) BKE_workspace_layout_remove(bmain, workspace, layout); } } + + BKE_viewer_path_blend_read_lib(reader, id->lib, &workspace->viewer_path); } static void workspace_blend_read_expand(BlendExpander *expander, ID *id) diff --git a/source/blender/blenlib/BLI_compiler_attrs.h b/source/blender/blenlib/BLI_compiler_attrs.h index 9ee626296cb..f0566e0b3e2 100644 --- a/source/blender/blenlib/BLI_compiler_attrs.h +++ b/source/blender/blenlib/BLI_compiler_attrs.h @@ -46,7 +46,7 @@ #endif /* the function return value points to memory (2 args for 'size * tot') */ -#ifdef __GNUC__ +#if defined(__GNUC__) && !defined(__clang__) # define ATTR_ALLOC_SIZE(args...) __attribute__((alloc_size(args))) #else # define ATTR_ALLOC_SIZE(...) diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh index c19317867a9..5916193894b 100644 --- a/source/blender/blenlib/BLI_math_vec_types.hh +++ b/source/blender/blenlib/BLI_math_vec_types.hh @@ -556,6 +556,11 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> } }; +using char3 = blender::vec_base<int8_t, 3>; + +using uchar3 = blender::vec_base<uint8_t, 3>; +using uchar4 = blender::vec_base<uint8_t, 4>; + using int2 = vec_base<int32_t, 2>; using int3 = vec_base<int32_t, 3>; using int4 = vec_base<int32_t, 4>; @@ -564,7 +569,11 @@ using uint2 = vec_base<uint32_t, 2>; using uint3 = vec_base<uint32_t, 3>; using uint4 = vec_base<uint32_t, 4>; +using short3 = blender::vec_base<int16_t, 3>; + using ushort2 = vec_base<uint16_t, 2>; +using ushort3 = blender::vec_base<uint16_t, 3>; +using ushort4 = blender::vec_base<uint16_t, 4>; using float2 = vec_base<float, 2>; using float3 = vec_base<float, 3>; diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index e0d05f8c36a..2ac77f000e9 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -171,9 +171,9 @@ set(SRC BLI_asan.h BLI_assert.h BLI_astar.h + BLI_bit_vector.hh BLI_bitmap.h BLI_bitmap_draw_2d.h - BLI_bit_vector.hh BLI_blenlib.h BLI_bounds.hh BLI_boxpack_2d.h @@ -239,6 +239,7 @@ set(SRC BLI_kdtree.h BLI_kdtree_impl.h BLI_lasso_2d.h + BLI_lazy_threading.hh BLI_length_parameterize.hh BLI_linear_allocator.hh BLI_link_utils.h diff --git a/source/blender/blenlib/intern/math_boolean.cc b/source/blender/blenlib/intern/math_boolean.cc index 871ea815e90..e5352540dd6 100644 --- a/source/blender/blenlib/intern/math_boolean.cc +++ b/source/blender/blenlib/intern/math_boolean.cc @@ -2191,18 +2191,18 @@ static double insphereadapt(const double *pa, INEXACT double _i, _j; double _0; - aex = (double)(pa[0] - pe[0]); - bex = (double)(pb[0] - pe[0]); - cex = (double)(pc[0] - pe[0]); - dex = (double)(pd[0] - pe[0]); - aey = (double)(pa[1] - pe[1]); - bey = (double)(pb[1] - pe[1]); - cey = (double)(pc[1] - pe[1]); - dey = (double)(pd[1] - pe[1]); - aez = (double)(pa[2] - pe[2]); - bez = (double)(pb[2] - pe[2]); - cez = (double)(pc[2] - pe[2]); - dez = (double)(pd[2] - pe[2]); + aex = double(pa[0] - pe[0]); + bex = double(pb[0] - pe[0]); + cex = double(pc[0] - pe[0]); + dex = double(pd[0] - pe[0]); + aey = double(pa[1] - pe[1]); + bey = double(pb[1] - pe[1]); + cey = double(pc[1] - pe[1]); + dey = double(pd[1] - pe[1]); + aez = double(pa[2] - pe[2]); + bez = double(pb[2] - pe[2]); + cez = double(pc[2] - pe[2]); + dez = double(pd[2] - pe[2]); Two_Product(aex, bey, aexbey1, aexbey0); Two_Product(bex, aey, bexaey1, bexaey0); diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c index c03243acb26..b8c17ce20fa 100644 --- a/source/blender/blenlib/intern/noise.c +++ b/source/blender/blenlib/intern/noise.c @@ -1329,8 +1329,8 @@ float BLI_noise_mg_fbm( float BLI_noise_mg_multi_fractal( float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis) { - /* This one is in fact rather confusing, - * there seem to be errors in the original source code (in all three versions of proc.text&mod), + /* This one is in fact rather confusing, there seem to be errors in the original source code + * (in all three versions of `proc.text & mod`), * I modified it to something that made sense to me, so it might be wrong. */ float (*noisefunc)(float, float, float); diff --git a/source/blender/blenlib/tests/performance/CMakeLists.txt b/source/blender/blenlib/tests/performance/CMakeLists.txt index 722fd44733a..aa26f796e0d 100644 --- a/source/blender/blenlib/tests/performance/CMakeLists.txt +++ b/source/blender/blenlib/tests/performance/CMakeLists.txt @@ -6,8 +6,8 @@ set(INC .. ../.. ../../../makesdna - ../../../../../intern/guardedalloc ../../../../../intern/atomic + ../../../../../intern/guardedalloc ) include_directories(${INC}) diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 7c07d373999..fa9368db0d8 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -2515,6 +2515,17 @@ static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, View } } +static void lib_link_restore_viewer_path(struct IDNameLib_Map *id_map, ViewerPath *viewer_path) +{ + LISTBASE_FOREACH (ViewerPathElem *, elem, &viewer_path->path) { + if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) { + auto typed_elem = reinterpret_cast<IDViewerPathElem *>(elem); + typed_elem->id = static_cast<ID *>( + restore_pointer_by_name(id_map, (ID *)typed_elem->id, USER_IGNORE)); + } + } +} + static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, Main *newmain, WorkSpaceLayout *layout) @@ -2532,6 +2543,8 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, restore_pointer_by_name(id_map, (ID *)v3d->camera, USER_REAL)); v3d->ob_center = static_cast<Object *>( restore_pointer_by_name(id_map, (ID *)v3d->ob_center, USER_REAL)); + + lib_link_restore_viewer_path(id_map, &v3d->viewer_path); } else if (sl->spacetype == SPACE_GRAPH) { SpaceGraph *sipo = (SpaceGraph *)sl; @@ -2741,14 +2754,7 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map, } else if (sl->spacetype == SPACE_SPREADSHEET) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type == SPREADSHEET_CONTEXT_OBJECT) { - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; - object_context->object = static_cast<Object *>( - restore_pointer_by_name(id_map, (ID *)object_context->object, USER_IGNORE)); - } - } + lib_link_restore_viewer_path(id_map, &sspreadsheet->viewer_path); } } } @@ -2770,6 +2776,7 @@ void blo_lib_link_restore(Main *oldmain, } workspace->pin_scene = static_cast<Scene *>( restore_pointer_by_name(id_map, (ID *)workspace->pin_scene, USER_IGNORE)); + lib_link_restore_viewer_path(id_map, &workspace->viewer_path); } LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) { @@ -5104,12 +5111,12 @@ static void convert_pointer_array_64_to_32(BlendDataReader *reader, for (int i = 0; i < array_size; i++) { uint64_t ptr = src[i]; BLI_endian_switch_uint64(&ptr); - dst[i] = (uint32_t)(ptr >> 3); + dst[i] = uint32_t(ptr >> 3); } } else { for (int i = 0; i < array_size; i++) { - dst[i] = (uint32_t)(src[i] >> 3); + dst[i] = uint32_t(src[i] >> 3); } } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 5cbfcb66bf9..3e26516cd69 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3385,7 +3385,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) View3D *v3d = (View3D *)sl; v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 | V3D_FLAG_UNUSED_12); - v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 | + v3d->flag2 &= ~((1 << 3) | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 | V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15); break; } diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index f0ebc6c7942..373d68082a6 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -1757,7 +1757,7 @@ static void versioning_replace_legacy_mix_rgb_node(bNodeTree *ntree) node->type = SH_NODE_MIX; NodeShaderMix *data = (NodeShaderMix *)MEM_callocN(sizeof(NodeShaderMix), __func__); data->blend_type = node->custom1; - data->clamp_result = node->custom2; + data->clamp_result = (node->custom2 & SHD_MIXRGB_CLAMP) ? 1 : 0; data->clamp_factor = 1; data->data_type = SOCK_RGBA; data->factor_mode = NODE_MIX_MODE_UNIFORM; @@ -3034,9 +3034,9 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) gpmd->factor *= 2.0f; } else { - gpmd->step = 1 + (int)(gpmd->factor * max_ff(0.0f, - min_ff(5.1f * sqrtf(gpmd->step) - 3.0f, - gpmd->step + 2.0f))); + gpmd->step = 1 + int(gpmd->factor * max_ff(0.0f, + min_ff(5.1f * sqrtf(gpmd->step) - 3.0f, + gpmd->step + 2.0f))); gpmd->factor = 1.0f; } } @@ -3337,6 +3337,14 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!DNA_struct_elem_find(fd->filesdna, "Sculpt", "float", "automasking_cavity_factor")) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->toolsettings && scene->toolsettings->sculpt) { + scene->toolsettings->sculpt->automasking_cavity_factor = 0.5f; + } + } + } + if (!MAIN_VERSION_ATLEAST(bmain, 302, 14)) { /* Compensate for previously wrong squared distance. */ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { @@ -3519,6 +3527,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) BKE_main_namemap_validate_and_fix(bmain); } + if (!MAIN_VERSION_ATLEAST(bmain, 304, 1)) { /* Image generation information transferred to tiles. */ if (!DNA_struct_elem_find(fd->filesdna, "ImageTile", "int", "gen_x")) { @@ -3575,6 +3584,13 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_ATLEAST(bmain, 304, 2)) { + /* Initialize brush curves sculpt settings. */ + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + brush->automasking_cavity_factor = 0.5f; + } + } + /** * Versioning code until next subversion bump goes here. * @@ -3586,5 +3602,18 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->flag2 |= V3D_SHOW_VIEWER; + v3d->overlay.flag |= V3D_OVERLAY_VIEWER_ATTRIBUTE; + v3d->overlay.viewer_attribute_opacity = 0.8f; + } + } + } + } } } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 99ca49f3d4f..bf04228efef 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -563,7 +563,7 @@ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short ofl CustomData_data_multiply(type, &max, 0.5f); CustomData_data_add(type, &min, &max); - /* snap CD (uv, vcol) points to their centroid */ + /* Snap custom-data (UV, vertex-colors) points to their centroid. */ while (!BLI_stack_is_empty(block_stack)) { void *block; BLI_stack_pop(block_stack, &block); diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index bd479bad945..02f0a25ea06 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -229,14 +229,15 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool #ifdef USE_WALKER /* Walk over selected elements starting at active */ - BMW_init(&walker, - bm, - BMW_CONNECTED_VERTEX, - ELE_VERT_TAG, - BMW_MASK_NOP, - BMW_MASK_NOP, - BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ - BMW_NIL_LAY); + BMW_init( + &walker, + bm, + BMW_CONNECTED_VERTEX, + ELE_VERT_TAG, + BMW_MASK_NOP, + BMW_MASK_NOP, + BMW_FLAG_NOP, /* don't use #BMW_FLAG_TEST_HIDDEN here since we want to deselect all. */ + BMW_NIL_LAY); BLI_assert(walker.order == BMW_BREADTH_FIRST); for (v = BMW_begin(&walker, v_first); v != NULL; v = BMW_step(&walker)) { diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index d832676fe2c..4a9025641f9 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -27,6 +27,7 @@ struct ListBase; struct PointerRNA; struct Scene; struct ViewLayer; +struct ViewerPath; #ifdef __cplusplus extern "C" { @@ -152,6 +153,12 @@ typedef struct DEGObjectIterSettings { * and will crash if you try to access it. */ uint32_t flags; + + /** + * When set, the final evaluated geometry of the corresponding object is omitted. Instead the + * geometry for the viewer path included in the iterator. + */ + const struct ViewerPath *viewer_path; } DEGObjectIterSettings; /** @@ -170,6 +177,9 @@ typedef struct DEGObjectIterData { eEvaluationMode eval_mode; + /** Object whose preview instead of evaluated geometry should be part of the iterator. */ + struct Object *object_orig_with_preview; + struct Object *next_object; /* **** Iteration over dupli-list. *** */ diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index bcae5de1e1e..5a92f483420 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -127,14 +127,11 @@ bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject return false; } -void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object) +void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object, ListBase *duplis) { - if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && - ((object->transflag & OB_DUPLI) || object->runtime.geometry_set_eval != nullptr)) { - data->dupli_parent = object; - data->dupli_list = object_duplilist(data->graph, data->scene, object); - data->dupli_object_next = (DupliObject *)data->dupli_list->first; - } + data->dupli_parent = object; + data->dupli_list = duplis; + data->dupli_object_next = static_cast<DupliObject *>(duplis->first); } /* Returns false when iterator is exhausted. */ @@ -250,7 +247,18 @@ bool deg_iterator_objects_step(DEGObjectIterData *data) } Object *object = (Object *)id_node->id_cow; + Object *object_orig = DEG_get_original_object(object); BLI_assert(deg::deg_validate_copy_on_write_datablock(&object->id)); + object->runtime.select_id = object_orig->runtime.select_id; + + const bool use_preview = object_orig == data->object_orig_with_preview; + if (use_preview) { + ListBase *preview_duplis = object_duplilist_preview( + data->graph, data->scene, object, data->settings->viewer_path); + deg_iterator_duplis_init(data, object, preview_duplis); + data->id_node_index++; + return true; + } int ob_visibility = OB_VISIBLE_ALL; if (data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) { @@ -261,9 +269,12 @@ bool deg_iterator_objects_step(DEGObjectIterData *data) } } - object->runtime.select_id = DEG_get_original_object(object)->runtime.select_id; if (ob_visibility & OB_VISIBLE_INSTANCES) { - deg_iterator_duplis_init(data, object); + if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && + ((object->transflag & OB_DUPLI) || object->runtime.geometry_set_eval != nullptr)) { + ListBase *duplis = object_duplilist(data->graph, data->scene, object); + deg_iterator_duplis_init(data, object, duplis); + } } if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) { @@ -301,6 +312,22 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) data->eval_mode = DEG_get_mode(depsgraph); deg_invalidate_iterator_work_data(data); + /* Determine if the preview of any object should be in the iterator. */ + const ViewerPath *viewer_path = data->settings->viewer_path; + if (viewer_path != nullptr) { + if (!BLI_listbase_is_empty(&viewer_path->path)) { + const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path->path.first); + if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) { + const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem); + if (id_elem->id != nullptr) { + if (GS(id_elem->id->name) == ID_OB) { + data->object_orig_with_preview = reinterpret_cast<Object *>(id_elem->id); + } + } + } + } + } + DEG_iterator_objects_next(iter); } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 540041ed02a..01268509200 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -88,12 +88,13 @@ set(SRC intern/draw_instance_data.c intern/draw_manager.c intern/draw_manager.cc - intern/draw_manager_data.c + intern/draw_manager_data.cc intern/draw_manager_exec.c intern/draw_manager_profiling.c intern/draw_manager_shader.c - intern/draw_manager_text.c + intern/draw_manager_text.cc intern/draw_manager_texture.c + intern/draw_pbvh.cc intern/draw_select_buffer.c intern/draw_shader.cc intern/draw_texture_pool.cc @@ -201,10 +202,12 @@ set(SRC engines/overlay/overlay_sculpt.cc engines/overlay/overlay_sculpt_curves.cc engines/overlay/overlay_shader.cc + engines/overlay/overlay_viewer_attribute.cc engines/overlay/overlay_volume.cc engines/overlay/overlay_wireframe.cc DRW_engine.h + DRW_pbvh.h DRW_select_buffer.h intern/DRW_gpu_wrapper.hh intern/DRW_render.h @@ -229,6 +232,7 @@ set(SRC intern/draw_manager_testing.h intern/draw_manager_text.h intern/draw_pass.hh + intern/draw_pbvh.h intern/draw_resource.cc intern/draw_resource.hh intern/draw_shader.h @@ -250,6 +254,7 @@ set(SRC engines/eevee/eevee_lut.h engines/eevee/eevee_private.h engines/eevee_next/eevee_camera.hh + engines/eevee_next/eevee_cryptomatte.hh engines/eevee_next/eevee_depth_of_field.hh engines/eevee_next/eevee_engine.h engines/eevee_next/eevee_film.hh @@ -645,12 +650,18 @@ set(GLSL_SRC engines/overlay/shaders/overlay_particle_vert.glsl engines/overlay/shaders/overlay_point_varying_color_frag.glsl engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl + engines/overlay/shaders/overlay_pointcloud_only_vert.glsl engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl engines/overlay/shaders/overlay_sculpt_mask_frag.glsl engines/overlay/shaders/overlay_sculpt_mask_vert.glsl engines/overlay/shaders/overlay_uniform_color_frag.glsl engines/overlay/shaders/overlay_varying_color.glsl + engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl + engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl + engines/overlay/shaders/overlay_viewer_attribute_frag.glsl + engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl + engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl engines/overlay/shaders/overlay_volume_gridlines_vert.glsl engines/overlay/shaders/overlay_volume_velocity_vert.glsl engines/overlay/shaders/overlay_wireframe_frag.glsl diff --git a/source/blender/draw/DRW_pbvh.h b/source/blender/draw/DRW_pbvh.h new file mode 100644 index 00000000000..ffd4b92d87b --- /dev/null +++ b/source/blender/draw/DRW_pbvh.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. */ + +/** \file + * \ingroup draw + */ + +#pragma once + +/* Needed for BKE_ccg.h. */ +#include "BLI_assert.h" +#include "BLI_bitmap.h" + +#include "BKE_ccg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GPUViewport; +struct PBVHAttrReq; +struct GPUBatch; +struct PBVHNode; +struct GSet; +struct DMFlagMat; +struct Object; +struct Mesh; +struct MLoopTri; +struct CustomData; +struct MVert; +struct MEdge; +struct MLoop; +struct MPoly; +struct SubdivCCG; +struct BMesh; + +typedef struct PBVHBatches PBVHBatches; + +typedef struct PBVH_GPU_Args { + int pbvh_type; + + struct BMesh *bm; + const struct Mesh *me; + const struct MVert *mvert; + const struct MLoop *mloop; + const struct MPoly *mpoly; + int mesh_verts_num, mesh_faces_num, mesh_grids_num; + struct CustomData *vdata, *ldata, *pdata; + const float (*vert_normals)[3]; + + int face_sets_color_seed, face_sets_color_default; + int *face_sets; /* for PBVH_FACES and PBVH_GRIDS */ + + struct SubdivCCG *subdiv_ccg; + const struct DMFlagMat *grid_flag_mats; + const int *grid_indices; + CCGKey ccg_key; + CCGElem **grids; + void **gridfaces; + BLI_bitmap **grid_hidden; + + int *prim_indices; + int totprim; + + bool *hide_poly; + + int node_verts_num; + + const struct MLoopTri *mlooptri; + struct PBVHNode *node; + + /* BMesh. */ + struct GSet *bm_unique_vert, *bm_other_verts, *bm_faces; + int cd_mask_layer; +} PBVH_GPU_Args; + +typedef struct PBVHGPUFormat PBVHGPUFormat; + +void DRW_pbvh_node_update(PBVHBatches *batches, PBVH_GPU_Args *args); +void DRW_pbvh_update_pre(PBVHBatches *batches, PBVH_GPU_Args *args); + +void DRW_pbvh_node_gpu_flush(PBVHBatches *batches); +struct PBVHBatches *DRW_pbvh_node_create(PBVH_GPU_Args *args); +void DRW_pbvh_node_free(PBVHBatches *batches); +struct GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches, + struct PBVHAttrReq *attrs, + int attrs_num, + PBVH_GPU_Args *args, + int *r_prim_count); +struct GPUBatch *DRW_pbvh_lines_get(struct PBVHBatches *batches, + struct PBVHAttrReq *attrs, + int attrs_num, + PBVH_GPU_Args *args, + int *r_prim_count); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 975d9e299bf..86c565371c1 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -199,7 +199,7 @@ static void basic_cache_populate(void *vedata, Object *ob) } if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(shgrp, ob, false, false); + DRW_shgroup_call_sculpt(shgrp, ob, false, false, false, false, false); } else { if (stl->g_data->use_material_slot_selection && BKE_object_supports_material_slots(ob)) { diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 94f29d64628..1cb630e6d59 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -824,14 +824,17 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, if (use_sculpt_pbvh) { struct DRWShadingGroup **shgrps_array = BLI_array_alloca(shgrps_array, materials_len); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + MATCACHE_AS_ARRAY(matcache, shading_gpumat, materials_len, gpumat_array); + MATCACHE_AS_ARRAY(matcache, shading_grp, materials_len, shgrps_array); - DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, gpumat_array, materials_len, ob); MATCACHE_AS_ARRAY(matcache, depth_grp, materials_len, shgrps_array); - DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, gpumat_array, materials_len, ob); MATCACHE_AS_ARRAY(matcache, shadow_grp, materials_len, shgrps_array); - DRW_shgroup_call_sculpt_with_materials(shgrps_array, materials_len, ob); + DRW_shgroup_call_sculpt_with_materials(shgrps_array, gpumat_array, materials_len, ob); } else { struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 88e56bdc01c..6f30ffcb364 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -837,7 +837,7 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; struct GPUTexture *unf_source_buffer; /* pointer copy */ struct GPUTexture *unf_base_buffer; /* pointer copy */ - /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */ + /* Not allocated, just a copy of a *GPUtexture in EEVEE_TextureList. */ struct GPUTexture *source_buffer; /* latest updated texture */ struct GPUFrameBuffer *target_buffer; /* next target to render to */ struct GPUTexture *final_tx; /* Final color to transform to display color space. */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index bbcae92561d..c2c4706138f 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -16,6 +16,7 @@ #include "UI_interface.h" +#include "BKE_duplilist.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -204,6 +205,7 @@ static void OVERLAY_cache_init(void *vedata) } OVERLAY_antialiasing_cache_init(data); OVERLAY_armature_cache_init(data); + OVERLAY_viewer_attribute_cache_init(data); OVERLAY_background_cache_init(data); OVERLAY_fade_cache_init(data); OVERLAY_mode_transfer_cache_init(data); @@ -300,8 +302,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) } const DRWContextState *draw_ctx = DRW_context_state_get(); + DupliObject *dupli_object = DRW_object_get_dupli(ob); + Object *dupli_parent = DRW_object_get_dupli_parent(ob); const bool is_select = DRW_state_is_select(); const bool renderable = DRW_object_is_renderable(ob); + const bool is_preview = dupli_object != nullptr && + dupli_object->preview_base_geometry != nullptr; const bool in_pose_mode = ob->type == OB_ARMATURE && OVERLAY_armature_is_pose_mode(ob, draw_ctx); const bool in_edit_mode = overlay_object_is_edit_mode(pd, ob); const bool is_instance = (ob->base_flag & BASE_FROM_DUPLI); @@ -313,7 +319,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) (pd->ctx_mode == CTX_MODE_PARTICLE); const bool in_paint_mode = (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT); - const bool in_sculpt_curve_mode = (ob == draw_ctx->obact) && + const bool in_sculpt_curve_mode = (ob == draw_ctx->obact || + (is_preview && dupli_parent == draw_ctx->obact)) && (draw_ctx->object_mode & OB_MODE_SCULPT_CURVES); const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != nullptr) && (ob->sculpt->mode_type == OB_MODE_SCULPT); @@ -374,6 +381,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OVERLAY_pose_cache_populate(data, ob); } + if (pd->overlay.flag & V3D_OVERLAY_VIEWER_ATTRIBUTE) { + if (is_preview) { + OVERLAY_viewer_attribute_cache_populate(data, ob); + } + } + if (ob->type == OB_VOLUME) { OVERLAY_volume_cache_populate(data, ob); } @@ -627,6 +640,9 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_metaball_draw(data); OVERLAY_gpencil_draw(data); OVERLAY_extra_draw(data); + if (pd->overlay.flag & V3D_OVERLAY_VIEWER_ATTRIBUTE) { + OVERLAY_viewer_attribute_draw(data); + } if (DRW_state_is_fbo()) { GPU_framebuffer_bind(fbl->overlay_color_only_fb); diff --git a/source/blender/draw/engines/overlay/overlay_facing.cc b/source/blender/draw/engines/overlay/overlay_facing.cc index 9a501c8f1bb..e40c32b30fc 100644 --- a/source/blender/draw/engines/overlay/overlay_facing.cc +++ b/source/blender/draw/engines/overlay/overlay_facing.cc @@ -48,7 +48,7 @@ void OVERLAY_facing_cache_populate(OVERLAY_Data *vedata, Object *ob) const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(pd->facing_grp[is_xray], ob, false, false); + DRW_shgroup_call_sculpt(pd->facing_grp[is_xray], ob, false, false, false, false, false); } else { struct GPUBatch *geom = DRW_cache_object_surface_get(ob); diff --git a/source/blender/draw/engines/overlay/overlay_fade.cc b/source/blender/draw/engines/overlay/overlay_fade.cc index ee5540d91eb..f99e77b75f2 100644 --- a/source/blender/draw/engines/overlay/overlay_fade.cc +++ b/source/blender/draw/engines/overlay/overlay_fade.cc @@ -58,7 +58,7 @@ void OVERLAY_fade_cache_populate(OVERLAY_Data *vedata, Object *ob) const bool is_xray = (ob->dtx & OB_DRAW_IN_FRONT) != 0; if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(pd->fade_grp[is_xray], ob, false, false); + DRW_shgroup_call_sculpt(pd->fade_grp[is_xray], ob, false, false, false, false, false); } else { struct GPUBatch *geom = DRW_cache_object_surface_get(ob); diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc index 0cffa528219..e31c40fff41 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.cc +++ b/source/blender/draw/engines/overlay/overlay_grid.cc @@ -144,8 +144,8 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) zneg_flag = zpos_flag; - /* Persp : If camera is below floor plane, we switch clipping - * Ortho : If eye vector is looking up, we switch clipping */ + /* Perspective: If camera is below floor plane, we switch clipping. + * Orthographic: If eye vector is looking up, we switch clipping. */ if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) || ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) { zpos_flag |= CLIP_ZPOS; diff --git a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc index b312a12a07b..5222abfc743 100644 --- a/source/blender/draw/engines/overlay/overlay_mode_transfer.cc +++ b/source/blender/draw/engines/overlay/overlay_mode_transfer.cc @@ -110,7 +110,7 @@ void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob) pd->mode_transfer.any_animated = true; if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false); + DRW_shgroup_call_sculpt(mode_transfer_grp[is_xray], ob, false, false, false, false, false); } else { struct GPUBatch *geom = DRW_cache_object_surface_get(ob); diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index 0a783c44029..b1118e084a6 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -61,6 +61,7 @@ typedef struct OVERLAY_PassList { DRWPass *armature_ps[2]; DRWPass *armature_bone_select_ps; DRWPass *armature_transp_ps[2]; + DRWPass *attribute_ps; DRWPass *background_ps; DRWPass *clipping_frustum_ps; DRWPass *edit_curve_wire_ps[2]; @@ -284,6 +285,12 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *pointcloud_dots_grp; DRWShadingGroup *sculpt_mask_grp; DRWShadingGroup *sculpt_curves_selection_grp; + DRWShadingGroup *viewer_attribute_curve_grp; + DRWShadingGroup *viewer_attribute_curves_grp; + DRWShadingGroup *viewer_attribute_mesh_grp; + DRWShadingGroup *viewer_attribute_pointcloud_grp; + DRWShadingGroup *viewer_attribute_instance_grp; + DRWShadingGroup *viewer_attribute_instance_pointcloud_grp; DRWShadingGroup *volume_selection_surface_grp; DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */ DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */ @@ -678,6 +685,10 @@ void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata); void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata); +void OVERLAY_viewer_attribute_cache_init(OVERLAY_Data *vedata); +void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *object); +void OVERLAY_viewer_attribute_draw(OVERLAY_Data *vedata); + void OVERLAY_wireframe_init(OVERLAY_Data *vedata); void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata); void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, @@ -745,6 +756,7 @@ GPUShader *OVERLAY_shader_image(void); GPUShader *OVERLAY_shader_motion_path_line(void); GPUShader *OVERLAY_shader_motion_path_vert(void); GPUShader *OVERLAY_shader_uniform_color(void); +GPUShader *OVERLAY_shader_uniform_color_pointcloud(void); GPUShader *OVERLAY_shader_outline_prepass(bool use_wire); GPUShader *OVERLAY_shader_outline_prepass_curves(void); GPUShader *OVERLAY_shader_outline_prepass_gpencil(void); @@ -761,6 +773,10 @@ GPUShader *OVERLAY_shader_particle_dot(void); GPUShader *OVERLAY_shader_particle_shape(void); GPUShader *OVERLAY_shader_sculpt_mask(void); GPUShader *OVERLAY_shader_sculpt_curves_selection(void); +GPUShader *OVERLAY_shader_viewer_attribute_curve(void); +GPUShader *OVERLAY_shader_viewer_attribute_curves(void); +GPUShader *OVERLAY_shader_viewer_attribute_mesh(void); +GPUShader *OVERLAY_shader_viewer_attribute_pointcloud(void); GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac); GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range); GPUShader *OVERLAY_shader_wireframe(bool custom_bias); diff --git a/source/blender/draw/engines/overlay/overlay_sculpt.cc b/source/blender/draw/engines/overlay/overlay_sculpt.cc index ddad1f06537..8f142d68350 100644 --- a/source/blender/draw/engines/overlay/overlay_sculpt.cc +++ b/source/blender/draw/engines/overlay/overlay_sculpt.cc @@ -53,7 +53,7 @@ void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob) } if (use_pbvh) { - DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true); + DRW_shgroup_call_sculpt(pd->sculpt_mask_grp, ob, false, true, true, false, false); } else { sculpt_overlays = DRW_mesh_batch_cache_get_sculpt_overlays(static_cast<Mesh *>(ob->data)); diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index b0a6926a57f..b7e5e8c56b7 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -93,6 +93,11 @@ typedef struct OVERLAY_Shaders { GPUShader *sculpt_mask; GPUShader *sculpt_curves_selection; GPUShader *uniform_color; + GPUShader *uniform_color_pointcloud; + GPUShader *viewer_attribute_mesh; + GPUShader *viewer_attribute_pointcloud; + GPUShader *viewer_attribute_curve; + GPUShader *viewer_attribute_curves; GPUShader *volume_velocity_needle_sh; GPUShader *volume_velocity_mac_sh; GPUShader *volume_velocity_sh; @@ -818,6 +823,55 @@ GPUShader *OVERLAY_shader_sculpt_curves_selection(void) return sh_data->sculpt_curves_selection; } +GPUShader *OVERLAY_shader_viewer_attribute_mesh(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->viewer_attribute_mesh) { + sh_data->viewer_attribute_mesh = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_mesh_clipped" : + "overlay_viewer_attribute_mesh"); + } + return sh_data->viewer_attribute_mesh; +} + +GPUShader *OVERLAY_shader_viewer_attribute_pointcloud(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->viewer_attribute_pointcloud) { + sh_data->viewer_attribute_pointcloud = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? + "overlay_viewer_attribute_pointcloud_clipped" : + "overlay_viewer_attribute_pointcloud"); + } + return sh_data->viewer_attribute_pointcloud; +} + +GPUShader *OVERLAY_shader_viewer_attribute_curve(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->viewer_attribute_curve) { + sh_data->viewer_attribute_curve = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_curve_clipped" : + "overlay_viewer_attribute_curve"); + } + return sh_data->viewer_attribute_curve; +} + +GPUShader *OVERLAY_shader_viewer_attribute_curves(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->viewer_attribute_curves) { + sh_data->viewer_attribute_curves = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_viewer_attribute_curves_clipped" : + "overlay_viewer_attribute_curves"); + } + return sh_data->viewer_attribute_curves; +} + struct GPUShader *OVERLAY_shader_uniform_color(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -829,6 +883,18 @@ struct GPUShader *OVERLAY_shader_uniform_color(void) return sh_data->uniform_color; } +struct GPUShader *OVERLAY_shader_uniform_color_pointcloud() +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->uniform_color_pointcloud) { + sh_data->uniform_color_pointcloud = GPU_shader_create_from_info_name( + draw_ctx->sh_cfg ? "overlay_uniform_color_pointcloud_clipped" : + "overlay_uniform_color_pointcloud"); + } + return sh_data->uniform_color_pointcloud; +} + struct GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; diff --git a/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc new file mode 100644 index 00000000000..d57ea08d888 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_viewer_attribute.cc @@ -0,0 +1,181 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +#include "BLI_math_vector.hh" +#include "BLI_span.hh" + +#include "GPU_batch.h" + +#include "BKE_attribute.hh" +#include "BKE_curves.hh" +#include "BKE_duplilist.h" +#include "BKE_geometry_set.hh" + +#include "draw_cache_extract.hh" +#include "draw_cache_impl.h" +#include "overlay_private.hh" + +void OVERLAY_viewer_attribute_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + + const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->attribute_ps, state | pd->clipping_state); + + GPUShader *mesh_sh = OVERLAY_shader_viewer_attribute_mesh(); + GPUShader *pointcloud_sh = OVERLAY_shader_viewer_attribute_pointcloud(); + GPUShader *curve_sh = OVERLAY_shader_viewer_attribute_curve(); + GPUShader *curves_sh = OVERLAY_shader_viewer_attribute_curves(); + GPUShader *uniform_sh = OVERLAY_shader_uniform_color(); + GPUShader *uniform_pointcloud_sh = OVERLAY_shader_uniform_color_pointcloud(); + pd->viewer_attribute_mesh_grp = DRW_shgroup_create(mesh_sh, psl->attribute_ps); + pd->viewer_attribute_pointcloud_grp = DRW_shgroup_create(pointcloud_sh, psl->attribute_ps); + pd->viewer_attribute_curve_grp = DRW_shgroup_create(curve_sh, psl->attribute_ps); + pd->viewer_attribute_curves_grp = DRW_shgroup_create(curves_sh, psl->attribute_ps); + pd->viewer_attribute_instance_grp = DRW_shgroup_create(uniform_sh, psl->attribute_ps); + pd->viewer_attribute_instance_pointcloud_grp = DRW_shgroup_create(uniform_pointcloud_sh, + psl->attribute_ps); +} + +static void populate_cache_for_instance(Object &object, + OVERLAY_PrivateData &pd, + const DupliObject &dupli_object, + const float opacity) +{ + using namespace blender; + using namespace blender::bke; + + const GeometrySet &base_geometry = *dupli_object.preview_base_geometry; + const InstancesComponent &instances = + *base_geometry.get_component_for_read<InstancesComponent>(); + const AttributeAccessor instance_attributes = *instances.attributes(); + const VArray attribute = instance_attributes.lookup<ColorGeometry4f>(".viewer"); + if (!attribute) { + return; + } + ColorGeometry4f color = attribute.get(dupli_object.preview_instance_index); + color.a *= opacity; + switch (object.type) { + case OB_MESH: { + { + DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp); + DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); + GPUBatch *batch = DRW_cache_mesh_surface_get(&object); + DRW_shgroup_call(sub_grp, batch, &object); + } + if (GPUBatch *batch = DRW_cache_mesh_loose_edges_get(&object)) { + DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp); + DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); + DRW_shgroup_call(sub_grp, batch, &object); + } + break; + } + case OB_POINTCLOUD: { + DRWShadingGroup *sub_grp = DRW_shgroup_create_sub( + pd.viewer_attribute_instance_pointcloud_grp); + DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); + GPUBatch *batch = DRW_cache_pointcloud_surface_get(&object); + DRW_shgroup_call_instance_range(sub_grp, &object, batch, 0, 0); + break; + } + case OB_CURVES_LEGACY: { + DRWShadingGroup *sub_grp = DRW_shgroup_create_sub(pd.viewer_attribute_instance_grp); + DRW_shgroup_uniform_vec4_copy(sub_grp, "ucolor", color); + GPUBatch *batch = DRW_cache_curve_edge_wire_get(&object); + DRW_shgroup_call_obmat(sub_grp, batch, object.obmat); + break; + } + case OB_CURVES: { + /* Not supported yet because instances of this type are currently drawn as legacy curves. + */ + break; + } + } +} + +static void populate_cache_for_geometry(Object &object, + OVERLAY_PrivateData &pd, + const float opacity) +{ + using namespace blender; + using namespace blender::bke; + + switch (object.type) { + case OB_MESH: { + Mesh *mesh = static_cast<Mesh *>(object.data); + if (mesh->attributes().contains(".viewer")) { + GPUBatch *batch = DRW_cache_mesh_surface_viewer_attribute_get(&object); + DRW_shgroup_uniform_float_copy(pd.viewer_attribute_mesh_grp, "opacity", opacity); + DRW_shgroup_call(pd.viewer_attribute_mesh_grp, batch, &object); + } + break; + } + case OB_POINTCLOUD: { + PointCloud *pointcloud = static_cast<PointCloud *>(object.data); + if (pointcloud->attributes().contains(".viewer")) { + GPUBatch *batch = DRW_cache_pointcloud_surface_viewer_attribute_get(&object); + DRW_shgroup_uniform_float_copy(pd.viewer_attribute_pointcloud_grp, "opacity", opacity); + DRW_shgroup_call_instance_range(pd.viewer_attribute_pointcloud_grp, &object, batch, 0, 0); + } + break; + } + case OB_CURVES_LEGACY: { + Curve *curve = static_cast<Curve *>(object.data); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curve->curve_eval->geometry); + if (curves.attributes().contains(".viewer")) { + GPUBatch *batch = DRW_cache_curve_edge_wire_viewer_attribute_get(&object); + DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curve_grp, "opacity", opacity); + DRW_shgroup_call_obmat(pd.viewer_attribute_curve_grp, batch, object.obmat); + } + break; + } + case OB_CURVES: { + Curves *curves_id = static_cast<Curves *>(object.data); + const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry); + if (curves.attributes().contains(".viewer")) { + bool is_point_domain; + GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute( + curves_id, ".viewer", &is_point_domain); + DRWShadingGroup *grp = DRW_shgroup_curves_create_sub( + &object, pd.viewer_attribute_curves_grp, nullptr); + DRW_shgroup_uniform_float_copy(pd.viewer_attribute_curves_grp, "opacity", opacity); + DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain); + DRW_shgroup_uniform_texture(grp, "color_tx", *texture); + } + break; + } + } +} + +void OVERLAY_viewer_attribute_cache_populate(OVERLAY_Data *vedata, Object *object) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + const float opacity = vedata->stl->pd->overlay.viewer_attribute_opacity; + DupliObject *dupli_object = DRW_object_get_dupli(object); + + if (dupli_object->preview_instance_index >= 0) { + const InstancesComponent &instances = + *dupli_object->preview_base_geometry->get_component_for_read<InstancesComponent>(); + if (instances.attributes()->contains(".viewer")) { + populate_cache_for_instance(*object, *pd, *dupli_object, opacity); + return; + } + } + populate_cache_for_geometry(*object, *pd, opacity); +} + +void OVERLAY_viewer_attribute_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + DRW_draw_pass(psl->attribute_ps); +} diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.cc b/source/blender/draw/engines/overlay/overlay_wireframe.cc index edaa96651b2..bff1bf46923 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.cc +++ b/source/blender/draw/engines/overlay/overlay_wireframe.cc @@ -302,7 +302,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, DRW_shgroup_call_no_cull(shgrp, geom, ob); } else if (use_sculpt_pbvh) { - DRW_shgroup_call_sculpt(shgrp, ob, true, false); + DRW_shgroup_call_sculpt(shgrp, ob, true, false, false, false, false); } else { DRW_shgroup_call(shgrp, geom, ob); diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh index 8c9c943393f..40b7249a997 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh @@ -587,8 +587,20 @@ GPU_SHADER_CREATE_INFO(overlay_uniform_color) .fragment_source("overlay_uniform_color_frag.glsl") .additional_info("draw_mesh"); +GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud) + .do_static_compilation(true) + .push_constant(Type::VEC4, "ucolor") + .fragment_out(0, Type::VEC4, "fragColor") + .vertex_source("overlay_pointcloud_only_vert.glsl") + .fragment_source("overlay_uniform_color_frag.glsl") + .additional_info("draw_pointcloud"); + GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped) .do_static_compilation(true) .additional_info("overlay_depth_only", "drw_clipped"); +GPU_SHADER_CREATE_INFO(overlay_uniform_color_pointcloud_clipped) + .do_static_compilation(true) + .additional_info("overlay_uniform_color_pointcloud", "drw_clipped"); + /** \} */ diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh new file mode 100644 index 00000000000..20d4797b76f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_create_info.hh" + +GPU_SHADER_INTERFACE_INFO(overlay_viewer_attribute_iface, "").smooth(Type::VEC4, "finalColor"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_common).push_constant(Type::FLOAT, "opacity"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_mesh) + .do_static_compilation(true) + .vertex_source("overlay_viewer_attribute_mesh_vert.glsl") + .fragment_source("overlay_viewer_attribute_frag.glsl") + .fragment_out(0, Type::VEC4, "out_color") + .fragment_out(1, Type::VEC4, "lineOutput") + .vertex_in(0, Type::VEC3, "pos") + .vertex_in(1, Type::VEC4, "attribute_value") + .vertex_out(overlay_viewer_attribute_iface) + .additional_info("overlay_viewer_attribute_common", "draw_mesh"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_mesh_clipped) + .do_static_compilation(true) + .additional_info("overlay_viewer_attribute_mesh", "drw_clipped"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud) + .do_static_compilation(true) + .vertex_source("overlay_viewer_attribute_pointcloud_vert.glsl") + .fragment_source("overlay_viewer_attribute_frag.glsl") + .fragment_out(0, Type::VEC4, "out_color") + .fragment_out(1, Type::VEC4, "lineOutput") + .vertex_in(3, Type::VEC4, "attribute_value") + .vertex_out(overlay_viewer_attribute_iface) + .additional_info("overlay_viewer_attribute_common", "draw_pointcloud"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_pointcloud_clipped) + .do_static_compilation(true) + .additional_info("overlay_viewer_attribute_pointcloud", "drw_clipped"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curve) + .do_static_compilation(true) + .vertex_source("overlay_viewer_attribute_curve_vert.glsl") + .fragment_source("overlay_viewer_attribute_frag.glsl") + .fragment_out(0, Type::VEC4, "out_color") + .fragment_out(1, Type::VEC4, "lineOutput") + .vertex_in(0, Type::VEC3, "pos") + .vertex_in(1, Type::VEC4, "attribute_value") + .vertex_out(overlay_viewer_attribute_iface) + .additional_info("overlay_viewer_attribute_common", "draw_modelmat", "draw_resource_id"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curve_clipped) + .do_static_compilation(true) + .additional_info("overlay_viewer_attribute_curve", "drw_clipped"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curves) + .do_static_compilation(true) + .vertex_source("overlay_viewer_attribute_curves_vert.glsl") + .fragment_source("overlay_viewer_attribute_frag.glsl") + .fragment_out(0, Type::VEC4, "out_color") + .fragment_out(1, Type::VEC4, "lineOutput") + .sampler(0, ImageType::FLOAT_BUFFER, "color_tx") + .push_constant(Type::BOOL, "is_point_domain") + .vertex_out(overlay_viewer_attribute_iface) + .additional_info("overlay_viewer_attribute_common", "draw_hair"); + +GPU_SHADER_CREATE_INFO(overlay_viewer_attribute_curves_clipped) + .do_static_compilation(true) + .additional_info("overlay_viewer_attribute_curves", "drw_clipped"); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl new file mode 100644 index 00000000000..8a7e81028d3 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_pointcloud_only_vert.glsl @@ -0,0 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl) + +void main() +{ + vec3 world_pos = pointcloud_get_pos(); + gl_Position = point_world_to_ndc(world_pos); +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl new file mode 100644 index 00000000000..7c2c386b2f5 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curve_vert.glsl @@ -0,0 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + finalColor = attribute_value; +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl new file mode 100644 index 00000000000..23d313e036f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_curves_vert.glsl @@ -0,0 +1,28 @@ +#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_hair_lib.glsl) + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 world_pos, tan, binor; + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + world_pos, + tan, + binor, + time, + thickness, + thick_time); + gl_Position = point_world_to_ndc(world_pos); + + if (is_point_domain) { + finalColor = texelFetch(color_tx, hair_get_base_id()); + } + else { + finalColor = texelFetch(color_tx, hair_get_strand_id()); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl new file mode 100644 index 00000000000..e5752ada940 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_frag.glsl @@ -0,0 +1,8 @@ + +void main() +{ + out_color = finalColor; + out_color.a *= opacity; + /* Writing to this second texture is necessary to avoid undefined behavior. */ + lineOutput = vec4(0.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl new file mode 100644 index 00000000000..7c2c386b2f5 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_mesh_vert.glsl @@ -0,0 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +void main() +{ + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + finalColor = attribute_value; +} diff --git a/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl new file mode 100644 index 00000000000..e706e8f9033 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/overlay_viewer_attribute_pointcloud_vert.glsl @@ -0,0 +1,10 @@ +#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl) + +void main() +{ + vec3 world_pos = pointcloud_get_pos(); + gl_Position = point_world_to_ndc(world_pos); + finalColor = attribute_value; +} diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index ee9521289d9..36a980bd506 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -102,7 +102,11 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR); if (use_single_drawcall) { DRWShadingGroup *grp = workbench_material_setup(wpd, ob, ob->actcol, color_type, NULL); - DRW_shgroup_call_sculpt(grp, ob, false, false); + + bool use_color = color_type == V3D_SHADING_VERTEX_COLOR; + bool use_uv = color_type == V3D_SHADING_TEXTURE_COLOR; + + DRW_shgroup_call_sculpt(grp, ob, false, false, false, use_color, use_uv); } else { const int materials_len = DRW_cache_object_material_count_get(ob); @@ -110,7 +114,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, for (int i = 0; i < materials_len; i++) { shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL); } - DRW_shgroup_call_sculpt_with_materials(shgrps, materials_len, ob); + DRW_shgroup_call_sculpt_with_materials(shgrps, NULL, materials_len, ob); } } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 7b80ffd2b88..1752198c349 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -398,8 +398,18 @@ void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup, struct GPUBatch *geom, struct GPUBatch *inst_attributes); -void DRW_shgroup_call_sculpt(DRWShadingGroup *sh, Object *ob, bool wire, bool mask); -void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **sh, int num_sh, Object *ob); +void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup, + Object *ob, + bool use_wire, + bool use_mask, + bool use_fset, + bool use_color, + bool use_uv); + +void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups, + struct GPUMaterial **gpumats, + int num_shgroups, + Object *ob); DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, struct GPUVertFormat *format, @@ -934,6 +944,14 @@ typedef struct DRWContextState { const DRWContextState *DRW_context_state_get(void); +struct DRW_Attributes; +struct DRW_MeshCDMask; + +void DRW_mesh_batch_cache_get_attributes(struct Object *object, + struct Mesh *me, + struct DRW_Attributes **r_attrs, + struct DRW_MeshCDMask **r_cd_needed); + #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h index b577c6c4162..786301d0164 100644 --- a/source/blender/draw/intern/draw_attributes.h +++ b/source/blender/draw/intern/draw_attributes.h @@ -16,6 +16,7 @@ #include "BLI_sys_types.h" #include "BLI_threads.h" +#include "BLI_utildefines.h" #include "GPU_shader.h" #include "GPU_vertex_format.h" @@ -36,6 +37,23 @@ typedef struct DRW_Attributes { int num_requests; } DRW_Attributes; +typedef struct DRW_MeshCDMask { + uint32_t uv : 8; + uint32_t tan : 8; + uint32_t orco : 1; + uint32_t tan_orco : 1; + uint32_t sculpt_overlays : 1; + /** + * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857) + */ + uint32_t edit_uv : 1; +} DRW_MeshCDMask; + +/* Keep `DRW_MeshCDMask` struct within a `uint32_t`. + * bit-wise and atomic operations are used to compare and update the struct. + * See `mesh_cd_layers_type_*` functions. */ +BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits") + void drw_attributes_clear(DRW_Attributes *attributes); void drw_attributes_merge(DRW_Attributes *dst, diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 6537490c06c..eec15a4668d 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -2889,6 +2889,12 @@ GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(Object *ob) return DRW_mesh_batch_cache_get_edit_mesh_analysis(ob->data); } +GPUBatch *DRW_cache_mesh_surface_viewer_attribute_get(Object *ob) +{ + BLI_assert(ob->type == OB_MESH); + return DRW_mesh_batch_cache_get_surface_viewer_attribute(ob->data); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -2902,6 +2908,13 @@ GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob) return DRW_curve_batch_cache_get_wire_edge(cu); } +GPUBatch *DRW_cache_curve_edge_wire_viewer_attribute_get(Object *ob) +{ + BLI_assert(ob->type == OB_CURVES_LEGACY); + struct Curve *cu = ob->data; + return DRW_curve_batch_cache_get_wire_edge_viewer_attribute(cu); +} + GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob) { BLI_assert(ob->type == OB_CURVES_LEGACY); @@ -3005,6 +3018,12 @@ GPUBatch *DRW_cache_pointcloud_surface_get(Object *object) return DRW_pointcloud_batch_cache_get_surface(object); } +GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(Object *object) +{ + BLI_assert(object->type == OB_POINTCLOUD); + return DRW_pointcloud_batch_cache_get_surface_viewer_attribute(object); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -3369,7 +3388,7 @@ void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format, /* Active render layer name. */ if (is_active_render) { - GPU_vertformat_alias_add(format, base_name); + GPU_vertformat_alias_add(format, cl->type == CD_MLOOPUV ? "a" : base_name); } /* Active display layer name. */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 4e8788ada08..058f28f094d 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -170,10 +170,12 @@ struct GPUBatch *DRW_cache_mesh_surface_sculptcolors_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_weights_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_surface_mesh_analysis_get(struct Object *ob); struct GPUBatch *DRW_cache_mesh_face_wireframe_get(struct Object *ob); +struct GPUBatch *DRW_cache_mesh_surface_viewer_attribute_get(struct Object *ob); /* Curve */ struct GPUBatch *DRW_cache_curve_edge_wire_get(struct Object *ob); +struct GPUBatch *DRW_cache_curve_edge_wire_viewer_attribute_get(struct Object *ob); /* edit-mode */ @@ -226,6 +228,7 @@ struct GPUBatch *DRW_cache_curves_edge_detection_get(struct Object *ob, bool *r_ struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj); struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj); +struct GPUBatch *DRW_cache_pointcloud_surface_viewer_attribute_get(struct Object *obj); /* Volume */ diff --git a/source/blender/draw/intern/draw_cache_extract.hh b/source/blender/draw/intern/draw_cache_extract.hh index 203da22406c..4fe360eecd7 100644 --- a/source/blender/draw/intern/draw_cache_extract.hh +++ b/source/blender/draw/intern/draw_cache_extract.hh @@ -52,22 +52,6 @@ enum { DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2), }; -struct DRW_MeshCDMask { - uint32_t uv : 8; - uint32_t tan : 8; - uint32_t orco : 1; - uint32_t tan_orco : 1; - uint32_t sculpt_overlays : 1; - /** - * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857) - */ - uint32_t edit_uv : 1; -}; -/* Keep `DRW_MeshCDMask` struct within a `uint32_t`. - * bit-wise and atomic operations are used to compare and update the struct. - * See `mesh_cd_layers_type_*` functions. */ -BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint32_t), "DRW_MeshCDMask exceeds 32 bits") - enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, MR_ITER_POLY = 1 << 1, @@ -130,6 +114,7 @@ struct MeshBufferList { GPUVertBuf *poly_idx; GPUVertBuf *fdot_idx; GPUVertBuf *attr[GPU_MAX_ATTR]; + GPUVertBuf *attr_viewer; } vbo; /* Index Buffers: * Only need to be updated when topology changes. */ @@ -191,6 +176,7 @@ struct MeshBatchList { /* Same as wire_loops but only has uvs. */ GPUBatch *wire_loops_uvs; GPUBatch *sculpt_overlays; + GPUBatch *surface_viewer_attribute; }; #define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *)) @@ -228,6 +214,7 @@ enum DRWBatchFlag { MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)), MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)), MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)), + MBC_VIEWER_ATTRIBUTE_OVERLAY = (1u << MBC_BATCH_INDEX(surface_viewer_attribute)), MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN), }; ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 104e9551c88..aac45926a1e 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -638,6 +638,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, for (int i = 0; i < GPU_MAX_ATTR; i++) { EXTRACT_ADD_REQUESTED(vbo, attr[i]); } + EXTRACT_ADD_REQUESTED(vbo, attr_viewer); EXTRACT_ADD_REQUESTED(ibo, tris); if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) { diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 7f7d0a7613f..e49b37b451f 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -100,6 +100,7 @@ void DRW_curve_batch_cache_create_requested(struct Object *ob, const struct Scen int DRW_curve_material_count_get(struct Curve *cu); struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu); +struct GPUBatch *DRW_curve_batch_cache_get_wire_edge_viewer_attribute(struct Curve *cu); struct GPUBatch *DRW_curve_batch_cache_get_normal_edge(struct Curve *cu); struct GPUBatch *DRW_curve_batch_cache_get_edit_edges(struct Curve *cu); struct GPUBatch *DRW_curve_batch_cache_get_edit_verts(struct Curve *cu); @@ -148,6 +149,7 @@ int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud); struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob); struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob); +struct GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(struct Object *ob); struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); @@ -189,6 +191,7 @@ struct GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(struct Object *object, struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len); + struct GPUBatch **DRW_mesh_batch_cache_get_surface_texpaint(struct Object *object, struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Object *object, @@ -198,6 +201,7 @@ struct GPUBatch *DRW_mesh_batch_cache_get_surface_vertpaint(struct Object *objec struct GPUBatch *DRW_mesh_batch_cache_get_surface_sculpt(struct Object *object, struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_surface_weights(struct Mesh *me); struct GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(struct Mesh *me); +struct GPUBatch *DRW_mesh_batch_cache_get_surface_viewer_attribute(struct Mesh *me); /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_curve.cc b/source/blender/draw/intern/draw_cache_impl_curve.cc index 695c348d8e2..6188b1e0544 100644 --- a/source/blender/draw/intern/draw_cache_impl_curve.cc +++ b/source/blender/draw/intern/draw_cache_impl_curve.cc @@ -10,6 +10,7 @@ #include "MEM_guardedalloc.h" #include "BLI_array.hh" +#include "BLI_color.hh" #include "BLI_listbase.h" #include "BLI_math_vec_types.hh" #include "BLI_math_vector.h" @@ -38,6 +39,7 @@ #include "draw_cache_impl.h" /* own include */ using blender::Array; +using blender::ColorGeometry4f; using blender::float3; using blender::IndexRange; using blender::Span; @@ -296,6 +298,7 @@ static int curve_render_data_normal_len_get(const CurveRenderData *rdata) struct CurveBatchCache { struct { GPUVertBuf *curves_pos; + GPUVertBuf *attr_viewer; } ordered; struct { @@ -314,6 +317,7 @@ struct CurveBatchCache { struct { GPUBatch *curves; + GPUBatch *curves_viewer_attribute; /* control handles and vertices */ GPUBatch *edit_edges; GPUBatch *edit_verts; @@ -474,6 +478,31 @@ static void curve_create_curves_pos(CurveRenderData *rdata, GPUVertBuf *vbo_curv GPU_vertbuf_attr_fill(vbo_curves_pos, attr_id.pos, positions.data()); } +static void curve_create_attribute(CurveRenderData *rdata, GPUVertBuf *vbo_attr) +{ + if (rdata->curve_eval == nullptr) { + return; + } + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + const int vert_len = curve_render_data_wire_verts_len_get(rdata); + GPU_vertbuf_init_with_format(vbo_attr, &format); + GPU_vertbuf_data_alloc(vbo_attr, vert_len); + + const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap( + rdata->curve_eval->geometry); + curves.ensure_can_interpolate_to_evaluated(); + const blender::VArraySpan<ColorGeometry4f> colors = curves.attributes().lookup<ColorGeometry4f>( + ".viewer", ATTR_DOMAIN_POINT); + ColorGeometry4f *vbo_data = static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(vbo_attr)); + curves.interpolate_to_evaluated(colors, + blender::MutableSpan<ColorGeometry4f>{vbo_data, vert_len}); +} + static void curve_create_curves_lines(CurveRenderData *rdata, GPUIndexBuf *ibo_curve_lines) { if (rdata->curve_eval == nullptr) { @@ -769,6 +798,12 @@ GPUBatch *DRW_curve_batch_cache_get_wire_edge(Curve *cu) return DRW_batch_request(&cache->batch.curves); } +GPUBatch *DRW_curve_batch_cache_get_wire_edge_viewer_attribute(Curve *cu) +{ + CurveBatchCache *cache = curve_batch_cache_get(cu); + return DRW_batch_request(&cache->batch.curves_viewer_attribute); +} + GPUBatch *DRW_curve_batch_cache_get_normal_edge(Curve *cu) { CurveBatchCache *cache = curve_batch_cache_get(cu); @@ -810,6 +845,11 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen DRW_ibo_request(cache->batch.curves, &cache->ibo.curves_lines); DRW_vbo_request(cache->batch.curves, &cache->ordered.curves_pos); } + if (DRW_batch_requested(cache->batch.curves_viewer_attribute, GPU_PRIM_LINE_STRIP)) { + DRW_ibo_request(cache->batch.curves_viewer_attribute, &cache->ibo.curves_lines); + DRW_vbo_request(cache->batch.curves_viewer_attribute, &cache->ordered.curves_pos); + DRW_vbo_request(cache->batch.curves_viewer_attribute, &cache->ordered.attr_viewer); + } /* Edit mode */ if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) { @@ -833,6 +873,8 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen /* Generate MeshRenderData flags */ int mr_flag = 0; DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->ordered.curves_pos, CU_DATATYPE_WIRE); + DRW_ADD_FLAG_FROM_VBO_REQUEST( + mr_flag, cache->ordered.attr_viewer, CU_DATATYPE_WIRE | CU_DATATYPE_OVERLAY); DRW_ADD_FLAG_FROM_IBO_REQUEST(mr_flag, cache->ibo.curves_lines, CU_DATATYPE_WIRE); DRW_ADD_FLAG_FROM_VBO_REQUEST(mr_flag, cache->edit.pos, CU_DATATYPE_OVERLAY); @@ -851,6 +893,9 @@ void DRW_curve_batch_cache_create_requested(Object *ob, const struct Scene *scen if (DRW_vbo_requested(cache->ordered.curves_pos)) { curve_create_curves_pos(rdata, cache->ordered.curves_pos); } + if (DRW_vbo_requested(cache->ordered.attr_viewer)) { + curve_create_attribute(rdata, cache->ordered.attr_viewer); + } if (DRW_ibo_requested(cache->ibo.curves_lines)) { curve_create_curves_lines(rdata, cache->ibo.curves_lines); } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index c22382b3e09..acab4798ea8 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -62,6 +62,7 @@ #include "draw_subdivision.h" #include "draw_cache_impl.h" /* own include */ +#include "draw_manager.h" #include "mesh_extractors/extract_mesh.hh" @@ -104,7 +105,8 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index) MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES | MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION | - MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT; + MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_VIEWER_ATTRIBUTE_OVERLAY | + MBC_SURFACE_PER_MAT; case BUFFER_INDEX(vbo.lnor): return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT; case BUFFER_INDEX(vbo.edge_fac): @@ -166,9 +168,12 @@ static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index) case BUFFER_INDEX(vbo.attr[13]): case BUFFER_INDEX(vbo.attr[14]): return MBC_SURFACE | MBC_SURFACE_PER_MAT; + case BUFFER_INDEX(vbo.attr_viewer): + return MBC_VIEWER_ATTRIBUTE_OVERLAY; case BUFFER_INDEX(ibo.tris): return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR | - MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS; + MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS | + MBC_VIEWER_ATTRIBUTE_OVERLAY; case BUFFER_INDEX(ibo.lines): return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES; case BUFFER_INDEX(ibo.lines_loose): @@ -977,6 +982,27 @@ GPUBatch *DRW_mesh_batch_cache_get_edit_mesh_analysis(Mesh *me) return DRW_batch_request(&cache->batch.edit_mesh_analysis); } +void DRW_mesh_get_attributes(Object *object, + Mesh *me, + struct GPUMaterial **gpumat_array, + int gpumat_array_len, + DRW_Attributes *r_attrs, + DRW_MeshCDMask *r_cd_needed) +{ + DRW_Attributes attrs_needed; + drw_attributes_clear(&attrs_needed); + DRW_MeshCDMask cd_needed = mesh_cd_calc_used_gpu_layers( + object, me, gpumat_array, gpumat_array_len, &attrs_needed); + + if (r_attrs) { + *r_attrs = attrs_needed; + } + + if (r_cd_needed) { + *r_cd_needed = cd_needed; + } +} + GPUBatch **DRW_mesh_batch_cache_get_surface_shaded(Object *object, Mesh *me, struct GPUMaterial **gpumat_array, @@ -1057,6 +1083,16 @@ GPUBatch *DRW_mesh_batch_cache_get_sculpt_overlays(Mesh *me) return cache->batch.sculpt_overlays; } +GPUBatch *DRW_mesh_batch_cache_get_surface_viewer_attribute(Mesh *me) +{ + MeshBatchCache *cache = mesh_batch_cache_get(me); + + mesh_batch_cache_add_request(cache, MBC_VIEWER_ATTRIBUTE_OVERLAY); + DRW_batch_request(&cache->batch.surface_viewer_attribute); + + return cache->batch.surface_viewer_attribute; +} + /** \} */ /* ---------------------------------------------------------------------- */ @@ -1802,6 +1838,14 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv); DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data); } + assert_deps_valid( + MBC_VIEWER_ATTRIBUTE_OVERLAY, + {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.attr_viewer)}); + if (DRW_batch_requested(cache->batch.surface_viewer_attribute, GPU_PRIM_TRIS)) { + DRW_ibo_request(cache->batch.surface_viewer_attribute, &mbuflist->ibo.tris); + DRW_vbo_request(cache->batch.surface_viewer_attribute, &mbuflist->vbo.pos_nor); + DRW_vbo_request(cache->batch.surface_viewer_attribute, &mbuflist->vbo.attr_viewer); + } #ifdef DEBUG auto assert_final_deps_valid = [&](const int buffer_index) { @@ -1833,6 +1877,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, for (const int i : IndexRange(GPU_MAX_ATTR)) { assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i])); } + assert_final_deps_valid(BUFFER_INDEX(vbo.attr_viewer)); assert_final_deps_valid(BUFFER_INDEX(ibo.tris)); assert_final_deps_valid(BUFFER_INDEX(ibo.lines)); diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc index a43b23c8969..72be5b37652 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.cc +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.cc @@ -32,11 +32,13 @@ struct PointCloudBatchCache { GPUVertBuf *pos; /* Position and radius. */ GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */ + GPUVertBuf *attr_viewer; GPUIndexBuf *geom_indices; GPUBatch *dots; GPUBatch *surface; GPUBatch **surface_per_mat; + GPUBatch *surface_viewer_attribute; /* settings to determine if cache is invalid */ bool is_dirty; @@ -109,6 +111,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->surface); GPU_VERTBUF_DISCARD_SAFE(cache->pos); GPU_VERTBUF_DISCARD_SAFE(cache->geom); + GPU_VERTBUF_DISCARD_SAFE(cache->attr_viewer); GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices); if (cache->surface_per_mat) { @@ -116,6 +119,7 @@ static void pointcloud_batch_cache_clear(PointCloud &pointcloud) GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); } } + GPU_BATCH_DISCARD_SAFE(cache->surface_viewer_attribute); MEM_SAFE_FREE(cache->surface_per_mat); } @@ -227,6 +231,30 @@ static void pointcloud_batch_cache_ensure_geom(PointCloudBatchCache &cache) cache.geom_indices = GPU_indexbuf_build(&builder); } +static void pointcloud_batch_cache_ensure_attribute_overlay(const PointCloud &pointcloud, + PointCloudBatchCache &cache) +{ + using namespace blender; + if (cache.attr_viewer != nullptr) { + return; + } + + const bke::AttributeAccessor attributes = pointcloud.attributes(); + const VArray<ColorGeometry4f> colors = attributes.lookup_or_default<ColorGeometry4f>( + ".viewer", ATTR_DOMAIN_POINT, {1.0f, 0.0f, 1.0f, 1.0f}); + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + cache.attr_viewer = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(cache.attr_viewer, pointcloud.totpoint); + MutableSpan<ColorGeometry4f> vbo_data{ + static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(cache.attr_viewer)), + pointcloud.totpoint}; + colors.materialize(vbo_data); +} + GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) { PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); @@ -256,6 +284,25 @@ GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob) return cache->surface; } +GPUBatch *DRW_pointcloud_batch_cache_get_surface_viewer_attribute(Object *ob) +{ + PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); + PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + + if (cache->surface_viewer_attribute == nullptr) { + pointcloud_batch_cache_ensure_pos(pointcloud, *cache); + pointcloud_batch_cache_ensure_geom(*cache); + pointcloud_batch_cache_ensure_attribute_overlay(pointcloud, *cache); + + cache->surface_viewer_attribute = GPU_batch_create( + GPU_PRIM_TRIS, cache->geom, cache->geom_indices); + GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->attr_viewer, false); + GPU_batch_instbuf_add_ex(cache->surface_viewer_attribute, cache->pos, false); + } + + return cache->surface_viewer_attribute; +} + GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, struct GPUMaterial **UNUSED(gpumat_array), uint gpumat_array_len) diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 7ed5ca7c983..a56883ce304 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -585,87 +585,18 @@ static DRWUniformAttrBuf *drw_uniform_attrs_pool_ensure(GHash *table, return (DRWUniformAttrBuf *)*pval; } -/* This function mirrors lookup_property in cycles/blender/blender_object.cpp */ -static bool drw_uniform_property_lookup(ID *id, const char *name, float r_data[4]) -{ - PointerRNA ptr, id_ptr; - PropertyRNA *prop; - - if (!id) { - return false; - } - - RNA_id_pointer_create(id, &id_ptr); - - if (!RNA_path_resolve(&id_ptr, name, &ptr, &prop)) { - return false; - } - - if (prop == NULL) { - return false; - } - - PropertyType type = RNA_property_type(prop); - int arraylen = RNA_property_array_length(&ptr, prop); - - if (arraylen == 0) { - float value; - - if (type == PROP_FLOAT) { - value = RNA_property_float_get(&ptr, prop); - } - else if (type == PROP_INT) { - value = RNA_property_int_get(&ptr, prop); - } - else { - return false; - } - - copy_v4_fl4(r_data, value, value, value, 1); - return true; - } - - if (type == PROP_FLOAT && arraylen <= 4) { - copy_v4_fl4(r_data, 0, 0, 0, 1); - RNA_property_float_get_array(&ptr, prop, r_data); - return true; - } - - return false; -} - -/* This function mirrors lookup_instance_property in cycles/blender/blender_object.cpp */ static void drw_uniform_attribute_lookup(GPUUniformAttr *attr, Object *ob, Object *dupli_parent, DupliObject *dupli_source, float r_data[4]) { - copy_v4_fl(r_data, 0); - /* If requesting instance data, check the parent particle system and object. */ if (attr->use_dupli) { - if (dupli_source && dupli_source->particle_system) { - ParticleSettings *settings = dupli_source->particle_system->part; - if (drw_uniform_property_lookup((ID *)settings, attr->name_id_prop, r_data) || - drw_uniform_property_lookup((ID *)settings, attr->name, r_data)) { - return; - } - } - if (drw_uniform_property_lookup((ID *)dupli_parent, attr->name_id_prop, r_data) || - drw_uniform_property_lookup((ID *)dupli_parent, attr->name, r_data)) { - return; - } + BKE_object_dupli_find_rgba_attribute(ob, dupli_source, dupli_parent, attr->name, r_data); } - - /* Check the object and mesh. */ - if (ob) { - if (drw_uniform_property_lookup((ID *)ob, attr->name_id_prop, r_data) || - drw_uniform_property_lookup((ID *)ob, attr->name, r_data) || - drw_uniform_property_lookup((ID *)ob->data, attr->name_id_prop, r_data) || - drw_uniform_property_lookup((ID *)ob->data, attr->name, r_data)) { - return; - } + else { + BKE_object_dupli_find_rgba_attribute(ob, NULL, NULL, attr->name, r_data); } } diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h index 9053544d98a..17978938ced 100644 --- a/source/blender/draw/intern/draw_instance_data.h +++ b/source/blender/draw/intern/draw_instance_data.h @@ -16,6 +16,10 @@ #define DRW_BUFFER_VERTS_CHUNK 128 +#ifdef __cplusplus +extern "C" { +#endif + struct GHash; struct GPUUniformAttrList; @@ -107,3 +111,7 @@ void DRW_uniform_attrs_pool_flush_all(struct GHash *table); void DRW_uniform_attrs_pool_clear_all(struct GHash *table); struct DRWSparseUniformBuf *DRW_uniform_attrs_pool_find_ubo(struct GHash *table, const struct GPUUniformAttrList *key); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 51762e29506..b6ca56d36fc 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -38,6 +38,7 @@ #include "BKE_pointcloud.h" #include "BKE_screen.h" #include "BKE_subdiv_modifier.h" +#include "BKE_viewer_path.h" #include "BKE_volume.h" #include "DNA_camera_types.h" @@ -1695,6 +1696,9 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph, DEGObjectIterSettings deg_iter_settings = {0}; deg_iter_settings.depsgraph = depsgraph; deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; + if (v3d->flag2 & V3D_SHOW_VIEWER) { + deg_iter_settings.viewer_path = &v3d->viewer_path; + } DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -2497,6 +2501,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DEGObjectIterSettings deg_iter_settings = {0}; deg_iter_settings.depsgraph = depsgraph; deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; + if (v3d->flag2 & V3D_SHOW_VIEWER) { + deg_iter_settings.viewer_path = &v3d->viewer_path; + } DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { if (!BKE_object_is_visible_in_viewport(v3d, ob)) { continue; @@ -2662,6 +2669,9 @@ static void drw_draw_depth_loop_impl(struct Depsgraph *depsgraph, DEGObjectIterSettings deg_iter_settings = {0}; deg_iter_settings.depsgraph = DST.draw_ctx.depsgraph; deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; + if (v3d->flag2 & V3D_SHOW_VIEWER) { + deg_iter_settings.viewer_path = &v3d->viewer_path; + } DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { if ((object_type_exclude_viewport & (1 << ob->type)) != 0) { continue; @@ -3103,6 +3113,8 @@ void DRW_render_context_enable(Render *render) WM_init_opengl(); } + GPU_render_begin(); + if (GPU_use_main_context_workaround()) { GPU_context_main_lock(); DRW_opengl_context_enable(); @@ -3126,6 +3138,8 @@ void DRW_render_context_enable(Render *render) void DRW_render_context_disable(Render *render) { + GPU_render_end(); + if (GPU_use_main_context_workaround()) { DRW_opengl_context_disable(); GPU_context_main_unlock(); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index 4f71e665390..67d0f79b83e 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -694,6 +694,16 @@ bool drw_engine_data_engines_data_validate(GPUViewport *viewport, void **engine_ void drw_engine_data_cache_release(GPUViewport *viewport); void drw_engine_data_free(GPUViewport *viewport); +struct DRW_Attributes; +struct DRW_MeshCDMask; +struct GPUMaterial; +void DRW_mesh_get_attributes(struct Object *object, + struct Mesh *me, + struct GPUMaterial **gpumat_array, + int gpumat_array_len, + struct DRW_Attributes *r_attrs, + struct DRW_MeshCDMask *r_cd_needed); + void DRW_manager_begin_sync(void); void DRW_manager_end_sync(void); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.cc index 820242720c8..25d56ea7a72 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -5,7 +5,11 @@ * \ingroup draw */ +#include "DRW_pbvh.h" + +#include "draw_attributes.h" #include "draw_manager.h" +#include "draw_pbvh.h" #include "BKE_curve.h" #include "BKE_duplilist.h" @@ -26,10 +30,11 @@ #include "DNA_meta_types.h" #include "DNA_screen_types.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_hash.h" #include "BLI_link_utils.h" #include "BLI_listbase.h" +#include "BLI_math_bits.h" #include "BLI_memblock.h" #include "BLI_mempool.h" @@ -37,7 +42,6 @@ # include "BLI_math_bits.h" #endif -#include "GPU_buffers.h" #include "GPU_capabilities.h" #include "GPU_material.h" #include "GPU_uniform_buffer.h" @@ -60,13 +64,13 @@ static void draw_call_sort(DRWCommand *array, DRWCommand *array_tmp, int array_len) { - /* Count unique batches. Tt's not really important if + /* Count unique batches. It's not really important if * there is collisions. If there is a lot of different batches, * the sorting benefit will be negligible. * So at least sort fast! */ uchar idx[128] = {0}; /* Shift by 6 positions knowing each GPUBatch is > 64 bytes */ -#define KEY(a) ((((size_t)((a).draw.batch)) >> 6) % ARRAY_SIZE(idx)) +#define KEY(a) ((size_t((a).draw.batch) >> 6) % ARRAY_SIZE(idx)) BLI_assert(array_len <= ARRAY_SIZE(idx)); for (int i = 0; i < array_len; i++) { @@ -98,9 +102,9 @@ void drw_resource_buffer_finish(DRWData *vmempool) /* TODO: find a better system. currently a lot of obinfos UBO are going to be unused * if not rendering with Eevee. */ - if (vmempool->matrices_ubo == NULL) { - vmempool->matrices_ubo = MEM_callocN(list_size, __func__); - vmempool->obinfos_ubo = MEM_callocN(list_size, __func__); + if (vmempool->matrices_ubo == nullptr) { + vmempool->matrices_ubo = static_cast<GPUUniformBuf **>(MEM_callocN(list_size, __func__)); + vmempool->obinfos_ubo = static_cast<GPUUniformBuf **>(MEM_callocN(list_size, __func__)); vmempool->ubo_len = ubo_len; } @@ -111,8 +115,10 @@ void drw_resource_buffer_finish(DRWData *vmempool) } if (ubo_len != vmempool->ubo_len) { - vmempool->matrices_ubo = MEM_recallocN(vmempool->matrices_ubo, list_size); - vmempool->obinfos_ubo = MEM_recallocN(vmempool->obinfos_ubo, list_size); + vmempool->matrices_ubo = static_cast<GPUUniformBuf **>( + MEM_recallocN(vmempool->matrices_ubo, list_size)); + vmempool->obinfos_ubo = static_cast<GPUUniformBuf **>( + MEM_recallocN(vmempool->obinfos_ubo, list_size)); vmempool->ubo_len = ubo_len; } @@ -120,7 +126,7 @@ void drw_resource_buffer_finish(DRWData *vmempool) for (int i = 0; i < ubo_len; i++) { void *data_obmat = BLI_memblock_elem_get(vmempool->obmats, i, 0); void *data_infos = BLI_memblock_elem_get(vmempool->obinfos, i, 0); - if (vmempool->matrices_ubo[i] == NULL) { + if (vmempool->matrices_ubo[i] == nullptr) { vmempool->matrices_ubo[i] = GPU_uniformbuf_create(sizeof(DRWObjectMatrix) * DRW_RESOURCE_CHUNK_LEN); vmempool->obinfos_ubo[i] = GPU_uniformbuf_create(sizeof(DRWObjectInfos) * @@ -133,11 +139,12 @@ void drw_resource_buffer_finish(DRWData *vmempool) DRW_uniform_attrs_pool_flush_all(vmempool->obattrs_ubo_pool); /* Aligned alloc to avoid unaligned memcpy. */ - DRWCommandChunk *chunk_tmp = MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, "tmp call chunk"); + DRWCommandChunk *chunk_tmp = static_cast<DRWCommandChunk *>( + MEM_mallocN_aligned(sizeof(DRWCommandChunk), 16, __func__)); DRWCommandChunk *chunk; BLI_memblock_iter iter; BLI_memblock_iternew(vmempool->commands, &iter); - while ((chunk = BLI_memblock_iterstep(&iter))) { + while ((chunk = static_cast<DRWCommandChunk *>(BLI_memblock_iterstep(&iter)))) { bool sortable = true; /* We can only sort chunks that contain #DRWCommandDraw only. */ for (int i = 0; i < ARRAY_SIZE(chunk->command_type) && sortable; i++) { @@ -175,7 +182,7 @@ static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, DRWUniformChunk *unichunk = shgroup->uniforms; /* Happens on first uniform or if chunk is full. */ if (!unichunk || unichunk->uniform_used == unichunk->uniform_len) { - unichunk = BLI_memblock_alloc(DST.vmempool->uniforms); + unichunk = static_cast<DRWUniformChunk *>(BLI_memblock_alloc(DST.vmempool->uniforms)); unichunk->uniform_len = ARRAY_SIZE(shgroup->uniforms->uniforms); unichunk->uniform_used = 0; BLI_LINKS_PREPEND(shgroup->uniforms, unichunk); @@ -239,7 +246,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup, DRW_UNIFORM_TEXTURE, DRW_UNIFORM_TEXTURE_REF)); int location = GPU_shader_get_uniform(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, location, type, value, 0, length, arraysize); + drw_shgroup_uniform_create_ex( + shgroup, location, type, value, GPU_SAMPLER_DEFAULT, length, arraysize); } void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, @@ -247,7 +255,7 @@ void DRW_shgroup_uniform_texture_ex(DRWShadingGroup *shgroup, const GPUTexture *tex, eGPUSamplerState sampler_state) { - BLI_assert(tex != NULL); + BLI_assert(tex != nullptr); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE, tex, sampler_state, 0, 1); } @@ -262,7 +270,7 @@ void DRW_shgroup_uniform_texture_ref_ex(DRWShadingGroup *shgroup, GPUTexture **tex, eGPUSamplerState sampler_state) { - BLI_assert(tex != NULL); + BLI_assert(tex != nullptr); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_TEXTURE_REF, tex, sampler_state, 0, 1); } @@ -274,23 +282,24 @@ void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, void DRW_shgroup_uniform_image(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) { - BLI_assert(tex != NULL); + BLI_assert(tex != nullptr); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_IMAGE, tex, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_IMAGE, tex, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_uniform_image_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) { - BLI_assert(tex != NULL); + BLI_assert(tex != nullptr); int loc = GPU_shader_get_texture_binding(shgroup->shader, name); - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_IMAGE_REF, tex, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, loc, DRW_UNIFORM_IMAGE_REF, tex, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuf *ubo DRW_DEBUG_FILE_LINE_ARGS) { - BLI_assert(ubo != NULL); + BLI_assert(ubo != nullptr); int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); if (loc == -1) { #ifdef DRW_UNUSED_RESOURCE_TRACKING @@ -304,14 +313,14 @@ void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK, ubo, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup, const char *name, GPUUniformBuf **ubo DRW_DEBUG_FILE_LINE_ARGS) { - BLI_assert(ubo != NULL); + BLI_assert(ubo != nullptr); int loc = GPU_shader_get_uniform_block_binding(shgroup->shader, name); if (loc == -1) { #ifdef DRW_UNUSED_RESOURCE_TRACKING @@ -325,14 +334,15 @@ void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup, const char *name, const GPUStorageBuf *ssbo DRW_DEBUG_FILE_LINE_ARGS) { - BLI_assert(ssbo != NULL); + BLI_assert(ssbo != nullptr); /* TODO(@fclem): Fix naming inconsistency. */ int loc = GPU_shader_get_ssbo(shgroup->shader, name); if (loc == -1) { @@ -347,14 +357,15 @@ void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK, ssbo, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK, ssbo, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup, const char *name, GPUStorageBuf **ssbo DRW_DEBUG_FILE_LINE_ARGS) { - BLI_assert(ssbo != NULL); + BLI_assert(ssbo != nullptr); /* TODO(@fclem): Fix naming inconsistency. */ int loc = GPU_shader_get_ssbo(shgroup->shader, name); if (loc == -1) { @@ -369,7 +380,8 @@ void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK_REF, ssbo, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK_REF, ssbo, GPU_SAMPLER_DEFAULT, 0, 1); } void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, @@ -518,7 +530,8 @@ void DRW_shgroup_uniform_mat4_copy(DRWShadingGroup *shgroup, * and array-size used to determine the number of elements * copied in draw_update_uniforms. */ for (int i = 0; i < 4; i++) { - drw_shgroup_uniform_create_ex(shgroup, location, DRW_UNIFORM_FLOAT_COPY, &value[i], 0, 4, 4); + drw_shgroup_uniform_create_ex( + shgroup, location, DRW_UNIFORM_FLOAT_COPY, &value[i], GPU_SAMPLER_DEFAULT, 4, 4); } } @@ -538,8 +551,13 @@ void DRW_shgroup_vertex_buffer_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex( - shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, vertex_buffer, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, + location, + DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE, + vertex_buffer, + GPU_SAMPLER_DEFAULT, + 0, + 1); } void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup, @@ -558,8 +576,13 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup, #endif return; } - drw_shgroup_uniform_create_ex( - shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, vertex_buffer, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, + location, + DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF, + vertex_buffer, + GPU_SAMPLER_DEFAULT, + 0, + 1); } void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup, @@ -570,8 +593,13 @@ void DRW_shgroup_buffer_texture(DRWShadingGroup *shgroup, if (location == -1) { return; } - drw_shgroup_uniform_create_ex( - shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE, vertex_buffer, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, + location, + DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE, + vertex_buffer, + GPU_SAMPLER_DEFAULT, + 0, + 1); } void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup, @@ -582,8 +610,13 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup, if (location == -1) { return; } - drw_shgroup_uniform_create_ex( - shgroup, location, DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF, vertex_buffer, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, + location, + DRW_UNIFORM_VERTEX_BUFFER_AS_TEXTURE_REF, + vertex_buffer, + GPU_SAMPLER_DEFAULT, + 0, + 1); } /** \} */ @@ -593,11 +626,11 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup, static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4]) { - ID *ob_data = (ob) ? ob->data : NULL; + ID *ob_data = (ob) ? static_cast<ID *>(ob->data) : nullptr; float loc[3], size[3]; - float *texcoloc = NULL; - float *texcosize = NULL; - if (ob_data != NULL) { + float *texcoloc = nullptr; + float *texcosize = nullptr; + if (ob_data != nullptr) { switch (GS(ob_data->name)) { case ID_VO: { BoundBox *bbox = BKE_volume_boundbox_get(ob); @@ -608,7 +641,7 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4]) break; } case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, &texcosize); + BKE_mesh_texspace_get_reference((Mesh *)ob_data, nullptr, &texcoloc, &texcosize); break; case ID_CU_LEGACY: { Curve *cu = (Curve *)ob_data; @@ -628,7 +661,7 @@ static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[4]) } } - if ((texcoloc != NULL) && (texcosize != NULL)) { + if ((texcoloc != nullptr) && (texcosize != nullptr)) { mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f); invert_v3(r_orcofacs[1]); sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize); @@ -666,7 +699,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob) /* TODO(fclem): this is rather costly to do at runtime. Maybe we can * put it in ob->runtime and make depsgraph ensure it is up to date. */ BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0); - ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF); + ob_infos->ob_random = random * (1.0f / float(0xFFFFFFFF)); /* Object State. */ ob_infos->ob_flag = 1.0f; /* Required to have a correct sign */ ob_infos->ob_flag += (ob->base_flag & BASE_SELECTED) ? (1 << 1) : 0; @@ -687,7 +720,7 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob) static void drw_call_culling_init(DRWCullingState *cull, Object *ob) { const BoundBox *bbox; - if (ob != NULL && (bbox = BKE_object_boundbox_get(ob))) { + if (ob != nullptr && (bbox = BKE_object_boundbox_get(ob))) { float corner[3]; /* Get BoundSphere center and radius from the BoundBox. */ mid_v3_v3v3(cull->bsphere.center, bbox->vec[0], bbox->vec[6]); @@ -705,16 +738,19 @@ static void drw_call_culling_init(DRWCullingState *cull, Object *ob) cull->bsphere.radius = -1.0f; } /* Reset user data */ - cull->user_data = NULL; + cull->user_data = nullptr; } static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob) { - DRWCullingState *culling = BLI_memblock_alloc(DST.vmempool->cullstates); - DRWObjectMatrix *ob_mats = BLI_memblock_alloc(DST.vmempool->obmats); + DRWCullingState *culling = static_cast<DRWCullingState *>( + BLI_memblock_alloc(DST.vmempool->cullstates)); + DRWObjectMatrix *ob_mats = static_cast<DRWObjectMatrix *>( + BLI_memblock_alloc(DST.vmempool->obmats)); /* FIXME Meh, not always needed but can be accessed after creation. * Also it needs to have the same resource handle. */ - DRWObjectInfos *ob_infos = BLI_memblock_alloc(DST.vmempool->obinfos); + DRWObjectInfos *ob_infos = static_cast<DRWObjectInfos *>( + BLI_memblock_alloc(DST.vmempool->obinfos)); UNUSED_VARS(ob_infos); DRWResourceHandle handle = DST.resource_handle; @@ -745,13 +781,13 @@ static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) { - if (ob == NULL) { - if (obmat == NULL) { + if (ob == nullptr) { + if (obmat == nullptr) { DRWResourceHandle handle = 0; return handle; } - return drw_resource_handle_new(obmat, NULL); + return drw_resource_handle_new(obmat, nullptr); } if (DST.ob_handle == 0) { @@ -762,8 +798,8 @@ static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, if (shgroup->objectinfo) { if (!DST.ob_state_obinfo_init) { DST.ob_state_obinfo_init = true; - DRWObjectInfos *ob_infos = DRW_memblock_elem_from_handle(DST.vmempool->obinfos, - &DST.ob_handle); + DRWObjectInfos *ob_infos = static_cast<DRWObjectInfos *>( + DRW_memblock_elem_from_handle(DST.vmempool->obinfos, &DST.ob_handle)); drw_call_obinfos_init(ob_infos, ob); } @@ -783,20 +819,21 @@ static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, static void command_type_set(uint64_t *command_type_bits, int index, eDRWCommandType type) { - command_type_bits[index / 16] |= ((uint64_t)type) << ((index % 16) * 4); + command_type_bits[index / 16] |= uint64_t(type) << ((index % 16) * 4); } eDRWCommandType command_type_get(const uint64_t *command_type_bits, int index) { - return ((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF); + return eDRWCommandType((command_type_bits[index / 16] >> ((index % 16) * 4)) & 0xF); } static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type) { DRWCommandChunk *chunk = shgroup->cmd.last; - if (chunk == NULL) { - DRWCommandSmallChunk *smallchunk = BLI_memblock_alloc(DST.vmempool->commands_small); + if (chunk == nullptr) { + DRWCommandSmallChunk *smallchunk = static_cast<DRWCommandSmallChunk *>( + BLI_memblock_alloc(DST.vmempool->commands_small)); smallchunk->command_len = ARRAY_SIZE(smallchunk->commands); smallchunk->command_used = 0; smallchunk->command_type[0] = 0x0lu; @@ -804,7 +841,7 @@ static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type) BLI_LINKS_APPEND(&shgroup->cmd, chunk); } else if (chunk->command_used == chunk->command_len) { - chunk = BLI_memblock_alloc(DST.vmempool->commands); + chunk = static_cast<DRWCommandChunk *>(BLI_memblock_alloc(DST.vmempool->commands)); chunk->command_len = ARRAY_SIZE(chunk->commands); chunk->command_used = 0; memset(chunk->command_type, 0x0, sizeof(chunk->command_type)); @@ -818,7 +855,7 @@ static void *drw_command_create(DRWShadingGroup *shgroup, eDRWCommandType type) static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle) { - DRWCommandDraw *cmd = drw_command_create(shgroup, DRW_CMD_DRAW); + DRWCommandDraw *cmd = static_cast<DRWCommandDraw *>(drw_command_create(shgroup, DRW_CMD_DRAW)); cmd->batch = batch; cmd->handle = handle; } @@ -826,7 +863,8 @@ static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResou static void drw_command_draw_range( DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count) { - DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE); + DRWCommandDrawRange *cmd = static_cast<DRWCommandDrawRange *>( + drw_command_create(shgroup, DRW_CMD_DRAW_RANGE)); cmd->batch = batch; cmd->handle = handle; cmd->vert_first = start; @@ -836,7 +874,8 @@ static void drw_command_draw_range( static void drw_command_draw_instance( DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint count, bool use_attr) { - DRWCommandDrawInstance *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE); + DRWCommandDrawInstance *cmd = static_cast<DRWCommandDrawInstance *>( + drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE)); cmd->batch = batch; cmd->handle = handle; cmd->inst_count = count; @@ -846,7 +885,8 @@ static void drw_command_draw_instance( static void drw_command_draw_intance_range( DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count) { - DRWCommandDrawInstanceRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE_RANGE); + DRWCommandDrawInstanceRange *cmd = static_cast<DRWCommandDrawInstanceRange *>( + drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE_RANGE)); cmd->batch = batch; cmd->handle = handle; cmd->inst_first = start; @@ -858,7 +898,8 @@ static void drw_command_compute(DRWShadingGroup *shgroup, int groups_y_len, int groups_z_len) { - DRWCommandCompute *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE); + DRWCommandCompute *cmd = static_cast<DRWCommandCompute *>( + drw_command_create(shgroup, DRW_CMD_COMPUTE)); cmd->groups_x_len = groups_x_len; cmd->groups_y_len = groups_y_len; cmd->groups_z_len = groups_z_len; @@ -866,19 +907,22 @@ static void drw_command_compute(DRWShadingGroup *shgroup, static void drw_command_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]) { - DRWCommandComputeRef *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE_REF); + DRWCommandComputeRef *cmd = static_cast<DRWCommandComputeRef *>( + drw_command_create(shgroup, DRW_CMD_COMPUTE_REF)); cmd->groups_ref = groups_ref; } static void drw_command_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf *indirect_buf) { - DRWCommandComputeIndirect *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE_INDIRECT); + DRWCommandComputeIndirect *cmd = static_cast<DRWCommandComputeIndirect *>( + drw_command_create(shgroup, DRW_CMD_COMPUTE_INDIRECT)); cmd->indirect_buf = indirect_buf; } static void drw_command_barrier(DRWShadingGroup *shgroup, eGPUBarrier type) { - DRWCommandBarrier *cmd = drw_command_create(shgroup, DRW_CMD_BARRIER); + DRWCommandBarrier *cmd = static_cast<DRWCommandBarrier *>( + drw_command_create(shgroup, DRW_CMD_BARRIER)); cmd->type = type; } @@ -887,7 +931,8 @@ static void drw_command_draw_procedural(DRWShadingGroup *shgroup, DRWResourceHandle handle, uint vert_count) { - DRWCommandDrawProcedural *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL); + DRWCommandDrawProcedural *cmd = static_cast<DRWCommandDrawProcedural *>( + drw_command_create(shgroup, DRW_CMD_DRAW_PROCEDURAL)); cmd->batch = batch; cmd->handle = handle; cmd->vert_count = vert_count; @@ -898,7 +943,8 @@ static void drw_command_draw_indirect(DRWShadingGroup *shgroup, DRWResourceHandle handle, GPUStorageBuf *indirect_buf) { - DRWCommandDrawIndirect *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INDIRECT); + DRWCommandDrawIndirect *cmd = static_cast<DRWCommandDrawIndirect *>( + drw_command_create(shgroup, DRW_CMD_DRAW_INDIRECT)); cmd->batch = batch; cmd->handle = handle; cmd->indirect_buf = indirect_buf; @@ -907,8 +953,9 @@ static void drw_command_draw_indirect(DRWShadingGroup *shgroup, static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, uint select_id) { /* Only one can be valid. */ - BLI_assert(buf == NULL || select_id == -1); - DRWCommandSetSelectID *cmd = drw_command_create(shgroup, DRW_CMD_SELECTID); + BLI_assert(buf == nullptr || select_id == -1); + DRWCommandSetSelectID *cmd = static_cast<DRWCommandSetSelectID *>( + drw_command_create(shgroup, DRW_CMD_SELECTID)); cmd->select_buf = buf; cmd->select_id = select_id; } @@ -921,7 +968,8 @@ static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, BLI_assert(write_mask <= 0xFF); BLI_assert(reference <= 0xFF); BLI_assert(compare_mask <= 0xFF); - DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL); + DRWCommandSetStencil *cmd = static_cast<DRWCommandSetStencil *>( + drw_command_create(shgroup, DRW_CMD_STENCIL)); cmd->write_mask = write_mask; cmd->comp_mask = compare_mask; cmd->ref = reference; @@ -936,7 +984,8 @@ static void drw_command_clear(DRWShadingGroup *shgroup, float depth, uchar stencil) { - DRWCommandClear *cmd = drw_command_create(shgroup, DRW_CMD_CLEAR); + DRWCommandClear *cmd = static_cast<DRWCommandClear *>( + drw_command_create(shgroup, DRW_CMD_CLEAR)); cmd->clear_channels = channels; cmd->r = r; cmd->g = g; @@ -951,7 +1000,8 @@ static void drw_command_set_mutable_state(DRWShadingGroup *shgroup, DRWState disable) { /* TODO: Restrict what state can be changed. */ - DRWCommandSetMutableState *cmd = drw_command_create(shgroup, DRW_CMD_DRWSTATE); + DRWCommandSetMutableState *cmd = static_cast<DRWCommandSetMutableState *>( + drw_command_create(shgroup, DRW_CMD_DRWSTATE)); cmd->enable = enable; cmd->disable = disable; } @@ -963,17 +1013,17 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, bool bypass_culling, void *user_data) { - BLI_assert(geom != NULL); + BLI_assert(geom != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : obmat, ob); drw_command_draw(shgroup, geom, handle); /* Culling data. */ if (user_data || bypass_culling) { - DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, - &DST.ob_handle); + DRWCullingState *culling = static_cast<DRWCullingState *>( + DRW_memblock_elem_from_handle(DST.vmempool->cullstates, &DST.ob_handle)); if (user_data) { culling->user_data = user_data; @@ -988,22 +1038,22 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, void DRW_shgroup_call_range( DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_num) { - BLI_assert(geom != NULL); + BLI_assert(geom != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); drw_command_draw_range(shgroup, geom, handle, v_sta, v_num); } void DRW_shgroup_call_instance_range( DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_num) { - BLI_assert(geom != NULL); + BLI_assert(geom != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_num); } @@ -1045,11 +1095,11 @@ static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, uint vert_count) { BLI_assert(vert_count > 0); - BLI_assert(geom != NULL); + BLI_assert(geom != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); drw_command_draw_procedural(shgroup, geom, handle, vert_count); } @@ -1076,7 +1126,7 @@ void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, Object *ob, GPUStorageBuf *indirect_buf) { - struct GPUBatch *geom = NULL; + struct GPUBatch *geom = nullptr; switch (primitive_type) { case GPU_PRIM_POINTS: geom = drw_cache_procedural_points_get(); @@ -1097,9 +1147,9 @@ void DRW_shgroup_call_procedural_indirect(DRWShadingGroup *shgroup, break; } if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); drw_command_draw_indirect(shgroup, geom, handle, indirect_buf); } @@ -1108,11 +1158,11 @@ void DRW_shgroup_call_instances(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint count) { - BLI_assert(geom != NULL); + BLI_assert(geom != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); drw_command_draw_instance(shgroup, geom, handle, count, false); } @@ -1121,14 +1171,14 @@ void DRW_shgroup_call_instances_with_attrs(DRWShadingGroup *shgroup, struct GPUBatch *geom, struct GPUBatch *inst_attributes) { - BLI_assert(geom != NULL); - BLI_assert(inst_attributes != NULL); + BLI_assert(geom != nullptr); + BLI_assert(inst_attributes != nullptr); if (G.f & G_FLAG_PICKSEL) { - drw_command_set_select_id(shgroup, NULL, DST.select_id); + drw_command_set_select_id(shgroup, nullptr, DST.select_id); } - DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : nullptr, ob); GPUBatch *batch = DRW_temp_batch_instance_request( - DST.vmempool->idatalist, NULL, inst_attributes, geom); + DST.vmempool->idatalist, nullptr, inst_attributes, geom); drw_command_draw_instance(shgroup, batch, handle, 0, true); } @@ -1144,6 +1194,8 @@ typedef struct DRWSculptCallbackData { bool fast_mode; /* Set by draw manager. Do not init. */ int debug_node_nr; + PBVHAttrReq *attrs; + int attrs_num; } DRWSculptCallbackData; #define SCULPT_DEBUG_COLOR(id) (sculpt_debug_colors[id % 9]) @@ -1159,29 +1211,35 @@ static float sculpt_debug_colors[9][4] = { {0.7f, 0.2f, 1.0f, 1.0f}, }; -static void sculpt_draw_cb(DRWSculptCallbackData *scd, GPU_PBVH_Buffers *buffers) +static void sculpt_draw_cb(DRWSculptCallbackData *scd, + PBVHBatches *batches, + PBVH_GPU_Args *pbvh_draw_args) { - if (!buffers) { + if (!batches) { return; } - /* Meh... use_mask is a bit misleading here. */ - if (scd->use_mask && !GPU_pbvh_buffers_has_overlays(buffers)) { - return; + int primcount; + GPUBatch *geom; + + if (!scd->use_wire) { + geom = DRW_pbvh_tris_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount); + } + else { + geom = DRW_pbvh_lines_get(batches, scd->attrs, scd->attrs_num, pbvh_draw_args, &primcount); } - GPUBatch *geom = GPU_pbvh_buffers_batch_get(buffers, scd->fast_mode, scd->use_wire); short index = 0; if (scd->use_mats) { - index = GPU_pbvh_buffers_material_index_get(buffers); + index = drw_pbvh_material_index_get(batches); if (index >= scd->num_shading_groups) { index = 0; } } DRWShadingGroup *shgrp = scd->shading_groups[index]; - if (geom != NULL && shgrp != NULL) { + if (geom != nullptr && shgrp != nullptr) { if (SCULPT_DEBUG_BUFFERS) { /* Color each buffers in different colors. Only work in solid/Xray mode. */ shgrp = DRW_shgroup_create_sub(shgrp); @@ -1237,7 +1295,7 @@ static void drw_sculpt_get_frustum_planes(Object *ob, float planes[6][4]) static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) { /* PBVH should always exist for non-empty meshes, created by depsgraph eval. */ - PBVH *pbvh = (scd->ob->sculpt) ? scd->ob->sculpt->pbvh : NULL; + PBVH *pbvh = (scd->ob->sculpt) ? scd->ob->sculpt->pbvh : nullptr; if (!pbvh) { return; } @@ -1246,8 +1304,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) RegionView3D *rv3d = drwctx->rv3d; const bool navigating = rv3d && (rv3d->rflag & RV3D_NAVIGATING); - Paint *p = NULL; - if (drwctx->evil_C != NULL) { + Paint *p = nullptr; + if (drwctx->evil_C != nullptr) { p = BKE_paint_get_active_from_context(drwctx->evil_C); } @@ -1291,16 +1349,18 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) update_only_visible = true; } - Mesh *mesh = scd->ob->data; + Mesh *mesh = static_cast<Mesh *>(scd->ob->data); BKE_pbvh_update_normals(pbvh, mesh->runtime.subdiv_ccg); BKE_pbvh_draw_cb(pbvh, update_only_visible, &update_frustum, &draw_frustum, - (void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb, + (void (*)(void *, PBVHBatches *, PBVH_GPU_Args *))sculpt_draw_cb, scd, - scd->use_mats); + scd->use_mats, + scd->attrs, + scd->attrs_num); if (SCULPT_DEBUG_BUFFERS) { int debug_node_nr = 0; @@ -1313,31 +1373,141 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd) } } -void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup, Object *ob, bool use_wire, bool use_mask) +void DRW_shgroup_call_sculpt(DRWShadingGroup *shgroup, + Object *ob, + bool use_wire, + bool use_mask, + bool use_fset, + bool use_color, + bool use_uv) { - DRWSculptCallbackData scd = { - .ob = ob, - .shading_groups = &shgroup, - .num_shading_groups = 1, - .use_wire = use_wire, - .use_mats = false, - .use_mask = use_mask, - }; + DRWSculptCallbackData scd{}; + scd.ob = ob; + scd.shading_groups = &shgroup; + scd.num_shading_groups = 1; + scd.use_wire = use_wire; + scd.use_mats = false; + scd.use_mask = use_mask; + + PBVHAttrReq attrs[16]; + int attrs_num = 0; + + memset(attrs, 0, sizeof(attrs)); + + /* NOTE: these are NOT #eCustomDataType, they are extended values, ASAN may warn about this. */ + attrs[attrs_num++].type = (eCustomDataType)CD_PBVH_CO_TYPE; + attrs[attrs_num++].type = (eCustomDataType)CD_PBVH_NO_TYPE; + + if (use_mask) { + attrs[attrs_num++].type = (eCustomDataType)CD_PBVH_MASK_TYPE; + } + + if (use_fset) { + attrs[attrs_num++].type = (eCustomDataType)CD_PBVH_FSET_TYPE; + } + + Mesh *me = BKE_object_get_original_mesh(ob); + + if (use_color) { + CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); + + if (layer) { + eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer); + + attrs[attrs_num].type = eCustomDataType(layer->type); + attrs[attrs_num].domain = domain; + + BLI_strncpy(attrs[attrs_num].name, layer->name, sizeof(attrs[attrs_num].name)); + attrs_num++; + } + } + + if (use_uv) { + int layer_i = CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV); + if (layer_i != -1) { + CustomDataLayer *layer = me->ldata.layers + layer_i; + + attrs[attrs_num].type = CD_MLOOPUV; + attrs[attrs_num].domain = ATTR_DOMAIN_CORNER; + BLI_strncpy(attrs[attrs_num].name, layer->name, sizeof(attrs[attrs_num].name)); + + attrs_num++; + } + } + + scd.attrs = attrs; + scd.attrs_num = attrs_num; + drw_sculpt_generate_calls(&scd); } void DRW_shgroup_call_sculpt_with_materials(DRWShadingGroup **shgroups, + GPUMaterial **gpumats, int num_shgroups, Object *ob) { - DRWSculptCallbackData scd = { - .ob = ob, - .shading_groups = shgroups, - .num_shading_groups = num_shgroups, - .use_wire = false, - .use_mats = true, - .use_mask = false, - }; + DRW_Attributes draw_attrs; + DRW_MeshCDMask cd_needed; + + if (gpumats) { + DRW_mesh_get_attributes(ob, (Mesh *)ob->data, gpumats, num_shgroups, &draw_attrs, &cd_needed); + } + else { + memset(&draw_attrs, 0, sizeof(draw_attrs)); + memset(&cd_needed, 0, sizeof(cd_needed)); + } + + int attrs_num = 2 + draw_attrs.num_requests; + + /* UV maps are not in attribute requests. */ + attrs_num += count_bits_i(cd_needed.uv); + + blender::Array<PBVHAttrReq, 16> attrs(attrs_num, PBVHAttrReq{}); + + int attrs_i = 0; + + /* NOTE: these are NOT #eCustomDataType, they are extended values, ASAN may warn about this. */ + attrs[attrs_i++].type = (eCustomDataType)CD_PBVH_CO_TYPE; + attrs[attrs_i++].type = (eCustomDataType)CD_PBVH_NO_TYPE; + + for (int i = 0; i < draw_attrs.num_requests; i++) { + DRW_AttributeRequest *req = draw_attrs.requests + i; + + attrs[attrs_i].type = req->cd_type; + attrs[attrs_i].domain = req->domain; + BLI_strncpy(attrs[attrs_i].name, req->attribute_name, sizeof(PBVHAttrReq::name)); + attrs_i++; + } + + /* UV maps are not in attribute requests. */ + Mesh *me = (Mesh *)ob->data; + + for (uint i = 0; i < 32; i++) { + if (cd_needed.uv & (1 << i)) { + int layer_i = CustomData_get_layer_index_n(&me->ldata, CD_MLOOPUV, i); + CustomDataLayer *layer = layer_i != -1 ? me->ldata.layers + layer_i : nullptr; + + if (layer) { + attrs[attrs_i].type = CD_MLOOPUV; + attrs[attrs_i].domain = ATTR_DOMAIN_CORNER; + BLI_strncpy(attrs[attrs_i].name, layer->name, sizeof(PBVHAttrReq::name)); + attrs_i++; + } + } + } + + attrs_num = attrs_i; + + DRWSculptCallbackData scd{}; + scd.ob = ob; + scd.shading_groups = shgroups; + scd.num_shading_groups = num_shgroups; + scd.use_wire = false; + scd.use_mats = true; + scd.use_mask = false; + scd.attrs = attrs.data(); + scd.attrs_num = attrs_num; + drw_sculpt_generate_calls(&scd); } @@ -1348,15 +1518,16 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, GPUPrimType prim_type) { BLI_assert(ELEM(prim_type, GPU_PRIM_POINTS, GPU_PRIM_LINES, GPU_PRIM_TRI_FAN)); - BLI_assert(format != NULL); + BLI_assert(format != nullptr); - DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); + DRWCallBuffer *callbuf = static_cast<DRWCallBuffer *>( + BLI_memblock_alloc(DST.vmempool->callbuffers)); callbuf->buf = DRW_temp_buffer_request(DST.vmempool->idatalist, format, &callbuf->count); - callbuf->buf_select = NULL; + callbuf->buf_select = nullptr; callbuf->count = 0; if (G.f & G_FLAG_PICKSEL) { - /* Not actually used for rendering but alloced in one chunk. */ + /* Not actually used for rendering but allocated in one chunk. */ if (inst_select_format.attr_len == 0) { GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } @@ -1365,7 +1536,7 @@ DRWCallBuffer *DRW_shgroup_call_buffer(DRWShadingGroup *shgroup, drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } - DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); + DRWResourceHandle handle = drw_resource_handle(shgroup, nullptr, nullptr); GPUBatch *batch = DRW_temp_batch_request(DST.vmempool->idatalist, callbuf->buf, prim_type); drw_command_draw(shgroup, batch, handle); @@ -1376,16 +1547,17 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, struct GPUVertFormat *format, GPUBatch *geom) { - BLI_assert(geom != NULL); - BLI_assert(format != NULL); + BLI_assert(geom != nullptr); + BLI_assert(format != nullptr); - DRWCallBuffer *callbuf = BLI_memblock_alloc(DST.vmempool->callbuffers); + DRWCallBuffer *callbuf = static_cast<DRWCallBuffer *>( + BLI_memblock_alloc(DST.vmempool->callbuffers)); callbuf->buf = DRW_temp_buffer_request(DST.vmempool->idatalist, format, &callbuf->count); - callbuf->buf_select = NULL; + callbuf->buf_select = nullptr; callbuf->count = 0; if (G.f & G_FLAG_PICKSEL) { - /* Not actually used for rendering but alloced in one chunk. */ + /* Not actually used for rendering but allocated in one chunk. */ if (inst_select_format.attr_len == 0) { GPU_vertformat_attr_add(&inst_select_format, "selectId", GPU_COMP_I32, 1, GPU_FETCH_INT); } @@ -1394,9 +1566,9 @@ DRWCallBuffer *DRW_shgroup_call_buffer_instance(DRWShadingGroup *shgroup, drw_command_set_select_id(shgroup, callbuf->buf_select, -1); } - DRWResourceHandle handle = drw_resource_handle(shgroup, NULL, NULL); + DRWResourceHandle handle = drw_resource_handle(shgroup, nullptr, nullptr); GPUBatch *batch = DRW_temp_batch_instance_request( - DST.vmempool->idatalist, callbuf->buf, NULL, geom); + DST.vmempool->idatalist, callbuf->buf, nullptr, geom); drw_command_draw(shgroup, batch, handle); return callbuf; @@ -1457,8 +1629,8 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *callbuf, const void *attr[], uint static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) { - shgroup->uniforms = NULL; - shgroup->uniform_attrs = NULL; + shgroup->uniforms = nullptr; + shgroup->uniform_attrs = nullptr; int view_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_VIEW); int model_ubo_location = GPU_shader_get_builtin_block(shader, GPU_UNIFORM_BLOCK_MODEL); @@ -1480,22 +1652,22 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (chunkid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 0, 1); + shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); } if (resourceid_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 0, 1); + shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); } if (baseinst_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 0, 1); + shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); } if (model_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, NULL, 0, 0, 1); + shgroup, model_ubo_location, DRW_UNIFORM_BLOCK_OBMATS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); } else { /* NOTE: This is only here to support old hardware fallback where uniform buffer is still @@ -1503,17 +1675,23 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) int model = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL); int modelinverse = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MODEL_INV); if (model != -1) { - drw_shgroup_uniform_create_ex(shgroup, model, DRW_UNIFORM_MODEL_MATRIX, NULL, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, model, DRW_UNIFORM_MODEL_MATRIX, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); } if (modelinverse != -1) { - drw_shgroup_uniform_create_ex( - shgroup, modelinverse, DRW_UNIFORM_MODEL_MATRIX_INVERSE, NULL, 0, 0, 1); + drw_shgroup_uniform_create_ex(shgroup, + modelinverse, + DRW_UNIFORM_MODEL_MATRIX_INVERSE, + nullptr, + GPU_SAMPLER_DEFAULT, + 0, + 1); } } if (info_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, NULL, 0, 0, 1); + shgroup, info_ubo_location, DRW_UNIFORM_BLOCK_OBINFOS, nullptr, GPU_SAMPLER_DEFAULT, 0, 1); /* Abusing this loc to tell shgroup we need the obinfos. */ shgroup->objectinfo = 1; @@ -1524,7 +1702,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (view_ubo_location != -1) { drw_shgroup_uniform_create_ex( - shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, 0, 0, 1); + shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, G_draw.view_ubo, GPU_SAMPLER_DEFAULT, 0, 1); } #ifdef DEBUG @@ -1532,7 +1710,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (debug_print_location != -1) { GPUStorageBuf *buf = drw_debug_gpu_print_buf_get(); drw_shgroup_uniform_create_ex( - shgroup, debug_print_location, DRW_UNIFORM_STORAGE_BLOCK, buf, 0, 0, 1); + shgroup, debug_print_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1); # ifndef DISABLE_DEBUG_SHADER_PRINT_BARRIER /* Add a barrier to allow multiple shader writing to the same buffer. */ DRW_shgroup_barrier(shgroup, GPU_BARRIER_SHADER_STORAGE); @@ -1543,7 +1721,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) if (debug_draw_location != -1) { GPUStorageBuf *buf = drw_debug_gpu_draw_buf_get(); drw_shgroup_uniform_create_ex( - shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, 0, 0, 1); + shgroup, debug_draw_location, DRW_UNIFORM_STORAGE_BLOCK, buf, GPU_SAMPLER_DEFAULT, 0, 1); /* NOTE(fclem): No barrier as ordering is not important. */ } #endif @@ -1564,13 +1742,14 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) { - DRWShadingGroup *shgroup = BLI_memblock_alloc(DST.vmempool->shgroups); + DRWShadingGroup *shgroup = static_cast<DRWShadingGroup *>( + BLI_memblock_alloc(DST.vmempool->shgroups)); BLI_LINKS_APPEND(&pass->shgroups, shgroup); shgroup->shader = shader; - shgroup->cmd.first = NULL; - shgroup->cmd.last = NULL; + shgroup->cmd.first = nullptr; + shgroup->cmd.last = nullptr; shgroup->pass_handle = pass->handle; return shgroup; @@ -1580,14 +1759,14 @@ static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass { if (!gpupass) { /* Shader compilation error */ - return NULL; + return nullptr; } GPUShader *sh = GPU_pass_shader_get(gpupass); if (!sh) { /* Shader not yet compiled */ - return NULL; + return nullptr; } DRWShadingGroup *grp = drw_shgroup_create_ex(sh, pass); @@ -1601,7 +1780,7 @@ static void drw_shgroup_material_texture(DRWShadingGroup *grp, { DRW_shgroup_uniform_texture_ex(grp, name, gputex, state); - GPUTexture **gputex_ref = BLI_memblock_alloc(DST.vmempool->images); + GPUTexture **gputex_ref = static_cast<GPUTexture **>(BLI_memblock_alloc(DST.vmempool->images)); *gputex_ref = gputex; GPU_texture_ref(gputex); } @@ -1615,16 +1794,19 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial if (tex->ima) { /* Image */ GPUTexture *gputex; - ImageUser *iuser = tex->iuser_available ? &tex->iuser : NULL; + ImageUser *iuser = tex->iuser_available ? &tex->iuser : nullptr; if (tex->tiled_mapping_name[0]) { - gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, NULL); - drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); - gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, NULL); - drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state); + gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, nullptr); + drw_shgroup_material_texture( + grp, gputex, tex->sampler_name, eGPUSamplerState(tex->sampler_state)); + gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, nullptr); + drw_shgroup_material_texture( + grp, gputex, tex->tiled_mapping_name, eGPUSamplerState(tex->sampler_state)); } else { - gputex = BKE_image_get_gpu_texture(tex->ima, iuser, NULL); - drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); + gputex = BKE_image_get_gpu_texture(tex->ima, iuser, nullptr); + drw_shgroup_material_texture( + grp, gputex, tex->sampler_name, eGPUSamplerState(tex->sampler_state)); } } else if (tex->colorband) { @@ -1633,19 +1815,21 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial } else if (tex->sky) { /* Sky */ - DRW_shgroup_uniform_texture_ex(grp, tex->sampler_name, *tex->sky, tex->sampler_state); + DRW_shgroup_uniform_texture_ex( + grp, tex->sampler_name, *tex->sky, eGPUSamplerState(tex->sampler_state)); } } GPUUniformBuf *ubo = GPU_material_uniform_buffer_get(material); - if (ubo != NULL) { + if (ubo != nullptr) { DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); } const GPUUniformAttrList *uattrs = GPU_material_uniform_attributes(material); - if (uattrs != NULL) { + if (uattrs != nullptr) { int loc = GPU_shader_get_uniform_block_binding(grp->shader, GPU_ATTRIBUTE_UBO_BLOCK_NAME); - drw_shgroup_uniform_create_ex(grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, 0, 0, 1); + drw_shgroup_uniform_create_ex( + grp, loc, DRW_UNIFORM_BLOCK_OBATTRS, uattrs, GPU_SAMPLER_DEFAULT, 0, 1); grp->uniform_attrs = uattrs; } } @@ -1653,7 +1837,7 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial GPUVertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttrFormat attrs[], int arraysize) { - GPUVertFormat *format = MEM_callocN(sizeof(GPUVertFormat), "GPUVertFormat"); + GPUVertFormat *format = MEM_cnew<GPUVertFormat>(__func__); for (int i = 0; i < arraysize; i++) { GPU_vertformat_attr_add(format, @@ -1688,21 +1872,22 @@ DRWShadingGroup *DRW_shgroup_transform_feedback_create(struct GPUShader *shader, DRWPass *pass, GPUVertBuf *tf_target) { - BLI_assert(tf_target != NULL); + BLI_assert(tf_target != nullptr); DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); drw_shgroup_init(shgroup, shader); - drw_shgroup_uniform_create_ex(shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, 0, 0, 1); + drw_shgroup_uniform_create_ex( + shgroup, 0, DRW_UNIFORM_TFEEDBACK_TARGET, tf_target, GPU_SAMPLER_DEFAULT, 0, 1); return shgroup; } void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) { - drw_command_set_mutable_state(shgroup, state, 0x0); + drw_command_set_mutable_state(shgroup, state, DRW_STATE_NO_DRAW); } void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) { - drw_command_set_mutable_state(shgroup, 0x0, state); + drw_command_set_mutable_state(shgroup, DRW_STATE_NO_DRAW, state); } void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, @@ -1745,15 +1930,16 @@ bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) DRWShadingGroup *DRW_shgroup_create_sub(DRWShadingGroup *shgroup) { - DRWShadingGroup *shgroup_new = BLI_memblock_alloc(DST.vmempool->shgroups); + DRWShadingGroup *shgroup_new = static_cast<DRWShadingGroup *>( + BLI_memblock_alloc(DST.vmempool->shgroups)); *shgroup_new = *shgroup; drw_shgroup_init(shgroup_new, shgroup_new->shader); - shgroup_new->cmd.first = NULL; - shgroup_new->cmd.last = NULL; + shgroup_new->cmd.first = nullptr; + shgroup_new->cmd.last = nullptr; - DRWPass *parent_pass = DRW_memblock_elem_from_handle(DST.vmempool->passes, - &shgroup->pass_handle); + DRWPass *parent_pass = static_cast<DRWPass *>( + DRW_memblock_elem_from_handle(DST.vmempool->passes, &shgroup->pass_handle)); BLI_LINKS_INSERT_AFTER(&parent_pass->shgroups, shgroup, shgroup_new); @@ -1951,14 +2137,14 @@ static void draw_view_matrix_state_update(ViewInfos *storage, const float viewmat[4][4], const float winmat[4][4]) { - copy_m4_m4(storage->viewmat, viewmat); - invert_m4_m4(storage->viewinv, storage->viewmat); + copy_m4_m4(storage->viewmat.values, viewmat); + invert_m4_m4(storage->viewinv.values, storage->viewmat.values); - copy_m4_m4(storage->winmat, winmat); - invert_m4_m4(storage->wininv, storage->winmat); + copy_m4_m4(storage->winmat.values, winmat); + invert_m4_m4(storage->wininv.values, storage->winmat.values); - mul_m4_m4m4(storage->persmat, winmat, viewmat); - invert_m4_m4(storage->persinv, storage->persmat); + mul_m4_m4m4(storage->persmat.values, winmat, viewmat); + invert_m4_m4(storage->persinv.values, storage->persmat.values); const bool is_persp = (winmat[3][3] == 0.0f); @@ -1981,7 +2167,7 @@ static void draw_view_matrix_state_update(ViewInfos *storage, /* convert the view vectors to view space */ for (int i = 0; i < 4; i++) { - mul_project_m4_v3(storage->wininv, view_vecs[i]); + mul_project_m4_v3(storage->wininv.values, view_vecs[i]); /* normalized trick see: * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ if (is_persp) { @@ -1991,13 +2177,15 @@ static void draw_view_matrix_state_update(ViewInfos *storage, } /** - * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and - * view_vecs[1] is the vector going from the near-bottom-left corner to - * the far-top-right corner. - * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner - * when Z = 1, and top-left corner if Z = 1. - * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed) - * distance from the near plane to the far clip plane. + * - When orthographic: + * `view_vecs[0]` is the near-bottom-left corner of the frustum and + * `view_vecs[1]` is the vector going from the near-bottom-left corner to + * the far-top-right corner. + * - When perspective: + * `view_vecs[0].xy` and `view_vecs[1].xy` are respectively the bottom-left corner + * when Z = 1, and top-left corner if `Z = 1`. + * `view_vecs[0].z` the near clip distance and `view_vecs[1].z` is the (signed) + * distance from the near plane to the far clip plane. */ copy_v3_v3(storage->viewvecs[0], view_vecs[0]); @@ -2013,7 +2201,7 @@ DRWView *DRW_view_create(const float viewmat[4][4], const float (*culling_winmat)[4], DRWCallVisibilityFn *visibility_fn) { - DRWView *view = BLI_memblock_alloc(DST.vmempool->views); + DRWView *view = static_cast<DRWView *>(BLI_memblock_alloc(DST.vmempool->views)); if (DST.primary_view_num < MAX_CULLED_VIEWS) { view->culling_mask = 1u << DST.primary_view_num++; @@ -2024,7 +2212,7 @@ DRWView *DRW_view_create(const float viewmat[4][4], } view->clip_planes_len = 0; view->visibility_fn = visibility_fn; - view->parent = NULL; + view->parent = nullptr; copy_v4_fl4(view->storage.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); @@ -2046,11 +2234,11 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view, { /* Search original parent. */ const DRWView *ori_view = parent_view; - while (ori_view->parent != NULL) { + while (ori_view->parent != nullptr) { ori_view = ori_view->parent; } - DRWView *view = BLI_memblock_alloc(DST.vmempool->views); + DRWView *view = static_cast<DRWView *>(BLI_memblock_alloc(DST.vmempool->views)); /* Perform copy. */ *view = *ori_view; @@ -2067,7 +2255,7 @@ DRWView *DRW_view_create_sub(const DRWView *parent_view, void DRW_view_update_sub(DRWView *view, const float viewmat[4][4], const float winmat[4][4]) { - BLI_assert(view->parent != NULL); + BLI_assert(view->parent != nullptr); view->is_dirty = true; view->is_inverted = (is_negative_m4(viewmat) == is_negative_m4(winmat)); @@ -2084,7 +2272,7 @@ void DRW_view_update(DRWView *view, /* DO NOT UPDATE THE DEFAULT VIEW. * Create sub-views instead, or a copy. */ BLI_assert(view != DST.view_default); - BLI_assert(view->parent == NULL); + BLI_assert(view->parent == nullptr); view->is_dirty = true; view->is_inverted = (is_negative_m4(viewmat) == is_negative_m4(winmat)); @@ -2117,7 +2305,7 @@ void DRW_view_update(DRWView *view, invert_m4_m4(wininv, winmat); } else { - copy_m4_m4(wininv, view->storage.wininv); + copy_m4_m4(wininv, view->storage.wininv.values); } float viewinv[4][4]; @@ -2126,11 +2314,11 @@ void DRW_view_update(DRWView *view, invert_m4_m4(viewinv, viewmat); } else { - copy_m4_m4(viewinv, view->storage.viewinv); + copy_m4_m4(viewinv, view->storage.viewinv.values); } draw_frustum_boundbox_calc(viewinv, winmat, &view->frustum_corners); - draw_frustum_culling_planes_calc(view->storage.persmat, view->frustum_planes); + draw_frustum_culling_planes_calc(view->storage.persmat.values, view->frustum_planes); draw_frustum_bound_sphere_calc( &view->frustum_corners, viewinv, winmat, wininv, &view->frustum_bsphere); @@ -2158,14 +2346,14 @@ const DRWView *DRW_view_default_get(void) void DRW_view_reset(void) { - DST.view_default = NULL; - DST.view_active = NULL; - DST.view_previous = NULL; + DST.view_default = nullptr; + DST.view_active = nullptr; + DST.view_previous = nullptr; } void DRW_view_default_set(const DRWView *view) { - BLI_assert(DST.view_default == NULL); + BLI_assert(DST.view_default == nullptr); DST.view_default = (DRWView *)view; } @@ -2207,7 +2395,7 @@ bool DRW_view_is_persp_get(const DRWView *view) float DRW_view_near_distance_get(const DRWView *view) { view = (view) ? view : DST.view_default; - const float(*projmat)[4] = view->storage.winmat; + const float4x4 &projmat = view->storage.winmat; if (DRW_view_is_persp_get(view)) { return -projmat[3][2] / (projmat[2][2] - 1.0f); @@ -2219,7 +2407,7 @@ float DRW_view_near_distance_get(const DRWView *view) float DRW_view_far_distance_get(const DRWView *view) { view = (view) ? view : DST.view_default; - const float(*projmat)[4] = view->storage.winmat; + const float4x4 &projmat = view->storage.winmat; if (DRW_view_is_persp_get(view)) { return -projmat[3][2] / (projmat[2][2] + 1.0f); @@ -2232,21 +2420,21 @@ void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse) { view = (view) ? view : DST.view_default; const ViewInfos *storage = &view->storage; - copy_m4_m4(mat, (inverse) ? storage->viewinv : storage->viewmat); + copy_m4_m4(mat, (inverse) ? storage->viewinv.values : storage->viewmat.values); } void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse) { view = (view) ? view : DST.view_default; const ViewInfos *storage = &view->storage; - copy_m4_m4(mat, (inverse) ? storage->wininv : storage->winmat); + copy_m4_m4(mat, (inverse) ? storage->wininv.values : storage->winmat.values); } void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse) { view = (view) ? view : DST.view_default; const ViewInfos *storage = &view->storage; - copy_m4_m4(mat, (inverse) ? storage->persinv : storage->persmat); + copy_m4_m4(mat, (inverse) ? storage->persinv.values : storage->persmat.values); } /** \} */ @@ -2257,19 +2445,19 @@ void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse) DRWPass *DRW_pass_create(const char *name, DRWState state) { - DRWPass *pass = BLI_memblock_alloc(DST.vmempool->passes); + DRWPass *pass = static_cast<DRWPass *>(BLI_memblock_alloc(DST.vmempool->passes)); pass->state = state | DRW_STATE_PROGRAM_POINT_SIZE; if (G.debug & G_DEBUG_GPU) { BLI_strncpy(pass->name, name, MAX_PASS_NAME); } - pass->shgroups.first = NULL; - pass->shgroups.last = NULL; + pass->shgroups.first = nullptr; + pass->shgroups.last = nullptr; pass->handle = DST.pass_handle; DRW_handle_increment(&DST.pass_handle); - pass->original = NULL; - pass->next = NULL; + pass->original = nullptr; + pass->next = nullptr; return pass; } @@ -2285,7 +2473,7 @@ DRWPass *DRW_pass_create_instance(const char *name, DRWPass *original, DRWState void DRW_pass_link(DRWPass *first, DRWPass *second) { BLI_assert(first != second); - BLI_assert(first->next == NULL); + BLI_assert(first->next == nullptr); first->next = second; } @@ -2344,7 +2532,7 @@ static int pass_shgroup_dist_sort(const void *a, const void *b) void DRW_pass_sort_shgroup_z(DRWPass *pass) { - const float(*viewinv)[4] = DST.view_active->storage.viewinv; + const float4x4 &viewinv = DST.view_active->storage.viewinv; if (!(pass->shgroups.first && pass->shgroups.first->next)) { /* Nothing to sort */ @@ -2370,7 +2558,8 @@ void DRW_pass_sort_shgroup_z(DRWPass *pass) * (see T76730 & D7729). */ // BLI_assert(handle != 0); - DRWObjectMatrix *obmats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle); + DRWObjectMatrix *obmats = static_cast<DRWObjectMatrix *>( + DRW_memblock_elem_from_handle(DST.vmempool->obmats, &handle)); /* Compute distance to camera. */ float tmp[3]; diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.cc index 8987a6e2b20..d41127c3641 100644 --- a/source/blender/draw/intern/draw_manager_text.c +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -38,7 +38,7 @@ #include "draw_manager_text.h" #include "intern/bmesh_polygon.h" -typedef struct ViewCachedString { +struct ViewCachedString { float vec[3]; union { uchar ub[4]; @@ -51,20 +51,20 @@ typedef struct ViewCachedString { /* str is allocated past the end */ char str[0]; -} ViewCachedString; +}; -typedef struct DRWTextStore { +struct DRWTextStore { BLI_memiter *cache_strings; -} DRWTextStore; +}; DRWTextStore *DRW_text_cache_create(void) { - DRWTextStore *dt = MEM_callocN(sizeof(*dt), __func__); + DRWTextStore *dt = MEM_cnew<DRWTextStore>(__func__); dt->cache_strings = BLI_memiter_create(1 << 14); /* 16kb */ return dt; } -void DRW_text_cache_destroy(struct DRWTextStore *dt) +void DRW_text_cache_destroy(DRWTextStore *dt) { BLI_memiter_destroy(dt->cache_strings); MEM_freeN(dt); @@ -90,7 +90,8 @@ void DRW_text_cache_add(DRWTextStore *dt, alloc_len = str_len + 1; } - vos = BLI_memiter_alloc(dt->cache_strings, sizeof(ViewCachedString) + alloc_len); + vos = static_cast<ViewCachedString *>( + BLI_memiter_alloc(dt->cache_strings, sizeof(ViewCachedString) + alloc_len)); copy_v3_v3(vos->vec, co); copy_v4_v4_uchar(vos->col.ub, col); @@ -128,7 +129,7 @@ static void drw_text_cache_draw_ex(DRWTextStore *dt, ARegion *region) BLF_size(font_id, style->widget.points * U.dpi_fac); BLI_memiter_iter_init(dt->cache_strings, &it); - while ((vos = BLI_memiter_iter_step(&it))) { + while ((vos = static_cast<ViewCachedString *>(BLI_memiter_iter_step(&it)))) { if (vos->sco[0] != IS_CLIPPED) { if (col_pack_prev != vos->col.pack) { BLF_color4ubv(font_id, vos->col.ub); @@ -136,7 +137,7 @@ static void drw_text_cache_draw_ex(DRWTextStore *dt, ARegion *region) } BLF_position( - font_id, (float)(vos->sco[0] + vos->xoffs), (float)(vos->sco[1] + vos->yoffs), 2.0f); + font_id, float(vos->sco[0] + vos->xoffs), float(vos->sco[1] + vos->yoffs), 2.0f); BLF_draw(font_id, (vos->flag & DRW_TEXT_CACHE_STRING_PTR) ? *((const char **)vos->str) : vos->str, vos->str_len); @@ -147,16 +148,16 @@ static void drw_text_cache_draw_ex(DRWTextStore *dt, ARegion *region) GPU_matrix_projection_set(original_proj); } -void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d) +void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, View3D *v3d) { ViewCachedString *vos; if (v3d) { - RegionView3D *rv3d = region->regiondata; + RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); int tot = 0; /* project first and test */ BLI_memiter_handle it; BLI_memiter_iter_init(dt->cache_strings, &it); - while ((vos = BLI_memiter_iter_step(&it))) { + while ((vos = static_cast<ViewCachedString *>(BLI_memiter_iter_step(&it)))) { if (ED_view3d_project_short_ex( region, (vos->flag & DRW_TEXT_CACHE_GLOBALSPACE) ? rv3d->persmat : rv3d->persmatob, @@ -192,10 +193,10 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *region, struct View3D *v3d) BLI_memiter_iter_init(dt->cache_strings, &it); View2D *v2d = ®ion->v2d; float viewmat[4][4]; - rctf region_space = {0.0f, region->winx, 0.0f, region->winy}; + rctf region_space = {0.0f, float(region->winx), 0.0f, float(region->winy)}; BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, ®ion_space, viewmat); - while ((vos = BLI_memiter_iter_step(&it))) { + while ((vos = static_cast<ViewCachedString *>(BLI_memiter_iter_step(&it)))) { float p[3]; copy_v3_v3(p, vos->vec); mul_m4_v3(viewmat, p); @@ -216,9 +217,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, /* Do not use ascii when using non-default unit system, some unit chars are utf8 (micro, square, * etc.). See bug T36090. */ - struct DRWTextStore *dt = DRW_text_cache_ensure(); + DRWTextStore *dt = DRW_text_cache_ensure(); const short txt_flag = DRW_TEXT_CACHE_GLOBALSPACE; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); BMEditMesh *em = me->edit_mesh; float v1[3], v2[3], v3[3], vmid[3], fvec[3]; char numstr[32]; /* Stores the measurement display text here */ @@ -232,8 +233,9 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, float clip_planes[4][4]; /* allow for displaying shape keys and deform mods */ BMIter iter; - const float(*vert_coords)[3] = (me->runtime.edit_data ? me->runtime.edit_data->vertexCos : NULL); - const bool use_coords = (vert_coords != NULL); + const float(*vert_coords)[3] = (me->runtime.edit_data ? me->runtime.edit_data->vertexCos : + nullptr); + const bool use_coords = (vert_coords != nullptr); /* when 2 or more edge-info options are enabled, space apart */ short edge_tex_count = 0; @@ -246,7 +248,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) && (em->selectmode & SCE_SELECT_EDGE)) { edge_tex_count += 1; } - const short edge_tex_sep = (short)((edge_tex_count - 1) * 5.0f * U.dpi_fac); + const short edge_tex_sep = short((edge_tex_count - 1) * 5.0f * U.dpi_fac); /* Make the precision of the display value proportionate to the grid-size. */ @@ -334,7 +336,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGEANG, col); - const float(*poly_normals)[3] = NULL; + const float(*poly_normals)[3] = nullptr; if (use_coords) { BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); BKE_editmesh_cache_ensure_poly_normals(em, me->runtime.edit_data); @@ -410,7 +412,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col); int i, n; - BMFace *f = NULL; + BMFace *f = nullptr; /* Alternative to using `poly_to_tri_count(i, BM_elem_index_get(f->l_first))` * without having to add an extra loop. */ int looptri_index = 0; @@ -448,14 +450,14 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, area += area_tri_v3(v1, v2, v3); } - mul_v3_fl(vmid, 1.0f / (float)n); + mul_v3_fl(vmid, 1.0f / float(n)); mul_m4_v3(ob->obmat, vmid); if (unit->system) { numstr_len = BKE_unit_value_as_string( numstr, sizeof(numstr), - (double)(area * unit->scale_length * unit->scale_length), + double(area * unit->scale_length * unit->scale_length), 3, B_UNIT_AREA, unit, diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc new file mode 100644 index 00000000000..287270079e5 --- /dev/null +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -0,0 +1,1245 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2005 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + * + * PBVH drawing. + * Embeds GPU meshes inside of PBVH nodes, used by mesh sculpt mode. + */ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap.h" +#include "BLI_ghash.h" +#include "BLI_math_color.h" +#include "BLI_utildefines.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_attribute.h" +#include "BKE_ccg.h" +#include "BKE_customdata.h" +#include "BKE_mesh.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" +#include "BKE_subdiv_ccg.h" + +#include "GPU_batch.h" + +#include "DRW_engine.h" +#include "DRW_pbvh.h" + +#include "bmesh.h" +#include "draw_pbvh.h" +#include "gpu_private.h" + +#define MAX_PBVH_BATCH_KEY 512 +#define MAX_PBVH_VBOS 16 + +#include "BLI_index_range.hh" +#include "BLI_map.hh" +#include "BLI_math_vec_types.hh" +#include "BLI_vector.hh" +#include <vector> + +#include <algorithm> +#include <string> + +using blender::char3; +using blender::float2; +using blender::float3; +using blender::float4; +using blender::IndexRange; +using blender::Map; +using blender::short3; +using blender::uchar3; +using blender::ushort3; +using blender::ushort4; +using blender::Vector; + +using string = std::string; + +struct PBVHVbo { + uint64_t type; + eAttrDomain domain; + string name; + GPUVertBuf *vert_buf = nullptr; + string key; + + PBVHVbo(eAttrDomain _domain, uint64_t _type, string _name) + : type(_type), domain(_domain), name(_name) + { + } + + void clear_data() + { + GPU_vertbuf_clear(vert_buf); + } + + string build_key() + { + char buf[512]; + + sprintf(buf, "%d:%d:%s", int(type), int(domain), name.c_str()); + + key = string(buf); + return key; + } +}; + +struct PBVHBatch { + Vector<int> vbos; + string key; + GPUBatch *tris = nullptr, *lines = nullptr; + int tris_count = 0, lines_count = 0; + + void sort_vbos(Vector<PBVHVbo> &master_vbos) + { + struct cmp { + Vector<PBVHVbo> &master_vbos; + + cmp(Vector<PBVHVbo> &_master_vbos) : master_vbos(_master_vbos) + { + } + + bool operator()(const int &a, const int &b) + { + return master_vbos[a].key < master_vbos[b].key; + } + }; + + std::sort(vbos.begin(), vbos.end(), cmp(master_vbos)); + } + + string build_key(Vector<PBVHVbo> &master_vbos) + { + key = ""; + + sort_vbos(master_vbos); + + for (int vbo_i : vbos) { + key += master_vbos[vbo_i].key + ":"; + } + + return key; + } +}; + +static CustomData *get_cdata(eAttrDomain domain, PBVH_GPU_Args *args) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + return args->vdata; + case ATTR_DOMAIN_CORNER: + return args->ldata; + case ATTR_DOMAIN_FACE: + return args->pdata; + default: + return nullptr; + } +} + +struct PBVHBatches { + Vector<PBVHVbo> vbos; + Map<string, PBVHBatch> batches; + GPUIndexBuf *tri_index = nullptr; + GPUIndexBuf *lines_index = nullptr; + int faces_count = 0; /* Used by PBVH_BMESH and PBVH_GRIDS */ + int tris_count = 0, lines_count = 0; + bool needs_tri_index = false; + + int material_index = 0; + + int count_faces(PBVH_GPU_Args *args) + { + int count = 0; + + switch (args->pbvh_type) { + case PBVH_FACES: { + for (int i = 0; i < args->totprim; i++) { + int face_index = args->mlooptri[args->prim_indices[i]].poly; + + if (args->hide_poly && args->hide_poly[face_index]) { + continue; + } + + count++; + } + break; + } + case PBVH_GRIDS: { + count = BKE_pbvh_count_grid_quads((BLI_bitmap **)args->grid_hidden, + args->grid_indices, + args->totprim, + args->ccg_key.grid_size); + + break; + } + case PBVH_BMESH: { + GSET_FOREACH_BEGIN (BMFace *, f, args->bm_faces) { + if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + count++; + } + } + GSET_FOREACH_END(); + } + } + + return count; + } + + PBVHBatches(PBVH_GPU_Args *args) + { + faces_count = count_faces(args); + + if (args->pbvh_type == PBVH_BMESH) { + tris_count = faces_count; + } + } + + ~PBVHBatches() + { + for (PBVHBatch &batch : batches.values()) { + GPU_BATCH_DISCARD_SAFE(batch.tris); + GPU_BATCH_DISCARD_SAFE(batch.lines); + } + + for (PBVHVbo &vbo : vbos) { + GPU_vertbuf_discard(vbo.vert_buf); + } + + GPU_INDEXBUF_DISCARD_SAFE(tri_index); + GPU_INDEXBUF_DISCARD_SAFE(lines_index); + } + + string build_key(PBVHAttrReq *attrs, int attrs_num) + { + string key; + PBVHBatch batch; + Vector<PBVHVbo> vbos; + + for (int i : IndexRange(attrs_num)) { + PBVHAttrReq *attr = attrs + i; + + PBVHVbo vbo(attr->domain, attr->type, string(attr->name)); + vbo.build_key(); + + vbos.append(vbo); + batch.vbos.append(i); + } + + batch.build_key(vbos); + return batch.key; + } + + bool has_vbo(eAttrDomain domain, int type, string name) + { + for (PBVHVbo &vbo : vbos) { + if (vbo.domain == domain && vbo.type == type && vbo.name == name) { + return true; + } + } + + return false; + } + + int get_vbo_index(PBVHVbo *vbo) + { + for (int i : IndexRange(vbos.size())) { + if (vbo == &vbos[i]) { + return i; + } + } + + return -1; + } + + PBVHVbo *get_vbo(eAttrDomain domain, int type, string name) + { + for (PBVHVbo &vbo : vbos) { + if (vbo.domain == domain && vbo.type == type && vbo.name == name) { + return &vbo; + } + } + + return nullptr; + } + + bool has_batch(PBVHAttrReq *attrs, int attrs_num) + { + return batches.contains(build_key(attrs, attrs_num)); + } + + PBVHBatch &ensure_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args) + { + if (!has_batch(attrs, attrs_num)) { + create_batch(attrs, attrs_num, args); + } + + return batches.lookup(build_key(attrs, attrs_num)); + } + + void fill_vbo_normal_faces( + PBVHVbo & /*vbo*/, + PBVH_GPU_Args *args, + std::function<void(std::function<void(int, int, int, const MLoopTri *)> callback)> + foreach_faces, + GPUVertBufRaw *access) + { + float fno[3]; + short no[3]; + int last_poly = -1; + bool smooth = false; + + foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri *tri) { + const MPoly *mp = args->mpoly + tri->poly; + + if (tri->poly != last_poly) { + last_poly = tri->poly; + + if (!(mp->flag & ME_SMOOTH)) { + smooth = true; + BKE_mesh_calc_poly_normal(mp, args->mloop + mp->loopstart, args->mvert, fno); + normal_float_to_short_v3(no, fno); + } + else { + smooth = false; + } + } + + if (!smooth) { + normal_float_to_short_v3(no, args->vert_normals[vertex_i]); + } + + *static_cast<short3 *>(GPU_vertbuf_raw_step(access)) = no; + }); + } + + void fill_vbo_grids_intern( + PBVHVbo &vbo, + PBVH_GPU_Args *args, + std::function< + void(std::function<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func)> + foreach_grids) + { + uint vert_per_grid = square_i(args->ccg_key.grid_size - 1) * 4; + uint vert_count = args->totprim * vert_per_grid; + + int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf); + void *existing_data = GPU_vertbuf_get_data(vbo.vert_buf); + + if (existing_data == nullptr || existing_num != vert_count) { + /* Allocate buffer if not allocated yet or size changed. */ + GPU_vertbuf_data_alloc(vbo.vert_buf, vert_count); + } + + GPUVertBufRaw access; + GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access); + + switch (vbo.type) { + case CD_PROP_COLOR: + case CD_PROP_BYTE_COLOR: { + /* TODO: Implement color support for multires similar to the mesh cache + * extractor code. For now just upload white. + */ + const ushort4 white(USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX); + + foreach_grids( + [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { + *static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = white; + }); + break; + } + case CD_PBVH_CO_TYPE: + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *co = CCG_elem_co(&args->ccg_key, elems[i]); + + *static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = co; + }); + break; + + case CD_PBVH_NO_TYPE: + foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) { + float3 no(0.0f, 0.0f, 0.0f); + + const bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + + if (smooth) { + no = CCG_elem_no(&args->ccg_key, elems[0]); + } + else { + for (int j = 0; j < 4; j++) { + no += CCG_elem_no(&args->ccg_key, elems[j]); + } + } + + normalize_v3(no); + short sno[3]; + + normal_float_to_short_v3(sno, no); + + *static_cast<short3 *>(GPU_vertbuf_raw_step(&access)) = sno; + }); + break; + + case CD_PBVH_MASK_TYPE: + foreach_grids([&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem *elems[4], int i) { + float *mask = CCG_elem_mask(&args->ccg_key, elems[i]); + + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = mask ? uchar(*mask * 255.0f) : + 255; + }); + break; + + case CD_PBVH_FSET_TYPE: { + int *face_sets = args->face_sets; + + if (!face_sets) { + uchar white[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + + foreach_grids( + [&](int /*x*/, int /*y*/, int /*grid_index*/, CCGElem * /*elems*/[4], int /*i*/) { + *static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = white; + }); + } + else { + foreach_grids( + [&](int /*x*/, int /*y*/, int grid_index, CCGElem * /*elems*/[4], int /*i*/) { + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + + if (face_sets) { + const int face_index = BKE_subdiv_ccg_grid_to_face_index(args->subdiv_ccg, + grid_index); + const int fset = face_sets[face_index]; + + /* Skip for the default color Face Set to render it white. */ + if (fset != args->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + fset, args->face_sets_color_seed, face_set_color); + } + } + + *static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = face_set_color; + }); + } + break; + } + } + } + + void fill_vbo_grids(PBVHVbo &vbo, PBVH_GPU_Args *args) + { + int gridsize = args->ccg_key.grid_size; + + uint totgrid = args->totprim; + + auto foreach_solid = + [&](std::function<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) { + for (int i = 0; i < totgrid; i++) { + const int grid_index = args->grid_indices[i]; + + CCGElem *grid = args->grids[grid_index]; + + for (int y = 0; y < gridsize - 1; y++) { + for (int x = 0; x < gridsize - 1; x++) { + CCGElem *elems[4] = { + CCG_grid_elem(&args->ccg_key, grid, x, y), + CCG_grid_elem(&args->ccg_key, grid, x + 1, y), + CCG_grid_elem(&args->ccg_key, grid, x + 1, y + 1), + CCG_grid_elem(&args->ccg_key, grid, x, y + 1), + }; + + func(x, y, grid_index, elems, 0); + func(x + 1, y, grid_index, elems, 1); + func(x + 1, y + 1, grid_index, elems, 2); + func(x, y + 1, grid_index, elems, 3); + } + } + } + }; + + auto foreach_indexed = + [&](std::function<void(int x, int y, int grid_index, CCGElem *elems[4], int i)> func) { + for (int i = 0; i < totgrid; i++) { + const int grid_index = args->grid_indices[i]; + + CCGElem *grid = args->grids[grid_index]; + + for (int y = 0; y < gridsize; y++) { + for (int x = 0; x < gridsize; x++) { + CCGElem *elems[4] = { + CCG_grid_elem(&args->ccg_key, grid, x, y), + CCG_grid_elem(&args->ccg_key, grid, x + 1, y), + CCG_grid_elem(&args->ccg_key, grid, x + 1, y + 1), + CCG_grid_elem(&args->ccg_key, grid, x, y + 1), + }; + + func(x, y, grid_index, elems, 0); + } + } + } + }; + + if (needs_tri_index) { + fill_vbo_grids_intern(vbo, args, foreach_indexed); + } + else { + fill_vbo_grids_intern(vbo, args, foreach_solid); + } + } + + void fill_vbo_faces(PBVHVbo &vbo, PBVH_GPU_Args *args) + { + auto foreach_faces = + [&](std::function<void(int buffer_i, int tri_i, int vertex_i, const MLoopTri *tri)> func) { + int buffer_i = 0; + const MLoop *mloop = args->mloop; + + for (int i : IndexRange(args->totprim)) { + int face_index = args->mlooptri[args->prim_indices[i]].poly; + + if (args->hide_poly && args->hide_poly[face_index]) { + continue; + } + + const MLoopTri *tri = args->mlooptri + args->prim_indices[i]; + + for (int j : IndexRange(3)) { + func(buffer_i, j, mloop[tri->tri[j]].v, tri); + buffer_i++; + } + } + }; + + int totvert = 0; + foreach_faces([&totvert](int, int, int, const MLoopTri *) { totvert++; }); + + int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf); + void *existing_data = GPU_vertbuf_get_data(vbo.vert_buf); + + if (existing_data == nullptr || existing_num != totvert) { + /* Allocate buffer if not allocated yet or size changed. */ + GPU_vertbuf_data_alloc(vbo.vert_buf, totvert); + } + + GPUVertBufRaw access; + GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access); + + switch (vbo.type) { + case CD_PBVH_CO_TYPE: + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri * /*tri*/) { + *static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = args->mvert[vertex_i].co; + }); + break; + case CD_PBVH_NO_TYPE: + fill_vbo_normal_faces(vbo, args, foreach_faces, &access); + break; + case CD_PBVH_MASK_TYPE: { + float *mask = static_cast<float *>(CustomData_get_layer(args->vdata, CD_PAINT_MASK)); + + if (mask) { + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri * /*tri*/) { + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(mask[vertex_i] * + 255.0f); + }); + } + else { + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const MLoopTri * /*tri*/) { + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0; + }); + } + break; + } + case CD_PBVH_FSET_TYPE: { + int *face_sets = static_cast<int *>( + CustomData_get_layer_named(args->pdata, CD_PROP_INT32, ".sculpt_face_set")); + + if (face_sets) { + int last_poly = -1; + uchar fset_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const MLoopTri *tri) { + if (last_poly != tri->poly) { + last_poly = tri->poly; + + const int fset = face_sets[tri->poly]; + + if (fset != args->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + fset, args->face_sets_color_seed, fset_color); + } + else { + /* Skip for the default color face set to render it white. */ + fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX; + } + } + + *static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color; + }); + } + else { + uchar fset_color[4] = {255, 255, 255, 255}; + + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const MLoopTri * /*tri*/) { + *static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color; + }); + } + + break; + } + case CD_MLOOPUV: { + MLoopUV *mloopuv = static_cast<MLoopUV *>( + CustomData_get_layer_named(args->ldata, CD_MLOOPUV, vbo.name.c_str())); + + foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const MLoopTri *tri) { + *static_cast<float2 *>(GPU_vertbuf_raw_step(&access)) = mloopuv[tri->tri[tri_i]].uv; + }); + break; + } + case CD_PROP_COLOR: + if (vbo.domain == ATTR_DOMAIN_POINT) { + MPropCol *mpropcol = static_cast<MPropCol *>( + CustomData_get_layer_named(args->vdata, CD_PROP_COLOR, vbo.name.c_str())); + + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri * /*tri*/) { + ushort color[4]; + MPropCol *col = mpropcol + vertex_i; + + color[0] = unit_float_to_ushort_clamp(col->color[0]); + color[1] = unit_float_to_ushort_clamp(col->color[1]); + color[2] = unit_float_to_ushort_clamp(col->color[2]); + color[3] = unit_float_to_ushort_clamp(col->color[3]); + + *static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color; + }); + } + else if (vbo.domain == ATTR_DOMAIN_CORNER) { + MPropCol *mpropcol = static_cast<MPropCol *>( + CustomData_get_layer_named(args->ldata, CD_PROP_COLOR, vbo.name.c_str())); + + foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const MLoopTri *tri) { + ushort color[4]; + MPropCol *col = mpropcol + tri->tri[tri_i]; + + color[0] = unit_float_to_ushort_clamp(col->color[0]); + color[1] = unit_float_to_ushort_clamp(col->color[1]); + color[2] = unit_float_to_ushort_clamp(col->color[2]); + color[3] = unit_float_to_ushort_clamp(col->color[3]); + + *static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color; + }); + } + break; + case CD_PROP_BYTE_COLOR: + if (vbo.domain == ATTR_DOMAIN_POINT) { + MLoopCol *mbytecol = static_cast<MLoopCol *>( + CustomData_get_layer_named(args->vdata, CD_PROP_BYTE_COLOR, vbo.name.c_str())); + + foreach_faces( + [&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri * /*tri*/) { + ushort color[4]; + MLoopCol *col = mbytecol + vertex_i; + + color[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->r]); + color[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->g]); + color[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->b]); + color[3] = col->a * 257; + + *static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color; + }); + } + else if (vbo.domain == ATTR_DOMAIN_CORNER) { + MLoopCol *mbytecol = static_cast<MLoopCol *>( + CustomData_get_layer_named(args->ldata, CD_PROP_BYTE_COLOR, vbo.name.c_str())); + + foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const MLoopTri *tri) { + ushort color[4]; + MLoopCol *col = mbytecol + tri->tri[tri_i]; + + color[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->r]); + color[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->g]); + color[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->b]); + color[3] = col->a * 257; + + *static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color; + }); + } + break; + } + } + + void gpu_flush() + { + for (PBVHVbo &vbo : vbos) { + if (vbo.vert_buf && GPU_vertbuf_get_data(vbo.vert_buf)) { + GPU_vertbuf_use(vbo.vert_buf); + } + } + } + + void update(PBVH_GPU_Args *args) + { + check_index_buffers(args); + + for (PBVHVbo &vbo : vbos) { + fill_vbo(vbo, args); + } + } + + void fill_vbo_bmesh(PBVHVbo &vbo, PBVH_GPU_Args *args) + { + auto foreach_bmesh = [&](std::function<void(BMLoop * l)> callback) { + GSET_FOREACH_BEGIN (BMFace *, f, args->bm_faces) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + continue; + } + + BMLoop *l = f->l_first; + do { + callback(l); + } while ((l = l->next) != f->l_first); + } + GSET_FOREACH_END(); + }; + + faces_count = 0; + GSET_FOREACH_BEGIN (BMFace *, f, args->bm_faces) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + continue; + } + + BMLoop *l = f->l_first; + do { + faces_count++; + } while ((l = l->next) != f->l_first); + } + GSET_FOREACH_END(); + tris_count = faces_count; + + int existing_num = GPU_vertbuf_get_vertex_len(vbo.vert_buf); + void *existing_data = GPU_vertbuf_get_data(vbo.vert_buf); + + int vert_count = tris_count * 3; + + if (existing_data == nullptr || existing_num != vert_count) { + /* Allocate buffer if not allocated yet or size changed. */ + GPU_vertbuf_data_alloc(vbo.vert_buf, vert_count); + } + + GPUVertBufRaw access; + GPU_vertbuf_attr_get_raw_data(vbo.vert_buf, 0, &access); + + switch (vbo.type) { + case CD_PBVH_CO_TYPE: + foreach_bmesh( + [&](BMLoop *l) { *static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = l->v->co; }); + break; + + case CD_PBVH_NO_TYPE: + foreach_bmesh([&](BMLoop *l) { + short no[3]; + bool smooth = BM_elem_flag_test(l->f, BM_ELEM_SMOOTH); + + normal_float_to_short_v3(no, smooth ? l->v->no : l->f->no); + *static_cast<short3 *>(GPU_vertbuf_raw_step(&access)) = no; + }); + break; + + case CD_PBVH_MASK_TYPE: { + int cd_mask = args->cd_mask_layer; + + if (cd_mask == -1) { + foreach_bmesh( + [&](BMLoop * /*l*/) { *static_cast<float *>(GPU_vertbuf_raw_step(&access)) = 0; }); + } + else { + foreach_bmesh([&](BMLoop *l) { + float mask = BM_ELEM_CD_GET_FLOAT(l->v, cd_mask); + + *static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(mask * 255.0f); + }); + } + break; + } + case CD_PBVH_FSET_TYPE: { + uchar3 white(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX); + + foreach_bmesh([&](BMLoop * /*l*/) { + *static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = white; + }); + } + } + } + + void fill_vbo(PBVHVbo &vbo, PBVH_GPU_Args *args) + { + switch (args->pbvh_type) { + case PBVH_FACES: + fill_vbo_faces(vbo, args); + break; + case PBVH_GRIDS: + fill_vbo_grids(vbo, args); + break; + case PBVH_BMESH: + fill_vbo_bmesh(vbo, args); + break; + } + } + + void create_vbo(eAttrDomain domain, const uint32_t type, string name, PBVH_GPU_Args *args) + { + PBVHVbo vbo(domain, type, name); + GPUVertFormat format; + + bool need_aliases = !ELEM( + type, CD_PBVH_CO_TYPE, CD_PBVH_NO_TYPE, CD_PBVH_FSET_TYPE, CD_PBVH_MASK_TYPE); + + GPU_vertformat_clear(&format); + + switch (type) { + case CD_PBVH_CO_TYPE: + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + break; + case CD_PROP_FLOAT3: + GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + need_aliases = true; + break; + case CD_PBVH_NO_TYPE: + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + break; + case CD_PROP_FLOAT2: + GPU_vertformat_attr_add(&format, "a", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + need_aliases = true; + break; + case CD_MLOOPUV: + GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + need_aliases = true; + break; + case CD_PBVH_FSET_TYPE: + GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); + break; + case CD_PBVH_MASK_TYPE: + GPU_vertformat_attr_add(&format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + break; + case CD_PROP_FLOAT: + GPU_vertformat_attr_add(&format, "f", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + need_aliases = true; + break; + case CD_PROP_COLOR: + case CD_PROP_BYTE_COLOR: { + GPU_vertformat_attr_add(&format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + need_aliases = true; + break; + } + default: + BLI_assert(0); + printf("%s: error\n", __func__); + + break; + } + + if (need_aliases) { + CustomData *cdata = get_cdata(domain, args); + int layer_i = cdata ? CustomData_get_named_layer_index(cdata, type, name.c_str()) : -1; + CustomDataLayer *layer = layer_i != -1 ? cdata->layers + layer_i : nullptr; + + if (layer) { + bool is_render, is_active; + const char *prefix = "a"; + + if (ELEM(type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) { + prefix = "c"; + + CustomDataLayer *render = BKE_id_attributes_render_color_get(&args->me->id); + CustomDataLayer *active = BKE_id_attributes_active_color_get(&args->me->id); + + is_render = render && layer && STREQ(render->name, layer->name); + is_active = active && layer && STREQ(active->name, layer->name); + } + else { + switch (type) { + case CD_MLOOPUV: + prefix = "u"; + break; + default: + break; + } + + const char *active_name = CustomData_get_active_layer_name(cdata, type); + const char *render_name = CustomData_get_render_layer_name(cdata, type); + + is_active = active_name && STREQ(layer->name, active_name); + is_render = render_name && STREQ(layer->name, render_name); + } + + DRW_cdlayer_attr_aliases_add(&format, prefix, cdata, layer, is_render, is_active); + } + else { + printf("%s: error looking up attribute %s\n", __func__, name.c_str()); + } + } + + vbo.vert_buf = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STATIC); + vbo.build_key(); + fill_vbo(vbo, args); + + vbos.append(vbo); + } + + void update_pre(PBVH_GPU_Args *args) + { + if (args->pbvh_type == PBVH_BMESH) { + int count = count_faces(args); + + if (faces_count != count) { + for (PBVHVbo &vbo : vbos) { + vbo.clear_data(); + } + + GPU_INDEXBUF_DISCARD_SAFE(tri_index); + GPU_INDEXBUF_DISCARD_SAFE(lines_index); + + tri_index = lines_index = nullptr; + faces_count = tris_count = count; + } + } + } + + void create_index_faces(PBVH_GPU_Args *args) + { + /* Calculate number of edges*/ + int edge_count = 0; + for (int i = 0; i < args->totprim; i++) { + const MLoopTri *lt = args->mlooptri + args->prim_indices[i]; + + if (args->hide_poly && args->hide_poly[lt->poly]) { + continue; + } + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges); + + if (r_edges[0] != -1) { + edge_count++; + } + if (r_edges[1] != -1) { + edge_count++; + } + if (r_edges[2] != -1) { + edge_count++; + } + } + + GPUIndexBufBuilder elb_lines; + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, edge_count * 2, INT_MAX); + + int vertex_i = 0; + for (int i = 0; i < args->totprim; i++) { + const MLoopTri *lt = args->mlooptri + args->prim_indices[i]; + + if (args->hide_poly && args->hide_poly[lt->poly]) { + continue; + } + + int r_edges[3]; + BKE_mesh_looptri_get_real_edges(args->me, lt, r_edges); + + if (r_edges[0] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vertex_i, vertex_i + 1); + } + if (r_edges[1] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 1, vertex_i + 2); + } + if (r_edges[2] != -1) { + GPU_indexbuf_add_line_verts(&elb_lines, vertex_i + 2, vertex_i); + } + + vertex_i += 3; + } + + lines_index = GPU_indexbuf_build(&elb_lines); + } + + void create_index_bmesh(PBVH_GPU_Args *args) + { + GPUIndexBufBuilder elb_lines; + GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tris_count * 3 * 2, INT_MAX); + + int v_index = 0; + lines_count = 0; + + GSET_FOREACH_BEGIN (BMFace *, f, args->bm_faces) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + continue; + } + + GPU_indexbuf_add_line_verts(&elb_lines, v_index, v_index + 1); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); + GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index); + + lines_count += 3; + v_index += 3; + } + GSET_FOREACH_END(); + + lines_index = GPU_indexbuf_build(&elb_lines); + } + + void create_index_grids(PBVH_GPU_Args *args) + { + needs_tri_index = true; + int gridsize = args->ccg_key.grid_size; + int totgrid = args->totprim; + + for (int i : IndexRange(args->totprim)) { + int grid_index = args->grid_indices[i]; + bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + BLI_bitmap *gh = args->grid_hidden[grid_index]; + + for (int y = 0; y < gridsize - 1; y++) { + for (int x = 0; x < gridsize - 1; x++) { + if (gh && paint_is_grid_face_hidden(gh, gridsize, x, y)) { + /* Skip hidden faces by just setting smooth to true. */ + smooth = true; + goto outer_loop_break; + } + } + } + + outer_loop_break: + + if (!smooth) { + needs_tri_index = false; + break; + } + } + + GPUIndexBufBuilder elb, elb_lines; + + CCGKey *key = &args->ccg_key; + + uint visible_quad_len = BKE_pbvh_count_grid_quads( + (BLI_bitmap **)args->grid_hidden, args->grid_indices, totgrid, key->grid_size); + + GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX); + GPU_indexbuf_init( + &elb_lines, GPU_PRIM_LINES, 2 * totgrid * gridsize * (gridsize - 1), INT_MAX); + + if (needs_tri_index) { + uint offset = 0; + const uint grid_vert_len = gridsize * gridsize; + for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { + uint v0, v1, v2, v3; + bool grid_visible = false; + + BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]]; + + for (int j = 0; j < gridsize - 1; j++) { + for (int k = 0; k < gridsize - 1; k++) { + /* Skip hidden grid face */ + if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) { + continue; + } + /* Indices in a Clockwise QUAD disposition. */ + v0 = offset + j * gridsize + k; + v1 = v0 + 1; + v2 = v1 + gridsize; + v3 = v2 - 1; + + GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1); + GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2); + + GPU_indexbuf_add_line_verts(&elb_lines, v0, v1); + GPU_indexbuf_add_line_verts(&elb_lines, v0, v3); + + if (j + 2 == gridsize) { + GPU_indexbuf_add_line_verts(&elb_lines, v2, v3); + } + grid_visible = true; + } + + if (grid_visible) { + GPU_indexbuf_add_line_verts(&elb_lines, v1, v2); + } + } + } + } + else { + uint offset = 0; + const uint grid_vert_len = square_uint(gridsize - 1) * 4; + for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { + bool grid_visible = false; + BLI_bitmap *gh = args->grid_hidden[args->grid_indices[i]]; + + uint v0, v1, v2, v3; + for (int j = 0; j < gridsize - 1; j++) { + for (int k = 0; k < gridsize - 1; k++) { + /* Skip hidden grid face */ + if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) { + continue; + } + /* VBO data are in a Clockwise QUAD disposition. */ + v0 = offset + (j * (gridsize - 1) + k) * 4; + v1 = v0 + 1; + v2 = v0 + 2; + v3 = v0 + 3; + + GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1); + GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2); + + GPU_indexbuf_add_line_verts(&elb_lines, v0, v1); + GPU_indexbuf_add_line_verts(&elb_lines, v0, v3); + + if (j + 2 == gridsize) { + GPU_indexbuf_add_line_verts(&elb_lines, v2, v3); + } + grid_visible = true; + } + + if (grid_visible) { + GPU_indexbuf_add_line_verts(&elb_lines, v1, v2); + } + } + } + } + + tri_index = GPU_indexbuf_build(&elb); + lines_index = GPU_indexbuf_build(&elb_lines); + } + + void create_index(PBVH_GPU_Args *args) + { + switch (args->pbvh_type) { + case PBVH_FACES: + create_index_faces(args); + break; + case PBVH_BMESH: + create_index_bmesh(args); + break; + case PBVH_GRIDS: + create_index_grids(args); + break; + } + + for (PBVHBatch &batch : batches.values()) { + GPU_batch_elembuf_set(batch.tris, tri_index, false); + GPU_batch_elembuf_set(batch.lines, lines_index, false); + } + } + + void check_index_buffers(PBVH_GPU_Args *args) + { + if (!lines_index) { + create_index(args); + } + } + + void create_batch(PBVHAttrReq *attrs, int attrs_num, PBVH_GPU_Args *args) + { + check_index_buffers(args); + + PBVHBatch batch; + + batch.tris = GPU_batch_create(GPU_PRIM_TRIS, + nullptr, + /* can be nullptr if buffer is empty */ + tri_index); + batch.tris_count = tris_count; + + if (lines_index) { + batch.lines = GPU_batch_create(GPU_PRIM_LINES, nullptr, lines_index); + batch.lines_count = lines_count; + } + + for (int i : IndexRange(attrs_num)) { + PBVHAttrReq *attr = attrs + i; + + if (!has_vbo(attr->domain, int(attr->type), attr->name)) { + create_vbo(attr->domain, uint32_t(attr->type), attr->name, args); + } + + PBVHVbo *vbo = get_vbo(attr->domain, uint32_t(attr->type), attr->name); + int vbo_i = get_vbo_index(vbo); + + batch.vbos.append(vbo_i); + GPU_batch_vertbuf_add_ex(batch.tris, vbo->vert_buf, false); + + if (batch.lines) { + GPU_batch_vertbuf_add_ex(batch.lines, vbo->vert_buf, false); + } + } + + batch.build_key(vbos); + batches.add(batch.key, batch); + } +}; + +void DRW_pbvh_node_update(PBVHBatches *batches, PBVH_GPU_Args *args) +{ + batches->update(args); +} + +void DRW_pbvh_node_gpu_flush(PBVHBatches *batches) +{ + batches->gpu_flush(); +} + +PBVHBatches *DRW_pbvh_node_create(PBVH_GPU_Args *args) +{ + PBVHBatches *batches = new PBVHBatches(args); + return batches; +} + +void DRW_pbvh_node_free(PBVHBatches *batches) +{ + delete batches; +} + +GPUBatch *DRW_pbvh_tris_get(PBVHBatches *batches, + PBVHAttrReq *attrs, + int attrs_num, + PBVH_GPU_Args *args, + int *r_prim_count) +{ + PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args); + + *r_prim_count = batch.tris_count; + + return batch.tris; +} + +GPUBatch *DRW_pbvh_lines_get(PBVHBatches *batches, + PBVHAttrReq *attrs, + int attrs_num, + PBVH_GPU_Args *args, + int *r_prim_count) +{ + PBVHBatch &batch = batches->ensure_batch(attrs, attrs_num, args); + + *r_prim_count = batch.lines_count; + + return batch.lines; +} + +void DRW_pbvh_update_pre(struct PBVHBatches *batches, struct PBVH_GPU_Args *args) +{ + batches->update_pre(args); +} + +int drw_pbvh_material_index_get(struct PBVHBatches *batches) +{ + return batches->material_index; +} diff --git a/source/blender/draw/intern/draw_pbvh.h b/source/blender/draw/intern/draw_pbvh.h new file mode 100644 index 00000000000..9e3401d864f --- /dev/null +++ b/source/blender/draw/intern/draw_pbvh.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "DNA_customdata_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct PBVHBatches; + +enum { + CD_PBVH_CO_TYPE = CD_NUMTYPES, + CD_PBVH_NO_TYPE = CD_NUMTYPES + 1, + CD_PBVH_FSET_TYPE = CD_NUMTYPES + 2, + CD_PBVH_MASK_TYPE = CD_NUMTYPES + 3 +}; + +int drw_pbvh_material_index_get(struct PBVHBatches *batches); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_resource.cc b/source/blender/draw/intern/draw_resource.cc index 689df4edb31..f57058190fb 100644 --- a/source/blender/draw/intern/draw_resource.cc +++ b/source/blender/draw/intern/draw_resource.cc @@ -19,58 +19,6 @@ * \{ */ /** - * Extract object attribute from RNA property. - * Returns true if the attribute was correctly extracted. - * This function mirrors lookup_property in cycles/blender/blender_object.cpp - */ -bool ObjectAttribute::id_property_lookup(ID *id, const char *name) -{ - PointerRNA ptr, id_ptr; - PropertyRNA *prop; - - if (id == nullptr) { - return false; - } - - RNA_id_pointer_create(id, &id_ptr); - - if (!RNA_path_resolve(&id_ptr, name, &ptr, &prop)) { - return false; - } - - if (prop == nullptr) { - return false; - } - - PropertyType type = RNA_property_type(prop); - int array_len = RNA_property_array_length(&ptr, prop); - - if (array_len == 0) { - float value; - - if (type == PROP_FLOAT) { - value = RNA_property_float_get(&ptr, prop); - } - else if (type == PROP_INT) { - value = RNA_property_int_get(&ptr, prop); - } - else { - return false; - } - - *reinterpret_cast<float4 *>(&data_x) = float4(value, value, value, 1.0f); - return true; - } - - if (type == PROP_FLOAT && array_len <= 4) { - *reinterpret_cast<float4 *>(&data_x) = float4(0.0f, 0.0f, 0.0f, 1.0f); - RNA_property_float_get_array(&ptr, prop, &data_x); - return true; - } - return false; -} - -/** * Go through all possible source of the given object uniform attribute. * Returns true if the attribute was correctly filled. * This function mirrors lookup_instance_property in cycles/blender/blender_object.cpp @@ -81,29 +29,12 @@ bool ObjectAttribute::sync(const blender::draw::ObjectRef &ref, const GPUUniform /* If requesting instance data, check the parent particle system and object. */ if (attr.use_dupli) { - if ((ref.dupli_object != nullptr) && (ref.dupli_object->particle_system != nullptr)) { - ParticleSettings *settings = ref.dupli_object->particle_system->part; - if (this->id_property_lookup((ID *)settings, attr.name_id_prop) || - this->id_property_lookup((ID *)settings, attr.name)) { - return true; - } - } - if (this->id_property_lookup((ID *)ref.dupli_parent, attr.name_id_prop) || - this->id_property_lookup((ID *)ref.dupli_parent, attr.name)) { - return true; - } + return BKE_object_dupli_find_rgba_attribute( + ref.object, ref.dupli_object, ref.dupli_parent, attr.name, &data_x); } - - /* Check the object and mesh. */ - if (ref.object != nullptr) { - if (this->id_property_lookup((ID *)ref.object, attr.name_id_prop) || - this->id_property_lookup((ID *)ref.object, attr.name) || - this->id_property_lookup((ID *)ref.object->data, attr.name_id_prop) || - this->id_property_lookup((ID *)ref.object->data, attr.name)) { - return true; - } + else { + return BKE_object_dupli_find_rgba_attribute(ref.object, nullptr, nullptr, attr.name, &data_x); } - return false; } /** \} */ diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index bedbedcf438..a572b9ee865 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -205,7 +205,6 @@ struct ObjectAttribute { #if !defined(GPU_SHADER) && defined(__cplusplus) bool sync(const blender::draw::ObjectRef &ref, const GPUUniformAttr &attr); - bool id_property_lookup(ID *id, const char *name); #endif }; #pragma pack(pop) diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index c85ec2acae1..b0faa7b81b5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -439,3 +439,4 @@ extern const MeshExtract extract_edge_idx; extern const MeshExtract extract_vert_idx; extern const MeshExtract extract_fdot_idx; extern const MeshExtract extract_attr[GPU_MAX_ATTR]; +extern const MeshExtract extract_attr_viewer; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 240e9b4fa60..c602b768df9 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -14,6 +14,8 @@ #include "BLI_string.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" +#include "BKE_mesh.h" #include "draw_attributes.h" #include "draw_subdivision.h" @@ -432,6 +434,40 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF return extractor; } +static void extract_mesh_attr_viewer_init(const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "attribute_value", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, mr->loop_len); + MutableSpan<ColorGeometry4f> attr{static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(vbo)), + mr->loop_len}; + + const StringRefNull attr_name = ".viewer"; + const bke::AttributeAccessor attributes = mr->me->attributes(); + attributes + .lookup_or_default<ColorGeometry4f>(attr_name, ATTR_DOMAIN_CORNER, {1.0f, 0.0f, 1.0f, 1.0f}) + .materialize(attr); +} + +constexpr MeshExtract create_extractor_attr_viewer() +{ + MeshExtract extractor = {nullptr}; + extractor.init = extract_mesh_attr_viewer_init; + extractor.data_type = MR_DATA_NONE; + extractor.data_size = 0; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr_viewer); + return extractor; +} + /** \} */ } // namespace blender::draw @@ -457,3 +493,5 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = { CREATE_EXTRACTOR_ATTR(13), CREATE_EXTRACTOR_ATTR(14), }; + +const MeshExtract extract_attr_viewer = blender::draw::create_extractor_attr_viewer(); diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index dc631483857..f238c7e25b1 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -254,6 +254,7 @@ static void test_overlay_glsl_shaders() EXPECT_NE(OVERLAY_shader_motion_path_line(), nullptr); EXPECT_NE(OVERLAY_shader_motion_path_vert(), nullptr); EXPECT_NE(OVERLAY_shader_uniform_color(), nullptr); + EXPECT_NE(OVERLAY_shader_uniform_color_pointcloud(), nullptr); EXPECT_NE(OVERLAY_shader_outline_prepass(false), nullptr); EXPECT_NE(OVERLAY_shader_outline_prepass(true), nullptr); EXPECT_NE(OVERLAY_shader_outline_prepass_curves(), nullptr); @@ -272,6 +273,10 @@ static void test_overlay_glsl_shaders() EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr); EXPECT_NE(OVERLAY_shader_sculpt_mask(), nullptr); EXPECT_NE(OVERLAY_shader_sculpt_curves_selection(), nullptr); + EXPECT_NE(OVERLAY_shader_viewer_attribute_curve(), nullptr); + EXPECT_NE(OVERLAY_shader_viewer_attribute_curves(), nullptr); + EXPECT_NE(OVERLAY_shader_viewer_attribute_mesh(), nullptr); + EXPECT_NE(OVERLAY_shader_viewer_attribute_pointcloud(), nullptr); EXPECT_NE(OVERLAY_shader_volume_velocity(false, false), nullptr); EXPECT_NE(OVERLAY_shader_volume_velocity(false, true), nullptr); EXPECT_NE(OVERLAY_shader_volume_velocity(true, false), nullptr); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index ea631da27af..7402e1efa53 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -54,10 +54,9 @@ #include "WM_api.h" #include "WM_types.h" -/* ************************************************************************** */ -/* CHANNELS API - Exposed API */ - -/* -------------------------- Selection ------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Public Channel Selection API + * \{ */ void ANIM_set_active_channel(bAnimContext *ac, void *data, @@ -463,7 +462,11 @@ void ANIM_anim_channels_select_toggle(bAnimContext *ac) ANIM_animdata_freelist(&anim_data); } -/* ---------------------------- Graph Editor ------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public Graph Editor API + * \{ */ /* Copy a certain channel setting to parents of the modified channel. */ static void anim_flush_channel_setting_up(bAnimContext *ac, @@ -627,7 +630,11 @@ void ANIM_flush_setting_anim_channels(bAnimContext *ac, anim_flush_channel_setting_down(ac, setting, mode, match, matchLevel); } -/* -------------------------- F-Curves ------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Public F-Curves API + * \{ */ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu) { @@ -699,10 +706,11 @@ bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt) return false; } -/* ************************************************************************** */ -/* OPERATORS */ +/** \} */ -/* ****************** Operator Utilities ********************************** */ +/* -------------------------------------------------------------------- */ +/** \name Operator Utilities + * \{ */ /* poll callback for being in an Animation Editor channels list region */ static bool animedit_poll_channels_active(bContext *C) @@ -748,7 +756,11 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C) return true; } -/* ****************** Rearrange Channels Operator ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Move (Rearrange) Channels Operator + * \{ */ /* constants for channel rearranging */ /* WARNING: don't change existing ones without modifying rearrange func accordingly */ @@ -1581,7 +1593,11 @@ static void ANIM_OT_channels_move(wmOperatorType *ot) ""); } -/* ******************** Group Channel Operator ************************ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Group Channel Operator + * \{ */ static bool animchannels_grouping_poll(bContext *C) { @@ -1739,7 +1755,11 @@ static void ANIM_OT_channels_group(wmOperatorType *ot) // RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } -/* ----------------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Ungroup Channels Operator + * \{ */ static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1805,7 +1825,11 @@ static void ANIM_OT_channels_ungroup(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Delete Channel Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Channel Operator + * \{ */ static void tag_update_animation_element(bAnimListElem *ale) { @@ -1976,7 +2000,11 @@ static void ANIM_OT_channels_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************** Set Flags Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set/Toggle Channel Flags Operator Utilities + * \{ */ /* defines for setting animation-channel flags */ static const EnumPropertyItem prop_animchannel_setflag_types[] = { @@ -2223,7 +2251,11 @@ static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */ } -/* ********************** Expand Channels Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Expand Channels Operator + * \{ */ static int animchannels_expand_exec(bContext *C, wmOperator *op) { @@ -2268,7 +2300,11 @@ static void ANIM_OT_channels_expand(wmOperatorType *ot) ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)"); } -/* ********************** Collapse Channels Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Collapse Channels Operator + * \{ */ static int animchannels_collapse_exec(bContext *C, wmOperator *op) { @@ -2313,17 +2349,22 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot) ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)"); } -/* ************ Remove All "Empty" AnimData Blocks Operator ********* */ -/* We define "empty" AnimData blocks here as those which have all 3 of criteria: - * 1) No active action OR that active actions are empty - * Assuming that all legitimate entries will have an action, - * and that empty actions - * 2) No NLA Tracks + NLA Strips - * Assuming that users haven't set up any of these as "placeholders" - * for convenience sake, and that most that exist were either unintentional - * or are no longer wanted - * 3) No drivers - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Remove All "Empty" AnimData Blocks Operator + * + * We define "empty" AnimData blocks here as those which have all 3 of criteria: + * + * 1) No active action OR that active actions are empty + * Assuming that all legitimate entries will have an action, + * and that empty actions + * 2) No NLA Tracks + NLA Strips + * Assuming that users haven't set up any of these as "placeholders" + * for convenience sake, and that most that exist were either unintentional + * or are no longer wanted + * 3) No drivers + * \{ */ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2422,7 +2463,11 @@ static void ANIM_OT_channels_clean_empty(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Reenable Disabled Operator ******************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Re-enable Disabled Operator + * \{ */ static bool animchannels_enable_poll(bContext *C) { @@ -2499,7 +2544,11 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ****************** Select Filter Textbox Operator ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Filter Text-box Operator + * \{ */ /* XXX: make this generic? */ static bool animchannels_select_filter_poll(bContext *C) @@ -2572,7 +2621,11 @@ static void ANIM_OT_channels_select_filter(wmOperatorType *ot) ot->poll = animchannels_select_filter_poll; } -/* ********************** Select All Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select All Operator + * \{ */ static int animchannels_selectall_exec(bContext *C, wmOperator *op) { @@ -2627,7 +2680,11 @@ static void ANIM_OT_channels_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ******************** Box Select Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * \{ */ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectmode) { @@ -2705,8 +2762,6 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm ANIM_animdata_freelist(&anim_data); } -/* ------------------- */ - static int animchannels_box_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -2765,8 +2820,13 @@ static void ANIM_OT_channels_select_box(wmOperatorType *ot) WM_operator_properties_gesture_box_select(ot); } -/* ******************* Rename Operator ***************************** */ -/* Allow renaming some channels by clicking on them */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Rename Channel Operator + * + * Allow renaming some channels by clicking on them. + * \{ */ static bool rename_anim_channels(bAnimContext *ac, int channel_index) { @@ -2923,7 +2983,12 @@ static void ANIM_OT_channels_rename(wmOperatorType *ot) ot->poll = animedit_poll_channels_active; } -/* ******************** Mouse-Click Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Channel Keyframes Operator (Internal Logic) + * \{ */ + /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */ static int click_select_channel_scene(bAnimListElem *ale, @@ -3366,9 +3431,13 @@ static int mouse_anim_channels(bContext *C, return notifierFlags; } -/* ------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Channel Keyframes Operator + * \{ */ -/* handle clicking */ +/** Handle picking logic. */ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { bAnimContext ac; @@ -3554,8 +3623,11 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************************************************************** */ -/* Operator Registration */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Registration + * \{ */ void ED_operatortypes_animchannels(void) { @@ -3596,4 +3668,4 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf) WM_keymap_ensure(keyconf, "Animation Channels", 0, 0); } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index 98be58fbddc..facddc047c5 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -997,6 +997,7 @@ static int surface_set_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&curves_ob.id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id); + WM_event_add_notifier(C, NC_NODE | NA_ADDED, NULL); /* Required for deformation. */ new_surface_ob.modifier_flag |= OB_MODIFIER_FLAG_ADD_REST_POSITION; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3aa83262505..9d101490283 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2914,7 +2914,7 @@ static int gpencil_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) /* return data */ copy_v3_v3(&pt->x, fpt); - gpencil_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_world_to_object_space_point(depsgraph, obact, gpl, pt); changed = true; } @@ -3015,7 +3015,7 @@ static int gpencil_snap_to_cursor(bContext *C, wmOperator *op) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { copy_v3_v3(&pt->x, cursor_global); - gpencil_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_world_to_object_space_point(depsgraph, obact, gpl, pt); changed = true; } @@ -5460,7 +5460,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps, const struct GP_SelectLassoUserData *data = user_data; bGPDspoint pt2; int x0, y0; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 79ce68f5aa1..03d4df61e14 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -87,6 +87,8 @@ typedef struct tStroke { bGPDframe *gpf; /** Referenced stroke. */ bGPDstroke *gps; + /** Array of 2D points */ + float (*points2d)[2]; /** Extreme Stroke A. */ bGPDstroke *gps_ext_a; /** Extreme Stroke B. */ @@ -199,6 +201,7 @@ typedef struct tGPDfill { bool skip_layer_check(short fill_layer_mode, int gpl_active_index, int gpl_index); static void gpencil_draw_boundary_lines(const struct bContext *UNUSED(C), struct tGPDfill *tgpf); +static void gpencil_fill_status_indicators(struct tGPDfill *tgpf); /* Free temp stroke array. */ static void stroke_array_free(tGPDfill *tgpf) @@ -206,6 +209,7 @@ static void stroke_array_free(tGPDfill *tgpf) if (tgpf->stroke_array) { for (int i = 0; i < tgpf->stroke_array_num; i++) { tStroke *stroke = tgpf->stroke_array[i]; + MEM_SAFE_FREE(stroke->points2d); MEM_freeN(stroke); } MEM_SAFE_FREE(tgpf->stroke_array); @@ -392,6 +396,9 @@ static void gpencil_load_array_strokes(tGPDfill *tgpf) continue; } + float diff_mat[4][4]; + BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, tgpf->ob, gpl, diff_mat); + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* Check if stroke can be drawn. */ if ((gps->points == NULL) || (gps->totpoints < 2)) { @@ -407,13 +414,26 @@ static void gpencil_load_array_strokes(tGPDfill *tgpf) continue; } - tStroke *stroke = MEM_callocN(sizeof(tStroke), "temp stroke data"); + tStroke *stroke = MEM_callocN(sizeof(tStroke), __func__); stroke->gpl = gpl; stroke->gpf = gpf; stroke->gps = gps; /* Create the extension strokes only for Lines. */ if (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND) { + /* Convert all points to 2D to speed up collision checks and avoid convert in each + * iteration. */ + stroke->points2d = (float(*)[2])MEM_mallocN(sizeof(*stroke->points2d) * gps->totpoints, + "GP Stroke temp 2d points"); + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + bGPDspoint pt2; + gpencil_point_to_world_space(pt, diff_mat, &pt2); + gpencil_point_to_xy_fl( + &tgpf->gsc, gps, &pt2, &stroke->points2d[i][0], &stroke->points2d[i][1]); + } + /* Extend start. */ bGPDspoint *pt1 = &gps->points[0]; stroke->gps_ext_a = BKE_gpencil_stroke_new(gps->mat_nr, 2, gps->thickness); @@ -469,12 +489,64 @@ static void set_stroke_collide(bGPDstroke *gps_a, bGPDstroke *gps_b, const float * temp strokes without adding new variables to the bGPStroke struct. */ gps_a->fill_opacity_fac = connection_dist; gps_b->fill_opacity_fac = connection_dist; + BKE_gpencil_stroke_boundingbox_calc(gps_a); + BKE_gpencil_stroke_boundingbox_calc(gps_b); +} + +static void gpencil_stroke_collision( + tGPDfill *tgpf, bGPDlayer *gpl, bGPDstroke *gps_a, float a1xy[2], float a2xy[2]) +{ + const float connection_dist = tgpf->fill_extend_fac * 0.1f; + float diff_mat[4][4], inv_mat[4][4]; + + /* Transform matrix for original stroke.*/ + BKE_gpencil_layer_transform_matrix_get(tgpf->depsgraph, tgpf->ob, gpl, diff_mat); + invert_m4_m4(inv_mat, diff_mat); + + for (int idx = 0; idx < tgpf->stroke_array_num; idx++) { + tStroke *stroke = tgpf->stroke_array[idx]; + bGPDstroke *gps_b = stroke->gps; + + if (!extended_bbox_overlap(gps_a->boundbox_min, + gps_a->boundbox_max, + gps_b->boundbox_min, + gps_b->boundbox_max, + 1.1f)) { + continue; + } + + /* Loop all segments of the stroke. */ + for (int i = 0; i < gps_b->totpoints - 1; i++) { + /* Skip segments over same pixel. */ + if (((int)a1xy[0] == (int)stroke->points2d[i + 1][0]) && + ((int)a1xy[1] == (int)stroke->points2d[i + 1][1])) { + continue; + } + + /* Check if extensions cross. */ + if (isect_seg_seg_v2_simple(a1xy, a2xy, stroke->points2d[i], stroke->points2d[i + 1])) { + bGPDspoint *extreme_a = &gps_a->points[1]; + float intersection2D[2]; + isect_line_line_v2_point( + a1xy, a2xy, stroke->points2d[i], stroke->points2d[i + 1], intersection2D); + + gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, intersection2D, &extreme_a->x); + mul_m4_v3(inv_mat, &extreme_a->x); + BKE_gpencil_stroke_boundingbox_calc(gps_a); + + gps_a->flag |= GP_STROKE_COLLIDE; + gps_a->fill_opacity_fac = connection_dist; + return; + } + } + } } /* Cut the extended lines if collide. */ static void gpencil_cut_extensions(tGPDfill *tgpf) { const float connection_dist = tgpf->fill_extend_fac * 0.1f; + const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0; bGPDlayer *gpl_prev = NULL; bGPDframe *gpf_prev = NULL; @@ -525,11 +597,11 @@ static void gpencil_cut_extensions(tGPDfill *tgpf) /* First stroke. */ bGPDspoint *pt = &gps_a->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(&tgpf->gsc, gps_a, &pt2, &a1xy[0], &a1xy[1]); pt = &gps_a->points[1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(&tgpf->gsc, gps_a, &pt2, &a2xy[0], &a2xy[1]); bGPDspoint *extreme_a = &gps_a->points[1]; @@ -547,16 +619,16 @@ static void gpencil_cut_extensions(tGPDfill *tgpf) gps_a->boundbox_max, gps_b->boundbox_min, gps_b->boundbox_max, - connection_dist)) { + 1.1f)) { continue; } pt = &gps_b->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(&tgpf->gsc, gps_b, &pt2, &b1xy[0], &b1xy[1]); pt = &gps_b->points[1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(&tgpf->gsc, gps_b, &pt2, &b2xy[0], &b2xy[1]); bGPDspoint *extreme_b = &gps_b->points[1]; @@ -574,9 +646,10 @@ static void gpencil_cut_extensions(tGPDfill *tgpf) } /* Check if extensions cross. */ if (isect_seg_seg_v2_simple(a1xy, a2xy, b1xy, b2xy)) { - float intersection[2]; - isect_line_line_v2_point(a1xy, a2xy, b1xy, b2xy, intersection); - gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, intersection, intersection3D); + float intersection2D[2]; + isect_line_line_v2_point(a1xy, a2xy, b1xy, b2xy, intersection2D); + + gpencil_point_xy_to_3d(&tgpf->gsc, tgpf->scene, intersection2D, intersection3D); mul_m4_v3(inv_mat, intersection3D); copy_v3_v3(&extreme_a->x, intersection3D); copy_v3_v3(&extreme_b->x, intersection3D); @@ -597,6 +670,11 @@ static void gpencil_cut_extensions(tGPDfill *tgpf) break; } } + + /* Check if collide with normal strokes. */ + if (use_stroke_collide && (gps_a->flag & GP_STROKE_COLLIDE) == 0) { + gpencil_stroke_collision(tgpf, stroke->gpl, gps_a, a1xy, a2xy); + } } } MEM_SAFE_FREE(gps_array); @@ -770,28 +848,37 @@ static void gpencil_update_extend(tGPDfill *tgpf) gpencil_delete_temp_stroke_extension(tgpf, false); gpencil_create_extensions_radius(tgpf); } + gpencil_fill_status_indicators(tgpf); WM_event_add_notifier(tgpf->C, NC_GPENCIL | NA_EDITED, NULL); } static bool gpencil_stroke_is_drawable(tGPDfill *tgpf, bGPDstroke *gps) { + const bool is_line_mode = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND); + const bool show_help = (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) != 0; + const bool show_extend = (tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) != 0; + const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0; + const bool is_extend_stroke = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG); + const bool is_help_stroke = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_HELP); + const bool stroke_collide = (gps->flag & GP_STROKE_COLLIDE) != 0; + + if (is_line_mode && is_extend_stroke && tgpf->is_render && use_stroke_collide && + !stroke_collide) { + return false; + } + if (tgpf->is_render) { return true; } - const bool show_help = (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) != 0; - const bool show_extend = (tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) != 0; - const bool is_extend = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG); - const bool is_extend_help = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_HELP); - if ((!show_help) && (show_extend)) { - if (!is_extend && !is_extend_help) { + if (!is_extend_stroke && !is_help_stroke) { return false; } } if ((show_help) && (!show_extend)) { - if (is_extend || is_extend_help) { + if (is_extend_stroke || is_help_stroke) { return false; } } @@ -822,6 +909,9 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, const bool is_extend = (gps->flag & GP_STROKE_NOFILL) && (gps->flag & GP_STROKE_TAG) && !(gps->flag & GP_STROKE_HELP); const bool is_help = gps->flag & GP_STROKE_HELP; + const bool is_line_mode = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND); + const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0; + const bool stroke_collide = (gps->flag & GP_STROKE_COLLIDE) != 0; if (!gpencil_stroke_is_drawable(tgpf, gps)) { return; @@ -841,7 +931,12 @@ static void gpencil_draw_basic_stroke(tGPDfill *tgpf, col[3] = (gps->flag & GP_STROKE_TAG) ? 0.0f : 0.5f; } else if ((is_extend) && (!tgpf->is_render)) { - copy_v4_v4(col, extend_col); + if (stroke_collide || !use_stroke_collide || !is_line_mode) { + copy_v4_v4(col, extend_col); + } + else { + copy_v4_v4(col, help_col); + } } else { copy_v4_v4(col, ink); @@ -2133,7 +2228,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* if parented change position relative to parent object */ for (int a = 0; a < tgpf->sbuffer_used; a++) { pt = &gps->points[a]; - gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); + gpencil_world_to_object_space_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ @@ -2153,11 +2248,21 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* ----------------------- */ /* Drawing */ /* Helper: Draw status message while the user is running the operator */ -static void gpencil_fill_status_indicators(bContext *C) +static void gpencil_fill_status_indicators(tGPDfill *tgpf) { - const char *status_str = TIP_( - "Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back, S: Switch Mode"); - ED_workspace_status_text(C, status_str); + const bool is_extend = (tgpf->fill_extend_mode == GP_FILL_EMODE_EXTEND); + const bool use_stroke_collide = (tgpf->flag & GP_BRUSH_FILL_STROKE_COLLIDE) != 0; + + char status_str[UI_MAX_DRAW_STR]; + BLI_snprintf(status_str, + sizeof(status_str), + TIP_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back, S: Switch Mode, D: " + "Stroke Collision | %s %s (%.3f)"), + (is_extend) ? TIP_("Extend") : TIP_("Radius"), + (is_extend && use_stroke_collide) ? TIP_("Stroke: ON") : TIP_("Stroke: OFF"), + tgpf->fill_extend_fac); + + ED_workspace_status_text(tgpf->C, status_str); } /* draw boundary lines to see fill limits */ @@ -2424,7 +2529,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH); - gpencil_fill_status_indicators(C); + gpencil_fill_status_indicators(tgpf); DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -2556,9 +2661,12 @@ static bool gpencil_find_and_mark_empty_areas(tGPDfill *tgpf) get_pixel(ibuf, i, rgba); if (rgba[3] == 0.0f) { set_pixel(ibuf, i, blue_col); + BKE_image_release_ibuf(tgpf->ima, ibuf, NULL); return true; } } + + BKE_image_release_ibuf(tgpf->ima, ibuf, NULL); return false; } @@ -2584,6 +2692,9 @@ static bool gpencil_do_frame_fill(tGPDfill *tgpf, const bool is_inverted) gpencil_invert_image(tgpf); while (gpencil_find_and_mark_empty_areas(tgpf)) { gpencil_boundaryfill_area(tgpf); + if (FILL_DEBUG) { + break; + } } } @@ -2664,8 +2775,10 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) const bool is_inverted = (is_brush_inv && (event->modifier & KM_CTRL) == 0) || (!is_brush_inv && (event->modifier & KM_CTRL) != 0); const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(tgpf->gpd); - const bool do_extend = (tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES); - const bool help_lines = ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || (do_extend)); + const bool extend_lines = (tgpf->fill_extend_fac > 0.0f); + const bool show_extend = ((tgpf->flag & GP_BRUSH_FILL_SHOW_EXTENDLINES) && !is_inverted); + const bool help_lines = (((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) || show_extend) && + !is_inverted); int estate = OPERATOR_RUNNING_MODAL; switch (event->type) { @@ -2734,7 +2847,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) int step = ((float)i / (float)total) * 100.0f; WM_cursor_time(win, step); - if (do_extend) { + if (extend_lines) { gpencil_update_extend(tgpf); } @@ -2765,7 +2878,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) loop_limit++; } - if (do_extend) { + if (extend_lines) { gpencil_delete_temp_stroke_extension(tgpf, true); } @@ -2794,13 +2907,13 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) estate = OPERATOR_CANCELLED; } } - else if (do_extend) { + else if (extend_lines) { gpencil_update_extend(tgpf); } tgpf->oldkey = event->type; break; case EVT_SKEY: - if ((do_extend) && (event->val == KM_PRESS)) { + if ((show_extend) && (event->val == KM_PRESS)) { /* Clean temp strokes. */ stroke_array_free(tgpf); @@ -2815,6 +2928,15 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) gpencil_update_extend(tgpf); } break; + case EVT_DKEY: + if ((show_extend) && (event->val == KM_PRESS)) { + tgpf->flag ^= GP_BRUSH_FILL_STROKE_COLLIDE; + /* Clean temp strokes. */ + stroke_array_free(tgpf); + gpencil_delete_temp_stroke_extension(tgpf, true); + gpencil_update_extend(tgpf); + } + break; case EVT_PAGEUPKEY: case WHEELUPMOUSE: if (tgpf->oldkey == 1) { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 4d62f834d86..4847e3eabf3 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -276,35 +276,35 @@ void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc, float *r_y); /** - * Convert point to parent space + * Convert point to world space * * \param pt: Original point - * \param diff_mat: Matrix with the difference between original parent matrix + * \param diff_mat: Matrix with the transformation * \param[out] r_pt: Pointer to new point after apply matrix */ -void gpencil_point_to_parent_space(const bGPDspoint *pt, - const float diff_mat[4][4], - bGPDspoint *r_pt); +void gpencil_point_to_world_space(const bGPDspoint *pt, + const float diff_mat[4][4], + bGPDspoint *r_pt); /** * Change points position relative to parent object */ /** * Change position relative to parent object */ -void gpencil_apply_parent(struct Depsgraph *depsgraph, - struct Object *obact, - bGPDlayer *gpl, - bGPDstroke *gps); +void gpencil_world_to_object_space(struct Depsgraph *depsgraph, + struct Object *obact, + bGPDlayer *gpl, + bGPDstroke *gps); /** * Change point position relative to parent object */ /** * Change point position relative to parent object */ -void gpencil_apply_parent_point(struct Depsgraph *depsgraph, - struct Object *obact, - bGPDlayer *gpl, - bGPDspoint *pt); +void gpencil_world_to_object_space_point(struct Depsgraph *depsgraph, + struct Object *obact, + bGPDlayer *gpl, + bGPDspoint *pt); /** * generic based on gpencil_point_to_xy_fl diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index dc63acf5136..4cd2bebe4a7 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -167,20 +167,20 @@ static bool gpencil_stroke_need_flip(Depsgraph *depsgraph, /* Line from start of strokes. */ pt = &gps_from->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_start[0], &v_from_start[1]); pt = &gps_to->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_start[0], &v_to_start[1]); /* Line from end of strokes. */ pt = &gps_from->points[gps_from->totpoints - 1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_end[0], &v_from_end[1]); pt = &gps_to->points[gps_to->totpoints - 1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(pt, diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_end[0], &v_to_end[1]); const bool isect_lines = (isect_seg_seg_v2(v_from_start, v_to_start, v_from_end, v_to_end) == diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index e1eeda5437a..80600abcf78 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1137,7 +1137,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) pt = gps->points; for (int i = 0; i < gps->totpoints; i++, pt++) { /* if parented change position relative to parent object */ - gpencil_apply_parent_point(depsgraph, obact, gpl, pt); + gpencil_world_to_object_space_point(depsgraph, obact, gpl, pt); } /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ @@ -1302,7 +1302,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) /* reproject to plane (only in 3d space) */ gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ - gpencil_apply_parent(depsgraph, obact, gpl, gps); + gpencil_world_to_object_space(depsgraph, obact, gpl, gps); /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ if ((!is_depth) && (((align_flag & GP_PROJECT_VIEWSPACE) && is_lock_axis_view) || is_camera)) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); @@ -1551,7 +1551,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, /* only process if it hasn't been masked out... */ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { bGPDspoint pt_temp; - gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp); + gpencil_point_to_world_space(gps->points, p->diff_mat, &pt_temp); gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { @@ -1575,7 +1575,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, /* get points to work with */ pt1 = gps->points + i; bGPDspoint npt; - gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_world_space(pt1, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); /* Do bound-box check first. */ @@ -1633,14 +1633,14 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } bGPDspoint npt; - gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_world_space(pt1, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); + gpencil_point_to_world_space(pt2, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); if (pt0) { - gpencil_point_to_parent_space(pt0, p->diff_mat, &npt); + gpencil_point_to_world_space(pt0, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]); } else { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index b13cab8be6d..67774b97c10 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1073,7 +1073,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* if parented change position relative to parent object */ for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; - gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); + gpencil_world_to_object_space_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); } /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 52e6200978c..c2e548397e3 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1462,7 +1462,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDspoint pt_temp; pt = &gps->points[0]; if ((is_masking && (pt->flag & GP_SPOINT_SELECT) != 0) || (!is_masking)) { - gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp); gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; @@ -1499,10 +1499,10 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, } } bGPDspoint npt; - gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_world_space(pt1, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_world_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the bound-box of the selection stroke. */ @@ -1803,7 +1803,7 @@ static bool get_automasking_strokes_list(tGP_BrushEditData *gso) bGPDspoint npt; if (gps->totpoints == 1) { - gpencil_point_to_parent_space(gps->points, bound_mat, &npt); + gpencil_point_to_world_space(gps->points, bound_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); /* Only check if point is inside. */ @@ -1821,7 +1821,7 @@ static bool get_automasking_strokes_list(tGP_BrushEditData *gso) pt2 = gps->points + i + 1; /* Check first point. */ - gpencil_point_to_parent_space(pt1, bound_mat, &npt); + gpencil_point_to_world_space(pt1, bound_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); if (len_v2v2_int(mval_i, pc1) <= radius) { BLI_ghash_insert(gso->automasking_strokes, gps, gps); @@ -1830,7 +1830,7 @@ static bool get_automasking_strokes_list(tGP_BrushEditData *gso) } /* Check second point. */ - gpencil_point_to_parent_space(pt2, bound_mat, &npt); + gpencil_point_to_world_space(pt2, bound_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); if (len_v2v2_int(mval_i, pc2) <= radius) { BLI_ghash_insert(gso->automasking_strokes, gps, gps); diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 5c3724e6ea4..a8968111d93 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -1497,7 +1497,7 @@ static bool gpencil_stroke_do_circle_sel(bGPdata *gpd, pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; bGPDspoint pt_temp; - gpencil_point_to_parent_space(pt, diff_mat, &pt_temp); + gpencil_point_to_world_space(pt, diff_mat, &pt_temp); gpencil_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); /* do boundbox check first */ @@ -2477,7 +2477,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) int xy[2]; bGPDspoint pt2; - gpencil_point_to_parent_space(pt, gpstroke_iter.diff_mat, &pt2); + gpencil_point_to_world_space(pt, gpstroke_iter.diff_mat, &pt2); gpencil_point_to_xy(&gsc, gps_active, &pt2, &xy[0], &xy[1]); /* do boundbox check first */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index c972d7c680f..98d5192a632 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -612,17 +612,17 @@ void gpencil_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc) } } -void gpencil_point_to_parent_space(const bGPDspoint *pt, - const float diff_mat[4][4], - bGPDspoint *r_pt) +void gpencil_point_to_world_space(const bGPDspoint *pt, + const float diff_mat[4][4], + bGPDspoint *r_pt) { - float fpt[3]; - - mul_v3_m4v3(fpt, diff_mat, &pt->x); - copy_v3_v3(&r_pt->x, fpt); + mul_v3_m4v3(&r_pt->x, diff_mat, &pt->x); } -void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, bGPDstroke *gps) +void gpencil_world_to_object_space(Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + bGPDstroke *gps) { bGPDspoint *pt; int i; @@ -630,34 +630,29 @@ void gpencil_apply_parent(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, b /* undo matrix */ float diff_mat[4][4]; float inverse_diff_mat[4][4]; - float fpt[3]; BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); for (i = 0; i < gps->totpoints; i++) { pt = &gps->points[i]; - mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x); - copy_v3_v3(&pt->x, fpt); + mul_m4_v3(inverse_diff_mat, &pt->x); } } -void gpencil_apply_parent_point(Depsgraph *depsgraph, - Object *obact, - bGPDlayer *gpl, - bGPDspoint *pt) +void gpencil_world_to_object_space_point(Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + bGPDspoint *pt) { /* undo matrix */ float diff_mat[4][4]; float inverse_diff_mat[4][4]; - float fpt[3]; BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); - mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x); - - copy_v3_v3(&pt->x, fpt); + mul_m4_v3(inverse_diff_mat, &pt->x); } void gpencil_point_to_xy( @@ -942,7 +937,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * float xy[2]; bGPDspoint pt2; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); /* Planar - All on same plane parallel to the viewplane */ @@ -1088,7 +1083,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, * artifacts in the final points. */ bGPDspoint pt2; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy_fl(gsc, gps_active, &pt2, &xy[0], &xy[1]); /* Project stroke in one axis */ @@ -1122,7 +1117,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph, copy_v3_v3(&pt->x, &pt2.x); /* apply parent again */ - gpencil_apply_parent_point(depsgraph, gsc->ob, gpl, pt); + gpencil_world_to_object_space_point(depsgraph, gsc->ob, gpl, pt); } /* Project screen-space back to 3D space (from current perspective) * so that all points have been treated the same way. */ @@ -2948,7 +2943,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc, for (int i = 0; i < 8; i++) { bGPDspoint pt_dummy, pt_dummy_ps; copy_v3_v3(&pt_dummy.x, bb.vec[i]); - gpencil_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(&pt_dummy, diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &bounds[i][0], &bounds[i][1]); } @@ -3012,7 +3007,7 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps, int i; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { bGPDspoint pt2; - gpencil_point_to_parent_space(pt, diff_mat, &pt2); + gpencil_point_to_world_space(pt, diff_mat, &pt2); gpencil_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]); } @@ -3038,9 +3033,9 @@ void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc, { bGPDspoint pt_dummy_ps; - gpencil_point_to_parent_space(&gps->points[0], diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(&gps->points[0], diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl1[0], &r_ctrl1[1]); - gpencil_point_to_parent_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps); + gpencil_point_to_world_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps); gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl2[0], &r_ctrl2[1]); } @@ -3068,11 +3063,11 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C, float pt2d_start[2], pt2d_end[2]; bGPDspoint *pt = &gps->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_parent); + gpencil_point_to_world_space(pt, diff_mat, &pt_parent); gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_start[0], &pt2d_start[1]); pt = &gps->points[gps->totpoints - 1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_parent); + gpencil_point_to_world_space(pt, diff_mat, &pt_parent); gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_end[0], &pt2d_end[1]); /* Loop all strokes of the active frame. */ @@ -3098,11 +3093,11 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C, float pt2d_target_start[2], pt2d_target_end[2]; pt = &gps_target->points[0]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_parent); + gpencil_point_to_world_space(pt, diff_mat, &pt_parent); gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_start[0], &pt2d_target_start[1]); pt = &gps_target->points[gps_target->totpoints - 1]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_parent); + gpencil_point_to_world_space(pt, diff_mat, &pt_parent); gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]); /* If the distance to the original stroke extremes is too big, the stroke must not be joined. @@ -3126,7 +3121,7 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C, for (i = 0, pt = gps_target->points; i < gps_target->totpoints; i++, pt++) { /* Convert point to 2D. */ float pt2d[2]; - gpencil_point_to_parent_space(pt, diff_mat, &pt_parent); + gpencil_point_to_world_space(pt, diff_mat, &pt_parent); gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d[0], &pt2d[1]); /* Check with Start point. */ diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index c221d8e25e4..75b5ce8dd48 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -846,7 +846,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp); gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; @@ -884,10 +884,10 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, } bGPDspoint npt; - gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_world_space(pt1, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_world_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the bound-box of the selection stroke. */ diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index fbfea067eca..8a949db5c5f 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -413,7 +413,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; - gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gpencil_point_to_world_space(gps->points, diff_mat, &pt_temp); gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; @@ -440,10 +440,10 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, pt2 = gps->points + i + 1; bGPDspoint npt; - gpencil_point_to_parent_space(pt1, diff_mat, &npt); + gpencil_point_to_world_space(pt1, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - gpencil_point_to_parent_space(pt2, diff_mat, &npt); + gpencil_point_to_world_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the bound-box of the selection stroke */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 26743a2bd08..a47ffe0b99a 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -197,7 +197,7 @@ void EDBM_automerge_and_split(struct Object *obedit, /** Export for ED_undo_sys. */ void ED_mesh_undosys_type(struct UndoType *ut); -/* editmesh_select.c */ +/* editmesh_select.cc */ void EDBM_select_mirrored(struct BMEditMesh *em, const struct Mesh *me, diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 144fa4e0b93..e1fd53ccdee 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -469,6 +469,8 @@ bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, str void ED_workspace_status_text(struct bContext *C, const char *str); +void ED_workspace_do_listen(struct bContext *C, const struct wmNotifier *note); + /* anim */ /** * Results in fully updated anim system. diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 1e220d33ff4..1c1ce41ef7a 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -34,7 +34,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, /* sculpt_transform.c */ void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob); -void ED_sculpt_init_transform(struct bContext *C, struct Object *ob, const char *undo_name); +void ED_sculpt_init_transform(struct bContext *C, + struct Object *ob, + const int mval[2], + const char *undo_name); void ED_sculpt_end_transform(struct bContext *C, struct Object *ob); /* sculpt_undo.c */ diff --git a/source/blender/editors/include/ED_spreadsheet.h b/source/blender/editors/include/ED_spreadsheet.h index da13e6d3636..736da367a44 100644 --- a/source/blender/editors/include/ED_spreadsheet.h +++ b/source/blender/editors/include/ED_spreadsheet.h @@ -7,7 +7,6 @@ struct Main; struct Object; struct SpaceNode; struct SpaceSpreadsheet; -struct SpreadsheetContext; struct bContext; struct bNode; @@ -15,29 +14,8 @@ struct bNode; extern "C" { #endif -struct SpreadsheetContext *ED_spreadsheet_context_new(int type); -void ED_spreadsheet_context_free(struct SpreadsheetContext *context); -void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet); -bool ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet); -uint64_t ED_spreadsheet_context_path_hash(const struct SpaceSpreadsheet *sspreadsheet); - struct ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet); -void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet, - struct SpaceNode *snode, - struct bNode *node); -void ED_spreadsheet_context_paths_set_geometry_node(struct Main *bmain, - struct SpaceNode *snode, - struct bNode *node); -void ED_spreadsheet_context_path_set_evaluated_object(struct SpaceSpreadsheet *sspreadsheet, - struct Object *object); - -void ED_spreadsheet_context_path_guess(const struct bContext *C, - struct SpaceSpreadsheet *sspreadsheet); -bool ED_spreadsheet_context_path_is_active(const struct bContext *C, - struct SpaceSpreadsheet *sspreadsheet); -bool ED_spreadsheet_context_path_exists(struct Main *bmain, struct SpaceSpreadsheet *sspreadsheet); - #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 38e542fc0ca..23cbcabbc0e 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -341,8 +341,6 @@ bool ED_uvedit_udim_params_from_image_space(const struct SpaceImage *sima, struct UVPackIsland_Params { uint rotate : 1; - /** -1 not to align to axis, otherwise 0,1 for X,Y. */ - int rotate_align_axis : 2; uint only_selected_uvs : 1; uint only_selected_faces : 1; uint use_seams : 1; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 0c61977d5cf..78b7274e42b 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -227,6 +227,7 @@ typedef enum { /** outside range (mainly for short), (can't avoid) */ V3D_PROJ_RET_OVERFLOW = 6, } eV3DProjStatus; +ENUM_OPERATORS(eV3DProjStatus, V3D_PROJ_RET_OVERFLOW); /* some clipping tests are optional */ typedef enum { @@ -349,7 +350,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, const uchar color_point[4], eSnapMode snap_elem_type); -/* view3d_iterators.c */ +/* view3d_iterators.cc */ /* foreach iterators */ @@ -456,7 +457,9 @@ void ED_view3d_project_float_v3_m4(const struct ARegion *region, float r_co[3], const float mat[4][4]); -eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base *base); +eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, + struct Base *base, + short r_co[2]); /* *** short *** */ eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region, @@ -1311,7 +1314,7 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene, bool do_foreground, bool do_camera_frame); -/* view3d_gizmo_preselect_type.c */ +/* view3d_gizmo_preselect_type.cc */ void ED_view3d_gizmo_mesh_preselect_get_active(struct bContext *C, struct wmGizmo *gz, diff --git a/source/blender/editors/include/ED_viewer_path.hh b/source/blender/editors/include/ED_viewer_path.hh new file mode 100644 index 00000000000..957dfddb8af --- /dev/null +++ b/source/blender/editors/include/ED_viewer_path.hh @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include <optional> + +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +#include "BKE_viewer_path.h" + +struct Main; +struct SpaceNode; +struct bNode; +struct bContext; +struct Object; + +namespace blender::ed::viewer_path { + +/** + * Activates the given node in the context provided by the editor. This indirectly updates all + * non-pinned viewer paths in other editors (spreadsheet and 3d view). + */ +void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node); + +/** + * Returns the object referenced by the viewer path. This only returns something if the viewer path + * *only* contains the object and nothing more. + */ +Object *parse_object_only(const ViewerPath &viewer_path); + +/** + * Represents a parsed #ViewerPath for easier consumption. + */ +struct ViewerPathForGeometryNodesViewer { + Object *object; + blender::StringRefNull modifier_name; + blender::Vector<blender::StringRefNull> group_node_names; + blender::StringRefNull viewer_node_name; +}; + +/** + * Parses a #ViewerPath into a #ViewerPathForGeometryNodesViewer or returns none if that does not + * work. + */ +std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer( + const ViewerPath &viewer_path); + +/** + * Finds the node referenced by the #ViewerPath within the provided editor. If no node is + * referenced, null is returned. When two different editors show the same node group but in a + * different context, it's possible that the same node is active in one editor but not the other. + */ +bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode); + +/** + * Checks if the node referenced by the viewer path and its entire context still exists. The node + * does not have to be visible for this to return true. + */ +bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path); + +/** + * Checks if the node referenced by the viewer and its entire context is still active, i.e. some + * editor is showing it. + */ +bool is_active_geometry_nodes_viewer(const bContext &C, + const ViewerPathForGeometryNodesViewer &parsed_viewer_path); + +} // namespace blender::ed::viewer_path diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 403cb0116d2..42b3198a9c0 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -5933,7 +5933,7 @@ bContextStore *UI_but_context_get(const uiBut *but) void UI_but_unit_type_set(uiBut *but, const int unit_type) { - but->unit_type = (uchar)(RNA_SUBTYPE_UNIT_VALUE(unit_type)); + but->unit_type = uchar(RNA_SUBTYPE_UNIT_VALUE(unit_type)); } int UI_but_unit_type_get(const uiBut *but) diff --git a/source/blender/editors/interface/view2d_ops.cc b/source/blender/editors/interface/view2d_ops.cc index 0282c1b1813..c72a0c75ee4 100644 --- a/source/blender/editors/interface/view2d_ops.cc +++ b/source/blender/editors/interface/view2d_ops.cc @@ -1628,7 +1628,7 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w float step; if (sms->time_allowed != 0.0) { - step = (float)((v2d->smooth_timer->duration) / sms->time_allowed); + step = float((v2d->smooth_timer->duration) / sms->time_allowed); } else { step = 1.0f; @@ -1859,11 +1859,11 @@ static void scroller_activate_init(bContext *C, if (in_scroller == 'h') { /* horizontal scroller - calculate adjustment factor first */ - const float mask_size = (float)BLI_rcti_size_x(&v2d->hor); + const float mask_size = float(BLI_rcti_size_x(&v2d->hor)); vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size; /* pixel rounding */ - vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / (float)(BLI_rcti_size_x(®ion->winrct) + 1); + vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / float(BLI_rcti_size_x(®ion->winrct) + 1); /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle( @@ -1879,11 +1879,11 @@ static void scroller_activate_init(bContext *C, } else { /* vertical scroller - calculate adjustment factor first */ - const float mask_size = (float)BLI_rcti_size_y(&v2d->vert); + const float mask_size = float(BLI_rcti_size_y(&v2d->vert)); vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size; /* pixel rounding */ - vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / (float)(BLI_rcti_size_y(®ion->winrct) + 1); + vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / float(BLI_rcti_size_y(®ion->winrct) + 1); /* get 'zone' (i.e. which part of scroller is activated) */ vsm->zone = mouse_in_scroller_handle( @@ -2000,11 +2000,11 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *e switch (vsm->scroller) { case 'h': /* horizontal scroller - so only horizontal movement * ('cur' moves opposite to mouse) */ - vsm->delta = (float)(event->xy[0] - vsm->lastx); + vsm->delta = float(event->xy[0] - vsm->lastx); break; case 'v': /* vertical scroller - so only vertical movement * ('cur' moves opposite to mouse) */ - vsm->delta = (float)(event->xy[1] - vsm->lasty); + vsm->delta = float(event->xy[1] - vsm->lasty); break; } } @@ -2013,11 +2013,11 @@ static int scroller_activate_modal(bContext *C, wmOperator *op, const wmEvent *e switch (vsm->scroller) { case 'h': /* horizontal scroller - so only horizontal movement * ('cur' moves with mouse) */ - vsm->delta = (float)(vsm->lastx - event->xy[0]); + vsm->delta = float(vsm->lastx - event->xy[0]); break; case 'v': /* vertical scroller - so only vertical movement * ('cur' moves with to mouse) */ - vsm->delta = (float)(vsm->lasty - event->xy[1]); + vsm->delta = float(vsm->lasty - event->xy[1]); break; } } @@ -2080,11 +2080,11 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, const wmEvent * switch (vsm->scroller) { case 'h': /* horizontal scroller - so only horizontal movement * ('cur' moves opposite to mouse) */ - vsm->delta = (float)(event->xy[0] - vsm->scrollbar_orig); + vsm->delta = float(event->xy[0] - vsm->scrollbar_orig); break; case 'v': /* vertical scroller - so only vertical movement * ('cur' moves opposite to mouse) */ - vsm->delta = (float)(event->xy[1] - vsm->scrollbar_orig); + vsm->delta = float(event->xy[1] - vsm->scrollbar_orig); break; } scroller_activate_apply(C, op); @@ -2177,8 +2177,8 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) const int snap_test = ED_region_snap_size_test(region); /* zoom 1.0 */ - const int winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1); - const int winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1); + const int winx = float(BLI_rcti_size_x(&v2d->mask) + 1); + const int winy = float(BLI_rcti_size_y(&v2d->mask) + 1); v2d->cur.xmax = v2d->cur.xmin + winx; v2d->cur.ymax = v2d->cur.ymin + winy; diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 218564eaf30..c1049e32d4c 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -45,7 +45,7 @@ set(SRC editmesh_preselect_elem.c editmesh_rip.c editmesh_rip_edge.c - editmesh_select.c + editmesh_select.cc editmesh_select_similar.c editmesh_tools.c editmesh_undo.c diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 591e06be80c..63b0eb778d7 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -226,7 +226,7 @@ static void ringsel_finish(bContext *C, wmOperator *op) } else { /* XXX Is this piece of code ever used now? Simple loop select is now - * in editmesh_select.c (around line 1000)... */ + * in editmesh_select.cc (around line 1000)... */ /* sets as active, useful for other tools */ if (em->selectmode & SCE_SELECT_VERTEX) { /* low priority TODO: get vertrex close to mouse. */ @@ -473,7 +473,7 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) static int ringcut_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - /* When accessed as a tool, get the active edge from the preselection gizmo. */ + /* When accessed as a tool, get the active edge from the pre-selection gizmo. */ { ARegion *region = CTX_wm_region(C); wmGizmoMap *gzmap = region->gizmo_map; diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index 06565fbf314..bf9664fa10d 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -73,7 +73,7 @@ static void edbm_flag_disable_all_multi(const Scene *scene, MEM_freeN(objects); } -/* When accessed as a tool, get the active edge from the preselection gizmo. */ +/** When accessed as a tool, get the active edge from the pre-selection gizmo. */ static bool edbm_preselect_or_active(bContext *C, const View3D *v3d, Base **r_base, BMElem **r_ele) { ARegion *region = CTX_wm_region(C); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.cc index 34f7301c4b1..675540bea73 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -7,17 +7,16 @@ #include "MEM_guardedalloc.h" -#include "BLI_array.h" #include "BLI_bitmap.h" #include "BLI_heap.h" #include "BLI_linklist.h" -#include "BLI_linklist_stack.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_math_bits.h" #include "BLI_rand.h" #include "BLI_string.h" #include "BLI_utildefines_stack.h" +#include "BLI_vector.hh" #include "BKE_context.h" #include "BKE_customdata.h" @@ -182,11 +181,11 @@ static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint return (BMElem *)BM_vert_at_index_find_or_table(em->bm, elem_id); default: BLI_assert(0); - return NULL; + return nullptr; } } - return NULL; + return nullptr; } /** \} */ @@ -218,8 +217,8 @@ struct NearestVertUserData { bool use_cycle; int cycle_index_prev; - struct NearestVertUserData_Hit hit; - struct NearestVertUserData_Hit hit_cycle; + NearestVertUserData_Hit hit; + NearestVertUserData_Hit hit_cycle; }; static void findnearestvert__doClosest(void *userData, @@ -227,7 +226,7 @@ static void findnearestvert__doClosest(void *userData, const float screen_co[2], int index) { - struct NearestVertUserData *data = userData; + NearestVertUserData *data = static_cast<NearestVertUserData *>(userData); float dist_test, dist_test_bias; dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); @@ -244,7 +243,7 @@ static void findnearestvert__doClosest(void *userData, } if (data->use_cycle) { - if ((data->hit_cycle.vert == NULL) && (index > data->cycle_index_prev) && + if ((data->hit_cycle.vert == nullptr) && (index > data->cycle_index_prev) && (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { data->hit_cycle.dist_bias = dist_test_bias; data->hit_cycle.dist = dist_test; @@ -270,7 +269,7 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, uint index; BMVert *eve; - /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ + /* No after-queue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_VERTEX); @@ -281,7 +280,7 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, eve = (BMVert *)edbm_select_id_bm_elem_get(bases, index, &base_index); } else { - eve = NULL; + eve = nullptr; } } @@ -294,15 +293,15 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, return eve; } } - return NULL; + return nullptr; } - struct NearestVertUserData data = {{0}}; - const struct NearestVertUserData_Hit *hit = NULL; + NearestVertUserData data = {{0}}; + const NearestVertUserData_Hit *hit = nullptr; const eV3DProjTest clip_flag = RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d) ? V3D_PROJ_TEST_CLIP_DEFAULT : V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; - BMesh *prev_select_bm = NULL; + BMesh *prev_select_bm = nullptr; static struct { int index; @@ -345,8 +344,8 @@ BMVert *EDBM_vert_find_nearest_ex(ViewContext *vc, } } - if (hit == NULL) { - return NULL; + if (hit == nullptr) { + return nullptr; } prev_select.index = hit->index; @@ -360,7 +359,7 @@ BMVert *EDBM_vert_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) { BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); - return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, NULL); + return EDBM_vert_find_nearest_ex(vc, dist_px_manhattan_p, false, false, &base, 1, nullptr); } /* find the distance to the edge we already have */ @@ -376,7 +375,7 @@ static void find_nearest_edge_center__doZBuf(void *userData, const float screen_co_b[2], int UNUSED(index)) { - struct NearestEdgeUserData_ZBuf *data = userData; + NearestEdgeUserData_ZBuf *data = static_cast<NearestEdgeUserData_ZBuf *>(userData); if (eed == data->edge_test) { float dist_test; @@ -409,15 +408,15 @@ struct NearestEdgeUserData { bool use_cycle; int cycle_index_prev; - struct NearestEdgeUserData_Hit hit; - struct NearestEdgeUserData_Hit hit_cycle; + NearestEdgeUserData_Hit hit; + NearestEdgeUserData_Hit hit_cycle; }; /* NOTE: uses v3d, so needs active 3d window. */ static void find_nearest_edge__doClosest( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { - struct NearestEdgeUserData *data = userData; + NearestEdgeUserData *data = static_cast<NearestEdgeUserData *>(userData); float dist_test, dist_test_bias; float fac = line_point_factor_v2(data->mval_fl, screen_co_a, screen_co_b); @@ -463,7 +462,7 @@ static void find_nearest_edge__doClosest( } if (data->use_cycle) { - if ((data->hit_cycle.edge == NULL) && (index > data->cycle_index_prev) && + if ((data->hit_cycle.edge == nullptr) && (index > data->cycle_index_prev) && (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { float screen_co_mid[2]; @@ -496,7 +495,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, uint index; BMEdge *eed; - /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ + /* No after-queue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ { DRW_select_buffer_context_create(bases, bases_len, SCE_SELECT_EDGE); @@ -507,7 +506,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, eed = (BMEdge *)edbm_select_id_bm_elem_get(bases, index, &base_index); } else { - eed = NULL; + eed = nullptr; } } @@ -517,7 +516,7 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, /* exception for faces (verts don't need this) */ if (r_dist_center_px_manhattan && eed) { - struct NearestEdgeUserData_ZBuf data; + NearestEdgeUserData_ZBuf data; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; @@ -544,14 +543,14 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, return eed; } } - return NULL; + return nullptr; } - struct NearestEdgeUserData data = {{0}}; - const struct NearestEdgeUserData_Hit *hit = NULL; + NearestEdgeUserData data = {{0}}; + const NearestEdgeUserData_Hit *hit = nullptr; /* interpolate along the edge before doing a clipping plane test */ const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT & ~V3D_PROJ_TEST_CLIP_BB; - BMesh *prev_select_bm = NULL; + BMesh *prev_select_bm = nullptr; static struct { int index; @@ -596,8 +595,8 @@ BMEdge *EDBM_edge_find_nearest_ex(ViewContext *vc, } } - if (hit == NULL) { - return NULL; + if (hit == nullptr) { + return nullptr; } if (r_dist_center_px_manhattan) { @@ -616,7 +615,7 @@ BMEdge *EDBM_edge_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); return EDBM_edge_find_nearest_ex( - vc, dist_px_manhattan_p, NULL, false, false, NULL, &base, 1, NULL); + vc, dist_px_manhattan_p, nullptr, false, false, nullptr, &base, 1, nullptr); } /* find the distance to the face we already have */ @@ -631,7 +630,7 @@ static void find_nearest_face_center__doZBuf(void *userData, const float screen_co[2], int UNUSED(index)) { - struct NearestFaceUserData_ZBuf *data = userData; + NearestFaceUserData_ZBuf *data = static_cast<NearestFaceUserData_ZBuf *>(userData); if (efa == data->face_test) { const float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co); @@ -655,8 +654,8 @@ struct NearestFaceUserData { bool use_cycle; int cycle_index_prev; - struct NearestFaceUserData_Hit hit; - struct NearestFaceUserData_Hit hit_cycle; + NearestFaceUserData_Hit hit; + NearestFaceUserData_Hit hit_cycle; }; static void findnearestface__doClosest(void *userData, @@ -664,7 +663,7 @@ static void findnearestface__doClosest(void *userData, const float screen_co[2], int index) { - struct NearestFaceUserData *data = userData; + NearestFaceUserData *data = static_cast<NearestFaceUserData *>(userData); float dist_test, dist_test_bias; dist_test = dist_test_bias = len_manhattan_v2v2(data->mval_fl, screen_co); @@ -681,7 +680,7 @@ static void findnearestface__doClosest(void *userData, } if (data->use_cycle) { - if ((data->hit_cycle.face == NULL) && (index > data->cycle_index_prev) && + if ((data->hit_cycle.face == nullptr) && (index > data->cycle_index_prev) && (dist_test_bias < FIND_NEAR_CYCLE_THRESHOLD_MIN)) { data->hit_cycle.dist_bias = dist_test_bias; data->hit_cycle.dist = dist_test; @@ -732,7 +731,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, efa = (BMFace *)edbm_select_id_bm_elem_get(bases, index, &base_index); } else { - efa = NULL; + efa = nullptr; } } @@ -742,7 +741,7 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, /* exception for faces (verts don't need this) */ if (r_dist_center && efa) { - struct NearestFaceUserData_ZBuf data; + NearestFaceUserData_ZBuf data; data.mval_fl[0] = vc->mval[0]; data.mval_fl[1] = vc->mval[1]; @@ -767,13 +766,13 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, return efa; } } - return NULL; + return nullptr; } - struct NearestFaceUserData data = {{0}}; - const struct NearestFaceUserData_Hit *hit = NULL; + NearestFaceUserData data = {{0}}; + const NearestFaceUserData_Hit *hit = nullptr; const eV3DProjTest clip_flag = V3D_PROJ_TEST_CLIP_DEFAULT; - BMesh *prev_select_bm = NULL; + BMesh *prev_select_bm = nullptr; static struct { int index; @@ -816,8 +815,8 @@ BMFace *EDBM_face_find_nearest_ex(ViewContext *vc, } } - if (hit == NULL) { - return NULL; + if (hit == nullptr) { + return nullptr; } if (r_dist_center) { @@ -836,7 +835,7 @@ BMFace *EDBM_face_find_nearest(ViewContext *vc, float *dist_px_manhattan_p) BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); Base *base = BKE_view_layer_base_find(vc->view_layer, vc->obact); return EDBM_face_find_nearest_ex( - vc, dist_px_manhattan_p, NULL, false, false, false, NULL, &base, 1, NULL); + vc, dist_px_manhattan_p, nullptr, false, false, false, nullptr, &base, 1, nullptr); } #undef FIND_NEAR_SELECT_BIAS @@ -876,18 +875,18 @@ static bool unified_findnearest(ViewContext *vc, BMFace *ele; int base_index; } f, f_zbuf; - } hit = {{NULL}}; + } hit = {{nullptr}}; - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + /* No after-queue (yet), so we check it now, otherwise the em_xxxofs indices are bad. */ if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_FACE)) { float dist_center = 0.0f; float *dist_center_p = (em->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_VERTEX)) ? &dist_center : - NULL; + nullptr; uint base_index = 0; - BMFace *efa_zbuf = NULL; + BMFace *efa_zbuf = nullptr; BMFace *efa_test = EDBM_face_find_nearest_ex( vc, &dist, dist_center_p, true, true, use_cycle, &efa_zbuf, bases, bases_len, &base_index); @@ -906,10 +905,10 @@ static bool unified_findnearest(ViewContext *vc, if ((dist > 0.0f) && (em->selectmode & SCE_SELECT_EDGE)) { float dist_center = 0.0f; - float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : NULL; + float *dist_center_p = (em->selectmode & SCE_SELECT_VERTEX) ? &dist_center : nullptr; uint base_index = 0; - BMEdge *eed_zbuf = NULL; + BMEdge *eed_zbuf = nullptr; BMEdge *eed_test = EDBM_edge_find_nearest_ex( vc, &dist, dist_center_p, true, use_cycle, &eed_zbuf, bases, bases_len, &base_index); @@ -939,11 +938,11 @@ static bool unified_findnearest(ViewContext *vc, /* Return only one of 3 pointers, for front-buffer redraws. */ if (hit.v.ele) { - hit.f.ele = NULL; - hit.e.ele = NULL; + hit.f.ele = nullptr; + hit.e.ele = nullptr; } else if (hit.e.ele) { - hit.f.ele = NULL; + hit.f.ele = nullptr; } /* there may be a face under the cursor, who's center if too far away @@ -960,7 +959,7 @@ static bool unified_findnearest(ViewContext *vc, } /* Only one element type will be non-null. */ - BLI_assert(((hit.v.ele != NULL) + (hit.e.ele != NULL) + (hit.f.ele != NULL)) <= 1); + BLI_assert(((hit.v.ele != nullptr) + (hit.e.ele != nullptr) + (hit.f.ele != nullptr)) <= 1); if (hit.v.ele) { *r_base_index = hit.v.base_index; @@ -1010,35 +1009,34 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, int *r_base_index_vert, int *r_base_index_edge, int *r_base_index_face, - struct BMVert **r_eve, - struct BMEdge **r_eed, - struct BMFace **r_efa) + BMVert **r_eve, + BMEdge **r_eed, + BMFace **r_efa) { - - const float mval_fl[2] = {UNPACK2(vc->mval)}; + const float mval_fl[2] = {float(vc->mval[0]), float(vc->mval[1])}; float ray_origin[3], ray_direction[3]; struct { uint base_index; BMElem *ele; - } best = {0, NULL}; + } best = {0, nullptr}; /* Currently unused, keep since we may want to pick the best. */ UNUSED_VARS(best); struct { uint base_index; BMElem *ele; - } best_vert = {0, NULL}; + } best_vert = {0, nullptr}; struct { uint base_index; BMElem *ele; - } best_edge = {0, NULL}; + } best_edge = {0, nullptr}; struct { uint base_index; BMElem *ele; - } best_face = {0, NULL}; + } best_face = {0, nullptr}; if (ED_view3d_win_to_ray_clipped( vc->depsgraph, vc->region, vc->v3d, mval_fl, ray_origin, ray_direction, true)) { @@ -1047,9 +1045,9 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, float dist_sq_best_edge = FLT_MAX; float dist_sq_best_face = FLT_MAX; - const bool use_vert = (r_eve != NULL); - const bool use_edge = (r_eed != NULL); - const bool use_face = (r_efa != NULL); + const bool use_vert = (r_eve != nullptr); + const bool use_edge = (r_eed != nullptr); + const bool use_face = (r_efa != nullptr); for (uint base_index = 0; base_index < bases_len; base_index++) { Base *base_iter = bases[base_index]; @@ -1063,15 +1061,16 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, copy_m3_m4(imat3, obedit->obmat); invert_m3(imat3); - const float(*coords)[3] = NULL; + const float(*coords)[3] = nullptr; { - Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, obedit->data); + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(vc->depsgraph, + static_cast<ID *>(obedit->data)); if (me_eval->runtime.edit_data) { coords = me_eval->runtime.edit_data->vertexCos; } } - if (coords != NULL) { + if (coords != nullptr) { BM_mesh_elem_index_ensure(bm, BM_VERT); } @@ -1221,13 +1220,13 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, *r_base_index_face = best_face.base_index; if (r_eve) { - *r_eve = NULL; + *r_eve = nullptr; } if (r_eed) { - *r_eed = NULL; + *r_eed = nullptr; } if (r_efa) { - *r_efa = NULL; + *r_efa = nullptr; } if (best_vert.ele) { @@ -1240,7 +1239,7 @@ bool EDBM_unified_findnearest_from_raycast(ViewContext *vc, *r_efa = (BMFace *)best_face.ele; } - return (best_vert.ele != NULL || best_edge.ele != NULL || best_face.ele != NULL); + return (best_vert.ele != nullptr || best_edge.ele != nullptr || best_face.ele != nullptr); } /** \} */ @@ -1257,7 +1256,6 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) bool changed = false; /* group vars */ - int *groups_array; int(*group_index)[2]; int group_tot; int i; @@ -1267,9 +1265,10 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); + int *groups_array = static_cast<int *>( + MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__)); group_tot = BM_mesh_calc_face_groups( - bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT); + bm, groups_array, &group_index, nullptr, nullptr, nullptr, BM_ELEM_SELECT, BM_VERT); BM_mesh_elem_table_ensure(bm, BM_FACE); @@ -1280,7 +1279,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) const int fg_sta = group_index[i][0]; const int fg_len = group_index[i][1]; int j; - BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__); + BMFace **fg = static_cast<BMFace **>(MEM_mallocN(sizeof(*fg) * fg_len, __func__)); for (j = 0; j < fg_len; j++) { fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); @@ -1292,8 +1291,8 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) if (tot) { LinkData *link; - while ((link = BLI_pophead(&faces_regions))) { - BMFace *f, **faces = link->data; + while ((link = static_cast<LinkData *>(BLI_pophead(&faces_regions)))) { + BMFace *f, **faces = static_cast<BMFace **>(link->data); while ((f = *(faces++))) { BM_face_select_set(bm, f, true); } @@ -1309,7 +1308,7 @@ static int edbm_select_similar_region_exec(bContext *C, wmOperator *op) MEM_freeN(group_index); if (changed) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } else { @@ -1379,9 +1378,9 @@ static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *e return edbm_select_mode_exec(C, op); } -static char *edbm_select_mode_get_description(struct bContext *UNUSED(C), - struct wmOperatorType *UNUSED(op), - struct PointerRNA *values) +static char *edbm_select_mode_get_description(bContext *UNUSED(C), + wmOperatorType *UNUSED(op), + PointerRNA *values) { const int type = RNA_enum_get(values, "type"); @@ -1407,7 +1406,7 @@ static char *edbm_select_mode_get_description(struct bContext *UNUSED(C), } } - return NULL; + return nullptr; } void MESH_OT_select_mode(wmOperatorType *ot) @@ -1418,7 +1417,7 @@ void MESH_OT_select_mode(wmOperatorType *ot) {0, "DISABLE", 0, "Disable", "Disable selected markers"}, {1, "ENABLE", 0, "Enable", "Enable selected markers"}, {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1438,11 +1437,11 @@ void MESH_OT_select_mode(wmOperatorType *ot) /* properties */ /* Hide all, not to show redo panel. */ prop = RNA_def_boolean(ot->srna, "use_extend", false, "Extend", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); prop = RNA_def_boolean(ot->srna, "use_expand", false, "Expand", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); ot->prop = prop = RNA_def_enum(ot->srna, "type", rna_enum_mesh_select_mode_items, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); prop = RNA_def_enum( ot->srna, "action", actions_items, 2, "Action", "Selection action to execute"); @@ -1475,7 +1474,8 @@ static void walker_select_count(BMEditMesh *em, BMW_FLAG_TEST_HIDDEN, BMW_NIL_LAY); - for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { + for (ele = static_cast<BMElem *>(BMW_begin(&walker, start)); ele; + ele = static_cast<BMElem *>(BMW_step(&walker))) { r_count_by_select[BM_elem_flag_test(ele, BM_ELEM_SELECT) ? 1 : 0] += 1; /* Early exit when mixed (could be optional if needed. */ @@ -1503,7 +1503,8 @@ static void walker_select(BMEditMesh *em, int walkercode, void *start, const boo BMW_FLAG_TEST_HIDDEN, BMW_NIL_LAY); - for (ele = BMW_begin(&walker, start); ele; ele = BMW_step(&walker)) { + for (ele = static_cast<BMElem *>(BMW_begin(&walker, start)); ele; + ele = static_cast<BMElem *>(BMW_step(&walker))) { if (!select) { BM_select_history_remove(bm, ele); } @@ -1529,7 +1530,6 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) } BMEdge *eed; - BMEdge **edarray; int edindex; BMIter iter; int totedgesel = 0; @@ -1540,7 +1540,8 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) } } - edarray = MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array"); + BMEdge **edarray = static_cast<BMEdge **>( + MEM_mallocN(sizeof(BMEdge *) * totedgesel, "edge array")); edindex = 0; BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { @@ -1573,7 +1574,7 @@ static int edbm_loop_multiselect_exec(bContext *C, wmOperator *op) MEM_freeN(edarray); // if (EM_texFaceCheck()) - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -1664,10 +1665,10 @@ static void mouse_mesh_loop_edge( static bool mouse_mesh_loop( bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, bool ring) { - Base *basact = NULL; - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; + Base *basact = nullptr; + BMVert *eve = nullptr; + BMEdge *eed = nullptr; + BMFace *efa = nullptr; ViewContext vc; BMEditMesh *em; @@ -1677,8 +1678,8 @@ static bool mouse_mesh_loop( float mvalf[2]; em_setup_viewcontext(C, &vc); - mvalf[0] = (float)(vc.mval[0] = mval[0]); - mvalf[1] = (float)(vc.mval[1] = mval[1]); + mvalf[0] = float(vc.mval[0] = mval[0]); + mvalf[1] = float(vc.mval[1] = mval[1]); BMEditMesh *em_original = vc.em; const short selectmode = em_original->selectmode; @@ -1696,13 +1697,13 @@ static bool mouse_mesh_loop( em = vc.em; } else { - em = NULL; + em = nullptr; } } em_original->selectmode = selectmode; - if (em == NULL || eed == NULL) { + if (em == nullptr || eed == nullptr) { MEM_freeN(bases); return false; } @@ -1740,7 +1741,7 @@ static bool mouse_mesh_loop( } EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); } } @@ -1794,7 +1795,7 @@ static bool mouse_mesh_loop( BMFace *f; BMIter iterf; float best_dist = FLT_MAX; - efa = NULL; + efa = nullptr; /* We can't be sure this has already been set... */ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); @@ -1825,7 +1826,7 @@ static bool mouse_mesh_loop( MEM_freeN(bases); - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); return true; @@ -1943,7 +1944,7 @@ static int edbm_select_all_exec(bContext *C, wmOperator *op) EDBM_selectmode_flush(em); break; } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -1991,7 +1992,7 @@ static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) continue; } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -2023,14 +2024,14 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) * Gets called via generic mouse select operator. * \{ */ -bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params) +bool EDBM_select_pick(bContext *C, const int mval[2], const SelectPick_Params *params) { ViewContext vc; int base_index_active = -1; - BMVert *eve = NULL; - BMEdge *eed = NULL; - BMFace *efa = NULL; + BMVert *eve = nullptr; + BMEdge *eed = nullptr; + BMFace *efa = nullptr; /* setup view context for argument to callbacks */ em_setup_viewcontext(C, &vc); @@ -2055,7 +2056,7 @@ bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Pa Base *base_iter = bases[base_index]; Object *ob_iter = base_iter->object; EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); } changed = true; @@ -2199,7 +2200,7 @@ bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Pa if (efa->mat_nr != vc.obedit->actcol - 1) { vc.obedit->actcol = efa->mat_nr + 1; vc.em->mat_nr = efa->mat_nr; - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr); } /* Change active face-map on object. */ @@ -2227,7 +2228,7 @@ bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Pa ED_object_base_activate(C, basact); } - DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(vc.obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); changed = true; @@ -2249,7 +2250,7 @@ static void edbm_strip_selections(BMEditMesh *em) BMEditSelection *ese, *nextese; if (!(em->selectmode & SCE_SELECT_VERTEX)) { - ese = em->bm->selected.first; + ese = static_cast<BMEditSelection *>(em->bm->selected.first); while (ese) { nextese = ese->next; if (ese->htype == BM_VERT) { @@ -2259,7 +2260,7 @@ static void edbm_strip_selections(BMEditMesh *em) } } if (!(em->selectmode & SCE_SELECT_EDGE)) { - ese = em->bm->selected.first; + ese = static_cast<BMEditSelection *>(em->bm->selected.first); while (ese) { nextese = ese->next; if (ese->htype == BM_EDGE) { @@ -2269,7 +2270,7 @@ static void edbm_strip_selections(BMEditMesh *em) } } if (!(em->selectmode & SCE_SELECT_FACE)) { - ese = em->bm->selected.first; + ese = static_cast<BMEditSelection *>(em->bm->selected.first); while (ese) { nextese = ese->next; if (ese->htype == BM_FACE) { @@ -2450,14 +2451,14 @@ bool EDBM_selectmode_toggle_multi(bContext *C, ViewLayer *view_layer = CTX_data_view_layer(C); ToolSettings *ts = CTX_data_tool_settings(C); Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = NULL; + BMEditMesh *em = nullptr; bool ret = false; if (obedit && obedit->type == OB_MESH) { em = BKE_editmesh_from_object(obedit); } - if (em == NULL) { + if (em == nullptr) { return ret; } @@ -2549,16 +2550,17 @@ bool EDBM_selectmode_toggle_multi(bContext *C, if (ret == true) { ts->selectmode = em->selectmode; - em = NULL; + em = nullptr; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob_iter = objects[ob_index]; BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter); em_iter->selectmode = ts->selectmode; EDBM_selectmode_set(em_iter); - DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), + ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); } - WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } @@ -2573,11 +2575,11 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode) { Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = NULL; + BMEditMesh *em = nullptr; if (obedit && obedit->type == OB_MESH) { em = BKE_editmesh_from_object(obedit); } - if (em == NULL) { + if (em == nullptr) { return changed; } } @@ -2601,7 +2603,8 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode) if (em_iter->selectmode != ts->selectmode) { em_iter->selectmode = ts->selectmode; EDBM_selectmode_set(em_iter); - DEG_id_tag_update(ob_iter->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), + ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); changed = true; } @@ -2609,7 +2612,7 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode) MEM_freeN(objects); if (changed) { - WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL); + WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); } return changed; @@ -2706,7 +2709,7 @@ void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ } } -bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len) +bool EDBM_mesh_deselect_all_multi_ex(Base **bases, const uint bases_len) { bool changed_multi = false; for (uint base_index = 0; base_index < bases_len; base_index++) { @@ -2719,13 +2722,13 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len) } EDBM_flag_disable_all(em_iter, BM_ELEM_SELECT); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); changed_multi = true; } return changed_multi; } -bool EDBM_mesh_deselect_all_multi(struct bContext *C) +bool EDBM_mesh_deselect_all_multi(bContext *C) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; @@ -2739,7 +2742,7 @@ bool EDBM_mesh_deselect_all_multi(struct bContext *C) } bool EDBM_selectmode_disable_multi_ex(Scene *scene, - struct Base **bases, + Base **bases, const uint bases_len, const short selectmode_disable, const short selectmode_fallback) @@ -2757,7 +2760,7 @@ bool EDBM_selectmode_disable_multi_ex(Scene *scene, return changed_multi; } -bool EDBM_selectmode_disable_multi(struct bContext *C, +bool EDBM_selectmode_disable_multi(bContext *C, const short selectmode_disable, const short selectmode_fallback) { @@ -2767,7 +2770,7 @@ bool EDBM_selectmode_disable_multi(struct bContext *C, ED_view3d_viewcontext_init(C, &vc, depsgraph); uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( - vc.scene, vc.view_layer, NULL, &bases_len); + vc.scene, vc.view_layer, nullptr, &bases_len); bool changed_multi = EDBM_selectmode_disable_multi_ex( scene, bases, bases_len, selectmode_disable, selectmode_fallback); MEM_freeN(bases); @@ -2832,7 +2835,7 @@ static float bm_interior_face_group_calc_cost(ListBase *ls, const float *edge_le float area = 0.0f; float cost = 0.0f; bool found = false; - LISTBASE_FOREACH (struct BMFaceLink *, f_link, ls) { + LISTBASE_FOREACH (BMFaceLink *, f_link, ls) { BMFace *f = f_link->face; area += f_link->area; int i = BM_elem_index_get(f); @@ -2881,7 +2884,8 @@ bool EDBM_select_interior_faces(BMEditMesh *em) BMIter iter; bool changed = false; - float *edge_lengths = MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__); + float *edge_lengths = static_cast<float *>( + MEM_mallocN(sizeof(*edge_lengths) * bm->totedge, __func__)); { bool has_nonmanifold = false; @@ -2910,15 +2914,16 @@ bool EDBM_select_interior_faces(BMEditMesh *em) } /* group vars */ - int *fgroup_array; int(*fgroup_index)[2]; int fgroup_len; - fgroup_array = MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__); + int *fgroup_array = static_cast<int *>( + MEM_mallocN(sizeof(*fgroup_array) * bm->totface, __func__)); fgroup_len = BM_mesh_calc_face_groups( - bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, NULL, NULL, 0, BM_EDGE); + bm, fgroup_array, &fgroup_index, bm_interior_loop_filter_fn, nullptr, nullptr, 0, BM_EDGE); - int *fgroup_recalc_stack = MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__); + int *fgroup_recalc_stack = static_cast<int *>( + MEM_mallocN(sizeof(*fgroup_recalc_stack) * fgroup_len, __func__)); STACK_DECLARE(fgroup_recalc_stack); STACK_INIT(fgroup_recalc_stack, fgroup_len); @@ -2932,8 +2937,10 @@ bool EDBM_select_interior_faces(BMEditMesh *em) } bm->elem_index_dirty |= BM_FACE; - ListBase *fgroup_listbase = MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__); - struct BMFaceLink *f_link_array = MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__); + ListBase *fgroup_listbase = static_cast<ListBase *>( + MEM_callocN(sizeof(*fgroup_listbase) * fgroup_len, __func__)); + BMFaceLink *f_link_array = static_cast<BMFaceLink *>( + MEM_callocN(sizeof(*f_link_array) * bm->totface, __func__)); for (int i = 0; i < fgroup_len; i++) { const int fg_sta = fgroup_index[i][0]; @@ -2943,7 +2950,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) BMFace *f = BM_face_at_index(bm, face_index); BM_elem_index_set(f, i); - struct BMFaceLink *f_link = &f_link_array[face_index]; + BMFaceLink *f_link = &f_link_array[face_index]; f_link->face = f; f_link->area = BM_face_calc_area(f); BLI_addtail(&fgroup_listbase[i], f_link); @@ -2954,8 +2961,10 @@ bool EDBM_select_interior_faces(BMEditMesh *em) MEM_freeN(fgroup_index); Heap *fgroup_heap = BLI_heap_new_ex(fgroup_len); - HeapNode **fgroup_table = MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__); - bool *fgroup_dirty = MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__); + HeapNode **fgroup_table = static_cast<HeapNode **>( + MEM_mallocN(sizeof(*fgroup_table) * fgroup_len, __func__)); + bool *fgroup_dirty = static_cast<bool *>( + MEM_callocN(sizeof(*fgroup_dirty) * fgroup_len, __func__)); for (int i = 0; i < fgroup_len; i++) { const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); @@ -2963,7 +2972,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) fgroup_table[i] = BLI_heap_insert(fgroup_heap, -cost, POINTER_FROM_INT(i)); } else { - fgroup_table[i] = NULL; + fgroup_table[i] = nullptr; } } @@ -2993,7 +3002,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) } else { BLI_heap_remove(fgroup_heap, fgroup_table[i]); - fgroup_table[i] = NULL; + fgroup_table[i] = nullptr; } fgroup_dirty[i] = false; } @@ -3008,13 +3017,13 @@ bool EDBM_select_interior_faces(BMEditMesh *em) } const int i_min = POINTER_AS_INT(BLI_heap_pop_min(fgroup_heap)); - BLI_assert(fgroup_table[i_min] != NULL); + BLI_assert(fgroup_table[i_min] != nullptr); BLI_assert(fgroup_dirty[i_min] == false); - fgroup_table[i_min] = NULL; + fgroup_table[i_min] = nullptr; changed = true; - struct BMFaceLink *f_link; - while ((f_link = BLI_pophead(&fgroup_listbase[i_min]))) { + BMFaceLink *f_link; + while ((f_link = static_cast<BMFaceLink *>(BLI_pophead(&fgroup_listbase[i_min])))) { BMFace *f = f_link->face; BM_face_select_set(bm, f, true); BM_elem_index_set(f, -1); /* set-dirty */ @@ -3040,21 +3049,21 @@ bool EDBM_select_interior_faces(BMEditMesh *em) /* Merge the groups. */ LISTBASE_FOREACH (LinkData *, n, &fgroup_listbase[i_b]) { - BMFace *f_iter = n->data; + BMFace *f_iter = static_cast<BMFace *>(n->data); BM_elem_index_set(f_iter, i_a); } BLI_movelisttolist(&fgroup_listbase[i_a], &fgroup_listbase[i_b]); /* This may have been added to 'fgroup_recalc_stack', instead of removing it, - * just check the heap node isn't NULL before recalculating. */ + * just check the heap node isn't nullptr before recalculating. */ BLI_heap_remove(fgroup_heap, fgroup_table[i_b]); - fgroup_table[i_b] = NULL; + fgroup_table[i_b] = nullptr; /* Keep the dirty flag as-is for 'i_b', because it may be in the 'fgroup_recalc_stack' * and we don't want to add it again. - * Instead rely on the 'fgroup_table[i_b]' being NULL as a secondary check. */ + * Instead rely on the 'fgroup_table[i_b]' being nullptr as a secondary check. */ if (fgroup_dirty[i_a] == false) { - BLI_assert(fgroup_table[i_a] != NULL); + BLI_assert(fgroup_table[i_a] != nullptr); STACK_PUSH(fgroup_recalc_stack, i_a); fgroup_dirty[i_a] = true; } @@ -3067,7 +3076,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) do { int i_other = BM_elem_index_get(l_radial_iter->f); if (!ELEM(i_other, -1, i_min)) { - if ((fgroup_table[i_other] != NULL) && (fgroup_dirty[i_other] == false)) { + if ((fgroup_table[i_other] != nullptr) && (fgroup_dirty[i_other] == false)) { #if !defined(USE_DELAY_FACE_GROUP_COST_CALC) STACK_PUSH(fgroup_recalc_stack, i_other); #endif @@ -3082,7 +3091,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) for (int index = 0; index < STACK_SIZE(fgroup_recalc_stack); index++) { const int i = fgroup_recalc_stack[index]; - if (fgroup_table[i] != NULL && fgroup_dirty[i] == true) { + if (fgroup_table[i] != nullptr && fgroup_dirty[i] == true) { /* First update edge tags. */ const float cost = bm_interior_face_group_calc_cost(&fgroup_listbase[i], edge_lengths); if (cost != FLT_MAX) { @@ -3090,7 +3099,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) } else { BLI_heap_remove(fgroup_heap, fgroup_table[i]); - fgroup_table[i] = NULL; + fgroup_table[i] = nullptr; } } fgroup_dirty[i] = false; @@ -3105,7 +3114,7 @@ bool EDBM_select_interior_faces(BMEditMesh *em) MEM_freeN(fgroup_table); MEM_freeN(fgroup_dirty); - BLI_heap_free(fgroup_heap, NULL); + BLI_heap_free(fgroup_heap, nullptr); return changed; } @@ -3126,9 +3135,7 @@ struct DelimitData { int cd_loop_offset; }; -static bool select_linked_delimit_test(BMEdge *e, - int delimit, - const struct DelimitData *delimit_data) +static bool select_linked_delimit_test(BMEdge *e, int delimit, const DelimitData *delimit_data) { BLI_assert(delimit); @@ -3208,7 +3215,7 @@ static void select_linked_delimit_validate(BMesh *bm, int *delimit) static void select_linked_delimit_begin(BMesh *bm, int delimit) { - struct DelimitData delimit_data = {0}; + DelimitData delimit_data = {0}; if (delimit & BMO_DELIM_UV) { delimit_data.cd_loop_type = CD_MLOOPUV; @@ -3218,7 +3225,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit) } } - /* grr, shouldn't need to alloc BMO flags here */ + /* Shouldn't need to allocated BMO flags here (sigh). */ BM_mesh_elem_toolflags_ensure(bm); { @@ -3439,7 +3446,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) select_linked_delimit_end(em); } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -3603,7 +3610,7 @@ static void edbm_select_linked_pick_ex(BMEditMesh *em, BMElem *ele, bool sel, in static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; - Base *basact = NULL; + Base *basact = nullptr; BMVert *eve; BMEdge *eed; BMFace *efa; @@ -3679,7 +3686,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE RNA_int_set(op->ptr, "index", index); } - DEG_id_tag_update(basact->object->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(basact->object->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, basact->object->data); MEM_freeN(bases); @@ -3688,19 +3695,19 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) { - Object *obedit = NULL; + Object *obedit = nullptr; BMElem *ele; { const Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); /* Intentionally wrap negative values so the lookup fails. */ - const uint object_index = (uint)RNA_int_get(op->ptr, "object_index"); - const uint index = (uint)RNA_int_get(op->ptr, "index"); + const uint object_index = uint(RNA_int_get(op->ptr, "object_index")); + const uint index = uint(RNA_int_get(op->ptr, "index")); ele = EDBM_elem_from_index_any_multi(scene, view_layer, object_index, index, &obedit); } - if (ele == NULL) { + if (ele == nullptr) { return OPERATOR_CANCELLED; } @@ -3715,7 +3722,7 @@ static int edbm_select_linked_pick_exec(bContext *C, wmOperator *op) edbm_select_linked_pick_ex(em, ele, sel, delimit); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); return OPERATOR_FINISHED; @@ -3751,9 +3758,9 @@ void MESH_OT_select_linked_pick(wmOperatorType *ot) /* use for redo */ prop = RNA_def_int(ot->srna, "object_index", -1, -1, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE)); } /** \} */ @@ -3812,7 +3819,7 @@ static int edbm_select_face_by_sides_exec(bContext *C, wmOperator *op) EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -3827,7 +3834,7 @@ void MESH_OT_select_face_by_sides(wmOperatorType *ot) {1, "EQUAL", 0, "Equal To", ""}, {2, "GREATER", 0, "Greater Than", ""}, {3, "NOTEQUAL", 0, "Not Equal To", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -3912,7 +3919,7 @@ static int edbm_select_loose_exec(bContext *C, wmOperator *op) EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -3972,14 +3979,19 @@ static int edbm_select_mirror_exec(bContext *C, wmOperator *op) for (int axis = 0; axis < 3; axis++) { if ((1 << axis) & axis_flag) { - EDBM_select_mirrored(em, obedit->data, axis, extend, &tot_mirr_iter, &tot_fail_iter); + EDBM_select_mirrored(em, + static_cast<const Mesh *>(obedit->data), + axis, + extend, + &tot_mirr_iter, + &tot_fail_iter); } } if (tot_mirr_iter) { EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -4039,7 +4051,7 @@ static int edbm_select_more_exec(bContext *C, wmOperator *op) } EDBM_select_more(em, use_face_step); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -4090,7 +4102,7 @@ static int edbm_select_less_exec(bContext *C, wmOperator *op) } EDBM_select_less(em, use_face_step); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -4147,7 +4159,7 @@ static bool bm_edge_is_select_isolated(BMEdge *e) * order, starting from h_act. Deselects elements if the depth when they * are reached is not a multiple of "nth". */ static void walker_deselect_nth(BMEditMesh *em, - const struct CheckerIntervalParams *op_params, + const CheckerIntervalParams *op_params, BMHeader *h_act) { BMElem *ele; @@ -4158,7 +4170,7 @@ static void walker_deselect_nth(BMEditMesh *em, short mask_vert = 0, mask_edge = 0, mask_face = 0; /* No active element from which to start - nothing to do */ - if (h_act == NULL) { + if (h_act == nullptr) { return; } @@ -4187,12 +4199,12 @@ static void walker_deselect_nth(BMEditMesh *em, break; } - /* grr, shouldn't need to alloc BMO flags here */ + /* Shouldn't need to allocate BMO flags here (sigh). */ BM_mesh_elem_toolflags_ensure(bm); /* Walker restrictions uses BMO flags, not header flags, * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ - BMO_push(bm, NULL); + BMO_push(bm, nullptr); BM_ITER_MESH (ele, &iter, bm, itertype) { if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { BMO_elem_flag_enable(bm, (BMElemF *)ele, BMO_ELE_TAG); @@ -4206,7 +4218,7 @@ static void walker_deselect_nth(BMEditMesh *em, mask_vert, mask_edge, mask_face, - BMW_FLAG_NOP, /* don't use BMW_FLAG_TEST_HIDDEN here since we want to desel all */ + BMW_FLAG_NOP, /* Don't use #BMW_FLAG_TEST_HIDDEN here since we want to deselect all. */ BMW_NIL_LAY); /* use tag to avoid touching the same verts twice */ @@ -4215,7 +4227,8 @@ static void walker_deselect_nth(BMEditMesh *em, } BLI_assert(walker.order == BMW_BREADTH_FIRST); - for (ele = BMW_begin(&walker, h_act); ele != NULL; ele = BMW_step(&walker)) { + for (ele = static_cast<BMElem *>(BMW_begin(&walker, h_act)); ele != nullptr; + ele = static_cast<BMElem *>(BMW_step(&walker))) { if (!BM_elem_flag_test(ele, BM_ELEM_TAG)) { /* Deselect elements that aren't at "nth" depth from active */ const int depth = BMW_current_depth(&walker) - 1; @@ -4238,9 +4251,9 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, BMIter iter; BMElem *ele; - *r_eve = NULL; - *r_eed = NULL; - *r_efa = NULL; + *r_eve = nullptr; + *r_eed = nullptr; + *r_efa = nullptr; EDBM_selectmode_flush(em); ele = BM_mesh_active_elem_get(em->bm); @@ -4286,7 +4299,7 @@ static void deselect_nth_active(BMEditMesh *em, BMVert **r_eve, BMEdge **r_eed, } } -static bool edbm_deselect_nth(BMEditMesh *em, const struct CheckerIntervalParams *op_params) +static bool edbm_deselect_nth(BMEditMesh *em, const CheckerIntervalParams *op_params) { BMVert *v; BMEdge *e; @@ -4314,7 +4327,7 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op) { const Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - struct CheckerIntervalParams op_params; + CheckerIntervalParams op_params; WM_operator_properties_checker_interval_from_op(op, &op_params); bool found_active_elt = false; @@ -4332,12 +4345,11 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op) if (edbm_deselect_nth(em, &op_params) == true) { found_active_elt = true; - EDBM_update(obedit->data, - &(const struct EDBMUpdate_Params){ - .calc_looptri = false, - .calc_normals = false, - .is_destructive = false, - }); + EDBMUpdate_Params params{}; + params.calc_looptri = false; + params.calc_normals = false; + params.is_destructive = false; + EDBM_update(static_cast<Mesh *>(obedit->data), ¶ms); } } MEM_freeN(objects); @@ -4422,7 +4434,7 @@ static int edbm_select_sharp_edges_exec(bContext *C, wmOperator *op) else { EDBM_selectmode_flush(em); } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -4450,7 +4462,7 @@ void MESH_OT_edges_select_sharp(wmOperatorType *ot) prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, - NULL, + nullptr, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", @@ -4484,7 +4496,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) continue; } - BLI_LINKSTACK_DECLARE(stack, BMFace *); + blender::Vector<BMFace *> stack; BMIter iter, liter, liter2; BMFace *f; @@ -4492,8 +4504,6 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) BM_mesh_elem_hflag_disable_all(bm, BM_FACE, BM_ELEM_TAG, false); - BLI_LINKSTACK_INIT(stack); - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { if ((BM_elem_flag_test(f, BM_ELEM_HIDDEN) != 0) || (BM_elem_flag_test(f, BM_ELEM_TAG) != 0) || @@ -4501,7 +4511,7 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) continue; } - BLI_assert(BLI_LINKSTACK_SIZE(stack) == 0); + BLI_assert(stack.is_empty()); do { BM_face_select_set(bm, f, true); @@ -4520,16 +4530,14 @@ static int edbm_select_linked_flat_faces_exec(bContext *C, wmOperator *op) angle_cos = dot_v3v3(f->no, l2->f->no); if (angle_cos > angle_limit_cos) { - BLI_LINKSTACK_PUSH(stack, l2->f); + stack.append(l2->f); } } } - } while ((f = BLI_LINKSTACK_POP(stack))); + } while (!stack.is_empty() && (f = stack.pop_last())); } - BLI_LINKSTACK_FREE(stack); - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -4557,7 +4565,7 @@ void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) prop = RNA_def_float_rotation(ot->srna, "sharpness", 0, - NULL, + nullptr, DEG2RADF(0.01f), DEG2RADF(180.0f), "Sharpness", @@ -4634,7 +4642,7 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op) } } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); EDBM_selectmode_flush(em); @@ -4706,7 +4714,8 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) if (em->selectmode & SCE_SELECT_VERTEX) { int elem_map_len = 0; - BMVert **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__); + BMVert **elem_map = static_cast<BMVert **>( + MEM_mallocN(sizeof(*elem_map) * em->bm->totvert, __func__)); BMVert *eve; BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { @@ -4723,7 +4732,8 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) } else if (em->selectmode & SCE_SELECT_EDGE) { int elem_map_len = 0; - BMEdge **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__); + BMEdge **elem_map = static_cast<BMEdge **>( + MEM_mallocN(sizeof(*elem_map) * em->bm->totedge, __func__)); BMEdge *eed; BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { @@ -4739,7 +4749,8 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) } else { int elem_map_len = 0; - BMFace **elem_map = MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__); + BMFace **elem_map = static_cast<BMFace **>( + MEM_mallocN(sizeof(*elem_map) * em->bm->totface, __func__)); BMFace *efa; BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { @@ -4762,7 +4773,7 @@ static int edbm_select_random_exec(bContext *C, wmOperator *op) EDBM_deselect_flush(em); } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } @@ -4849,9 +4860,9 @@ static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + MDeformVert *dv = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset)); /* no dv or dv set with no weight */ - if (ELEM(NULL, dv, dv->dw)) { + if (ELEM(nullptr, dv, dv->dw)) { BM_vert_select_set(em->bm, eve, true); changed = true; } @@ -4860,7 +4871,7 @@ static int edbm_select_ungrouped_exec(bContext *C, wmOperator *op) if (changed) { EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } } @@ -4908,7 +4919,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) const int axis = RNA_enum_get(op->ptr, "axis"); const int sign = RNA_enum_get(op->ptr, "sign"); - if (v_act == NULL) { + if (v_act == nullptr) { BKE_report( op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); return OPERATOR_CANCELLED; @@ -4919,7 +4930,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) float value; float axis_mat[3][3]; - /* 3D view variables may be NULL, (no need to check in poll function). */ + /* 3D view variables may be nullptr, (no need to check in poll function). */ ED_transform_calc_orientation_from_type_ex(scene, view_layer, CTX_wm_view3d(C), @@ -4991,7 +5002,7 @@ static int edbm_select_axis_exec(bContext *C, wmOperator *op) if (changed) { EDBM_selectmode_flush(em_iter); WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit_iter->data); - DEG_id_tag_update(obedit_iter->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit_iter->data), ID_RECALC_SELECT); } } MEM_freeN(objects); @@ -5004,7 +5015,7 @@ void MESH_OT_select_axis(wmOperatorType *ot) {SELECT_AXIS_POS, "POS", 0, "Positive Axis", ""}, {SELECT_AXIS_NEG, "NEG", 0, "Negative Axis", ""}, {SELECT_AXIS_ALIGN, "ALIGN", 0, "Aligned Axis", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -5128,21 +5139,18 @@ void MESH_OT_region_to_loop(wmOperatorType *ot) static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ***region_out) { - BMFace **region = NULL; - BMFace **stack = NULL; - BLI_array_declare(region); - BLI_array_declare(stack); - BMFace *f; + blender::Vector<BMFace *> stack; + blender::Vector<BMFace *> region; - BLI_array_append(stack, l->f); + stack.append(l->f); BLI_gset_insert(visit_face_set, l->f); - while (BLI_array_len(stack) > 0) { + while (!stack.is_empty()) { BMIter liter1, liter2; BMLoop *l1, *l2; - f = BLI_array_pop(stack); - BLI_array_append(region, f); + BMFace *f = stack.pop_last(); + region.append(f); BM_ITER_ELEM (l1, &liter1, f, BM_LOOPS_OF_FACE) { if (BM_elem_flag_test(l1->e, flag)) { @@ -5157,16 +5165,17 @@ static int loop_find_region(BMLoop *l, int flag, GSet *visit_face_set, BMFace ** } if (BLI_gset_add(visit_face_set, l2->f)) { - BLI_array_append(stack, l2->f); + stack.append(l2->f); } } } } - BLI_array_free(stack); - - *region_out = region; - return BLI_array_len(region); + BMFace **region_alloc = static_cast<BMFace **>( + MEM_malloc_arrayN(region.size(), sizeof(BMFace *), __func__)); + memcpy(region_alloc, region.data(), region.as_span().size_in_bytes()); + *region_out = region_alloc; + return region.size(); } static int verg_radial(const void *va, const void *vb) @@ -5197,11 +5206,11 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) GSet *visit_face_set; BMIter iter; const int edges_len = em->bm->totedgesel; - BMEdge *e, **edges; + BMEdge *e; int count = 0, i; visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len); - edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__); + BMEdge **edges = static_cast<BMEdge **>(MEM_mallocN(sizeof(*edges) * edges_len, __func__)); i = 0; BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { @@ -5220,7 +5229,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) for (i = 0; i < edges_len; i++) { BMIter liter; BMLoop *l; - BMFace **region = NULL, **region_out; + BMFace **region = nullptr, **region_out; int c, tot = 0; e = edges[i]; @@ -5269,7 +5278,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger) } MEM_freeN(edges); - BLI_gset_free(visit_face_set, NULL); + BLI_gset_free(visit_face_set, nullptr); return count; } @@ -5312,7 +5321,7 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op) EDBM_selectmode_flush(em); - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 9f90ccc30ab..e6505715324 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -192,7 +192,7 @@ void MESH_OT_loopcut(struct wmOperatorType *ot); void MESH_OT_rip(struct wmOperatorType *ot); void MESH_OT_rip_edge(struct wmOperatorType *ot); -/* *** editmesh_select.c *** */ +/* *** editmesh_select.cc *** */ void MESH_OT_select_similar(struct wmOperatorType *ot); void MESH_OT_select_similar_region(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 21e56531096..2f18922f4ee 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -570,7 +570,9 @@ bool ED_object_parent_set(ReportList *reports, pchan = BKE_pose_channel_active_if_layer_visible(par); pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval); - if (pchan == NULL) { + if (pchan == NULL || pchan_eval == NULL) { + /* If pchan_eval is NULL, pchan should also be NULL. */ + BLI_assert_msg(pchan == NULL, "Missing evaluated bone data"); BKE_report(reports, RPT_ERROR, "No active bone"); return false; } diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 119758f3335..bde73402277 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -34,6 +34,7 @@ set(SRC screendump.c workspace_edit.c workspace_layout_edit.c + workspace_listen.cc screen_intern.h ) diff --git a/source/blender/editors/screen/workspace_listen.cc b/source/blender/editors/screen/workspace_listen.cc new file mode 100644 index 00000000000..84326007d66 --- /dev/null +++ b/source/blender/editors/screen/workspace_listen.cc @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_context.h" + +#include "ED_screen.h" +#include "ED_viewer_path.hh" + +#include "WM_api.h" + +/** + * Checks if the viewer path stored in the workspace is still active and resets it if not. + * The viewer path stored in the workspace is the ground truth for other editors, so it should be + * updated before other editors look at it. + */ +static void validate_viewer_paths(bContext &C, WorkSpace &workspace) +{ + if (BLI_listbase_is_empty(&workspace.viewer_path.path)) { + return; + } + + const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path = + blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace.viewer_path); + if (parsed_path.has_value() && + blender::ed::viewer_path::is_active_geometry_nodes_viewer(C, *parsed_path)) { + /* The current viewer path is still valid and active. */ + return; + } + /* Reset inactive viewer path. */ + BKE_viewer_path_clear(&workspace.viewer_path); + WM_event_add_notifier(&C, NC_VIEWER_PATH, nullptr); +} + +void ED_workspace_do_listen(bContext *C, const wmNotifier * /*note*/) +{ + WorkSpace *workspace = CTX_wm_workspace(C); + validate_viewer_paths(*C, *workspace); +} diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ae068f87095..f0194f1b93b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1268,11 +1268,11 @@ static bool sculpt_brush_use_topology_rake(const SculptSession *ss, const Brush /** * Test whether the #StrokeCache.sculpt_normal needs update in #do_brush_action */ -static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush) +static int sculpt_brush_needs_normal(const SculptSession *ss, Sculpt *sd, const Brush *brush) { return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(brush->sculpt_tool) && (ss->cache->normal_weight > 0.0f)) || - + SCULPT_automasking_needs_normal(ss, sd, brush) || ELEM(brush->sculpt_tool, SCULPT_TOOL_BLOB, SCULPT_TOOL_CREASE, @@ -2413,7 +2413,8 @@ float SCULPT_brush_strength_factor(SculptSession *ss, const float fno[3], float mask, const PBVHVertRef vertex, - int thread_id) + const int thread_id, + AutomaskingNodeData *automask_data) { StrokeCache *cache = ss->cache; const Scene *scene = cache->vc->scene; @@ -2497,7 +2498,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, avg *= 1.0f - mask; /* Auto-masking. */ - avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex); + avg *= SCULPT_automasking_factor_get(cache->automasking, ss, vertex, automask_data); return avg; } @@ -3087,7 +3088,8 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + NULL); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -3359,6 +3361,8 @@ static void do_brush_action(Sculpt *sd, /* Initialize auto-masking cache. */ if (SCULPT_is_automasking_enabled(sd, ss, brush)) { ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); + ss->last_automasking_settings_hash = SCULPT_automasking_settings_hash( + ob, ss->cache->automasking); } /* Initialize surface smooth cache. */ if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) && @@ -3389,7 +3393,7 @@ static void do_brush_action(Sculpt *sd, BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); } - if (sculpt_brush_needs_normal(ss, brush)) { + if (sculpt_brush_needs_normal(ss, sd, brush)) { update_sculpt_normal(sd, ob, nodes, totnode); } @@ -3541,6 +3545,12 @@ static void do_brush_action(Sculpt *sd, SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); } + if (!SCULPT_tool_can_reuse_automask(brush->sculpt_tool) || + (ss->cache->supports_gravity && sd->gravity_factor > 0.0f)) { + /* Clear cavity mask cache. */ + ss->last_automasking_settings_hash = 0; + } + /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ if (ss->cache->supports_gravity && !ELEM(brush->sculpt_tool, SCULPT_TOOL_CLOTH, @@ -4334,6 +4344,10 @@ static void sculpt_update_cache_invariants( cache->original = true; } + if (SCULPT_automasking_needs_original(sd, brush)) { + cache->original = true; + } + /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it * should work the opposite way. */ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) { @@ -5393,6 +5407,9 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f SCULPT_undo_push_begin_ex(ob, sculpt_tool_name(sd)); } + SCULPT_stroke_id_next(ob); + ss->cache->stroke_id = ss->stroke_id; + return true; } return false; @@ -5535,6 +5552,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str if (SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) { SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_IMAGE); } + else { + BKE_sculpt_attributes_destroy_temporary_stroke(ob); + } } else { SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); @@ -5991,4 +6011,91 @@ void SCULPT_fake_neighbors_free(Object *ob) sculpt_pose_fake_neighbors_free(ss); } +void SCULPT_automasking_node_begin(Object *ob, + const SculptSession *UNUSED(ss), + AutomaskingCache *automasking, + AutomaskingNodeData *node_data, + PBVHNode *node) +{ + if (!automasking) { + memset(node_data, 0, sizeof(*node_data)); + return; + } + + node_data->node = node; + node_data->have_orig_data = automasking->settings.flags & + (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL); + + if (node_data->have_orig_data) { + SCULPT_orig_vert_data_init(&node_data->orig_data, ob, node, SCULPT_UNDO_COORDS); + } + else { + memset(&node_data->orig_data, 0, sizeof(node_data->orig_data)); + } +} + +void SCULPT_automasking_node_update(SculptSession *UNUSED(ss), + AutomaskingNodeData *automask_data, + PBVHVertexIter *vd) +{ + if (automask_data->have_orig_data) { + SCULPT_orig_vert_data_update(&automask_data->orig_data, vd); + } +} + +bool SCULPT_vertex_is_occluded(SculptSession *ss, PBVHVertRef vertex, bool original) +{ + float ray_start[3], ray_end[3], ray_normal[3], face_normal[3]; + float co[3]; + + copy_v3_v3(co, SCULPT_vertex_co_get(ss, vertex)); + float mouse[2]; + + ED_view3d_project_float_v2_m4(ss->cache->vc->region, co, mouse, ss->cache->projection_mat); + + int depth = SCULPT_raycast_init(ss->cache->vc, mouse, ray_end, ray_start, ray_normal, original); + + negate_v3(ray_normal); + + copy_v3_v3(ray_start, SCULPT_vertex_co_get(ss, vertex)); + madd_v3_v3fl(ray_start, ray_normal, 0.002); + + SculptRaycastData srd = {0}; + srd.original = original; + srd.ss = ss; + srd.hit = false; + srd.ray_start = ray_start; + srd.ray_normal = ray_normal; + srd.depth = depth; + srd.face_normal = face_normal; + + isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal); + BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original); + + return srd.hit; +} + +void SCULPT_stroke_id_next(Object *ob) +{ + /* Manually wrap in int32 space to avoid tripping up undefined behavior + * sanitizers. + */ + ob->sculpt->stroke_id = (uchar)(((int)ob->sculpt->stroke_id + 1) & 255); +} + +void SCULPT_stroke_id_ensure(Object *ob) +{ + SculptSession *ss = ob->sculpt; + + if (!ss->attrs.automasking_stroke_id) { + SculptAttributeParams params = {0}; + ss->attrs.automasking_stroke_id = BKE_sculpt_attribute_ensure( + ob, + ATTR_DOMAIN_POINT, + CD_PROP_INT8, + SCULPT_ATTRIBUTE_NAME(automasking_stroke_id), + ¶ms); + } +} + /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index e8d934f146c..f0ce901e059 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -7,17 +7,22 @@ #include "MEM_guardedalloc.h" +#include "BLI_array.hh" #include "BLI_blenlib.h" #include "BLI_hash.h" #include "BLI_index_range.hh" #include "BLI_math.h" +#include "BLI_math_vec_types.hh" +#include "BLI_set.hh" #include "BLI_task.h" +#include "BLI_vector.hh" #include "DNA_brush_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" @@ -47,7 +52,10 @@ #include <cmath> #include <cstdlib> +using blender::float3; using blender::IndexRange; +using blender::Set; +using blender::Vector; AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss) { @@ -64,10 +72,13 @@ bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, const Brush *br, const eAutomasking_flag mode) { + int automasking = sd->automasking_flags; + if (br) { - return br->automasking_flags & mode || sd->automasking_flags & mode; + automasking |= br->automasking_flags; } - return sd->automasking_flags & mode; + + return (eAutomasking_flag)automasking & mode; } bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br) @@ -87,17 +98,85 @@ bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, co if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) { return true; } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BRUSH_NORMAL)) { + return true; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_VIEW_NORMAL)) { + return true; + } + if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_CAVITY_ALL)) { + return true; + } + return false; } static int sculpt_automasking_mode_effective_bits(const Sculpt *sculpt, const Brush *brush) { if (brush) { - return sculpt->automasking_flags | brush->automasking_flags; + int flags = sculpt->automasking_flags | brush->automasking_flags; + + /* Check if we are using brush cavity settings. */ + if (brush->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL) { + flags &= ~(BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_CAVITY_USE_CURVE | + BRUSH_AUTOMASKING_CAVITY_NORMAL); + flags |= brush->automasking_flags; + } + else if (sculpt->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL) { + flags &= ~(BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_CAVITY_USE_CURVE | + BRUSH_AUTOMASKING_CAVITY_NORMAL); + flags |= sculpt->automasking_flags; + } + + return flags; } return sculpt->automasking_flags; } +bool SCULPT_automasking_needs_normal(const SculptSession * /*ss*/, + const Sculpt *sculpt, + const Brush *brush) +{ + int flags = sculpt_automasking_mode_effective_bits(sculpt, brush); + + return flags & (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL); +} + +static float sculpt_automasking_normal_calc(SculptSession *ss, + PBVHVertRef vertex, + float3 &normal, + float limit_lower, + float limit_upper, + AutomaskingNodeData *automask_data) +{ + float3 normal_v; + + if (automask_data->have_orig_data) { + normal_v = automask_data->orig_data.no; + } + else { + SCULPT_vertex_normal_get(ss, vertex, normal_v); + } + + float angle = saacos(dot_v3v3(normal, normal_v)); + + /* note that limit is pre-divided by M_PI */ + + if (angle > limit_lower && angle < limit_upper) { + float t = 1.0f - (angle - limit_lower) / (limit_upper - limit_lower); + + /* smoothstep */ + t = t * t * (3.0 - 2.0 * t); + + return t; + } + else if (angle > limit_upper) { + return 0.0f; + } + + return 1.0f; +} + static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush *brush) { @@ -105,18 +184,324 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush if (automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) { return true; } - if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) { - return brush && brush->automasking_boundary_edges_propagation_steps != 1; - } - if (automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS) { + + if (automasking_flags & + (BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS | + BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL)) { return brush && brush->automasking_boundary_edges_propagation_steps != 1; } return false; } +static float automasking_brush_normal_factor(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vertex, + AutomaskingNodeData *automask_data) +{ + float falloff = automasking->settings.start_normal_falloff * M_PI; + float3 initial_normal; + + if (ss->cache) { + initial_normal = ss->cache->initial_normal; + } + else { + initial_normal = ss->filter_cache->initial_normal; + } + + return sculpt_automasking_normal_calc(ss, + vertex, + initial_normal, + automasking->settings.start_normal_limit - falloff * 0.5f, + automasking->settings.start_normal_limit + falloff * 0.5f, + automask_data); +} + +static float automasking_view_normal_factor(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vertex, + AutomaskingNodeData *automask_data) +{ + float falloff = automasking->settings.view_normal_falloff * M_PI; + + float3 view_normal; + + if (ss->cache) { + view_normal = ss->cache->view_normal; + } + else { + view_normal = ss->filter_cache->view_normal; + } + + return sculpt_automasking_normal_calc(ss, + vertex, + view_normal, + automasking->settings.view_normal_limit, + automasking->settings.view_normal_limit + falloff, + automask_data); +} + +static float automasking_view_occlusion_factor(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vertex, + uchar stroke_id, + AutomaskingNodeData * /*automask_data*/) +{ + char f = *(char *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_occlusion); + + if (stroke_id != automasking->current_stroke_id) { + f = *(char *)SCULPT_vertex_attr_get( + vertex, + ss->attrs.automasking_occlusion) = SCULPT_vertex_is_occluded(ss, vertex, true) ? 2 : 1; + } + + return f == 2; +} + +/* Updates vertex stroke id. */ +static float automasking_factor_end(SculptSession *ss, + AutomaskingCache *automasking, + PBVHVertRef vertex, + float value) +{ + if (ss->attrs.automasking_stroke_id) { + *(uchar *)SCULPT_vertex_attr_get( + vertex, ss->attrs.automasking_stroke_id) = automasking->current_stroke_id; + } + + return value; +} + +static float sculpt_cavity_calc_factor(AutomaskingCache *automasking, float factor) +{ + float sign = signf(factor); + + factor = fabsf(factor) * automasking->settings.cavity_factor * 50.0f; + + factor = factor * sign * 0.5f + 0.5f; + CLAMP(factor, 0.0f, 1.0f); + + return (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_INVERTED) ? 1.0f - factor : + factor; +} + +struct CavityBlurVert { + PBVHVertRef vertex; + float dist; + int depth; + + CavityBlurVert(PBVHVertRef vertex_, float dist_, int depth_) + : vertex(vertex_), dist(dist_), depth(depth_) + { + } + + CavityBlurVert() = default; +}; + +static void sculpt_calc_blurred_cavity(SculptSession *ss, + AutomaskingCache *automasking, + int steps, + PBVHVertRef vertex) +{ + float3 sno1(0.0f); + float3 sno2(0.0f); + float3 sco1(0.0f); + float3 sco2(0.0f); + float len1_sum = 0.0f; + int sco1_len = 0, sco2_len = 0; + + /* Steps starts at 1, but API and user interface + * are zero-based. + */ + steps++; + + Vector<CavityBlurVert, 64> queue; + Set<int64_t, 64> visit; + + int start = 0, end = 0; + + queue.resize(64); + + CavityBlurVert initial(vertex, 0.0f, 0); + + visit.add_new(vertex.i); + queue[0] = initial; + end = 1; + + const float *co1 = SCULPT_vertex_co_get(ss, vertex); + + while (start != end) { + CavityBlurVert &blurvert = queue[start]; + PBVHVertRef v = blurvert.vertex; + start = (start + 1) % queue.size(); + + float3 no; + + const float *co = SCULPT_vertex_co_get(ss, v); + SCULPT_vertex_normal_get(ss, v, no); + + float centdist = len_v3v3(co, co1); + + sco1 += co; + sno1 += no; + len1_sum += centdist; + sco1_len++; + + if (blurvert.depth < steps) { + sco2 += co; + sno2 += no; + sco2_len++; + } + + if (blurvert.depth >= steps) { + continue; + } + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v, ni) { + PBVHVertRef v2 = ni.vertex; + + if (visit.contains(v2.i)) { + continue; + } + + float dist = len_v3v3(SCULPT_vertex_co_get(ss, v2), SCULPT_vertex_co_get(ss, v)); + + visit.add_new(v2.i); + CavityBlurVert blurvert2(v2, dist, blurvert.depth + 1); + + int nextend = (end + 1) % queue.size(); + + if (nextend == start) { + int oldsize = queue.size(); + + queue.resize(queue.size() << 1); + + if (end < start) { + int n = oldsize - start; + + for (int i = 0; i < n; i++) { + queue[queue.size() - n + i] = queue[i + start]; + } + + start = queue.size() - n; + } + } + + queue[end] = blurvert2; + end = (end + 1) % queue.size(); + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } + + BLI_assert(sco1_len != sco2_len); + + if (!sco1_len) { + sco1 = SCULPT_vertex_co_get(ss, vertex); + } + else { + sco1 /= float(sco1_len); + len1_sum /= sco1_len; + } + + if (!sco2_len) { + sco2 = SCULPT_vertex_co_get(ss, vertex); + } + else { + sco2 /= float(sco2_len); + } + + normalize_v3(sno1); + if (dot_v3v3(sno1, sno1) == 0.0f) { + SCULPT_vertex_normal_get(ss, vertex, sno1); + } + + normalize_v3(sno2); + if (dot_v3v3(sno2, sno2) == 0.0f) { + SCULPT_vertex_normal_get(ss, vertex, sno2); + } + + float3 vec = sco1 - sco2; + float factor_sum = dot_v3v3(vec, sno2) / len1_sum; + + factor_sum = sculpt_cavity_calc_factor(automasking, factor_sum); + + *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_cavity) = factor_sum; +} + +int SCULPT_automasking_settings_hash(Object *ob, AutomaskingCache *automasking) +{ + SculptSession *ss = ob->sculpt; + + int hash; + int totvert = SCULPT_vertex_count_get(ss); + + hash = BLI_hash_int(automasking->settings.flags); + hash = BLI_hash_int_2d(hash, totvert); + + if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { + hash = BLI_hash_int_2d(hash, automasking->settings.cavity_blur_steps); + hash = BLI_hash_int_2d(hash, *reinterpret_cast<uint *>(&automasking->settings.cavity_factor)); + + if (automasking->settings.cavity_curve) { + CurveMap *cm = automasking->settings.cavity_curve->cm; + + for (int i = 0; i < cm->totpoint; i++) { + hash = BLI_hash_int_2d(hash, *reinterpret_cast<uint *>(&cm->curve[i].x)); + hash = BLI_hash_int_2d(hash, *reinterpret_cast<uint *>(&cm->curve[i].y)); + hash = BLI_hash_int_2d(hash, uint(cm->curve[i].flag)); + hash = BLI_hash_int_2d(hash, uint(cm->curve[i].shorty)); + } + } + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { + hash = BLI_hash_int_2d(hash, automasking->settings.initial_face_set); + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL) { + hash = BLI_hash_int_2d(hash, + *reinterpret_cast<uint *>(&automasking->settings.view_normal_falloff)); + hash = BLI_hash_int_2d(hash, + *reinterpret_cast<uint *>(&automasking->settings.view_normal_limit)); + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL) { + hash = BLI_hash_int_2d(hash, + *reinterpret_cast<uint *>(&automasking->settings.start_normal_falloff)); + hash = BLI_hash_int_2d(hash, + *reinterpret_cast<uint *>(&automasking->settings.start_normal_limit)); + } + + return hash; +} + +static float sculpt_automasking_cavity_factor(AutomaskingCache *automasking, + SculptSession *ss, + PBVHVertRef vertex) +{ + uchar stroke_id = *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_stroke_id); + + if (stroke_id != automasking->current_stroke_id) { + sculpt_calc_blurred_cavity(ss, automasking, automasking->settings.cavity_blur_steps, vertex); + } + + float factor = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_cavity); + bool inverted = automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_INVERTED; + + if ((automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) && + (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_USE_CURVE)) { + factor = inverted ? 1.0f - factor : factor; + factor = BKE_curvemapping_evaluateF(automasking->settings.cavity_curve, 0, factor); + factor = inverted ? 1.0f - factor : factor; + } + + return factor; +} + float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, - PBVHVertRef vert) + PBVHVertRef vert, + AutomaskingNodeData *automask_data) { if (!automasking) { return 1.0f; @@ -126,7 +511,25 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, * automasking information can't be computed in real time per vertex and needs to be * initialized for the whole mesh when the stroke starts. */ if (ss->attrs.automasking_factor) { - return *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); + float factor = *(float *)SCULPT_vertex_attr_get(vert, ss->attrs.automasking_factor); + + if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { + factor *= sculpt_automasking_cavity_factor(automasking, ss, vert); + } + + return factor; + } + + uchar stroke_id = ss->attrs.automasking_stroke_id ? + *(uchar *)(SCULPT_vertex_attr_get(vert, ss->attrs.automasking_stroke_id)) : + -1; + + bool do_occlusion = (automasking->settings.flags & + (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL)) == + (BRUSH_AUTOMASKING_VIEW_OCCLUSION | BRUSH_AUTOMASKING_VIEW_NORMAL); + if (do_occlusion && + automasking_view_occlusion_factor(automasking, ss, vert, stroke_id, automask_data)) { + return automasking_factor_end(ss, automasking, vert, 0.0f); } if (automasking->settings.flags & BRUSH_AUTOMASKING_FACE_SETS) { @@ -147,7 +550,23 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking, } } - return 1.0f; + float mask = 1.0f; + + if ((ss->cache || ss->filter_cache) && + (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) { + mask *= automasking_brush_normal_factor(automasking, ss, vert, automask_data); + } + + if ((ss->cache || ss->filter_cache) && + (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) { + mask *= automasking_view_normal_factor(automasking, ss, vert, automask_data); + } + + if (automasking->settings.flags & BRUSH_AUTOMASKING_CAVITY_ALL) { + mask *= sculpt_automasking_cavity_factor(automasking, ss, vert); + } + + return automasking_factor_end(ss, automasking, vert, mask); } void SCULPT_automasking_cache_free(AutomaskingCache *automasking) @@ -179,11 +598,8 @@ struct AutomaskFloodFillData { char symm; }; -static bool automask_floodfill_cb(SculptSession *ss, - PBVHVertRef from_v, - PBVHVertRef to_v, - bool UNUSED(is_duplicate), - void *userdata) +static bool automask_floodfill_cb( + SculptSession *ss, PBVHVertRef from_v, PBVHVertRef to_v, bool /*is_duplicate*/, void *userdata) { AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata; @@ -200,7 +616,7 @@ static void SCULPT_topology_automasking_init(Sculpt *sd, Object *ob) Brush *brush = BKE_paint_brush(&sd->paint); if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { - BLI_assert_msg(0, "Topology masking: pmap missing"); + BLI_assert_unreachable(); return; } @@ -328,6 +744,66 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski { automasking->settings.flags = sculpt_automasking_mode_effective_bits(sd, brush); automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss); + + automasking->settings.view_normal_limit = sd->automasking_view_normal_limit; + automasking->settings.view_normal_falloff = sd->automasking_view_normal_falloff; + automasking->settings.start_normal_limit = sd->automasking_start_normal_limit; + automasking->settings.start_normal_falloff = sd->automasking_start_normal_falloff; + + if (brush && (brush->automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) { + automasking->settings.cavity_curve = brush->automasking_cavity_curve; + automasking->settings.cavity_factor = brush->automasking_cavity_factor; + automasking->settings.cavity_blur_steps = brush->automasking_cavity_blur_steps; + } + else { + automasking->settings.cavity_curve = sd->automasking_cavity_curve; + automasking->settings.cavity_factor = sd->automasking_cavity_factor; + automasking->settings.cavity_blur_steps = sd->automasking_cavity_blur_steps; + } +} + +static void sculpt_normal_occlusion_automasking_fill(AutomaskingCache *automasking, + Object *ob, + eAutomasking_flag mode) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + /* No need to build original data since this is only called at the beginning of strokes.*/ + AutomaskingNodeData nodedata; + nodedata.have_orig_data = false; + + for (int i = 0; i < totvert; i++) { + PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + + float f = *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor); + + if (int(mode) & BRUSH_AUTOMASKING_BRUSH_NORMAL) { + f *= automasking_brush_normal_factor(automasking, ss, vertex, &nodedata); + } + if (int(mode) & BRUSH_AUTOMASKING_VIEW_NORMAL) { + if (int(mode) & BRUSH_AUTOMASKING_VIEW_OCCLUSION) { + f *= automasking_view_occlusion_factor(automasking, ss, vertex, -1, &nodedata); + } + + f *= automasking_view_normal_factor(automasking, ss, vertex, &nodedata); + } + + if (ss->attrs.automasking_stroke_id) { + *(uchar *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_stroke_id) = ss->stroke_id; + } + + *(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor) = f; + } +} + +bool SCULPT_tool_can_reuse_automask(int sculpt_tool) +{ + return ELEM(sculpt_tool, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR, + SCULPT_TOOL_MASK, + SCULPT_TOOL_DRAW_FACE_SETS); } AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob) @@ -344,6 +820,64 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush); SCULPT_boundary_info_ensure(ob); + automasking->current_stroke_id = ss->stroke_id; + + bool use_stroke_id = false; + int mode = sculpt_automasking_mode_effective_bits(sd, brush); + + if ((mode & BRUSH_AUTOMASKING_VIEW_OCCLUSION) && (mode & BRUSH_AUTOMASKING_VIEW_NORMAL)) { + use_stroke_id = true; + + if (!ss->attrs.automasking_occlusion) { + SculptAttributeParams params = {0}; + ss->attrs.automasking_occlusion = BKE_sculpt_attribute_ensure( + ob, + ATTR_DOMAIN_POINT, + CD_PROP_INT8, + SCULPT_ATTRIBUTE_NAME(automasking_occlusion), + ¶ms); + } + } + + if (mode & BRUSH_AUTOMASKING_CAVITY_ALL) { + use_stroke_id = true; + + if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_CAVITY_USE_CURVE)) { + BKE_curvemapping_init(brush->automasking_cavity_curve); + BKE_curvemapping_init(sd->automasking_cavity_curve); + } + + if (!ss->attrs.automasking_cavity) { + SculptAttributeParams params = {0}; + ss->attrs.automasking_cavity = BKE_sculpt_attribute_ensure( + ob, + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + SCULPT_ATTRIBUTE_NAME(automasking_cavity), + ¶ms); + } + } + + if (use_stroke_id) { + SCULPT_stroke_id_ensure(ob); + + bool have_occlusion = (mode & BRUSH_AUTOMASKING_VIEW_OCCLUSION) && + (mode & BRUSH_AUTOMASKING_VIEW_NORMAL); + + if (brush && SCULPT_tool_can_reuse_automask(brush->sculpt_tool) && !have_occlusion) { + int hash = SCULPT_automasking_settings_hash(ob, automasking); + + if (hash == ss->last_automasking_settings_hash) { + automasking->current_stroke_id = ss->last_automask_stroke_id; + automasking->can_reuse_mask = true; + } + } + + if (!automasking->can_reuse_mask) { + ss->last_automask_stroke_id = ss->stroke_id; + } + } + if (!SCULPT_automasking_needs_factors_cache(sd, brush)) { return automasking; } @@ -354,16 +888,31 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object ss->attrs.automasking_factor = BKE_sculpt_attribute_ensure( ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(automasking_factor), ¶ms); + float initial_value; + + /* Topology, boundary and boundary face sets build up the mask + * from zero which other modes can subtract from. If none of them are + * enabled initialize to 1. + */ + if (!(mode & (BRUSH_AUTOMASKING_BOUNDARY_EDGES | BRUSH_AUTOMASKING_TOPOLOGY | + BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS))) { + initial_value = 1.0f; + } + else { + initial_value = 0.0f; + } + for (int i : IndexRange(totvert)) { PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); - (*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor)) = 0.0f; + (*(float *)SCULPT_vertex_attr_get(vertex, ss->attrs.automasking_factor)) = initial_value; } const int boundary_propagation_steps = brush ? brush->automasking_boundary_edges_propagation_steps : 1; + /* Additive modes. */ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) { SCULPT_vertex_random_access_ensure(ss); SCULPT_topology_automasking_init(sd, ob); @@ -383,5 +932,22 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object ob, AUTOMASK_INIT_BOUNDARY_FACE_SETS, boundary_propagation_steps); } + /* Subtractive modes. */ + int normal_bits = sculpt_automasking_mode_effective_bits(sd, brush) & + (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL | + BRUSH_AUTOMASKING_VIEW_OCCLUSION); + + if (normal_bits) { + sculpt_normal_occlusion_automasking_fill(automasking, ob, (eAutomasking_flag)normal_bits); + } + return automasking; } + +bool SCULPT_automasking_needs_original(const Sculpt *sd, const Brush *brush) +{ + + return sculpt_automasking_mode_effective_bits(sd, brush) & + (BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_BRUSH_NORMAL | + BRUSH_AUTOMASKING_VIEW_NORMAL); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index 98f3d3a4472..ca7cf87bf3d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -681,12 +681,16 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, angle_factor = floorf(angle_factor * 10) / 10.0f; } const float angle = angle_factor * M_PI; + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].propagation_steps_num == -1) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_orig_vert_data_update(&orig_data, &vd); if (!SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { @@ -694,7 +698,8 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]); @@ -729,12 +734,16 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].propagation_steps_num == -1) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_orig_vert_data_update(&orig_data, &vd); if (!SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { @@ -742,7 +751,8 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -773,6 +783,9 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, PBVHVertexIter vd; SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary); @@ -781,6 +794,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_orig_vert_data_update(&orig_data, &vd); if (!SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { @@ -788,7 +802,8 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -819,12 +834,16 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, PBVHVertexIter vd; SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (boundary->edit_info[vd.index].propagation_steps_num == -1) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_orig_vert_data_update(&orig_data, &vd); if (!SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { @@ -832,7 +851,8 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, @@ -862,6 +882,9 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, PBVHVertexIter vd; SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary); float angle_factor = disp / ss->cache->radius; @@ -876,6 +899,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); SCULPT_orig_vert_data_update(&orig_data, &vd); if (!SCULPT_check_vertex_pivot_symmetry( orig_data.co, boundary->initial_vertex_position, symm)) { @@ -883,7 +907,8 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, } const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); float t_orig_co[3]; float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position); diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c index b9cc3f984d1..8cf0dafdd15 100644 --- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -302,10 +302,17 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + /* Offset vertex. */ const float fade = SCULPT_brush_strength_factor(ss, brush, @@ -315,7 +322,8 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -387,6 +395,10 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -405,6 +417,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -413,7 +427,8 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -485,6 +500,10 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -503,6 +522,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -511,7 +532,8 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -601,6 +623,10 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, /* Tilted plane (front part of the brush). */ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -621,6 +647,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix); sub_v3_v3v3(val, intr_tilt, vd.co); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -629,7 +657,8 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -764,6 +793,10 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -776,6 +809,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, sub_v3_v3v3(val, intr, vd.co); if (SCULPT_plane_trim(ss->cache, brush, val)) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -784,7 +819,8 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -922,6 +958,10 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -933,6 +973,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, sub_v3_v3v3(val, intr, vd.co); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -941,7 +983,8 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -1041,6 +1084,10 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { continue; @@ -1058,6 +1105,9 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, if (!SCULPT_plane_trim(ss->cache, brush, val)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */ const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, @@ -1067,7 +1117,8 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -1202,6 +1253,10 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, KelvinletParams params; BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { continue; @@ -1212,6 +1267,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, fade = 1.0f; } else { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1220,7 +1277,8 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); } mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -1267,7 +1325,9 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, if (vd.mask) { mul_v3_fl(disp, 1.0f - *vd.mask); } - mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); + mul_v3_fl( + disp, + SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex, &automask_data)); copy_v3_v3(proxy[vd.i], disp); } @@ -1339,12 +1399,18 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, orig_data.co, @@ -1353,7 +1419,8 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1412,6 +1479,10 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); @@ -1427,7 +1498,8 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -1485,12 +1557,18 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1499,7 +1577,8 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); const int vi = vd.index; float *disp_factor; @@ -1600,10 +1679,16 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1612,7 +1697,8 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float val[3]; if (vd.fno) { @@ -1668,10 +1754,16 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1680,7 +1772,8 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -1746,11 +1839,17 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } /* Offset vertex. */ + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1759,7 +1858,8 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float val1[3]; float val2[3]; @@ -1863,10 +1963,16 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, copy_v3_v3(x_object_space, stroke_xz[0]); copy_v3_v3(z_object_space, stroke_xz[1]); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -1875,7 +1981,8 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float disp_center[3]; float x_disp[3]; float z_disp[3]; @@ -1977,12 +2084,18 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, orig_data.co, @@ -1991,7 +2104,8 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); if (grab_silhouette) { float silhouette_test_dir[3]; @@ -2055,6 +2169,9 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, const float bstrength = ss->cache->bstrength; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; @@ -2110,7 +2227,9 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, mul_v3_fl(final_disp, 1.0f - *vd.mask); } - mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex)); + mul_v3_fl( + final_disp, + SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex, &automask_data)); copy_v3_v3(proxy[vd.i], final_disp); @@ -2174,12 +2293,18 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } /* Offset vertex. */ + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, brush, orig_data.co, @@ -2188,7 +2313,8 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2258,11 +2384,17 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, brush, orig_data.co, @@ -2271,7 +2403,8 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float current_disp[3]; float current_disp_norm[3]; float final_disp[3] = {0.0f, 0.0f, 0.0f}; @@ -2415,11 +2548,17 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, brush, orig_data.co, @@ -2428,7 +2567,8 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); if (vd.is_mesh) { @@ -2491,11 +2631,17 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -2504,7 +2650,8 @@ static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float limit_co[3]; float disp[3]; @@ -2557,11 +2704,17 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -2570,7 +2723,8 @@ static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float current_disp[3]; float current_disp_norm[3]; @@ -2718,16 +2872,29 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } - const float fade = - bstrength * - SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.vertex, thread_id) * - ss->cache->pressure; + SCULPT_automasking_node_update(ss, &automask_data, &vd); + + const float fade = bstrength * + SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + *vd.mask, + vd.vertex, + thread_id, + &automask_data) * + ss->cache->pressure; float avg[3], val[3]; @@ -2797,13 +2964,26 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } - const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.vertex, thread_id); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + 0.0f, + vd.vertex, + thread_id, + &automask_data); if (bstrength > 0.0f) { (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index 8ad0176dfa4..6df94eb5177 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -504,7 +504,13 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, madd_v3_v3fl(gravity, ss->cache->gravity_direction, -data->sd->gravity_factor); } + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float force[3]; float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); @@ -544,7 +550,8 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float brush_disp[3]; @@ -765,8 +772,13 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( } AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); const float sim_factor = @@ -788,7 +800,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex( mul_v3_fl(pos_diff, (1.0f - cloth_sim->damping) * sim_factor); const float mask_v = (1.0f - (vd.mask ? *vd.mask : 0.0f)) * - SCULPT_automasking_factor_get(automasking, ss, vd.vertex); + SCULPT_automasking_factor_get(automasking, ss, vd.vertex, &automask_data); madd_v3_v3fl(cloth_sim->pos[i], pos_diff, mask_v); madd_v3_v3fl(cloth_sim->pos[i], cloth_sim->acceleration[i], mask_v); @@ -821,6 +833,9 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, { AutomaskingCache *automasking = SCULPT_automasking_active_cache_get(ss); + AutomaskingNodeData automask_data = {0}; + + automask_data.have_orig_data = true; for (int constraint_it = 0; constraint_it < CLOTH_SIMULATION_ITERATIONS; constraint_it++) { for (int i = 0; i < cloth_sim->tot_length_constraints; i++) { @@ -859,10 +874,17 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss, PBVHVertRef vertex1 = BKE_pbvh_index_to_vertex(ss->pbvh, v1); PBVHVertRef vertex2 = BKE_pbvh_index_to_vertex(ss->pbvh, v2); + automask_data.orig_data.co = cloth_sim->init_pos[v1]; + automask_data.orig_data.no = cloth_sim->init_no[v1]; const float mask_v1 = (1.0f - SCULPT_vertex_mask_get(ss, vertex1)) * - SCULPT_automasking_factor_get(automasking, ss, vertex1); + SCULPT_automasking_factor_get( + automasking, ss, vertex1, &automask_data); + + automask_data.orig_data.co = cloth_sim->init_pos[v2]; + automask_data.orig_data.no = cloth_sim->init_no[v2]; const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, vertex2)) * - SCULPT_automasking_factor_get(automasking, ss, vertex2); + SCULPT_automasking_factor_get( + automasking, ss, vertex2, &automask_data); float sim_location[3]; cloth_brush_simulation_location_get(ss, brush, sim_location); @@ -1065,6 +1087,7 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(Object *ob, cloth_sim->last_iteration_pos = MEM_calloc_arrayN( totverts, sizeof(float[3]), "cloth sim last iteration pos"); cloth_sim->init_pos = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim init pos"); + cloth_sim->init_no = MEM_calloc_arrayN(totverts, sizeof(float[3]), "cloth sim init normals"); cloth_sim->length_constraint_tweak = MEM_calloc_arrayN( totverts, sizeof(float), "cloth sim length tweak"); @@ -1140,6 +1163,7 @@ void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation copy_v3_v3(cloth_sim->last_iteration_pos[i], SCULPT_vertex_co_get(ss, vertex)); copy_v3_v3(cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, vertex)); + SCULPT_vertex_normal_get(ss, vertex, cloth_sim->init_no[i]); copy_v3_v3(cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, vertex)); if (has_deformation_pos) { copy_v3_v3(cloth_sim->deformation_pos[i], SCULPT_vertex_co_get(ss, vertex)); @@ -1253,6 +1277,7 @@ void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim) MEM_SAFE_FREE(cloth_sim->deformation_pos); MEM_SAFE_FREE(cloth_sim->softbody_pos); MEM_SAFE_FREE(cloth_sim->init_pos); + MEM_SAFE_FREE(cloth_sim->init_no); MEM_SAFE_FREE(cloth_sim->deformation_strength); MEM_SAFE_FREE(cloth_sim->node_state); BLI_ghash_free(cloth_sim->node_state_index, NULL, NULL); @@ -1434,11 +1459,17 @@ static void cloth_filter_apply_forces_task_cb(void *__restrict userdata, sculpt_gravity[2] = -1.0f; } mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, SCULPT_automasking_active_cache_get(ss), &automask_data, node); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float fade = vd.mask ? *vd.mask : 0.0f; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); + fade *= SCULPT_automasking_factor_get( + ss->filter_cache->automasking, ss, vd.vertex, &automask_data); fade = 1.0f - fade; float force[3] = {0.0f, 0.0f, 0.0f}; float disp[3], temp[3], transform[3][3]; @@ -1580,8 +1611,11 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent /* Needs mask data to be available as it is used when solving the constraints. */ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + SCULPT_stroke_id_next(ob); + SCULPT_undo_push_begin(ob, op); - SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); + SCULPT_filter_cache_init( + C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius")); ss->filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob); @@ -1644,14 +1678,14 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* RNA. */ + SCULPT_mesh_filter_properties(ot); + RNA_def_enum(ot->srna, "type", prop_cloth_filter_type, CLOTH_FILTER_GRAVITY, "Filter Type", "Operation that is going to be applied to the mesh"); - RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); RNA_def_enum_flag(ot->srna, "force_axis", prop_cloth_filter_force_axis_items, diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index b5bcd0ba85f..0dda912a4fe 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -147,8 +147,13 @@ static void SCULPT_dynamic_topology_disable_ex( SculptSession *ss = ob->sculpt; Mesh *me = ob->data; - BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_vertex); - BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_face); + if (ss->attrs.dyntopo_node_id_vertex) { + BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_vertex); + } + + if (ss->attrs.dyntopo_node_id_face) { + BKE_sculpt_attribute_destroy(ob, ss->attrs.dyntopo_node_id_face); + } SCULPT_pbvh_clear(ob); diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c index 72b0b3a97fe..ecf296fbd66 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_expand.c @@ -2102,6 +2102,8 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SCULPT_stroke_id_next(ob); + /* Create and configure the Expand Cache. */ ss->expand_cache = MEM_callocN(sizeof(ExpandCache), "expand cache"); sculpt_expand_cache_initial_config_set(C, op, ss->expand_cache); diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 1b732a709c3..cc120e55c30 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -129,8 +129,13 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, const int thread_id = BLI_task_parallel_thread_id(tls); const float(*positions)[3] = SCULPT_mesh_deformed_positions_get(ss); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { MeshElemMap *vert_map = &ss->pmap[vd.index]; for (int j = 0; j < ss->pmap[vd.index].count; j++) { @@ -154,7 +159,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); if (fade > 0.05f) { ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set; @@ -173,7 +179,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); if (fade > 0.05f) { SCULPT_vertex_face_set_set(ss, vd.vertex, ss->cache->paint_face_set); @@ -205,8 +212,13 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, } const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } @@ -222,7 +234,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); if (vd.is_mesh) { @@ -237,6 +250,12 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); + if (ss->pbvh) { + Mesh *mesh = BKE_mesh_from_object(ob); + BKE_pbvh_face_sets_color_set( + ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default); + } + BKE_curvemapping_init(brush->curve); /* Threaded loop over nodes. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c index 161fc563950..0d21aa24e7d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c @@ -95,16 +95,23 @@ static void color_filter_task_cb(void *__restrict userdata, SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->filter_cache->automasking, &automask_data, data->nodes[n]); + PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float orig_color[3], final_color[4], hsv_color[3]; int hue; float brightness, contrast, gain, delta, offset; float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); + fade *= SCULPT_automasking_factor_get( + ss->filter_cache->automasking, ss, vd.vertex, &automask_data); if (fade == 0.0f) { continue; } @@ -334,6 +341,9 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent const bool use_automasking = SCULPT_is_automasking_enabled(sd, ss, NULL); if (use_automasking) { + /* Increment stroke id for automasking system. */ + SCULPT_stroke_id_next(ob); + /* Update the active face set manually as the paint cursor is not enabled when using the Mesh * Filter Tool. */ float mval_fl[2] = {UNPACK2(event->mval)}; @@ -358,7 +368,8 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } - SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COLOR); + SCULPT_filter_cache_init( + C, ob, sd, SCULPT_UNDO_COLOR, event->mval, RNA_float_get(op->ptr, "area_normal_radius")); FilterCache *filter_cache = ss->filter_cache; filter_cache->active_face_set = SCULPT_FACE_SET_NONE; filter_cache->automasking = SCULPT_automasking_cache_init(sd, NULL, ob); @@ -383,9 +394,9 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* rna */ + SCULPT_mesh_filter_properties(ot); + RNA_def_enum(ot->srna, "type", prop_color_filter_types, COLOR_FILTER_HUE, "Filter Type", ""); - RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); PropertyRNA *prop = RNA_def_float_color( ot->srna, "fill_color", 3, NULL, 0.0f, FLT_MAX, "Fill Color", "", 0.0f, 1.0f); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index bb27e4f1e9e..c4e719da006 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -303,173 +303,3 @@ void SCULPT_OT_mask_filter(struct wmOperatorType *ot) "Auto Iteration Count", "Use a automatic number of iterations based on the number of vertices of the sculpt"); } - -static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd) -{ - int total = 0; - float avg[3]; - zero_v3(avg); - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->vertex, ni) { - float normalized[3]; - sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.vertex), vd->co); - normalize_v3(normalized); - add_v3_v3(avg, normalized); - total++; - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - if (total > 0) { - mul_v3_fl(avg, 1.0f / total); - float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno); - float angle = max_ff(saacosf(dot), 0.0f); - return angle; - } - return 0.0f; -} - -typedef struct DirtyMaskRangeData { - float min, max; -} DirtyMaskRangeData; - -static void dirty_mask_compute_range_task_cb(void *__restrict userdata, - const int i, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - PBVHNode *node = data->nodes[i]; - DirtyMaskRangeData *range = tls->userdata_chunk; - PBVHVertexIter vd; - - BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - float dirty_mask = neighbor_dirty_mask(ss, &vd); - range->min = min_ff(dirty_mask, range->min); - range->max = max_ff(dirty_mask, range->max); - } - BKE_pbvh_vertex_iter_end; -} - -static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata), - void *__restrict chunk_join, - void *__restrict chunk) -{ - DirtyMaskRangeData *join = chunk_join; - DirtyMaskRangeData *range = chunk; - join->min = min_ff(range->min, join->min); - join->max = max_ff(range->max, join->max); -} - -static void dirty_mask_apply_task_cb(void *__restrict userdata, - const int i, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - PBVHNode *node = data->nodes[i]; - PBVHVertexIter vd; - - const bool dirty_only = data->dirty_mask_dirty_only; - const float min = data->dirty_mask_min; - const float max = data->dirty_mask_max; - - float range = max - min; - if (range < 0.0001f) { - range = 0.0f; - } - else { - range = 1.0f / range; - } - - BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { - float dirty_mask = neighbor_dirty_mask(ss, &vd); - float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range)); - if (dirty_only) { - mask = fminf(mask, 0.5f) * 2.0f; - } - *vd.mask = CLAMPIS(mask, 0.0f, 1.0f); - } - BKE_pbvh_vertex_iter_end; - BKE_pbvh_node_mark_update_mask(node); -} - -static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) -{ - ARegion *region = CTX_wm_region(C); - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - PBVH *pbvh = ob->sculpt->pbvh; - PBVHNode **nodes; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - int totnode; - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - SCULPT_vertex_random_access_ensure(ss); - - if (!ob->sculpt->pmap) { - return OPERATOR_CANCELLED; - } - - BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); - SCULPT_undo_push_begin(ob, op); - - for (int i = 0; i < totnode; i++) { - SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .nodes = nodes, - .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"), - }; - DirtyMaskRangeData range = { - .min = FLT_MAX, - .max = -FLT_MAX, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - - settings.func_reduce = dirty_mask_compute_range_reduce; - settings.userdata_chunk = ⦥ - settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - - BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); - data.dirty_mask_min = range.min; - data.dirty_mask_max = range.max; - BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); - - MEM_SAFE_FREE(nodes); - - BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask); - - SCULPT_undo_push_end(ob); - - ED_region_tag_redraw(region); - - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -void SCULPT_OT_dirty_mask(struct wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Dirty Mask"; - ot->idname = "SCULPT_OT_dirty_mask"; - ot->description = "Generates a mask based on the geometry cavity and pointiness"; - - /* API callbacks. */ - ot->exec = sculpt_dirty_mask_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER; - - /* RNA. */ - RNA_def_boolean( - ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas"); -} diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index ccdede46909..a71ef027dc4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -101,7 +101,12 @@ static void filter_cache_init_task_cb(void *__restrict userdata, SCULPT_undo_push_node(data->ob, node, data->filter_undo_type); } -void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int undo_type) +void SCULPT_filter_cache_init(bContext *C, + Object *ob, + Sculpt *sd, + const int undo_type, + const int mval[2], + float area_normal_radius) { SculptSession *ss = ob->sculpt; PBVH *pbvh = ob->sculpt->pbvh; @@ -159,6 +164,79 @@ void SCULPT_filter_cache_init(bContext *C, Object *ob, Sculpt *sd, const int und ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_m4_m4(ss->filter_cache->viewmat, vc.rv3d->viewmat); copy_m4_m4(ss->filter_cache->viewmat_inv, vc.rv3d->viewinv); + + Scene *scene = CTX_data_scene(C); + UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; + + float co[3]; + float mval_fl[2] = {(float)mval[0], (float)mval[1]}; + + if (SCULPT_stroke_get_location(C, co, mval_fl, false)) { + PBVHNode **nodes; + int totnode; + + /* Get radius from brush. */ + Brush *brush = BKE_paint_brush(&sd->paint); + float radius; + + if (brush) { + if (BKE_brush_use_locked_size(scene, brush)) { + radius = paint_calc_object_space_radius( + &vc, co, (float)BKE_brush_size_get(scene, brush) * area_normal_radius); + } + else { + radius = BKE_brush_unprojected_radius_get(scene, brush) * area_normal_radius; + } + } + else { + radius = paint_calc_object_space_radius(&vc, co, (float)ups->size * area_normal_radius); + } + + SculptSearchSphereData search_data2 = { + .original = true, + .center = co, + .radius_squared = radius * radius, + .ignore_fully_ineffective = true, + }; + + BKE_pbvh_search_gather(pbvh, SCULPT_search_sphere_cb, &search_data2, &nodes, &totnode); + + if (SCULPT_pbvh_calc_area_normal( + brush, ob, nodes, totnode, true, ss->filter_cache->initial_normal)) { + copy_v3_v3(ss->last_normal, ss->filter_cache->initial_normal); + } + else { + copy_v3_v3(ss->filter_cache->initial_normal, ss->last_normal); + } + + MEM_SAFE_FREE(nodes); + + /* Update last stroke location */ + + mul_m4_v3(ob->obmat, co); + + add_v3_v3(ups->average_stroke_accum, co); + ups->average_stroke_counter++; + ups->last_stroke_valid = true; + } + else { + /* Use last normal. */ + copy_v3_v3(ss->filter_cache->initial_normal, ss->last_normal); + } + + /* Update view normal */ + float projection_mat[4][4]; + float mat[3][3]; + float viewDir[3] = {0.0f, 0.0f, 1.0f}; + + ED_view3d_ob_project_mat_get(vc.rv3d, ob, projection_mat); + + invert_m4_m4(ob->imat, ob->obmat); + copy_m3_m4(mat, vc.rv3d->viewinv); + mul_m3_v3(mat, viewDir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, viewDir); + normalize_v3_v3(ss->filter_cache->view_normal, viewDir); } void SCULPT_filter_cache_free(SculptSession *ss) @@ -288,15 +366,20 @@ static void mesh_filter_task_cb(void *__restrict userdata, /* This produces better results as the relax operation is no completely focused on the * boundaries. */ const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin(data->ob, ss, ss->filter_cache->automasking, &automask_data, node); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3]; float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); + fade *= SCULPT_automasking_factor_get( + ss->filter_cache->automasking, ss, vd.vertex, &automask_data); if (fade == 0.0f && filter_type != MESH_FILTER_SURFACE_SMOOTH) { /* Surface Smooth can't skip the loop for this vertex as it needs to calculate its @@ -580,11 +663,18 @@ static void mesh_filter_surface_smooth_displace_task_cb( PBVHNode *node = data->nodes[i]; PBVHVertexIter vd; + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->filter_cache->automasking, &automask_data, data->nodes[i]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; - fade *= SCULPT_automasking_factor_get(ss->filter_cache->automasking, ss, vd.vertex); + fade *= SCULPT_automasking_factor_get( + ss->filter_cache->automasking, ss, vd.vertex, &automask_data); if (fade == 0.0f) { continue; } @@ -681,6 +771,9 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent } if (use_automasking) { + /* Increment stroke id for automasking system. */ + SCULPT_stroke_id_next(ob); + /* Update the active face set manually as the paint cursor is not enabled when using the Mesh * Filter Tool. */ float mval_fl[2] = {UNPACK2(event->mval)}; @@ -696,7 +789,8 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent SCULPT_undo_push_begin(ob, op); - SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); + SCULPT_filter_cache_init( + C, ob, sd, SCULPT_UNDO_COORDS, event->mval, RNA_float_get(op->ptr, "area_normal_radius")); FilterCache *filter_cache = ss->filter_cache; filter_cache->active_face_set = SCULPT_FACE_SET_NONE; @@ -743,6 +837,22 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_RUNNING_MODAL; } +void SCULPT_mesh_filter_properties(struct wmOperatorType *ot) +{ + RNA_def_float( + ot->srna, + "area_normal_radius", + 0.25, + 0.001, + 5.0, + "Normal Radius", + "Radius used for calculating area normal on initial click,\nin percentage of brush radius", + 0.01, + 1.0); + RNA_def_float( + ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); +} + void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) { /* Identifiers. */ @@ -758,14 +868,14 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* RNA. */ + SCULPT_mesh_filter_properties(ot); + RNA_def_enum(ot->srna, "type", prop_mesh_filter_types, MESH_FILTER_INFLATE, "Filter Type", "Operation that is going to be applied to the mesh"); - RNA_def_float( - ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter strength", -10.0f, 10.0f); RNA_def_enum_flag(ot->srna, "deform_axis", prop_mesh_filter_deform_axis_items, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 8dc7224769b..cc65f2b715b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -27,6 +27,7 @@ extern "C" { #endif struct AutomaskingCache; +struct AutomaskingNodeData; struct Image; struct ImageUser; struct KeyBlock; @@ -311,10 +312,6 @@ typedef struct SculptThreadedTaskData { float *cloth_sim_initial_location; float cloth_sim_radius; - float dirty_mask_min; - float dirty_mask_max; - bool dirty_mask_dirty_only; - /* Mask By Color Tool */ float mask_by_color_threshold; @@ -398,10 +395,20 @@ typedef struct AutomaskingSettings { /* Flags from eAutomasking_flag. */ int flags; int initial_face_set; + + float cavity_factor; + int cavity_blur_steps; + struct CurveMapping *cavity_curve; + + float start_normal_limit, start_normal_falloff; + float view_normal_limit, view_normal_falloff; } AutomaskingSettings; typedef struct AutomaskingCache { AutomaskingSettings settings; + + bool can_reuse_mask; + uchar current_stroke_id; } AutomaskingCache; typedef struct FilterCache { @@ -461,6 +468,8 @@ typedef struct FilterCache { /* Auto-masking. */ AutomaskingCache *automasking; + float initial_normal[3]; + float view_normal[3]; /* Pre-smoothed colors used by sharpening. Colors are HSL. */ float (*pre_smoothed_color)[4]; @@ -633,6 +642,7 @@ typedef struct StrokeCache { rcti previous_r; /* previous redraw rectangle */ rcti current_r; /* current redraw rectangle */ + int stroke_id; } StrokeCache; /* -------------------------------------------------------------------- */ @@ -910,6 +920,8 @@ float SCULPT_vertex_mask_get(struct SculptSession *ss, PBVHVertRef vertex); void SCULPT_vertex_color_get(const SculptSession *ss, PBVHVertRef vertex, float r_color[4]); void SCULPT_vertex_color_set(SculptSession *ss, PBVHVertRef vertex, const float color[4]); +bool SCULPT_vertex_is_occluded(SculptSession *ss, PBVHVertRef vertex, bool original); + /** Returns true if a color attribute exists in the current sculpt session. */ bool SCULPT_has_colors(const SculptSession *ss); @@ -1191,7 +1203,8 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss, const float fno[3], float mask, const PBVHVertRef vertex, - int thread_id); + int thread_id, + struct AutomaskingNodeData *automask_data); /** * Tilts a normal by the x and y tilt values using the view axis. @@ -1279,9 +1292,30 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); /** \name Auto-masking. * \{ */ +typedef struct AutomaskingNodeData { + PBVHNode *node; + SculptOrigVertData orig_data; + bool have_orig_data; +} AutomaskingNodeData; + +/** Call before PBVH vertex iteration. + * \param automask_data: pointer to an uninitialized AutomaskingNodeData struct. + */ +void SCULPT_automasking_node_begin(struct Object *ob, + const SculptSession *ss, + struct AutomaskingCache *automasking, + AutomaskingNodeData *automask_data, + PBVHNode *node); + +/* Call before SCULPT_automasking_factor_get and SCULPT_brush_strength_factor. */ +void SCULPT_automasking_node_update(SculptSession *ss, + AutomaskingNodeData *automask_data, + PBVHVertexIter *vd); + float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, SculptSession *ss, - PBVHVertRef vertex); + PBVHVertRef vertex, + AutomaskingNodeData *automask_data); /* Returns the automasking cache depending on the active tool. Used for code that can run both for * brushes and filter. */ @@ -1297,6 +1331,12 @@ float *SCULPT_boundary_automasking_init(Object *ob, eBoundaryAutomaskMode mode, int propagation_steps, float *automask_factor); +bool SCULPT_automasking_needs_normal(const SculptSession *ss, + const Sculpt *sculpt, + const Brush *brush); +bool SCULPT_automasking_needs_original(const struct Sculpt *sd, const struct Brush *brush); +int SCULPT_automasking_settings_hash(Object *ob, AutomaskingCache *automasking); + /** \} */ /* -------------------------------------------------------------------- */ @@ -1323,8 +1363,14 @@ float *SCULPT_geodesic_from_vertex(Object *ob, PBVHVertRef vertex, float limit_r /** \name Filter API * \{ */ -void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type); +void SCULPT_filter_cache_init(struct bContext *C, + Object *ob, + Sculpt *sd, + int undo_type, + const int mval[2], + float area_normal_radius); void SCULPT_filter_cache_free(SculptSession *ss); +void SCULPT_mesh_filter_properties(struct wmOperatorType *ot); void SCULPT_mask_filter_smooth_apply( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations); @@ -1587,7 +1633,6 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot); /* Mask filter and Dirty Mask. */ void SCULPT_OT_mask_filter(struct wmOperatorType *ot); -void SCULPT_OT_dirty_mask(struct wmOperatorType *ot); /* Mask and Face Sets Expand. */ @@ -1842,6 +1887,10 @@ BLI_INLINE bool SCULPT_tool_is_face_sets(int tool) return ELEM(tool, SCULPT_TOOL_DRAW_FACE_SETS); } +void SCULPT_stroke_id_ensure(struct Object *ob); +void SCULPT_stroke_id_next(struct Object *ob); +bool SCULPT_tool_can_reuse_automask(int sculpt_tool); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index 1e8d7361b11..f891812ae67 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -69,6 +69,10 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, test_radius *= brush->normal_radius_factor; test.radius_squared = test_radius * test_radius; + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -78,6 +82,9 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, float normal[3]; copy_v3_v3(normal, vd.no ? vd.no : vd.fno); mul_v3_m4v3(local_co, mat, vd.co); + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + /* Use the brush falloff to weight the sampled normals. */ const float fade = SCULPT_brush_strength_factor(ss, brush, @@ -87,7 +94,8 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); /* Sample the normal and area of the +X and -X axis individually. */ if (local_co[0] > 0.0f) { @@ -144,6 +152,10 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -184,6 +196,9 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, if (!SCULPT_plane_trim(ss->cache, brush, val)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + /* Deform the local space along the Y axis to avoid artifacts on curved strokes. */ /* This produces a not round brush tip. */ local_co[1] *= 2.0f; @@ -195,7 +210,8 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); mul_v3_v3fl(proxy[vd.i], val, fade); diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c index 52bfa61cd95..ea2261559ef 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.c +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -98,6 +98,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_path.h" #include "UI_interface.h" #include "UI_resources.h" @@ -1002,6 +1003,273 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot) 1.0f); } +typedef enum { + AUTOMASK_BAKE_MIX, + AUTOMASK_BAKE_MULTIPLY, + AUTOMASK_BAKE_DIVIDE, + AUTOMASK_BAKE_ADD, + AUTOMASK_BAKE_SUBTRACT, +} CavityBakeMixMode; + +typedef struct AutomaskBakeTaskData { + SculptSession *ss; + AutomaskingCache *automasking; + PBVHNode **nodes; + CavityBakeMixMode mode; + float factor; + Object *ob; +} AutomaskBakeTaskData; + +static void sculpt_bake_cavity_exec_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + AutomaskBakeTaskData *tdata = userdata; + SculptSession *ss = tdata->ss; + PBVHNode *node = tdata->nodes[n]; + PBVHVertexIter vd; + const CavityBakeMixMode mode = tdata->mode; + const float factor = tdata->factor; + + SCULPT_undo_push_node(tdata->ob, node, SCULPT_UNDO_MASK); + + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin(tdata->ob, ss, tdata->automasking, &automask_data, node); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { + SCULPT_automasking_node_update(ss, &automask_data, &vd); + + float automask = SCULPT_automasking_factor_get( + tdata->automasking, ss, vd.vertex, &automask_data); + float mask; + + switch (mode) { + case AUTOMASK_BAKE_MIX: + mask = automask; + break; + case AUTOMASK_BAKE_MULTIPLY: + mask = *vd.mask * automask; + break; + break; + case AUTOMASK_BAKE_DIVIDE: + mask = automask > 0.00001f ? *vd.mask / automask : 0.0f; + break; + break; + case AUTOMASK_BAKE_ADD: + mask = *vd.mask + automask; + break; + case AUTOMASK_BAKE_SUBTRACT: + mask = *vd.mask - automask; + break; + } + + mask = *vd.mask + (mask - *vd.mask) * factor; + CLAMP(mask, 0.0f, 1.0f); + + *vd.mask = mask; + } + BKE_pbvh_vertex_iter_end; + + BKE_pbvh_node_mark_update_mask(node); +} + +static int sculpt_bake_cavity_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + SCULPT_vertex_random_access_ensure(ss); + + MultiresModifierData *mmd = BKE_sculpt_multires_active(CTX_data_scene(C), ob); + BKE_sculpt_mask_layers_ensure(ob, mmd); + + SCULPT_undo_push_begin(ob, op); + + CavityBakeMixMode mode = RNA_enum_get(op->ptr, "mix_mode"); + float factor = RNA_float_get(op->ptr, "mix_factor"); + + PBVHNode **nodes; + int totnode; + + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + AutomaskBakeTaskData tdata; + + /* Set up automasking settings. + */ + Sculpt sd2 = *sd; + + /* Override cavity mask settings if use_automask_settings is false. */ + if (!RNA_boolean_get(op->ptr, "use_automask_settings")) { + if (RNA_boolean_get(op->ptr, "invert")) { + sd2.automasking_flags = BRUSH_AUTOMASKING_CAVITY_INVERTED; + } + else { + sd2.automasking_flags = BRUSH_AUTOMASKING_CAVITY_NORMAL; + } + + if (RNA_boolean_get(op->ptr, "use_curve")) { + sd2.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_USE_CURVE; + } + + sd2.automasking_cavity_blur_steps = RNA_int_get(op->ptr, "blur_steps"); + sd2.automasking_cavity_factor = RNA_float_get(op->ptr, "factor"); + + sd2.automasking_cavity_curve = sd->automasking_cavity_curve_op; + } + else { + sd2.automasking_flags &= BRUSH_AUTOMASKING_CAVITY_ALL | BRUSH_AUTOMASKING_CAVITY_USE_CURVE; + + /* Ensure cavity mask is actually enabled. */ + if (!(sd2.automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) { + sd2.automasking_flags |= BRUSH_AUTOMASKING_CAVITY_NORMAL; + } + } + + /* Create copy of brush with cleared automasking settings. */ + Brush brush2 = *brush; + brush2.automasking_flags = 0; + brush2.automasking_boundary_edges_propagation_steps = 1; + brush2.automasking_cavity_curve = sd2.automasking_cavity_curve; + + SCULPT_stroke_id_next(ob); + + tdata.ob = ob; + tdata.mode = mode; + tdata.factor = factor; + tdata.ss = ss; + tdata.nodes = nodes; + tdata.automasking = SCULPT_automasking_cache_init(&sd2, &brush2, ob); + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &tdata, sculpt_bake_cavity_exec_task_cb, &settings); + + MEM_SAFE_FREE(nodes); + SCULPT_automasking_cache_free(tdata.automasking); + + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + SCULPT_undo_push_end(ob); + + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + + /* Unlike other operators we do not tag the ID for update here; + * it triggers a PBVH rebuild which is too slow and ruins + * the interactivity of the tool. */ + + return OPERATOR_FINISHED; +} + +static void cavity_bake_ui(bContext *C, wmOperator *op) +{ + uiLayout *layout = op->layout; + Scene *scene = CTX_data_scene(C); + Sculpt *sd = scene->toolsettings ? scene->toolsettings->sculpt : NULL; + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + bool use_curve = false; + + if (!sd || !RNA_boolean_get(op->ptr, "use_automask_settings")) { + uiItemR(layout, op->ptr, "mix_mode", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "mix_factor", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "use_automask_settings", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "factor", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "blur_steps", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "invert", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "use_curve", 0, NULL, ICON_NONE); + + use_curve = RNA_boolean_get(op->ptr, "use_curve"); + } + else { + PointerRNA sculpt_ptr; + + RNA_pointer_create(&scene->id, &RNA_Sculpt, sd, &sculpt_ptr); + uiItemR(layout, op->ptr, "mix_mode", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "mix_factor", 0, NULL, ICON_NONE); + uiItemR(layout, op->ptr, "use_automask_settings", 0, NULL, ICON_NONE); + + use_curve = false; + } + + if (use_curve) { + PointerRNA sculpt_ptr; + + const char *curve_prop; + + if (RNA_boolean_get(op->ptr, "use_automask_settings")) { + curve_prop = "automasking_cavity_curve"; + } + else { + curve_prop = "automasking_cavity_curve_op"; + } + + if (scene->toolsettings && scene->toolsettings->sculpt) { + RNA_pointer_create(&scene->id, &RNA_Sculpt, scene->toolsettings->sculpt, &sculpt_ptr); + uiTemplateCurveMapping(layout, &sculpt_ptr, curve_prop, 'v', false, false, false, false); + } + } +} + +static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Mask From Cavity"; + ot->idname = "SCULPT_OT_mask_from_cavity"; + ot->description = "Creates a mask based on the curvature of the surface"; + ot->ui = cavity_bake_ui; + + static EnumPropertyItem mix_modes[] = { + {AUTOMASK_BAKE_MIX, "MIX", ICON_NONE, "Mix", ""}, + {AUTOMASK_BAKE_MULTIPLY, "MULTIPLY", ICON_NONE, "Multiply", ""}, + {AUTOMASK_BAKE_DIVIDE, "DIVIDE", ICON_NONE, "Divide", ""}, + {AUTOMASK_BAKE_ADD, "ADD", ICON_NONE, "Add", ""}, + {AUTOMASK_BAKE_SUBTRACT, "SUBTRACT", ICON_NONE, "Subtract", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + /* api callbacks */ + ot->exec = sculpt_bake_cavity_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "mix_mode", mix_modes, AUTOMASK_BAKE_MIX, "Mode", "Mix mode"); + RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 5.0f, "Mix Factor", "", 0.0f, 1.0f); + + RNA_def_boolean(ot->srna, + "use_automask_settings", + false, + "Use Automask Settings", + "Use default settings from Options panel in sculpt mode"); + + RNA_def_float(ot->srna, + "factor", + 0.5f, + 0.0f, + 5.0f, + "Cavity Factor", + "The contrast of the cavity mask", + 0.0f, + 1.0f); + RNA_def_int(ot->srna, + "blur_steps", + 2, + 0, + 25, + "Cavity Blur", + "The number of times the cavity mask is blurred", + 0, + 25); + RNA_def_boolean(ot->srna, "use_curve", false, "Use Curve", ""); + + RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", ""); +} + void ED_operatortypes_sculpt(void) { WM_operatortype_append(SCULPT_OT_brush_stroke); @@ -1015,7 +1283,6 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_set_detail_size); WM_operatortype_append(SCULPT_OT_mesh_filter); WM_operatortype_append(SCULPT_OT_mask_filter); - WM_operatortype_append(SCULPT_OT_dirty_mask); WM_operatortype_append(SCULPT_OT_mask_expand); WM_operatortype_append(SCULPT_OT_set_pivot_position); WM_operatortype_append(SCULPT_OT_face_sets_create); @@ -1037,4 +1304,5 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_mask_init); WM_operatortype_append(SCULPT_OT_expand); + WM_operatortype_append(SCULPT_OT_mask_from_cavity); } diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c index c494c71f1eb..7946affdec5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c +++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c @@ -70,10 +70,17 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -82,7 +89,8 @@ static void do_color_smooth_task_cb_exec(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float smooth_color[4]; SCULPT_neighbor_color_average(ss, smooth_color, vd.vertex); @@ -125,6 +133,10 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, IMB_colormanagement_srgb_to_scene_linear_v3(brush_color, brush_color); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + if (brush->flag & BRUSH_USE_GRADIENT) { switch (brush->gradient_stroke_mode) { case BRUSH_GRADIENT_PRESSURE: @@ -161,6 +173,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -169,7 +183,8 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); /* Density. */ float noise = 1.0f; @@ -195,8 +210,11 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata, paint_color, paint_color, wet_mix_color, ss->cache->paint_brush.wet_mix); blend_color_mix_float(color_buffer->color[vd.i], color_buffer->color[vd.i], paint_color); - /* Final mix over the original color using brush alpha. */ - mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha); + /* Final mix over the original color using brush alpha. We apply auto-making again + * at this point to avoid washing out non-binary masking modes like cavity masking. */ + float automasking = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); + mul_v4_v4fl(buffer_color, color_buffer->color[vd.i], brush->alpha * automasking); float col[4]; SCULPT_vertex_color_get(ss, vd.vertex, col); @@ -402,10 +420,17 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location); } + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -414,7 +439,8 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float current_disp[3]; float current_disp_norm[3]; diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc index f3ff29294f9..5c7f3ad396b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc +++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc @@ -153,7 +153,10 @@ template<typename ImageBuffer> class PaintingKernel { init_brush_test(); } - bool paint(const Triangles &triangles, const PackedPixelRow &pixel_row, ImBuf *image_buffer) + bool paint(const Triangles &triangles, + const PackedPixelRow &pixel_row, + ImBuf *image_buffer, + AutomaskingNodeData *automask_data) { image_accessor.set_image_position(image_buffer, pixel_row.start_image_coordinate); const TrianglePaintInput triangle = triangles.get_paint_input(pixel_row.triangle_index); @@ -171,6 +174,7 @@ template<typename ImageBuffer> class PaintingKernel { const float3 normal(0.0f, 0.0f, 0.0f); const float3 face_normal(0.0f, 0.0f, 0.0f); const float mask = 0.0f; + const float falloff_strength = SCULPT_brush_strength_factor( ss, brush, @@ -180,7 +184,8 @@ template<typename ImageBuffer> class PaintingKernel { face_normal, mask, BKE_pbvh_make_vref(PBVH_REF_NONE), - thread_id); + thread_id, + automask_data); float4 paint_color = brush_color * falloff_strength * brush_strength; float4 buffer_color; blend_color_mix_float(buffer_color, color, paint_color); @@ -321,6 +326,9 @@ static void do_paint_pixels(void *__restrict userdata, PaintingKernel<ImageBufferFloat4> kernel_float4(ss, brush, thread_id, positions); PaintingKernel<ImageBufferByte4> kernel_byte4(ss, brush, thread_id, positions); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin(ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + ImageUser image_user = *data->image_data.image_user; bool pixels_updated = false; for (UDIMTilePixels &tile_data : node_data.tiles) { @@ -347,10 +355,12 @@ static void do_paint_pixels(void *__restrict userdata, } bool pixels_painted = false; if (image_buffer->rect_float != nullptr) { - pixels_painted = kernel_float4.paint(node_data.triangles, pixel_row, image_buffer); + pixels_painted = kernel_float4.paint( + node_data.triangles, pixel_row, image_buffer, &automask_data); } else { - pixels_painted = kernel_byte4.paint(node_data.triangles, pixel_row, image_buffer); + pixels_painted = kernel_byte4.paint( + node_data.triangles, pixel_row, image_buffer, &automask_data); } if (pixels_painted) { diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index 4bafa99af84..e12f64a1f89 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -157,9 +157,13 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, SculptOrigVertData orig_data; SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); + SCULPT_automasking_node_update(ss, &automask_data, &vd); float total_disp[3]; zero_v3(total_disp); @@ -182,7 +186,8 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata, /* Apply the vertex mask to the displacement. */ const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; - const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.vertex); + const float automask = SCULPT_automasking_factor_get( + ss->cache->automasking, ss, vd.vertex, &automask_data); mul_v3_fl(disp, mask * automask); /* Accumulate the displacement. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 4cba8f78baa..759136cd292 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -217,11 +217,17 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -230,7 +236,8 @@ static void do_enhance_details_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float disp[3]; madd_v3_v3v3fl(disp, vd.co, ss->cache->detail_directions[vd.index], fade); @@ -300,11 +307,17 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor( ss, brush, @@ -314,7 +327,8 @@ static void do_smooth_brush_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), vd.vertex, - thread_id); + thread_id, + &automask_data); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.vertex) - *vd.mask; val *= fade * bstrength; @@ -470,12 +484,18 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( const int thread_id = BLI_task_parallel_thread_id(tls); SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -484,7 +504,8 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); float disp[3]; SCULPT_surface_smooth_laplacian_step( @@ -512,11 +533,17 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); + AutomaskingNodeData automask_data; + SCULPT_automasking_node_begin( + data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (!sculpt_brush_test_sq_fn(&test, vd.co)) { continue; } + + SCULPT_automasking_node_update(ss, &automask_data, &vd); + const float fade = bstrength * SCULPT_brush_strength_factor(ss, brush, vd.co, @@ -525,7 +552,8 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( vd.fno, vd.mask ? *vd.mask : 0.0f, vd.vertex, - thread_id); + thread_id, + &automask_data); SCULPT_surface_smooth_displace_step( ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.vertex, beta, fade); } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index ab29af32ad8..ebb12b84309 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -46,7 +46,10 @@ #include <math.h> #include <stdlib.h> -void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_name) +void ED_sculpt_init_transform(struct bContext *C, + Object *ob, + const int mval[2], + const char *undo_name) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = ob->sculpt; @@ -66,7 +69,8 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob, const char *undo_n ss->pivot_rot[3] = 1.0f; SCULPT_vertex_random_access_ensure(ss); - SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); + + SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS, mval, 5.0); if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) { ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 0d29a1f12e8..4435851b852 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -484,8 +484,13 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode) BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); Mesh *me = BKE_object_get_original_mesh(ob); - int *face_sets = CustomData_add_layer_named( - &me->pdata, CD_PROP_INT32, CD_CONSTRUCT, NULL, me->totpoly, ".sculpt_face_set"); + + int *face_sets = CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set"); + if (!face_sets) { + face_sets = CustomData_add_layer_named( + &me->pdata, CD_PROP_INT32, CD_CONSTRUCT, NULL, me->totpoly, ".sculpt_face_set"); + } + for (int i = 0; i < me->totpoly; i++) { SWAP(int, face_sets[i], unode->face_sets[i]); } @@ -738,8 +743,13 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase bool update = false, rebuild = false, update_mask = false, update_visibility = false; bool need_mask = false; bool need_refine_subdiv = false; + bool clear_automask_cache = false; for (unode = lb->first; unode; unode = unode->next) { + if (!ELEM(unode->type, SCULPT_UNDO_COLOR, SCULPT_UNDO_MASK)) { + clear_automask_cache = true; + } + /* Restore pivot. */ copy_v3_v3(ss->pivot_pos, unode->pivot_pos); copy_v3_v3(ss->pivot_rot, unode->pivot_rot); @@ -753,6 +763,10 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase } } + if (clear_automask_cache) { + ss->last_automasking_settings_hash = 0; + } + DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); if (lb->first) { diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt index b9e27c4de49..3ec814ada48 100644 --- a/source/blender/editors/space_action/CMakeLists.txt +++ b/source/blender/editors/space_action/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../gpu @@ -11,6 +12,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -35,5 +39,5 @@ set(LIB blender_add_lib(bf_editor_space_action "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_action bf_rna) diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index b54750accb0..2f22121f7de 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -42,6 +42,8 @@ #include "ED_space_api.h" #include "ED_time_scrub_ui.h" +#include "BLO_read_write.h" + #include "action_intern.h" /* own include */ /* ******************** default callbacks for action space ***************** */ @@ -834,6 +836,30 @@ static void action_space_subtype_item_extend(bContext *UNUSED(C), RNA_enum_items_add(item, totitem, rna_enum_space_action_mode_items); } +static void action_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceAction *saction = (SpaceAction *)sl; + memset(&saction->runtime, 0x0, sizeof(saction->runtime)); +} + +static void action_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceAction *saction = (SpaceAction *)sl; + bDopeSheet *ads = &saction->ads; + + if (ads) { + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); + } + + BLO_read_id_address(reader, parent_id->lib, &saction->action); +} + +static void action_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceAction, sl); +} + void ED_spacetype_action(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype action"); @@ -854,6 +880,9 @@ void ED_spacetype_action(void) st->space_subtype_item_extend = action_space_subtype_item_extend; st->space_subtype_get = action_space_subtype_get; st->space_subtype_set = action_space_subtype_set; + st->blend_read_data = action_blend_read_data; + st->blend_read_lib = action_blend_read_lib; + st->blend_write = action_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index d0ad510f5cf..53a00b6d70b 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../gpu ../../makesdna @@ -11,6 +12,9 @@ set(INC ../../windowmanager ../../../../intern/guardedalloc ../../bmesh + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -39,5 +43,5 @@ endif() blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_buttons bf_rna) diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 209d60d4f58..5a333869dea 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -37,6 +37,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #include "buttons_intern.h" /* own include */ /* -------------------------------------------------------------------- */ @@ -905,6 +907,31 @@ static void buttons_id_remap(ScrArea *UNUSED(area), } } +static void buttons_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceProperties *sbuts = (SpaceProperties *)sl; + + sbuts->path = NULL; + sbuts->texuser = NULL; + sbuts->mainbo = sbuts->mainb; + sbuts->mainbuser = sbuts->mainb; + sbuts->runtime = NULL; +} + +static void buttons_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceProperties *sbuts = (SpaceProperties *)sl; + BLO_read_id_address(reader, parent_id->lib, &sbuts->pinid); + if (sbuts->pinid == NULL) { + sbuts->flag &= ~SB_PIN_CONTEXT; + } +} + +static void buttons_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceProperties, sl); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -928,6 +955,9 @@ void ED_spacetype_buttons(void) st->listener = buttons_area_listener; st->context = buttons_context; st->id_remap = buttons_id_remap; + st->blend_read_data = buttons_blend_read_data; + st->blend_read_lib = buttons_blend_read_lib; + st->blend_write = buttons_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt index 8cb5299df6d..011072270db 100644 --- a/source/blender/editors/space_clip/CMakeLists.txt +++ b/source/blender/editors/space_clip/CMakeLists.txt @@ -6,6 +6,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../gpu diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index ab952470757..3631a1740f7 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -49,6 +49,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "clip_intern.h" /* own include */ @@ -1245,6 +1247,27 @@ static void clip_id_remap(ScrArea *UNUSED(area), BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL); } +static void clip_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceClip *sclip = (SpaceClip *)sl; + + sclip->scopes.track_search = NULL; + sclip->scopes.track_preview = NULL; + sclip->scopes.ok = 0; +} + +static void clip_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceClip *sclip = (SpaceClip *)sl; + BLO_read_id_address(reader, parent_id->lib, &sclip->clip); + BLO_read_id_address(reader, parent_id->lib, &sclip->mask_info.mask); +} + +static void clip_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceClip, sl); +} + void ED_spacetype_clip(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype clip"); @@ -1265,6 +1288,9 @@ void ED_spacetype_clip(void) st->dropboxes = clip_dropboxes; st->refresh = clip_refresh; st->id_remap = clip_id_remap; + st->blend_read_data = clip_blend_read_data; + st->blend_read_lib = clip_blend_read_lib; + st->blend_write = clip_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region"); diff --git a/source/blender/editors/space_console/CMakeLists.txt b/source/blender/editors/space_console/CMakeLists.txt index 345ab8b0970..51523bcb383 100644 --- a/source/blender/editors/space_console/CMakeLists.txt +++ b/source/blender/editors/space_console/CMakeLists.txt @@ -5,11 +5,15 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../gpu ../../makesdna ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern ) set(SRC @@ -31,3 +35,6 @@ endif() blender_add_lib(bf_editor_space_console "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# dna_type_offsets.h +add_dependencies(bf_editor_space_console bf_dna) diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 8838b5d341f..0abb108d5e8 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -28,6 +28,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "console_intern.h" /* own include */ /* ******************** default callbacks for console space ***************** */ @@ -284,6 +286,41 @@ static void console_main_region_listener(const wmRegionListenerParams *params) } } +static void console_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceConsole *sconsole = (SpaceConsole *)sl; + + BLO_read_list(reader, &sconsole->scrollback); + BLO_read_list(reader, &sconsole->history); + + /* Comma expressions, (e.g. expr1, expr2, expr3) evaluate each expression, + * from left to right. the right-most expression sets the result of the comma + * expression as a whole. */ + LISTBASE_FOREACH_MUTABLE (ConsoleLine *, cl, &sconsole->history) { + BLO_read_data_address(reader, &cl->line); + if (cl->line) { + /* The allocated length is not written, so reset here. */ + cl->len_alloc = cl->len + 1; + } + else { + BLI_remlink(&sconsole->history, cl); + MEM_freeN(cl); + } + } +} + +static void console_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceConsole *con = (SpaceConsole *)sl; + + LISTBASE_FOREACH (ConsoleLine *, cl, &con->history) { + /* 'len_alloc' is invalid on write, set from 'len' on read */ + BLO_write_struct(writer, ConsoleLine, cl); + BLO_write_raw(writer, (size_t)cl->len + 1, cl->line); + } + BLO_write_struct(writer, SpaceConsole, sl); +} + void ED_spacetype_console(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype console"); @@ -299,6 +336,8 @@ void ED_spacetype_console(void) st->operatortypes = console_operatortypes; st->keymap = console_keymap; st->dropboxes = console_dropboxes; + st->blend_read_data = console_blend_read_data; + st->blend_write = console_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype console region"); diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index fb9d5ab9b13..688aa846c30 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -16,6 +16,9 @@ set(INC ../../windowmanager ../../../../intern/atomic ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -89,5 +92,5 @@ endif() blender_add_lib(bf_editor_space_file "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_file bf_rna) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index bba0c27bb4d..a3182222263 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -41,6 +41,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "GPU_framebuffer.h" #include "file_indexer.h" #include "file_intern.h" /* own include */ @@ -986,6 +988,52 @@ static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper file_reset_filelist_showing_main_data(area, sfile); } +static void file_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceFile *sfile = (SpaceFile *)sl; + + /* this sort of info is probably irrelevant for reloading... + * plus, it isn't saved to files yet! + */ + sfile->folders_prev = sfile->folders_next = NULL; + BLI_listbase_clear(&sfile->folder_histories); + sfile->files = NULL; + sfile->layout = NULL; + sfile->op = NULL; + sfile->previews_timer = NULL; + sfile->tags = 0; + sfile->runtime = NULL; + BLO_read_data_address(reader, &sfile->params); + BLO_read_data_address(reader, &sfile->asset_params); + if (sfile->params) { + sfile->params->rename_id = NULL; + } + if (sfile->asset_params) { + sfile->asset_params->base_params.rename_id = NULL; + } +} + +static void file_blend_read_lib(BlendLibReader *UNUSED(reader), + ID *UNUSED(parent_id), + SpaceLink *sl) +{ + SpaceFile *sfile = (SpaceFile *)sl; + sfile->tags |= FILE_TAG_REBUILD_MAIN_FILES; +} + +static void file_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceFile *sfile = (SpaceFile *)sl; + + BLO_write_struct(writer, SpaceFile, sl); + if (sfile->params) { + BLO_write_struct(writer, FileSelectParams, sfile->params); + } + if (sfile->asset_params) { + BLO_write_struct(writer, FileAssetSelectParams, sfile->asset_params); + } +} + void ED_spacetype_file(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype file"); @@ -1009,6 +1057,9 @@ void ED_spacetype_file(void) st->space_subtype_set = file_space_subtype_set; st->context = file_context; st->id_remap = file_id_remap; + st->blend_read_data = file_blend_read_data; + st->blend_read_lib = file_blend_read_lib; + st->blend_write = file_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index 39878debc39..f67434b0f6d 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../gpu @@ -11,6 +12,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -50,5 +54,5 @@ endif() blender_add_lib(bf_editor_space_graph "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_graph bf_rna) diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 75c1e958e32..1dc02fee59d 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -45,6 +45,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "graph_intern.h" /* own include */ /* ******************** default callbacks for ipo space ***************** */ @@ -804,6 +806,42 @@ static void graph_space_subtype_item_extend(bContext *UNUSED(C), RNA_enum_items_add(item, totitem, rna_enum_space_graph_mode_items); } +static void graph_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceGraph *sipo = (SpaceGraph *)sl; + + BLO_read_data_address(reader, &sipo->ads); + memset(&sipo->runtime, 0x0, sizeof(sipo->runtime)); +} + +static void graph_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceGraph *sipo = (SpaceGraph *)sl; + bDopeSheet *ads = sipo->ads; + + if (ads) { + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); + } +} + +static void graph_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceGraph *sipo = (SpaceGraph *)sl; + ListBase tmpGhosts = sipo->runtime.ghost_curves; + + /* temporarily disable ghost curves when saving */ + BLI_listbase_clear(&sipo->runtime.ghost_curves); + + BLO_write_struct(writer, SpaceGraph, sl); + if (sipo->ads) { + BLO_write_struct(writer, bDopeSheet, sipo->ads); + } + + /* Re-enable ghost curves. */ + sipo->runtime.ghost_curves = tmpGhosts; +} + void ED_spacetype_ipo(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype ipo"); @@ -824,6 +862,9 @@ void ED_spacetype_ipo(void) st->space_subtype_item_extend = graph_space_subtype_item_extend; st->space_subtype_get = graph_space_subtype_get; st->space_subtype_set = graph_space_subtype_set; + st->blend_read_data = graph_blend_read_data; + st->blend_read_lib = graph_blend_read_lib; + st->blend_write = graph_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 4284d0f76af..f0915243bbc 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../bmesh ../../depsgraph @@ -17,6 +18,9 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -65,5 +69,5 @@ endif() blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_image bf_rna) diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 2b65267644a..71cbcea1c1f 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -50,6 +50,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "DRW_engine.h" #include "image_intern.h" @@ -1026,6 +1028,46 @@ static void image_space_subtype_item_extend(bContext *UNUSED(C), RNA_enum_items_add(item, totitem, rna_enum_space_image_mode_items); } +static void image_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceImage *sima = (SpaceImage *)sl; + + sima->iuser.scene = NULL; + sima->scopes.waveform_1 = NULL; + sima->scopes.waveform_2 = NULL; + sima->scopes.waveform_3 = NULL; + sima->scopes.vecscope = NULL; + sima->scopes.ok = 0; + + /* WARNING: gpencil data is no longer stored directly in sima after 2.5 + * so sacrifice a few old files for now to avoid crashes with new files! + * committed: r28002 */ +#if 0 + sima->gpd = newdataadr(fd, sima->gpd); + if (sima->gpd) { + BKE_gpencil_blend_read_data(fd, sima->gpd); + } +#endif +} + +static void image_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceImage *sima = (SpaceImage *)sl; + + BLO_read_id_address(reader, parent_id->lib, &sima->image); + BLO_read_id_address(reader, parent_id->lib, &sima->mask_info.mask); + + /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data + * so fingers crossed this works fine! + */ + BLO_read_id_address(reader, parent_id->lib, &sima->gpd); +} + +static void image_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceImage, sl); +} + /**************************** spacetype *****************************/ void ED_spacetype_image(void) @@ -1051,6 +1093,9 @@ void ED_spacetype_image(void) st->space_subtype_item_extend = image_space_subtype_item_extend; st->space_subtype_get = image_space_subtype_get; st->space_subtype_set = image_space_subtype_set; + st->blend_read_data = image_blend_read_data; + st->blend_read_lib = image_blend_read_lib; + st->blend_write = image_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index 4e9df2b93b0..03314158813 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -15,6 +15,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -37,5 +40,5 @@ set(LIB blender_add_lib(bf_editor_space_info "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_info bf_rna) diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index 63c8d74c684..11294ed6ecc 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -28,6 +28,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "info_intern.h" /* own include */ /* ******************** default callbacks for info space ***************** */ @@ -248,6 +250,11 @@ static void info_header_region_message_subscribe(const wmRegionMessageSubscribeP WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); } +static void info_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceInfo, sl); +} + void ED_spacetype_info(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype info"); @@ -262,6 +269,7 @@ void ED_spacetype_info(void) st->duplicate = info_duplicate; st->operatortypes = info_operatortypes; st->keymap = info_keymap; + st->blend_write = info_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype info region"); diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt index e6995085dbe..5df0ebb3b28 100644 --- a/source/blender/editors/space_nla/CMakeLists.txt +++ b/source/blender/editors/space_nla/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../gpu @@ -11,6 +12,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -36,5 +40,5 @@ set(LIB blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_nla bf_rna) diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index e658ddef513..12f8915764b 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -36,6 +36,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "nla_intern.h" /* own include */ /* ******************** default callbacks for nla space ***************** */ @@ -562,6 +564,33 @@ static void nla_id_remap(ScrArea *UNUSED(area), BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT); } +static void nla_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceNla *snla = (SpaceNla *)sl; + BLO_read_data_address(reader, &snla->ads); +} + +static void nla_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceNla *snla = (SpaceNla *)sl; + bDopeSheet *ads = snla->ads; + + if (ads) { + BLO_read_id_address(reader, parent_id->lib, &ads->source); + BLO_read_id_address(reader, parent_id->lib, &ads->filter_grp); + } +} + +static void nla_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceNla *snla = (SpaceNla *)sl; + + BLO_write_struct(writer, SpaceNla, snla); + if (snla->ads) { + BLO_write_struct(writer, bDopeSheet, snla->ads); + } +} + void ED_spacetype_nla(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype nla"); @@ -578,6 +607,9 @@ void ED_spacetype_nla(void) st->listener = nla_listener; st->keymap = nla_keymap; st->id_remap = nla_id_remap; + st->blend_read_data = nla_blend_read_data; + st->blend_read_lib = nla_blend_read_lib; + st->blend_write = nla_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index adb03439568..d7eccbf0b68 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../compositor ../../depsgraph @@ -18,6 +19,9 @@ set(INC ../../render ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -80,5 +84,5 @@ endif() blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_node bf_rna) diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 13d13b10339..93166c6de59 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1983,7 +1983,7 @@ static void node_draw_link_end_marker(const float2 center, UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_4fv(&rect, true, radius, color); - /* Roundbox disables alpha. Reenable it for node links that are drawn after this one. */ + /* Round-box disables alpha. Re-enable it for node links that are drawn after this one. */ GPU_blend(GPU_BLEND_ALPHA); } diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index efe53fd6f14..10e903ca79b 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -777,6 +777,8 @@ static int new_node_tree_exec(bContext *C, wmOperator *op) ED_node_tree_update(C); } + WM_event_add_notifier(C, NC_NODE | NA_ADDED, NULL); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 8f72d292740..29dad103dc3 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -60,6 +60,7 @@ #include "ED_node.h" #include "ED_screen.h" #include "ED_space_api.h" +#include "ED_viewer_path.hh" #include "UI_interface.hh" #include "UI_resources.h" @@ -95,6 +96,14 @@ extern void ui_draw_dropshadow( */ struct TreeDrawContext { /** + * Whether a viewer node is active in geometry nodes can not be determined by a flag on the node + * alone. That's because if the node group with the viewer is used multiple times, it's only + * active in one of these cases. + * The active node is cached here to avoid doing the more expensive check for every viewer node + * in the tree. + */ + const bNode *active_geometry_nodes_viewer = nullptr; + /** * Geometry nodes logs various data during execution. The logged data that corresponds to the * currently drawn node tree can be retrieved from the log below. */ @@ -639,15 +648,19 @@ static void node_update_hidden(bNode &node, uiBlock &block) node.totr.ymax); } -static int node_get_colorid(const bNode &node) +static int node_get_colorid(TreeDrawContext &tree_draw_ctx, const bNode &node) { const int nclass = (node.typeinfo->ui_class == nullptr) ? node.typeinfo->nclass : node.typeinfo->ui_class(&node); switch (nclass) { case NODE_CLASS_INPUT: return TH_NODE_INPUT; - case NODE_CLASS_OUTPUT: + case NODE_CLASS_OUTPUT: { + if (node.type == GEO_NODE_VIEWER) { + return &node == tree_draw_ctx.active_geometry_nodes_viewer ? TH_NODE_OUTPUT : TH_NODE; + } return (node.flag & NODE_DO_OUTPUT) ? TH_NODE_OUTPUT : TH_NODE; + } case NODE_CLASS_CONVERTER: return TH_NODE_CONVERTER; case NODE_CLASS_OP_COLOR: @@ -2055,7 +2068,7 @@ static void node_draw_basis(const bContext &C, const rctf &rct = node.totr; float color[4]; - int color_id = node_get_colorid(node); + int color_id = node_get_colorid(tree_draw_ctx, node); GPU_line_width(1.0f); @@ -2153,6 +2166,29 @@ static void node_draw_basis(const bContext &C, ""); UI_block_emboss_set(&block, UI_EMBOSS); } + if (node.type == GEO_NODE_VIEWER) { + const bool is_active = &node == tree_draw_ctx.active_geometry_nodes_viewer; + iconofs -= iconbutw; + UI_block_emboss_set(&block, UI_EMBOSS_NONE); + uiBut *but = uiDefIconBut(&block, + UI_BTYPE_BUT, + 0, + is_active ? ICON_HIDE_OFF : ICON_HIDE_ON, + iconofs, + rct.ymax - NODE_DY, + iconbutw, + UI_UNIT_Y, + nullptr, + 0, + 0, + 0, + 0, + ""); + /* Selection implicitly activates the node. */ + const char *operator_idname = is_active ? "NODE_OT_deactivate_viewer" : "NODE_OT_select"; + UI_but_func_set(but, node_toggle_button_cb, &node, (void *)operator_idname); + UI_block_emboss_set(&block, UI_EMBOSS); + } node_add_error_message_button(tree_draw_ctx, node, block, rct, iconofs); @@ -2341,7 +2377,7 @@ static void node_draw_hidden(const bContext &C, float scale; UI_view2d_scale_get(&v2d, &scale, nullptr); - const int color_id = node_get_colorid(node); + const int color_id = node_get_colorid(tree_draw_ctx, node); node_draw_extra_info_panel(tree_draw_ctx, snode, node, block); @@ -2698,7 +2734,8 @@ static void node_update_nodetree(const bContext &C, } } -static void frame_node_draw_label(const bNodeTree &ntree, +static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx, + const bNodeTree &ntree, const bNode &node, const SpaceNode &snode) { @@ -2717,7 +2754,7 @@ static void frame_node_draw_label(const bNodeTree &ntree, BLF_size(fontid, MIN2(24.0f, font_size) * U.dpi_fac); /* title color */ - int color_id = node_get_colorid(node); + int color_id = node_get_colorid(tree_draw_ctx, node); uchar color[3]; UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color); BLF_color3ubv(fontid, color); @@ -2831,7 +2868,7 @@ static void frame_node_draw(const bContext &C, } /* label and text */ - frame_node_draw_label(ntree, node, snode); + frame_node_draw_label(tree_draw_ctx, ntree, node, snode); node_draw_extra_info_panel(tree_draw_ctx, snode, node, block); @@ -3036,6 +3073,9 @@ static void draw_nodetree(const bContext &C, tree_draw_ctx.geo_tree_log->ensure_node_warnings(); tree_draw_ctx.geo_tree_log->ensure_node_run_time(); } + WorkSpace *workspace = CTX_wm_workspace(&C); + tree_draw_ctx.active_geometry_nodes_viewer = viewer_path::find_geometry_nodes_viewer( + workspace->viewer_path, *snode); } node_update_nodetree(C, tree_draw_ctx, ntree, nodes, blocks); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index e446d5421e7..8135369f271 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -43,7 +43,7 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_select_utils.h" -#include "ED_spreadsheet.h" +#include "ED_viewer_path.hh" #include "RNA_access.h" #include "RNA_define.h" @@ -821,8 +821,8 @@ void ED_node_set_active( } } node->flag |= NODE_DO_OUTPUT; - ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, node); } + blender::ed::viewer_path::activate_geometry_node(*bmain, *snode, *node); } } } @@ -1700,6 +1700,46 @@ void NODE_OT_preview_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int node_deactivate_viewer_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceNode &snode = *CTX_wm_space_node(C); + WorkSpace &workspace = *CTX_wm_workspace(C); + + bNode *active_viewer = viewer_path::find_geometry_nodes_viewer(workspace.viewer_path, snode); + + LISTBASE_FOREACH (bNode *, node, &snode.edittree->nodes) { + if (node->type != GEO_NODE_VIEWER) { + continue; + } + if (!(node->flag & SELECT)) { + continue; + } + if (node == active_viewer) { + node->flag &= ~NODE_DO_OUTPUT; + BKE_ntree_update_tag_node_property(snode.edittree, node); + } + } + + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); + + return OPERATOR_FINISHED; +} + +void NODE_OT_deactivate_viewer(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Deactivate Viewer Node"; + ot->description = "Deactivate selected viewer node in geometry nodes"; + ot->idname = __func__; + + /* callbacks */ + ot->exec = node_deactivate_viewer_exec; + ot->poll = ED_operator_node_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + static int node_options_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceNode *snode = CTX_wm_space_node(C); diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 21def1bd9d7..e0de5e2f71d 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -1047,6 +1047,8 @@ static int node_group_make_exec(bContext *C, wmOperator *op) ED_node_tree_propagate_change(C, bmain, nullptr); + WM_event_add_notifier(C, NC_NODE | NA_ADDED, NULL); + /* We broke relations in node tree, need to rebuild them in the graphs. */ DEG_relations_tag_update(bmain); diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 70ac0e48d01..50c03489027 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -322,6 +322,7 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot); void NODE_OT_preview_toggle(wmOperatorType *ot); void NODE_OT_options_toggle(wmOperatorType *ot); void NODE_OT_node_copy_color(wmOperatorType *ot); +void NODE_OT_deactivate_viewer(wmOperatorType *ot); void NODE_OT_read_viewlayers(wmOperatorType *ot); void NODE_OT_render_changed(wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index f02c019359d..6c52dae5b86 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -44,6 +44,7 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_options_toggle); WM_operatortype_append(NODE_OT_hide_socket_toggle); WM_operatortype_append(NODE_OT_node_copy_color); + WM_operatortype_append(NODE_OT_deactivate_viewer); WM_operatortype_append(NODE_OT_duplicate); WM_operatortype_append(NODE_OT_delete); @@ -135,6 +136,7 @@ void ED_operatormacros_node() mot = WM_operatortype_macro_define(ot, "NODE_OT_select"); RNA_boolean_set(mot->ptr, "extend", false); RNA_boolean_set(mot->ptr, "socket_select", true); + RNA_boolean_set(mot->ptr, "clear_viewer", true); WM_operatortype_macro_define(ot, "NODE_OT_link_viewer"); ot = WM_operatortype_append_macro("NODE_OT_translate_attach", diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index f597bf20b55..d9f87433c53 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -27,8 +27,8 @@ #include "ED_render.h" #include "ED_screen.h" #include "ED_space_api.h" -#include "ED_spreadsheet.h" #include "ED_util.h" +#include "ED_viewer_path.hh" #include "RNA_access.h" #include "RNA_define.h" @@ -495,17 +495,6 @@ static bool is_viewer_node(const bNode &node) return ELEM(node.type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER, GEO_NODE_VIEWER); } -static Vector<const bNode *> find_viewer_nodes(const bNodeTree &tree) -{ - Vector<const bNode *> viewer_nodes; - for (const bNode *node : tree.all_nodes()) { - if (is_viewer_node(*node)) { - viewer_nodes.append(node); - } - } - return viewer_nodes; -} - static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) { const bNode &node = socket.owner_node(); @@ -516,18 +505,10 @@ static bool is_viewer_socket_in_viewer(const bNodeSocket &socket) return socket.index() == 0; } -static bool is_linked_to_viewer(const bNodeSocket &socket, const bNode &viewer_node) +static bool is_viewer_socket(const bNodeSocket &socket) { - for (const bNodeSocket *target_socket : socket.directly_linked_sockets()) { - if (&target_socket->owner_node() != &viewer_node) { - continue; - } - if (!target_socket->is_available()) { - continue; - } - if (is_viewer_socket_in_viewer(*target_socket)) { - return true; - } + if (is_viewer_node(socket.owner_node())) { + return is_viewer_socket_in_viewer(socket); } return false; } @@ -549,137 +530,165 @@ static void remove_links_to_unavailable_viewer_sockets(bNodeTree &btree, bNode & } } -static const bNode *get_existing_viewer(const bNodeTree &tree) +static bNodeSocket *determine_socket_to_view(bNode &node_to_view) { - Vector<const bNode *> viewer_nodes = find_viewer_nodes(tree); - - /* Check if there is already an active viewer node that should be used. */ - for (const bNode *viewer_node : viewer_nodes) { - if (viewer_node->flag & NODE_DO_OUTPUT) { - return viewer_node; + int last_linked_socket_index = -1; + for (bNodeSocket *socket : node_to_view.output_sockets()) { + if (!socket_can_be_viewed(*socket)) { + continue; } - } - - /* If no active but non-active viewers exist, make one active. */ - if (!viewer_nodes.is_empty()) { - const_cast<bNode *>(viewer_nodes[0])->flag |= NODE_DO_OUTPUT; - return viewer_nodes[0]; - } - return nullptr; -} - -static const bNodeSocket *find_output_socket_to_be_viewed(const bNode *active_viewer_node, - const bNode &node_to_view) -{ - /* Check if any of the output sockets is selected, which is the case when the user just clicked - * on the socket. */ - for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { - if (output_socket->flag & SELECT) { - return output_socket; + for (bNodeLink *link : socket->directly_linked_links()) { + bNodeSocket &target_socket = *link->tosock; + bNode &target_node = *link->tonode; + if (is_viewer_socket(target_socket)) { + if (link->is_muted() || !(target_node.flag & NODE_DO_OUTPUT)) { + /* This socket is linked to a deactivated viewer, the viewer should be activated. */ + return socket; + } + last_linked_socket_index = socket->index(); + } } } - const bNodeSocket *last_socket_linked_to_viewer = nullptr; - if (active_viewer_node != nullptr) { - for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { - if (!socket_can_be_viewed(*output_socket)) { - continue; - } - if (is_linked_to_viewer(*output_socket, *active_viewer_node)) { - last_socket_linked_to_viewer = output_socket; + if (last_linked_socket_index == -1) { + /* Return the first socket that can be viewed. */ + for (bNodeSocket *socket : node_to_view.output_sockets()) { + if (socket_can_be_viewed(*socket)) { + return socket; } } + return nullptr; } - if (last_socket_linked_to_viewer == nullptr) { - /* If no output is connected to a viewer, use the first output that can be viewed. */ - for (const bNodeSocket *output_socket : node_to_view.output_sockets()) { - if (socket_can_be_viewed(*output_socket)) { - return output_socket; - } + + /* Pick the next socket to be linked to the viewer. */ + const int tot_outputs = node_to_view.output_sockets().size(); + for (const int offset : IndexRange(1, tot_outputs)) { + const int index = (last_linked_socket_index + offset) % tot_outputs; + bNodeSocket &output_socket = node_to_view.output_socket(index); + if (!socket_can_be_viewed(output_socket)) { + continue; } - } - else { - /* Pick the next socket to be linked to the viewer. */ - const int tot_outputs = node_to_view.output_sockets().size(); - for (const int offset : IndexRange(1, tot_outputs - 1)) { - const int index = (last_socket_linked_to_viewer->index() + offset) % tot_outputs; - const bNodeSocket &output_socket = node_to_view.output_socket(index); - if (!socket_can_be_viewed(output_socket)) { + bool is_currently_viewed = false; + for (const bNodeLink *link : output_socket.directly_linked_links()) { + bNodeSocket &target_socket = *link->tosock; + bNode &target_node = *link->tonode; + if (!is_viewer_socket(target_socket)) { continue; } - if (is_linked_to_viewer(output_socket, *active_viewer_node)) { + if (link->is_muted()) { continue; } - return &output_socket; + if (!(target_node.flag & NODE_DO_OUTPUT)) { + continue; + } + is_currently_viewed = true; + break; } + if (is_currently_viewed) { + continue; + } + return &output_socket; } return nullptr; } -static int link_socket_to_viewer(const bContext &C, - bNode *viewer_bnode, - bNode &bnode_to_view, - bNodeSocket &bsocket_to_view) +static void finalize_viewer_link(const bContext &C, + SpaceNode &snode, + bNode &viewer_node, + bNodeLink &viewer_link) { - SpaceNode &snode = *CTX_wm_space_node(&C); - bNodeTree &btree = *snode.edittree; + Main *bmain = CTX_data_main(&C); + remove_links_to_unavailable_viewer_sockets(*snode.edittree, viewer_node); + viewer_link.flag &= ~NODE_LINK_MUTED; + viewer_node.flag &= ~NODE_MUTED; + viewer_node.flag |= NODE_DO_OUTPUT; + if (snode.edittree->type == NTREE_GEOMETRY) { + viewer_path::activate_geometry_node(*bmain, snode, viewer_node); + } + ED_node_tree_propagate_change(&C, bmain, snode.edittree); +} + +static int view_socket(const bContext &C, + SpaceNode &snode, + bNodeTree &btree, + bNode &bnode_to_view, + bNodeSocket &bsocket_to_view) +{ + bNode *viewer_node = nullptr; + /* Try to find a viewer that is already active. */ + LISTBASE_FOREACH (bNode *, node, &btree.nodes) { + if (is_viewer_node(*node)) { + if (node->flag & NODE_DO_OUTPUT) { + viewer_node = node; + break; + } + } + } - if (viewer_bnode == nullptr) { - /* Create a new viewer node if none exists. */ + /* Try to reactivate existing viewer connection. */ + for (bNodeLink *link : bsocket_to_view.directly_linked_links()) { + bNodeSocket &target_socket = *link->tosock; + bNode &target_node = *link->tonode; + if (is_viewer_socket(target_socket) && ELEM(viewer_node, nullptr, &target_node)) { + finalize_viewer_link(C, snode, target_node, *link); + return OPERATOR_FINISHED; + } + } + + if (viewer_node == nullptr) { + LISTBASE_FOREACH (bNode *, node, &btree.nodes) { + if (is_viewer_node(*node)) { + viewer_node = node; + break; + } + } + } + if (viewer_node == nullptr) { const int viewer_type = get_default_viewer_type(&C); const float2 location{bsocket_to_view.locx / UI_DPI_FAC + 100, bsocket_to_view.locy / UI_DPI_FAC}; - viewer_bnode = add_static_node(C, viewer_type, location); - if (viewer_bnode == nullptr) { - return OPERATOR_CANCELLED; - } + viewer_node = add_static_node(C, viewer_type, location); } - bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_bnode, bsocket_to_view); + bNodeSocket *viewer_bsocket = node_link_viewer_get_socket(btree, *viewer_node, bsocket_to_view); if (viewer_bsocket == nullptr) { return OPERATOR_CANCELLED; } - - bNodeLink *link_to_change = nullptr; - LISTBASE_FOREACH (bNodeLink *, link, &btree.links) { + bNodeLink *viewer_link = nullptr; + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &btree.links) { if (link->tosock == viewer_bsocket) { - link_to_change = link; + viewer_link = link; break; } } - - if (link_to_change == nullptr) { - nodeAddLink(&btree, &bnode_to_view, &bsocket_to_view, viewer_bnode, viewer_bsocket); + if (viewer_link == nullptr) { + viewer_link = nodeAddLink( + &btree, &bnode_to_view, &bsocket_to_view, viewer_node, viewer_bsocket); } else { - link_to_change->fromnode = &bnode_to_view; - link_to_change->fromsock = &bsocket_to_view; + viewer_link->fromnode = &bnode_to_view; + viewer_link->fromsock = &bsocket_to_view; BKE_ntree_update_tag_link_changed(&btree); } - - remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode); - - if (btree.type == NTREE_GEOMETRY) { - ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode); - } - - ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree); - return OPERATOR_FINISHED; + finalize_viewer_link(C, snode, *viewer_node, *viewer_link); + return OPERATOR_CANCELLED; } -static int node_link_viewer(const bContext &C, bNode &bnode_to_view) +static int node_link_viewer(const bContext &C, bNode &bnode_to_view, bNodeSocket *bsocket_to_view) { SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree *btree = snode.edittree; btree->ensure_topology_cache(); - bNode *active_viewer_bnode = const_cast<bNode *>(get_existing_viewer(*btree)); - bNodeSocket *bsocket_to_view = const_cast<bNodeSocket *>( - find_output_socket_to_be_viewed(active_viewer_bnode, bnode_to_view)); if (bsocket_to_view == nullptr) { - return OPERATOR_FINISHED; + bsocket_to_view = determine_socket_to_view(bnode_to_view); } - return link_socket_to_viewer(C, active_viewer_bnode, bnode_to_view, *bsocket_to_view); + + if (bsocket_to_view == nullptr) { + return OPERATOR_CANCELLED; + } + + return view_socket(C, snode, *btree, bnode_to_view, *bsocket_to_view); } /** \} */ @@ -701,7 +710,15 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) { + bNodeSocket *socket_to_view = nullptr; + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + if (socket->flag & SELECT) { + socket_to_view = socket; + break; + } + } + + if (viewer_linking::node_link_viewer(*C, *node, socket_to_view) == OPERATOR_CANCELLED) { return OPERATOR_CANCELLED; } @@ -915,7 +932,7 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) ED_node_tree_propagate_change(&C, bmain, &ntree); - /* Ensure draglink tooltip is disabled. */ + /* Ensure drag-link tool-tip is disabled. */ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag); ED_workspace_status_text(&C, nullptr); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 1b47316ebd0..c11ae323115 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -23,13 +23,14 @@ #include "BKE_main.h" #include "BKE_node.h" #include "BKE_node_runtime.hh" +#include "BKE_node_tree_update.h" #include "BKE_workspace.h" #include "ED_node.h" /* own include */ #include "ED_screen.h" #include "ED_select_utils.h" -#include "ED_spreadsheet.h" #include "ED_view3d.h" +#include "ED_viewer_path.hh" #include "RNA_access.h" #include "RNA_define.h" @@ -644,6 +645,15 @@ static bool node_mouse_select(bContext *C, } } + if (RNA_boolean_get(op->ptr, "clear_viewer")) { + if (node == nullptr) { + /* Disable existing active viewer. */ + WorkSpace *workspace = CTX_wm_workspace(C); + BKE_viewer_path_clear(&workspace->viewer_path); + WM_event_add_notifier(C, NC_VIEWER_PATH, nullptr); + } + } + if (!(changed || found)) { return false; } @@ -655,7 +665,7 @@ static bool node_mouse_select(bContext *C, ED_node_set_active(&bmain, &snode, snode.edittree, node, &active_texture_changed); } else if (node != nullptr && node->type == GEO_NODE_VIEWER) { - ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node); + viewer_path::activate_geometry_node(bmain, snode, *node); } ED_node_set_active_viewer_key(&snode); node_sort(*snode.edittree); @@ -731,6 +741,12 @@ void NODE_OT_select(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", ""); + + RNA_def_boolean(ot->srna, + "clear_viewer", + false, + "Clear Viewer", + "Deactivate geometry nodes viewer when clicking in empty space"); } /** \} */ diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index b9983b6f269..3e5cbf88e15 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -14,6 +14,7 @@ #include "MEM_guardedalloc.h" #include "BKE_context.h" +#include "BKE_gpencil.h" #include "BKE_lib_id.h" #include "BKE_lib_remap.h" #include "BKE_node.h" @@ -27,6 +28,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -820,6 +823,9 @@ static void node_region_listener(const wmRegionListenerParams *params) ED_region_tag_redraw(region); } break; + case NC_VIEWER_PATH: + ED_region_tag_redraw(region); + break; } } @@ -1011,6 +1017,81 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, } } +static void node_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceNode *snode = (SpaceNode *)sl; + + if (snode->gpd) { + BLO_read_data_address(reader, &snode->gpd); + BKE_gpencil_blend_read_data(reader, snode->gpd); + } + + BLO_read_list(reader, &snode->treepath); + snode->edittree = nullptr; + snode->runtime = nullptr; +} + +static void node_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceNode *snode = (SpaceNode *)sl; + + /* node tree can be stored locally in id too, link this first */ + BLO_read_id_address(reader, parent_id->lib, &snode->id); + BLO_read_id_address(reader, parent_id->lib, &snode->from); + + bNodeTree *ntree = snode->id ? ntreeFromID(snode->id) : nullptr; + if (ntree) { + snode->nodetree = ntree; + } + else { + BLO_read_id_address(reader, parent_id->lib, &snode->nodetree); + } + + bNodeTreePath *path; + for (path = static_cast<bNodeTreePath *>(snode->treepath.first); path; path = path->next) { + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + path->nodetree = snode->nodetree; + } + else { + BLO_read_id_address(reader, parent_id->lib, &path->nodetree); + } + + if (!path->nodetree) { + break; + } + } + + /* remaining path entries are invalid, remove */ + bNodeTreePath *path_next; + for (; path; path = path_next) { + path_next = path->next; + + BLI_remlink(&snode->treepath, path); + MEM_freeN(path); + } + + /* edittree is just the last in the path, + * set this directly since the path may have been shortened above */ + if (snode->treepath.last) { + path = static_cast<bNodeTreePath *>(snode->treepath.last); + snode->edittree = path->nodetree; + } + else { + snode->edittree = nullptr; + } +} + +static void node_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceNode *snode = (SpaceNode *)sl; + BLO_write_struct(writer, SpaceNode, snode); + + LISTBASE_FOREACH (bNodeTreePath *, path, &snode->treepath) { + BLO_write_struct(writer, bNodeTreePath, path); + } +} + } // namespace blender::ed::space_node void ED_spacetype_node() @@ -1038,6 +1119,9 @@ void ED_spacetype_node() st->space_subtype_item_extend = node_space_subtype_item_extend; st->space_subtype_get = node_space_subtype_get; st->space_subtype_set = node_space_subtype_set; + st->blend_read_data = node_blend_read_data; + st->blend_read_lib = node_blend_read_lib; + st->blend_write = node_blend_write; /* regions: main window */ art = MEM_cnew<ARegionType>("spacetype node region"); diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index d29028dad63..d1998f15757 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -4,6 +4,7 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../gpu @@ -14,6 +15,9 @@ set(INC ../../windowmanager ../../../../intern/clog ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -90,5 +94,5 @@ set(LIB blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_outliner bf_rna) diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 76f93e5f518..64aaf00344b 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -2985,7 +2985,7 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, number_text, text_col); UI_fontstyle_set(fstyle); - GPU_blend(GPU_BLEND_ALPHA); /* Roundbox and text drawing disables. */ + GPU_blend(GPU_BLEND_ALPHA); /* Round-box and text drawing disables. */ } static void outliner_icon_background_colors(float icon_color[4], float icon_border[4]) @@ -3015,7 +3015,7 @@ static void outliner_draw_active_indicator(const float minx, UI_draw_roundbox_corner_set(UI_CNR_ALL); UI_draw_roundbox_aa(&rect, true, radius, icon_color); UI_draw_roundbox_aa(&rect, false, radius, icon_border); - GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */ + GPU_blend(GPU_BLEND_ALPHA); /* Round-box disables. */ } static void outliner_draw_iconrow_doit(uiBlock *block, @@ -3605,8 +3605,8 @@ static void outliner_draw_struct_marks(ARegion *region, immThemeColorShadeAlpha(TH_BACK, -15, -200); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y); - immVertex2f(pos, region->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); + immVertex2f(pos, 0, float(*starty) + UI_UNIT_Y); + immVertex2f(pos, region->v2d.cur.xmax, float(*starty) + UI_UNIT_Y); immEnd(); immUnbindProgram(); diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index 365bcae3f5d..e20bc0a956a 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -5,6 +5,9 @@ * \ingroup spoutliner */ +/* Allow using deprecated functionality for .blend file I/O. */ +#define DNA_DEPRECATED_ALLOW + #include <cstdio> #include <cstring> @@ -34,6 +37,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "outliner_intern.hh" #include "tree/tree_display.hh" @@ -251,6 +256,12 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) ED_region_tag_redraw(region); } break; + case NC_NODE: + if (ELEM(wmn->action, NA_ADDED, NA_REMOVED) && + ELEM(space_outliner->outlinevis, SO_LIBRARIES, SO_DATA_API)) { + ED_region_tag_redraw(region); + } + break; } } @@ -435,6 +446,115 @@ static void outliner_deactivate(struct ScrArea *area) ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } +static void outliner_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceOutliner *space_outliner = (SpaceOutliner *)sl; + + /* use #BLO_read_get_new_data_address_no_us and do not free old memory avoiding double + * frees and use of freed memory. this could happen because of a + * bug fixed in revision 58959 where the treestore memory address + * was not unique */ + TreeStore *ts = static_cast<TreeStore *>( + BLO_read_get_new_data_address_no_us(reader, space_outliner->treestore)); + space_outliner->treestore = nullptr; + if (ts) { + TreeStoreElem *elems = static_cast<TreeStoreElem *>( + BLO_read_get_new_data_address_no_us(reader, ts->data)); + + space_outliner->treestore = BLI_mempool_create( + sizeof(TreeStoreElem), ts->usedelem, 512, BLI_MEMPOOL_ALLOW_ITER); + if (ts->usedelem && elems) { + for (int i = 0; i < ts->usedelem; i++) { + TreeStoreElem *new_elem = static_cast<TreeStoreElem *>( + BLI_mempool_alloc(space_outliner->treestore)); + *new_elem = elems[i]; + } + } + /* we only saved what was used */ + space_outliner->storeflag |= SO_TREESTORE_CLEANUP; /* at first draw */ + } + space_outliner->tree.first = space_outliner->tree.last = nullptr; + space_outliner->runtime = nullptr; +} + +static void outliner_blend_read_lib(BlendLibReader *reader, ID *UNUSED(parent_id), SpaceLink *sl) +{ + SpaceOutliner *space_outliner = (SpaceOutliner *)sl; + + if (space_outliner->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + + BLI_mempool_iternew(space_outliner->treestore, &iter); + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + BLO_read_id_address(reader, nullptr, &tselem->id); + } + /* rebuild hash table, because it depends on ids too */ + space_outliner->storeflag |= SO_TREESTORE_REBUILD; + } +} + +static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space_outliner) +{ + BLI_mempool *ts = space_outliner->treestore; + + if (ts) { + const int elems = BLI_mempool_len(ts); + /* linearize mempool to array */ + TreeStoreElem *data = elems ? static_cast<TreeStoreElem *>( + BLI_mempool_as_arrayN(ts, "TreeStoreElem")) : + nullptr; + + if (data) { + BLO_write_struct(writer, SpaceOutliner, space_outliner); + + /* To store #TreeStore (instead of the mempool), two unique memory addresses are needed, + * which can be used to identify the data on read: + * 1) One for the #TreeStore data itself. + * 2) One for the array of #TreeStoreElem's inside #TreeStore (#TreeStore.data). + * + * For 1) we just use the mempool's address (#SpaceOutliner::treestore). + * For 2) we don't have such a direct choice. We can't just use the array's address from + * above, since that may not be unique over all Outliners. So instead use an address relative + * to 1). + */ + /* TODO the mempool could be moved to #SpaceOutliner_Runtime so that #SpaceOutliner could + * hold the #TreeStore directly. */ + + /* Address relative to the tree-store, as noted above. */ + void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); + /* There should be plenty of memory addresses within the mempool data that we can point into, + * just double-check we don't potentially end up with a memory address that another DNA + * struct might use. Assumes BLI_mempool uses the guarded allocator. */ + BLI_assert(MEM_allocN_len(ts) >= sizeof(void *) * 2); + + TreeStore ts_flat = {0}; + ts_flat.usedelem = elems; + ts_flat.totelem = elems; + ts_flat.data = static_cast<TreeStoreElem *>(data_addr); + + BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat); + BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data); + + MEM_freeN(data); + } + else { + SpaceOutliner space_outliner_flat = *space_outliner; + space_outliner_flat.treestore = nullptr; + BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat); + } + } + else { + BLO_write_struct(writer, SpaceOutliner, space_outliner); + } +} + +static void outliner_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceOutliner *space_outliner = (SpaceOutliner *)sl; + write_space_outliner(writer, space_outliner); +} + } // namespace blender::ed::outliner void ED_spacetype_outliner(void) @@ -457,6 +577,9 @@ void ED_spacetype_outliner(void) st->id_remap = outliner_id_remap; st->deactivate = outliner_deactivate; st->context = outliner_context; + st->blend_read_data = outliner_blend_read_data; + st->blend_read_lib = outliner_blend_read_lib; + st->blend_write = outliner_blend_write; /* regions: main window */ art = MEM_cnew<ARegionType>("spacetype outliner region"); diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt index f7fc4e38c17..8902703b6ea 100644 --- a/source/blender/editors/space_script/CMakeLists.txt +++ b/source/blender/editors/space_script/CMakeLists.txt @@ -4,11 +4,15 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../gpu ../../makesdna ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern ) @@ -32,3 +36,6 @@ endif() blender_add_lib(bf_editor_space_script "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# dna_type_offsets.h +add_dependencies(bf_editor_space_script bf_dna) diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index c35b1e00184..4495501efe9 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -24,6 +24,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #ifdef WITH_PYTHON #endif @@ -146,6 +148,25 @@ static void script_main_region_listener(const wmRegionListenerParams *UNUSED(par #endif } +static void script_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceScript *scpt = (SpaceScript *)sl; + /*scpt->script = NULL; - 2.45 set to null, better re-run the script */ + if (scpt->script) { + BLO_read_id_address(reader, parent_id->lib, &scpt->script); + if (scpt->script) { + SCRIPT_SET_NULL(scpt->script); + } + } +} + +static void script_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + SpaceScript *scr = (SpaceScript *)sl; + scr->but_refs = NULL; + BLO_write_struct(writer, SpaceScript, sl); +} + void ED_spacetype_script(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype script"); @@ -160,6 +181,8 @@ void ED_spacetype_script(void) st->duplicate = script_duplicate; st->operatortypes = script_operatortypes; st->keymap = script_keymap; + st->blend_read_lib = script_blend_read_lib; + st->blend_write = script_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype script region"); diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index deaec0136c4..5466beca255 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../depsgraph ../../draw @@ -16,6 +17,9 @@ set(INC ../../windowmanager ../../../../intern/atomic ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -62,5 +66,5 @@ endif() blender_add_lib(bf_editor_space_sequencer "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_sequencer bf_rna) diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 508f18ade5a..8b6d37caa41 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -44,6 +44,8 @@ #include "UI_interface.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "IMB_imbuf.h" /* Only for cursor drawing. */ @@ -991,6 +993,47 @@ static void sequencer_channel_region_draw(const bContext *C, ARegion *region) draw_channels(C, region); } +static void sequencer_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceSeq *sseq = (SpaceSeq *)sl; + + /* grease pencil data is not a direct data and can't be linked from direct_link* + * functions, it should be linked from lib_link* functions instead + * + * otherwise it'll lead to lost grease data on open because it'll likely be + * read from file after all other users of grease pencil and newdataadr would + * simple return NULL here (sergey) + */ +#if 0 + if (sseq->gpd) { + sseq->gpd = newdataadr(fd, sseq->gpd); + BKE_gpencil_blend_read_data(fd, sseq->gpd); + } +#endif + sseq->scopes.reference_ibuf = NULL; + sseq->scopes.zebra_ibuf = NULL; + sseq->scopes.waveform_ibuf = NULL; + sseq->scopes.sep_waveform_ibuf = NULL; + sseq->scopes.vector_ibuf = NULL; + sseq->scopes.histogram_ibuf = NULL; + memset(&sseq->runtime, 0x0, sizeof(sseq->runtime)); +} + +static void sequencer_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceSeq *sseq = (SpaceSeq *)sl; + + /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data + * so fingers crossed this works fine! + */ + BLO_read_id_address(reader, parent_id->lib, &sseq->gpd); +} + +static void sequencer_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceSeq, sl); +} + void ED_spacetype_sequencer(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer"); @@ -1011,6 +1054,9 @@ void ED_spacetype_sequencer(void) st->refresh = sequencer_refresh; st->listener = sequencer_listener; st->id_remap = sequencer_id_remap; + st->blend_read_data = sequencer_blend_read_data; + st->blend_read_lib = sequencer_blend_read_lib; + st->blend_write = sequencer_blend_write; /* Create regions: */ /* Main window. */ diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 173d976c124..08032ddbaeb 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../bmesh ../../depsgraph @@ -15,6 +16,9 @@ set(INC ../../nodes ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -23,7 +27,6 @@ set(SRC space_spreadsheet.cc spreadsheet_cache.cc spreadsheet_column.cc - spreadsheet_context.cc spreadsheet_data_source.cc spreadsheet_data_source_geometry.cc spreadsheet_dataset_draw.cc @@ -37,7 +40,6 @@ set(SRC spreadsheet_cache.hh spreadsheet_column.hh spreadsheet_column_values.hh - spreadsheet_context.hh spreadsheet_data_source.hh spreadsheet_data_source_geometry.hh spreadsheet_dataset_draw.hh @@ -63,5 +65,5 @@ endif() blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_spreadsheet bf_rna) diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 5fce0709d10..ee43519e260 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -10,6 +10,7 @@ #include "ED_screen.h" #include "ED_space_api.h" #include "ED_spreadsheet.h" +#include "ED_viewer_path.hh" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -21,6 +22,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "DEG_depsgraph_query.h" #include "RNA_access.h" @@ -32,7 +35,6 @@ #include "BLF_api.h" -#include "spreadsheet_context.hh" #include "spreadsheet_data_source_geometry.hh" #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_intern.hh" @@ -105,9 +107,7 @@ static void spreadsheet_free(SpaceLink *sl) LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) { spreadsheet_column_free(column); } - LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) { - spreadsheet_context_free(context); - } + BKE_viewer_path_clear(&sspreadsheet->viewer_path); } static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area) @@ -141,11 +141,7 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) BLI_addtail(&sspreadsheet_new->columns, new_column); } - BLI_listbase_clear(&sspreadsheet_new->context_path); - LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, src_context, &sspreadsheet_old->context_path) { - SpreadsheetContext *new_context = spreadsheet_context_copy(src_context); - BLI_addtail(&sspreadsheet_new->context_path, new_context); - } + BKE_viewer_path_copy(&sspreadsheet_new->viewer_path, &sspreadsheet_old->viewer_path); return (SpaceLink *)sspreadsheet_new; } @@ -161,19 +157,7 @@ static void spreadsheet_id_remap(ScrArea *UNUSED(area), const IDRemapper *mappings) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type != SPREADSHEET_CONTEXT_OBJECT) { - continue; - } - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; - - if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) { - object_context->object = nullptr; - continue; - } - - BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT); - } + BKE_viewer_path_id_remap(&sspreadsheet->viewer_path, mappings); } static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region) @@ -199,54 +183,105 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region) ID *ED_spreadsheet_get_current_id(const struct SpaceSpreadsheet *sspreadsheet) { - if (BLI_listbase_is_empty(&sspreadsheet->context_path)) { + if (BLI_listbase_is_empty(&sspreadsheet->viewer_path.path)) { return nullptr; } - SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first; - if (root_context->type != SPREADSHEET_CONTEXT_OBJECT) { + ViewerPathElem *root_context = static_cast<ViewerPathElem *>( + sspreadsheet->viewer_path.path.first); + if (root_context->type != VIEWER_PATH_ELEM_TYPE_ID) { return nullptr; } - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context; - return (ID *)object_context->object; + IDViewerPathElem *id_elem = reinterpret_cast<IDViewerPathElem *>(root_context); + return id_elem->id; } -/* Check if the pinned context still exists. If it doesn't try to find a new context. */ -static void update_pinned_context_path_if_outdated(const bContext *C) +static void view_active_object(const bContext *C, SpaceSpreadsheet *sspreadsheet) { - SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - Main *bmain = CTX_data_main(C); - if (!ED_spreadsheet_context_path_exists(bmain, sspreadsheet)) { - ED_spreadsheet_context_path_guess(C, sspreadsheet); - if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) { - ED_area_tag_redraw(CTX_wm_area(C)); - } - } - - if (BLI_listbase_is_empty(&sspreadsheet->context_path)) { - /* Don't pin empty context_path, that could be annoying. */ - sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED; + BKE_viewer_path_clear(&sspreadsheet->viewer_path); + Object *ob = CTX_data_active_object(C); + if (ob == nullptr) { + return; } + IDViewerPathElem *id_elem = BKE_viewer_path_elem_new_id(); + id_elem->id = &ob->id; + BLI_addtail(&sspreadsheet->viewer_path.path, id_elem); + ED_area_tag_redraw(CTX_wm_area(C)); } -static void update_context_path_from_context(const bContext *C) +static void spreadsheet_update_context(const bContext *C) { + using blender::ed::viewer_path::ViewerPathForGeometryNodesViewer; + SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - if (!ED_spreadsheet_context_path_is_active(C, sspreadsheet)) { - ED_spreadsheet_context_path_guess(C, sspreadsheet); - if (ED_spreadsheet_context_path_update_tag(sspreadsheet)) { - ED_area_tag_redraw(CTX_wm_area(C)); + Object *active_object = CTX_data_active_object(C); + Object *context_object = blender::ed::viewer_path::parse_object_only(sspreadsheet->viewer_path); + switch (eSpaceSpreadsheet_ObjectEvalState(sspreadsheet->object_eval_state)) { + case SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL: + case SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED: { + if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) { + if (context_object == nullptr) { + /* Object is not available anymore, so clear the pinning. */ + sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED; + } + else { + /* The object is still pinned, do nothing. */ + break; + } + } + else { + if (active_object != context_object) { + /* The active object has changed, so view the new active object. */ + view_active_object(C, sspreadsheet); + } + else { + /* Nothing changed. */ + break; + } + } + break; } - } -} + case SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE: { + WorkSpace *workspace = CTX_wm_workspace(C); + if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) { + const std::optional<ViewerPathForGeometryNodesViewer> parsed_path = + blender::ed::viewer_path::parse_geometry_nodes_viewer(sspreadsheet->viewer_path); + if (parsed_path.has_value()) { + if (blender::ed::viewer_path::exists_geometry_nodes_viewer(*parsed_path)) { + /* The pinned path is still valid, do nothing. */ + break; + } + else { + /* The pinned path does not exist anymore, clear pinning. */ + sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED; + } + } + else { + /* Unknown pinned path, clear pinning. */ + sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED; + } + } + /* Now try to update the viewer path from the workspace. */ + const std::optional<ViewerPathForGeometryNodesViewer> workspace_parsed_path = + blender::ed::viewer_path::parse_geometry_nodes_viewer(workspace->viewer_path); + if (workspace_parsed_path.has_value()) { + if (BKE_viewer_path_equal(&sspreadsheet->viewer_path, &workspace->viewer_path)) { + /* Nothing changed. */ + break; + } + else { + /* Update the viewer path from the workspace. */ + BKE_viewer_path_clear(&sspreadsheet->viewer_path); + BKE_viewer_path_copy(&sspreadsheet->viewer_path, &workspace->viewer_path); + } + } + else { + /* No active viewer node, change back to showing evaluated active object. */ + sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED; + view_active_object(C, sspreadsheet); + } -void spreadsheet_update_context_path(const bContext *C) -{ - SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); - if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) { - update_pinned_context_path_if_outdated(C); - } - else { - update_context_path_from_context(C); + break; + } } } @@ -388,7 +423,7 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); sspreadsheet->runtime->cache.set_all_unused(); - spreadsheet_update_context_path(C); + spreadsheet_update_context(C); std::unique_ptr<DataSource> data_source = get_data_source(C); if (!data_source) { @@ -437,6 +472,7 @@ static void spreadsheet_main_region_listener(const wmRegionListenerParams *param { ARegion *region = params->region; const wmNotifier *wmn = params->notifier; + SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first); switch (wmn->category) { case NC_SCENE: { @@ -465,6 +501,12 @@ static void spreadsheet_main_region_listener(const wmRegionListenerParams *param ED_region_tag_redraw(region); break; } + case NC_VIEWER_PATH: { + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { + ED_region_tag_redraw(region); + } + break; + } } } @@ -475,7 +517,7 @@ static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion static void spreadsheet_header_region_draw(const bContext *C, ARegion *region) { - spreadsheet_update_context_path(C); + spreadsheet_update_context(C); ED_region_header(C, region); } @@ -487,6 +529,7 @@ static void spreadsheet_header_region_listener(const wmRegionListenerParams *par { ARegion *region = params->region; const wmNotifier *wmn = params->notifier; + SpaceSpreadsheet *sspreadsheet = static_cast<SpaceSpreadsheet *>(params->area->spacedata.first); switch (wmn->category) { case NC_SCENE: { @@ -513,6 +556,12 @@ static void spreadsheet_header_region_listener(const wmRegionListenerParams *par ED_region_tag_redraw(region); break; } + case NC_VIEWER_PATH: { + if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { + ED_region_tag_redraw(region); + } + break; + } } } @@ -591,7 +640,7 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region) { - spreadsheet_update_context_path(C); + spreadsheet_update_context(C); ED_region_panels(C, region); } @@ -613,6 +662,57 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS { } +static void spreadsheet_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; + + sspreadsheet->runtime = nullptr; + BLO_read_list(reader, &sspreadsheet->row_filters); + LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { + BLO_read_data_address(reader, &row_filter->value_string); + } + BLO_read_list(reader, &sspreadsheet->columns); + LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) { + BLO_read_data_address(reader, &column->id); + BLO_read_data_address(reader, &column->id->name); + /* While the display name is technically runtime data, it is loaded here, otherwise the row + * filters might not now their type if their region draws before the main region. + * This would ideally be cleared here. */ + BLO_read_data_address(reader, &column->display_name); + } + + BKE_viewer_path_blend_read_data(reader, &sspreadsheet->viewer_path); +} + +static void spreadsheet_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; + BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &sspreadsheet->viewer_path); +} + +static void spreadsheet_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceSpreadsheet, sl); + SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; + + LISTBASE_FOREACH (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { + BLO_write_struct(writer, SpreadsheetRowFilter, row_filter); + BLO_write_string(writer, row_filter->value_string); + } + + LISTBASE_FOREACH (SpreadsheetColumn *, column, &sspreadsheet->columns) { + BLO_write_struct(writer, SpreadsheetColumn, column); + BLO_write_struct(writer, SpreadsheetColumnID, column->id); + BLO_write_string(writer, column->id->name); + /* While the display name is technically runtime data, we write it here, otherwise the row + * filters might not now their type if their region draws before the main region. + * This would ideally be cleared here. */ + BLO_write_string(writer, column->display_name); + } + + BKE_viewer_path_blend_write(writer, &sspreadsheet->viewer_path); +} + void ED_spacetype_spreadsheet() { SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet"); @@ -628,6 +728,9 @@ void ED_spacetype_spreadsheet() st->operatortypes = spreadsheet_operatortypes; st->keymap = spreadsheet_keymap; st->id_remap = spreadsheet_id_remap; + st->blend_read_data = spreadsheet_blend_read_data; + st->blend_read_lib = spreadsheet_blend_read_lib; + st->blend_write = spreadsheet_blend_write; /* regions: main window */ art = MEM_cnew<ARegionType>("spacetype spreadsheet region"); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc deleted file mode 100644 index ec9fa72edb1..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc +++ /dev/null @@ -1,591 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#include "MEM_guardedalloc.h" - -#include "BLI_hash.h" -#include "BLI_hash.hh" -#include "BLI_hash_mm2a.h" -#include "BLI_listbase.h" -#include "BLI_string.h" -#include "BLI_utildefines.h" -#include "BLI_vector.hh" - -#include "ED_screen.h" -#include "ED_spreadsheet.h" - -#include "DEG_depsgraph.h" - -#include "BKE_context.h" -#include "BKE_main.h" -#include "BKE_modifier.h" -#include "BKE_node.h" -#include "BKE_object.h" -#include "BKE_workspace.h" - -#include "DNA_modifier_types.h" -#include "DNA_windowmanager_types.h" - -#include "spreadsheet_context.hh" - -using blender::IndexRange; -using blender::Span; -using blender::StringRef; -using blender::Vector; - -namespace blender::ed::spreadsheet { - -static SpreadsheetContextObject *spreadsheet_context_object_new() -{ - SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__); - context->base.type = SPREADSHEET_CONTEXT_OBJECT; - return context; -} - -static SpreadsheetContextObject *spreadsheet_context_object_copy( - const SpreadsheetContextObject *src_context) -{ - SpreadsheetContextObject *new_context = spreadsheet_context_object_new(); - new_context->object = src_context->object; - return new_context; -} - -static void spreadsheet_context_object_hash(const SpreadsheetContextObject *context, - BLI_HashMurmur2A *mm2) -{ - BLI_hash_mm2a_add(mm2, (const uchar *)&context->object, sizeof(Object *)); -} - -static void spreadsheet_context_object_free(SpreadsheetContextObject *context) -{ - MEM_freeN(context); -} - -static SpreadsheetContextModifier *spreadsheet_context_modifier_new() -{ - SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__); - context->base.type = SPREADSHEET_CONTEXT_MODIFIER; - return context; -} - -static SpreadsheetContextModifier *spreadsheet_context_modifier_copy( - const SpreadsheetContextModifier *src_context) -{ - SpreadsheetContextModifier *new_context = spreadsheet_context_modifier_new(); - if (src_context->modifier_name) { - new_context->modifier_name = BLI_strdup(src_context->modifier_name); - } - return new_context; -} - -static void spreadsheet_context_modifier_hash(const SpreadsheetContextModifier *context, - BLI_HashMurmur2A *mm2) -{ - if (context->modifier_name) { - BLI_hash_mm2a_add(mm2, (const uchar *)context->modifier_name, strlen(context->modifier_name)); - } -} - -static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *context) -{ - if (context->modifier_name) { - MEM_freeN(context->modifier_name); - } - MEM_freeN(context); -} - -static SpreadsheetContextNode *spreadsheet_context_node_new() -{ - SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__); - context->base.type = SPREADSHEET_CONTEXT_NODE; - return context; -} - -static SpreadsheetContextNode *spreadsheet_context_node_copy( - const SpreadsheetContextNode *src_context) -{ - SpreadsheetContextNode *new_context = spreadsheet_context_node_new(); - if (src_context->node_name) { - new_context->node_name = BLI_strdup(src_context->node_name); - } - return new_context; -} - -static void spreadsheet_context_node_hash(const SpreadsheetContextNode *context, - BLI_HashMurmur2A *mm2) -{ - if (context->node_name) { - BLI_hash_mm2a_add(mm2, (const uchar *)context->node_name, strlen(context->node_name)); - } -} - -static void spreadsheet_context_node_free(SpreadsheetContextNode *context) -{ - if (context->node_name) { - MEM_freeN(context->node_name); - } - MEM_freeN(context); -} - -SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type) -{ - switch (type) { - case SPREADSHEET_CONTEXT_OBJECT: { - return (SpreadsheetContext *)spreadsheet_context_object_new(); - } - case SPREADSHEET_CONTEXT_MODIFIER: { - return (SpreadsheetContext *)spreadsheet_context_modifier_new(); - } - case SPREADSHEET_CONTEXT_NODE: { - return (SpreadsheetContext *)spreadsheet_context_node_new(); - } - } - BLI_assert_unreachable(); - return nullptr; -} - -SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context) -{ - switch (old_context->type) { - case SPREADSHEET_CONTEXT_OBJECT: { - return (SpreadsheetContext *)spreadsheet_context_object_copy( - (const SpreadsheetContextObject *)old_context); - } - case SPREADSHEET_CONTEXT_MODIFIER: { - return (SpreadsheetContext *)spreadsheet_context_modifier_copy( - (const SpreadsheetContextModifier *)old_context); - } - case SPREADSHEET_CONTEXT_NODE: { - return (SpreadsheetContext *)spreadsheet_context_node_copy( - (const SpreadsheetContextNode *)old_context); - } - } - BLI_assert_unreachable(); - return nullptr; -} - -static void spreadsheet_context_hash(const SpreadsheetContext *context, BLI_HashMurmur2A *mm2) -{ - BLI_hash_mm2a_add_int(mm2, context->type); - switch (context->type) { - case SPREADSHEET_CONTEXT_OBJECT: { - spreadsheet_context_object_hash((const SpreadsheetContextObject *)context, mm2); - break; - } - case SPREADSHEET_CONTEXT_MODIFIER: { - spreadsheet_context_modifier_hash((const SpreadsheetContextModifier *)context, mm2); - break; - } - case SPREADSHEET_CONTEXT_NODE: { - spreadsheet_context_node_hash((const SpreadsheetContextNode *)context, mm2); - break; - } - } -} - -void spreadsheet_context_free(SpreadsheetContext *context) -{ - switch (context->type) { - case SPREADSHEET_CONTEXT_OBJECT: { - return spreadsheet_context_object_free((SpreadsheetContextObject *)context); - } - case SPREADSHEET_CONTEXT_MODIFIER: { - return spreadsheet_context_modifier_free((SpreadsheetContextModifier *)context); - } - case SPREADSHEET_CONTEXT_NODE: { - return spreadsheet_context_node_free((SpreadsheetContextNode *)context); - } - } - BLI_assert_unreachable(); -} - -/** - * Tag any data relevant to the spreadsheet's context for recalculation in order to collect - * information to display in the editor, which may be cached during evaluation. - * \return True when any data has been tagged for update. - */ -static bool spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet) -{ - using namespace blender; - Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path; - if (context_path.is_empty()) { - return false; - } - if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return false; - } - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0]; - Object *object = object_context->object; - if (object == nullptr) { - return false; - } - if (context_path.size() == 1) { - /* No need to reevaluate, when the final or original object is viewed. */ - return false; - } - - DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); - return true; -} - -} // namespace blender::ed::spreadsheet - -SpreadsheetContext *ED_spreadsheet_context_new(int type) -{ - return blender::ed::spreadsheet::spreadsheet_context_new((eSpaceSpreadsheet_ContextType)type); -} - -void ED_spreadsheet_context_free(struct SpreadsheetContext *context) -{ - blender::ed::spreadsheet::spreadsheet_context_free(context); -} - -void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet) -{ - LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) { - ED_spreadsheet_context_free(context); - } - BLI_listbase_clear(&sspreadsheet->context_path); -} - -bool ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet) -{ - return blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet); -} - -uint64_t ED_spreadsheet_context_path_hash(const SpaceSpreadsheet *sspreadsheet) -{ - BLI_HashMurmur2A mm2; - BLI_hash_mm2a_init(&mm2, 1234); - LISTBASE_FOREACH (const SpreadsheetContext *, context, &sspreadsheet->context_path) { - blender::ed::spreadsheet::spreadsheet_context_hash(context, &mm2); - } - return BLI_hash_mm2a_end(&mm2); -} - -void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet, - struct SpaceNode *snode, - struct bNode *node) -{ - using namespace blender::ed::spreadsheet; - - Object *object = (Object *)snode->id; - /* Try to find the modifier the node tree belongs to. */ - ModifierData *modifier = BKE_object_active_modifier(object); - if (modifier && modifier->type != eModifierType_Nodes) { - modifier = nullptr; - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - if (md->type == eModifierType_Nodes) { - NodesModifierData *nmd = (NodesModifierData *)md; - if (nmd->node_group == snode->nodetree) { - modifier = md; - break; - } - } - } - } - if (modifier == nullptr) { - return; - } - - ED_spreadsheet_context_path_clear(sspreadsheet); - - { - SpreadsheetContextObject *context = spreadsheet_context_object_new(); - context->object = object; - BLI_addtail(&sspreadsheet->context_path, context); - } - { - SpreadsheetContextModifier *context = spreadsheet_context_modifier_new(); - context->modifier_name = BLI_strdup(modifier->name); - BLI_addtail(&sspreadsheet->context_path, context); - } - { - int i; - LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) { - if (i == 0) { - continue; - } - SpreadsheetContextNode *context = spreadsheet_context_node_new(); - context->node_name = BLI_strdup(path->node_name); - BLI_addtail(&sspreadsheet->context_path, context); - } - } - { - SpreadsheetContextNode *context = spreadsheet_context_node_new(); - context->node_name = BLI_strdup(node->name); - BLI_addtail(&sspreadsheet->context_path, context); - } - - sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE; -} - -void ED_spreadsheet_context_paths_set_geometry_node(Main *bmain, SpaceNode *snode, bNode *node) -{ - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - if (wm == nullptr) { - return; - } - LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { - bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = (SpaceLink *)area->spacedata.first; - if (sl->spacetype == SPACE_SPREADSHEET) { - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - if ((sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) == 0) { - const uint64_t context_hash_before = ED_spreadsheet_context_path_hash(sspreadsheet); - ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node); - const uint64_t context_hash_after = ED_spreadsheet_context_path_hash(sspreadsheet); - if (context_hash_before != context_hash_after) { - ED_spreadsheet_context_path_update_tag(sspreadsheet); - } - ED_area_tag_redraw(area); - } - } - } - } -} - -void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreadsheet, - Object *object) -{ - using namespace blender::ed::spreadsheet; - ED_spreadsheet_context_path_clear(sspreadsheet); - - SpreadsheetContextObject *context = spreadsheet_context_object_new(); - context->object = object; - BLI_addtail(&sspreadsheet->context_path, context); -} - -static bScreen *find_screen_to_search_for_context(wmWindow *window, - SpaceSpreadsheet *current_space) -{ - bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); - if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) { - /* If the spreadsheet is maximized, try to find the context in the unmaximized screen. */ - ScrArea *main_area = (ScrArea *)screen->areabase.first; - SpaceLink *sl = (SpaceLink *)main_area->spacedata.first; - if (sl == (SpaceLink *)current_space) { - return main_area->full; - } - } - return screen; -} - -void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet) -{ - ED_spreadsheet_context_path_clear(sspreadsheet); - - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - if (wm == nullptr) { - return; - } - - if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { - LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { - bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = (SpaceLink *)area->spacedata.first; - if (sl == nullptr) { - continue; - } - if (sl->spacetype == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)sl; - if (snode->edittree != nullptr) { - if (snode->edittree->type == NTREE_GEOMETRY) { - LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - if (node->type == GEO_NODE_VIEWER) { - if (node->flag & NODE_DO_OUTPUT) { - ED_spreadsheet_context_path_set_geometry_node(sspreadsheet, snode, node); - return; - } - } - } - } - } - } - } - } - } - - Object *active_object = CTX_data_active_object(C); - if (active_object != nullptr) { - ED_spreadsheet_context_path_set_evaluated_object(sspreadsheet, active_object); - return; - } -} - -bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *sspreadsheet) -{ - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - if (wm == nullptr) { - return false; - } - Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path; - if (context_path.is_empty()) { - return false; - } - if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return false; - } - Object *object = ((SpreadsheetContextObject *)context_path[0])->object; - if (object == nullptr) { - return false; - } - if (context_path.size() == 1) { - if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { - return false; - } - Object *active_object = CTX_data_active_object(C); - return object == active_object; - } - if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { - return false; - } - if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { - return false; - } - const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name; - const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name); - if (modifier == nullptr) { - return false; - } - const bool modifier_is_active = modifier->flag & eModifierFlag_Active; - if (modifier->type != eModifierType_Nodes) { - return false; - } - bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group; - if (root_node_tree == nullptr) { - return false; - } - const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2); - if (node_context_path.is_empty()) { - return false; - } - - LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { - bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = (SpaceLink *)area->spacedata.first; - if (sl == nullptr) { - continue; - } - if (sl->spacetype != SPACE_NODE) { - continue; - } - SpaceNode *snode = (SpaceNode *)sl; - if (snode->nodetree != root_node_tree) { - continue; - } - if (!modifier_is_active) { - if (!(snode->flag & SNODE_PIN)) { - /* Node tree has to be pinned when the modifier is not active. */ - continue; - } - } - if (snode->id != &object->id) { - continue; - } - Vector<bNodeTreePath *> tree_path = snode->treepath; - if (node_context_path.size() != tree_path.size()) { - continue; - } - int valid_count = 0; - for (const int i : IndexRange(tree_path.size() - 1)) { - if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) { - break; - } - SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)node_context_path[i]; - if (!STREQ(node_context->node_name, tree_path[i + 1]->node_name)) { - break; - } - valid_count++; - } - if (valid_count != tree_path.size() - 1) { - continue; - } - SpreadsheetContext *last_context = node_context_path.last(); - if (last_context->type != SPREADSHEET_CONTEXT_NODE) { - return false; - } - const char *node_name = ((SpreadsheetContextNode *)last_context)->node_name; - bNode *node = nodeFindNodebyName(snode->edittree, node_name); - if (node == nullptr) { - return false; - } - if (node->type != GEO_NODE_VIEWER) { - return false; - } - if (!(node->flag & NODE_DO_OUTPUT)) { - return false; - } - return true; - } - } - return false; -} - -bool ED_spreadsheet_context_path_exists(Main *UNUSED(bmain), SpaceSpreadsheet *sspreadsheet) -{ - Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path; - if (context_path.is_empty()) { - return false; - } - if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return false; - } - Object *object = ((SpreadsheetContextObject *)context_path[0])->object; - if (object == nullptr) { - return false; - } - if (context_path.size() == 1) { - return true; - } - if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { - return false; - } - const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name; - const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name); - if (modifier == nullptr) { - return false; - } - if (modifier->type != eModifierType_Nodes) { - return false; - } - bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group; - if (root_node_tree == nullptr) { - return false; - } - const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2); - if (node_context_path.is_empty()) { - return false; - } - bNodeTree *node_tree = root_node_tree; - for (const int i : node_context_path.index_range()) { - if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) { - return false; - } - const char *node_name = ((SpreadsheetContextNode *)node_context_path[i])->node_name; - bNode *node = nodeFindNodebyName(node_tree, node_name); - if (node == nullptr) { - return false; - } - if (node->type == GEO_NODE_VIEWER) { - if (i == node_context_path.index_range().last()) { - return true; - } - return false; - } - if (node->id != nullptr) { - if (GS(node->id->name) != ID_NT) { - return false; - } - node_tree = (bNodeTree *)node->id; - } - else { - return false; - } - } - return false; -} diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.hh b/source/blender/editors/space_spreadsheet/spreadsheet_context.hh deleted file mode 100644 index 758ae392894..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.hh +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -#include "DNA_space_types.h" - -namespace blender::ed::spreadsheet { - -SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type); -SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context); -void spreadsheet_context_free(SpreadsheetContext *context); - -} // namespace blender::ed::spreadsheet 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 fd2ac4d39a1..8af12590b0f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -98,7 +98,8 @@ void GeometryDataSource::foreach_default_column_ids( } SpreadsheetColumnID column_id; column_id.name = (char *)attribute_id.name().data(); - fn(column_id, false); + const bool is_front = attribute_id.name() == ".viewer"; + fn(column_id, is_front); return true; }); @@ -228,7 +229,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( return {}; } - return std::make_unique<ColumnValues>(column_id.name, std::move(varray)); + StringRefNull column_display_name = column_id.name; + if (column_display_name == ".viewer") { + column_display_name = "Viewer"; + } + + return std::make_unique<ColumnValues>(column_display_name, std::move(varray)); } int GeometryDataSource::tot_rows() const @@ -463,7 +469,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly); } else { - if (BLI_listbase_count(&sspreadsheet->context_path) == 1) { + 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; @@ -471,8 +477,8 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } else { if (const ViewerNodeLog *viewer_log = - nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_spreadsheet( - *sspreadsheet)) { + nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path( + sspreadsheet->viewer_path)) { geometry_set = viewer_log->geometry; } } @@ -481,25 +487,6 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread return geometry_set; } -static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet, - Map<std::string, GField> &r_fields) -{ - if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE) { - return; - } - if (BLI_listbase_count(&sspreadsheet->context_path) <= 1) { - /* No viewer is currently referenced by the context path. */ - return; - } - if (const ViewerNodeLog *viewer_log = - nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_spreadsheet( - *sspreadsheet)) { - if (viewer_log->field) { - r_fields.add("Viewer", viewer_log->field); - } - } -} - class GeometryComponentCacheKey : public SpreadsheetCache::Key { public: /* Use the pointer to the geometry component as a key to detect when the geometry changed. */ @@ -531,38 +518,6 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value { Map<std::pair<eAttrDomain, GField>, GArray<>> arrays; }; -static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, - const GeometryComponent &component, - ExtraColumns &r_extra_columns) -{ - Map<std::string, GField> fields_to_show; - find_fields_to_evaluate(sspreadsheet, fields_to_show); - - GeometryComponentCacheValue &cache = - sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>( - std::make_unique<GeometryComponentCacheKey>(component)); - - const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain; - const int domain_num = component.attribute_domain_size(domain); - for (const auto item : fields_to_show.items()) { - const StringRef name = item.key; - const GField &field = item.value; - - /* Use the cached evaluated array if it exists, otherwise evaluate the field now. */ - GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() { - GArray<> evaluated_array(field.cpp_type(), domain_num); - - bke::GeometryFieldContext field_context{component, domain}; - fn::FieldEvaluator field_evaluator{field_context, domain_num}; - field_evaluator.add_with_destination(field, evaluated_array); - field_evaluator.evaluate(); - return evaluated_array; - }); - - r_extra_columns.add(name, evaluated_array.as_span()); - } -} - std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval) { SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); @@ -574,15 +529,11 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object return {}; } - const GeometryComponent &component = *geometry_set.get_component_for_read(component_type); - ExtraColumns extra_columns; - add_fields_as_extra_columns(sspreadsheet, component, extra_columns); - if (component_type == GEO_COMPONENT_TYPE_VOLUME) { return std::make_unique<VolumeDataSource>(std::move(geometry_set)); } return std::make_unique<GeometryDataSource>( - object_eval, std::move(geometry_set), component_type, domain, std::move(extra_columns)); + object_eval, std::move(geometry_set), component_type, domain); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 71bc4768949..478b3372427 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -54,7 +54,7 @@ class GeometryDataSource : public DataSource { GeometrySet geometry_set, const GeometryComponentType component_type, const eAttrDomain domain, - ExtraColumns extra_columns) + ExtraColumns extra_columns = {}) : object_eval_(object_eval), geometry_set_(std::move(geometry_set)), component_(geometry_set_.get_component_for_read(component_type)), diff --git a/source/blender/editors/space_statusbar/CMakeLists.txt b/source/blender/editors/space_statusbar/CMakeLists.txt index cf0ccd4e552..f73e03815a3 100644 --- a/source/blender/editors/space_statusbar/CMakeLists.txt +++ b/source/blender/editors/space_statusbar/CMakeLists.txt @@ -11,6 +11,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -28,5 +31,5 @@ set(LIB blender_add_lib(bf_editor_space_statusbar "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_statusbar bf_rna) diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c index e99e8f21364..e82eeeed93a 100644 --- a/source/blender/editors/space_statusbar/space_statusbar.c +++ b/source/blender/editors/space_statusbar/space_statusbar.c @@ -21,6 +21,8 @@ #include "UI_interface.h" +#include "BLO_read_write.h" + #include "WM_api.h" #include "WM_message.h" #include "WM_types.h" @@ -130,6 +132,11 @@ static void statusbar_header_region_message_subscribe(const wmRegionMessageSubsc WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw); } +static void statusbar_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceStatusBar, sl); +} + void ED_spacetype_statusbar(void) { SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar"); @@ -144,6 +151,7 @@ void ED_spacetype_statusbar(void) st->duplicate = statusbar_duplicate; st->operatortypes = statusbar_operatortypes; st->keymap = statusbar_keymap; + st->blend_write = statusbar_blend_write; /* regions: header window */ art = MEM_callocN(sizeof(*art), "spacetype statusbar header region"); diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 38787a84fce..dfd6111e067 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -5,12 +5,16 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../gpu ../../makesdna ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern ) @@ -47,3 +51,6 @@ endif() blender_add_lib(bf_editor_space_text "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# dna_type_offsets.h +add_dependencies(bf_editor_space_text bf_dna) diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index be9bbdf109e..5b9b3651459 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -29,6 +29,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "RNA_path.h" @@ -395,6 +397,23 @@ static void text_id_remap(ScrArea *UNUSED(area), BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL); } +static void text_blend_read_data(BlendDataReader *UNUSED(reader), SpaceLink *sl) +{ + SpaceText *st = (SpaceText *)sl; + memset(&st->runtime, 0x0, sizeof(st->runtime)); +} + +static void text_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + SpaceText *st = (SpaceText *)sl; + BLO_read_id_address(reader, parent_id->lib, &st->text); +} + +static void text_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceText, sl); +} + /********************* registration ********************/ void ED_spacetype_text(void) @@ -415,6 +434,9 @@ void ED_spacetype_text(void) st->context = text_context; st->dropboxes = text_dropboxes; st->id_remap = text_id_remap; + st->blend_read_data = text_blend_read_data; + st->blend_read_lib = text_blend_read_lib; + st->blend_write = text_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype text region"); diff --git a/source/blender/editors/space_topbar/CMakeLists.txt b/source/blender/editors/space_topbar/CMakeLists.txt index f529c855e6d..a0854bd688c 100644 --- a/source/blender/editors/space_topbar/CMakeLists.txt +++ b/source/blender/editors/space_topbar/CMakeLists.txt @@ -11,6 +11,9 @@ set(INC ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern # RNA_prototypes.h ${CMAKE_BINARY_DIR}/source/blender/makesrna ) @@ -27,5 +30,5 @@ set(LIB blender_add_lib(bf_editor_space_topbar "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# RNA_prototypes.h +# RNA_prototypes.h dna_type_offsets.h add_dependencies(bf_editor_space_topbar bf_rna) diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index e4826ed5964..aa5689bd047 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -28,6 +28,8 @@ #include "UI_resources.h" #include "UI_view2d.h" +#include "BLO_read_write.h" + #include "RNA_access.h" #include "WM_api.h" @@ -282,6 +284,11 @@ static void undo_history_menu_register(void) WM_menutype_add(mt); } +static void topbar_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceTopBar, sl); +} + void ED_spacetype_topbar(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar"); @@ -296,6 +303,7 @@ void ED_spacetype_topbar(void) st->duplicate = topbar_duplicate; st->operatortypes = topbar_operatortypes; st->keymap = topbar_keymap; + st->blend_write = topbar_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype topbar main region"); diff --git a/source/blender/editors/space_userpref/CMakeLists.txt b/source/blender/editors/space_userpref/CMakeLists.txt index 37408dd85af..e75d5b28ffd 100644 --- a/source/blender/editors/space_userpref/CMakeLists.txt +++ b/source/blender/editors/space_userpref/CMakeLists.txt @@ -4,10 +4,14 @@ set(INC ../include ../../blenkernel ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern ) set(INC_SYS @@ -25,3 +29,6 @@ set(LIB ) blender_add_lib(bf_editor_space_userpref "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# dna_type_offsets.h +add_dependencies(bf_editor_space_userpref bf_dna) diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 06a4c1d8702..1516435c6fc 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -27,6 +27,8 @@ #include "UI_interface.h" +#include "BLO_read_write.h" + /* ******************** default callbacks for userpref space ***************** */ static SpaceLink *userpref_create(const ScrArea *area, const Scene *UNUSED(scene)) @@ -183,6 +185,11 @@ static void userpref_execute_region_listener(const wmRegionListenerParams *UNUSE { } +static void userpref_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + BLO_write_struct(writer, SpaceUserPref, sl); +} + void ED_spacetype_userpref(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype userpref"); @@ -197,6 +204,7 @@ void ED_spacetype_userpref(void) st->duplicate = userpref_duplicate; st->operatortypes = userpref_operatortypes; st->keymap = userpref_keymap; + st->blend_write = userpref_blend_write; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype userpref region"); diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 59519fcc0d3..579e27b9259 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -5,6 +5,7 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../bmesh ../../depsgraph @@ -41,11 +42,11 @@ set(SRC view3d_gizmo_navigate.c view3d_gizmo_navigate_type.c view3d_gizmo_preselect.c - view3d_gizmo_preselect_type.c + view3d_gizmo_preselect_type.cc view3d_gizmo_ruler.c view3d_gizmo_tool_generic.c view3d_header.c - view3d_iterators.c + view3d_iterators.cc view3d_navigate.c view3d_navigate_dolly.c view3d_navigate_fly.c diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 995ee6abe61..345958d86ec 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -5,6 +5,9 @@ * \ingroup spview3d */ +/* Allow using deprecated functionality for .blend file I/O. */ +#define DNA_DEPRECATED_ALLOW + #include <stdio.h> #include <string.h> @@ -29,6 +32,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_lattice.h" @@ -40,6 +44,7 @@ #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_viewer_path.h" #include "BKE_workspace.h" #include "ED_object.h" @@ -49,6 +54,7 @@ #include "ED_space_api.h" #include "ED_transform.h" #include "ED_undo.h" +#include "ED_viewer_path.hh" #include "GPU_matrix.h" @@ -67,6 +73,8 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "BLO_read_write.h" + #ifdef WITH_PYTHON # include "BPY_extern.h" #endif @@ -316,6 +324,8 @@ static void view3d_free(SpaceLink *sl) IDP_FreeProperty(vd->shading.prop); vd->shading.prop = nullptr; } + + BKE_viewer_path_clear(&vd->viewer_path); } /* spacetype; init callback */ @@ -354,6 +364,8 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl) v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop); } + BKE_viewer_path_copy(&v3dn->viewer_path, &v3do->viewer_path); + /* copy or clear inside new stuff */ return (SpaceLink *)v3dn; @@ -1313,6 +1325,16 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params) /* In case the region displays workspace settings. */ ED_region_tag_redraw(region); break; + case NC_VIEWER_PATH: { + if (v3d->flag2 & V3D_SHOW_VIEWER) { + ViewLayer *view_layer = WM_window_get_active_view_layer(window); + if (Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer)) { + ED_render_view3d_update(depsgraph, window, area, true); + } + ED_region_tag_redraw(region); + } + break; + } } } @@ -1974,6 +1996,60 @@ static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRema /* Object centers in local-view aren't used, see: T52663 */ view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true); } + BKE_viewer_path_id_remap(&view3d->viewer_path, mappings); +} + +static void view3d_blend_read_data(BlendDataReader *reader, SpaceLink *sl) +{ + View3D *v3d = (View3D *)sl; + + memset(&v3d->runtime, 0x0, sizeof(v3d->runtime)); + + if (v3d->gpd) { + BLO_read_data_address(reader, &v3d->gpd); + BKE_gpencil_blend_read_data(reader, v3d->gpd); + } + BLO_read_data_address(reader, &v3d->localvd); + + /* render can be quite heavy, set to solid on load */ + if (v3d->shading.type == OB_RENDER) { + v3d->shading.type = OB_SOLID; + } + v3d->shading.prev_type = OB_SOLID; + + BKE_screen_view3d_shading_blend_read_data(reader, &v3d->shading); + + BKE_screen_view3d_do_versions_250(v3d, &sl->regionbase); + + BKE_viewer_path_blend_read_data(reader, &v3d->viewer_path); +} + +static void view3d_blend_read_lib(BlendLibReader *reader, ID *parent_id, SpaceLink *sl) +{ + View3D *v3d = (View3D *)sl; + + BLO_read_id_address(reader, parent_id->lib, &v3d->camera); + BLO_read_id_address(reader, parent_id->lib, &v3d->ob_center); + + if (v3d->localvd) { + BLO_read_id_address(reader, parent_id->lib, &v3d->localvd->camera); + } + + BKE_viewer_path_blend_read_lib(reader, parent_id->lib, &v3d->viewer_path); +} + +static void view3d_blend_write(BlendWriter *writer, SpaceLink *sl) +{ + View3D *v3d = (View3D *)sl; + BLO_write_struct(writer, View3D, v3d); + + if (v3d->localvd) { + BLO_write_struct(writer, View3D, v3d->localvd); + } + + BKE_screen_view3d_shading_blend_write(writer, &v3d->shading); + + BKE_viewer_path_blend_write(writer, &v3d->viewer_path); } void ED_spacetype_view3d(void) @@ -1997,6 +2073,9 @@ void ED_spacetype_view3d(void) st->gizmos = view3d_widgets; st->context = view3d_context; st->id_remap = view3d_id_remap; + st->blend_read_data = view3d_blend_read_data; + st->blend_read_lib = view3d_blend_read_lib; + st->blend_write = view3d_blend_write; /* regions: main window */ art = MEM_cnew<ARegionType>("spacetype view3d main region"); diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index 9686609fa65..57c104455cd 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -55,6 +55,7 @@ #include "ED_screen_types.h" #include "ED_transform.h" #include "ED_view3d_offscreen.h" +#include "ED_viewer_path.hh" #include "DEG_depsgraph_query.h" @@ -121,8 +122,8 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, else { float rect_scale[2]; if (rect) { - rect_scale[0] = (float)BLI_rcti_size_x(rect) / (float)region->winx; - rect_scale[1] = (float)BLI_rcti_size_y(rect) / (float)region->winy; + rect_scale[0] = float(BLI_rcti_size_x(rect)) / float(region->winx); + rect_scale[1] = float(BLI_rcti_size_y(rect)) / float(region->winy); } /* NOTE: calls BKE_object_where_is_calc for camera... */ view3d_viewmatrix_set(depsgraph, scene, v3d, rv3d, rect ? rect_scale : nullptr); @@ -138,11 +139,11 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, if (!offscreen && rv3d->persp == RV3D_CAMOB && v3d->camera) { rctf cameraborder; ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, &cameraborder, false); - rv3d->viewcamtexcofac[0] = (float)region->winx / BLI_rctf_size_x(&cameraborder); - rv3d->viewcamtexcofac[1] = (float)region->winy / BLI_rctf_size_y(&cameraborder); + rv3d->viewcamtexcofac[0] = float(region->winx) / BLI_rctf_size_x(&cameraborder); + rv3d->viewcamtexcofac[1] = float(region->winy) / BLI_rctf_size_y(&cameraborder); - rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)region->winx; - rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)region->winy; + rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / float(region->winx); + rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / float(region->winy); } else { rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; @@ -167,10 +168,10 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); if (rect) { - len_sc = (float)max_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)); + len_sc = float(max_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect))); } else { - len_sc = (float)MAX2(region->winx, region->winy); + len_sc = float(MAX2(region->winx, region->winy)); } rv3d->pixsize = len_px / len_sc; @@ -560,10 +561,10 @@ static void drawviewborder(Scene *scene, Depsgraph *depsgraph, ARegion *region, * obscures the 3D camera border */ /* NOTE: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticeable * but keep it here in case we need to remove the workaround */ - x1i = (int)(x1 - 1.0001f); - y1i = (int)(y1 - 1.0001f); - x2i = (int)(x2 + (1.0f - 0.0001f)); - y2i = (int)(y2 + (1.0f - 0.0001f)); + x1i = int(x1 - 1.0001f); + y1i = int(y1 - 1.0001f); + x2i = int(x2 + (1.0f - 0.0001f)); + y2i = int(y2 + (1.0f - 0.0001f)); uint shdr_pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); @@ -842,7 +843,7 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit) if (r_grid_unit) { *r_grid_unit = BKE_unit_display_name_get(usys, i); } - return (float)BKE_unit_scalar_get(usys, i) / scene->unit.scale_length; + return float(BKE_unit_scalar_get(usys, i)) / scene->unit.scale_length; } } @@ -876,7 +877,7 @@ void ED_view3d_grid_steps(const Scene *scene, int i; for (i = 0; i < len; i++) { - r_grid_steps[i] = (float)BKE_unit_scalar_get(usys, len - 1 - i) * grid_scale; + r_grid_steps[i] = float(BKE_unit_scalar_get(usys, len - 1 - i)) * grid_scale; } for (; i < STEPS_LEN; i++) { /* Fill last slots */ @@ -1062,7 +1063,7 @@ static void draw_rotation_guide(const RegionView3D *rv3d) # define ROT_AXIS_DETAIL 13 const float s = 0.05f * scale; - const float step = 2.0f * (float)(M_PI / ROT_AXIS_DETAIL); + const float step = 2.0f * float(M_PI / ROT_AXIS_DETAIL); float q[4]; /* rotate ring so it's perpendicular to axis */ const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f; @@ -1294,7 +1295,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y * frame-number, collection, object name, bone name (if available), marker name (if available). */ static void draw_selected_name( - Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset) + const View3D *v3d, Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset) { const int cfra = scene->r.cfra; const char *msg_pin = " (Pinned)"; @@ -1385,7 +1386,7 @@ static void draw_selected_name( /* color depends on whether there is a keyframe */ if (id_frame_has_keyframe( - (ID *)ob, /* BKE_scene_ctime_get(scene) */ (float)cfra, ANIMFILTER_KEYS_LOCAL)) { + (ID *)ob, /* BKE_scene_ctime_get(scene) */ float(cfra), ANIMFILTER_KEYS_LOCAL)) { UI_FontThemeColor(font_id, TH_TIME_KEYFRAME); } else if (ED_gpencil_has_keyframe_v3d(scene, ob, cfra)) { @@ -1409,6 +1410,12 @@ static void draw_selected_name( s += sprintf(s, " <%s>", markern); } + if (v3d->flag2 & V3D_SHOW_VIEWER) { + if (!BLI_listbase_is_empty(&v3d->viewer_path.path)) { + s += sprintf(s, "%s", IFACE_(" (Viewer)")); + } + } + BLF_enable(font_id, BLF_SHADOW); BLF_shadow(font_id, 5, float4{0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); @@ -1502,7 +1509,7 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) if (U.uiflag & USER_DRAWVIEWINFO) { BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); - draw_selected_name(scene, view_layer, ob, xoffset, &yoffset); + draw_selected_name(v3d, scene, view_layer, ob, xoffset, &yoffset); } if (v3d->gridflag & (V3D_SHOW_FLOOR | V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z)) { @@ -1558,11 +1565,23 @@ RenderEngineType *ED_view3d_engine_type(const Scene *scene, int drawtype) return type; } +static void view3d_update_viewer_path(const bContext *C) +{ + View3D *v3d = CTX_wm_view3d(C); + WorkSpace *workspace = CTX_wm_workspace(C); + /* Always use viewer path from workspace, pinning is not supported currently. */ + if (!BKE_viewer_path_equal(&v3d->viewer_path, &workspace->viewer_path)) { + BKE_viewer_path_clear(&v3d->viewer_path); + BKE_viewer_path_copy(&v3d->viewer_path, &workspace->viewer_path); + } +} + void view3d_main_region_draw(const bContext *C, ARegion *region) { Main *bmain = CTX_data_main(C); View3D *v3d = CTX_wm_view3d(C); + view3d_update_viewer_path(C); view3d_draw_view(C, region); DRW_cache_free_old_subdiv(); @@ -2197,7 +2216,7 @@ void ED_view3d_select_id_validate(ViewContext *vc) int ED_view3d_backbuf_sample_size_clamp(ARegion *region, const float dist) { - return (int)min_ff(ceilf(dist), (float)max_ii(region->winx, region->winx)); + return int(min_ff(ceilf(dist), float(max_ii(region->winx, region->winx)))); } /** \} */ @@ -2262,7 +2281,7 @@ static ViewDepths *view3d_depths_create(ARegion *region) /* Convert in-place. */ int pixel_count = d->w * d->h; for (int i = 0; i < pixel_count; i++) { - d->depths[i] = (int_depths[i] >> 8u) / (float)0xFFFFFF; + d->depths[i] = (int_depths[i] >> 8u) / float(0xFFFFFF); } /* Assumed to be this as they are never changed. */ d->depth_range[0] = 0.0; @@ -2274,13 +2293,13 @@ static ViewDepths *view3d_depths_create(ARegion *region) float view3d_depth_near(ViewDepths *d) { /* Convert to float for comparisons. */ - const float near = (float)d->depth_range[0]; - const float far_real = (float)d->depth_range[1]; + const float near = float(d->depth_range[0]); + const float far_real = float(d->depth_range[1]); float far = far_real; const float *depths = d->depths; float depth = FLT_MAX; - int i = (int)d->w * (int)d->h; /* Cast to avoid short overflow. */ + int i = int(d->w) * int(d->h); /* Cast to avoid short overflow. */ /* Far is both the starting 'far' value * and the closest value found. */ @@ -2496,8 +2515,8 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset) printable[0] = '\0'; /* Doing an average for a more robust calculation. */ - fpsi->redrawtimes_fps[fpsi->redrawtime_index] = (float)(1.0 / - (fpsi->lredrawtime - fpsi->redrawtime)); + fpsi->redrawtimes_fps[fpsi->redrawtime_index] = float(1.0 / + (fpsi->lredrawtime - fpsi->redrawtime)); float fps = 0.0f; int tot = 0; @@ -2515,13 +2534,13 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset) const int font_id = BLF_default(); /* Is this more than half a frame behind? */ - if (fps + 0.5f < (float)(FPS)) { + if (fps + 0.5f < float(FPS)) { UI_FontThemeColor(font_id, TH_REDALERT); BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %.2f"), fps); } else { UI_FontThemeColor(font_id, TH_TEXT_HI); - BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), (int)(fps + 0.5f)); + BLI_snprintf(printable, sizeof(printable), IFACE_("fps: %i"), int(fps + 0.5f)); } BLF_enable(font_id, BLF_SHADOW); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc index 73617c0670f..83d1ed5f552 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc @@ -3,7 +3,7 @@ /** \file * \ingroup wm * - * \name Preselection Gizmo + * \name Pre-selection Gizmo * * Use for tools to hover over data before activation. * @@ -75,7 +75,7 @@ static bool gizmo_preselect_poll_for_draw(const bContext *C, wmGizmo *gz) /** \name Mesh Element (Vert/Edge/Face) Pre-Select Gizmo API * \{ */ -typedef struct MeshElemGizmo3D { +struct MeshElemGizmo3D { wmGizmo gizmo; Base **bases; uint bases_len; @@ -83,8 +83,8 @@ typedef struct MeshElemGizmo3D { int vert_index; int edge_index; int face_index; - struct EditMesh_PreSelElem *psel; -} MeshElemGizmo3D; + EditMesh_PreSelElem *psel; +}; static void gizmo_preselect_elem_draw(const bContext *C, wmGizmo *gz) { @@ -115,21 +115,20 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int EDBM_preselect_action_set(gz_ele->psel, PRESELECT_ACTION_DELETE); } - struct { + struct Best { Object *ob; BMElem *ele; float dist; int base_index; - } best = { - .dist = ED_view3d_select_dist_px(), - }; + } best{}; + best.dist = ED_view3d_select_dist_px(); { const Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); BKE_view_layer_synced_ensure(scene, view_layer); - if ((gz_ele->bases) == NULL || + if ((gz_ele->bases) == nullptr || (gz_ele->bases[0] != BKE_view_layer_active_base_get(view_layer))) { MEM_SAFE_FREE(gz_ele->bases); gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode( @@ -183,7 +182,7 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int if (eve_test) { BMVert *vert = (BMVert *)eve_test; float vert_p_co[2], vert_co[3]; - const float mval_f[2] = {UNPACK2(vc.mval)}; + const float mval_f[2] = {float(vc.mval[0]), float(vc.mval[1])}; mul_v3_m4v3(vert_co, gz_ele->bases[base_index_vert]->object->obmat, vert->co); ED_view3d_project_v2(vc.region, vert_co, vert_p_co); float len = len_v2v2(vert_p_co, mval_f); @@ -206,7 +205,7 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int } } - BMesh *bm = NULL; + BMesh *bm = nullptr; gz_ele->base_index = -1; gz_ele->vert_index = -1; @@ -230,11 +229,11 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int } if (best.ele) { - const float(*coords)[3] = NULL; + const float(*coords)[3] = nullptr; { Object *ob = gz_ele->bases[gz_ele->base_index]->object; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data); + Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, static_cast<ID *>(ob->data)); if (me_eval->runtime.edit_data) { coords = me_eval->runtime.edit_data->vertexCos; } @@ -264,7 +263,7 @@ static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int static void gizmo_preselect_elem_setup(wmGizmo *gz) { MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; - if (gz_ele->psel == NULL) { + if (gz_ele->psel == nullptr) { gz_ele->psel = EDBM_preselect_elem_create(); } gz_ele->base_index = -1; @@ -274,7 +273,7 @@ static void gizmo_preselect_elem_free(wmGizmo *gz) { MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz; EDBM_preselect_elem_destroy(gz_ele->psel); - gz_ele->psel = NULL; + gz_ele->psel = nullptr; MEM_SAFE_FREE(gz_ele->bases); } @@ -311,14 +310,14 @@ static void GIZMO_GT_mesh_preselect_elem_3d(wmGizmoType *gzt) /** \name Mesh Edge-Ring Pre-Select Gizmo API * \{ */ -typedef struct MeshEdgeRingGizmo3D { +struct MeshEdgeRingGizmo3D { wmGizmo gizmo; Base **bases; uint bases_len; int base_index; int edge_index; - struct EditMesh_PreSelEdgeRing *psel; -} MeshEdgeRingGizmo3D; + EditMesh_PreSelEdgeRing *psel; +}; static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz) { @@ -336,29 +335,27 @@ static void gizmo_preselect_edgering_draw(const bContext *C, wmGizmo *gz) static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const int mval[2]) { MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; - struct { + struct Best { Object *ob; BMEdge *eed; float dist; int base_index; - } best = { - .dist = ED_view3d_select_dist_px(), - }; + } best{}; + best.dist = ED_view3d_select_dist_px(); - struct { + struct Prev { int base_index; int edge_index; - } prev = { - .base_index = gz_ring->base_index, - .edge_index = gz_ring->edge_index, - }; + } prev{}; + prev.base_index = gz_ring->base_index; + prev.edge_index = gz_ring->edge_index; { const Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); BKE_view_layer_synced_ensure(scene, view_layer); - if ((gz_ring->bases) == NULL || + if ((gz_ring->bases) == nullptr || (gz_ring->bases[0] != BKE_view_layer_active_base_get(view_layer))) { MEM_SAFE_FREE(gz_ring->bases); gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode( @@ -371,8 +368,15 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const copy_v2_v2_int(vc.mval, mval); uint base_index; - BMEdge *eed_test = EDBM_edge_find_nearest_ex( - &vc, &best.dist, NULL, false, false, NULL, gz_ring->bases, gz_ring->bases_len, &base_index); + BMEdge *eed_test = EDBM_edge_find_nearest_ex(&vc, + &best.dist, + nullptr, + false, + false, + nullptr, + gz_ring->bases, + gz_ring->bases_len, + &base_index); if (eed_test) { best.ob = gz_ring->bases[base_index]->object; @@ -380,7 +384,7 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const best.base_index = base_index; } - BMesh *bm = NULL; + BMesh *bm = nullptr; if (best.eed) { gz_ring->base_index = best.base_index; bm = BKE_editmesh_from_object(gz_ring->bases[gz_ring->base_index]->object)->bm; @@ -405,7 +409,7 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const * the mesh hasn't been edited since last update. */ bool is_alloc = false; const float(*coords)[3] = BKE_editmesh_vert_coords_when_deformed( - vc.depsgraph, em_eval, scene_eval, ob_eval, NULL, &is_alloc); + vc.depsgraph, em_eval, scene_eval, ob_eval, nullptr, &is_alloc); EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords); if (is_alloc) { MEM_freeN((void *)coords); @@ -429,7 +433,7 @@ static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const static void gizmo_preselect_edgering_setup(wmGizmo *gz) { MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; - if (gz_ring->psel == NULL) { + if (gz_ring->psel == nullptr) { gz_ring->psel = EDBM_preselect_edgering_create(); } gz_ring->base_index = -1; @@ -439,7 +443,7 @@ static void gizmo_preselect_edgering_free(wmGizmo *gz) { MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz; EDBM_preselect_edgering_destroy(gz_ring->psel); - gz_ring->psel = NULL; + gz_ring->psel = nullptr; MEM_SAFE_FREE(gz_ring->bases); } @@ -500,8 +504,8 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C, const int object_index = RNA_int_get(gz->ptr, "object_index"); /* weak, allocate an array just to access the index. */ - Base *base = NULL; - Object *obedit = NULL; + Base *base = nullptr; + Object *obedit = nullptr; { uint bases_len; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode( @@ -514,7 +518,7 @@ void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C, } *r_base = base; - *r_ele = NULL; + *r_ele = nullptr; if (obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); @@ -562,7 +566,7 @@ void ED_view3d_gizmo_mesh_preselect_clear(wmGizmo *gz) const char *prop_ids[] = {"object_index", "vert_index", "edge_index", "face_index"}; for (int i = 0; i < ARRAY_SIZE(prop_ids); i++) { PropertyRNA *prop = RNA_struct_find_property(gz->ptr, prop_ids[i]); - if (prop == NULL) { + if (prop == nullptr) { continue; } RNA_property_int_set(gz->ptr, prop, -1); diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.cc index bee04931189..397933991da 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -57,9 +57,9 @@ static int content_planes_from_clip_flag(const ARegion *region, { BLI_assert(clip_flag & V3D_PROJ_TEST_CLIP_CONTENT); - float *clip_xmin = NULL, *clip_xmax = NULL; - float *clip_ymin = NULL, *clip_ymax = NULL; - float *clip_zmin = NULL, *clip_zmax = NULL; + float *clip_xmin = nullptr, *clip_xmax = nullptr; + float *clip_ymin = nullptr, *clip_ymax = nullptr; + float *clip_zmin = nullptr, *clip_zmax = nullptr; int planes_len = 0; @@ -84,7 +84,7 @@ static int content_planes_from_clip_flag(const ARegion *region, BLI_assert(planes_len <= 6); if (planes_len != 0) { - RegionView3D *rv3d = region->regiondata; + RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); float projmat[4][4]; ED_view3d_ob_project_mat_get(rv3d, ob, projmat); planes_from_projmat(projmat, clip_xmin, clip_xmax, clip_ymin, clip_ymax, clip_zmin, clip_zmax); @@ -202,24 +202,24 @@ static bool view3d_project_segment_to_screen_with_clip_tag(const ARegion *region /** \name Private User Data Structures * \{ */ -typedef struct foreachScreenObjectVert_userData { +struct foreachScreenObjectVert_userData { void (*func)(void *userData, const float screen_co[2], int index); void *userData; ViewContext vc; float (*positions)[3]; const bool *hide_vert; eV3DProjTest clip_flag; -} foreachScreenObjectVert_userData; +}; -typedef struct foreachScreenVert_userData { +struct foreachScreenVert_userData { void (*func)(void *userData, BMVert *eve, const float screen_co[2], int index); void *userData; ViewContext vc; eV3DProjTest clip_flag; -} foreachScreenVert_userData; +}; /* user data structures for derived mesh callbacks */ -typedef struct foreachScreenEdge_userData { +struct foreachScreenEdge_userData { void (*func)(void *userData, BMEdge *eed, const float screen_co_a[2], @@ -237,14 +237,14 @@ typedef struct foreachScreenEdge_userData { */ float content_planes[6][4]; int content_planes_len; -} foreachScreenEdge_userData; +}; -typedef struct foreachScreenFace_userData { +struct foreachScreenFace_userData { void (*func)(void *userData, BMFace *efa, const float screen_co_b[2], int index); void *userData; ViewContext vc; eV3DProjTest clip_flag; -} foreachScreenFace_userData; +}; /** * \note foreach functions should be called while drawing or directly after @@ -264,7 +264,8 @@ static void meshobject_foreachScreenVert__mapFunc(void *userData, const float co[3], const float UNUSED(no[3])) { - foreachScreenObjectVert_userData *data = userData; + foreachScreenObjectVert_userData *data = static_cast<foreachScreenObjectVert_userData *>( + userData); if (data->hide_vert && data->hide_vert[index]) { return; } @@ -317,7 +318,7 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, const float co[3], const float UNUSED(no[3])) { - foreachScreenVert_userData *data = userData; + foreachScreenVert_userData *data = static_cast<foreachScreenVert_userData *>(userData); BMVert *eve = BM_vert_at_index(data->vc.em->bm, index); if (UNLIKELY(BM_elem_flag_test(eve, BM_ELEM_HIDDEN))) { return; @@ -370,7 +371,7 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, const float v_a[3], const float v_b[3]) { - foreachScreenEdge_userData *data = userData; + foreachScreenEdge_userData *data = static_cast<foreachScreenEdge_userData *>(userData); BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index); if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) { return; @@ -451,7 +452,7 @@ static void mesh_foreachScreenEdge_clip_bb_segment__mapFunc(void *userData, const float v_a[3], const float v_b[3]) { - foreachScreenEdge_userData *data = userData; + foreachScreenEdge_userData *data = static_cast<foreachScreenEdge_userData *>(userData); BMEdge *eed = BM_edge_at_index(data->vc.em->bm, index); if (UNLIKELY(BM_elem_flag_test(eed, BM_ELEM_HIDDEN))) { return; @@ -518,7 +519,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc, BM_mesh_elem_table_ensure(vc->em->bm, BM_EDGE); - if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != NULL)) { + if ((clip_flag & V3D_PROJ_TEST_CLIP_BB) && (vc->rv3d->clipbb != nullptr)) { ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups. */ BKE_mesh_foreach_mapped_edge( me, vc->em->bm->totedge, mesh_foreachScreenEdge_clip_bb_segment__mapFunc, &data); @@ -539,7 +540,7 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, const float cent[3], const float UNUSED(no[3])) { - foreachScreenFace_userData *data = userData; + foreachScreenFace_userData *data = static_cast<foreachScreenFace_userData *>(userData); BMFace *efa = BM_face_at_index(data->vc.em->bm, index); if (UNLIKELY(BM_elem_flag_test(efa, BM_ELEM_HIDDEN))) { return; @@ -575,7 +576,7 @@ void mesh_foreachScreenFace( BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - if (me->runtime.subsurf_face_dot_tags != NULL) { + if (me->runtime.subsurf_face_dot_tags != nullptr) { BKE_mesh_foreach_mapped_subdiv_face_center( me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); } @@ -602,8 +603,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, void *userData, const eV3DProjTest clip_flag) { - Curve *cu = vc->obedit->data; - Nurb *nu; + Curve *cu = static_cast<Curve *>(vc->obedit->data); int i; ListBase *nurbs = BKE_curve_editNurbs_get(cu); /* If no point in the triple is selected, the handles are invisible. */ @@ -615,7 +615,7 @@ void nurbs_foreachScreenVert(ViewContext *vc, ED_view3d_clipping_local(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ } - for (nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { for (i = 0; i < nu->pntsu; i++) { BezTriple *bezt = &nu->bezt[i]; @@ -626,35 +626,39 @@ void nurbs_foreachScreenVert(ViewContext *vc, float screen_co[2]; if (!handles_visible) { - if (ED_view3d_project_float_object(vc->region, - bezt->vec[1], - screen_co, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == + if (ED_view3d_project_float_object( + vc->region, + bezt->vec[1], + screen_co, + eV3DProjTest(V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN)) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, false, screen_co); + func(userData, nu, nullptr, bezt, 1, false, screen_co); } } else { - if (ED_view3d_project_float_object(vc->region, - bezt->vec[0], - screen_co, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == + if (ED_view3d_project_float_object( + vc->region, + bezt->vec[0], + screen_co, + eV3DProjTest(V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN)) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 0, true, screen_co); + func(userData, nu, nullptr, bezt, 0, true, screen_co); } - if (ED_view3d_project_float_object(vc->region, - bezt->vec[1], - screen_co, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == + if (ED_view3d_project_float_object( + vc->region, + bezt->vec[1], + screen_co, + eV3DProjTest(V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN)) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 1, true, screen_co); + func(userData, nu, nullptr, bezt, 1, true, screen_co); } - if (ED_view3d_project_float_object(vc->region, - bezt->vec[2], - screen_co, - V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == + if (ED_view3d_project_float_object( + vc->region, + bezt->vec[2], + screen_co, + eV3DProjTest(V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN)) == V3D_PROJ_RET_OK) { - func(userData, nu, NULL, bezt, 2, true, screen_co); + func(userData, nu, nullptr, bezt, 2, true, screen_co); } } } @@ -667,9 +671,11 @@ void nurbs_foreachScreenVert(ViewContext *vc, if (bp->hide == 0) { float screen_co[2]; if (ED_view3d_project_float_object( - vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) == - V3D_PROJ_RET_OK) { - func(userData, nu, bp, NULL, -1, false, screen_co); + vc->region, + bp->vec, + screen_co, + eV3DProjTest(V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN)) == V3D_PROJ_RET_OK) { + func(userData, nu, bp, nullptr, -1, false, screen_co); } } } @@ -683,19 +689,18 @@ void nurbs_foreachScreenVert(ViewContext *vc, /** \name Edit-Meta: For Each Screen Meta-Element * \{ */ -void mball_foreachScreenElem(struct ViewContext *vc, +void mball_foreachScreenElem(ViewContext *vc, void (*func)(void *userData, - struct MetaElem *ml, + MetaElem *ml, const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag) { MetaBall *mb = (MetaBall *)vc->obedit->data; - MetaElem *ml; ED_view3d_check_mats_rv3d(vc->rv3d); - for (ml = mb->editelems->first; ml; ml = ml->next) { + LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { float screen_co[2]; if (ED_view3d_project_float_object(vc->region, &ml->x, screen_co, clip_flag) == V3D_PROJ_RET_OK) { @@ -716,12 +721,12 @@ void lattice_foreachScreenVert(ViewContext *vc, const eV3DProjTest clip_flag) { Object *obedit = vc->obedit; - Lattice *lt = obedit->data; + Lattice *lt = static_cast<Lattice *>(obedit->data); BPoint *bp = lt->editlatt->latt->def; DispList *dl = obedit->runtime.curve_cache ? BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) : - NULL; - const float *co = dl ? dl->verts : NULL; + nullptr; + const float *co = dl ? dl->verts : nullptr; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; ED_view3d_check_mats_rv3d(vc->rv3d); @@ -747,16 +752,15 @@ void lattice_foreachScreenVert(ViewContext *vc, /** \name Edit-Armature: For Each Screen Bone * \{ */ -void armature_foreachScreenBone(struct ViewContext *vc, +void armature_foreachScreenBone(ViewContext *vc, void (*func)(void *userData, - struct EditBone *ebone, + EditBone *ebone, const float screen_co_a[2], const float screen_co_b[2]), void *userData, const eV3DProjTest clip_flag) { - bArmature *arm = vc->obedit->data; - EditBone *ebone; + bArmature *arm = static_cast<bArmature *>(vc->obedit->data); ED_view3d_check_mats_rv3d(vc->rv3d); @@ -776,7 +780,7 @@ void armature_foreachScreenBone(struct ViewContext *vc, content_planes_len = 0; } - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { if (!EBONE_VISIBLE(arm, ebone)) { continue; } @@ -814,9 +818,9 @@ void armature_foreachScreenBone(struct ViewContext *vc, /** \name Pose: For Each Screen Bone * \{ */ -void pose_foreachScreenBone(struct ViewContext *vc, +void pose_foreachScreenBone(ViewContext *vc, void (*func)(void *userData, - struct bPoseChannel *pchan, + bPoseChannel *pchan, const float screen_co_a[2], const float screen_co_b[2]), void *userData, @@ -825,9 +829,8 @@ void pose_foreachScreenBone(struct ViewContext *vc, /* Almost _exact_ copy of #armature_foreachScreenBone */ const Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact); - const bArmature *arm_eval = ob_eval->data; + const bArmature *arm_eval = static_cast<const bArmature *>(ob_eval->data); bPose *pose = vc->obact->pose; - bPoseChannel *pchan; ED_view3d_check_mats_rv3d(vc->rv3d); @@ -847,7 +850,7 @@ void pose_foreachScreenBone(struct ViewContext *vc, content_planes_len = 0; } - for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { if (!PBONE_VISIBLE(arm_eval, pchan->bone)) { continue; } diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 1230515a180..498f86e36fd 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -75,14 +75,16 @@ void ED_view3d_project_float_v3_m4(const ARegion *region, /* Clipping Projection Functions * ***************************** */ -eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base *base) +eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, + struct Base *base, + short r_co[2]) { eV3DProjStatus ret = ED_view3d_project_short_global( - region, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT); + region, base->object->obmat[3], r_co, V3D_PROJ_TEST_CLIP_DEFAULT); if (ret != V3D_PROJ_RET_OK) { - base->sx = IS_CLIPPED; - base->sy = 0; + r_co[0] = IS_CLIPPED; + r_co[1] = 0; } return ret; @@ -532,12 +534,27 @@ bool ED_view3d_win_to_3d_on_plane(const ARegion *region, const bool do_clip, float r_out[3]) { + const RegionView3D *rv3d = region->regiondata; + const bool ray_co_is_centered = rv3d->is_persp == false && rv3d->persp != RV3D_CAMOB; + const bool do_clip_ray_plane = do_clip && !ray_co_is_centered; float ray_co[3], ray_no[3]; ED_view3d_win_to_origin(region, mval, ray_co); ED_view3d_win_to_vector(region, mval, ray_no); float lambda; - if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, do_clip)) { + if (isect_ray_plane_v3(ray_co, ray_no, plane, &lambda, do_clip_ray_plane)) { madd_v3_v3v3fl(r_out, ray_co, ray_no, lambda); + + /* Handle clipping with an orthographic view differently, + * check if the resulting point is behind the view instead of clipping the ray. */ + if (do_clip && (do_clip_ray_plane == false)) { + /* The offset is unit length where over 1.0 is beyond the views clip-plane (near and far) + * as non-camera orthographic views only use far distance in both directions. + * Multiply `r_out` by `persmat` (with translation), and get it's Z value. */ + const float z_offset = fabsf(dot_m4_v3_row_z(rv3d->persmat, r_out) + rv3d->persmat[3][2]); + if (z_offset > 1.0f) { + return false; + } + } return true; } return false; diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index 596e230d762..a3917e0ed44 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -574,10 +574,11 @@ static bool do_lasso_select_objects(ViewContext *vc, BKE_view_layer_synced_ensure(vc->scene, vc->view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(vc->view_layer)) { if (BASE_SELECTABLE(v3d, base)) { /* Use this to avoid unnecessary lasso look-ups. */ + short region_co[2]; const bool is_select = base->flag & BASE_SELECTED; - const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside( - mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED)); + const bool is_inside = + (ED_view3d_project_base(vc->region, base, region_co) == V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcoords, mcoords_len, region_co[0], region_co[1], IS_CLIPPED); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); @@ -1607,8 +1608,9 @@ static bool object_mouse_select_menu(bContext *C, } else { const int dist = 15 * U.pixelsize; - if (ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) { - const int delta_px[2] = {base->sx - mval[0], base->sy - mval[1]}; + short region_co[2]; + if (ED_view3d_project_base(vc->region, base, region_co) == V3D_PROJ_RET_OK) { + const int delta_px[2] = {region_co[0] - mval[0], region_co[1] - mval[1]}; if (len_manhattan_v2_int(delta_px) < dist) { ok = true; } diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c index 3792cfefe06..f4f2e2a1c6e 100644 --- a/source/blender/editors/transform/transform_convert_sculpt.c +++ b/source/blender/editors/transform/transform_convert_sculpt.c @@ -87,7 +87,7 @@ static void createTransSculpt(bContext *C, TransInfo *t) copy_m3_m4(td->axismtx, ob->obmat); BLI_assert(!(t->options & CTX_PAINT_CURVE)); - ED_sculpt_init_transform(C, ob, t->undo_name); + ED_sculpt_init_transform(C, ob, t->mval, t->undo_name); } /** \} */ diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 8e6a6c2c411..6591574323e 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1100,14 +1100,15 @@ static void gizmo_prepare_mat(const bContext *C, mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max); if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { - bGPdata *gpd = CTX_data_gpencil_data(C); - if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - /* pass */ - } - else { - BKE_view_layer_synced_ensure(scene, view_layer); - Object *ob = BKE_view_layer_active_object_get(view_layer); - if (ob != NULL) { + BKE_view_layer_synced_ensure(scene, view_layer); + Object *ob = BKE_view_layer_active_object_get(view_layer); + if (ob != NULL) { + /* Grease Pencil uses object origin. */ + bGPdata *gpd = CTX_data_gpencil_data(C); + if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { + ED_object_calc_active_center(ob, false, rv3d->twmat[3]); + } + else { if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) { SculptSession *ss = ob->sculpt; copy_v3_v3(rv3d->twmat[3], ss->pivot_pos); diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index a9e6adc6e60..128cb897ac4 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -28,6 +28,7 @@ set(SRC ed_util.c ed_util_imbuf.c ed_util_ops.cc + ed_viewer_path.cc gizmo_utils.c numinput.c select_utils.c @@ -89,6 +90,7 @@ set(SRC ../include/ED_uvedit.h ../include/ED_view3d.h ../include/ED_view3d_offscreen.h + ../include/ED_viewer_path.hh ../include/UI_abstract_view.hh ../include/UI_grid_view.hh ../include/UI_icons.h diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc new file mode 100644 index 00000000000..5c03367cba8 --- /dev/null +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "ED_viewer_path.hh" +#include "ED_screen.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_node_runtime.hh" +#include "BKE_workspace.h" + +#include "BLI_listbase.h" +#include "BLI_vector.hh" + +#include "DNA_modifier_types.h" +#include "DNA_windowmanager_types.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" + +namespace blender::ed::viewer_path { + +static void viewer_path_for_geometry_node(const SpaceNode &snode, + const bNode &node, + ViewerPath &r_dst) +{ + BKE_viewer_path_init(&r_dst); + + Object *ob = reinterpret_cast<Object *>(snode.id); + IDViewerPathElem *id_elem = BKE_viewer_path_elem_new_id(); + id_elem->id = &ob->id; + BLI_addtail(&r_dst.path, id_elem); + + NodesModifierData *modifier = nullptr; + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_Nodes) { + continue; + } + NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); + if (nmd->node_group != snode.nodetree) { + continue; + } + if (snode.flag & SNODE_PIN) { + /* If the node group is pinned, use the first matching modifier. This can be improved by + * storing the modifier name in the node editor when the context is pinned. */ + modifier = nmd; + break; + } + if (md->flag & eModifierFlag_Active) { + modifier = nmd; + } + } + + ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier(); + modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name); + BLI_addtail(&r_dst.path, modifier_elem); + + Vector<const bNodeTreePath *, 16> tree_path = snode.treepath; + for (const bNodeTreePath *tree_path_elem : tree_path.as_span().drop_front(1)) { + NodeViewerPathElem *node_elem = BKE_viewer_path_elem_new_node(); + node_elem->node_name = BLI_strdup(tree_path_elem->node_name); + BLI_addtail(&r_dst.path, node_elem); + } + + NodeViewerPathElem *viewer_node_elem = BKE_viewer_path_elem_new_node(); + viewer_node_elem->node_name = BLI_strdup(node.name); + BLI_addtail(&r_dst.path, viewer_node_elem); +} + +void activate_geometry_node(Main &bmain, SpaceNode &snode, bNode &node) +{ + wmWindowManager *wm = (wmWindowManager *)bmain.wm.first; + if (wm == nullptr) { + return; + } + LISTBASE_FOREACH (bNode *, iter_node, &snode.edittree->nodes) { + if (iter_node->type == GEO_NODE_VIEWER) { + SET_FLAG_FROM_TEST(iter_node->flag, iter_node == &node, NODE_DO_OUTPUT); + } + } + ViewerPath new_viewer_path{}; + BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&new_viewer_path); }); + viewer_path_for_geometry_node(snode, node, new_viewer_path); + + bool found_view3d_with_enabled_viewer = false; + View3D *any_view3d_without_viewer = nullptr; + LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { + WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook); + bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); + if (sl->spacetype == SPACE_SPREADSHEET) { + SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<SpaceSpreadsheet *>(sl); + if (!(sspreadsheet.flag & SPREADSHEET_FLAG_PINNED)) { + sspreadsheet.object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE; + } + } + else if (sl->spacetype == SPACE_VIEW3D) { + View3D &v3d = *reinterpret_cast<View3D *>(sl); + if (v3d.flag2 & V3D_SHOW_VIEWER) { + found_view3d_with_enabled_viewer = true; + } + else { + any_view3d_without_viewer = &v3d; + } + } + } + + /* Enable viewer in one viewport if it is disable in all of them. */ + if (!found_view3d_with_enabled_viewer && any_view3d_without_viewer != nullptr) { + any_view3d_without_viewer->flag2 |= V3D_SHOW_VIEWER; + } + + BKE_viewer_path_clear(&workspace->viewer_path); + BKE_viewer_path_copy(&workspace->viewer_path, &new_viewer_path); + + /* Make sure the viewed data becomes available. */ + DEG_id_tag_update(snode.id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_VIEWER_PATH, nullptr); + } +} + +Object *parse_object_only(const ViewerPath &viewer_path) +{ + if (BLI_listbase_count(&viewer_path.path) != 1) { + return nullptr; + } + const ViewerPathElem *elem = static_cast<ViewerPathElem *>(viewer_path.path.first); + if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) { + return nullptr; + } + ID *id = reinterpret_cast<const IDViewerPathElem *>(elem)->id; + if (id == nullptr) { + return nullptr; + } + if (GS(id->name) != ID_OB) { + return nullptr; + } + return reinterpret_cast<Object *>(id); +} + +std::optional<ViewerPathForGeometryNodesViewer> parse_geometry_nodes_viewer( + const ViewerPath &viewer_path) +{ + const Vector<const ViewerPathElem *, 16> elems_vec = viewer_path.path; + if (elems_vec.size() < 3) { + /* Need at least the object, modifier and viewer node name. */ + return std::nullopt; + } + Span<const ViewerPathElem *> remaining_elems = elems_vec; + const ViewerPathElem &id_elem = *remaining_elems[0]; + if (id_elem.type != VIEWER_PATH_ELEM_TYPE_ID) { + return std::nullopt; + } + ID *root_id = reinterpret_cast<const IDViewerPathElem &>(id_elem).id; + if (root_id == nullptr) { + return std::nullopt; + } + if (GS(root_id->name) != ID_OB) { + return std::nullopt; + } + Object *root_ob = reinterpret_cast<Object *>(root_id); + remaining_elems = remaining_elems.drop_front(1); + const ViewerPathElem &modifier_elem = *remaining_elems[0]; + if (modifier_elem.type != VIEWER_PATH_ELEM_TYPE_MODIFIER) { + return std::nullopt; + } + const char *modifier_name = + reinterpret_cast<const ModifierViewerPathElem &>(modifier_elem).modifier_name; + if (modifier_name == nullptr) { + return std::nullopt; + } + remaining_elems = remaining_elems.drop_front(1); + Vector<StringRefNull> node_names; + for (const ViewerPathElem *elem : remaining_elems) { + if (elem->type != VIEWER_PATH_ELEM_TYPE_NODE) { + return std::nullopt; + } + const char *node_name = reinterpret_cast<const NodeViewerPathElem *>(elem)->node_name; + if (node_name == nullptr) { + return std::nullopt; + } + node_names.append(node_name); + } + const StringRefNull viewer_node_name = node_names.pop_last(); + return ViewerPathForGeometryNodesViewer{root_ob, modifier_name, node_names, viewer_node_name}; +} + +bool exists_geometry_nodes_viewer(const ViewerPathForGeometryNodesViewer &parsed_viewer_path) +{ + const NodesModifierData *modifier = nullptr; + LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) { + if (md->type != eModifierType_Nodes) { + continue; + } + if (md->name != parsed_viewer_path.modifier_name) { + continue; + } + modifier = reinterpret_cast<const NodesModifierData *>(md); + break; + } + if (modifier == nullptr) { + return false; + } + if (modifier->node_group == nullptr) { + return false; + } + const bNodeTree *ngroup = modifier->node_group; + ngroup->ensure_topology_cache(); + for (const StringRefNull group_node_name : parsed_viewer_path.group_node_names) { + const bNode *group_node = nullptr; + for (const bNode *node : ngroup->group_nodes()) { + if (node->name != group_node_name) { + continue; + } + group_node = node; + break; + } + if (group_node == nullptr) { + return false; + } + if (group_node->id == nullptr) { + return false; + } + ngroup = reinterpret_cast<const bNodeTree *>(group_node->id); + } + const bNode *viewer_node = nullptr; + for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) { + if (node->name != parsed_viewer_path.viewer_node_name) { + continue; + } + viewer_node = node; + break; + } + if (viewer_node == nullptr) { + return false; + } + return true; +} + +bool is_active_geometry_nodes_viewer(const bContext &C, + const ViewerPathForGeometryNodesViewer &parsed_viewer_path) +{ + const NodesModifierData *modifier = nullptr; + LISTBASE_FOREACH (const ModifierData *, md, &parsed_viewer_path.object->modifiers) { + if (md->name != parsed_viewer_path.modifier_name) { + continue; + } + if (md->type != eModifierType_Nodes) { + return false; + } + modifier = reinterpret_cast<const NodesModifierData *>(md); + break; + } + if (modifier == nullptr) { + return false; + } + if (modifier->node_group == nullptr) { + return false; + } + const bool modifier_is_active = modifier->modifier.flag & eModifierFlag_Active; + + const Main *bmain = CTX_data_main(&C); + const wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); + if (wm == nullptr) { + return false; + } + LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) { + const bScreen *active_screen = BKE_workspace_active_screen_get(window->workspace_hook); + Vector<const bScreen *> screens = {active_screen}; + if (ELEM(active_screen->state, SCREENMAXIMIZED, SCREENFULL)) { + const ScrArea *area = static_cast<ScrArea *>(active_screen->areabase.first); + screens.append(area->full); + } + for (const bScreen *screen : screens) { + LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) { + const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); + if (sl == nullptr) { + continue; + } + if (sl->spacetype != SPACE_NODE) { + continue; + } + const SpaceNode &snode = *reinterpret_cast<const SpaceNode *>(sl); + if (!modifier_is_active) { + if (!(snode.flag & SNODE_PIN)) { + /* Node tree has to be pinned when the modifier is not active. */ + continue; + } + } + if (snode.id != &parsed_viewer_path.object->id) { + continue; + } + if (snode.nodetree != modifier->node_group) { + continue; + } + Vector<const bNodeTreePath *, 16> tree_path = snode.treepath; + if (tree_path.size() != parsed_viewer_path.group_node_names.size() + 1) { + continue; + } + bool valid_path = true; + for (const int i : parsed_viewer_path.group_node_names.index_range()) { + if (parsed_viewer_path.group_node_names[i] != tree_path[i + 1]->node_name) { + valid_path = false; + break; + } + } + if (!valid_path) { + continue; + } + const bNodeTree *ngroup = snode.edittree; + ngroup->ensure_topology_cache(); + const bNode *viewer_node = nullptr; + for (const bNode *node : ngroup->nodes_by_type("GeometryNodeViewer")) { + if (node->name != parsed_viewer_path.viewer_node_name) { + continue; + } + viewer_node = node; + } + if (viewer_node == nullptr) { + continue; + } + if (!(viewer_node->flag & NODE_DO_OUTPUT)) { + continue; + } + return true; + } + } + } + return false; +} + +bNode *find_geometry_nodes_viewer(const ViewerPath &viewer_path, SpaceNode &snode) +{ + const std::optional<ViewerPathForGeometryNodesViewer> parsed_viewer_path = + parse_geometry_nodes_viewer(viewer_path); + if (!parsed_viewer_path.has_value()) { + return nullptr; + } + + snode.edittree->ensure_topology_cache(); + bNode *possible_viewer = nullptr; + for (bNode *node : snode.edittree->nodes_by_type("GeometryNodeViewer")) { + if (node->name == parsed_viewer_path->viewer_node_name) { + possible_viewer = node; + break; + } + } + if (possible_viewer == nullptr) { + return nullptr; + } + ViewerPath tmp_viewer_path; + BLI_SCOPED_DEFER([&]() { BKE_viewer_path_clear(&tmp_viewer_path); }); + viewer_path_for_geometry_node(snode, *possible_viewer, tmp_viewer_path); + + if (BKE_viewer_path_equal(&viewer_path, &tmp_viewer_path)) { + return possible_viewer; + } + return nullptr; +} + +} // namespace blender::ed::viewer_path diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index d28aba9816f..c226ad4c461 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -40,17 +40,6 @@ /** \name UV Face Utilities * \{ */ -static void bm_face_uv_scale_y(BMFace *f, const float scale_y, const int cd_loop_uv_offset) -{ - BMLoop *l_iter; - BMLoop *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset)); - luv->uv[1] *= scale_y; - } while ((l_iter = l_iter->next) != l_first); -} - static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f, const float offset[2], const float scale[2], @@ -75,7 +64,7 @@ static void bm_face_uv_translate_and_scale_around_pivot(BMFace *f, * \{ */ static void bm_face_array_calc_bounds(BMFace **faces, - int faces_len, + const int faces_len, const int cd_loop_uv_offset, rctf *r_bounds_rect) { @@ -159,68 +148,66 @@ static float (*bm_face_array_calc_unique_uv_coords( return coords; } -/** - * \param align_to_axis: - * - -1: don't align to an axis. - * - 0: align horizontally. - * - 1: align vertically. - */ -static void bm_face_array_uv_rotate_fit_aabb(BMFace **faces, - int faces_len, - int align_to_axis, - const int cd_loop_uv_offset) +static void face_island_uv_rotate_fit_aabb(FaceIsland *island) { + BMFace **faces = island->faces; + const int faces_len = island->faces_len; + const float aspect_y = island->aspect_y; + const int cd_loop_uv_offset = island->cd_loop_uv_offset; + /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */ int coords_len; float(*coords)[2] = bm_face_array_calc_unique_uv_coords( faces, faces_len, cd_loop_uv_offset, &coords_len); - float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len); - - if (align_to_axis != -1) { - if (angle != 0.0f) { - float matrix[2][2]; - angle_to_mat2(matrix, angle); - for (int i = 0; i < coords_len; i++) { - mul_m2_v2(matrix, coords[i]); - } + /* Correct aspect ratio. */ + if (aspect_y != 1.0f) { + for (int i = 0; i < coords_len; i++) { + coords[i][1] /= aspect_y; } + } - float bounds_min[2], bounds_max[2]; - INIT_MINMAX2(bounds_min, bounds_max); + float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len); + + /* Rotate coords by `angle` before computing bounding box. */ + if (angle != 0.0f) { + float matrix[2][2]; + angle_to_mat2(matrix, angle); + matrix[0][1] *= aspect_y; + matrix[1][1] *= aspect_y; for (int i = 0; i < coords_len; i++) { - minmax_v2v2_v2(bounds_min, bounds_max, coords[i]); + mul_m2_v2(matrix, coords[i]); } + } - float size[2]; - sub_v2_v2v2(size, bounds_max, bounds_min); - if (align_to_axis ? (size[1] < size[0]) : (size[0] < size[1])) { - angle += DEG2RAD(90.0); - } + /* Compute new AABB. */ + float bounds_min[2], bounds_max[2]; + INIT_MINMAX2(bounds_min, bounds_max); + for (int i = 0; i < coords_len; i++) { + minmax_v2v2_v2(bounds_min, bounds_max, coords[i]); + } + + float size[2]; + sub_v2_v2v2(size, bounds_max, bounds_min); + if (size[1] < size[0]) { + angle += DEG2RADF(90.0f); } MEM_freeN(coords); + /* Apply rotation back to BMesh. */ if (angle != 0.0f) { float matrix[2][2]; angle_to_mat2(matrix, angle); + matrix[1][0] *= 1.0f / aspect_y; + /* matrix[1][1] *= aspect_y / aspect_y; */ + matrix[0][1] *= aspect_y; for (int i = 0; i < faces_len; i++) { BM_face_uv_transform(faces[i], matrix, cd_loop_uv_offset); } } } -static void bm_face_array_uv_scale_y(BMFace **faces, - int faces_len, - const float scale_y, - const int cd_loop_uv_offset) -{ - for (int i = 0; i < faces_len; i++) { - BMFace *f = faces[i]; - bm_face_uv_scale_y(f, scale_y, cd_loop_uv_offset); - } -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -276,7 +263,7 @@ static float uv_nearest_image_tile_distance(const Image *image, * Calculates distance to nearest UDIM grid tile in UV space and its UDIM tile number. */ static float uv_nearest_grid_tile_distance(const int udim_grid[2], - float coords[2], + const float coords[2], float nearest_tile_co[2]) { const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])}; @@ -419,7 +406,7 @@ int bm_mesh_calc_uv_islands(const Scene *scene, /* -------------------------------------------------------------------- */ /** \name Public UV Island Packing * - * \note This behavior follows #param_pack. + * \note This behavior loosely follows #GEO_uv_parametrizer_pack. * \{ */ void ED_uvedit_pack_islands_multi(const Scene *scene, @@ -428,17 +415,13 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params) { - /* Align to the Y axis, could make this configurable. */ - const int rotate_align_axis = 1; - ListBase island_list = {NULL}; - int island_list_len = 0; + blender::Vector<FaceIsland *> island_vector; for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMesh *bm = em->bm; - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); if (cd_loop_uv_offset == -1) { continue; } @@ -452,34 +435,38 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } } - island_list_len += bm_mesh_calc_uv_islands(scene, - bm, - &island_list, - params->only_selected_faces, - params->only_selected_uvs, - params->use_seams, - aspect_y, - cd_loop_uv_offset); + ListBase island_list = {NULL}; + bm_mesh_calc_uv_islands(scene, + em->bm, + &island_list, + params->only_selected_faces, + params->only_selected_uvs, + params->use_seams, + aspect_y, + cd_loop_uv_offset); + + int index; + LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) { + island_vector.append(island); + } } - if (island_list_len == 0) { + if (island_vector.size() == 0) { return; } float margin = scene->toolsettings->uvcalc_margin; double area = 0.0f; - struct FaceIsland **island_array = static_cast<struct FaceIsland **>( - MEM_mallocN(sizeof(*island_array) * island_list_len, __func__)); BoxPack *boxarray = static_cast<BoxPack *>( - MEM_mallocN(sizeof(*boxarray) * island_list_len, __func__)); + MEM_mallocN(sizeof(*boxarray) * island_vector.size(), __func__)); - int index; /* Coordinates of bounding box containing all selected UVs. */ float selection_min_co[2], selection_max_co[2]; INIT_MINMAX2(selection_min_co, selection_max_co); - LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) { + for (int index = 0; index < island_vector.size(); index++) { + FaceIsland *island = island_vector[index]; /* Skip calculation if using specified UDIM option. */ if (udim_params && (udim_params->use_target_udim == false)) { @@ -497,18 +484,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } if (params->rotate) { - if (island->aspect_y != 1.0f) { - bm_face_array_uv_scale_y( - island->faces, island->faces_len, 1.0f / island->aspect_y, island->cd_loop_uv_offset); - } - - bm_face_array_uv_rotate_fit_aabb( - island->faces, island->faces_len, rotate_align_axis, island->cd_loop_uv_offset); - - if (island->aspect_y != 1.0f) { - bm_face_array_uv_scale_y( - island->faces, island->faces_len, island->aspect_y, island->cd_loop_uv_offset); - } + face_island_uv_rotate_fit_aabb(island); } bm_face_array_calc_bounds( @@ -521,8 +497,6 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, box->w = BLI_rctf_size_x(&island->bounds_rect); box->h = BLI_rctf_size_y(&island->bounds_rect); - island_array[index] = island; - if (margin > 0.0f) { area += double(sqrtf(box->w * box->h)); } @@ -536,12 +510,12 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } if (margin > 0.0f) { - /* Logic matches behavior from #param_pack, + /* Logic matches behavior from #GEO_uv_parametrizer_pack, * use area so multiply the margin by the area to give * predictable results not dependent on UV scale. */ margin = (margin * float(area)) * 0.1f; - for (int i = 0; i < island_list_len; i++) { - struct FaceIsland *island = island_array[i]; + for (int i = 0; i < island_vector.size(); i++) { + FaceIsland *island = island_vector[i]; BoxPack *box = &boxarray[i]; BLI_rctf_pad(&island->bounds_rect, margin, margin); @@ -551,7 +525,7 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } float boxarray_size[2]; - BLI_box_pack_2d(boxarray, island_list_len, &boxarray_size[0], &boxarray_size[1]); + BLI_box_pack_2d(boxarray, island_vector.size(), &boxarray_size[0], &boxarray_size[1]); /* Don't change the aspect when scaling. */ boxarray_size[0] = boxarray_size[1] = max_ff(boxarray_size[0], boxarray_size[1]); @@ -605,8 +579,8 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, } } - for (int i = 0; i < island_list_len; i++) { - struct FaceIsland *island = island_array[boxarray[i].index]; + for (int i = 0; i < island_vector.size(); i++) { + FaceIsland *island = island_vector[boxarray[i].index]; const float pivot[2] = { island->bounds_rect.xmin, island->bounds_rect.ymin, @@ -628,12 +602,11 @@ void ED_uvedit_pack_islands_multi(const Scene *scene, WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); } - for (int i = 0; i < island_list_len; i++) { - MEM_freeN(island_array[i]->faces); - MEM_freeN(island_array[i]); + for (FaceIsland *island : island_vector) { + MEM_freeN(island->faces); + MEM_freeN(island); } - MEM_freeN(island_array); MEM_freeN(boxarray); } diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 299b4671d9f..7131750d701 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1145,7 +1145,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op) use_udim_params ? &udim_params : NULL, &(struct UVPackIsland_Params){ .rotate = rotate, - .rotate_align_axis = -1, .only_selected_uvs = true, .only_selected_faces = true, .correct_aspect = true, @@ -2419,8 +2418,6 @@ static int smart_project_exec(bContext *C, wmOperator *op) NULL, &(struct UVPackIsland_Params){ .rotate = true, - /* We could make this optional. */ - .rotate_align_axis = 1, .only_selected_uvs = only_selected_uvs, .only_selected_faces = true, .correct_aspect = correct_aspect, diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index a322922e86e..e2285a3fd3e 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -47,7 +47,6 @@ set(SRC intern/gpu_batch.cc intern/gpu_batch_presets.c intern/gpu_batch_utils.c - intern/gpu_buffers.c intern/gpu_capabilities.cc intern/gpu_codegen.cc intern/gpu_compute.cc @@ -84,7 +83,6 @@ set(SRC GPU_batch.h GPU_batch_presets.h GPU_batch_utils.h - GPU_buffers.h GPU_capabilities.h GPU_common.h GPU_common_types.h @@ -559,6 +557,7 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh ../draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh + ../draw/engines/overlay/shaders/infos/overlay_viewer_attribute_info.hh ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh ../draw/engines/select/shaders/infos/select_id_info.hh diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h deleted file mode 100644 index 11d0faf37d4..00000000000 --- a/source/blender/gpu/GPU_buffers.h +++ /dev/null @@ -1,156 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2005 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - */ - -#pragma once - -#include <stddef.h> - -#include "BKE_attribute.h" -#include "BKE_pbvh.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct BMesh; -struct CCGElem; -struct CCGKey; -struct DMFlagMat; -struct GSet; -struct TableGSet; -struct Mesh; -struct MLoop; -struct MLoopCol; -struct MLoopTri; -struct MPoly; -struct MPropCol; -struct Mesh; -struct PBVH; -struct SubdivCCG; -struct CustomData; - -typedef struct PBVHGPUFormat PBVHGPUFormat; - -/** - * Buffers for drawing from PBVH grids. - */ -typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; - -/** - * Build must be called once before using the other functions, - * used every time mesh topology changes. - * - * Threaded: do not call any functions that use OpenGL calls! - */ -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct Mesh *mesh, - const struct MLoopTri *looptri, - const int *face_indices, - int face_indices_len); - -/** - * Threaded: do not call any functions that use OpenGL calls! - */ -GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, - unsigned int **grid_hidden, - bool smooth); - -/** - * Threaded: do not call any functions that use OpenGL calls! - */ -GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading); - -/** - * Free part of data for update. Not thread safe, must run in OpenGL main thread. - */ -void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers); -void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, - const struct DMFlagMat *grid_flag_mats, - const int *grid_indices); - -/** - * Update mesh buffers without topology changes. Threaded. - */ -enum { - GPU_PBVH_BUFFERS_SHOW_MASK = (1 << 1), - GPU_PBVH_BUFFERS_SHOW_VCOL = (1 << 2), - GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS = (1 << 3), -}; - -/** - * Creates a vertex buffer (coordinate, normal, color) and, - * if smooth shading, an element index buffer. - * Threaded: do not call any functions that use OpenGL calls! - */ -void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - const struct Mesh *mesh, - const float (*positions)[3], - const float *vmask, - const int *sculpt_face_sets, - const int face_sets_color_seed, - const int face_sets_color_default, - const int update_flags, - const float (*vert_normals)[3]); - -bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type, - PBVHGPUFormat *vbo_id, - const struct CustomData *vdata, - const struct CustomData *ldata, - bool active_attrs_only); - -/** - * Creates a vertex buffer (coordinate, normal, color) and, - * if smooth shading, an element index buffer. - * Threaded: do not call any functions that use OpenGL calls! - */ -void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id, - struct GPU_PBVH_Buffers *buffers, - struct BMesh *bm, - struct GSet *bm_faces, - struct GSet *bm_unique_verts, - struct GSet *bm_other_verts, - const int update_flags); - -/** - * Threaded: do not call any functions that use OpenGL calls! - */ -void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - struct SubdivCCG *subdiv_ccg, - struct CCGElem **grids, - const struct DMFlagMat *grid_flag_mats, - int *grid_indices, - int totgrid, - const int *sculpt_face_sets, - int face_sets_color_seed, - int face_sets_color_default, - const struct CCGKey *key, - int update_flags); - -/** - * Finish update. Not thread safe, must run in OpenGL main - * thread. - */ -void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers); - -/** - * Free buffers. Not thread safe, must run in OpenGL main thread. - */ -void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers); - -/** Draw. */ -struct GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires); - -short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers); -bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers); - -PBVHGPUFormat *GPU_pbvh_make_format(void); -void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 1c9bdc77bac..31354585308 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -335,8 +335,6 @@ typedef struct GPUUniformAttr { /* Meaningful part of the attribute set key. */ char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */ - /** Escaped name with [""]. */ - char name_id_prop[64 * 2 + 4]; /** Hash of name[64] + use_dupli. */ uint32_t hash_code; bool use_dupli; diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 8b54f4c9822..e91d4703014 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -257,6 +257,15 @@ GPUTexture *GPU_texture_create_view(const char *name, int layer_len, bool cube_as_array); +GPUTexture *GPU_texture_create_single_layer_view(const char *name, const GPUTexture *src); + +/** + * Create an alias of the source texture as a texture array with only one layer. + * Works for 1D, 2D and cube-map source texture. + * If \a src is freed, the texture view will continue to be valid. + */ +GPUTexture *GPU_texture_create_single_layer_array_view(const char *name, const GPUTexture *src); + void GPU_texture_update_mipmap(GPUTexture *tex, int miplvl, eGPUDataFormat gpu_data_format, diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc index c871004deac..e1876f6d8ac 100644 --- a/source/blender/gpu/intern/gpu_batch.cc +++ b/source/blender/gpu/intern/gpu_batch.cc @@ -56,7 +56,6 @@ void GPU_batch_init_ex(GPUBatch *batch, GPUIndexBuf *elem, eGPUBatchFlag owns_flag) { - BLI_assert(verts != nullptr); /* Do not pass any other flag */ BLI_assert((owns_flag & ~(GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX)) == 0); diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c deleted file mode 100644 index 6dbff95db8e..00000000000 --- a/source/blender/gpu/intern/gpu_buffers.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2005 Blender Foundation. All rights reserved. */ - -/** \file - * \ingroup gpu - * - * Mesh drawing using OpenGL VBO (Vertex Buffer Objects) - */ - -#include <limits.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "BLI_bitmap.h" -#include "BLI_ghash.h" -#include "BLI_math_color.h" -#include "BLI_utildefines.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_attribute.h" -#include "BKE_ccg.h" -#include "BKE_customdata.h" -#include "BKE_mesh.h" -#include "BKE_paint.h" -#include "BKE_pbvh.h" -#include "BKE_subdiv_ccg.h" - -#include "GPU_batch.h" -#include "GPU_buffers.h" - -#include "DRW_engine.h" - -#include "gpu_private.h" - -#include "bmesh.h" - -struct GPU_PBVH_Buffers { - GPUIndexBuf *index_buf, *index_buf_fast; - GPUIndexBuf *index_lines_buf, *index_lines_buf_fast; - GPUVertBuf *vert_buf; - - GPUBatch *lines; - GPUBatch *lines_fast; - GPUBatch *triangles; - GPUBatch *triangles_fast; - - /* mesh pointers in case buffer allocation fails */ - const MPoly *mpoly; - const MLoop *mloop; - const MLoopTri *looptri; - const float (*positions)[3]; - - const int *face_indices; - int face_indices_len; - - /* grid pointers */ - CCGKey gridkey; - CCGElem **grids; - const DMFlagMat *grid_flag_mats; - BLI_bitmap *const *grid_hidden; - const int *grid_indices; - int totgrid; - - bool use_bmesh; - bool clear_bmesh_on_flush; - - uint tot_tri, tot_quad; - - short material_index; - - /* The PBVH ensures that either all faces in the node are - * smooth-shaded or all faces are flat-shaded */ - bool smooth; - - bool show_overlay; -}; - -typedef struct GPUAttrRef { - uchar domain, type; - ushort cd_offset; - int layer_idx; -} GPUAttrRef; - -#define MAX_GPU_ATTR 256 - -typedef struct PBVHGPUFormat { - GPUVertFormat format; - uint pos, nor, msk, fset; - uint col[MAX_GPU_ATTR]; - uint uv[MAX_GPU_ATTR]; - int totcol, totuv; - - /* Upload only the active color and UV attributes, - * used for workbench mode. */ - bool active_attrs_only; -} PBVHGPUFormat; - -PBVHGPUFormat *GPU_pbvh_make_format(void) -{ - PBVHGPUFormat *vbo_id = MEM_callocN(sizeof(PBVHGPUFormat), "PBVHGPUFormat"); - - GPU_pbvh_attribute_names_update(PBVH_FACES, vbo_id, NULL, NULL, false); - - return vbo_id; -} - -void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id) -{ - MEM_SAFE_FREE(vbo_id); -} - -static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask, - eCustomDataMask type_mask, - const CustomData *vdata, - const CustomData *edata, - const CustomData *ldata, - const CustomData *pdata, - GPUAttrRef r_cd_attrs[MAX_GPU_ATTR], - bool active_only, - int active_type, - int active_domain, - const CustomDataLayer *active_layer, - const CustomDataLayer *render_layer); - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name PBVH Utils - * \{ */ - -void gpu_pbvh_init() -{ -} - -void gpu_pbvh_exit() -{ - /* Nothing to do. */ -} - -static CustomDataLayer *get_active_layer(const CustomData *cdata, int type) -{ - int idx = CustomData_get_active_layer_index(cdata, type); - return idx != -1 ? cdata->layers + idx : NULL; -} - -static CustomDataLayer *get_render_layer(const CustomData *cdata, int type) -{ - int idx = CustomData_get_render_layer_index(cdata, type); - return idx != -1 ? cdata->layers + idx : NULL; -} - -/* Allocates a non-initialized buffer to be sent to GPU. - * Return is false it indicates that the memory map failed. */ -static bool gpu_pbvh_vert_buf_data_set(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - uint vert_len) -{ - /* Keep so we can test #GPU_USAGE_DYNAMIC buffer use. - * Not that format initialization match in both blocks. - * Do this to keep braces balanced - otherwise indentation breaks. */ - - if (buffers->vert_buf == NULL) { - /* Initialize vertex buffer (match 'VertexBufferFormat'). */ - buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&vbo_id->format, GPU_USAGE_STATIC); - } - if (GPU_vertbuf_get_data(buffers->vert_buf) == NULL || - GPU_vertbuf_get_vertex_len(buffers->vert_buf) != vert_len) { - /* Allocate buffer if not allocated yet or size changed. */ - GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len); - } - - return GPU_vertbuf_get_data(buffers->vert_buf) != NULL; -} - -static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim) -{ - if (buffers->triangles == NULL) { - buffers->triangles = GPU_batch_create(prim, - buffers->vert_buf, - /* can be NULL if buffer is empty */ - buffers->index_buf); - } - - if ((buffers->triangles_fast == NULL) && buffers->index_buf_fast) { - buffers->triangles_fast = GPU_batch_create(prim, buffers->vert_buf, buffers->index_buf_fast); - } - - if (buffers->lines == NULL) { - buffers->lines = GPU_batch_create(GPU_PRIM_LINES, - buffers->vert_buf, - /* can be NULL if buffer is empty */ - buffers->index_lines_buf); - } - - if ((buffers->lines_fast == NULL) && buffers->index_lines_buf_fast) { - buffers->lines_fast = GPU_batch_create( - GPU_PRIM_LINES, buffers->vert_buf, buffers->index_lines_buf_fast); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mesh PBVH - * \{ */ - -static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt, const bool *hide_poly) -{ - return !paint_is_face_hidden(lt, hide_poly); -} - -void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - const Mesh *mesh, - const float (*positions)[3], - const float *vmask, - const int *sculpt_face_sets, - int face_sets_color_seed, - int face_sets_color_default, - int update_flags, - const float (*vert_normals)[3]) -{ - GPUAttrRef vcol_refs[MAX_GPU_ATTR]; - GPUAttrRef cd_uvs[MAX_GPU_ATTR]; - - const bool *hide_poly = (const bool *)CustomData_get_layer_named( - &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); - const int *material_indices = (const int *)CustomData_get_layer_named( - &mesh->pdata, CD_PROP_INT32, "material_index"); - - const CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&mesh->id); - eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&mesh->id, actcol) : - ATTR_DOMAIN_AUTO; - - const CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&mesh->id); - - int totcol; - - if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) { - totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, - CD_MASK_COLOR_ALL, - &mesh->vdata, - NULL, - &mesh->ldata, - NULL, - vcol_refs, - vbo_id->active_attrs_only, - actcol ? actcol->type : 0, - actcol_domain, - actcol, - rendercol); - } - else { - totcol = 0; - } - - int totuv = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER, - CD_MASK_MLOOPUV, - NULL, - NULL, - &mesh->ldata, - NULL, - cd_uvs, - vbo_id->active_attrs_only, - CD_MLOOPUV, - ATTR_DOMAIN_CORNER, - get_active_layer(&mesh->ldata, CD_MLOOPUV), - get_render_layer(&mesh->ldata, CD_MLOOPUV)); - - const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_face_sets = sculpt_face_sets && - (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; - bool empty_mask = true; - bool default_face_set = true; - - { - const int totelem = buffers->tot_tri * 3; - - /* Build VBO */ - if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totelem)) { - GPUVertBufRaw pos_step = {0}; - GPUVertBufRaw nor_step = {0}; - GPUVertBufRaw msk_step = {0}; - GPUVertBufRaw fset_step = {0}; - GPUVertBufRaw col_step = {0}; - GPUVertBufRaw uv_step = {0}; - - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->pos, &pos_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->nor, &nor_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->msk, &msk_step); - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->fset, &fset_step); - - /* calculate normal for each polygon only once */ - uint mpoly_prev = UINT_MAX; - short no[3] = {0, 0, 0}; - - if (totuv > 0) { - for (int uv_i = 0; uv_i < totuv; uv_i++) { - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step); - - GPUAttrRef *ref = cd_uvs + uv_i; - CustomDataLayer *layer = mesh->ldata.layers + ref->layer_idx; - MLoopUV *muv = layer->data; - - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - - if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { - continue; - } - - for (uint j = 0; j < 3; j++) { - MLoopUV *muv2 = muv + lt->tri[j]; - - memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv)); - } - } - } - } - - for (int col_i = 0; col_i < totcol; col_i++) { - GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step); - - const MPropCol *pcol = NULL; - const MLoopCol *mcol = NULL; - - GPUAttrRef *ref = vcol_refs + col_i; - const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? &mesh->vdata : &mesh->ldata; - const CustomDataLayer *layer = cdata->layers + ref->layer_idx; - - bool color_loops = ref->domain == ATTR_DOMAIN_CORNER; - - if (layer->type == CD_PROP_COLOR) { - pcol = (const MPropCol *)layer->data; - } - else { - mcol = (const MLoopCol *)layer->data; - } - - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - const uint vtri[3] = { - buffers->mloop[lt->tri[0]].v, - buffers->mloop[lt->tri[1]].v, - buffers->mloop[lt->tri[2]].v, - }; - - if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { - continue; - } - - for (uint j = 0; j < 3; j++) { - /* Vertex Colors. */ - const uint loop_index = lt->tri[j]; - - ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - - if (pcol) { - const MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]); - - scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]); - scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]); - scol[2] = unit_float_to_ushort_clamp(pcol2->color[2]); - scol[3] = unit_float_to_ushort_clamp(pcol2->color[3]); - } - else { - const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]); - - scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]); - scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]); - scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]); - scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f)); - } - - memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol)); - } - } - } - - for (uint i = 0; i < buffers->face_indices_len; i++) { - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]]; - const uint vtri[3] = { - buffers->mloop[lt->tri[0]].v, - buffers->mloop[lt->tri[1]].v, - buffers->mloop[lt->tri[2]].v, - }; - - if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { - continue; - } - - /* Face normal and mask */ - if (lt->poly != mpoly_prev && !buffers->smooth) { - const MPoly *mp = &buffers->mpoly[lt->poly]; - float fno[3]; - BKE_mesh_calc_poly_normal(mp, &buffers->mloop[mp->loopstart], positions, fno); - normal_float_to_short_v3(no, fno); - mpoly_prev = lt->poly; - } - - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - if (show_face_sets) { - const int fset = sculpt_face_sets[lt->poly]; - /* Skip for the default color Face Set to render it white. */ - if (fset != face_sets_color_default) { - BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); - default_face_set = false; - } - } - - float fmask = 0.0f; - uchar cmask = 0; - if (show_mask && !buffers->smooth) { - fmask = (vmask[vtri[0]] + vmask[vtri[1]] + vmask[vtri[2]]) / 3.0f; - cmask = (uchar)(fmask * 255); - } - - for (uint j = 0; j < 3; j++) { - copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), positions[vtri[j]]); - - if (buffers->smooth) { - normal_float_to_short_v3(no, vert_normals[vtri[j]]); - } - copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no); - - if (show_mask && buffers->smooth) { - cmask = (uchar)(vmask[vtri[j]] * 255); - } - - *(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask; - empty_mask = empty_mask && (cmask == 0); - /* Face Sets. */ - memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3])); - } - } - } - - gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); - } - - /* Get material index from the first face of this buffer. */ - const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]]; - buffers->material_index = material_indices ? material_indices[lt->poly] : 0; - - buffers->show_overlay = !empty_mask || !default_face_set; - buffers->positions = positions; -} - -GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh, - const MLoopTri *looptri, - const int *face_indices, - const int face_indices_len) -{ - GPU_PBVH_Buffers *buffers; - int i, tottri; - int tot_real_edges = 0; - - const MPoly *polys = BKE_mesh_polys(mesh); - const MLoop *loops = BKE_mesh_loops(mesh); - - buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - - const bool *hide_poly = (bool *)CustomData_get_layer_named( - &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); - - /* smooth or flat for all */ - buffers->smooth = polys[looptri[face_indices[0]].poly].flag & ME_SMOOTH; - - buffers->show_overlay = false; - - /* Count the number of visible triangles */ - for (i = 0, tottri = 0; i < face_indices_len; i++) { - const MLoopTri *lt = &looptri[face_indices[i]]; - if (gpu_pbvh_is_looptri_visible(lt, hide_poly)) { - int r_edges[3]; - BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); - for (int j = 0; j < 3; j++) { - if (r_edges[j] != -1) { - tot_real_edges++; - } - } - tottri++; - } - } - - if (tottri == 0) { - buffers->tot_tri = 0; - - buffers->mpoly = polys; - buffers->mloop = loops; - buffers->looptri = looptri; - buffers->face_indices = face_indices; - buffers->face_indices_len = 0; - - return buffers; - } - - /* Fill the only the line buffer. */ - GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tot_real_edges, INT_MAX); - int vert_idx = 0; - - for (i = 0; i < face_indices_len; i++) { - const MLoopTri *lt = &looptri[face_indices[i]]; - - /* Skip hidden faces */ - if (!gpu_pbvh_is_looptri_visible(lt, hide_poly)) { - continue; - } - - int r_edges[3]; - BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges); - if (r_edges[0] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 0, vert_idx * 3 + 1); - } - if (r_edges[1] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 1, vert_idx * 3 + 2); - } - if (r_edges[2] != -1) { - GPU_indexbuf_add_line_verts(&elb_lines, vert_idx * 3 + 2, vert_idx * 3 + 0); - } - - vert_idx++; - } - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - - buffers->tot_tri = tottri; - - buffers->mpoly = polys; - buffers->mloop = loops; - buffers->looptri = looptri; - - buffers->face_indices = face_indices; - buffers->face_indices_len = face_indices_len; - - return buffers; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Grid PBVH - * \{ */ - -static void gpu_pbvh_grid_fill_index_buffers(GPU_PBVH_Buffers *buffers, - SubdivCCG *UNUSED(subdiv_ccg), - const int *UNUSED(face_sets), - const int *grid_indices, - uint visible_quad_len, - int totgrid, - int gridsize) -{ - GPUIndexBufBuilder elb, elb_lines; - GPUIndexBufBuilder elb_fast, elb_lines_fast; - - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX); - GPU_indexbuf_init(&elb_fast, GPU_PRIM_TRIS, 2 * totgrid, INT_MAX); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, 2 * totgrid * gridsize * (gridsize - 1), INT_MAX); - GPU_indexbuf_init(&elb_lines_fast, GPU_PRIM_LINES, 4 * totgrid, INT_MAX); - - if (buffers->smooth) { - uint offset = 0; - const uint grid_vert_len = gridsize * gridsize; - for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { - uint v0, v1, v2, v3; - bool grid_visible = false; - - BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]]; - - for (int j = 0; j < gridsize - 1; j++) { - for (int k = 0; k < gridsize - 1; k++) { - /* Skip hidden grid face */ - if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) { - continue; - } - /* Indices in a Clockwise QUAD disposition. */ - v0 = offset + j * gridsize + k; - v1 = v0 + 1; - v2 = v1 + gridsize; - v3 = v2 - 1; - - GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1); - GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2); - - GPU_indexbuf_add_line_verts(&elb_lines, v0, v1); - GPU_indexbuf_add_line_verts(&elb_lines, v0, v3); - - if (j + 2 == gridsize) { - GPU_indexbuf_add_line_verts(&elb_lines, v2, v3); - } - grid_visible = true; - } - - if (grid_visible) { - GPU_indexbuf_add_line_verts(&elb_lines, v1, v2); - } - } - - if (grid_visible) { - /* Grid corners */ - v0 = offset; - v1 = offset + gridsize - 1; - v2 = offset + grid_vert_len - 1; - v3 = offset + grid_vert_len - gridsize; - - GPU_indexbuf_add_tri_verts(&elb_fast, v0, v2, v1); - GPU_indexbuf_add_tri_verts(&elb_fast, v0, v3, v2); - - GPU_indexbuf_add_line_verts(&elb_lines_fast, v0, v1); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v1, v2); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v2, v3); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v3, v0); - } - } - } - else { - uint offset = 0; - const uint grid_vert_len = square_uint(gridsize - 1) * 4; - for (int i = 0; i < totgrid; i++, offset += grid_vert_len) { - bool grid_visible = false; - BLI_bitmap *gh = buffers->grid_hidden[grid_indices[i]]; - - uint v0, v1, v2, v3; - for (int j = 0; j < gridsize - 1; j++) { - for (int k = 0; k < gridsize - 1; k++) { - /* Skip hidden grid face */ - if (gh && paint_is_grid_face_hidden(gh, gridsize, k, j)) { - continue; - } - /* VBO data are in a Clockwise QUAD disposition. */ - v0 = offset + (j * (gridsize - 1) + k) * 4; - v1 = v0 + 1; - v2 = v0 + 2; - v3 = v0 + 3; - - GPU_indexbuf_add_tri_verts(&elb, v0, v2, v1); - GPU_indexbuf_add_tri_verts(&elb, v0, v3, v2); - - GPU_indexbuf_add_line_verts(&elb_lines, v0, v1); - GPU_indexbuf_add_line_verts(&elb_lines, v0, v3); - - if (j + 2 == gridsize) { - GPU_indexbuf_add_line_verts(&elb_lines, v2, v3); - } - grid_visible = true; - } - - if (grid_visible) { - GPU_indexbuf_add_line_verts(&elb_lines, v1, v2); - } - } - - if (grid_visible) { - /* Grid corners */ - v0 = offset; - v1 = offset + (gridsize - 1) * 4 - 3; - v2 = offset + grid_vert_len - 2; - v3 = offset + grid_vert_len - (gridsize - 1) * 4 + 3; - - GPU_indexbuf_add_tri_verts(&elb_fast, v0, v2, v1); - GPU_indexbuf_add_tri_verts(&elb_fast, v0, v3, v2); - - GPU_indexbuf_add_line_verts(&elb_lines_fast, v0, v1); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v1, v2); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v2, v3); - GPU_indexbuf_add_line_verts(&elb_lines_fast, v3, v0); - } - } - } - - buffers->index_buf = GPU_indexbuf_build(&elb); - buffers->index_buf_fast = GPU_indexbuf_build(&elb_fast); - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - buffers->index_lines_buf_fast = GPU_indexbuf_build(&elb_lines_fast); -} - -void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers, - const struct DMFlagMat *grid_flag_mats, - const int *grid_indices) -{ - const bool smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH; - - if (buffers->smooth != smooth) { - buffers->smooth = smooth; - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); - - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - } -} - -void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - SubdivCCG *subdiv_ccg, - CCGElem **grids, - const struct DMFlagMat *grid_flag_mats, - int *grid_indices, - int totgrid, - const int *sculpt_face_sets, - const int face_sets_color_seed, - const int face_sets_color_default, - const struct CCGKey *key, - const int update_flags) -{ - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; - const bool show_face_sets = sculpt_face_sets && - (update_flags & GPU_PBVH_BUFFERS_SHOW_SCULPT_FACE_SETS) != 0; - bool empty_mask = true; - bool default_face_set = true; - - int i, j, k, x, y; - - /* Build VBO */ - const int has_mask = key->has_mask; - - uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4); - uint vert_count = totgrid * vert_per_grid; - - if (buffers->index_buf == NULL) { - uint visible_quad_len = BKE_pbvh_count_grid_quads( - (BLI_bitmap **)buffers->grid_hidden, grid_indices, totgrid, key->grid_size); - - /* totally hidden node, return here to avoid BufferData with zero below. */ - if (visible_quad_len == 0) { - return; - } - - gpu_pbvh_grid_fill_index_buffers(buffers, - subdiv_ccg, - sculpt_face_sets, - grid_indices, - visible_quad_len, - totgrid, - key->grid_size); - } - - uint vbo_index_offset = 0; - /* Build VBO */ - if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, vert_count)) { - GPUIndexBufBuilder elb_lines; - - if (buffers->index_lines_buf == NULL) { - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, totgrid * key->grid_area * 2, vert_count); - } - - for (i = 0; i < totgrid; i++) { - const int grid_index = grid_indices[i]; - CCGElem *grid = grids[grid_index]; - int vbo_index = vbo_index_offset; - - uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - - if (show_face_sets && subdiv_ccg && sculpt_face_sets) { - const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, grid_index); - - const int fset = sculpt_face_sets[face_index]; - /* Skip for the default color Face Set to render it white. */ - if (fset != face_sets_color_default) { - BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color); - default_face_set = false; - } - } - - if (buffers->smooth) { - for (y = 0; y < key->grid_size; y++) { - for (x = 0; x < key->grid_size; x++) { - CCGElem *elem = CCG_grid_elem(key, grid, x, y); - GPU_vertbuf_attr_set( - buffers->vert_buf, vbo_id->pos, vbo_index, CCG_elem_co(key, elem)); - - short no_short[3]; - normal_float_to_short_v3(no_short, CCG_elem_no(key, elem)); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index, no_short); - - if (has_mask && show_mask) { - float fmask = *CCG_elem_mask(key, elem); - uchar cmask = (uchar)(fmask * 255); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index, &cmask); - empty_mask = empty_mask && (cmask == 0); - } - - if (show_vcol) { - const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index, &vcol); - } - - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index, &face_set_color); - - vbo_index += 1; - } - } - vbo_index_offset += key->grid_area; - } - else { - for (j = 0; j < key->grid_size - 1; j++) { - for (k = 0; k < key->grid_size - 1; k++) { - CCGElem *elems[4] = { - CCG_grid_elem(key, grid, k, j), - CCG_grid_elem(key, grid, k + 1, j), - CCG_grid_elem(key, grid, k + 1, j + 1), - CCG_grid_elem(key, grid, k, j + 1), - }; - float *co[4] = { - CCG_elem_co(key, elems[0]), - CCG_elem_co(key, elems[1]), - CCG_elem_co(key, elems[2]), - CCG_elem_co(key, elems[3]), - }; - - float fno[3]; - short no_short[3]; - /* NOTE: Clockwise indices ordering, that's why we invert order here. */ - normal_quad_v3(fno, co[3], co[2], co[1], co[0]); - normal_float_to_short_v3(no_short, fno); - - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 0, co[0]); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 0, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 1, co[1]); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 1, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 2, co[2]); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 2, no_short); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 3, co[3]); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 3, no_short); - - if (has_mask && show_mask) { - float fmask = (*CCG_elem_mask(key, elems[0]) + *CCG_elem_mask(key, elems[1]) + - *CCG_elem_mask(key, elems[2]) + *CCG_elem_mask(key, elems[3])) * - 0.25f; - uchar cmask = (uchar)(fmask * 255); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 0, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 1, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 2, &cmask); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 3, &cmask); - empty_mask = empty_mask && (cmask == 0); - } - - const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 0, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 1, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 2, &vcol); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 3, &vcol); - - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 0, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 1, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 2, &face_set_color); - GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 3, &face_set_color); - - vbo_index += 4; - } - } - vbo_index_offset += square_i(key->grid_size - 1) * 4; - } - } - - gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); - } - - /* Get material index from the first face of this buffer. */ - buffers->material_index = grid_flag_mats[grid_indices[0]].mat_nr; - - buffers->grids = grids; - buffers->grid_indices = grid_indices; - buffers->totgrid = totgrid; - buffers->grid_flag_mats = grid_flag_mats; - buffers->gridkey = *key; - buffers->show_overlay = !empty_mask || !default_face_set; -} - -GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden, bool smooth) -{ - GPU_PBVH_Buffers *buffers; - - buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - buffers->grid_hidden = grid_hidden; - buffers->totgrid = totgrid; - buffers->smooth = smooth; - - buffers->show_overlay = false; - - return buffers; -} - -#undef FILL_QUAD_BUFFER - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name BMesh PBVH - * \{ */ - -/* Output a BMVert into a VertexBufferFormat array at v_index. */ -static void gpu_bmesh_vert_to_buffer_copy(PBVHGPUFormat *vbo_id, - BMVert *v, - GPUVertBuf *vert_buf, - int v_index, - const float fno[3], - const float *fmask, - const int cd_vert_mask_offset, - const bool show_mask, - const bool show_vcol, - bool *empty_mask) -{ - /* Vertex should always be visible if it's used by a visible face. */ - BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN)); - - /* Set coord, normal, and mask */ - GPU_vertbuf_attr_set(vert_buf, vbo_id->pos, v_index, v->co); - - short no_short[3]; - normal_float_to_short_v3(no_short, fno ? fno : v->no); - GPU_vertbuf_attr_set(vert_buf, vbo_id->nor, v_index, no_short); - - if (show_mask) { - float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset); - uchar cmask = (uchar)(effective_mask * 255); - GPU_vertbuf_attr_set(vert_buf, vbo_id->msk, v_index, &cmask); - *empty_mask = *empty_mask && (cmask == 0); - } - - if (show_vcol) { - const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}; - GPU_vertbuf_attr_set(vert_buf, vbo_id->col[0], v_index, &vcol); - } - - /* Add default face sets color to avoid artifacts. */ - const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; - GPU_vertbuf_attr_set(vert_buf, vbo_id->fset, v_index, &face_set); -} - -/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */ -static int gpu_bmesh_vert_visible_count(GSet *bm_unique_verts, GSet *bm_other_verts) -{ - GSetIterator gs_iter; - int totvert = 0; - - GSET_ITER (gs_iter, bm_unique_verts) { - BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - totvert++; - } - } - GSET_ITER (gs_iter, bm_other_verts) { - BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - totvert++; - } - } - - return totvert; -} - -/* Return the total number of visible faces */ -static int gpu_bmesh_face_visible_count(GSet *bm_faces) -{ - GSetIterator gh_iter; - int totface = 0; - - GSET_ITER (gh_iter, bm_faces) { - BMFace *f = BLI_gsetIterator_getKey(&gh_iter); - - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - totface++; - } - } - - return totface; -} - -void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers) -{ - if (buffers->smooth) { - /* Smooth needs to recreate index buffer, so we have to invalidate the batch. */ - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - } - else { - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - } -} - -void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id, - GPU_PBVH_Buffers *buffers, - BMesh *bm, - GSet *bm_faces, - GSet *bm_unique_verts, - GSet *bm_other_verts, - const int update_flags) -{ - const bool show_mask = (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0; - const bool show_vcol = (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0; - int tottri, totvert; - bool empty_mask = true; - BMFace *f = NULL; - - /* Count visible triangles */ - tottri = gpu_bmesh_face_visible_count(bm_faces); - - if (buffers->smooth) { - /* Count visible vertices */ - totvert = gpu_bmesh_vert_visible_count(bm_unique_verts, bm_other_verts); - } - else { - totvert = tottri * 3; - } - - if (!tottri) { - if (BLI_gset_len(bm_faces) != 0) { - /* Node is just hidden. */ - } - else { - buffers->clear_bmesh_on_flush = true; - } - buffers->tot_tri = 0; - return; - } - - /* TODO: make mask layer optional for bmesh buffer. */ - const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK); - - /* Fill vertex buffer */ - if (!gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totvert)) { - /* Memory map failed */ - return; - } - - int v_index = 0; - - if (buffers->smooth) { - /* Fill the vertex and triangle buffer in one pass over faces. */ - GPUIndexBufBuilder elb, elb_lines; - GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottri, totvert); - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, totvert); - - GHash *bm_vert_to_index = BLI_ghash_int_new_ex("bm_vert_to_index", totvert); - - GSetIterator gs_iter; - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); - - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; - BM_face_as_array_vert_tri(f, v); - - uint idx[3]; - for (int i = 0; i < 3; i++) { - void **idx_p; - if (!BLI_ghash_ensure_p(bm_vert_to_index, v[i], &idx_p)) { - /* Add vertex to the vertex buffer each time a new one is encountered */ - *idx_p = POINTER_FROM_UINT(v_index); - - gpu_bmesh_vert_to_buffer_copy(vbo_id, - v[i], - buffers->vert_buf, - v_index, - NULL, - NULL, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - - idx[i] = v_index; - v_index++; - } - else { - /* Vertex already in the vertex buffer, just get the index. */ - idx[i] = POINTER_AS_UINT(*idx_p); - } - } - - GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]); - - GPU_indexbuf_add_line_verts(&elb_lines, idx[0], idx[1]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[1], idx[2]); - GPU_indexbuf_add_line_verts(&elb_lines, idx[2], idx[0]); - } - } - - BLI_ghash_free(bm_vert_to_index, NULL, NULL); - - buffers->tot_tri = tottri; - if (buffers->index_buf == NULL) { - buffers->index_buf = GPU_indexbuf_build(&elb); - } - else { - GPU_indexbuf_build_in_place(&elb, buffers->index_buf); - } - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - } - else { - GSetIterator gs_iter; - - GPUIndexBufBuilder elb_lines; - GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3); - - GSET_ITER (gs_iter, bm_faces) { - f = BLI_gsetIterator_getKey(&gs_iter); - - BLI_assert(f->len == 3); - - if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - BMVert *v[3]; - float fmask = 0.0f; - int i; - - BM_face_as_array_vert_tri(f, v); - - /* Average mask value */ - for (i = 0; i < 3; i++) { - fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset); - } - fmask /= 3.0f; - - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2); - GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0); - - for (i = 0; i < 3; i++) { - gpu_bmesh_vert_to_buffer_copy(vbo_id, - v[i], - buffers->vert_buf, - v_index++, - f->no, - &fmask, - cd_vert_mask_offset, - show_mask, - show_vcol, - &empty_mask); - } - } - } - - buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines); - buffers->tot_tri = tottri; - } - - /* Get material index from the last face we iterated on. */ - buffers->material_index = (f) ? f->mat_nr : 0; - - buffers->show_overlay = !empty_mask; - - gpu_pbvh_batch_init(buffers, GPU_PRIM_TRIS); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Generic - * \{ */ - -GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading) -{ - GPU_PBVH_Buffers *buffers; - - buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers"); - buffers->use_bmesh = true; - buffers->smooth = smooth_shading; - buffers->show_overlay = true; - - return buffers; -} - -/** - * Builds a list of attributes from a set of domains and a set of - * customdata types. - * - * \param active_only: Returns only one item, a #GPUAttrRef to active_layer. - * \param active_layer: #CustomDataLayer to use for the active layer. - * \param active_layer: #CustomDataLayer to use for the render layer. - */ -static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask, - eCustomDataMask type_mask, - const CustomData *vdata, - const CustomData *edata, - const CustomData *ldata, - const CustomData *pdata, - GPUAttrRef r_cd_attrs[MAX_GPU_ATTR], - bool active_only, - int active_type, - int active_domain, - const CustomDataLayer *active_layer, - const CustomDataLayer *render_layer) -{ - const CustomData *cdata_active = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata; - - if (!cdata_active) { - return 0; - } - - if (active_only) { - int idx = active_layer ? active_layer - cdata_active->layers : -1; - - if (idx >= 0 && idx < cdata_active->totlayer) { - r_cd_attrs[0].cd_offset = cdata_active->layers[idx].offset; - r_cd_attrs[0].domain = active_domain; - r_cd_attrs[0].type = active_type; - r_cd_attrs[0].layer_idx = idx; - - return 1; - } - - return 0; - } - - const CustomData *datas[4] = {vdata, edata, pdata, ldata}; - - int count = 0; - for (eAttrDomain domain = 0; domain < 4; domain++) { - const CustomData *cdata = datas[domain]; - - if (!cdata || !((1 << domain) & domain_mask)) { - continue; - } - - const CustomDataLayer *cl = cdata->layers; - - for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) { - if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) { - GPUAttrRef *ref = r_cd_attrs + count; - - ref->cd_offset = cl->offset; - ref->type = cl->type; - ref->layer_idx = i; - ref->domain = domain; - - count++; - } - } - } - - /* Ensure render layer is last, draw cache code seems to need this. */ - - for (int i = 0; i < count; i++) { - GPUAttrRef *ref = r_cd_attrs + i; - const CustomData *cdata = datas[ref->domain]; - - if (cdata->layers + ref->layer_idx == render_layer) { - SWAP(GPUAttrRef, r_cd_attrs[i], r_cd_attrs[count - 1]); - break; - } - } - - return count; -} - -static bool gpu_pbvh_format_equals(PBVHGPUFormat *a, PBVHGPUFormat *b) -{ - bool bad = false; - - bad |= a->active_attrs_only != b->active_attrs_only; - - bad |= a->pos != b->pos; - bad |= a->fset != b->fset; - bad |= a->msk != b->msk; - bad |= a->nor != b->nor; - - for (int i = 0; i < MIN2(a->totuv, b->totuv); i++) { - bad |= a->uv[i] != b->uv[i]; - } - - for (int i = 0; i < MIN2(a->totcol, b->totcol); i++) { - bad |= a->col[i] != b->col[i]; - } - - bad |= a->totuv != b->totuv; - bad |= a->totcol != b->totcol; - - return !bad; -} - -bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type, - PBVHGPUFormat *vbo_id, - const CustomData *vdata, - const CustomData *ldata, - bool active_attrs_only) -{ - const bool active_only = active_attrs_only; - PBVHGPUFormat old_format = *vbo_id; - - GPU_vertformat_clear(&vbo_id->format); - - vbo_id->active_attrs_only = active_attrs_only; - - if (vbo_id->format.attr_len == 0) { - vbo_id->pos = GPU_vertformat_attr_add( - &vbo_id->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - vbo_id->nor = GPU_vertformat_attr_add( - &vbo_id->format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - - /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */ - vbo_id->msk = GPU_vertformat_attr_add( - &vbo_id->format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); - - vbo_id->totcol = 0; - if (pbvh_type == PBVH_FACES) { - int ci = 0; - - Mesh me_query; - - BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id); - - const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id); - const CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id); - eAttrDomain active_color_domain = active_color_layer ? - BKE_id_attribute_domain(&me_query.id, - active_color_layer) : - ATTR_DOMAIN_POINT; - - GPUAttrRef vcol_layers[MAX_GPU_ATTR]; - int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR, - CD_MASK_COLOR_ALL, - vdata, - NULL, - ldata, - NULL, - vcol_layers, - active_only, - active_color_layer ? active_color_layer->type : -1, - active_color_domain, - active_color_layer, - render_color_layer); - - for (int i = 0; i < totlayer; i++) { - GPUAttrRef *ref = vcol_layers + i; - const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata; - - const CustomDataLayer *layer = cdata->layers + ref->layer_idx; - - if (vbo_id->totcol < MAX_GPU_ATTR) { - vbo_id->col[ci++] = GPU_vertformat_attr_add( - &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - vbo_id->totcol++; - - bool is_render = render_color_layer == layer; - bool is_active = active_color_layer == layer; - - DRW_cdlayer_attr_aliases_add(&vbo_id->format, "c", cdata, layer, is_render, is_active); - } - } - } - - /* ensure at least one vertex color layer */ - if (vbo_id->totcol == 0) { - vbo_id->col[0] = GPU_vertformat_attr_add( - &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - vbo_id->totcol = 1; - - GPU_vertformat_alias_add(&vbo_id->format, "ac"); - } - - vbo_id->fset = GPU_vertformat_attr_add( - &vbo_id->format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); - - vbo_id->totuv = 0; - if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) { - GPUAttrRef uv_layers[MAX_GPU_ATTR]; - const CustomDataLayer *active = NULL, *render = NULL; - - active = get_active_layer(ldata, CD_MLOOPUV); - render = get_render_layer(ldata, CD_MLOOPUV); - - int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER, - CD_MASK_MLOOPUV, - NULL, - NULL, - ldata, - NULL, - uv_layers, - active_only, - CD_MLOOPUV, - ATTR_DOMAIN_CORNER, - active, - render); - - vbo_id->totuv = totlayer; - - for (int i = 0; i < totlayer; i++) { - GPUAttrRef *ref = uv_layers + i; - - vbo_id->uv[i] = GPU_vertformat_attr_add( - &vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - const CustomDataLayer *cl = ldata->layers + ref->layer_idx; - bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV); - - DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active); - - /* Apparently the render attribute is 'a' while active is 'au', - * at least going by the draw cache extractor code. - */ - if (cl == render) { - GPU_vertformat_alias_add(&vbo_id->format, "a"); - } - } - } - } - - if (!gpu_pbvh_format_equals(&old_format, vbo_id)) { - return true; - } - - return false; -} - -GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires) -{ - if (wires) { - return (fast && buffers->lines_fast) ? buffers->lines_fast : buffers->lines; - } - - return (fast && buffers->triangles_fast) ? buffers->triangles_fast : buffers->triangles; -} - -bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers) -{ - return buffers->show_overlay; -} - -short GPU_pbvh_buffers_material_index_get(GPU_PBVH_Buffers *buffers) -{ - return buffers->material_index; -} - -static void gpu_pbvh_buffers_clear(GPU_PBVH_Buffers *buffers) -{ - GPU_BATCH_DISCARD_SAFE(buffers->lines); - GPU_BATCH_DISCARD_SAFE(buffers->lines_fast); - GPU_BATCH_DISCARD_SAFE(buffers->triangles); - GPU_BATCH_DISCARD_SAFE(buffers->triangles_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_lines_buf); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf_fast); - GPU_INDEXBUF_DISCARD_SAFE(buffers->index_buf); - GPU_VERTBUF_DISCARD_SAFE(buffers->vert_buf); -} - -void GPU_pbvh_buffers_update_flush(GPU_PBVH_Buffers *buffers) -{ - /* Free empty bmesh node buffers. */ - if (buffers->clear_bmesh_on_flush) { - gpu_pbvh_buffers_clear(buffers); - buffers->clear_bmesh_on_flush = false; - } - - /* Force flushing to the GPU. */ - if (buffers->vert_buf && GPU_vertbuf_get_data(buffers->vert_buf)) { - GPU_vertbuf_use(buffers->vert_buf); - } -} - -void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers) -{ - if (buffers) { - gpu_pbvh_buffers_clear(buffers); - MEM_freeN(buffers); - } -} - -/** \} */ diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc index 42f4e048131..99e47f5452a 100644 --- a/source/blender/gpu/intern/gpu_index_buffer.cc +++ b/source/blender/gpu/intern/gpu_index_buffer.cc @@ -388,13 +388,13 @@ void IndexBuf::squeeze_indices_short(uint min_idx, 0xFFFFu : (max_idx - min_idx); for (uint i = 0; i < index_len_; i++) { - ushort_idx[i] = (uint16_t)MIN2(clamp_max_idx, uint_idx[i] - min_idx); + ushort_idx[i] = uint16_t(MIN2(clamp_max_idx, uint_idx[i] - min_idx)); } } else { index_base_ = 0; for (uint i = 0; i < index_len_; i++) { - ushort_idx[i] = (uint16_t)(uint_idx[i]); + ushort_idx[i] = uint16_t(uint_idx[i]); } } } diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index 34b355eefaf..2dbb4b215bb 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -36,18 +36,10 @@ void GPU_init(void) gpu_codegen_init(); gpu_batch_init(); - -#ifndef GPU_STANDALONE - gpu_pbvh_init(); -#endif } void GPU_exit(void) { -#ifndef GPU_STANDALONE - gpu_pbvh_exit(); -#endif - gpu_batch_exit(); gpu_codegen_exit(); diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 510c16dfb02..e1ae731d49c 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -416,11 +416,6 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph, if (attr == NULL && attrs->count < GPU_MAX_UNIFORM_ATTR) { attr = MEM_callocN(sizeof(*attr), __func__); STRNCPY(attr->name, name); - { - char attr_name_esc[sizeof(attr->name) * 2]; - BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc)); - SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc); - } attr->use_dupli = use_dupli; attr->hash_code = BLI_ghashutil_strhash_p(attr->name) << 1 | (attr->use_dupli ? 0 : 1); attr->id = -1; diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index bec8b8a0df3..a0ee518e747 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -132,6 +132,7 @@ bool Texture::init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format) bool Texture::init_view(const GPUTexture *src_, eGPUTextureFormat format, + eGPUTextureType type, int mip_start, int mip_len, int layer_start, @@ -144,7 +145,7 @@ bool Texture::init_view(const GPUTexture *src_, d_ = src->d_; layer_start = min_ii(layer_start, src->layer_count() - 1); layer_len = min_ii(layer_len, (src->layer_count() - layer_start)); - switch (src->type_) { + switch (type) { case GPU_TEXTURE_1D_ARRAY: h_ = layer_len; break; @@ -163,8 +164,7 @@ bool Texture::init_view(const GPUTexture *src_, mipmaps_ = mip_len; format_ = format; format_flag_ = to_format_flag(format); - /* For now always copy the target. Target aliasing could be exposed later. */ - type_ = src->type_; + type_ = type; if (cube_as_array) { BLI_assert(type_ & GPU_TEXTURE_CUBE); type_ = (type_ & ~GPU_TEXTURE_CUBE) | GPU_TEXTURE_2D_ARRAY; @@ -404,7 +404,26 @@ GPUTexture *GPU_texture_create_view(const char *name, BLI_assert(mip_len > 0); BLI_assert(layer_len > 0); Texture *view = GPUBackend::get()->texture_alloc(name); - view->init_view(src, format, mip_start, mip_len, layer_start, layer_len, cube_as_array); + view->init_view(src, + format, + unwrap(src)->type_get(), + mip_start, + mip_len, + layer_start, + layer_len, + cube_as_array); + return wrap(view); +} + +GPUTexture *GPU_texture_create_single_layer_view(const char *name, const GPUTexture *src) +{ + eGPUTextureFormat format = unwrap(src)->format_get(); + eGPUTextureType type = unwrap(src)->type_get(); + BLI_assert(ELEM(type, GPU_TEXTURE_1D, GPU_TEXTURE_2D, GPU_TEXTURE_CUBE)); + type |= GPU_TEXTURE_ARRAY; + + Texture *view = GPUBackend::get()->texture_alloc(name); + view->init_view(src, format, type, 0, 9999, 0, 1, false); return wrap(view); } diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 8521b0fd77f..b96a9b870e5 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -108,6 +108,7 @@ class Texture { bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format); bool init_view(const GPUTexture *src, eGPUTextureFormat format, + eGPUTextureType type, int mip_start, int mip_len, int layer_start, diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h index 530c056b584..348e8f4e098 100644 --- a/source/blender/makesdna/DNA_brush_defaults.h +++ b/source/blender/makesdna/DNA_brush_defaults.h @@ -91,6 +91,8 @@ .pose_ik_segments = 1, \ .hardness = 0.0f, \ .automasking_boundary_edges_propagation_steps = 1, \ + .automasking_cavity_blur_steps = 0,\ + .automasking_cavity_factor = 0.5f,\ \ /* A kernel radius of 1 has almost no effect (T63233). */ \ .blur_kernel_radius = 2, \ diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 476000d8885..570b569a4dd 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -89,6 +89,8 @@ typedef enum eGPDbrush_Flag { GP_BRUSH_TRIM_STROKE = (1 << 16), /* Post process convert to outline stroke */ GP_BRUSH_OUTLINE_STROKE = (1 << 17), + /* Collide with stroke. */ + GP_BRUSH_FILL_STROKE_COLLIDE = (1 << 18), } eGPDbrush_Flag; typedef enum eGPDbrush_Flag2 { @@ -326,6 +328,18 @@ typedef enum eAutomasking_flag { BRUSH_AUTOMASKING_FACE_SETS = (1 << 1), BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2), BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3), + BRUSH_AUTOMASKING_CAVITY_NORMAL = (1 << 4), + + /* Note: normal and inverted are mutually exclusive, + * inverted has priority if both bits are set. + */ + BRUSH_AUTOMASKING_CAVITY_INVERTED = (1 << 5), + BRUSH_AUTOMASKING_CAVITY_ALL = (1 << 4) | (1 << 5), + BRUSH_AUTOMASKING_CAVITY_USE_CURVE = (1 << 6), + /* (1 << 7) - unused. */ + BRUSH_AUTOMASKING_BRUSH_NORMAL = (1 << 8), + BRUSH_AUTOMASKING_VIEW_NORMAL = (1 << 9), + BRUSH_AUTOMASKING_VIEW_OCCLUSION = (1 << 10), } eAutomasking_flag; typedef enum ePaintBrush_flag { diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 761a36e8d1f..a415122579e 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -388,6 +388,11 @@ typedef struct Brush { struct BrushGpencilSettings *gpencil_settings; struct BrushCurvesSculptSettings *curves_sculpt_settings; + + int automasking_cavity_blur_steps; + float automasking_cavity_factor; + + struct CurveMapping *automasking_cavity_curve; } Brush; /* Struct to hold palette colors for sorting. */ diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index e011e1c491e..827e07725a1 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -71,27 +71,23 @@ typedef enum eViewLayerCryptomatteFlags { typedef struct Base { struct Base *next, *prev; - /* Flags which are based on the collections flags evaluation, does not - * include flags from object's restrictions. */ - short flag_from_collection; + struct Object *object; + + /* Pointer to an original base. Is initialized for evaluated view layer. + * NOTE: Only allowed to be accessed from within active dependency graph. */ + struct Base *base_orig; + unsigned int lay DNA_DEPRECATED; /* Final flags, including both accumulated collection flags and object's * restriction flags. */ short flag; - + /* Flags which are based on the collections flags evaluation, does not + * include flags from object's restrictions. */ + short flag_from_collection; + short flag_legacy; unsigned short local_view_bits; - short sx, sy; - char _pad1[6]; - struct Object *object; - unsigned int lay DNA_DEPRECATED; - int flag_legacy; unsigned short local_collections_bits; - short _pad2[3]; - - /* Pointer to an original base. Is initialized for evaluated view layer. - * NOTE: Only allowed to be accessed from within active dependency graph. */ - struct Base *base_orig; - void *_pad; + char _pad1[2]; } Base; typedef struct ViewLayerEngineData { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index dbda24fb8b7..963567133d9 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1598,6 +1598,8 @@ typedef struct NodeGeometryImageTexture { typedef struct NodeGeometryViewer { /* eCustomDataType. */ int8_t data_type; + /* eAttrDomain. */ + int8_t domain; } NodeGeometryViewer; typedef struct NodeGeometryUVUnwrap { diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index f152a5bcc61..44f1d3479b1 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -279,7 +279,7 @@ typedef struct ParticleSettings { struct PartDeflect *pd; struct PartDeflect *pd2; - /* modified dm support */ + /* Evaluated mesh support. */ short use_modifier_stack; char _pad5[2]; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index c8ff0083b5e..80b1049ca23 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1021,8 +1021,15 @@ typedef struct Sculpt { float constant_detail; float detail_percent; + int automasking_cavity_blur_steps; + float automasking_cavity_factor; char _pad[4]; + float automasking_start_normal_limit, automasking_start_normal_falloff; + float automasking_view_normal_limit, automasking_view_normal_falloff; + + struct CurveMapping *automasking_cavity_curve; + struct CurveMapping *automasking_cavity_curve_op; /* For use by operators */ struct Object *gravity_object; } Sculpt; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5a819ead4ec..7f0dd2f9be6 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -22,6 +22,7 @@ #include "DNA_vec_types.h" /* Hum ... Not really nice... but needed for spacebuts. */ #include "DNA_view2d_types.h" +#include "DNA_viewer_path_types.h" #ifdef __cplusplus extern "C" { @@ -1888,32 +1889,6 @@ typedef struct SpreadsheetColumn { char *display_name; } SpreadsheetColumn; -/** - * An item in SpaceSpreadsheet.context_path. - * This is a bases struct for the structs below. - */ -typedef struct SpreadsheetContext { - struct SpreadsheetContext *next, *prev; - /* eSpaceSpreadsheet_ContextType. */ - int type; - char _pad[4]; -} SpreadsheetContext; - -typedef struct SpreadsheetContextObject { - SpreadsheetContext base; - struct Object *object; -} SpreadsheetContextObject; - -typedef struct SpreadsheetContextModifier { - SpreadsheetContext base; - char *modifier_name; -} SpreadsheetContextModifier; - -typedef struct SpreadsheetContextNode { - SpreadsheetContext base; - char *node_name; -} SpreadsheetContextNode; - typedef struct SpaceSpreadsheet { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1930,12 +1905,11 @@ typedef struct SpaceSpreadsheet { ListBase row_filters; /** - * List of #SpreadsheetContext. - * This is a path to the data that is displayed in the spreadsheet. - * It can be set explicitly by an action of the user (e.g. clicking the preview icon in a - * geometry node) or it can be derived from context automatically based on some heuristic. + * Context that is currently displayed in the editor. This is usually a either a single object + * (in original/evaluated mode) or path to a viewer node. This is retrieved from the workspace + * but can be pinned so that it stays constant even when the active node changes. */ - ListBase context_path; + ViewerPath viewer_path; /* eSpaceSpreadsheet_FilterFlag. */ uint8_t filter_flag; diff --git a/source/blender/makesdna/DNA_view3d_defaults.h b/source/blender/makesdna/DNA_view3d_defaults.h index b2d17b0ea22..c6c93c33086 100644 --- a/source/blender/makesdna/DNA_view3d_defaults.h +++ b/source/blender/makesdna/DNA_view3d_defaults.h @@ -36,8 +36,10 @@ #define _DNA_DEFAULT_View3DOverlay \ { \ + .flag = V3D_OVERLAY_VIEWER_ATTRIBUTE, \ .wireframe_threshold = 1.0f, \ .wireframe_opacity = 1.0f, \ + .viewer_attribute_opacity = 0.8f, \ .xray_alpha_bone = 0.5f, \ .bone_wire_alpha = 1.0f, \ .fade_alpha = 0.40f, \ @@ -81,7 +83,7 @@ .gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID, \ \ .flag = V3D_SELECT_OUTLINE, \ - .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION, \ + .flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION | V3D_SHOW_VIEWER, \ \ .lens = 50.0f, \ .clip_start = 0.01f, \ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 2b422f9aebf..f3e56ba7039 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -22,6 +22,7 @@ struct wmTimer; #include "DNA_movieclip_types.h" #include "DNA_object_types.h" #include "DNA_view3d_enums.h" +#include "DNA_viewer_path_types.h" #ifdef __cplusplus extern "C" { @@ -205,6 +206,7 @@ typedef struct View3DOverlay { float weight_paint_mode_opacity; float sculpt_mode_mask_opacity; float sculpt_mode_face_sets_opacity; + float viewer_attribute_opacity; /** Armature edit/pose mode settings. */ float xray_alpha_bone; @@ -227,8 +229,6 @@ typedef struct View3DOverlay { float gpencil_vertex_paint_opacity; /** Handles display type for curves. */ int handle_display; - - char _pad[4]; } View3DOverlay; /** #View3DOverlay.handle_display */ @@ -348,6 +348,9 @@ typedef struct View3D { View3DShading shading; View3DOverlay overlay; + /** Path to the viewer node that is currently previewed. This is retrieved from the workspace. */ + ViewerPath viewer_path; + /** Runtime evaluation data (keep last). */ View3D_Runtime runtime; } View3D; @@ -443,7 +446,7 @@ enum { /** #View3D.flag2 (int) */ #define V3D_HIDE_OVERLAYS (1 << 2) -#define V3D_FLAG2_UNUSED_3 (1 << 3) /* cleared */ +#define V3D_SHOW_VIEWER (1 << 3) #define V3D_SHOW_ANNOTATION (1 << 4) #define V3D_LOCK_CAMERA (1 << 5) #define V3D_FLAG2_UNUSED_6 (1 << 6) /* cleared */ @@ -528,6 +531,7 @@ enum { V3D_OVERLAY_HIDE_OBJECT_ORIGINS = (1 << 10), V3D_OVERLAY_STATS = (1 << 11), V3D_OVERLAY_FADE_INACTIVE = (1 << 12), + V3D_OVERLAY_VIEWER_ATTRIBUTE = (1 << 13), }; /** #View3DOverlay.edit_flag */ diff --git a/source/blender/makesdna/DNA_viewer_path_types.h b/source/blender/makesdna/DNA_viewer_path_types.h new file mode 100644 index 00000000000..8f470b66ca0 --- /dev/null +++ b/source/blender/makesdna/DNA_viewer_path_types.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "BLI_listbase.h" +#include "BLI_utildefines.h" + +struct ID; + +typedef enum ViewerPathElemType { + VIEWER_PATH_ELEM_TYPE_ID = 0, + VIEWER_PATH_ELEM_TYPE_MODIFIER = 1, + VIEWER_PATH_ELEM_TYPE_NODE = 2, +} ViewerPathElemType; + +typedef struct ViewerPathElem { + struct ViewerPathElem *next, *prev; + int type; + char _pad[4]; +} ViewerPathElem; + +typedef struct IDViewerPathElem { + ViewerPathElem base; + struct ID *id; +} IDViewerPathElem; + +typedef struct ModifierViewerPathElem { + ViewerPathElem base; + char *modifier_name; +} ModifierViewerPathElem; + +typedef struct NodeViewerPathElem { + ViewerPathElem base; + char *node_name; +} NodeViewerPathElem; + +typedef struct ViewerPath { + /** List of #ViewerPathElem. */ + ListBase path; +} ViewerPath; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index 1a6e19c31ad..e99f317f057 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -10,6 +10,7 @@ #include "DNA_ID.h" #include "DNA_asset_types.h" +#include "DNA_viewer_path_types.h" #ifdef __cplusplus extern "C" { @@ -143,6 +144,13 @@ typedef struct WorkSpace { /** Workspace-wide active asset library, for asset UIs to use (e.g. asset view UI template). The * Asset Browser has its own and doesn't use this. */ AssetLibraryReference asset_library_ref; + + /** + * Ground truth for the currently active viewer node. When a viewer node is activated its path is + * set here. Editors can check here for which node is active (currently the node editor, + * spreadsheet and viewport do this). + */ + ViewerPath viewer_path; } WorkSpace; /** diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index f83ec0dc09b..e6b1ea1321c 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -38,6 +38,13 @@ # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" +static void rna_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + + DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); +} + static void rna_Armature_update_data(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { ID *id = ptr->owner_id; @@ -1365,6 +1372,7 @@ static void rna_def_armature_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Bone", "Armature's active bone"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Armature_act_bone_set", NULL, NULL); + RNA_def_property_update(prop, 0, "rna_Armature_update"); /* TODO: redraw. */ /* RNA_def_property_collection_active(prop, prop_act); */ @@ -1389,7 +1397,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_pointer_sdna(prop, NULL, "act_edbone"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active EditBone", "Armatures active edit bone"); - // RNA_def_property_update(prop, 0, "rna_Armature_act_editbone_update"); + RNA_def_property_update(prop, 0, "rna_Armature_update"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Armature_act_edit_bone_set", NULL, NULL); /* TODO: redraw. */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index a50264e64db..3c9590ddcbe 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -92,6 +92,19 @@ static const EnumPropertyItem rna_enum_brush_texture_slot_map_texture_mode_items #endif /* clang-format off */ +/* Note: we don't actually turn these into a single enum bitmask property, + * instead we construct individual boolean properties. */ +const EnumPropertyItem RNA_automasking_flags[] = { + {BRUSH_AUTOMASKING_TOPOLOGY, "use_automasking_topology", 0,"Topology", "Affect only vertices connected to the active vertex under the brush"}, + {BRUSH_AUTOMASKING_FACE_SETS, "use_automasking_face_sets", 0,"Face Sets", "Affect only vertices that share Face Sets with the active vertex"}, + {BRUSH_AUTOMASKING_BOUNDARY_EDGES, "use_automasking_boundary_edges", 0,"Mesh Boundary Auto-Masking", "Do not affect non manifold boundary edges"}, + {BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS, "use_automasking_boundary_face_sets", 0,"Face Sets Boundary Automasking", "Do not affect vertices that belong to a Face Set boundary"}, + {BRUSH_AUTOMASKING_CAVITY_NORMAL, "use_automasking_cavity", 0,"Cavity Mask", "Do not affect vertices on peaks, based on the surface curvature"}, + {BRUSH_AUTOMASKING_CAVITY_INVERTED, "use_automasking_cavity_inverted", 0,"Inverted Cavity Mask", "Do not affect vertices within crevices, based on the surface curvature"}, + {BRUSH_AUTOMASKING_CAVITY_USE_CURVE, "use_automasking_custom_cavity_curve", 0,"Custom Cavity Curve", "Use custom curve"}, + {0, NULL, 0, NULL, NULL} +}; + const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_DRAW, "DRAW", ICON_BRUSH_SCULPT_DRAW, "Draw", ""}, {SCULPT_TOOL_DRAW_SHARP, "DRAW_SHARP", ICON_BRUSH_SCULPT_DRAW, "Draw Sharp", ""}, @@ -1084,6 +1097,32 @@ static const EnumPropertyItem *rna_BrushTextureSlot_map_mode_itemf(bContext *C, # undef rna_enum_brush_texture_slot_map_sculpt_mode_items } +static void rna_Brush_automasking_invert_cavity_set(PointerRNA *ptr, bool val) +{ + Brush *brush = (Brush *)ptr->data; + + if (val) { + brush->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_NORMAL; + brush->automasking_flags |= BRUSH_AUTOMASKING_CAVITY_INVERTED; + } + else { + brush->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_INVERTED; + } +} + +static void rna_Brush_automasking_cavity_set(PointerRNA *ptr, bool val) +{ + Brush *brush = (Brush *)ptr->data; + + if (val) { + brush->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_INVERTED; + brush->automasking_flags |= BRUSH_AUTOMASKING_CAVITY_NORMAL; + } + else { + brush->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_NORMAL; + } +} + #else static void rna_def_brush_texture_slot(BlenderRNA *brna) @@ -1927,7 +1966,14 @@ static void rna_def_gpencil_options(BlenderRNA *brna) prop = RNA_def_property(srna, "show_fill_extend", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_EXTENDLINES); RNA_def_property_boolean_default(prop, true); - RNA_def_property_ui_text(prop, "Show Extend Lines", "Show help lines for stroke extension"); + RNA_def_property_ui_text(prop, "Visual Aids", "Show help lines for stroke extension"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + + prop = RNA_def_property(srna, "use_collide_strokes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_STROKE_COLLIDE); + RNA_def_property_boolean_default(prop, false); + RNA_def_property_ui_text( + prop, "Strokes Collision", "Check if extend lines collide with strokes"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); prop = RNA_def_property(srna, "show_fill", PROP_BOOLEAN, PROP_NONE); @@ -3178,32 +3224,65 @@ static void rna_def_brush(BlenderRNA *brna) "When locked keep using the plane origin of surface where stroke was initiated"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY); - RNA_def_property_ui_text(prop, - "Topology Auto-Masking", - "Affect only vertices connected to the active vertex under the brush"); + const EnumPropertyItem *entry = RNA_automasking_flags; + do { + prop = RNA_def_property(srna, entry->identifier, PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", entry->value); + RNA_def_property_ui_text(prop, entry->name, entry->description); + + if (entry->value == BRUSH_AUTOMASKING_CAVITY_NORMAL) { + RNA_def_property_boolean_funcs(prop, NULL, "rna_Brush_automasking_cavity_set"); + } + else if (entry->value == BRUSH_AUTOMASKING_CAVITY_INVERTED) { + RNA_def_property_boolean_funcs(prop, NULL, "rna_Brush_automasking_invert_cavity_set"); + } + + RNA_def_property_update(prop, 0, "rna_Brush_update"); + } while ((++entry)->identifier); + + prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor"); + RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask"); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_range(prop, 0.0f, 5.0f); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_automasking_face_sets", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_FACE_SETS); - RNA_def_property_ui_text(prop, - "Face Sets Auto-Masking", - "Affect only vertices that share Face Sets with the active vertex"); + prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps"); + RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred"); + RNA_def_property_range(prop, 0.0f, 25.0f); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES); + prop = RNA_def_property(srna, "automasking_cavity_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "automasking_cavity_curve"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "use_automasking_start_normal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BRUSH_NORMAL); RNA_def_property_ui_text( - prop, "Mesh Boundary Auto-Masking", "Do not affect non manifold boundary edges"); + prop, + "Area Normal", + "Affect only vertices with a similar normal to where the stroke starts"); RNA_def_property_update(prop, 0, "rna_Brush_update"); - prop = RNA_def_property(srna, "use_automasking_boundary_face_sets", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna( - prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS); - RNA_def_property_ui_text(prop, - "Face Sets Boundary Automasking", - "Do not affect vertices that belong to a Face Set boundary"); + prop = RNA_def_property(srna, "use_automasking_view_normal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_NORMAL); + RNA_def_property_ui_text( + prop, "View Normal", "Affect only vertices with a normal that faces the viewer"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + + prop = RNA_def_property(srna, "use_automasking_view_occlusion", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_OCCLUSION); + RNA_def_property_ui_text( + prop, + "Occlusion", + "Only affect vertices that are not occluded by other faces. (Slower performance)"); RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index a66a347f905..370ccaf9f64 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -916,8 +916,8 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN DefRNA.laststruct = srna; if (srnafrom) { - /* copy from struct to derive stuff, a bit clumsy since we can't - * use MEM_dupallocN, data structs may not be alloced but builtin */ + /* Copy from struct to derive stuff, a bit clumsy since we can't + * use #MEM_dupallocN, data structs may not be allocated but builtin. */ memcpy(srna, srnafrom, sizeof(StructRNA)); srna->cont.prophash = NULL; BLI_listbase_clear(&srna->cont.properties); diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index eb39492c7dc..db5b3c33c59 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -61,6 +61,14 @@ void **rna_DepsgraphIterator_instance(PointerRNA *ptr) } # endif +/* Temporary hack for Cycles until it is changed to work with the C API directly. */ +DupliObject *rna_hack_DepsgraphObjectInstance_dupli_object_get(PointerRNA *ptr) +{ + RNA_DepsgraphIterator *di = ptr->data; + DEGObjectIterData *deg_iter = (DEGObjectIterData *)di->iter.data; + return deg_iter->dupli_object_current; +} + static PointerRNA rna_DepsgraphObjectInstance_object_get(PointerRNA *ptr) { RNA_DepsgraphIterator *di = ptr->data; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index ae8208ed0d8..bbc7ce0d896 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -1812,7 +1812,7 @@ static void rna_def_modifier_gpenciltime(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); prop = RNA_def_property(srna, "seg_repeat", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 0, INT16_MAX); + RNA_def_property_range(prop, 1, INT16_MAX); RNA_def_property_ui_text(prop, "Repeat", "Number of cycle repeats"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 3d5c1810558..8e652753ec0 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -24,7 +24,7 @@ struct AssetLibraryReference; struct FreestyleSettings; struct ID; struct IDOverrideLibrary; -struct IDOverrideLibraryPropertyOperation; +struct IDOverrideLibraryenOperation; struct IDProperty; struct Main; struct Object; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bdf68dea67b..4ec2799186e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -10803,6 +10803,12 @@ static void def_geo_viewer(StructRNA *srna) RNA_def_property_enum_default(prop, CD_PROP_FLOAT); RNA_def_property_ui_text(prop, "Data Type", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update"); + + prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_enum_attribute_domain_with_auto_items); + RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); + RNA_def_property_ui_text(prop, "Domain", "Domain to evaluate the field on"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } static void def_geo_realize_instances(StructRNA *srna) @@ -12663,6 +12669,7 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_property_int_funcs( prop, "rna_NodeTree_active_input_get", "rna_NodeTree_active_input_set", NULL); RNA_def_property_ui_text(prop, "Active Input", "Index of the active input"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_NODE, NULL); prop = RNA_def_property(srna, "outputs", PROP_COLLECTION, PROP_NONE); @@ -12676,6 +12683,7 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_property_int_funcs( prop, "rna_NodeTree_active_output_get", "rna_NodeTree_active_output_set", NULL); RNA_def_property_ui_text(prop, "Active Output", "Index of the active output"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_NODE, NULL); /* exposed as a function for runtime interface type properties */ diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 57f0ec720d9..20b691ad88c 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -3428,7 +3428,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Loop Count", "Number of times the keys are looped"); RNA_def_property_update(prop, 0, "rna_Particle_redo"); - /* modified dm support */ + /* Evaluated mesh support. */ prop = RNA_def_property(srna, "use_modifier_stack", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_modifier_stack", 0); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index a4298c8c3aa..d8ad3d1f41e 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -9,6 +9,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -33,6 +34,8 @@ #include "bmesh.h" +extern const EnumPropertyItem RNA_automasking_flags[]; + const EnumPropertyItem rna_enum_particle_edit_hair_brush_items[] = { {PE_BRUSH_COMB, "COMB", 0, "Comb", "Comb hairs"}, {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth hairs"}, @@ -598,6 +601,31 @@ static char *rna_GPencilSculptGuide_path(const PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.gpencil_sculpt.guide"); } +static void rna_Sculpt_automasking_invert_cavity_set(PointerRNA *ptr, bool val) +{ + Sculpt *sd = (Sculpt *)ptr->data; + + if (val) { + sd->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_NORMAL; + sd->automasking_flags |= BRUSH_AUTOMASKING_CAVITY_INVERTED; + } + else { + sd->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_INVERTED; + } +} + +static void rna_Sculpt_automasking_cavity_set(PointerRNA *ptr, bool val) +{ + Sculpt *sd = (Sculpt *)ptr->data; + + if (val) { + sd->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_INVERTED; + sd->automasking_flags |= BRUSH_AUTOMASKING_CAVITY_NORMAL; + } + else { + sd->automasking_flags &= ~BRUSH_AUTOMASKING_CAVITY_NORMAL; + } +} #else static void rna_def_paint_curve(BlenderRNA *brna) @@ -883,32 +911,95 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Sculpt_update"); - prop = RNA_def_property(srna, "use_automasking_topology", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_TOPOLOGY); - RNA_def_property_ui_text(prop, - "Topology Auto-Masking", - "Affect only vertices connected to the active vertex under the brush"); + const EnumPropertyItem *entry = RNA_automasking_flags; + do { + prop = RNA_def_property(srna, entry->identifier, PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", entry->value); + RNA_def_property_ui_text(prop, entry->name, entry->description); + + if (entry->value == BRUSH_AUTOMASKING_CAVITY_NORMAL) { + RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_cavity_set"); + } + else if (entry->value == BRUSH_AUTOMASKING_CAVITY_INVERTED) { + RNA_def_property_boolean_funcs(prop, NULL, "rna_Sculpt_automasking_invert_cavity_set"); + } + + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + } while ((++entry)->identifier); + + prop = RNA_def_property(srna, "automasking_cavity_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "automasking_cavity_factor"); + RNA_def_property_ui_text(prop, "Cavity Factor", "The contrast of the cavity mask"); + RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); + RNA_def_property_range(prop, 0.0f, 5.0f); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "use_automasking_face_sets", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_FACE_SETS); - RNA_def_property_ui_text(prop, - "Face Sets Auto-Masking", - "Affect only vertices that share Face Sets with the active vertex"); + prop = RNA_def_property(srna, "automasking_cavity_blur_steps", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "automasking_cavity_blur_steps"); + RNA_def_property_ui_text(prop, "Blur Steps", "The number of times the cavity mask is blurred"); + RNA_def_property_range(prop, 0.0f, 25.0f); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "use_automasking_boundary_edges", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_EDGES); + prop = RNA_def_property(srna, "automasking_cavity_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "automasking_cavity_curve"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_cavity_curve_op", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "automasking_cavity_curve_op"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Cavity Curve", "Curve used for the sensitivity"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_start_normal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BRUSH_NORMAL); RNA_def_property_ui_text( - prop, "Mesh Boundary Auto-Masking", "Do not affect non manifold boundary edges"); + prop, + "Area Normal", + "Affect only vertices with a similar normal to where the stroke starts"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "use_automasking_boundary_face_sets", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna( - prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS); - RNA_def_property_ui_text(prop, - "Face Sets Boundary Auto-Masking", - "Do not affect vertices that belong to a Face Set boundary"); + prop = RNA_def_property(srna, "use_automasking_view_normal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_NORMAL); + RNA_def_property_ui_text( + prop, "View Normal", "Affect only vertices with a normal that faces the viewer"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "use_automasking_view_occlusion", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "automasking_flags", BRUSH_AUTOMASKING_VIEW_OCCLUSION); + RNA_def_property_ui_text( + prop, + "Occlusion", + "Only affect vertices that are not occluded by other faces. (Slower performance)"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_start_normal_limit", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "automasking_start_normal_limit"); + RNA_def_property_range(prop, 0.0001f, M_PI); + RNA_def_property_ui_text(prop, "Area Normal Limit", "The range of angles that will be affected"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_start_normal_falloff", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "automasking_start_normal_falloff"); + RNA_def_property_range(prop, 0.0001f, 1.0f); + RNA_def_property_ui_text( + prop, "Area Normal Falloff", "Extend the angular range with a falloff gradient"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_view_normal_limit", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "automasking_view_normal_limit"); + RNA_def_property_range(prop, 0.0001f, M_PI); + RNA_def_property_ui_text(prop, "View Normal Limit", "The range of angles that will be affected"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "automasking_view_normal_falloff", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "automasking_view_normal_falloff"); + RNA_def_property_range(prop, 0.0001f, 1.0f); + RNA_def_property_ui_text( + prop, "View Normal Falloff", "Extend the angular range with a falloff gradient"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "symmetrize_direction", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 9bbe37b5187..738b41828e0 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -19,6 +19,7 @@ #include "BKE_movieclip.h" #include "BKE_node.h" #include "BKE_studiolight.h" +#include "BKE_viewer_path.h" #include "ED_asset.h" #include "ED_spreadsheet.h" @@ -3279,59 +3280,21 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UN return item_array; } -static SpreadsheetContext *rna_SpaceSpreadsheet_context_path_append(SpaceSpreadsheet *sspreadsheet, - int type) +static StructRNA *rna_viewer_path_elem_refine(PointerRNA *ptr) { - SpreadsheetContext *context = ED_spreadsheet_context_new(type); - BLI_addtail(&sspreadsheet->context_path, context); - ED_spreadsheet_context_path_update_tag(sspreadsheet); - WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL); - return context; -} - -static void rna_SpaceSpreadsheet_context_path_clear(SpaceSpreadsheet *sspreadsheet) -{ - ED_spreadsheet_context_path_clear(sspreadsheet); - ED_spreadsheet_context_path_update_tag(sspreadsheet); - WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL); -} - -static StructRNA *rna_spreadsheet_context_refine(PointerRNA *ptr) -{ - SpreadsheetContext *context = ptr->data; - switch (context->type) { - case SPREADSHEET_CONTEXT_OBJECT: - return &RNA_SpreadsheetContextObject; - case SPREADSHEET_CONTEXT_MODIFIER: - return &RNA_SpreadsheetContextModifier; - case SPREADSHEET_CONTEXT_NODE: - return &RNA_SpreadsheetContextNode; + ViewerPathElem *elem = ptr->data; + switch (elem->type) { + case VIEWER_PATH_ELEM_TYPE_ID: + return &RNA_IDViewerPathElem; + case VIEWER_PATH_ELEM_TYPE_MODIFIER: + return &RNA_ModifierViewerPathElem; + case VIEWER_PATH_ELEM_TYPE_NODE: + return &RNA_NodeViewerPathElem; } BLI_assert_unreachable(); return NULL; } -static void rna_spreadsheet_context_update(Main *UNUSED(bmain), - Scene *UNUSED(scene), - PointerRNA *ptr) -{ - bScreen *screen = (bScreen *)ptr->owner_id; - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = area->spacedata.first; - if (sl->spacetype == SPACE_SPREADSHEET) { - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - ED_spreadsheet_context_path_update_tag(sspreadsheet); - } - } -} - -static void rna_SpaceSpreadsheet_context_path_guess(SpaceSpreadsheet *sspreadsheet, bContext *C) -{ - ED_spreadsheet_context_path_guess(C, sspreadsheet); - ED_spreadsheet_context_path_update_tag(sspreadsheet); - WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL); -} - static void rna_FileAssetSelectParams_catalog_id_get(PointerRNA *ptr, char *value) { const FileAssetSelectParams *params = ptr->data; @@ -4456,6 +4419,20 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_viewer_attribute", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_VIEWER_ATTRIBUTE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Viewer Node", "Show attribute overlay for active viewer node"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "viewer_attribute_opacity", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "overlay.viewer_attribute_opacity"); + RNA_def_property_ui_text( + prop, "Viewer Attribute Opacity", "Opacity of the attribute that is currently visualized"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_paint_wire", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "overlay.paint_flag", V3D_OVERLAY_PAINT_WIRE); RNA_def_property_ui_text(prop, "Show Wire", "Use wireframe display in painting modes"); @@ -5107,6 +5084,11 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Visibility Icon", ""); + prop = RNA_def_property(srna, "show_viewer", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_VIEWER); + RNA_def_property_ui_text(prop, "Show Viewer", "Display non-final geometry from viewer nodes"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D | NS_VIEW3D_SHADING, NULL); + /* Nested Structs */ prop = RNA_def_property(srna, "shading", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -7883,93 +7865,77 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); } -static const EnumPropertyItem spreadsheet_context_type_items[] = { - {SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""}, - {SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""}, - {SPREADSHEET_CONTEXT_NODE, "NODE", ICON_NONE, "Node", ""}, +static const EnumPropertyItem viewer_path_elem_type_items[] = { + {VIEWER_PATH_ELEM_TYPE_ID, "ID", ICON_NONE, "ID", ""}, + {VIEWER_PATH_ELEM_TYPE_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""}, + {VIEWER_PATH_ELEM_TYPE_NODE, "NODE", ICON_NONE, "Node", ""}, {0, NULL, 0, NULL, NULL}, }; -static void rna_def_space_spreadsheet_context(BlenderRNA *brna) +static void rna_def_viewer_path_elem(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "SpreadsheetContext", NULL); - RNA_def_struct_ui_text(srna, "Spreadsheet Context", "Element of spreadsheet context path"); - RNA_def_struct_refine_func(srna, "rna_spreadsheet_context_refine"); + srna = RNA_def_struct(brna, "ViewerPathElem", NULL); + RNA_def_struct_ui_text(srna, "Viewer Path Element", "Element of a viewer path"); + RNA_def_struct_refine_func(srna, "rna_viewer_path_elem_refine"); prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, spreadsheet_context_type_items); - RNA_def_property_ui_text(prop, "Type", "Type of the context"); + RNA_def_property_enum_items(prop, viewer_path_elem_type_items); + RNA_def_property_ui_text(prop, "Type", "Type of the path element"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - - rna_def_space_generic_show_region_toggles(srna, - (1 << RGN_TYPE_CHANNELS) | (1 << RGN_TYPE_FOOTER)); } -static void rna_def_space_spreadsheet_context_object(BlenderRNA *brna) +static void rna_def_id_viewer_path_elem(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "SpreadsheetContextObject", "SpreadsheetContext"); + srna = RNA_def_struct(brna, "IDViewerPathElem", "ViewerPathElem"); - prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "Object"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update"); + prop = RNA_def_property(srna, "id", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "ID", ""); } -static void rna_def_space_spreadsheet_context_modifier(BlenderRNA *brna) +static void rna_def_modifier_viewer_path_elem(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "SpreadsheetContextModifier", "SpreadsheetContext"); + srna = RNA_def_struct(brna, "ModifierViewerPathElem", "ViewerPathElem"); prop = RNA_def_property(srna, "modifier_name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Modifier Name", ""); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update"); } -static void rna_def_space_spreadsheet_context_node(BlenderRNA *brna) +static void rna_def_node_viewer_path_elem(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "SpreadsheetContextNode", "SpreadsheetContext"); + srna = RNA_def_struct(brna, "NodeViewerPathElem", "ViewerPathElem"); prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Node Name", ""); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update"); } -static void rna_def_space_spreadsheet_context_path(BlenderRNA *brna, PropertyRNA *cprop) +static void rna_def_viewer_path(BlenderRNA *brna) { StructRNA *srna; - PropertyRNA *parm; - FunctionRNA *func; - - RNA_def_property_srna(cprop, "SpreadsheetContextPath"); - srna = RNA_def_struct(brna, "SpreadsheetContextPath", NULL); - RNA_def_struct_sdna(srna, "SpaceSpreadsheet"); + PropertyRNA *prop; - func = RNA_def_function(srna, "append", "rna_SpaceSpreadsheet_context_path_append"); - RNA_def_function_ui_description(func, "Append a context path element"); - parm = RNA_def_property(func, "type", PROP_ENUM, PROP_NONE); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_property_enum_items(parm, spreadsheet_context_type_items); - parm = RNA_def_pointer( - func, "context", "SpreadsheetContext", "", "Newly created context path element"); - RNA_def_function_return(func, parm); + rna_def_viewer_path_elem(brna); + rna_def_id_viewer_path_elem(brna); + rna_def_modifier_viewer_path_elem(brna); + rna_def_node_viewer_path_elem(brna); - func = RNA_def_function(srna, "clear", "rna_SpaceSpreadsheet_context_path_clear"); - RNA_def_function_ui_description(func, "Clear entire context path"); + srna = RNA_def_struct(brna, "ViewerPath", NULL); + RNA_def_struct_ui_text(srna, "Viewer Path", "Path to data that is viewed"); - func = RNA_def_function(srna, "guess", "rna_SpaceSpreadsheet_context_path_guess"); - RNA_def_function_ui_description(func, "Guess the context path from the current context"); - RNA_def_function_flag(func, FUNC_USE_CONTEXT); + prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "ViewerPathElem"); + RNA_def_property_ui_text(prop, "Viewer Path", NULL); } static void rna_def_space_spreadsheet(BlenderRNA *brna) @@ -7996,11 +7962,6 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - rna_def_space_spreadsheet_context(brna); - rna_def_space_spreadsheet_context_object(brna); - rna_def_space_spreadsheet_context_modifier(brna); - rna_def_space_spreadsheet_context_node(brna); - srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space"); RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data"); @@ -8017,15 +7978,14 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Filter", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); - prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "display_viewer_path_collapsed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED); RNA_def_property_ui_text(prop, "Display Context Path Collapsed", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL); - prop = RNA_def_property(srna, "context_path", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "SpreadsheetContext"); - RNA_def_property_ui_text(prop, "Context Path", "Context path to the data being displayed"); - rna_def_space_spreadsheet_context_path(brna, prop); + prop = RNA_def_property(srna, "viewer_path", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text( + prop, "Viewer Path", "Path to the data that is displayed in the spreadsheet"); prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY); @@ -8073,6 +8033,7 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna) void RNA_def_space(BlenderRNA *brna) { rna_def_space(brna); + rna_def_viewer_path(brna); rna_def_space_image(brna); rna_def_space_sequencer(brna); rna_def_space_text(brna); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 8bace2e048c..90ae3c8093c 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -43,7 +43,7 @@ set(SRC intern/MOD_collision.c intern/MOD_correctivesmooth.c intern/MOD_curve.c - intern/MOD_datatransfer.c + intern/MOD_datatransfer.cc intern/MOD_decimate.c intern/MOD_displace.c intern/MOD_dynamicpaint.c @@ -66,7 +66,7 @@ set(SRC intern/MOD_multires.c intern/MOD_nodes.cc intern/MOD_none.c - intern/MOD_normal_edit.c + intern/MOD_normal_edit.cc intern/MOD_ocean.c intern/MOD_particleinstance.c intern/MOD_particlesystem.cc @@ -81,7 +81,7 @@ set(SRC intern/MOD_solidify.c intern/MOD_solidify_extrude.c intern/MOD_solidify_nonmanifold.c - intern/MOD_subsurf.c + intern/MOD_subsurf.cc intern/MOD_surface.c intern/MOD_surfacedeform.c intern/MOD_triangulate.c @@ -92,7 +92,7 @@ set(SRC intern/MOD_volume_displace.cc intern/MOD_volume_to_mesh.cc intern/MOD_warp.c - intern/MOD_wave.c + intern/MOD_wave.cc intern/MOD_weighted_normal.c intern/MOD_weightvg_util.c intern/MOD_weightvgedit.c diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 4576ac68413..70d6cb9ff76 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -79,7 +79,7 @@ extern ModifierTypeInfo modifierType_VolumeToMesh; /* MOD_util.c */ /** - * Only called by `BKE_modifier.h/modifier.c` + * Only called by `BKE_modifier.h/modifier.cc` */ void modifier_type_init(ModifierTypeInfo *types[]); diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.cc index ca5a79469b3..5a407065a35 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.cc @@ -50,7 +50,7 @@ static void initData(ModifierData *md) DataTransferModifierData *dtmd = (DataTransferModifierData *)md; int i; - dtmd->ob_source = NULL; + dtmd->ob_source = nullptr; dtmd->data_types = 0; dtmd->vmap_mode = MREMAP_MODE_VERT_NEAREST; @@ -115,7 +115,7 @@ static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *u static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx) { DataTransferModifierData *dtmd = (DataTransferModifierData *)md; - if (dtmd->ob_source != NULL) { + if (dtmd->ob_source != nullptr) { CustomData_MeshMasks cddata_masks = {0}; BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks); BKE_mesh_remap_calc_source_cddata_masks_from_map_modes( @@ -159,7 +159,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * ReportList reports; /* Only used to check whether we are operating on org data or not... */ - Mesh *me = ctx->object->data; + const Mesh *me = static_cast<const Mesh *>(ctx->object->data); Object *ob_source = dtmd->ob_source; @@ -171,7 +171,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * SpaceTransform space_transform_data; SpaceTransform *space_transform = (dtmd->flags & MOD_DATATRANSFER_OBSRC_TRANSFORM) ? &space_transform_data : - NULL; + nullptr; if (space_transform) { BLI_SPACE_TRANSFORM_SETUP(space_transform, ctx->object, ob_source); @@ -186,7 +186,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * (dtmd->data_types & DT_TYPES_AFFECT_MESH)) { /* We need to duplicate data here, otherwise setting custom normals, edges' sharpness, etc., * could modify org mesh, see T43671. */ - result = (Mesh *)BKE_id_copy_ex(NULL, &me_mod->id, NULL, LIB_ID_COPY_LOCALIZE); + result = (Mesh *)BKE_id_copy_ex(nullptr, &me_mod->id, nullptr, LIB_ID_COPY_LOCALIZE); } BKE_reports_init(&reports, RPT_STORE); @@ -247,7 +247,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropDecorate(sub, false); uiItemR(sub, ptr, "use_object_transform", 0, "", ICON_ORIENTATION_GLOBAL); - uiItemR(layout, ptr, "mix_mode", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mix_mode", 0, nullptr, ICON_NONE); row = uiLayoutRow(layout, false); uiLayoutSetActive(row, @@ -255,9 +255,9 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)); - uiItemR(row, ptr, "mix_factor", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "mix_factor", 0, nullptr, ICON_NONE); - modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr); uiItemO(layout, IFACE_("Generate Data Layers"), ICON_NONE, "OBJECT_OT_datalayout_transfer"); @@ -266,22 +266,22 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) static void vertex_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayout *layout = panel->layout; - uiItemR(layout, ptr, "use_vert_data", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_vert_data", 0, nullptr, ICON_NONE); } static void vertex_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); bool use_vert_data = RNA_boolean_get(ptr, "use_vert_data"); uiLayoutSetActive(layout, use_vert_data); - uiItemR(layout, ptr, "data_types_verts", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "data_types_verts", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -292,7 +292,7 @@ static void vertex_vgroup_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetActive(layout, RNA_enum_get(ptr, "data_types_verts") & DT_TYPE_MDEFORMVERT); @@ -306,20 +306,20 @@ static void edge_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); - uiItemR(layout, ptr, "use_edge_data", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_edge_data", 0, nullptr, ICON_NONE); } static void edge_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_edge_data")); - uiItemR(layout, ptr, "data_types_edges", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "data_types_edges", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -330,20 +330,20 @@ static void face_corner_panel_draw_header(const bContext *UNUSED(C), Panel *pane { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); - uiItemR(layout, ptr, "use_loop_data", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_loop_data", 0, nullptr, ICON_NONE); } static void face_corner_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_loop_data")); - uiItemR(layout, ptr, "data_types_loops", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "data_types_loops", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -354,7 +354,7 @@ static void vert_vcol_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -370,7 +370,7 @@ static void face_corner_vcol_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -386,7 +386,7 @@ static void face_corner_uv_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -394,27 +394,27 @@ static void face_corner_uv_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "layers_uv_select_src", 0, IFACE_("Layer Selection"), ICON_NONE); uiItemR(layout, ptr, "layers_uv_select_dst", 0, IFACE_("Layer Mapping"), ICON_NONE); - uiItemR(layout, ptr, "islands_precision", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "islands_precision", 0, nullptr, ICON_NONE); } static void face_panel_draw_header(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); - uiItemR(layout, ptr, "use_poly_data", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_poly_data", 0, nullptr, ICON_NONE); } static void face_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetActive(layout, RNA_boolean_get(ptr, "use_poly_data")); - uiItemR(layout, ptr, "data_types_polys", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "data_types_polys", 0, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -426,7 +426,7 @@ static void advanced_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayout *row, *sub; uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -436,7 +436,7 @@ static void advanced_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_distance")); uiItemR(sub, ptr, "max_distance", 0, "", ICON_NONE); - uiItemR(layout, ptr, "ray_radius", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "ray_radius", 0, nullptr, ICON_NONE); } static void panelRegister(ARegionType *region_type) @@ -445,11 +445,15 @@ static void panelRegister(ARegionType *region_type) region_type, eModifierType_DataTransfer, panel_draw); PanelType *vertex_panel = modifier_subpanel_register( region_type, "vertex", "", vertex_panel_draw_header, vertex_panel_draw, panel_type); - modifier_subpanel_register( - region_type, "vertex_vgroup", "Vertex Groups", NULL, vertex_vgroup_panel_draw, vertex_panel); + modifier_subpanel_register(region_type, + "vertex_vgroup", + "Vertex Groups", + nullptr, + vertex_vgroup_panel_draw, + vertex_panel); modifier_subpanel_register( - region_type, "vert_vcol", "Colors", NULL, vert_vcol_panel_draw, vertex_panel); + region_type, "vert_vcol", "Colors", nullptr, vert_vcol_panel_draw, vertex_panel); modifier_subpanel_register( region_type, "edge", "", edge_panel_draw_header, edge_panel_draw, panel_type); @@ -463,16 +467,16 @@ static void panelRegister(ARegionType *region_type) modifier_subpanel_register(region_type, "face_corner_vcol", "Colors", - NULL, + nullptr, face_corner_vcol_panel_draw, face_corner_panel); modifier_subpanel_register( - region_type, "face_corner_uv", "UVs", NULL, face_corner_uv_panel_draw, face_corner_panel); + region_type, "face_corner_uv", "UVs", nullptr, face_corner_uv_panel_draw, face_corner_panel); modifier_subpanel_register( region_type, "face", "", face_panel_draw_header, face_panel_draw, panel_type); modifier_subpanel_register( - region_type, "advanced", "Topology Mapping", NULL, advanced_panel_draw, panel_type); + region_type, "advanced", "Topology Mapping", nullptr, advanced_panel_draw, panel_type); } #undef DT_TYPES_AFFECT_MESH @@ -489,24 +493,24 @@ ModifierTypeInfo modifierType_DataTransfer = { /* copyData */ BKE_modifier_copydata_generic, - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, + /* deformVerts */ nullptr, + /* deformMatrices */ nullptr, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyGeometrySet */ NULL, + /* modifyGeometrySet */ nullptr, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, + /* freeData */ nullptr, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, + /* dependsOnTime */ nullptr, /* dependsOnNormals */ dependsOnNormals, /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* foreachTexLink */ nullptr, + /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ nullptr, + /* blendRead */ nullptr, }; diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index 7c5bb988012..ba4c03f68de 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -33,6 +33,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" +#include "DNA_view3d_types.h" #include "DNA_windowmanager_types.h" #include "BKE_attribute_math.hh" @@ -80,6 +81,7 @@ #include "ED_screen.h" #include "ED_spreadsheet.h" #include "ED_undo.h" +#include "ED_viewer_path.hh" #include "NOD_geometry.h" #include "NOD_geometry_nodes_lazy_function.hh" @@ -828,25 +830,6 @@ static void initialize_group_input(NodesModifierData &nmd, } } -static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain) -{ - wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; - if (wm == nullptr) { - return {}; - } - Vector<SpaceSpreadsheet *> spreadsheets; - LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { - bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - SpaceLink *sl = (SpaceLink *)area->spacedata.first; - if (sl->spacetype == SPACE_SPREADSHEET) { - spreadsheets.append((SpaceSpreadsheet *)sl); - } - } - } - return spreadsheets; -} - static const lf::FunctionNode &find_viewer_lf_node(const bNode &viewer_bnode) { return *blender::nodes::ensure_geometry_nodes_lazy_function_graph(viewer_bnode.owner_tree()) @@ -858,50 +841,33 @@ static const lf::FunctionNode &find_group_lf_node(const bNode &group_bnode) ->mapping.group_node_map.lookup(&group_bnode); } -static void find_side_effect_nodes_for_spreadsheet( - const SpaceSpreadsheet &sspreadsheet, +static void find_side_effect_nodes_for_viewer_path( + const ViewerPath &viewer_path, const NodesModifierData &nmd, const ModifierEvalContext &ctx, - const bNodeTree &root_tree, MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes) { - Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path; - if (context_path.size() < 3) { - return; - } - if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return; - } - if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { + const std::optional<blender::ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path = + blender::ed::viewer_path::parse_geometry_nodes_viewer(viewer_path); + if (!parsed_path.has_value()) { return; } - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0]; - if (object_context->object != DEG_get_original_object(ctx.object)) { + if (parsed_path->object != DEG_get_original_object(ctx.object)) { return; } - SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1]; - if (StringRef(modifier_context->modifier_name) != nmd.modifier.name) { + if (parsed_path->modifier_name != nmd.modifier.name) { return; } - for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) { - if (context->type != SPREADSHEET_CONTEXT_NODE) { - return; - } - } blender::ComputeContextBuilder compute_context_builder; - compute_context_builder.push<blender::bke::ModifierComputeContext>(nmd.modifier.name); - - const Span<SpreadsheetContextNode *> nested_group_contexts = - context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>(); - const SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last(); + compute_context_builder.push<blender::bke::ModifierComputeContext>(parsed_path->modifier_name); + const bNodeTree *group = nmd.node_group; Stack<const bNode *> group_node_stack; - const bNodeTree *group = &root_tree; - for (SpreadsheetContextNode *node_context : nested_group_contexts) { + for (const StringRefNull group_node_name : parsed_path->group_node_names) { const bNode *found_node = nullptr; for (const bNode *node : group->group_nodes()) { - if (STREQ(node->name, node_context->node_name)) { + if (node->name == group_node_name) { found_node = node; break; } @@ -913,13 +879,13 @@ static void find_side_effect_nodes_for_spreadsheet( return; } group_node_stack.push(found_node); - group = reinterpret_cast<const bNodeTree *>(found_node->id); - compute_context_builder.push<blender::bke::NodeGroupComputeContext>(node_context->node_name); + group = reinterpret_cast<bNodeTree *>(found_node->id); + compute_context_builder.push<blender::bke::NodeGroupComputeContext>(group_node_name); } const bNode *found_viewer_node = nullptr; for (const bNode *viewer_node : group->nodes_by_type("GeometryNodeViewer")) { - if (STREQ(viewer_node->name, last_context->node_name)) { + if (viewer_node->name == parsed_path->viewer_node_name) { found_viewer_node = viewer_node; break; } @@ -943,16 +909,29 @@ static void find_side_effect_nodes_for_spreadsheet( static void find_side_effect_nodes( const NodesModifierData &nmd, const ModifierEvalContext &ctx, - const bNodeTree &tree, MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> &r_side_effect_nodes) { Main *bmain = DEG_get_bmain(ctx.depsgraph); - - /* Based on every visible spreadsheet context path, get a list of sockets that need to have their - * intermediate geometries cached for display. */ - Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain); - for (SpaceSpreadsheet *sspreadsheet : spreadsheets) { - find_side_effect_nodes_for_spreadsheet(*sspreadsheet, nmd, ctx, tree, r_side_effect_nodes); + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; + if (wm == nullptr) { + return; + } + LISTBASE_FOREACH (const wmWindow *, window, &wm->windows) { + const bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook); + const WorkSpace *workspace = BKE_workspace_active_get(window->workspace_hook); + find_side_effect_nodes_for_viewer_path(workspace->viewer_path, nmd, ctx, r_side_effect_nodes); + LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) { + const SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first); + if (sl->spacetype == SPACE_SPREADSHEET) { + const SpaceSpreadsheet &sspreadsheet = *reinterpret_cast<const SpaceSpreadsheet *>(sl); + find_side_effect_nodes_for_viewer_path( + sspreadsheet.viewer_path, nmd, ctx, r_side_effect_nodes); + } + if (sl->spacetype == SPACE_VIEW3D) { + const View3D &v3d = *reinterpret_cast<const View3D *>(sl); + find_side_effect_nodes_for_viewer_path(v3d.viewer_path, nmd, ctx, r_side_effect_nodes); + } + } } } @@ -1162,7 +1141,7 @@ static GeometrySet compute_geometry( geo_nodes_modifier_data.eval_log = eval_log.get(); } MultiValueMap<blender::ComputeContextHash, const lf::FunctionNode *> r_side_effect_nodes; - find_side_effect_nodes(*nmd, *ctx, btree, r_side_effect_nodes); + find_side_effect_nodes(*nmd, *ctx, r_side_effect_nodes); geo_nodes_modifier_data.side_effect_nodes = &r_side_effect_nodes; blender::nodes::GeoNodesLFUserData user_data; user_data.modifier_data = &geo_nodes_modifier_data; diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.cc index d7de1dc3326..e707130a832 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -47,13 +47,14 @@ static void generate_vert_coordinates(Mesh *mesh, float (*r_cos)[3], float r_size[3]) { + using namespace blender; float min_co[3], max_co[3]; float diff[3]; bool do_diff = false; INIT_MINMAX(min_co, max_co); - const float(*positions)[3] = BKE_mesh_positions(mesh); + const Span<float3> positions = mesh->positions(); for (int i = 0; i < mesh->totvert; i++) { copy_v3_v3(r_cos[i], positions[i]); if (r_size != NULL && ob_center == NULL) { @@ -63,8 +64,8 @@ static void generate_vert_coordinates(Mesh *mesh, /* Get size (i.e. deformation of the spheroid generating normals), * either from target object, or own geometry. */ - if (r_size != NULL) { - if (ob_center != NULL) { + if (r_size != nullptr) { + if (ob_center != nullptr) { /* Using 'scale' as 'size' here. The input object is typically an empty * who's scale is used to define an ellipsoid instead of a simple sphere. */ @@ -88,7 +89,7 @@ static void generate_vert_coordinates(Mesh *mesh, } } - if (ob_center != NULL) { + if (ob_center != nullptr) { float inv_obmat[4][4]; /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */ @@ -100,7 +101,7 @@ static void generate_vert_coordinates(Mesh *mesh, do_diff = true; } - else if (offset != NULL && !is_zero_v3(offset)) { + else if (offset != nullptr && !is_zero_v3(offset)) { negate_v3_v3(diff, offset); do_diff = true; @@ -129,12 +130,12 @@ static void mix_normals(const float mix_factor, const int loops_num) { /* Mix with org normals... */ - float *facs = NULL, *wfac; + float *facs = nullptr, *wfac; float(*no_new)[3], (*no_old)[3]; int i; if (dvert) { - facs = MEM_malloc_arrayN((size_t)loops_num, sizeof(*facs), __func__); + facs = static_cast<float *>(MEM_malloc_arrayN(size_t(loops_num), sizeof(*facs), __func__)); BKE_defvert_extract_vgroup_to_loopweights( dvert, defgrp_index, verts_num, mloop, loops_num, use_invert_vgroup, facs); } @@ -164,7 +165,7 @@ static void mix_normals(const float mix_factor, *no_new, *no_old, *no_new, - (mix_limit < (float)M_PI) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); + (mix_limit < float(M_PI)) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac); } MEM_SAFE_FREE(facs); @@ -180,7 +181,7 @@ static bool polygons_check_flip(MLoop *mloop, const int polys_num) { const MPoly *mp; - MDisps *mdisp = CustomData_get_layer(ldata, CD_MDISPS); + MDisps *mdisp = static_cast<MDisps *>(CustomData_get_layer(ldata, CD_MDISPS)); int i; bool flipped = false; @@ -235,11 +236,13 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; int i; - float(*cos)[3] = MEM_malloc_arrayN((size_t)verts_num, sizeof(*cos), __func__); - float(*nos)[3] = MEM_malloc_arrayN((size_t)loops_num, sizeof(*nos), __func__); + float(*cos)[3] = static_cast<float(*)[3]>( + MEM_malloc_arrayN(size_t(verts_num), sizeof(*cos), __func__)); + float(*nos)[3] = static_cast<float(*)[3]>( + MEM_malloc_arrayN(size_t(loops_num), sizeof(*nos), __func__)); float size[3]; - BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)verts_num, __func__); + BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(verts_num), __func__); generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, verts_num, cos, size); @@ -372,7 +375,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; - float(*nos)[3] = MEM_malloc_arrayN((size_t)loops_num, sizeof(*nos), __func__); + float(*nos)[3] = static_cast<float(*)[3]>( + MEM_malloc_arrayN(size_t(loops_num), sizeof(*nos), __func__)); float target_co[3]; int i; @@ -395,10 +399,11 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, } } else { - float(*cos)[3] = MEM_malloc_arrayN((size_t)verts_num, sizeof(*cos), __func__); - generate_vert_coordinates(mesh, ob, ob_target, NULL, verts_num, cos, NULL); + float(*cos)[3] = static_cast<float(*)[3]>( + MEM_malloc_arrayN(size_t(verts_num), sizeof(*cos), __func__)); + generate_vert_coordinates(mesh, ob, ob_target, nullptr, verts_num, cos, nullptr); - BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)verts_num, __func__); + BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(verts_num), __func__); const MLoop *ml; float(*no)[3]; @@ -485,7 +490,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0); const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) && (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') && - (enmd->mix_limit == (float)M_PI)); + (enmd->mix_limit == float(M_PI))); /* Do not run that modifier at all if autosmooth is disabled! */ if (!is_valid_target_with_error(ctx->object, enmd) || mesh->totloop == 0) { @@ -513,7 +518,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, /* We need to duplicate data here, otherwise setting custom normals * (which may also affect sharp edges) could * modify original mesh, see T43671. */ - result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE); + result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE); } else { result = mesh; @@ -531,17 +536,19 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, int defgrp_index; const MDeformVert *dvert; - float(*loopnors)[3] = NULL; + float(*loopnors)[3] = nullptr; CustomData *ldata = &result->ldata; const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(result); const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(result); - short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL); + short(*clnors)[2] = static_cast<short(*)[2]>(CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL)); if (use_current_clnors) { - clnors = CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, loops_num); - loopnors = MEM_malloc_arrayN((size_t)loops_num, sizeof(*loopnors), __func__); + clnors = static_cast<short(*)[2]>( + CustomData_duplicate_referenced_layer(ldata, CD_CUSTOMLOOPNORMAL, loops_num)); + loopnors = static_cast<float(*)[3]>( + MEM_malloc_arrayN(size_t(loops_num), sizeof(*loopnors), __func__)); BKE_mesh_normals_loop_split(positions, vert_normals, @@ -556,13 +563,14 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, polys_num, true, result->smoothresh, - NULL, + nullptr, clnors, - NULL); + nullptr); } - if (clnors == NULL) { - clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, loops_num); + if (clnors == nullptr) { + clnors = static_cast<short(*)[2]>( + CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops_num)); } MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); @@ -687,15 +695,15 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) int mode = RNA_enum_get(ptr, "mode"); - uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); - uiItemR(layout, ptr, "target", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "target", 0, nullptr, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, mode == MOD_NORMALEDIT_MODE_DIRECTIONAL); - uiItemR(col, ptr, "use_direction_parallel", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_direction_parallel", 0, nullptr, ICON_NONE); modifier_panel_end(layout, ptr); } @@ -711,13 +719,13 @@ static void mix_mode_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); - uiItemR(layout, ptr, "mix_mode", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "mix_factor", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mix_mode", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "mix_factor", 0, nullptr, ICON_NONE); - modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "mix_limit", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "mix_limit", 0, nullptr, ICON_NONE); uiItemR(row, ptr, "no_polynors_fix", @@ -730,7 +738,7 @@ static void offset_panel_draw(const bContext *UNUSED(C), Panel *panel) { uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); int mode = RNA_enum_get(ptr, "mode"); PointerRNA target_ptr = RNA_pointer_get(ptr, "target"); @@ -742,15 +750,16 @@ static void offset_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); uiLayoutSetActive(layout, needs_object_offset); - uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "offset", 0, nullptr, ICON_NONE); } static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register( region_type, eModifierType_NormalEdit, panel_draw); - modifier_subpanel_register(region_type, "mix", "Mix", NULL, mix_mode_panel_draw, panel_type); - modifier_subpanel_register(region_type, "offset", "Offset", NULL, offset_panel_draw, panel_type); + modifier_subpanel_register(region_type, "mix", "Mix", nullptr, mix_mode_panel_draw, panel_type); + modifier_subpanel_register( + region_type, "offset", "Offset", nullptr, offset_panel_draw, panel_type); } ModifierTypeInfo modifierType_NormalEdit = { @@ -765,24 +774,24 @@ ModifierTypeInfo modifierType_NormalEdit = { /* copyData */ BKE_modifier_copydata_generic, - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, + /* deformVerts */ nullptr, + /* deformMatrices */ nullptr, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyGeometrySet */ NULL, + /* modifyGeometrySet */ nullptr, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, + /* freeData */ nullptr, /* isDisabled */ isDisabled, /* updateDepsgraph */ updateDepsgraph, - /* dependsOnTime */ NULL, + /* dependsOnTime */ nullptr, /* dependsOnNormals */ dependsOnNormals, /* foreachIDLink */ foreachIDLink, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* foreachTexLink */ nullptr, + /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ nullptr, + /* blendRead */ nullptr, }; diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index 7d3d384d3a8..0a7d2324fde 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -123,7 +123,7 @@ static void deformVerts(ModifierData *md, } } - /* clear old dm */ + /* Clear old evaluated mesh. */ bool had_mesh_final = (psmd->mesh_final != nullptr); if (psmd->mesh_final) { BKE_id_free(nullptr, psmd->mesh_final); diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c index b2197ce8a50..a8c6a0903a3 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c @@ -2047,7 +2047,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, 0.0f; } if (result_edge_bweight) { - result_edge_bweight[insert] = orig_edge_bweight[(*l)->old_edge]; + result_edge_bweight[insert] = orig_edge_bweight ? orig_edge_bweight[(*l)->old_edge] : + 0.0f; } if (bevel_convex != 0.0f && (*l)->faces[1] != NULL) { result_edge_bweight[insert] = clamp_f( diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.cc index 95bbc5ea8cc..ab2f07513d2 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -91,16 +91,16 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla BKE_modifier_copydata_generic(md, target, flag); - tsmd->emCache = tsmd->mCache = NULL; + tsmd->emCache = tsmd->mCache = nullptr; } static void freeRuntimeData(void *runtime_data_v) { - if (runtime_data_v == NULL) { + if (runtime_data_v == nullptr) { return; } SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v; - if (runtime_data->subdiv != NULL) { + if (runtime_data->subdiv != nullptr) { BKE_subdiv_free(runtime_data->subdiv); } MEM_freeN(runtime_data); @@ -111,12 +111,12 @@ static void freeData(ModifierData *md) SubsurfModifierData *smd = (SubsurfModifierData *)md; if (smd->mCache) { - ccgSubSurf_free(smd->mCache); - smd->mCache = NULL; + ccgSubSurf_free(static_cast<CCGSubSurf *>(smd->mCache)); + smd->mCache = nullptr; } if (smd->emCache) { - ccgSubSurf_free(smd->emCache); - smd->emCache = NULL; + ccgSubSurf_free(static_cast<CCGSubSurf *>(smd->emCache)); + smd->emCache = nullptr; } freeRuntimeData(smd->modifier.runtime); } @@ -235,7 +235,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. The * difference is that here we do not check for the final edit mesh pointer as it is not yet * assigned at this stage of modifier stack evaluation. */ - const bool is_editmode = (mesh->edit_mesh != NULL); + const bool is_editmode = (mesh->edit_mesh != nullptr); const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode); if (BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ctx->object, mesh, smd, required_mode)) { subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data); @@ -244,7 +244,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false); - if (subdiv == NULL) { + if (subdiv == nullptr) { /* Happens on bad topology, but also on empty input mesh. */ return result; } @@ -265,8 +265,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } if (use_clnors) { - float(*lnors)[3] = CustomData_get_layer(&result->ldata, CD_NORMAL); - BLI_assert(lnors != NULL); + float(*lnors)[3] = static_cast<float(*)[3]>(CustomData_get_layer(&result->ldata, CD_NORMAL)); + BLI_assert(lnors != nullptr); BKE_mesh_set_custom_normals(result, lnors); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); CustomData_set_layer_flag(&result->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); @@ -299,7 +299,7 @@ static void deformMatrices(ModifierData *md, } SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false); - if (subdiv == NULL) { + if (subdiv == nullptr) { /* Happens on bad topology, but also on empty input mesh. */ return; } @@ -319,9 +319,9 @@ static bool get_show_adaptive_options(const bContext *C, Panel *panel) } /* Only show adaptive options if this is the last modifier. */ - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); - ModifierData *md = ptr->data; - if (md->next != NULL) { + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); + ModifierData *md = static_cast<ModifierData *>(ptr->data); + if (md->next != nullptr) { return false; } @@ -350,8 +350,8 @@ static void panel_draw(const bContext *C, Panel *panel) /* Only test for adaptive subdivision if built with cycles. */ bool show_adaptive_options = false; bool ob_use_adaptive_subdivision = false; - PointerRNA cycles_ptr = {NULL}; - PointerRNA ob_cycles_ptr = {NULL}; + PointerRNA cycles_ptr = {nullptr}; + PointerRNA ob_cycles_ptr = {nullptr}; #ifdef WITH_CYCLES PointerRNA scene_ptr; Scene *scene = CTX_data_scene(C); @@ -368,7 +368,7 @@ static void panel_draw(const bContext *C, Panel *panel) UNUSED_VARS(C); #endif - uiItemR(layout, ptr, "subdivision_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "subdivision_type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -381,7 +381,7 @@ static void panel_draw(const bContext *C, Panel *panel) ICON_NONE); } if (ob_use_adaptive_subdivision && show_adaptive_options) { - uiItemR(layout, &ob_cycles_ptr, "dicing_rate", 0, NULL, ICON_NONE); + uiItemR(layout, &ob_cycles_ptr, "dicing_rate", 0, nullptr, ICON_NONE); float render = MAX2(RNA_float_get(&cycles_ptr, "dicing_rate") * RNA_float_get(&ob_cycles_ptr, "dicing_rate"), 0.1f); @@ -406,11 +406,11 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(col, ptr, "render_levels", 0, IFACE_("Render"), ICON_NONE); } - uiItemR(layout, ptr, "show_only_control_edges", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "show_only_control_edges", 0, nullptr, ICON_NONE); - SubsurfModifierData *smd = ptr->data; - Object *ob = ob_ptr.data; - Mesh *mesh = ob->data; + SubsurfModifierData *smd = static_cast<SubsurfModifierData *>(ptr->data); + const Object *ob = static_cast<const Object *>(ob_ptr.data); + const Mesh *mesh = static_cast<const Mesh *>(ob->data); if (BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(smd, mesh)) { uiItemL(layout, "Autosmooth or custom normals detected, disabling GPU subdivision", ICON_INFO); } @@ -443,30 +443,30 @@ static void advanced_panel_draw(const bContext *C, Panel *panel) uiLayoutSetPropSep(layout, true); uiLayoutSetActive(layout, !(show_adaptive_options && ob_use_adaptive_subdivision)); - uiItemR(layout, ptr, "use_limit_surface", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_limit_surface", 0, nullptr, ICON_NONE); uiLayout *col = uiLayoutColumn(layout, true); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_limit_surface")); - uiItemR(col, ptr, "quality", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "quality", 0, nullptr, ICON_NONE); - uiItemR(layout, ptr, "uv_smooth", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "boundary_smooth", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_creases", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_custom_normals", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "uv_smooth", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "boundary_smooth", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_creases", 0, nullptr, ICON_NONE); + uiItemR(layout, ptr, "use_custom_normals", 0, nullptr, ICON_NONE); } static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Subsurf, panel_draw); modifier_subpanel_register( - region_type, "advanced", "Advanced", NULL, advanced_panel_draw, panel_type); + region_type, "advanced", "Advanced", nullptr, advanced_panel_draw, panel_type); } static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData *)md; - smd->emCache = smd->mCache = NULL; + smd->emCache = smd->mCache = nullptr; } ModifierTypeInfo modifierType_Subsurf = { @@ -482,24 +482,24 @@ ModifierTypeInfo modifierType_Subsurf = { /* copyData */ copyData, - /* deformVerts */ NULL, + /* deformVerts */ nullptr, /* deformMatrices */ deformMatrices, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyGeometrySet */ NULL, + /* modifyGeometrySet */ nullptr, /* initData */ initData, /* requiredDataMask */ requiredDataMask, /* freeData */ freeData, /* isDisabled */ isDisabled, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, + /* updateDepsgraph */ nullptr, + /* dependsOnTime */ nullptr, /* dependsOnNormals */ dependsOnNormals, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, + /* foreachIDLink */ nullptr, + /* foreachTexLink */ nullptr, /* freeRuntimeData */ freeRuntimeData, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, + /* blendWrite */ nullptr, /* blendRead */ blendRead, }; diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.cc index b49a47b0fb4..0fc2d76f87e 100644 --- a/source/blender/modifiers/intern/MOD_wave.c +++ b/source/blender/modifiers/intern/MOD_wave.cc @@ -55,7 +55,7 @@ static void initData(ModifierData *md) MEMCPY_STRUCT_AFTER(wmd, DNA_struct_default_get(WaveModifierData), modifier); } -static bool dependsOnTime(struct Scene *UNUSED(scene), ModifierData *UNUSED(md)) +static bool dependsOnTime(Scene *UNUSED(scene), ModifierData *UNUSED(md)) { return true; } @@ -79,15 +79,15 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte WaveModifierData *wmd = (WaveModifierData *)md; bool need_transform_relation = false; - if (wmd->objectcenter != NULL) { + if (wmd->objectcenter != nullptr) { DEG_add_object_relation(ctx->node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier"); need_transform_relation = true; } - if (wmd->texture != NULL) { + if (wmd->texture != nullptr) { DEG_add_generic_id_relation(ctx->node, &wmd->texture->id, "Wave Modifier"); - if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) { + if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != nullptr) { MOD_depsgraph_update_object_bone_relation( ctx->node, wmd->map_object, wmd->map_bone, "Wave Modifier"); need_transform_relation = true; @@ -135,20 +135,20 @@ static void waveModifier_do(WaveModifierData *md, const MDeformVert *dvert; int defgrp_index; float ctime = DEG_get_ctime(ctx->depsgraph); - float minfac = (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); + float minfac = float(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow)); float lifefac = wmd->height; - float(*tex_co)[3] = NULL; + float(*tex_co)[3] = nullptr; const int wmd_axis = wmd->flag & (MOD_WAVE_X | MOD_WAVE_Y); const float falloff = wmd->falloff; float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */ const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0; - const float(*vert_normals)[3] = NULL; - if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) { + const float(*vert_normals)[3] = nullptr; + if ((wmd->flag & MOD_WAVE_NORM) && (mesh != nullptr)) { vert_normals = BKE_mesh_vertex_normals_ensure(mesh); } - if (wmd->objectcenter != NULL) { + if (wmd->objectcenter != nullptr) { float mat[4][4]; /* get the control object's location in local coordinates */ invert_m4_m4(ob->imat, ob->obmat); @@ -175,14 +175,14 @@ static void waveModifier_do(WaveModifierData *md, lifefac = 0.0; } else { - lifefac = (float)(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); + lifefac = float(wmd->height * (1.0f - sqrtf(lifefac / wmd->damp))); } } } Tex *tex_target = wmd->texture; - if (mesh != NULL && tex_target != NULL) { - tex_co = MEM_malloc_arrayN(verts_num, sizeof(*tex_co), "waveModifier_do tex_co"); + if (mesh != nullptr && tex_target != nullptr) { + tex_co = static_cast<float(*)[3]>(MEM_malloc_arrayN(verts_num, sizeof(*tex_co), __func__)); MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co); MOD_init_texture((MappingInfoModifierData *)wmd, ctx); @@ -227,7 +227,7 @@ static void waveModifier_do(WaveModifierData *md, amplit -= (ctime - wmd->timeoffs) * wmd->speed; if (wmd->flag & MOD_WAVE_CYCL) { - amplit = (float)fmodf(amplit - wmd->width, 2.0f * wmd->width) + wmd->width; + amplit = float(fmodf(amplit - wmd->width, 2.0f * wmd->width)) + wmd->width; } if (falloff != 0.0f) { @@ -252,7 +252,7 @@ static void waveModifier_do(WaveModifierData *md, /* GAUSSIAN */ if ((falloff_fac != 0.0f) && (amplit > -wmd->width) && (amplit < wmd->width)) { amplit = amplit * wmd->narrow; - amplit = (float)(1.0f / expf(amplit * amplit) - minfac); + amplit = float(1.0f / expf(amplit * amplit) - minfac); /* Apply texture. */ if (tex_co) { @@ -295,54 +295,54 @@ static void deformVerts(ModifierData *md, int verts_num) { WaveModifierData *wmd = (WaveModifierData *)md; - Mesh *mesh_src = NULL; + Mesh *mesh_src = nullptr; if (wmd->flag & MOD_WAVE_NORM) { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, vertexCos, verts_num, false); + mesh_src = MOD_deform_mesh_eval_get(ctx->object, nullptr, mesh, vertexCos, verts_num, false); } - else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, NULL, mesh, NULL, verts_num, false); + else if (wmd->texture != nullptr || wmd->defgrp_name[0] != '\0') { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, nullptr, mesh, nullptr, verts_num, false); } waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, verts_num); - if (!ELEM(mesh_src, NULL, mesh)) { - BKE_id_free(NULL, mesh_src); + if (!ELEM(mesh_src, nullptr, mesh)) { + BKE_id_free(nullptr, mesh_src); } } static void deformVertsEM(ModifierData *md, const ModifierEvalContext *ctx, - struct BMEditMesh *editData, + BMEditMesh *editData, Mesh *mesh, float (*vertexCos)[3], int verts_num) { WaveModifierData *wmd = (WaveModifierData *)md; - Mesh *mesh_src = NULL; + Mesh *mesh_src = nullptr; if (wmd->flag & MOD_WAVE_NORM) { mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, vertexCos, verts_num, false); } - else if (wmd->texture != NULL || wmd->defgrp_name[0] != '\0') { - mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, NULL, verts_num, false); + else if (wmd->texture != nullptr || wmd->defgrp_name[0] != '\0') { + mesh_src = MOD_deform_mesh_eval_get(ctx->object, editData, mesh, nullptr, verts_num, false); } /* TODO(@campbellbarton): use edit-mode data only (remove this line). */ - if (mesh_src != NULL) { + if (mesh_src != nullptr) { BKE_mesh_wrapper_ensure_mdata(mesh_src); } waveModifier_do(wmd, ctx, ctx->object, mesh_src, vertexCos, verts_num); - if (!ELEM(mesh_src, NULL, mesh)) { + if (!ELEM(mesh_src, nullptr, mesh)) { /* Important not to free `vertexCos` owned by the caller. */ EditMeshData *edit_data = mesh_src->runtime.edit_data; if (edit_data->vertexCos == vertexCos) { - edit_data->vertexCos = NULL; + edit_data->vertexCos = nullptr; } - BKE_id_free(NULL, mesh_src); + BKE_id_free(nullptr, mesh_src); } } @@ -357,10 +357,12 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); row = uiLayoutRowWithHeading(layout, true, IFACE_("Motion")); - uiItemR(row, ptr, "use_x", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE); - uiItemR(row, ptr, "use_y", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, NULL, ICON_NONE); + uiItemR( + row, ptr, "use_x", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, nullptr, ICON_NONE); + uiItemR( + row, ptr, "use_y", UI_ITEM_R_TOGGLE | UI_ITEM_R_FORCE_BLANK_DECORATE, nullptr, ICON_NONE); - uiItemR(layout, ptr, "use_cyclic", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_cyclic", 0, nullptr, ICON_NONE); row = uiLayoutRowWithHeading(layout, true, IFACE_("Along Normals")); uiItemR(row, ptr, "use_normal", 0, "", ICON_NONE); @@ -372,11 +374,11 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "falloff_radius", 0, IFACE_("Falloff"), ICON_NONE); - uiItemR(col, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "narrowness", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "height", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "width", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); + uiItemR(col, ptr, "narrowness", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr); modifier_panel_end(layout, ptr); } @@ -386,7 +388,7 @@ static void position_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayout *col; uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -402,7 +404,7 @@ static void time_panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayout *col; uiLayout *layout = panel->layout; - PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr); uiLayoutSetPropSep(layout, true); @@ -410,7 +412,7 @@ static void time_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(col, ptr, "time_offset", 0, IFACE_("Offset"), ICON_NONE); uiItemR(col, ptr, "lifetime", 0, IFACE_("Life"), ICON_NONE); uiItemR(col, ptr, "damping_time", 0, IFACE_("Damping"), ICON_NONE); - uiItemR(col, ptr, "speed", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "speed", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } static void texture_panel_draw(const bContext *C, Panel *panel) @@ -423,7 +425,7 @@ static void texture_panel_draw(const bContext *C, Panel *panel) int texture_coords = RNA_enum_get(ptr, "texture_coords"); - uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); + uiTemplateID(layout, C, ptr, "texture", "texture.new", nullptr, nullptr, 0, ICON_NONE, nullptr); uiLayoutSetPropSep(layout, true); @@ -446,7 +448,7 @@ static void texture_panel_draw(const bContext *C, Panel *panel) } else if (texture_coords == MOD_DISP_MAP_UV && RNA_enum_get(&ob_ptr, "type") == OB_MESH) { PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data"); - uiItemPointerR(col, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE); + uiItemPointerR(col, ptr, "uv_layer", &obj_data_ptr, "uv_layers", nullptr, ICON_NONE); } } @@ -454,10 +456,10 @@ static void panelRegister(ARegionType *region_type) { PanelType *panel_type = modifier_panel_register(region_type, eModifierType_Wave, panel_draw); modifier_subpanel_register( - region_type, "position", "Start Position", NULL, position_panel_draw, panel_type); - modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type); + region_type, "position", "Start Position", nullptr, position_panel_draw, panel_type); + modifier_subpanel_register(region_type, "time", "Time", nullptr, time_panel_draw, panel_type); modifier_subpanel_register( - region_type, "texture", "Texture", NULL, texture_panel_draw, panel_type); + region_type, "texture", "Texture", nullptr, texture_panel_draw, panel_type); } ModifierTypeInfo modifierType_Wave = { @@ -473,23 +475,23 @@ ModifierTypeInfo modifierType_Wave = { /* copyData */ BKE_modifier_copydata_generic, /* deformVerts */ deformVerts, - /* deformMatrices */ NULL, + /* deformMatrices */ nullptr, /* deformVertsEM */ deformVertsEM, - /* deformMatricesEM */ NULL, - /* modifyMesh */ NULL, - /* modifyGeometrySet */ NULL, + /* deformMatricesEM */ nullptr, + /* modifyMesh */ nullptr, + /* modifyGeometrySet */ nullptr, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, + /* freeData */ nullptr, + /* isDisabled */ nullptr, /* updateDepsgraph */ updateDepsgraph, /* dependsOnTime */ dependsOnTime, /* dependsOnNormals */ dependsOnNormals, /* foreachIDLink */ foreachIDLink, /* foreachTexLink */ foreachTexLink, - /* freeRuntimeData */ NULL, + /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ nullptr, + /* blendRead */ nullptr, }; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index e9c0f2be368..422ee747649 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -60,6 +60,7 @@ set(SRC NOD_geometry.h NOD_geometry_exec.hh NOD_geometry_nodes_lazy_function.hh + NOD_geometry_nodes_log.hh NOD_math_functions.hh NOD_multi_function.hh NOD_node_declaration.hh diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 4ead6326295..7916bb6d08c 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -46,6 +46,8 @@ void register_node_type_geo_curve_spline_type(void); void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); +void register_node_type_geo_curve_topology_curve_of_point(void); +void register_node_type_geo_curve_topology_points_of_curve(void); void register_node_type_geo_curve_trim(void); void register_node_type_geo_deform_curves_on_surface(void); void register_node_type_geo_delete_geometry(void); @@ -110,6 +112,13 @@ void register_node_type_geo_mesh_subdivide(void); void register_node_type_geo_mesh_to_curve(void); void register_node_type_geo_mesh_to_points(void); void register_node_type_geo_mesh_to_volume(void); +void register_node_type_geo_mesh_topology_corners_of_face(void); +void register_node_type_geo_mesh_topology_corners_of_vertex(void); +void register_node_type_geo_mesh_topology_edges_of_corner(void); +void register_node_type_geo_mesh_topology_edges_of_vertex(void); +void register_node_type_geo_mesh_topology_face_of_corner(void); +void register_node_type_geo_mesh_topology_offset_corner_in_face(void); +void register_node_type_geo_mesh_topology_vertex_of_corner(void); void register_node_type_geo_object_info(void); void register_node_type_geo_points_to_vertices(void); void register_node_type_geo_points_to_volume(void); diff --git a/source/blender/nodes/NOD_geometry_nodes_log.hh b/source/blender/nodes/NOD_geometry_nodes_log.hh index cf59c99bc79..2b0c16c8656 100644 --- a/source/blender/nodes/NOD_geometry_nodes_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_log.hh @@ -33,6 +33,7 @@ #include "BKE_attribute.h" #include "BKE_geometry_set.hh" +#include "BKE_viewer_path.h" #include "FN_field.hh" @@ -156,7 +157,6 @@ class GeometryInfoLog : public ValueLog { class ViewerNodeLog { public: GeometrySet geometry; - GField field; }; using Clock = std::chrono::steady_clock; @@ -214,7 +214,7 @@ class GeoTreeLogger { ~GeoTreeLogger(); void log_value(const bNode &node, const bNodeSocket &socket, GPointer value); - void log_viewer_node(const bNode &viewer_node, const GeometrySet &geometry, const GField &field); + void log_viewer_node(const bNode &viewer_node, GeometrySet geometry); }; /** @@ -333,8 +333,7 @@ class GeoModifierLog { * Utility accessor to logged data. */ static GeoTreeLog *get_tree_log_for_node_editor(const SpaceNode &snode); - static const ViewerNodeLog *find_viewer_node_log_for_spreadsheet( - const SpaceSpreadsheet &sspreadsheet); + static const ViewerNodeLog *find_viewer_node_log_for_path(const ViewerPath &viewer_path); }; } // namespace blender::nodes::geo_eval_log diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 574a8dcab96..c4e1d54baef 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -303,9 +303,11 @@ DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER,0, "SPLINE_PARAMETER", Spl DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type,"CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "Change the type of curves") DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "Convert curves into a mesh, optionally with a custom profile shape defined by curves") DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "Generate a point cloud by sampling positions along curves") +DefNode(GeometryNode, GEO_NODE_CURVE_TOPOLOGY_CURVE_OF_POINT, 0, "CURVE_OF_POINT", CurveOfPoint, "Curve of Point", "Retrieve the curve a control point is part of") +DefNode(GeometryNode, GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE, 0, "POINTS_OF_CURVE", PointsOfCurve, "Points of Curve", "Retrieve a point index within a curve") DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_ON_SURFACE, 0, "DEFORM_CURVES_ON_SURFACE", DeformCurvesOnSurface, "Deform Curves on Surface", "Translate and rotate curves based on changes between the object's original and evaluated surface mesh") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "Remove selected elements of a geometry") -DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME, def_geo_distribute_points_in_volume, "DISTRIBUTE_POINTS_IN_VOLUME", DistributePointsInVolume, "Distribute Points In Volume", "Generate points inside a volume") +DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME, def_geo_distribute_points_in_volume, "DISTRIBUTE_POINTS_IN_VOLUME", DistributePointsInVolume, "Distribute Points in Volume", "Generate points inside a volume") DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "Generate points spread out on the surface of a mesh") DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "Convert Faces into vertices and vertices into faces") DefNode(GeometryNode, GEO_NODE_DUPLICATE_ELEMENTS, def_geo_duplicate_elements, "DUPLICATE_ELEMENTS", DuplicateElements, "Duplicate Elements", "Generate an arbitrary number copies of each selected input element") @@ -366,6 +368,13 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_S DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "Generate a curve from a mesh") DefNode(GeometryNode, GEO_NODE_MESH_TO_POINTS, def_geo_mesh_to_points, "MESH_TO_POINTS", MeshToPoints, "Mesh to Points", "Generate a point cloud from a mesh's vertices") DefNode(GeometryNode, GEO_NODE_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh to Volume", "Create a fog volume with the shape of the input mesh's surface") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, 0, "CORNERS_OF_FACE", CornersOfFace, "Corners of Face", "Retrieve corners that make up a face") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX, 0, "CORNERS_OF_VERTEX", CornersOfVertex, "Corners of Vertex", "Retrieve face corners connected to vertices") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, 0, "EDGES_OF_CORNER", EdgesOfCorner, "Edges of Corner", "Retrieve the edges on boths sides of a face corner") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, 0, "EDGES_OF_VERTEX", EdgesOfVertex, "Edges of Vertex", "Retrieve the edges connected to each vertex") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER, 0, "FACE_OF_CORNER", FaceOfCorner, "Face of Corner", "Retrieve the face each face corner is part of") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE, 0, "OFFSET_CORNER_IN_FACE", OffsetCornerInFace, "Offset Corner in Face", "Retrieve corners in the same face as another") +DefNode(GeometryNode, GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER, 0, "VERTEX_OF_CORNER", VertexOfCorner, "Vertex of Corner", "Retrieve the vertex each face corner is attached to") DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "Retrieve information from an object") DefNode(GeometryNode, GEO_NODE_POINTS_TO_VERTICES, 0, "POINTS_TO_VERTICES", PointsToVertices, "Points to Vertices", "Generate a mesh vertex for each point cloud point") DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "Generate a fog volume sphere around every point") diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index b80e87e80ac..40b2ae61915 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -56,6 +56,8 @@ set(SRC nodes/node_geo_curve_subdivide.cc nodes/node_geo_curve_to_mesh.cc nodes/node_geo_curve_to_points.cc + nodes/node_geo_curve_topology_curve_of_point.cc + nodes/node_geo_curve_topology_points_of_curve.cc nodes/node_geo_curve_trim.cc nodes/node_geo_deform_curves_on_surface.cc nodes/node_geo_delete_geometry.cc @@ -120,6 +122,13 @@ set(SRC nodes/node_geo_mesh_to_curve.cc nodes/node_geo_mesh_to_points.cc nodes/node_geo_mesh_to_volume.cc + nodes/node_geo_mesh_topology_corners_of_face.cc + nodes/node_geo_mesh_topology_corners_of_vertex.cc + nodes/node_geo_mesh_topology_edges_of_corner.cc + nodes/node_geo_mesh_topology_edges_of_vertex.cc + nodes/node_geo_mesh_topology_face_of_corner.cc + nodes/node_geo_mesh_topology_offset_corner_in_face.cc + nodes/node_geo_mesh_topology_vertex_of_corner.cc nodes/node_geo_object_info.cc nodes/node_geo_points.cc nodes/node_geo_points_to_vertices.cc @@ -130,13 +139,13 @@ set(SRC nodes/node_geo_remove_attribute.cc nodes/node_geo_rotate_instances.cc nodes/node_geo_sample_index.cc - nodes/node_geo_sample_nearest_surface.cc nodes/node_geo_sample_nearest.cc + nodes/node_geo_sample_nearest_surface.cc nodes/node_geo_scale_elements.cc nodes/node_geo_scale_instances.cc + nodes/node_geo_self_object.cc nodes/node_geo_separate_components.cc nodes/node_geo_separate_geometry.cc - nodes/node_geo_self_object.cc nodes/node_geo_set_curve_handles.cc nodes/node_geo_set_curve_radius.cc nodes/node_geo_set_curve_tilt.cc diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 5aeb68b3fdc..adcf47f57fe 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -87,7 +87,27 @@ void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data, const MutableSpan<float> r_distances_sq, const MutableSpan<float3> r_positions); +int apply_offset_in_cyclic_range(IndexRange range, int start_index, int offset); + std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type); std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket); +class FieldAtIndexInput final : public bke::GeometryFieldInput { + private: + Field<int> index_field_; + GField value_field_; + eAttrDomain value_field_domain_; + + public: + FieldAtIndexInput(Field<int> index_field, GField value_field, eAttrDomain value_field_domain); + + GVArray get_varray_for_context(const bke::GeometryFieldContext &context, + const IndexMask mask) const final; + + std::optional<eAttrDomain> preferred_domain(const GeometryComponent & /*component*/) const final + { + return value_field_domain_; + } +}; + } // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc index 4ad6efebfa8..4504839dc5a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc @@ -285,6 +285,12 @@ template<typename T> class AccumulateFieldInput final : public bke::GeometryFiel } return false; } + + std::optional<eAttrDomain> preferred_domain( + const GeometryComponent & /*component*/) const override + { + return source_domain_; + } }; template<typename T> class TotalFieldInput final : public bke::GeometryFieldInput { @@ -355,6 +361,12 @@ template<typename T> class TotalFieldInput final : public bke::GeometryFieldInpu } return false; } + + std::optional<eAttrDomain> preferred_domain( + const GeometryComponent & /*component*/) const override + { + return source_domain_; + } }; template<typename T> std::string identifier_suffix() diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index c9df66f1eea..99dd4d9f798 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -106,33 +106,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -static void try_capture_field_on_geometry(GeometryComponent &component, - const AttributeIDRef &attribute_id, - const eAttrDomain domain, - const GField &field) -{ - const int domain_size = component.attribute_domain_size(domain); - if (domain_size == 0) { - return; - } - bke::GeometryFieldContext field_context{component, domain}; - MutableAttributeAccessor attributes = *component.attributes_for_write(); - const IndexMask mask{IndexMask(domain_size)}; - - const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type()); - GAttributeWriter output_attribute = attributes.lookup_or_add_for_write( - attribute_id, domain, data_type); - if (!output_attribute) { - return; - } - - fn::FieldEvaluator evaluator{field_context, &mask}; - evaluator.add_with_destination(field, output_attribute.varray); - evaluator.evaluate(); - - output_attribute.finish(); -} - static StringRefNull identifier_suffix(eCustomDataType data_type) { switch (data_type) { @@ -206,7 +179,7 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_instances()) { GeometryComponent &component = geometry_set.get_component_for_write( GEO_COMPONENT_TYPE_INSTANCES); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } } else { @@ -217,7 +190,7 @@ static void node_geo_exec(GeoNodeExecParams params) for (const GeometryComponentType type : types) { if (geometry_set.has(type)) { GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + bke::try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } } }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 28d979facac..d3d0dcfb794 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -90,6 +90,11 @@ class EndpointFieldInput final : public bke::CurvesFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index b1c3bbfb81e..b4181528696 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -108,6 +108,11 @@ class HandleTypeFieldInput final : public bke::CurvesFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index b5d8d1f020a..00d3129a63d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -126,6 +126,10 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry value *= factor; } } + else if (curve_lengths.size() == 1) { + /* The curve is a single point. */ + curve_lengths[0] = 0.0f; + } else { /* It is arbitrary what to do in those rare cases when all the points are * in the same position. In this case we are just arbitrarily giving a valid @@ -280,6 +284,11 @@ class IndexOnSplineFieldInput final : public bke::CurvesFieldInput { { return dynamic_cast<const IndexOnSplineFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc new file mode 100644 index 00000000000..4d60ab939ca --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_curve_of_point.cc @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_curves.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_curve_topology_curve_of_point_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Point Index")) + .implicit_field(implicit_field_inputs::index) + .description(N_("The control point to retrieve data from")); + b.add_output<decl::Int>(N_("Curve Index")) + .dependent_field() + .description(N_("The curve the control point is part of")); + b.add_output<decl::Int>(N_("Index in Curve")) + .dependent_field() + .description(N_("How far along the control point is along its curve")); +} + +class CurveOfPointInput final : public bke::CurvesFieldInput { + public: + CurveOfPointInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point Curve Index") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const bke::CurvesGeometry &curves, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + return VArray<int>::ForContainer(curves.point_to_curve_map()); + } + + uint64_t hash() const override + { + return 413209687345908697; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (dynamic_cast<const CurveOfPointInput *>(&other)) { + return true; + } + return false; + } +}; + +class PointIndexInCurveInput final : public bke::CurvesFieldInput { + public: + PointIndexInCurveInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Point Index in Curve") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const bke::CurvesGeometry &curves, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + const Span<int> offsets = curves.offsets(); + Array<int> point_to_curve_map = curves.point_to_curve_map(); + return VArray<int>::ForFunc( + curves.points_num(), + [offsets, point_to_curve_map = std::move(point_to_curve_map)](const int point_i) { + const int curve_i = point_to_curve_map[point_i]; + return point_i - offsets[curve_i]; + }); + } + + uint64_t hash() const final + { + return 9834765987345677; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const PointIndexInCurveInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> point_index = params.extract_input<Field<int>>("Point Index"); + if (params.output_is_required("Curve Index")) { + params.set_output( + "Curve Index", + Field<int>(std::make_shared<FieldAtIndexInput>( + point_index, Field<int>(std::make_shared<CurveOfPointInput>()), ATTR_DOMAIN_POINT))); + } + if (params.output_is_required("Index in Curve")) { + params.set_output("Index in Curve", + Field<int>(std::make_shared<FieldAtIndexInput>( + point_index, + Field<int>(std::make_shared<PointIndexInCurveInput>()), + ATTR_DOMAIN_POINT))); + } +} + +} // namespace blender::nodes::node_geo_curve_topology_curve_of_point_cc + +void register_node_type_geo_curve_topology_curve_of_point() +{ + namespace file_ns = blender::nodes::node_geo_curve_topology_curve_of_point_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_TOPOLOGY_CURVE_OF_POINT, "Curve of Point", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc new file mode 100644 index 00000000000..62a8ba9a976 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_topology_points_of_curve.cc @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_curves.hh" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_curve_topology_points_of_curve_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Curve Index")) + .implicit_field(implicit_field_inputs::index) + .description(N_("The curve to retrieve data from. Defaults to the curve from the context")); + b.add_input<decl::Float>(N_("Weights")) + .supports_field() + .hide_value() + .description(N_("Values used to sort the curve's points. Uses indices by default")); + b.add_input<decl::Int>(N_("Sort Index")) + .min(0) + .supports_field() + .description(N_("Which of the sorted points to output")); + b.add_output<decl::Int>(N_("Total")) + .dependent_field() + .description(N_("The number of points in the curve")); + b.add_output<decl::Int>(N_("Point Index")) + .dependent_field() + .description(N_("A point of the curve, chosen by the sort index")); +} + +class PointsOfCurveInput final : public bke::CurvesFieldInput { + const Field<int> curve_index_; + const Field<int> sort_index_; + const Field<float> sort_weight_; + + public: + PointsOfCurveInput(Field<int> curve_index, Field<int> sort_index, Field<float> sort_weight) + : bke::CurvesFieldInput(CPPType::get<int>(), "Point of Curve"), + curve_index_(std::move(curve_index)), + sort_index_(std::move(sort_index)), + sort_weight_(std::move(sort_weight)) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const bke::CurvesGeometry &curves, + const eAttrDomain domain, + const IndexMask mask) const final + { + const bke::CurvesFieldContext context{curves, domain}; + fn::FieldEvaluator evaluator{context, &mask}; + evaluator.add(curve_index_); + evaluator.add(sort_index_); + evaluator.evaluate(); + const VArray<int> curve_indices = evaluator.get_evaluated<int>(0); + const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1); + + const bke::CurvesFieldContext point_context{curves, ATTR_DOMAIN_POINT}; + fn::FieldEvaluator point_evaluator{point_context, curves.points_num()}; + point_evaluator.add(sort_weight_); + point_evaluator.evaluate(); + const VArray<float> all_sort_weights = point_evaluator.get_evaluated<float>(0); + + Array<int> point_of_curve(mask.min_array_size()); + threading::parallel_for(mask.index_range(), 256, [&](const IndexRange range) { + /* Reuse arrays to avoid allocation. */ + Array<float> sort_weights; + Array<int> sort_indices; + + for (const int selection_i : mask.slice(range)) { + const int curve_i = curve_indices[selection_i]; + const int index_in_sort = indices_in_sort[selection_i]; + if (!curves.curves_range().contains(curve_i)) { + point_of_curve[selection_i] = 0; + continue; + } + + const IndexRange points = curves.points_for_curve(curve_i); + + /* Retrieve the weights for each point. */ + sort_weights.reinitialize(points.size()); + all_sort_weights.materialize_compressed(IndexMask(points), sort_weights.as_mutable_span()); + + /* Sort a separate array of compressed indices corresponding to the compressed weights. + * This allows using `materialize_compressed` to avoid virtual function call overhead + * when accessing values in the sort weights. However, it means a separate array of + * indices within the compressed array is necessary for sorting. */ + sort_indices.reinitialize(points.size()); + std::iota(sort_indices.begin(), sort_indices.end(), 0); + std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) { + return sort_weights[a] < sort_weights[b]; + }); + + const int index_in_sort_wrapped = mod_i(index_in_sort, points.size()); + point_of_curve[selection_i] = points[sort_indices[index_in_sort_wrapped]]; + } + }); + + return VArray<int>::ForContainer(std::move(point_of_curve)); + } + + uint64_t hash() const override + { + return 26978695677882; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const auto *typed = dynamic_cast<const PointsOfCurveInput *>(&other)) { + return typed->curve_index_ == curve_index_ && typed->sort_index_ == sort_index_ && + typed->sort_weight_ == sort_weight_; + } + return false; + } +}; + +class CurvePointCountInput final : public bke::CurvesFieldInput { + public: + CurvePointCountInput() : bke::CurvesFieldInput(CPPType::get<int>(), "Curve Point Count") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const bke::CurvesGeometry &curves, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CURVE) { + return {}; + } + return VArray<int>::ForFunc(curves.curves_num(), [&, curves](const int64_t curve_i) { + return curves.points_num_for_curve(curve_i); + }); + } + + uint64_t hash() const final + { + return 903847569873762; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CurvePointCountInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> curve_index = params.extract_input<Field<int>>("Curve Index"); + if (params.output_is_required("Total")) { + params.set_output("Total", + Field<int>(std::make_shared<FieldAtIndexInput>( + curve_index, + Field<int>(std::make_shared<CurvePointCountInput>()), + ATTR_DOMAIN_CURVE))); + } + if (params.output_is_required("Point Index")) { + params.set_output("Point Index", + Field<int>(std::make_shared<PointsOfCurveInput>( + curve_index, + params.extract_input<Field<int>>("Sort Index"), + params.extract_input<Field<float>>("Weights")))); + } +} + +} // namespace blender::nodes::node_geo_curve_topology_points_of_curve_cc + +void register_node_type_geo_curve_topology_points_of_curve() +{ + namespace file_ns = blender::nodes::node_geo_curve_topology_points_of_curve_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_CURVE_TOPOLOGY_POINTS_OF_CURVE, "Points of Curve", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc index 9ef9ee8ad6e..f0bd01a012b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc @@ -106,6 +106,11 @@ class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc index 4d7e4b00c5a..af6f15da60c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc @@ -11,6 +11,63 @@ #include "NOD_socket_search_link.hh" +namespace blender::nodes { + +FieldAtIndexInput::FieldAtIndexInput(Field<int> index_field, + GField value_field, + eAttrDomain value_field_domain) + : bke::GeometryFieldInput(value_field.cpp_type(), "Field at Index"), + index_field_(std::move(index_field)), + value_field_(std::move(value_field)), + value_field_domain_(value_field_domain) +{ +} + +GVArray FieldAtIndexInput::get_varray_for_context(const bke::GeometryFieldContext &context, + const IndexMask mask) const +{ + const std::optional<AttributeAccessor> attributes = context.attributes(); + if (!attributes) { + return {}; + } + + const bke::GeometryFieldContext value_field_context{ + context.geometry(), context.type(), value_field_domain_}; + FieldEvaluator value_evaluator{value_field_context, + attributes->domain_size(value_field_domain_)}; + value_evaluator.add(value_field_); + value_evaluator.evaluate(); + const GVArray &values = value_evaluator.get_evaluated(0); + + FieldEvaluator index_evaluator{context, &mask}; + index_evaluator.add(index_field_); + index_evaluator.evaluate(); + const VArray<int> indices = index_evaluator.get_evaluated<int>(0); + + GVArray output_array; + attribute_math::convert_to_static_type(*type_, [&](auto dummy) { + using T = decltype(dummy); + Array<T> dst_array(mask.min_array_size()); + VArray<T> src_values = values.typed<T>(); + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + for (const int i : mask.slice(range)) { + const int index = indices[i]; + if (src_values.index_range().contains(index)) { + dst_array[i] = src_values[index]; + } + else { + dst_array[i] = {}; + } + } + }); + output_array = VArray<T>::ForContainer(std::move(dst_array)); + }); + + return output_array; +} + +} // namespace blender::nodes + namespace blender::nodes::node_geo_field_at_index_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -89,60 +146,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -class FieldAtIndex final : public bke::GeometryFieldInput { - private: - Field<int> index_field_; - GField value_field_; - eAttrDomain value_field_domain_; - - public: - FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain) - : bke::GeometryFieldInput(value_field.cpp_type(), "Field at Index"), - index_field_(std::move(index_field)), - value_field_(std::move(value_field)), - value_field_domain_(value_field_domain) - { - } - - GVArray get_varray_for_context(const bke::GeometryFieldContext &context, - const IndexMask mask) const final - { - const bke::GeometryFieldContext value_field_context{ - context.geometry(), context.type(), value_field_domain_}; - FieldEvaluator value_evaluator{value_field_context, - context.attributes()->domain_size(value_field_domain_)}; - value_evaluator.add(value_field_); - value_evaluator.evaluate(); - const GVArray &values = value_evaluator.get_evaluated(0); - - FieldEvaluator index_evaluator{context, &mask}; - index_evaluator.add(index_field_); - index_evaluator.evaluate(); - const VArray<int> indices = index_evaluator.get_evaluated<int>(0); - - GVArray output_array; - attribute_math::convert_to_static_type(*type_, [&](auto dummy) { - using T = decltype(dummy); - Array<T> dst_array(mask.min_array_size()); - VArray<T> src_values = values.typed<T>(); - threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { - for (const int i : mask.slice(range)) { - const int index = indices[i]; - if (src_values.index_range().contains(index)) { - dst_array[i] = src_values[index]; - } - else { - dst_array[i] = {}; - } - } - }); - output_array = VArray<T>::ForContainer(std::move(dst_array)); - }); - - return output_array; - } -}; - static StringRefNull identifier_suffix(eCustomDataType data_type) { switch (data_type) { @@ -173,8 +176,8 @@ static void node_geo_exec(GeoNodeExecParams params) using T = decltype(dummy); static const std::string identifier = "Value_" + identifier_suffix(data_type); Field<T> value_field = params.extract_input<Field<T>>(identifier); - Field<T> output_field{ - std::make_shared<FieldAtIndex>(std::move(index_field), std::move(value_field), domain)}; + Field<T> output_field{std::make_shared<FieldAtIndexInput>( + std::move(index_field), std::move(value_field), domain)}; params.set_output(identifier, std::move(output_field)); }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc index b5d0c8cdd74..7af4b13cd57 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_control_point_neighbors.cc @@ -6,6 +6,22 @@ #include "node_geometry_util.hh" +namespace blender::nodes { + +int apply_offset_in_cyclic_range(const IndexRange range, const int start_index, const int offset) +{ + BLI_assert(range.contains(start_index)); + const int start_in_range = start_index - range.first(); + const int offset_in_range = start_in_range + offset; + const int mod_offset = offset_in_range % range.size(); + if (mod_offset >= 0) { + return range[mod_offset]; + } + return range.last(-(mod_offset + 1)); +} + +} // namespace blender::nodes + namespace blender::nodes::node_geo_input_control_point_neighbors_cc { static void node_declare(NodeDeclarationBuilder &b) @@ -28,29 +44,6 @@ static void node_declare(NodeDeclarationBuilder &b) "curves data-block")); } -static int apply_offset_in_cyclic_range(const IndexRange range, - const int start_index, - const int offset) -{ - BLI_assert(range.contains(start_index)); - const int start_in_range = start_index - range.first(); - const int offset_in_range = start_in_range + offset; - const int mod_offset = offset_in_range % range.size(); - if (mod_offset >= 0) { - return range[mod_offset]; - } - return range.last(-(mod_offset + 1)); -} - -static Array<int> build_parent_curves(const bke::CurvesGeometry &curves) -{ - Array<int> parent_curves(curves.points_num()); - for (const int i : curves.curves_range()) { - parent_curves.as_mutable_span().slice(curves.points_for_curve(i)).fill(i); - } - return parent_curves; -} - class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput { private: const Field<int> index_; @@ -70,7 +63,7 @@ class ControlPointNeighborFieldInput final : public bke::CurvesFieldInput { const IndexMask mask) const final { const VArray<bool> cyclic = curves.cyclic(); - const Array<int> parent_curves = build_parent_curves(curves); + const Array<int> parent_curves = curves.point_to_curve_map(); const bke::CurvesFieldContext context{curves, domain}; fn::FieldEvaluator evaluator{context, &mask}; @@ -118,7 +111,7 @@ class OffsetValidFieldInput final : public bke::CurvesFieldInput { const IndexMask mask) const final { const VArray<bool> cyclic = curves.cyclic(); - const Array<int> parent_curves = build_parent_curves(curves); + const Array<int> parent_curves = curves.point_to_curve_map(); const bke::CurvesFieldContext context{curves, domain}; fn::FieldEvaluator evaluator{context, &mask}; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index bff2e7831c6..2979d0e4639 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -84,6 +84,11 @@ class HandlePositionFieldInput final : public bke::CurvesFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const CurvesGeometry & /*curves*/) const + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc index 2de2b87ad1e..7f5b0bd070e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -102,6 +102,11 @@ class AngleFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const AngleFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; class SignedAngleFieldInput final : public bke::MeshFieldInput { @@ -176,6 +181,11 @@ class SignedAngleFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const SignedAngleFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index bfe8753c039..a579202738d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -48,6 +48,11 @@ class EdgeNeighborCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const EdgeNeighborCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index ae410536dcd..10770ea07d6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -25,15 +25,15 @@ static void node_declare(NodeDeclarationBuilder &b) .description(N_("The position of the second vertex in the edge")); } -enum VertexNumber { VERTEX_ONE, VERTEX_TWO }; +enum class VertNumber { V1, V2 }; static VArray<int> construct_edge_verts_gvarray(const Mesh &mesh, - const VertexNumber vertex, + const VertNumber vertex, const eAttrDomain domain) { const Span<MEdge> edges = mesh.edges(); if (domain == ATTR_DOMAIN_EDGE) { - if (vertex == VERTEX_ONE) { + if (vertex == VertNumber::V1) { return VArray<int>::ForFunc(edges.size(), [edges](const int i) -> int { return edges[i].v1; }); } @@ -42,12 +42,12 @@ static VArray<int> construct_edge_verts_gvarray(const Mesh &mesh, return {}; } -class EdgeVerticesFieldInput final : public bke::MeshFieldInput { +class EdgeVertsInput final : public bke::MeshFieldInput { private: - VertexNumber vertex_; + VertNumber vertex_; public: - EdgeVerticesFieldInput(VertexNumber vertex) + EdgeVertsInput(VertNumber vertex) : bke::MeshFieldInput(CPPType::get<int>(), "Edge Vertices Field"), vertex_(vertex) { category_ = Category::Generated; @@ -62,27 +62,31 @@ class EdgeVerticesFieldInput final : public bke::MeshFieldInput { uint64_t hash() const override { - return vertex_ == VERTEX_ONE ? 23847562893465 : 92384598734567; + return vertex_ == VertNumber::V1 ? 23847562893465 : 92384598734567; } bool is_equal_to(const fn::FieldNode &other) const override { - if (const EdgeVerticesFieldInput *other_field = dynamic_cast<const EdgeVerticesFieldInput *>( - &other)) { + if (const EdgeVertsInput *other_field = dynamic_cast<const EdgeVertsInput *>(&other)) { return vertex_ == other_field->vertex_; } return false; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static VArray<float3> construct_edge_positions_gvarray(const Mesh &mesh, - const VertexNumber vertex, + const VertNumber vertex, const eAttrDomain domain) { const Span<float3> positions = mesh.positions(); const Span<MEdge> edges = mesh.edges(); - if (vertex == VERTEX_ONE) { + if (vertex == VertNumber::V1) { return mesh.attributes().adapt_domain<float3>( VArray<float3>::ForFunc( edges.size(), [positions, edges](const int i) { return positions[edges[i].v1]; }), @@ -98,10 +102,10 @@ static VArray<float3> construct_edge_positions_gvarray(const Mesh &mesh, class EdgePositionFieldInput final : public bke::MeshFieldInput { private: - VertexNumber vertex_; + VertNumber vertex_; public: - EdgePositionFieldInput(VertexNumber vertex) + EdgePositionFieldInput(VertNumber vertex) : bke::MeshFieldInput(CPPType::get<float3>(), "Edge Position Field"), vertex_(vertex) { category_ = Category::Generated; @@ -116,7 +120,7 @@ class EdgePositionFieldInput final : public bke::MeshFieldInput { uint64_t hash() const override { - return vertex_ == VERTEX_ONE ? 987456978362 : 374587679866; + return vertex_ == VertNumber::V1 ? 987456978362 : 374587679866; } bool is_equal_to(const fn::FieldNode &other) const override @@ -127,14 +131,19 @@ class EdgePositionFieldInput final : public bke::MeshFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static void node_geo_exec(GeoNodeExecParams params) { - Field<int> vertex_field_1{std::make_shared<EdgeVerticesFieldInput>(VERTEX_ONE)}; - Field<int> vertex_field_2{std::make_shared<EdgeVerticesFieldInput>(VERTEX_TWO)}; - Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VERTEX_ONE)}; - Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VERTEX_TWO)}; + Field<int> vertex_field_1{std::make_shared<EdgeVertsInput>(VertNumber::V1)}; + Field<int> vertex_field_2{std::make_shared<EdgeVertsInput>(VertNumber::V2)}; + Field<float3> position_field_1{std::make_shared<EdgePositionFieldInput>(VertNumber::V1)}; + Field<float3> position_field_2{std::make_shared<EdgePositionFieldInput>(VertNumber::V2)}; params.set_output("Vertex Index 1", std::move(vertex_field_1)); params.set_output("Vertex Index 2", std::move(vertex_field_2)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc index 3ae3e66c387..d60067ac5b9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -56,6 +56,11 @@ class FaceAreaFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const FaceAreaFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_FACE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc index cac7dade79d..0bd1cf968df 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc @@ -87,6 +87,11 @@ class PlanarFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const PlanarFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_FACE; + } }; static void geo_node_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index 9e85eae3a31..429526588ce 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -66,6 +66,11 @@ class FaceNeighborCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const FaceNeighborCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_FACE; + } }; static VArray<int> construct_vertex_count_varray(const Mesh &mesh, const eAttrDomain domain) @@ -102,6 +107,11 @@ class FaceVertexCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const FaceVertexCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_FACE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index 9d7735e707d..6d19d3be511 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -61,6 +61,11 @@ class IslandFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const IslandFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; class IslandCountFieldInput final : public bke::MeshFieldInput { @@ -100,6 +105,11 @@ class IslandCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const IslandCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc index ab44a6c8515..6b7f62a944c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -58,6 +58,11 @@ class VertexCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const VertexCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; static VArray<int> construct_face_count_gvarray(const Mesh &mesh, const eAttrDomain domain) @@ -98,6 +103,11 @@ class VertexFaceCountFieldInput final : public bke::MeshFieldInput { { return dynamic_cast<const VertexFaceCountFieldInput *>(&other) != nullptr; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc index a54daabde3b..00c92e30443 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc @@ -143,6 +143,11 @@ class ShortestEdgePathsNextVertFieldInput final : public bke::MeshFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput { @@ -206,6 +211,11 @@ class ShortestEdgePathsCostFieldInput final : public bke::MeshFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_POINT; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc index df1427ac5b9..0326c55b65a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_interpolate_domain.cc @@ -111,6 +111,12 @@ class InterpolateDomain final : public bke::GeometryFieldInput { return attributes.adapt_domain( GVArray::ForGArray(std::move(values)), src_domain_, context.domain()); } + + std::optional<eAttrDomain> preferred_domain( + const GeometryComponent & /*component*/) const override + { + return src_domain_; + } }; static StringRefNull identifier_suffix(eCustomDataType data_type) diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 628688f3b47..dfb4181926e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -100,6 +100,12 @@ class MaterialSelectionFieldInput final : public bke::GeometryFieldInput { } return false; } + + std::optional<eAttrDomain> preferred_domain( + const GeometryComponent & /*component*/) const override + { + return ATTR_DOMAIN_FACE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc index 88cccfb2f94..1b9852cf7b9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc @@ -65,6 +65,11 @@ class BoundaryFieldInput final : public bke::MeshFieldInput { return mesh.attributes().adapt_domain<bool>( VArray<bool>::ForContainer(std::move(boundary)), ATTR_DOMAIN_EDGE, domain); } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_EDGE; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc new file mode 100644 index 00000000000..cf35f9dbdc5 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_task.hh" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_corners_of_face_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Face Index")) + .implicit_field(implicit_field_inputs::index) + .description(N_("The face to retrieve data from. Defaults to the face from the context")); + b.add_input<decl::Float>(N_("Weights")) + .supports_field() + .hide_value() + .description(N_("Values used to sort the face's corners. Uses indices by default")); + b.add_input<decl::Int>(N_("Sort Index")) + .min(0) + .supports_field() + .description(N_("Which of the sorted corners to output")); + b.add_output<decl::Int>(N_("Total")) + .dependent_field() + .description(N_("The number of corners in the face")); + b.add_output<decl::Int>(N_("Corner Index")) + .dependent_field() + .description(N_("A corner of the face, chosen by the sort index")); +} + +class CornersOfFaceInput final : public bke::MeshFieldInput { + const Field<int> face_index_; + const Field<int> sort_index_; + const Field<float> sort_weight_; + + public: + CornersOfFaceInput(Field<int> face_index, Field<int> sort_index, Field<float> sort_weight) + : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Face"), + face_index_(std::move(face_index)), + sort_index_(std::move(sort_index)), + sort_weight_(std::move(sort_weight)) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask mask) const final + { + const Span<MPoly> polys = mesh.polys(); + + const bke::MeshFieldContext context{mesh, domain}; + fn::FieldEvaluator evaluator{context, &mask}; + evaluator.add(face_index_); + evaluator.add(sort_index_); + evaluator.evaluate(); + const VArray<int> face_indices = evaluator.get_evaluated<int>(0); + const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1); + + const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER}; + fn::FieldEvaluator corner_evaluator{corner_context, mesh.totloop}; + corner_evaluator.add(sort_weight_); + corner_evaluator.evaluate(); + const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0); + + Array<int> corner_of_face(mask.min_array_size()); + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + /* Reuse arrays to avoid allocation. */ + Array<float> sort_weights; + Array<int> sort_indices; + + for (const int selection_i : mask.slice(range)) { + const int poly_i = face_indices[selection_i]; + const int index_in_sort = indices_in_sort[selection_i]; + if (!polys.index_range().contains(poly_i)) { + corner_of_face[selection_i] = 0; + continue; + } + + const MPoly &poly = polys[poly_i]; + const IndexRange corners(poly.loopstart, poly.totloop); + + /* Retrieve the weights for each corner. */ + sort_weights.reinitialize(corners.size()); + all_sort_weights.materialize_compressed(IndexMask(corners), + sort_weights.as_mutable_span()); + + /* Sort a separate array of compressed indices corresponding to the compressed weights. + * This allows using `materialize_compressed` to avoid virtual function call overhead + * when accessing values in the sort weights. However, it means a separate array of + * indices within the compressed array is necessary for sorting. */ + sort_indices.reinitialize(corners.size()); + std::iota(sort_indices.begin(), sort_indices.end(), 0); + std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) { + return sort_weights[a] < sort_weights[b]; + }); + + const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size()); + corner_of_face[selection_i] = corners[sort_indices[index_in_sort_wrapped]]; + } + }); + + return VArray<int>::ForContainer(std::move(corner_of_face)); + } + + uint64_t hash() const final + { + return 6927982716657; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const auto *typed = dynamic_cast<const CornersOfFaceInput *>(&other)) { + return typed->face_index_ == face_index_ && typed->sort_index_ == sort_index_ && + typed->sort_weight_ == sort_weight_; + } + return false; + } +}; + +static int get_poly_totloop(const MPoly &poly) +{ + return poly.totloop; +} + +class CornersOfFaceCountInput final : public bke::MeshFieldInput { + public: + CornersOfFaceCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Face Corner Count") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_FACE) { + return {}; + } + return VArray<int>::ForDerivedSpan<MPoly, get_poly_totloop>(mesh.polys()); + } + + uint64_t hash() const final + { + return 8345908765432698; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornersOfFaceCountInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> face_index = params.extract_input<Field<int>>("Face Index"); + if (params.output_is_required("Total")) { + params.set_output("Total", + Field<int>(std::make_shared<FieldAtIndexInput>( + face_index, + Field<int>(std::make_shared<CornersOfFaceCountInput>()), + ATTR_DOMAIN_FACE))); + } + if (params.output_is_required("Corner Index")) { + params.set_output("Corner Index", + Field<int>(std::make_shared<CornersOfFaceInput>( + face_index, + params.extract_input<Field<int>>("Sort Index"), + params.extract_input<Field<float>>("Weights")))); + } +} + +} // namespace blender::nodes::node_geo_mesh_topology_corners_of_face_cc + +void register_node_type_geo_mesh_topology_corners_of_face() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_corners_of_face_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_FACE, "Corners of Face", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc new file mode 100644 index 00000000000..9c3d3819a7c --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Vertex Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The vertex to retrieve data from. Defaults to the vertex from the context")); + b.add_input<decl::Float>(N_("Weights")) + .supports_field() + .hide_value() + .description( + N_("Values used to sort corners attached to the vertex. Uses indices by default")); + b.add_input<decl::Int>(N_("Sort Index")) + .min(0) + .supports_field() + .description(N_("Which of the sorted corners to output")); + b.add_output<decl::Int>(N_("Total")) + .dependent_field() + .description(N_("The number of faces or corners connected to each vertex")); + b.add_output<decl::Int>(N_("Corner Index")) + .dependent_field() + .description(N_("A corner connected to the face, chosen by the sort index")); +} + +static void convert_span(const Span<int> src, MutableSpan<int64_t> dst) +{ + for (const int i : src.index_range()) { + dst[i] = src[i]; + } +} + +class CornersOfVertInput final : public bke::MeshFieldInput { + const Field<int> vert_index_; + const Field<int> sort_index_; + const Field<float> sort_weight_; + + public: + CornersOfVertInput(Field<int> vert_index, Field<int> sort_index, Field<float> sort_weight) + : bke::MeshFieldInput(CPPType::get<int>(), "Corner of Vertex"), + vert_index_(std::move(vert_index)), + sort_index_(std::move(sort_index)), + sort_weight_(std::move(sort_weight)) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask mask) const final + { + const IndexRange vert_range(mesh.totvert); + const Span<MLoop> loops = mesh.loops(); + Array<Vector<int>> vert_to_corner_map = mesh_topology::build_vert_to_corner_map(loops, + mesh.totvert); + + const bke::MeshFieldContext context{mesh, domain}; + fn::FieldEvaluator evaluator{context, &mask}; + evaluator.add(vert_index_); + evaluator.add(sort_index_); + evaluator.evaluate(); + const VArray<int> vert_indices = evaluator.get_evaluated<int>(0); + const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1); + + const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER}; + fn::FieldEvaluator corner_evaluator{corner_context, loops.size()}; + corner_evaluator.add(sort_weight_); + corner_evaluator.evaluate(); + const VArray<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0); + + Array<int> corner_of_vertex(mask.min_array_size()); + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + /* Reuse arrays to avoid allocation. */ + Array<int64_t> corner_indices; + Array<float> sort_weights; + Array<int> sort_indices; + + for (const int selection_i : mask.slice(range)) { + const int vert_i = vert_indices[selection_i]; + const int index_in_sort = indices_in_sort[selection_i]; + if (!vert_range.contains(vert_i)) { + corner_of_vertex[selection_i] = 0; + continue; + } + + const Span<int> corners = vert_to_corner_map[vert_i]; + + /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ + corner_indices.reinitialize(corners.size()); + convert_span(corners, corner_indices); + + /* Retrieve a compressed array of weights for each edge. */ + sort_weights.reinitialize(corners.size()); + all_sort_weights.materialize_compressed(IndexMask(corner_indices), + sort_weights.as_mutable_span()); + + /* Sort a separate array of compressed indices corresponding to the compressed weights. + * This allows using `materialize_compressed` to avoid virtual function call overhead + * when accessing values in the sort weights. However, it means a separate array of + * indices within the compressed array is necessary for sorting. */ + sort_indices.reinitialize(corners.size()); + std::iota(sort_indices.begin(), sort_indices.end(), 0); + std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) { + return sort_weights[a] < sort_weights[b]; + }); + + const int index_in_sort_wrapped = mod_i(index_in_sort, corners.size()); + corner_of_vertex[selection_i] = corner_indices[sort_indices[index_in_sort_wrapped]]; + } + }); + + return VArray<int>::ForContainer(std::move(corner_of_vertex)); + } + + uint64_t hash() const final + { + return 3541871368173645; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const auto *typed = dynamic_cast<const CornersOfVertInput *>(&other)) { + return typed->vert_index_ == vert_index_ && typed->sort_index_ == sort_index_ && + typed->sort_weight_ == sort_weight_; + } + return false; + } +}; + +class CornersOfVertCountInput final : public bke::MeshFieldInput { + public: + CornersOfVertCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Vertex Corner Count") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + const Span<MLoop> loops = mesh.loops(); + Array<int> counts(mesh.totvert, 0); + for (const int i : loops.index_range()) { + counts[loops[i].v]++; + } + return VArray<int>::ForContainer(std::move(counts)); + } + + uint64_t hash() const final + { + return 253098745374645; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornersOfVertCountInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> vert_index = params.extract_input<Field<int>>("Vertex Index"); + if (params.output_is_required("Total")) { + params.set_output("Total", + Field<int>(std::make_shared<FieldAtIndexInput>( + vert_index, + Field<int>(std::make_shared<CornersOfVertCountInput>()), + ATTR_DOMAIN_POINT))); + } + if (params.output_is_required("Corner Index")) { + params.set_output("Corner Index", + Field<int>(std::make_shared<CornersOfVertInput>( + vert_index, + params.extract_input<Field<int>>("Sort Index"), + params.extract_input<Field<float>>("Weights")))); + } +} +} // namespace blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc + +void register_node_type_geo_mesh_topology_corners_of_vertex() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_corners_of_vertex_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_CORNERS_OF_VERTEX, "Corners of Vertex", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc new file mode 100644 index 00000000000..866db4cf1b0 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_edges_of_corner_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Corner Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The corner to retrieve data from. Defaults to the corner from the context")); + b.add_output<decl::Int>(N_("Next Edge Index")) + .dependent_field() + .description( + N_("The edge after the corner in the face, in the direction of increasing indices")); + b.add_output<decl::Int>(N_("Previous Edge Index")) + .dependent_field() + .description( + N_("The edge before the corner in the face, in the direction of decreasing indices")); +} + +static int get_loop_edge(const MLoop &loop) +{ + return loop.e; +} + +class CornerNextEdgeFieldInput final : public bke::MeshFieldInput { + public: + CornerNextEdgeFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Next Edge") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CORNER) { + return {}; + } + return VArray<int>::ForDerivedSpan<MLoop, get_loop_edge>(mesh.loops()); + } + + uint64_t hash() const final + { + return 1892753404495; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornerNextEdgeFieldInput *>(&other)) { + return true; + } + return false; + } +}; + +class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput { + public: + CornerPreviousEdgeFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Previous Edge") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CORNER) { + return {}; + } + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + Array<int> corner_to_poly_map = mesh_topology::build_corner_to_poly_map(polys, mesh.totloop); + return VArray<int>::ForFunc( + mesh.totloop, + [polys, loops, corner_to_poly_map = std::move(corner_to_poly_map)](const int corner_i) { + const int poly_i = corner_to_poly_map[corner_i]; + const MPoly &poly = polys[poly_i]; + const int corner_i_prev = mesh_topology::previous_poly_corner(poly, corner_i); + return loops[corner_i_prev].e; + }); + } + + uint64_t hash() const final + { + return 987298345762465; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornerPreviousEdgeFieldInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> corner_index = params.extract_input<Field<int>>("Corner Index"); + if (params.output_is_required("Next Edge Index")) { + params.set_output("Next Edge Index", + Field<int>(std::make_shared<FieldAtIndexInput>( + corner_index, + Field<int>(std::make_shared<CornerNextEdgeFieldInput>()), + ATTR_DOMAIN_CORNER))); + } + if (params.output_is_required("Previous Edge Index")) { + params.set_output("Previous Edge Index", + Field<int>(std::make_shared<FieldAtIndexInput>( + corner_index, + Field<int>(std::make_shared<CornerPreviousEdgeFieldInput>()), + ATTR_DOMAIN_CORNER))); + } +} + +} // namespace blender::nodes::node_geo_mesh_topology_edges_of_corner_cc + +void register_node_type_geo_mesh_topology_edges_of_corner() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_edges_of_corner_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_CORNER, "Edges of Corner", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc new file mode 100644 index 00000000000..11b41ac5605 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Vertex Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The vertex to retrieve data from. Defaults to the vertex from the context")); + b.add_input<decl::Float>(N_("Weights")) + .supports_field() + .hide_value() + .description( + N_("Values used to sort the edges connected to the vertex. Uses indices by default")); + b.add_input<decl::Int>(N_("Sort Index")) + .min(0) + .supports_field() + .description(N_("Which of the sorted edges to output")); + b.add_output<decl::Int>(N_("Total")) + .dependent_field() + .description(N_("The number of edges connected to each vertex")); + b.add_output<decl::Int>(N_("Edge Index")) + .dependent_field() + .description(N_("An edge connected to the face, chosen by the sort index")); +} + +static void convert_span(const Span<int> src, MutableSpan<int64_t> dst) +{ + for (const int i : src.index_range()) { + dst[i] = src[i]; + } +} + +class EdgesOfVertInput final : public bke::MeshFieldInput { + const Field<int> vert_index_; + const Field<int> sort_index_; + const Field<float> sort_weight_; + + public: + EdgesOfVertInput(Field<int> vert_index, Field<int> sort_index, Field<float> sort_weight) + : bke::MeshFieldInput(CPPType::get<int>(), "Edge of Vertex"), + vert_index_(std::move(vert_index)), + sort_index_(std::move(sort_index)), + sort_weight_(std::move(sort_weight)) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask mask) const final + { + const IndexRange vert_range(mesh.totvert); + const Span<MEdge> edges = mesh.edges(); + Array<Vector<int>> vert_to_edge_map = mesh_topology::build_vert_to_edge_map(edges, + mesh.totvert); + + const bke::MeshFieldContext context{mesh, domain}; + fn::FieldEvaluator evaluator{context, &mask}; + evaluator.add(vert_index_); + evaluator.add(sort_index_); + evaluator.evaluate(); + const VArray<int> vert_indices = evaluator.get_evaluated<int>(0); + const VArray<int> indices_in_sort = evaluator.get_evaluated<int>(1); + + const bke::MeshFieldContext edge_context{mesh, ATTR_DOMAIN_EDGE}; + fn::FieldEvaluator edge_evaluator{edge_context, mesh.totedge}; + edge_evaluator.add(sort_weight_); + edge_evaluator.evaluate(); + const VArray<float> all_sort_weights = edge_evaluator.get_evaluated<float>(0); + + Array<int> edge_of_vertex(mask.min_array_size()); + threading::parallel_for(mask.index_range(), 1024, [&](const IndexRange range) { + /* Reuse arrays to avoid allocation. */ + Array<int64_t> edge_indices; + Array<float> sort_weights; + Array<int> sort_indices; + + for (const int selection_i : mask.slice(range)) { + const int vert_i = vert_indices[selection_i]; + const int index_in_sort = indices_in_sort[selection_i]; + if (!vert_range.contains(vert_i)) { + edge_of_vertex[selection_i] = 0; + continue; + } + + const Span<int> edges = vert_to_edge_map[vert_i]; + + /* Retrieve the connected edge indices as 64 bit integers for #materialize_compressed. */ + edge_indices.reinitialize(edges.size()); + convert_span(edges, edge_indices); + + /* Retrieve a compressed array of weights for each edge. */ + sort_weights.reinitialize(edges.size()); + all_sort_weights.materialize_compressed(IndexMask(edge_indices), + sort_weights.as_mutable_span()); + + /* Sort a separate array of compressed indices corresponding to the compressed weights. + * This allows using `materialize_compressed` to avoid virtual function call overhead + * when accessing values in the sort weights. However, it means a separate array of + * indices within the compressed array is necessary for sorting. */ + sort_indices.reinitialize(edges.size()); + std::iota(sort_indices.begin(), sort_indices.end(), 0); + std::stable_sort(sort_indices.begin(), sort_indices.end(), [&](int a, int b) { + return sort_weights[a] < sort_weights[b]; + }); + + const int index_in_sort_wrapped = mod_i(index_in_sort, edges.size()); + edge_of_vertex[selection_i] = edge_indices[sort_indices[index_in_sort_wrapped]]; + } + }); + + return VArray<int>::ForContainer(std::move(edge_of_vertex)); + } + + uint64_t hash() const final + { + return 98762349875636; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const auto *typed = dynamic_cast<const EdgesOfVertInput *>(&other)) { + return typed->vert_index_ == vert_index_ && typed->sort_index_ == sort_index_ && + typed->sort_weight_ == sort_weight_; + } + return false; + } +}; + +class EdgesOfVertCountInput final : public bke::MeshFieldInput { + public: + EdgesOfVertCountInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Face Index") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_POINT) { + return {}; + } + const Span<MEdge> edges = mesh.edges(); + Array<int> counts(mesh.totvert, 0); + for (const int i : edges.index_range()) { + counts[edges[i].v1]++; + counts[edges[i].v2]++; + } + return VArray<int>::ForContainer(std::move(counts)); + } + + uint64_t hash() const final + { + return 436758278618374; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const EdgesOfVertCountInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> vert_index = params.extract_input<Field<int>>("Vertex Index"); + if (params.output_is_required("Total")) { + params.set_output("Total", + Field<int>(std::make_shared<FieldAtIndexInput>( + vert_index, + Field<int>(std::make_shared<EdgesOfVertCountInput>()), + ATTR_DOMAIN_POINT))); + } + if (params.output_is_required("Edge Index")) { + params.set_output("Edge Index", + Field<int>(std::make_shared<EdgesOfVertInput>( + vert_index, + params.extract_input<Field<int>>("Sort Index"), + params.extract_input<Field<float>>("Weights")))); + } +} + +} // namespace blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc + +void register_node_type_geo_mesh_topology_edges_of_vertex() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_edges_of_vertex_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_EDGES_OF_VERTEX, "Edges of Vertex", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc new file mode 100644 index 00000000000..06a69682c90 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_face_of_corner_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Corner Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The corner to retrieve data from. Defaults to the corner from the context")); + b.add_output<decl::Int>(N_("Face Index")) + .dependent_field() + .description(N_("The index of the face the corner is a part of")); + b.add_output<decl::Int>(N_("Index in Face")) + .dependent_field() + .description(N_("The index of the corner starting from the first corner in the face")); +} + +class CornerFaceIndexInput final : public bke::MeshFieldInput { + public: + CornerFaceIndexInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Face Index") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CORNER) { + return {}; + } + return VArray<int>::ForContainer( + mesh_topology::build_corner_to_poly_map(mesh.polys(), mesh.totloop)); + } + + uint64_t hash() const final + { + return 2348712958475728; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + return dynamic_cast<const CornerFaceIndexInput *>(&other) != nullptr; + } +}; + +class CornerIndexInFaceInput final : public bke::MeshFieldInput { + public: + CornerIndexInFaceInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Index In Face") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CORNER) { + return {}; + } + const Span<MPoly> polys = mesh.polys(); + Array<int> corner_to_poly_map = mesh_topology::build_corner_to_poly_map(polys, mesh.totloop); + return VArray<int>::ForFunc( + mesh.totloop, + [polys, corner_to_poly_map = std::move(corner_to_poly_map)](const int corner_i) { + const int poly_i = corner_to_poly_map[corner_i]; + return corner_i - polys[poly_i].loopstart; + }); + } + + uint64_t hash() const final + { + return 97837176448; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornerIndexInFaceInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> corner_index = params.extract_input<Field<int>>("Corner Index"); + if (params.output_is_required("Face Index")) { + params.set_output("Face Index", + Field<int>(std::make_shared<FieldAtIndexInput>( + corner_index, + Field<int>(std::make_shared<CornerFaceIndexInput>()), + ATTR_DOMAIN_CORNER))); + } + if (params.output_is_required("Index in Face")) { + params.set_output("Index in Face", + Field<int>(std::make_shared<FieldAtIndexInput>( + corner_index, + Field<int>(std::make_shared<CornerIndexInFaceInput>()), + ATTR_DOMAIN_CORNER))); + } +} + +} // namespace blender::nodes::node_geo_mesh_topology_face_of_corner_cc + +void register_node_type_geo_mesh_topology_face_of_corner() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_face_of_corner_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_FACE_OF_CORNER, "Face of Corner", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc new file mode 100644 index 00000000000..e1b3572aa75 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Corner Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The corner to retrieve data from. Defaults to the corner from the context")); + b.add_input<decl::Int>(N_("Offset")) + .supports_field() + .description(N_("The number of corners to move around the face before finding the result, " + "circling around the start of the face if necessary")); + b.add_output<decl::Int>(N_("Corner Index")) + .dependent_field() + .description(N_("The index of the offset corner")); +} + +class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput { + const Field<int> corner_index_; + const Field<int> offset_; + + public: + OffsetCornerInFaceFieldInput(Field<int> corner_index, Field<int> offset) + : bke::MeshFieldInput(CPPType::get<int>(), "Offset Corner in Face"), + corner_index_(std::move(corner_index)), + offset_(std::move(offset)) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask mask) const final + { + const IndexRange corner_range(mesh.totloop); + const Span<MPoly> polys = mesh.polys(); + + const bke::MeshFieldContext context{mesh, domain}; + fn::FieldEvaluator evaluator{context, &mask}; + evaluator.add(corner_index_); + evaluator.add(offset_); + evaluator.evaluate(); + const VArray<int> corner_indices = evaluator.get_evaluated<int>(0); + const VArray<int> offsets = evaluator.get_evaluated<int>(1); + + Array<int> corner_to_poly_map = mesh_topology::build_corner_to_poly_map(polys, mesh.totloop); + + Array<int> offset_corners(mask.min_array_size()); + threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) { + for (const int selection_i : range) { + const int corner_i = corner_indices[selection_i]; + const int offset = offsets[selection_i]; + if (!corner_range.contains(corner_i)) { + offset_corners[selection_i] = 0; + continue; + } + + const int poly_i = corner_to_poly_map[corner_i]; + const IndexRange poly_range(polys[poly_i].loopstart, polys[poly_i].totloop); + offset_corners[selection_i] = apply_offset_in_cyclic_range(poly_range, corner_i, offset); + } + }); + + return VArray<int>::ForContainer(std::move(offset_corners)); + } + + uint64_t hash() const final + { + return get_default_hash(offset_); + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (const OffsetCornerInFaceFieldInput *other_field = + dynamic_cast<const OffsetCornerInFaceFieldInput *>(&other)) { + return other_field->corner_index_ == corner_index_ && other_field->offset_ == offset_; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + params.set_output("Corner Index", + Field<int>(std::make_shared<OffsetCornerInFaceFieldInput>( + params.extract_input<Field<int>>("Corner Index"), + params.extract_input<Field<int>>("Offset")))); +} + +} // namespace blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc + +void register_node_type_geo_mesh_topology_offset_corner_in_face() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_offset_corner_in_face_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, + GEO_NODE_MESH_TOPOLOGY_OFFSET_CORNER_IN_FACE, + "Offset Corner in Face", + NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc new file mode 100644 index 00000000000..f0163fa553a --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_mesh.h" + +#include "BLI_task.hh" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Corner Index")) + .implicit_field(implicit_field_inputs::index) + .description( + N_("The corner to retrieve data from. Defaults to the corner from the context")); + b.add_output<decl::Int>(N_("Vertex Index")) + .dependent_field() + .description(N_("The vertex the corner is attached to")); +} + +static int get_loop_vert(const MLoop &loop) +{ + return loop.v; +} + +class CornerVertFieldInput final : public bke::MeshFieldInput { + public: + CornerVertFieldInput() : bke::MeshFieldInput(CPPType::get<int>(), "Corner Vertex") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + if (domain != ATTR_DOMAIN_CORNER) { + return {}; + } + return VArray<int>::ForDerivedSpan<MLoop, get_loop_vert>(mesh.loops()); + } + + uint64_t hash() const final + { + return 30495867093876; + } + + bool is_equal_to(const fn::FieldNode &other) const final + { + if (dynamic_cast<const CornerVertFieldInput *>(&other)) { + return true; + } + return false; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + params.set_output("Vertex Index", + Field<int>(std::make_shared<FieldAtIndexInput>( + params.extract_input<Field<int>>("Corner Index"), + Field<int>(std::make_shared<CornerVertFieldInput>()), + ATTR_DOMAIN_CORNER))); +} + +} // namespace blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc + +void register_node_type_geo_mesh_topology_vertex_of_corner() +{ + namespace file_ns = blender::nodes::node_geo_mesh_topology_vertex_of_corner_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_TOPOLOGY_VERTEX_OF_CORNER, "Vertex of Corner", NODE_CLASS_INPUT); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc index d0b770aadad..51b21b218fe 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc @@ -87,56 +87,6 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -static void try_capture_field_on_geometry(GeometryComponent &component, - const StringRef name, - const eAttrDomain domain, - const GField &field, - std::atomic<bool> &r_failure) -{ - MutableAttributeAccessor attributes = *component.attributes_for_write(); - const int domain_size = attributes.domain_size(domain); - if (domain_size == 0) { - return; - } - - bke::GeometryFieldContext field_context{component, domain}; - const IndexMask mask{IndexMask(domain_size)}; - - const CPPType &type = field.cpp_type(); - const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type); - const bke::AttributeValidator validator = attributes.lookup_validator(name); - - /* Could avoid allocating a new buffer if: - * - We are writing to an attribute that exists already with the correct domain and type. - * - The field does not depend on that attribute (we can't easily check for that yet). */ - void *buffer = MEM_mallocN(type.size() * domain_size, __func__); - - fn::FieldEvaluator evaluator{field_context, &mask}; - evaluator.add_with_destination(validator.validate_field_if_necessary(field), - GMutableSpan{type, buffer, domain_size}); - evaluator.evaluate(); - - if (GAttributeWriter attribute = attributes.lookup_for_write(name)) { - if (attribute.domain == domain && attribute.varray.type() == type) { - attribute.varray.set_all(buffer); - attribute.finish(); - type.destruct_n(buffer, domain_size); - MEM_freeN(buffer); - return; - } - } - attributes.remove(name); - if (attributes.add(name, domain, data_type, bke::AttributeInitMoveArray{buffer})) { - return; - } - - /* If the name corresponds to a builtin attribute, removing the attribute might fail if - * it's required, and adding the attribute might fail if the domain or type is incorrect. */ - type.destruct_n(buffer, domain_size); - MEM_freeN(buffer); - r_failure = true; -} - static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -192,7 +142,9 @@ static void node_geo_exec(GeoNodeExecParams params) if (geometry_set.has_instances()) { GeometryComponent &component = geometry_set.get_component_for_write( GEO_COMPONENT_TYPE_INSTANCES); - try_capture_field_on_geometry(component, name, domain, field, failure); + if (!bke::try_capture_field_on_geometry(component, name, domain, field)) { + failure.store(true); + } } } else { @@ -201,7 +153,9 @@ static void node_geo_exec(GeoNodeExecParams params) {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}) { if (geometry_set.has(type)) { GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, name, domain, field, failure); + if (!bke::try_capture_field_on_geometry(component, name, domain, field)) { + failure.store(true); + } } } }); diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc index 0294acb8cd9..ae6d1210de9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc @@ -118,6 +118,11 @@ class PackIslandsFieldInput final : public bke::MeshFieldInput { { return construct_uv_gvarray(mesh, selection_field, uv_field, rotate, margin, domain); } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_CORNER; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc index c18745731ed..86a3758a35b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc @@ -160,6 +160,11 @@ class UnwrapFieldInput final : public bke::MeshFieldInput { { return construct_uv_gvarray(mesh, selection, seam, fill_holes, margin, method, domain); } + + std::optional<eAttrDomain> preferred_domain(const Mesh & /*mesh*/) const override + { + return ATTR_DOMAIN_CORNER; + } }; static void node_geo_exec(GeoNodeExecParams params) diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 2c8a70901f8..ec900a41bbc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -6,7 +6,7 @@ #include "UI_resources.h" #include "ED_node.h" -#include "ED_spreadsheet.h" +#include "ED_viewer_path.hh" #include "NOD_socket_search_link.hh" @@ -30,12 +30,18 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__); data->data_type = CD_PROP_FLOAT; + data->domain = ATTR_DOMAIN_AUTO; node->storage = data; } static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); +} + +static void node_layout_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } @@ -79,7 +85,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) SpaceNode *snode = CTX_wm_space_node(¶ms.C); Main *bmain = CTX_data_main(¶ms.C); ED_node_set_active(bmain, snode, ¶ms.node_tree, &viewer_node, nullptr); - ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node); + ed::viewer_path::activate_geometry_node(*bmain, *snode, viewer_node); }; const std::optional<eCustomDataType> type = node_socket_to_custom_data_type( @@ -132,7 +138,9 @@ void register_node_type_geo_viewer() node_type_update(&ntype, file_ns::node_update); node_type_init(&ntype, file_ns::node_init); ntype.declare = file_ns::node_declare; - ntype.draw_buttons_ex = file_ns::node_layout; + ntype.draw_buttons = file_ns::node_layout; + ntype.draw_buttons_ex = file_ns::node_layout_ex; ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 7a78547b10b..eca0bef3e65 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -543,19 +543,53 @@ class LazyFunctionForViewerNode : public LazyFunction { } GeometrySet geometry = params.extract_input<GeometrySet>(0); + const NodeGeometryViewer *storage = static_cast<NodeGeometryViewer *>(bnode_.storage); - GField field; if (use_field_input_) { const void *value_or_field = params.try_get_input_data_ptr(1); BLI_assert(value_or_field != nullptr); const ValueOrFieldCPPType &value_or_field_type = static_cast<const ValueOrFieldCPPType &>( *inputs_[1].type); - field = value_or_field_type.as_field(value_or_field); + GField field = value_or_field_type.as_field(value_or_field); + const eAttrDomain domain = eAttrDomain(storage->domain); + const StringRefNull viewer_attribute_name = ".viewer"; + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry.has_instances()) { + GeometryComponent &component = geometry.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + bke::try_capture_field_on_geometry( + component, viewer_attribute_name, ATTR_DOMAIN_INSTANCE, field); + } + } + else { + geometry.modify_geometry_sets([&](GeometrySet &geometry) { + for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE}) { + if (geometry.has(type)) { + GeometryComponent &component = geometry.get_component_for_write(type); + eAttrDomain used_domain = domain; + if (used_domain == ATTR_DOMAIN_AUTO) { + if (const std::optional<eAttrDomain> detected_domain = + bke::try_detect_field_domain(component, field)) { + used_domain = *detected_domain; + } + else { + used_domain = type == GEO_COMPONENT_TYPE_MESH ? ATTR_DOMAIN_CORNER : + ATTR_DOMAIN_POINT; + } + } + bke::try_capture_field_on_geometry( + component, viewer_attribute_name, used_domain, field); + } + } + }); + } } geo_eval_log::GeoTreeLogger &tree_logger = user_data->modifier_data->eval_log->get_local_tree_logger(*user_data->compute_context); - tree_logger.log_viewer_node(bnode_, geometry, field); + tree_logger.log_viewer_node(bnode_, std::move(geometry)); } }; @@ -1037,6 +1071,12 @@ struct GeometryNodesLazyFunctionGraphBuilder { void insert_links_from_socket(const bNodeSocket &from_bsocket, lf::OutputSocket &from_lf_socket) { + const bNode &from_bnode = from_bsocket.owner_node(); + if (this->is_dangling_reroute_input(from_bnode)) { + /* Dangling reroutes should not be used as source of values. */ + return; + } + const Span<const bNodeLink *> links_from_bsocket = from_bsocket.directly_linked_links(); struct TypeWithLinks { @@ -1132,6 +1172,33 @@ struct GeometryNodesLazyFunctionGraphBuilder { } } + bool is_dangling_reroute_input(const bNode &node) + { + if (!node.is_reroute()) { + return false; + } + const bNode *iter_node = &node; + /* It is guaranteed at a higher level that there are no link cycles. */ + while (true) { + const Span<const bNodeLink *> links = iter_node->input_socket(0).directly_linked_links(); + BLI_assert(links.size() <= 1); + if (links.is_empty()) { + return true; + } + const bNodeLink &link = *links[0]; + if (!link.is_available()) { + return false; + } + if (link.is_muted()) { + return false; + } + iter_node = link.fromnode; + if (!iter_node->is_reroute()) { + return false; + } + } + } + lf::OutputSocket *insert_type_conversion_if_necessary( lf::OutputSocket &from_socket, const CPPType &to_type, diff --git a/source/blender/nodes/intern/geometry_nodes_log.cc b/source/blender/nodes/intern/geometry_nodes_log.cc index aadf69f10c5..909f7779e95 100644 --- a/source/blender/nodes/intern/geometry_nodes_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_log.cc @@ -6,12 +6,15 @@ #include "BKE_compute_contexts.hh" #include "BKE_curves.hh" #include "BKE_node_runtime.hh" +#include "BKE_viewer_path.h" #include "FN_field_cpp_type.hh" #include "DNA_modifier_types.h" #include "DNA_space_types.h" +#include "ED_viewer_path.hh" + namespace blender::nodes::geo_eval_log { using fn::FieldInput; @@ -188,13 +191,10 @@ void GeoTreeLogger::log_value(const bNode &node, const bNodeSocket &socket, cons } } -void GeoTreeLogger::log_viewer_node(const bNode &viewer_node, - const GeometrySet &geometry, - const GField &field) +void GeoTreeLogger::log_viewer_node(const bNode &viewer_node, GeometrySet geometry) { destruct_ptr<ViewerNodeLog> log = this->allocator->construct<ViewerNodeLog>(); - log->geometry = geometry; - log->field = field; + log->geometry = std::move(geometry); log->geometry.ensure_owns_direct_data(); this->viewer_node_logs.append({this->allocator->copy_string(viewer_node.name), std::move(log)}); } @@ -545,29 +545,17 @@ GeoTreeLog *GeoModifierLog::get_tree_log_for_node_editor(const SpaceNode &snode) return &modifier_log->get_tree_log(compute_context_builder.hash()); } -const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_spreadsheet( - const SpaceSpreadsheet &sspreadsheet) +const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_path(const ViewerPath &viewer_path) { - Vector<const SpreadsheetContext *> context_path = sspreadsheet.context_path; - if (context_path.size() < 3) { - return nullptr; - } - if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) { - return nullptr; - } - if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) { - return nullptr; - } - const SpreadsheetContextObject *object_context = - reinterpret_cast<const SpreadsheetContextObject *>(context_path[0]); - const SpreadsheetContextModifier *modifier_context = - reinterpret_cast<const SpreadsheetContextModifier *>(context_path[1]); - if (object_context->object == nullptr) { + const std::optional<ed::viewer_path::ViewerPathForGeometryNodesViewer> parsed_path = + ed::viewer_path::parse_geometry_nodes_viewer(viewer_path); + if (!parsed_path.has_value()) { return nullptr; } + const Object *object = parsed_path->object; NodesModifierData *nmd = nullptr; - LISTBASE_FOREACH (ModifierData *, md, &object_context->object->modifiers) { - if (STREQ(md->name, modifier_context->modifier_name)) { + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->name == parsed_path->modifier_name) { if (md->type == eModifierType_Nodes) { nmd = reinterpret_cast<NodesModifierData *>(md); } @@ -583,27 +571,16 @@ const ViewerNodeLog *GeoModifierLog::find_viewer_node_log_for_spreadsheet( static_cast<nodes::geo_eval_log::GeoModifierLog *>(nmd->runtime_eval_log); ComputeContextBuilder compute_context_builder; - compute_context_builder.push<bke::ModifierComputeContext>(modifier_context->modifier_name); - for (const SpreadsheetContext *context : context_path.as_span().drop_front(2).drop_back(1)) { - if (context->type != SPREADSHEET_CONTEXT_NODE) { - return nullptr; - } - const SpreadsheetContextNode &node_context = *reinterpret_cast<const SpreadsheetContextNode *>( - context); - compute_context_builder.push<bke::NodeGroupComputeContext>(node_context.node_name); + compute_context_builder.push<bke::ModifierComputeContext>(parsed_path->modifier_name); + for (const StringRef group_node_name : parsed_path->group_node_names) { + compute_context_builder.push<bke::NodeGroupComputeContext>(group_node_name); } const ComputeContextHash context_hash = compute_context_builder.hash(); nodes::geo_eval_log::GeoTreeLog &tree_log = modifier_log->get_tree_log(context_hash); tree_log.ensure_viewer_node_logs(); - const SpreadsheetContext *last_context = context_path.last(); - if (last_context->type != SPREADSHEET_CONTEXT_NODE) { - return nullptr; - } - const SpreadsheetContextNode &last_node_context = - *reinterpret_cast<const SpreadsheetContextNode *>(last_context); const ViewerNodeLog *viewer_log = tree_log.viewer_node_logs.lookup_default( - last_node_context.node_name, nullptr); + parsed_path->viewer_node_name, nullptr); return viewer_log; } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 333ab9487d1..3978f7f37cc 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -909,6 +909,11 @@ static int BPy_IDGroup_Iter_clear(BPy_IDGroup_Iter *self) return 0; } +static int BPy_IDGroup_Iter_is_gc(BPy_IDGroup_Iter *self) +{ + return (self->group != NULL); +} + static bool BPy_Group_Iter_same_size_or_raise_error(BPy_IDGroup_Iter *self) { if (self->len_init == self->group->prop->len) { @@ -1000,6 +1005,7 @@ static void IDGroup_Iter_init_type(void) SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC); SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_Iter_traverse); SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_Iter_clear); + SHARED_MEMBER_SET(tp_is_gc, (inquiry)BPy_IDGroup_Iter_is_gc); SHARED_MEMBER_SET(tp_iter, PyObject_SelfIter); #undef SHARED_MEMBER_SET @@ -1015,6 +1021,7 @@ static PyObject *IDGroup_Iter_New_WithType(BPy_IDProperty *group, iter->group = group; if (group != NULL) { Py_INCREF(group); + BLI_assert(!PyObject_GC_IsTracked((PyObject *)iter)); PyObject_GC_Track(iter); iter->cur = (reversed ? group->prop->data.group.last : group->prop->data.group.first); iter->len_init = group->prop->len; @@ -1086,6 +1093,11 @@ static int BPy_IDGroup_View_clear(BPy_IDGroup_View *self) return 0; } +static int BPy_IDGroup_View_is_gc(BPy_IDGroup_View *self) +{ + return (self->group != NULL); +} + /* View Specific API's (Key/Value/Items). */ static PyObject *BPy_Group_ViewKeys_iter(BPy_IDGroup_View *self) @@ -1233,6 +1245,7 @@ static void IDGroup_View_init_type(void) SHARED_MEMBER_SET(tp_flags, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC); SHARED_MEMBER_SET(tp_traverse, (traverseproc)BPy_IDGroup_View_traverse); SHARED_MEMBER_SET(tp_clear, (inquiry)BPy_IDGroup_View_clear); + SHARED_MEMBER_SET(tp_is_gc, (inquiry)BPy_IDGroup_View_is_gc); SHARED_MEMBER_SET(tp_methods, BPy_IDGroup_View_methods); #undef SHARED_MEMBER_SET @@ -2087,6 +2100,7 @@ static BPy_IDGroup_View *IDGroup_View_New_WithType(BPy_IDProperty *group, PyType iter->group = group; if (group != NULL) { Py_INCREF(group); + BLI_assert(!PyObject_GC_IsTracked((PyObject *)iter)); PyObject_GC_Track(iter); } return iter; diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c index 879e1c0ce8b..a36b1dfd1b5 100644 --- a/source/blender/python/gpu/gpu_py_batch.c +++ b/source/blender/python/gpu/gpu_py_batch.c @@ -111,6 +111,7 @@ static PyObject *pygpu_batch__tp_new(PyTypeObject *UNUSED(type), PyObject *args, Py_INCREF(py_indexbuf); } + BLI_assert(!PyObject_GC_IsTracked((PyObject *)ret)); PyObject_GC_Track(ret); #endif @@ -273,6 +274,11 @@ static int pygpu_batch__tp_clear(BPyGPUBatch *self) return 0; } +static int pygpu_batch__tp_is_gc(BPyGPUBatch *self) +{ + return self->references != NULL; +} + #endif static void pygpu_batch__tp_dealloc(BPyGPUBatch *self) @@ -313,6 +319,7 @@ PyTypeObject BPyGPUBatch_Type = { .tp_doc = pygpu_batch__tp_doc, .tp_traverse = (traverseproc)pygpu_batch__tp_traverse, .tp_clear = (inquiry)pygpu_batch__tp_clear, + .tp_is_gc = (inquiry)pygpu_batch__tp_is_gc, #else .tp_flags = Py_TPFLAGS_DEFAULT, #endif diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c index 551eb4451c2..30a434f8667 100644 --- a/source/blender/python/gpu/gpu_py_buffer.c +++ b/source/blender/python/gpu/gpu_py_buffer.c @@ -153,6 +153,7 @@ static BPyGPUBuffer *pygpu_buffer_make_from_data(PyObject *parent, if (parent) { Py_INCREF(parent); buffer->parent = parent; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)buffer)); PyObject_GC_Track(buffer); } return buffer; @@ -422,6 +423,11 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args return (PyObject *)buffer; } +static int pygpu_buffer__tp_is_gc(BPyGPUBuffer *self) +{ + return self->parent != NULL; +} + /* BPyGPUBuffer sequence methods */ static int pygpu_buffer__sq_length(BPyGPUBuffer *self) @@ -677,6 +683,7 @@ PyTypeObject BPyGPU_BufferType = { .tp_methods = pygpu_buffer__tp_methods, .tp_getset = pygpu_buffer_getseters, .tp_new = pygpu_buffer__tp_new, + .tp_is_gc = (inquiry)pygpu_buffer__tp_is_gc, }; static size_t pygpu_buffer_calc_size(const int format, diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index ff84a5c75d7..b6c75f7a793 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -307,6 +307,7 @@ static PyObject *bpy_prop_deferred_data_CreatePyObject(PyObject *fn, PyObject *k Py_INCREF(kw); } self->kw = kw; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); return (PyObject *)self; } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 8cc66854c77..56ad05d5501 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1174,6 +1174,7 @@ static void pyrna_struct_reference_set(BPy_StructRNA *self, PyObject *reference) if (reference) { self->reference = reference; Py_INCREF(reference); + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } } diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c index a3e865f4846..3c7ec3bddc3 100644 --- a/source/blender/python/intern/bpy_rna_data.c +++ b/source/blender/python/intern/bpy_rna_data.c @@ -183,6 +183,7 @@ static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self) self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); return (PyObject *)self->data_rna; diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 2bf608fd1d6..c4c0659100b 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -697,6 +697,18 @@ int BaseMathObject_clear(BaseMathObject *self) return 0; } +/** Only to validate assumptions when debugging. */ +#ifndef NDEBUG +static bool BaseMathObject_is_tracked(BaseMathObject *self) +{ + PyObject *cb_user = self->cb_user; + self->cb_user = (void *)(uintptr_t)-1; + bool is_tracked = PyObject_GC_IsTracked((PyObject *)self); + self->cb_user = cb_user; + return is_tracked; +} +#endif /* NDEBUG */ + void BaseMathObject_dealloc(BaseMathObject *self) { /* only free non wrapped */ @@ -705,13 +717,48 @@ void BaseMathObject_dealloc(BaseMathObject *self) } if (self->cb_user) { + BLI_assert(BaseMathObject_is_tracked(self) == true); PyObject_GC_UnTrack(self); BaseMathObject_clear(self); } + else if (!BaseMathObject_CheckExact(self)) { + /* Sub-classed types get an extra track (in Pythons internal `subtype_dealloc` function). */ + BLI_assert(BaseMathObject_is_tracked(self) == true); + PyObject_GC_UnTrack(self); + BLI_assert(BaseMathObject_is_tracked(self) == false); + } Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); /* breaks sub-types. */ } +int BaseMathObject_is_gc(BaseMathObject *self) +{ + return self->cb_user != NULL; +} + +PyObject *_BaseMathObject_new_impl(PyTypeObject *root_type, PyTypeObject *base_type) +{ + PyObject *obj; + if (ELEM(base_type, NULL, root_type)) { + obj = _PyObject_GC_New(root_type); + if (obj) { + BLI_assert(BaseMathObject_is_tracked((BaseMathObject *)obj) == false); + } + } + else { + /* Calls Generic allocation function which always tracks + * (because `root_type` is flagged for GC). */ + obj = base_type->tp_alloc(base_type, 0); + if (obj) { + BLI_assert(BaseMathObject_is_tracked((BaseMathObject *)obj) == true); + PyObject_GC_UnTrack(obj); + BLI_assert(BaseMathObject_is_tracked((BaseMathObject *)obj) == false); + } + } + + return obj; +} + /*----------------------------MODULE INIT-------------------------*/ static struct PyMethodDef M_Mathutils_methods[] = { {NULL, NULL, 0, NULL}, diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 27d84a80601..f4beaf92ad4 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -17,9 +17,10 @@ extern char BaseMathObject_is_frozen_doc[]; extern char BaseMathObject_is_valid_doc[]; extern char BaseMathObject_owner_doc[]; +PyObject *_BaseMathObject_new_impl(PyTypeObject *root_type, PyTypeObject *base_type); + #define BASE_MATH_NEW(struct_name, root_type, base_type) \ - ((struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : \ - _PyObject_GC_New(&(root_type))))) + ((struct_name *)_BaseMathObject_new_impl(&root_type, base_type)) /** #BaseMathObject.flag */ enum { @@ -76,6 +77,7 @@ PyObject *BaseMathObject_freeze(BaseMathObject *self); int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg); int BaseMathObject_clear(BaseMathObject *self); void BaseMathObject_dealloc(BaseMathObject *self); +int BaseMathObject_is_gc(BaseMathObject *self); PyMODINIT_FUNC PyInit_mathutils(void); diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index a66178baefc..432b1709d82 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -1156,7 +1156,7 @@ PyTypeObject color_Type = { NULL, /* tp_alloc */ Color_new, /* tp_new */ NULL, /* tp_free */ - NULL, /* tp_is_gc */ + (inquiry)BaseMathObject_is_gc, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ @@ -1235,6 +1235,7 @@ PyObject *Color_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar cb_sub self->cb_user = cb_user; self->cb_type = cb_type; self->cb_subtype = cb_subtype; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c index 78c98d8f482..8da2b20d9a5 100644 --- a/source/blender/python/mathutils/mathutils_Euler.c +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -821,7 +821,7 @@ PyTypeObject euler_Type = { NULL, /* tp_alloc */ Euler_new, /* tp_new */ NULL, /* tp_free */ - NULL, /* tp_is_gc */ + (inquiry)BaseMathObject_is_gc, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ @@ -904,6 +904,7 @@ PyObject *Euler_CreatePyObject_cb(PyObject *cb_user, self->cb_user = cb_user; self->cb_type = cb_type; self->cb_subtype = cb_subtype; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index af01c571fe9..51362ec595f 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -3366,7 +3366,7 @@ PyTypeObject matrix_Type = { NULL, /*tp_alloc*/ Matrix_new, /*tp_new*/ NULL, /*tp_free*/ - NULL, /*tp_is_gc*/ + (inquiry)BaseMathObject_is_gc, /*tp_is_gc*/ NULL, /*tp_bases*/ NULL, /*tp_mro*/ NULL, /*tp_cache*/ @@ -3474,6 +3474,7 @@ PyObject *Matrix_CreatePyObject_cb( self->cb_user = cb_user; self->cb_type = cb_type; self->cb_subtype = cb_subtype; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } return (PyObject *)self; diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 892f38d22ae..d5519676081 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -1724,7 +1724,7 @@ PyTypeObject quaternion_Type = { NULL, /* tp_alloc */ Quaternion_new, /* tp_new */ NULL, /* tp_free */ - NULL, /* tp_is_gc */ + (inquiry)BaseMathObject_is_gc, /* tp_is_gc */ NULL, /* tp_bases */ NULL, /* tp_mro */ NULL, /* tp_cache */ @@ -1800,6 +1800,7 @@ PyObject *Quaternion_CreatePyObject_cb(PyObject *cb_user, uchar cb_type, uchar c self->cb_user = cb_user; self->cb_type = cb_type; self->cb_subtype = cb_subtype; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index 161f05deafd..654ddcb1237 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -3265,8 +3265,8 @@ PyTypeObject vector_Type = { /* Low-level free-memory routine */ NULL, /* freefunc tp_free; */ /* For PyObject_IS_GC */ - NULL, /* inquiry tp_is_gc; */ - NULL, /* PyObject *tp_bases; */ + (inquiry)BaseMathObject_is_gc, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ /* method resolution order */ NULL, /* PyObject *tp_mro; */ NULL, /* PyObject *tp_cache; */ @@ -3357,6 +3357,7 @@ PyObject *Vector_CreatePyObject_cb(PyObject *cb_user, int vec_num, uchar cb_type self->cb_user = cb_user; self->cb_type = cb_type; self->cb_subtype = cb_subtype; + BLI_assert(!PyObject_GC_IsTracked((PyObject *)self)); PyObject_GC_Track(self); } diff --git a/source/blender/render/intern/engine.cc b/source/blender/render/intern/engine.cc index 9b5a5fff6b0..10a4788ef77 100644 --- a/source/blender/render/intern/engine.cc +++ b/source/blender/render/intern/engine.cc @@ -152,7 +152,6 @@ static void engine_depsgraph_free(RenderEngine *engine) /* Need GPU context since this might free GPU buffers. */ const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT); if (use_gpu_context) { - GPU_render_begin(); DRW_render_context_enable(engine->re); } @@ -161,7 +160,6 @@ static void engine_depsgraph_free(RenderEngine *engine) if (use_gpu_context) { DRW_render_context_disable(engine->re); - GPU_render_end(); } } } @@ -758,7 +756,6 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer) /* Need GPU context since this might free GPU buffers. */ const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph; if (use_gpu_context) { - GPU_render_begin(); DRW_render_context_enable(engine->re); } @@ -766,7 +763,6 @@ static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer) if (use_gpu_context) { DRW_render_context_disable(engine->re); - GPU_render_end(); } } else { @@ -939,7 +935,6 @@ static void engine_render_view_layer(Render *re, if (use_engine) { const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT); if (use_gpu_context) { - GPU_render_begin(); DRW_render_context_enable(engine->re); } @@ -955,7 +950,6 @@ static void engine_render_view_layer(Render *re, if (use_gpu_context) { DRW_render_context_disable(engine->re); - GPU_render_end(); } } diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index e17fa8faad6..3c907659049 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -14,6 +14,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_customdata.h" #include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -44,7 +45,7 @@ class TextureMarginMap { /** Maps UV-edges to their corresponding UV-edge. */ Vector<int> loop_adjacency_map_; /** Maps UV-edges to their corresponding polygon. */ - Vector<int> loop_to_poly_map_; + Array<int> loop_to_poly_map_; int w_, h_; float uv_offset_[2]; @@ -289,13 +290,8 @@ class TextureMarginMap { void build_tables() { - loop_to_poly_map_.resize(totloop_); - for (int i = 0; i < totpoly_; i++) { - for (int j = 0; j < mpoly_[i].totloop; j++) { - int l = j + mpoly_[i].loopstart; - loop_to_poly_map_[l] = i; - } - } + loop_to_poly_map_ = blender::mesh_topology::build_corner_to_poly_map({mpoly_, totpoly_}, + totloop_); loop_adjacency_map_.resize(totloop_, -1); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index ba1d8d3ccb7..e25169109e7 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -353,6 +353,8 @@ typedef struct wmNotifier { #define NC_LIGHTPROBE (26 << 24) /* Changes to asset data in the current .blend. */ #define NC_ASSET (27 << 24) +/* Changes to the active viewer path. */ +#define NC_VIEWER_PATH (28 << 24) /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index d88a5a5a18b..38e37d73eb9 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -632,6 +632,7 @@ void wm_event_do_notifiers(bContext *C) win->screen->id.name + 2, note->category); # endif + ED_workspace_do_listen(C, note); ED_screen_do_listen(C, note); LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 05577406b48..13a311cb55c 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1157,10 +1157,10 @@ elseif(APPLE) ) if(WITH_BLENDER_THUMBNAILER) - install( - TARGETS blender-thumbnailer - DESTINATION Blender.app/Contents/MacOS/ - ) + install( + TARGETS blender-thumbnailer + DESTINATION Blender.app/Contents/MacOS/ + ) endif() if(PLATFORM_BUNDLED_LIBRARIES AND TARGETDIR_LIB) diff --git a/source/tools b/source/tools -Subproject 2a541f164a222ef7bcd036d37687738acee8d94 +Subproject 2ab59df2c987d383a7ed9dbcd4f3897bbba7c12 diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py index b67bc22102c..8c90a1f93b8 100644 --- a/tests/python/bl_load_addons.py +++ b/tests/python/bl_load_addons.py @@ -14,7 +14,7 @@ import sys import importlib BLACKLIST_DIRS = ( - os.path.join(bpy.utils.resource_path('USER'), "scripts"), + bpy.utils.user_resource('SCRIPTS'), ) + tuple(addon_utils.paths()[1:]) BLACKLIST_ADDONS = set() diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py index 784d8984935..48087179554 100644 --- a/tests/python/bl_load_py_modules.py +++ b/tests/python/bl_load_py_modules.py @@ -42,7 +42,7 @@ if not bpy.app.build_options.xr_openxr: BLACKLIST.add("viewport_vr_preview") BLACKLIST_DIRS = ( - os.path.join(bpy.utils.resource_path('USER'), "scripts"), + os.path.join(bpy.utils.user_resource('SCRIPTS')), ) + tuple(addon_utils.paths()[1:]) diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py index ccb0814e5eb..19e1d41d8cf 100644 --- a/tests/python/bl_run_operators.py +++ b/tests/python/bl_run_operators.py @@ -83,7 +83,7 @@ op_blacklist = ( "object.voxel_remesh", "mesh.paint_mask_slice", "paint.mask_flood_fill", - "sculpt.dirty_mask", + "sculpt.mask_from_cavity", # TODO: use empty temp dir to avoid behavior depending on local setup. "view3d.pastebuffer", # Needs active window. |