Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/device/opencl/memory_manager.cpp2
-rw-r--r--intern/cycles/device/opencl/opencl.h1
-rw-r--r--intern/cycles/device/opencl/opencl_split.cpp19
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py23
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py3
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py6
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py4
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py4
-rw-r--r--release/scripts/startup/bl_ui/space_time.py4
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py10
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py22
-rw-r--r--source/blender/blenkernel/BKE_paint.h3
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h4
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c41
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect_edges.c2
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h2
-rw-r--r--source/blender/draw/DRW_engine.h1
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_mesh.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_data.c23
-rw-r--r--source/blender/draw/engines/workbench/workbench_deferred.c2
-rw-r--r--source/blender/draw/engines/workbench/workbench_forward.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c10
-rw-r--r--source/blender/draw/intern/draw_manager_text.c6
-rw-r--r--source/blender/draw/intern/draw_manager_text.h2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c11
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c3
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c48
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h15
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h3
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c3
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c43
-rw-r--r--source/blender/makesrna/intern/rna_workspace_api.c4
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weld.c1910
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c29
47 files changed, 2146 insertions, 169 deletions
diff --git a/intern/cycles/device/opencl/memory_manager.cpp b/intern/cycles/device/opencl/memory_manager.cpp
index f85aadce1c2..06d4746a86e 100644
--- a/intern/cycles/device/opencl/memory_manager.cpp
+++ b/intern/cycles/device/opencl/memory_manager.cpp
@@ -251,7 +251,7 @@ void MemoryManager::set_kernel_arg_buffers(cl_kernel kernel, cl_uint *narg)
device->kernel_set_args(kernel, (*narg)++, *device_buffer.buffer);
}
else {
- device->kernel_set_args(kernel, (*narg)++, device->null_mem);
+ device->kernel_set_args(kernel, (*narg)++, 0);
}
}
}
diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h
index 82b961b8de7..61b1e3e3b6b 100644
--- a/intern/cycles/device/opencl/opencl.h
+++ b/intern/cycles/device/opencl/opencl.h
@@ -381,7 +381,6 @@ class OpenCLDevice : public Device {
ConstMemMap const_mem_map;
MemMap mem_map;
- device_ptr null_mem;
bool device_initialized;
string platform_name;
diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp
index eea5cf2fb8a..76f9ce7a18f 100644
--- a/intern/cycles/device/opencl/opencl_split.cpp
+++ b/intern/cycles/device/opencl/opencl_split.cpp
@@ -611,7 +611,6 @@ OpenCLDevice::OpenCLDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, b
cdDevice = NULL;
cxContext = NULL;
cqCommandQueue = NULL;
- null_mem = 0;
device_initialized = false;
textures_need_update = true;
use_preview_kernels = !background;
@@ -662,12 +661,6 @@ OpenCLDevice::OpenCLDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, b
return;
}
- null_mem = (device_ptr)clCreateBuffer(cxContext, CL_MEM_READ_ONLY, 1, NULL, &ciErr);
- if (opencl_error(ciErr)) {
- opencl_error("OpenCL: Error creating memory buffer for NULL");
- return;
- }
-
/* Allocate this right away so that texture_info
* is placed at offset 0 in the device memory buffers. */
texture_info.resize(1);
@@ -689,9 +682,6 @@ OpenCLDevice::~OpenCLDevice()
memory_manager.free();
- if (null_mem)
- clReleaseMemObject(CL_MEM_PTR(null_mem));
-
ConstMemMap::iterator mt;
for (mt = const_mem_map.begin(); mt != const_mem_map.end(); mt++) {
delete mt->second;
@@ -962,7 +952,7 @@ void OpenCLDevice::mem_alloc(device_memory &mem)
opencl_assert_err(ciErr, "clCreateBuffer");
}
else {
- mem.device_pointer = null_mem;
+ mem.device_pointer = 0;
}
stats.mem_alloc(size);
@@ -1084,7 +1074,7 @@ void OpenCLDevice::mem_free(device_memory &mem)
}
else {
if (mem.device_pointer) {
- if (mem.device_pointer != null_mem) {
+ if (mem.device_pointer != 0) {
opencl_assert(clReleaseMemObject(CL_MEM_PTR(mem.device_pointer)));
}
mem.device_pointer = 0;
@@ -1120,7 +1110,7 @@ device_ptr OpenCLDevice::mem_alloc_sub_ptr(device_memory &mem, int offset, int s
void OpenCLDevice::mem_free_sub_ptr(device_ptr device_pointer)
{
- if (device_pointer && device_pointer != null_mem) {
+ if (device_pointer != 0) {
opencl_assert(clReleaseMemObject(CL_MEM_PTR(device_pointer)));
}
}
@@ -1239,8 +1229,7 @@ void OpenCLDevice::set_kernel_arg_mem(cl_kernel kernel, cl_uint *narg, const cha
ptr = CL_MEM_PTR(i->second);
}
else {
- /* work around NULL not working, even though the spec says otherwise */
- ptr = CL_MEM_PTR(null_mem);
+ ptr = 0;
}
opencl_assert(clSetKernelArg(kernel, (*narg)++, sizeof(ptr), (void *)&ptr));
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 7a5f40de483..173e7e5f332 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -168,6 +168,13 @@ def _template_items_context_menu(menu, key_args_primary):
]
+def _template_items_context_panel(menu, key_args_primary):
+ return [
+ op_panel(menu, kmi_args)
+ for kmi_args in (key_args_primary, {"type": 'APP', "value": 'PRESS'})
+ ]
+
+
def _template_space_region_type_toggle(*, toolbar_key=None, sidebar_key=None):
items = []
if toolbar_key is not None:
@@ -3154,7 +3161,7 @@ def km_grease_pencil_stroke_paint_mode(params):
("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
# Draw context menu
- *_template_items_context_menu("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
])
return keymap
@@ -3237,7 +3244,7 @@ def km_grease_pencil_stroke_paint_erase(params):
return keymap
-def km_grease_pencil_stroke_paint_fill(_params):
+def km_grease_pencil_stroke_paint_fill(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Fill)",
@@ -3258,7 +3265,7 @@ def km_grease_pencil_stroke_paint_fill(_params):
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'DRAW'), ("wait_for_input", False), ("disable_straight", True), ("disable_fill", True)]}),
# Lasso select
- ("gpencil.select_lasso", {"type": _params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
+ ("gpencil.select_lasso", {"type": params.action_tweak, "value": 'ANY', "ctrl": True, "alt": True}, None),
])
return keymap
@@ -3287,7 +3294,7 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Display
*_grease_pencil_display(),
# Context menu
- *_template_items_context_menu("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
])
return keymap
@@ -3715,7 +3722,7 @@ def km_image_paint(params):
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
("wm.context_menu_enum", {"type": 'E', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.image_paint.brush.stroke_method')]}),
- *_template_items_context_menu("VIEW3D_PT_paint_texture_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_texture_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3764,7 +3771,7 @@ def km_vertex_paint(params):
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
("wm.context_menu_enum", {"type": 'E', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.vertex_paint.brush.stroke_method')]}),
- *_template_items_context_menu("VIEW3D_PT_paint_vertex_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_vertex_context_menu", params.context_menu_event),
])
if params.legacy:
@@ -3810,7 +3817,7 @@ def km_weight_paint(params):
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask_vertex')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
- *_template_items_context_menu("VIEW3D_PT_paint_weight_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_paint_weight_context_menu", params.context_menu_event),
])
if params.select_mouse == 'LEFTMOUSE':
@@ -3922,7 +3929,7 @@ def km_sculpt(params):
{"properties": [("data_path", 'tool_settings.sculpt.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
op_menu_pie("VIEW3D_MT_sculpt_mask_edit_pie", {"type" : 'A', "value": 'PRESS'}),
- *_template_items_context_menu("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
+ *_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
])
if params.legacy:
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index d7ba10495f4..9ae5dbe071d 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -133,7 +133,6 @@ def _template_items_basic_tools(*, connected=False):
op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
- op_tool_cycle("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
op_tool_cycle("builtin.annotate", {"type": 'D', "value": 'PRESS'}),
op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
@@ -2631,7 +2630,6 @@ def km_pose(params):
op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool_cycle("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
])
@@ -3018,6 +3016,9 @@ def km_sculpt(params):
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ # Remesh
+ ("object.voxel_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
+ ("object.quadriflow_remesh", {"type": 'R', "value": 'PRESS', "ctrl": True, "alt": True}, None),
# Brush properties
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS'},
{"properties": [("scalar", 0.9)]}),
@@ -3256,7 +3257,6 @@ def km_lattice(params):
op_tool_cycle("builtin.move", {"type": 'W', "value": 'PRESS'}),
op_tool_cycle("builtin.rotate", {"type": 'E', "value": 'PRESS'}),
op_tool_cycle("builtin.scale", {"type": 'R', "value": 'PRESS'}),
- op_tool_cycle("builtin.scale_cage", {"type": 'R', "value": 'PRESS', "shift": True}),
op_tool_cycle("builtin.transform", {"type": 'T', "value": 'PRESS'}),
op_tool_cycle("builtin.measure", {"type": 'M', "value": 'PRESS'}),
])
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 581b6be886c..3edce6b3b52 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -400,10 +400,9 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
else:
sub.operator("object.shape_key_retime", icon='RECOVER_LAST', text="")
+ layout.use_property_split = True
if key.use_relative:
if ob.active_shape_key_index != 0:
- layout.use_property_split = True
-
row = layout.row()
row.active = enable_edit_value
row.prop(kb, "value")
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index dbd835a4a76..8e54a9824ab 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -1481,6 +1481,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "material_offset", text="Material Offset")
+ def WELD(self, layout, ob, md):
+ layout.prop(md, "merge_threshold", text="Distance")
+ layout.prop(md, "max_interactions")
+ layout.prop_search(md, "vertex_group", ob, "vertex_groups")
+
def DATA_TRANSFER(self, layout, ob, md):
row = layout.row(align=True)
row.prop(md, "object")
@@ -2408,7 +2413,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
subcol.enabled = md.duplications > 0
subcol.prop(md, "distance")
subcol.prop(md, "offset", slider=True)
-
+
subcol.separator()
subcol.prop(md, "enable_fading")
@@ -2444,7 +2449,7 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
-
+
classes = (
DATA_PT_modifiers,
DATA_PT_gpencil_modifiers,
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 5082400db73..5fa98c533c3 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -630,9 +630,9 @@ class GPENCIL_MT_gpencil_draw_delete(Menu):
class GPENCIL_MT_cleanup(Menu):
bl_label = "Clean Up"
- def draw(self, _context):
+ def draw(self, context):
- ob = _context.active_object
+ ob = context.active_object
layout = self.layout
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index 7c28095259e..d8d90fec583 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -367,7 +367,7 @@ def brush_basic_sculpt_settings(layout, context, brush, *, compact=False):
layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {}))
-def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact=True, is_toolbar=False):
+def brush_basic_gpencil_paint_settings(layout, context, brush, tool, *, compact=True, is_toolbar=False):
gp_settings = brush.gpencil_settings
# Brush details
@@ -397,7 +397,7 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID')
# Fill options
if is_toolbar:
- settings = _context.tool_settings.gpencil_sculpt
+ settings = context.tool_settings.gpencil_sculpt
row = layout.row(align=True)
sub = row.row(align=True)
sub.popover(
@@ -429,7 +429,7 @@ def brush_basic_gpencil_paint_settings(layout, _context, brush, tool, *, compact
"builtin.circle",
"builtin.polyline",
}:
- settings = _context.tool_settings.gpencil_sculpt
+ settings = context.tool_settings.gpencil_sculpt
if is_toolbar:
row = layout.row(align=True)
row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 752e1741984..968492db374 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -93,8 +93,8 @@ class GRAPH_MT_editor_menus(Menu):
bl_idname = "GRAPH_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
- st = _context.space_data
+ def draw(self, context):
+ st = context.space_data
layout = self.layout
layout.menu("GRAPH_MT_view")
layout.menu("GRAPH_MT_select")
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 24d6f65d9b9..28b67c93666 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -70,8 +70,8 @@ class NLA_MT_editor_menus(Menu):
bl_idname = "NLA_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
- st = _context.space_data
+ def draw(self, context):
+ st = context.space_data
layout = self.layout
layout.menu("NLA_MT_view")
layout.menu("NLA_MT_select")
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 6d60c67ded0..629958a783e 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -87,10 +87,10 @@ class TIME_MT_editor_menus(Menu):
bl_idname = "TIME_MT_editor_menus"
bl_label = ""
- def draw(self, _context):
+ def draw(self, context):
layout = self.layout
horizontal = (layout.direction == 'VERTICAL')
- st = _context.space_data
+ st = context.space_data
if horizontal:
row = layout.row()
sub = row.row(align=True)
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 4413dee4189..532f5e023b6 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -738,10 +738,10 @@ class ToolSelectPanelHelper:
else:
label = "Active Tool"
- split = layout.split(factor=0.5)
+ split = layout.split(factor=0.33)
row = split.row()
row.alignment = 'RIGHT'
- row.label(text="Drag")
+ row.label(text="Drag:")
row = split.row()
row.context_pointer_set("tool", tool)
row.popover(panel="TOPBAR_PT_tool_fallback", text=label)
@@ -751,7 +751,6 @@ class ToolSelectPanelHelper:
# Show a list of tools in the popover.
@staticmethod
def draw_fallback_tool_items(layout, context):
-
space_type = context.space_data.type
if space_type == 'PROPERTIES':
space_type = 'VIEW_3D'
@@ -930,9 +929,8 @@ def _activate_by_item(context, space_type, item, index, *, as_fallback=False):
data_block=item.data_block or "",
operator=item.operator or "",
index=index,
-
- idname_fallback=item_fallback.idname if item_fallback else "",
- keymap_fallback=item_fallback.keymap[0] if (item_fallback and item_fallback.keymap) else "",
+ idname_fallback=(item_fallback and item_fallback.idname) or "",
+ keymap_fallback=(item_fallback and item_fallback.keymap and item_fallback.keymap[0]) or "",
)
WindowManager = bpy.types.WindowManager
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 68d39a3be64..f0c1b0d135f 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -326,15 +326,12 @@ class _defs_view3d_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap="3D View Tool: Tweak",
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -407,7 +404,7 @@ class _defs_edit_armature:
idname="builtin.roll",
label="Roll",
icon="ops.armature.bone.roll",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -417,7 +414,7 @@ class _defs_edit_armature:
idname="builtin.bone_envelope",
label="Bone Envelope",
icon="ops.transform.bone_envelope",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -427,7 +424,7 @@ class _defs_edit_armature:
idname="builtin.bone_size",
label="Bone Size",
icon="ops.transform.bone_size",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -490,7 +487,7 @@ class _defs_edit_mesh:
idname="builtin.rip_edge",
label="Rip Edge",
icon="ops.mesh.rip_edge",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -869,7 +866,7 @@ class _defs_edit_curve:
idname="builtin.tilt",
label="Tilt",
icon="ops.transform.tilt",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -882,7 +879,7 @@ class _defs_edit_curve:
"Expand or contract the radius of the selected curve points"
),
icon="ops.curve.radius",
- widget=None,
+ widget="VIEW3D_GGT_tool_generic_handle_free",
keymap=(),
)
@@ -1211,15 +1208,12 @@ class _defs_image_uv_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap=(),
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -1597,15 +1591,12 @@ class _defs_node_select:
@ToolDef.from_fn
def select():
- def draw_settings(_context, _layout, _tool):
- pass
return dict(
idname="builtin.select",
label="Tweak",
icon="ops.generic.select",
widget=None,
keymap="Node Tool: Tweak",
- draw_settings=draw_settings,
)
@ToolDef.from_fn
@@ -1615,7 +1606,6 @@ class _defs_node_select:
row = layout.row()
row.use_property_split = False
row.prop(props, "mode", text="", expand=True, icon_only=True)
- pass
return dict(
idname="builtin.select_box",
label="Select Box",
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 536268c067e..fdd3bd7cd86 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -265,7 +265,10 @@ typedef struct SculptSession {
float cursor_location[3];
float cursor_normal[3];
float cursor_view_normal[3];
+
+ /* TODO(jbakker): Replace rv3d adn v3d with ViewContext */
struct RegionView3D *rv3d;
+ struct View3D *v3d;
/* Dynamic mesh preview */
int *preview_vert_index_list;
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index b305e919e76..70fa633eeac 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -93,7 +93,6 @@ enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
BVH_OVERLAP_USE_THREADING = (1 << 0),
BVH_OVERLAP_RETURN_PAIRS = (1 << 1),
- BVH_OVERLAP_BREAK_ON_FIRST = (1 << 2),
};
enum {
/* Use a priority queue to process nodes in the optimal order (for slow callbacks) */
@@ -167,7 +166,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
void *userdata,
- int flag);
+ const uint max_interactions,
+ const int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2,
unsigned int *r_overlap_tot,
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index ae862c5ece5..71f276bc68f 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -122,6 +122,7 @@ typedef struct BVHOverlapData_Shared {
typedef struct BVHOverlapData_Thread {
BVHOverlapData_Shared *shared;
struct BLI_Stack *overlap; /* store BVHTreeOverlap */
+ uint max_interactions;
/* use for callbacks */
int thread;
} BVHOverlapData_Thread;
@@ -1186,9 +1187,9 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread,
/**
* a version of #tree_overlap_traverse_cb that that break on first true return.
*/
-static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
- const BVHNode *node1,
- const BVHNode *node2)
+static bool tree_overlap_num_recursive(BVHOverlapData_Thread *data_thread,
+ const BVHNode *node1,
+ const BVHNode *node2)
{
BVHOverlapData_Shared *data = data_thread->shared;
int j;
@@ -1213,20 +1214,23 @@ static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread,
overlap->indexA = node1->index;
overlap->indexB = node2->index;
}
- return true;
+ return (--data_thread->max_interactions) == 0;
}
}
else {
for (j = 0; j < node2->totnode; j++) {
- if (tree_overlap_traverse_first_cb(data_thread, node1, node2->children[j])) {
+ if (tree_overlap_num_recursive(data_thread, node1, node2->children[j])) {
return true;
}
}
}
}
else {
+ const uint max_interactions = data_thread->max_interactions;
for (j = 0; j < node1->totnode; j++) {
- tree_overlap_traverse_first_cb(data_thread, node1->children[j], node2);
+ if (tree_overlap_num_recursive(data_thread, node1->children[j], node2)) {
+ data_thread->max_interactions = max_interactions;
+ }
}
}
}
@@ -1262,17 +1266,16 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata,
}
}
-static void bvhtree_overlap_first_task_cb(void *__restrict userdata,
- const int j,
- const TaskParallelTLS *__restrict UNUSED(tls))
+static void bvhtree_overlap_num_task_cb(void *__restrict userdata,
+ const int j,
+ const TaskParallelTLS *__restrict UNUSED(tls))
{
BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j];
BVHOverlapData_Shared *data_shared = data->shared;
- tree_overlap_traverse_first_cb(
- data,
- data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
- data_shared->tree2->nodes[data_shared->tree2->totleaf]);
+ tree_overlap_num_recursive(data,
+ data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j],
+ data_shared->tree2->nodes[data_shared->tree2->totleaf]);
}
BVHTreeOverlap *BLI_bvhtree_overlap_ex(
@@ -1282,14 +1285,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* optional callback to test the overlap before adding (must be thread-safe!) */
BVHTree_OverlapCallback callback,
void *userdata,
- int flag)
+ const uint max_interactions,
+ const int flag)
{
bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0;
bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0;
- bool break_on_first = (flag & BVH_OVERLAP_BREAK_ON_FIRST) != 0;
- /* `RETURN_PAIRS` was not implemented without `BREAK_ON_FIRST`. */
- BLI_assert(overlap_pairs || break_on_first);
+ /* `RETURN_PAIRS` was not implemented without `max_interations`. */
+ BLI_assert(overlap_pairs || max_interactions);
const int thread_num = BLI_bvhtree_overlap_thread_num(tree1);
int j;
@@ -1328,6 +1331,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
/* init BVHOverlapData_Thread */
data[j].shared = &data_shared;
data[j].overlap = overlap_pairs ? BLI_stack_new(sizeof(BVHTreeOverlap), __func__) : NULL;
+ data[j].max_interactions = max_interactions;
/* for callback */
data[j].thread = j;
@@ -1339,7 +1343,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex(
BLI_task_parallel_range(0,
thread_num,
data,
- break_on_first ? bvhtree_overlap_first_task_cb : bvhtree_overlap_task_cb,
+ max_interactions ? bvhtree_overlap_num_task_cb : bvhtree_overlap_task_cb,
&settings);
if (overlap_pairs) {
@@ -1374,6 +1378,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap(
r_overlap_tot,
callback,
userdata,
+ 0,
BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS);
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c
index ffdcf179491..82e2151dc01 100644
--- a/source/blender/bmesh/tools/bmesh_intersect_edges.c
+++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c
@@ -604,7 +604,7 @@ static void bvhtree_overlap_thread_safe(const BVHTree *tree1,
BVHTree_OverlapCallback callback,
void *userdata)
{
- BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, BVH_OVERLAP_BREAK_ON_FIRST);
+ BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, 1, 0);
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
index fb456611b15..c8ddffa57c7 100644
--- a/source/blender/depsgraph/DEG_depsgraph_query.h
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -26,6 +26,8 @@
#ifndef __DEG_DEPSGRAPH_QUERY_H__
#define __DEG_DEPSGRAPH_QUERY_H__
+#include "BLI_iterator.h"
+
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 5edfadd7f41..b9e7908b3ef 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -134,6 +134,7 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph,
struct View3D *v3d,
struct GPUViewport *viewport);
void DRW_draw_depth_object(struct ARegion *ar,
+ struct View3D *v3d,
struct GPUViewport *viewport,
struct Object *object);
void DRW_draw_select_id(struct Depsgraph *depsgraph,
diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
index c8f98702e60..56fbc3cca01 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c
@@ -360,7 +360,9 @@ void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata)
OVERLAY_PrivateData *pd = vedata->stl->pd;
OVERLAY_FramebufferList *fbl = vedata->fbl;
- GPU_framebuffer_bind(fbl->overlay_default_fb);
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ }
DRW_draw_pass(psl->edit_mesh_weight_ps);
DRW_draw_pass(psl->edit_mesh_analysis_ps);
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index 41d099772ee..06044ff92b3 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -74,7 +74,7 @@ static void OVERLAY_engine_init(void *vedata)
}
pd->wireframe_mode = (v3d->shading.type == OB_WIRE);
- pd->clipping_state = (rv3d->rflag & RV3D_CLIPPING) ? DRW_STATE_CLIP_PLANES : 0;
+ pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0;
pd->xray_enabled = XRAY_ACTIVE(v3d);
pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
pd->clear_in_front = (v3d->shading.type != OB_SOLID);
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 42375f29d4d..f07b21ebcc2 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -116,6 +116,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wpd->preferences = &U;
View3D *v3d = draw_ctx->v3d;
+ RegionView3D *rv3d = draw_ctx->rv3d;
+
if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) {
wpd->shading = scene->display.shading;
wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display));
@@ -193,22 +195,19 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd)
wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f);
/* Will be NULL when rendering. */
- if (draw_ctx->rv3d != NULL) {
- RegionView3D *rv3d = draw_ctx->rv3d;
- if (rv3d->rflag & RV3D_CLIPPING) {
- wpd->world_clip_planes = rv3d->clip;
- UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color);
- if (wpd->use_color_management) {
- srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
- }
- else {
- copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
- }
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
+ wpd->world_clip_planes = rv3d->clip;
+ UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color);
+ if (wpd->use_color_management) {
+ srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
}
else {
- wpd->world_clip_planes = NULL;
+ copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color);
}
}
+ else {
+ wpd->world_clip_planes = NULL;
+ }
workbench_world_data_update_shadow_direction_vs(wpd);
workbench_world_data_ubo_ensure(scene, wpd);
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index da5ab0c3122..8e61750da38 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -716,7 +716,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
}
DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL);
- if (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb) {
+ if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND);
grp = DRW_shgroup_create(shader, psl->background_pass);
wpd->world_clip_planes_batch = DRW_draw_background_clipping_batch_from_rv3d(draw_ctx->rv3d);
diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c
index 87f3b28c665..dbd7ebfe0d1 100644
--- a/source/blender/draw/engines/workbench/workbench_forward.c
+++ b/source/blender/draw/engines/workbench/workbench_forward.c
@@ -421,7 +421,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata)
/* TODO(campbell): displays but masks geometry,
* only use with wire or solid-without-xray for now. */
if ((wpd->shading.type != OB_WIRE && !XRAY_FLAG_ENABLED(wpd)) &&
- (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb)) {
+ RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) {
psl->background_pass = DRW_pass_create("Background",
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL);
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 4bfae75848b..5832db31c4e 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -584,7 +584,7 @@ static void drw_context_state_init(void)
}
DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_DEFAULT;
- if (DST.draw_ctx.rv3d && DST.draw_ctx.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(DST.draw_ctx.v3d, DST.draw_ctx.rv3d)) {
DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_CLIPPED;
}
}
@@ -1235,7 +1235,7 @@ static void drw_engines_draw_text(void)
PROFILE_START(stime);
if (data->text_draw_cache) {
- DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar);
+ DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar, DST.draw_ctx.v3d);
}
PROFILE_END_UPDATE(data->render_time, stime);
@@ -2571,7 +2571,7 @@ static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_
/**
* Clears the Depth Buffer and draws only the specified object.
*/
-void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
+void DRW_draw_depth_object(ARegion *ar, View3D *v3d, GPUViewport *viewport, Object *object)
{
RegionView3D *rv3d = ar->regiondata;
@@ -2588,7 +2588,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
GPU_depth_test(true);
const float(*world_clip_planes)[4] = NULL;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_set(rv3d);
ED_view3d_clipping_local(rv3d, object->obmat);
world_clip_planes = rv3d->clip_local;
@@ -2625,7 +2625,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object)
break;
}
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c
index b6dab0b2077..9462a0d8072 100644
--- a/source/blender/draw/intern/draw_manager_text.c
+++ b/source/blender/draw/intern/draw_manager_text.c
@@ -119,7 +119,7 @@ void DRW_text_cache_add(DRWTextStore *dt,
}
}
-void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
+void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar, struct View3D *v3d)
{
RegionView3D *rv3d = ar->regiondata;
ViewCachedString *vos;
@@ -147,7 +147,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
if (tot) {
int col_pack_prev = 0;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
@@ -185,7 +185,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar)
GPU_matrix_pop();
GPU_matrix_projection_set(original_proj);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_enable();
}
}
diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h
index 5e9692ff490..a8eb45ee8f5 100644
--- a/source/blender/draw/intern/draw_manager_text.h
+++ b/source/blender/draw/intern/draw_manager_text.h
@@ -41,7 +41,7 @@ void DRW_text_cache_add(struct DRWTextStore *dt,
short flag,
const uchar col[4]);
-void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar);
+void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar, struct View3D *v3d);
void DRW_text_edit_mesh_measure_stats(struct ARegion *ar,
struct View3D *v3d,
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 1adbbe30286..4c4aa4214b2 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1460,7 +1460,8 @@ static bool point_is_visible(KnifeTool_OpData *kcd,
BMFace *f_hit;
/* If box clipping on, make sure p is not clipped */
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING && ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) {
return false;
}
@@ -1484,7 +1485,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd,
dist = kcd->vc.v3d->clip_end * 2.0f;
}
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
float view_clip[2][3];
/* note: view_clip[0] should never get clipped */
copy_v3_v3(view_clip[0], p_ofs);
@@ -1935,7 +1936,7 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius
dis_sq = len_squared_v2v2(kfv->sco, sco);
if (dis_sq < radius_sq) {
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
c++;
}
@@ -2045,7 +2046,7 @@ static KnifeEdge *knife_find_closest_edge(
/* now we have 'lambda' calculated (in screen-space) */
knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
/* check we're in the view */
if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
continue;
@@ -2152,7 +2153,7 @@ static KnifeVert *knife_find_closest_vert(
dis_sq = len_squared_v2v2(kfv->sco, sco);
if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) {
if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) {
curv = kfv;
curdis_sq = dis_sq;
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 510d734451b..c57490041bc 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -887,7 +887,7 @@ static bool project_bucket_point_occluded(const ProjPaintState *ps,
const float pixelScreenCo[4])
{
int isect_ret;
- const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0;
+ const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
/* we could return 0 for 1 face buckets, as long as this function assumes
* that the point its testing is only every originated from an existing face */
@@ -3024,7 +3024,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
const bool is_ortho = ps->is_ortho;
const bool is_flip_object = ps->is_flip_object;
const bool do_backfacecull = ps->do_backfacecull;
- const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0;
+ const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d);
vCo[0] = ps->mvert_eval[lt_vtri[0]].co;
vCo[1] = ps->mvert_eval[lt_vtri[1]].co;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index f813be7d0a2..b26d706bbf4 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1013,6 +1013,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob)
void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d;
+ View3D *v3d = ss->cache ? ss->cache->vc->v3d : ss->v3d;
test->radius_squared = ss->cache ? ss->cache->radius_squared :
ss->cursor_radius * ss->cursor_radius;
@@ -1033,7 +1034,7 @@ void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->mirror_symmetry_pass = ss->cache ? ss->cache->mirror_symmetry_pass : 0;
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
test->clip_rv3d = rv3d;
}
else {
@@ -6896,6 +6897,7 @@ static float sculpt_raycast_init(ViewContext *vc,
float dist;
Object *ob = vc->obact;
RegionView3D *rv3d = vc->ar->regiondata;
+ View3D *v3d = vc->v3d;
/* TODO: what if the segment is totally clipped? (return == 0) */
ED_view3d_win_to_segment_clipped(
@@ -6910,7 +6912,7 @@ static float sculpt_raycast_init(ViewContext *vc,
if ((rv3d->is_persp == false) &&
/* if the ray is clipped, don't adjust its start/end */
- ((rv3d->rflag & RV3D_CLIPPING) == 0)) {
+ RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal);
/* recalculate the normal */
@@ -7005,6 +7007,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
copy_v3_v3(ss->cursor_normal, srd.face_normal);
copy_v3_v3(ss->cursor_location, out->location);
ss->rv3d = vc.rv3d;
+ ss->v3d = vc.v3d;
if (!BKE_brush_use_locked_size(scene, brush)) {
radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush));
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 0e408077206..9a6f685f5fc 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2172,6 +2172,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_Wireframe:
data.icon = ICON_MOD_WIREFRAME;
break;
+ case eModifierType_Weld:
+ data.icon = ICON_AUTOMERGE_OFF; /* XXX, needs own icon */
+ break;
case eModifierType_LaplacianDeform:
data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */
break;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 6235f994272..061977d0c91 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -796,7 +796,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a
GPU_clear(GPU_DEPTH_BIT);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_set(rv3d);
}
/* get surface depth without bias */
@@ -817,7 +817,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a
WM_draw_region_viewport_unbind(ar);
- if (rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) {
ED_view3d_clipping_disable();
}
rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED;
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index 17b575cedae..38cb5ad8651 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -228,7 +228,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
- DRW_draw_depth_object(vc->ar, viewport, obact_eval);
+ DRW_draw_depth_object(vc->ar, vc->v3d, viewport, obact_eval);
}
vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index d7f7e96ba08..8b4012d6547 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -1099,7 +1099,7 @@ int view3d_opengl_select(ViewContext *vc,
GPU_depth_test(true);
}
- if (vc->rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d)) {
ED_view3d_clipping_set(vc->rv3d);
}
@@ -1167,7 +1167,7 @@ int view3d_opengl_select(ViewContext *vc,
GPU_depth_test(false);
}
- if (vc->rv3d->rflag & RV3D_CLIPPING) {
+ if (RV3D_CLIPPING_ENABLED(v3d, vc->rv3d)) {
ED_view3d_clipping_disable();
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 336f9974e7d..f19147baa89 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -1743,6 +1743,13 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
RegionView3D *rv3d = ar->regiondata;
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
if (ggd->use_twtype_refresh) {
ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
if (ggd->twtype != ggd->twtype_prev) {
@@ -1829,13 +1836,6 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) {
ggd->gizmos[i]->select_bias = rotate_select_bias;
}
-
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
}
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
@@ -2176,6 +2176,13 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_SCALE);
@@ -2231,13 +2238,6 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
/* Needed to test view orientation changes. */
copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
-
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
}
static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
@@ -2388,6 +2388,16 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
struct TransformBounds tbounds;
+ if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
+ gzgroup->use_fallback_keymap = true;
+ }
+ else {
+ gzgroup->use_fallback_keymap = false;
+ }
+
+ /* Needed to test view orientation changes. */
+ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
+
const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene,
SCE_ORIENT_ROTATE);
@@ -2440,16 +2450,6 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
-
- /* Needed to test view orientation changes. */
- copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv);
-
- if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
- gzgroup->use_fallback_keymap = true;
- }
- else {
- gzgroup->use_fallback_keymap = false;
- }
}
static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 75a860de053..1c986c3c260 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -86,11 +86,12 @@ typedef enum ModifierType {
eModifierType_MeshSequenceCache = 52,
eModifierType_SurfaceDeform = 53,
eModifierType_WeightedNormal = 54,
- eModifierType_FunctionDeform = 55,
+ eModifierType_Weld = 55,
eModifierType_FunctionPoints = 56,
eModifierType_BParticles = 57,
eModifierType_BParticlesOutput = 58,
- NUM_MODIFIER_TYPES
+ eModifierType_FunctionDeform = 59,
+ NUM_MODIFIER_TYPES,
} ModifierType;
typedef enum ModifierMode {
@@ -1814,6 +1815,16 @@ enum {
MOD_WIREFRAME_CREASE = (1 << 5),
};
+typedef struct WeldModifierData {
+ ModifierData modifier;
+
+ /* the limit below which to merge vertices in adjacent duplicates */
+ float merge_dist;
+ unsigned int max_interactions;
+ /** Name of vertex group to use to mask, MAX_VGROUP_NAME. */
+ char defgrp_name[64];
+} WeldModifierData;
+
typedef struct DataTransferModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index a9a20980677..93b93bbdbf7 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -376,6 +376,9 @@ typedef struct View3D {
#define RV3D_VIEW_CAMERA 8
#define RV3D_VIEW_IS_AXIS(view) (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM))
+#define RV3D_CLIPPING_ENABLED(v3d, rv3d) \
+ (rv3d && v3d && (rv3d->rflag & RV3D_CLIPPING) && ELEM(v3d->shading.type, OB_WIRE, OB_SOLID) && \
+ rv3d->clipbb)
/** #View3D.flag2 (int) */
#define V3D_HIDE_OVERLAYS (1 << 2)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 46403d40e9d..00491f25b17 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -742,6 +742,7 @@ extern StructRNA RNA_Window;
extern StructRNA RNA_WindowManager;
extern StructRNA RNA_WipeSequence;
extern StructRNA RNA_WireframeModifier;
+extern StructRNA RNA_WeldModifier;
extern StructRNA RNA_WoodTexture;
extern StructRNA RNA_WorkSpace;
extern StructRNA RNA_World;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index a22b261368c..7c9b4254e4d 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -27,7 +27,7 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
-#define DEBUG_OVERRIDE_TIMEIT
+// #define DEBUG_OVERRIDE_TIMEIT
#ifdef DEBUG_OVERRIDE_TIMEIT
# include "PIL_time_utildefines.h"
@@ -598,7 +598,6 @@ bool RNA_struct_override_matches(Main *bmain,
const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
-//#define DEBUG_OVERRIDE_TIMEIT
#ifdef DEBUG_OVERRIDE_TIMEIT
static float _sum_time_global = 0.0f;
static float _num_time_global = 0.0f;
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index ca4ca07fe73..7c9ac6a2072 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -187,6 +187,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WIREFRAME,
"Wireframe",
"Convert faces into thickened edges"},
+ {eModifierType_Weld,
+ "WELD",
+ ICON_AUTOMERGE_OFF,
+ "Weld",
+ "Finds groups of vertices closer then dist and merges them together"},
{eModifierType_FunctionPoints, "FUNCTION_POINTS", ICON_NONE, "Function Points", ""},
{0, "", 0, N_("Deform"), ""},
{eModifierType_Armature,
@@ -704,6 +709,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_LaplacianDeformModifier;
case eModifierType_Wireframe:
return &RNA_WireframeModifier;
+ case eModifierType_Weld:
+ return &RNA_WeldModifier;
case eModifierType_DataTransfer:
return &RNA_DataTransferModifier;
case eModifierType_NormalEdit:
@@ -815,6 +822,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name);
RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(Weld, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
@@ -5671,6 +5679,40 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_weld(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "WeldModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier");
+ RNA_def_struct_sdna(srna, "WeldModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF);
+
+ prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "merge_dist");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 0.001, 6);
+ RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "max_interactions", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "max_interactions");
+ RNA_def_property_ui_text(
+ prop,
+ "Duplicate Limit",
+ "For a better performance, limits the number of elements found per vertex. "
+ "(0 makes it infinite)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(
+ prop, "Vertex Group", "Vertex group name for selecting the affected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeldModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
static void rna_def_modifier_datatransfer(BlenderRNA *brna)
{
StructRNA *srna;
@@ -6488,6 +6530,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_meshcache(brna);
rna_def_modifier_laplaciandeform(brna);
rna_def_modifier_wireframe(brna);
+ rna_def_modifier_weld(brna);
rna_def_modifier_datatransfer(brna);
rna_def_modifier_normaledit(brna);
rna_def_modifier_meshseqcache(brna);
diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c
index f244a674e57..5cc55bfad8a 100644
--- a/source/blender/makesrna/intern/rna_workspace_api.c
+++ b/source/blender/makesrna/intern/rna_workspace_api.c
@@ -63,8 +63,8 @@ static void rna_WorkSpaceTool_setup(ID *id,
STRNCPY(tref_rt.op, op_idname);
tref_rt.index = index;
- STRNCPY(tref_rt.idname_fallback, idname_fallback ? idname_fallback : NULL);
- STRNCPY(tref_rt.keymap_fallback, keymap_fallback ? keymap_fallback : NULL);
+ STRNCPY(tref_rt.idname_fallback, idname_fallback);
+ STRNCPY(tref_rt.keymap_fallback, keymap_fallback);
WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, idname);
}
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index f6b98f43029..e0232431930 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -109,6 +109,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
+ intern/MOD_weld.c
intern/MOD_wireframe.c
MOD_modifiertypes.h
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 10f8d83b5bc..0560ed86c75 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -75,6 +75,7 @@ extern ModifierTypeInfo modifierType_UVWarp;
extern ModifierTypeInfo modifierType_MeshCache;
extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
+extern ModifierTypeInfo modifierType_Weld;
extern ModifierTypeInfo modifierType_DataTransfer;
extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 723ad779864..45ec79d7801 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -301,6 +301,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshCache);
INIT_TYPE(LaplacianDeform);
INIT_TYPE(Wireframe);
+ INIT_TYPE(Weld);
INIT_TYPE(DataTransfer);
INIT_TYPE(NormalEdit);
INIT_TYPE(CorrectiveSmooth);
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c
new file mode 100644
index 00000000000..ca6998b9aa4
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weld.c
@@ -0,0 +1,1910 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ *
+ * Weld modifier: Remove doubles.
+ */
+
+/* TODOs:
+ * - Review weight and vertex color interpolation.;
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BLI_alloca.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_deform.h"
+#include "BKE_bvhutils.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph.h"
+
+//#define USE_WELD_DEBUG
+//#define USE_WELD_NORMALS
+
+/* Indicates when the element was not computed. */
+#define OUT_OF_CONTEXT (uint)(-1)
+/* Indicates if the edge or face will be collapsed. */
+#define ELEM_COLLAPSED (uint)(-2)
+/* indicates whether an edge or vertex in groups_map will be merged. */
+#define ELEM_MERGED (uint)(-2)
+
+/* Used to indicate a range in an array specifying a group. */
+struct WeldGroup {
+ uint len;
+ uint ofs;
+};
+
+/* Edge groups that will be merged. Final vertices are also indicated. */
+struct WeldGroupEdge {
+ struct WeldGroup group;
+ uint v1;
+ uint v2;
+};
+
+typedef struct WeldVert {
+ /* Indexes relative to the original Mesh. */
+ uint vert_dest;
+ uint vert_orig;
+} WeldVert;
+
+typedef struct WeldEdge {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint edge_dest;
+ uint edge_orig;
+ uint vert_a;
+ uint vert_b;
+ };
+ };
+} WeldEdge;
+
+typedef struct WeldLoop {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint vert;
+ uint edge;
+ uint loop_orig;
+ uint loop_skip_to;
+ };
+ };
+} WeldLoop;
+
+typedef struct WeldPoly {
+ union {
+ uint flag;
+ struct {
+ /* Indexes relative to the original Mesh. */
+ uint poly_dst;
+ uint poly_orig;
+ uint loop_start;
+ uint loop_end;
+ /* Final Polygon Size. */
+ uint len;
+ /* Group of loops that will be affected. */
+ struct WeldGroup loops;
+ };
+ };
+} WeldPoly;
+
+typedef struct WeldMesh {
+ /* Group of vertices to be merged. */
+ struct WeldGroup *vert_groups;
+ uint *vert_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ uint *vert_groups_map;
+
+ /* Group of edges to be merged. */
+ struct WeldGroupEdge *edge_groups;
+ uint *edge_groups_buffer;
+ /* From the original index of the vertex, this indicates which group it is or is going to be
+ * merged. */
+ uint *edge_groups_map;
+
+ /* References all polygons and loops that will be affected. */
+ WeldLoop *wloop;
+ WeldPoly *wpoly;
+ WeldPoly *wpoly_new;
+ uint wloop_len;
+ uint wpoly_len;
+ uint wpoly_new_len;
+
+ /* From the actual index of the element in the mesh, it indicates what is the index of the Weld
+ * element above. */
+ uint *loop_map;
+ uint *poly_map;
+
+ uint vert_kill_tot;
+ uint edge_kill_tot;
+ uint loop_kill_tot;
+ uint poly_kill_tot; /* Including the new polygons. */
+
+ /* Size of the affected polygon with more sides. */
+ uint max_poly_len;
+} WeldMesh;
+
+typedef struct WeldLoopOfPolyIter {
+ uint loop_start;
+ uint loop_end;
+ const WeldLoop *wloop;
+ const MLoop *mloop;
+ const uint *loop_map;
+ /* Weld group. */
+ uint *group;
+
+ uint l_curr;
+ uint l_next;
+
+ /* Return */
+ uint group_len;
+ uint v;
+ uint e;
+ char type;
+} WeldLoopOfPolyIter;
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Utils
+ * \{ */
+
+#ifdef USE_WELD_DEBUG
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ uint *group_buffer);
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
+
+static void weld_assert_vert_dest_map_setup(const BVHTreeOverlap *overlap,
+ const uint overlap_tot,
+ const uint *vert_dest_map)
+{
+ const BVHTreeOverlap *overlap_iter = &overlap[0];
+ for (uint i = overlap_tot; i--; overlap_iter++) {
+ uint indexA = overlap_iter->indexA;
+ uint indexB = overlap_iter->indexB;
+ uint va_dst = vert_dest_map[indexA];
+ uint vb_dst = vert_dest_map[indexB];
+
+ BLI_assert(va_dst == vb_dst);
+ }
+}
+
+static void weld_assert_edge_kill_len(const WeldEdge *wedge,
+ const uint wedge_len,
+ const uint supposed_kill_tot)
+{
+ uint kills = 0;
+ const WeldEdge *we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ uint edge_dest = we->edge_dest;
+ /* Magically includes collapsed edges. */
+ if (edge_dest != OUT_OF_CONTEXT) {
+ kills++;
+ }
+ }
+ BLI_assert(kills == supposed_kill_tot);
+}
+
+static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
+ const WeldPoly *wpoly_new,
+ const uint wpoly_new_len,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ const uint *poly_map,
+ const MPoly *mpoly,
+ const uint mpoly_len,
+ const uint mloop_len,
+ const uint supposed_poly_kill_tot,
+ const uint supposed_loop_kill_tot)
+{
+ uint poly_kills = 0;
+ uint loop_kills = mloop_len;
+ const MPoly *mp = &mpoly[0];
+ for (uint i = 0; i < mpoly_len; i++, mp++) {
+ uint poly_ctx = poly_map[i];
+ if (poly_ctx != OUT_OF_CONTEXT) {
+ const WeldPoly *wp = &wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ poly_kills++;
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ uint remain = wp->len;
+ uint l = wp->loop_start;
+ while (remain) {
+ uint l_next = l + 1;
+ uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+ }
+ else {
+ loop_kills -= mp->totloop;
+ }
+ }
+
+ const WeldPoly *wp = &wpoly_new[0];
+ for (uint i = wpoly_new_len; i--; wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ poly_kills++;
+ continue;
+ }
+ uint remain = wp->len;
+ uint l = wp->loop_start;
+ while (remain) {
+ uint l_next = l + 1;
+ uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag != ELEM_COLLAPSED) {
+ loop_kills--;
+ remain--;
+ }
+ }
+ else {
+ loop_kills--;
+ remain--;
+ }
+ l = l_next;
+ }
+ }
+
+ BLI_assert(poly_kills == supposed_poly_kill_tot);
+ BLI_assert(loop_kills == supposed_loop_kill_tot);
+}
+
+static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map)
+{
+ const uint len = wp->len;
+ uint *verts = BLI_array_alloca(verts, len);
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ return;
+ }
+ else {
+ uint i = 0;
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ verts[i++] = iter.v;
+ }
+ }
+ for (uint i = 0; i < len; i++) {
+ uint va = verts[i];
+ for (uint j = i + 1; j < len; j++) {
+ uint vb = verts[j];
+ BLI_assert(va != vb);
+ }
+ }
+}
+
+static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return;
+ }
+
+ uint len = wp->len;
+ const WeldLoop *wl = &wloop[wp->loops.ofs];
+ BLI_assert(wp->loop_start <= wl->loop_orig);
+
+ uint end_wloop = wp->loops.ofs + wp->loops.len;
+ const WeldLoop *wl_end = &wloop[end_wloop - 1];
+
+ uint min_len = 0;
+ for (; wl <= wl_end; wl++) {
+ BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
+ if (wl->flag != ELEM_COLLAPSED) {
+ min_len++;
+ }
+ }
+ BLI_assert(len >= min_len);
+
+ uint max_len = wp->loop_end - wp->loop_start + 1;
+ BLI_assert(len <= max_len);
+}
+#endif
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Vert API
+ * \{ */
+
+static void weld_vert_ctx_alloc_and_setup(const uint vert_tot,
+ const BVHTreeOverlap *overlap,
+ const uint overlap_tot,
+ uint *r_vert_dest_map,
+ WeldVert **r_wvert,
+ uint *r_wvert_tot,
+ uint *r_vert_kill_tot)
+{
+ uint *v_dest_iter = &r_vert_dest_map[0];
+ for (uint i = vert_tot; i--; v_dest_iter++) {
+ *v_dest_iter = OUT_OF_CONTEXT;
+ }
+
+ uint vert_kill_tot = 0;
+ const BVHTreeOverlap *overlap_iter = &overlap[0];
+ for (uint i = 0; i < overlap_tot; i++, overlap_iter++) {
+ uint indexA = overlap_iter->indexA;
+ uint indexB = overlap_iter->indexB;
+
+ BLI_assert(indexA < indexB);
+
+ uint va_dst = r_vert_dest_map[indexA];
+ uint vb_dst = r_vert_dest_map[indexB];
+ if (va_dst == OUT_OF_CONTEXT) {
+ if (vb_dst == OUT_OF_CONTEXT) {
+ vb_dst = indexA;
+ r_vert_dest_map[indexB] = vb_dst;
+ }
+ r_vert_dest_map[indexA] = vb_dst;
+ vert_kill_tot++;
+ }
+ else if (vb_dst == OUT_OF_CONTEXT) {
+ r_vert_dest_map[indexB] = va_dst;
+ vert_kill_tot++;
+ }
+ else if (va_dst != vb_dst) {
+ uint v_new, v_old;
+ if (va_dst < vb_dst) {
+ v_new = va_dst;
+ v_old = vb_dst;
+ }
+ else {
+ v_new = vb_dst;
+ v_old = va_dst;
+ }
+ BLI_assert(r_vert_dest_map[v_old] == v_old);
+ BLI_assert(r_vert_dest_map[v_new] == v_new);
+ vert_kill_tot++;
+
+ const BVHTreeOverlap *overlap_iter_b = &overlap[0];
+ for (uint j = i + 1; j--; overlap_iter_b++) {
+ indexA = overlap_iter_b->indexA;
+ indexB = overlap_iter_b->indexB;
+ va_dst = r_vert_dest_map[indexA];
+ vb_dst = r_vert_dest_map[indexB];
+ if (ELEM(v_old, vb_dst, va_dst)) {
+ r_vert_dest_map[indexA] = v_new;
+ r_vert_dest_map[indexB] = v_new;
+ }
+ }
+ BLI_assert(r_vert_dest_map[v_old] == v_new);
+ }
+ }
+
+ /* Vert Context. */
+ uint wvert_tot = 0;
+
+ WeldVert *wvert, *wv;
+ wvert = MEM_mallocN(sizeof(*wvert) * vert_tot, __func__);
+ wv = &wvert[0];
+
+ v_dest_iter = &r_vert_dest_map[0];
+ for (uint i = 0; i < vert_tot; i++, v_dest_iter++) {
+ if (*v_dest_iter != OUT_OF_CONTEXT) {
+ wv->vert_dest = *v_dest_iter;
+ wv->vert_orig = i;
+ wv++;
+ wvert_tot++;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_vert_dest_map_setup(overlap, overlap_tot, r_vert_dest_map);
+#endif
+
+ *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_tot);
+ *r_wvert_tot = wvert_tot;
+ *r_vert_kill_tot = vert_kill_tot;
+}
+
+static void weld_vert_groups_setup(const uint vert_tot,
+ const uint wvert_tot,
+ const WeldVert *wvert,
+ const uint *vert_dest_map,
+ uint *r_vert_groups_map,
+ uint **r_vert_groups_buffer,
+ struct WeldGroup **r_vert_groups)
+{
+ /* Get weld vert groups. */
+
+ uint wgroups_len = 0;
+ const uint *vert_dest_iter = &vert_dest_map[0];
+ uint *group_map_iter = &r_vert_groups_map[0];
+ for (uint i = 0; i < vert_tot; i++, group_map_iter++, vert_dest_iter++) {
+ uint vert_dest = *vert_dest_iter;
+ if (vert_dest != OUT_OF_CONTEXT) {
+ if (vert_dest != i) {
+ *group_map_iter = ELEM_MERGED;
+ }
+ else {
+ *group_map_iter = wgroups_len;
+ wgroups_len++;
+ }
+ }
+ else {
+ *group_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
+
+ const WeldVert *wv = &wvert[0];
+ for (uint i = wvert_tot; i--; wv++) {
+ uint group_index = r_vert_groups_map[wv->vert_dest];
+ wgroups[group_index].len++;
+ }
+
+ uint ofs = 0;
+ struct WeldGroup *wg_iter = &wgroups[0];
+ for (uint i = wgroups_len; i--; wg_iter++) {
+ wg_iter->ofs = ofs;
+ ofs += wg_iter->len;
+ }
+
+ BLI_assert(ofs == wvert_tot);
+
+ uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
+ wv = &wvert[0];
+ for (uint i = wvert_tot; i--; wv++) {
+ uint group_index = r_vert_groups_map[wv->vert_dest];
+ groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
+ }
+
+ wg_iter = &wgroups[0];
+ for (uint i = wgroups_len; i--; wg_iter++) {
+ wg_iter->ofs -= wg_iter->len;
+ }
+
+ *r_vert_groups = wgroups;
+ *r_vert_groups_buffer = groups_buffer;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Edge API
+ * \{ */
+
+static void weld_edge_ctx_setup(const uint vert_tot,
+ const uint wedge_len,
+ struct WeldGroup *r_vlinks,
+ uint *r_edge_dest_map,
+ WeldEdge *r_wedge,
+ uint *r_edge_kiil_tot)
+{
+ WeldEdge *we;
+
+ /* Setup Edge Overlap. */
+ uint edge_kill_tot = 0;
+
+ struct WeldGroup *vl_iter, *v_links;
+ v_links = r_vlinks;
+ vl_iter = &v_links[0];
+
+ we = &r_wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ if (dst_vert_a == dst_vert_b) {
+ BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
+ we->flag = ELEM_COLLAPSED;
+ edge_kill_tot++;
+ continue;
+ }
+
+ v_links[dst_vert_a].len++;
+ v_links[dst_vert_b].len++;
+ }
+
+ uint link_tot = 0;
+ vl_iter = &v_links[0];
+ for (uint i = vert_tot; i--; vl_iter++) {
+ vl_iter->ofs = link_tot;
+ link_tot += vl_iter->len;
+ }
+
+ if (link_tot) {
+ uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_tot, __func__);
+
+ we = &r_wedge[0];
+ for (uint i = 0; i < wedge_len; i++, we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
+ link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
+ }
+
+ vl_iter = &v_links[0];
+ for (uint i = vert_tot; i--; vl_iter++) {
+ /* Fix offset */
+ vl_iter->ofs -= vl_iter->len;
+ }
+
+ we = &r_wedge[0];
+ for (uint i = 0; i < wedge_len; i++, we++) {
+ if (we->edge_dest != OUT_OF_CONTEXT) {
+ /* No need to retest edges.
+ * (Already includes collapsed edges). */
+ continue;
+ }
+
+ uint dst_vert_a = we->vert_a;
+ uint dst_vert_b = we->vert_b;
+
+ struct WeldGroup *link_a = &v_links[dst_vert_a];
+ struct WeldGroup *link_b = &v_links[dst_vert_b];
+
+ uint edges_len_a = link_a->len;
+ uint edges_len_b = link_b->len;
+
+ if (edges_len_a <= 1 || edges_len_b <= 1) {
+ continue;
+ }
+
+ uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ uint edge_orig = we->edge_orig;
+
+ for (; edges_len_a--; edges_ctx_a++) {
+ uint e_ctx_a = *edges_ctx_a;
+ if (e_ctx_a == i) {
+ continue;
+ }
+ while (edges_len_b && *edges_ctx_b < e_ctx_a) {
+ edges_ctx_b++;
+ edges_len_b--;
+ }
+ if (edges_len_b == 0) {
+ break;
+ }
+ uint e_ctx_b = *edges_ctx_b;
+ if (e_ctx_a == e_ctx_b) {
+ WeldEdge *we_b = &r_wedge[e_ctx_b];
+ BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
+ BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b));
+ BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT);
+ BLI_assert(we_b->edge_orig != edge_orig);
+ r_edge_dest_map[we_b->edge_orig] = edge_orig;
+ we_b->edge_dest = edge_orig;
+ edge_kill_tot++;
+ }
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_tot);
+#endif
+
+ MEM_freeN(link_edge_buffer);
+ }
+
+ *r_edge_kiil_tot = edge_kill_tot;
+}
+
+static void weld_edge_ctx_alloc(const MEdge *medge,
+ const uint edge_tot,
+ const uint *vert_dest_map,
+ uint *r_edge_dest_map,
+ uint **r_edge_ctx_map,
+ WeldEdge **r_wedge,
+ uint *r_wedge_len)
+{
+ /* Edge Context. */
+ uint *edge_map = MEM_mallocN(sizeof(*edge_map) * edge_tot, __func__);
+ uint wedge_tot = 0;
+
+ WeldEdge *wedge, *we;
+ wedge = MEM_mallocN(sizeof(*wedge) * edge_tot, __func__);
+ we = &wedge[0];
+
+ const MEdge *me = &medge[0];
+ uint *e_dest_iter = &r_edge_dest_map[0];
+ uint *iter = &edge_map[0];
+ for (uint i = 0; i < edge_tot; i++, me++, iter++, e_dest_iter++) {
+ uint v1 = me->v1;
+ uint v2 = me->v2;
+ uint v_dest_1 = vert_dest_map[v1];
+ uint v_dest_2 = vert_dest_map[v2];
+ if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
+ we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we->edge_dest = OUT_OF_CONTEXT;
+ we->edge_orig = i;
+ we++;
+ *e_dest_iter = i;
+ *iter = wedge_tot++;
+ }
+ else {
+ *e_dest_iter = OUT_OF_CONTEXT;
+ *iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_tot);
+ *r_wedge_len = wedge_tot;
+ *r_edge_ctx_map = edge_map;
+}
+
+static void weld_edge_groups_setup(const uint edge_tot,
+ const uint edge_kill_tot,
+ const uint wedge_len,
+ WeldEdge *wedge,
+ const uint *wedge_map,
+ uint *r_edge_groups_map,
+ uint **r_edge_groups_buffer,
+ struct WeldGroupEdge **r_edge_groups)
+{
+
+ /* Get weld edge groups. */
+
+ struct WeldGroupEdge *wegroups, *wegrp_iter;
+
+ uint wgroups_len = wedge_len - edge_kill_tot;
+ wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
+ wegrp_iter = &wegroups[0];
+
+ wgroups_len = 0;
+ const uint *edge_ctx_iter = &wedge_map[0];
+ uint *group_map_iter = &r_edge_groups_map[0];
+ for (uint i = edge_tot; i--; edge_ctx_iter++, group_map_iter++) {
+ uint edge_ctx = *edge_ctx_iter;
+ if (edge_ctx != OUT_OF_CONTEXT) {
+ WeldEdge *we = &wedge[edge_ctx];
+ uint edge_dest = we->edge_dest;
+ if (edge_dest != OUT_OF_CONTEXT) {
+ BLI_assert(edge_dest != we->edge_orig);
+ *group_map_iter = ELEM_MERGED;
+ }
+ else {
+ we->edge_dest = we->edge_orig;
+ wegrp_iter->v1 = we->vert_a;
+ wegrp_iter->v2 = we->vert_b;
+ *group_map_iter = wgroups_len;
+ wgroups_len++;
+ wegrp_iter++;
+ }
+ }
+ else {
+ *group_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ BLI_assert(wgroups_len == wedge_len - edge_kill_tot);
+
+ WeldEdge *we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint group_index = r_edge_groups_map[we->edge_dest];
+ wegroups[group_index].group.len++;
+ }
+
+ uint ofs = 0;
+ wegrp_iter = &wegroups[0];
+ for (uint i = wgroups_len; i--; wegrp_iter++) {
+ wegrp_iter->group.ofs = ofs;
+ ofs += wegrp_iter->group.len;
+ }
+
+ uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
+ we = &wedge[0];
+ for (uint i = wedge_len; i--; we++) {
+ if (we->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint group_index = r_edge_groups_map[we->edge_dest];
+ groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
+ }
+
+ wegrp_iter = &wegroups[0];
+ for (uint i = wgroups_len; i--; wegrp_iter++) {
+ wegrp_iter->group.ofs -= wegrp_iter->group.len;
+ }
+
+ *r_edge_groups_buffer = groups_buffer;
+ *r_edge_groups = wegroups;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Poly and Loop API
+ * \{ */
+
+static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
+ const WeldPoly *wp,
+ const WeldLoop *wloop,
+ const MLoop *mloop,
+ const uint *loop_map,
+ uint *group_buffer)
+{
+ if (wp->flag == ELEM_COLLAPSED) {
+ return false;
+ }
+
+ iter->loop_start = wp->loop_start;
+ iter->loop_end = wp->loop_end;
+ iter->wloop = wloop;
+ iter->mloop = mloop;
+ iter->loop_map = loop_map;
+ iter->group = group_buffer;
+
+ iter->l_next = iter->loop_start;
+#ifdef USE_WELD_DEBUG
+ iter->v = OUT_OF_CONTEXT;
+#endif
+ return true;
+}
+
+static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
+{
+ uint loop_end = iter->loop_end;
+ const WeldLoop *wloop = iter->wloop;
+ const uint *loop_map = iter->loop_map;
+ iter->group_len = 0;
+ uint l = iter->l_curr = iter->l_next;
+ while (l <= loop_end) {
+ uint l_next = l + 1;
+ const uint loop_ctx = loop_map[l];
+ if (loop_ctx != OUT_OF_CONTEXT) {
+ const WeldLoop *wl = &wloop[loop_ctx];
+ if (wl->loop_skip_to != OUT_OF_CONTEXT) {
+ l_next = wl->loop_skip_to;
+ }
+ if (wl->flag == ELEM_COLLAPSED) {
+ if (iter->group) {
+ if (l == iter->loop_start) {
+ uint l_prev = loop_end;
+ const uint loop_ctx_end = loop_map[l_prev];
+ if (loop_ctx_end != OUT_OF_CONTEXT) {
+ const WeldLoop *wl_prev = &wloop[loop_ctx_end];
+ while (wl_prev->flag == ELEM_COLLAPSED) {
+ iter->group[iter->group_len++] = l_prev--;
+ wl_prev--;
+ if (wl_prev->loop_orig != l_prev) {
+ break;
+ }
+ }
+ }
+ }
+ iter->group[iter->group_len++] = l;
+ }
+ l = l_next;
+ continue;
+ }
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter->v != wl->vert);
+#endif
+ iter->v = wl->vert;
+ iter->e = wl->edge;
+ iter->type = 1;
+ }
+ else {
+ const MLoop *ml = &iter->mloop[l];
+#ifdef USE_WELD_DEBUG
+ BLI_assert(iter->v != ml->v);
+#endif
+ iter->v = ml->v;
+ iter->e = ml->e;
+ iter->type = 0;
+ }
+ if (iter->group) {
+ iter->group[iter->group_len++] = l;
+ }
+ iter->l_next = l_next;
+ return true;
+ }
+
+ return false;
+}
+
+static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
+ const uint mpoly_len,
+ const MLoop *mloop,
+ const uint mloop_len,
+ const uint *vert_dest_map,
+ const uint *edge_dest_map,
+ WeldMesh *r_weld_mesh)
+{
+ /* Loop/Poly Context. */
+ uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
+ uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
+ uint wloop_len = 0;
+ uint wpoly_len = 0;
+ uint max_ctx_poly_len = 4;
+
+ WeldLoop *wloop, *wl;
+ wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
+ wl = &wloop[0];
+
+ WeldPoly *wpoly, *wp;
+ wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
+ wp = &wpoly[0];
+
+ uint maybe_new_poly = 0;
+
+ const MPoly *mp = &mpoly[0];
+ uint *iter = &poly_map[0];
+ uint *loop_map_iter = &loop_map[0];
+ for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
+ const uint loopstart = mp->loopstart;
+ const uint totloop = mp->totloop;
+
+ uint vert_ctx_len = 0;
+
+ uint l = loopstart;
+ uint prev_wloop_len = wloop_len;
+ const MLoop *ml = &mloop[l];
+ for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
+ uint v = ml->v;
+ uint e = ml->e;
+ uint v_dest = vert_dest_map[v];
+ uint e_dest = edge_dest_map[e];
+ bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
+ bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
+ if (is_vert_ctx) {
+ vert_ctx_len++;
+ }
+ if (is_vert_ctx || is_edge_ctx) {
+ wl->vert = is_vert_ctx ? v_dest : v;
+ wl->edge = is_edge_ctx ? e_dest : e;
+ wl->loop_orig = l;
+ wl->loop_skip_to = OUT_OF_CONTEXT;
+ wl++;
+
+ *loop_map_iter = wloop_len++;
+ }
+ else {
+ *loop_map_iter = OUT_OF_CONTEXT;
+ }
+ }
+ if (wloop_len != prev_wloop_len) {
+ uint loops_len = wloop_len - prev_wloop_len;
+
+ wp->poly_dst = OUT_OF_CONTEXT;
+ wp->poly_orig = i;
+ wp->loops.len = loops_len;
+ wp->loops.ofs = prev_wloop_len;
+ wp->loop_start = loopstart;
+ wp->loop_end = loopstart + totloop - 1;
+ wp->len = totloop;
+ wp++;
+
+ *iter = wpoly_len++;
+ if (totloop > 5 && vert_ctx_len > 1) {
+ uint max_new = (totloop / 3) - 1;
+ vert_ctx_len /= 2;
+ maybe_new_poly += MIN2(max_new, vert_ctx_len);
+ CLAMP_MIN(max_ctx_poly_len, totloop);
+ }
+ }
+ else {
+ *iter = OUT_OF_CONTEXT;
+ }
+ }
+
+ if (mpoly_len < (wpoly_len + maybe_new_poly)) {
+ WeldPoly *wpoly_tmp = wpoly;
+ wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
+ memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
+ MEM_freeN(wpoly_tmp);
+ }
+
+ WeldPoly *poly_new = &wpoly[wpoly_len];
+
+ r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
+ r_weld_mesh->wpoly = wpoly;
+ r_weld_mesh->wpoly_new = poly_new;
+ r_weld_mesh->wloop_len = wloop_len;
+ r_weld_mesh->wpoly_len = wpoly_len;
+ r_weld_mesh->wpoly_new_len = 0;
+ r_weld_mesh->loop_map = loop_map;
+ r_weld_mesh->poly_map = poly_map;
+ r_weld_mesh->max_poly_len = max_ctx_poly_len;
+}
+
+static void weld_poly_split_recursive(const uint *vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ const MLoop *mloop,
+#endif
+ uint ctx_verts_len,
+ WeldPoly *r_wp,
+ WeldMesh *r_weld_mesh,
+ uint *r_poly_kill,
+ uint *r_loop_kill)
+{
+ uint poly_len = r_wp->len;
+ if (poly_len > 3 && ctx_verts_len > 1) {
+ const uint ctx_loops_len = r_wp->loops.len;
+ const uint ctx_loops_ofs = r_wp->loops.ofs;
+ WeldLoop *wloop = r_weld_mesh->wloop;
+ WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
+
+ uint loop_kill = 0;
+
+ WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
+ WeldLoop *wla = &poly_loops[0];
+ WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1];
+ while (wla_prev->flag == ELEM_COLLAPSED) {
+ wla_prev--;
+ }
+ const uint la_len = ctx_loops_len - 1;
+ for (uint la = 0; la < la_len; la++, wla++) {
+ wa_continue:
+ if (wla->flag == ELEM_COLLAPSED) {
+ continue;
+ }
+ uint vert_a = wla->vert;
+ /* Only test vertices that will be merged. */
+ if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
+ uint lb = la + 1;
+ WeldLoop *wlb = wla + 1;
+ WeldLoop *wlb_prev = wla;
+ uint killed_ab = 0;
+ ctx_verts_len = 1;
+ for (; lb < ctx_loops_len; lb++, wlb++) {
+ BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
+ if (wlb->flag == ELEM_COLLAPSED) {
+ killed_ab++;
+ continue;
+ }
+ uint vert_b = wlb->vert;
+ if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ if (vert_a == vert_b) {
+ const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const uint dist_b = poly_len - dist_a;
+
+ BLI_assert(dist_a != 0 && dist_b != 0);
+ if (dist_a == 1 || dist_b == 1) {
+ BLI_assert(dist_a != dist_b);
+ BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
+ }
+ else {
+ WeldLoop *wl_tmp = NULL;
+ if (dist_a == 2) {
+ wl_tmp = wlb_prev;
+ BLI_assert(wla->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wla->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (dist_b == 2) {
+ if (wl_tmp != NULL) {
+ r_wp->flag = ELEM_COLLAPSED;
+ *r_poly_kill += 1;
+ }
+ else {
+ wl_tmp = wla_prev;
+ BLI_assert(wlb->flag != ELEM_COLLAPSED);
+ BLI_assert(wl_tmp->flag != ELEM_COLLAPSED);
+ wlb->flag = ELEM_COLLAPSED;
+ wl_tmp->flag = ELEM_COLLAPSED;
+ }
+ loop_kill += 2;
+ poly_len -= 2;
+ }
+ if (wl_tmp == NULL) {
+ const uint new_loops_len = lb - la;
+ const uint new_loops_ofs = ctx_loops_ofs + la;
+
+ WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
+ new_wp->poly_dst = OUT_OF_CONTEXT;
+ new_wp->poly_orig = r_wp->poly_orig;
+ new_wp->loops.len = new_loops_len;
+ new_wp->loops.ofs = new_loops_ofs;
+ new_wp->loop_start = wla->loop_orig;
+ new_wp->loop_end = wlb_prev->loop_orig;
+ new_wp->len = dist_a;
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ new_wp,
+ r_weld_mesh,
+ r_poly_kill,
+ r_loop_kill);
+ BLI_assert(dist_b == poly_len - dist_a);
+ poly_len = dist_b;
+ if (wla_prev->loop_orig > wla->loop_orig) {
+ /* New start. */
+ r_wp->loop_start = wlb->loop_orig;
+ }
+ else {
+ /* The `loop_start` doesn't change but some loops must be skipped. */
+ wla_prev->loop_skip_to = wlb->loop_orig;
+ }
+ wla = wlb;
+ la = lb;
+ goto wa_continue;
+ }
+ break;
+ }
+ }
+ if (wlb->flag != ELEM_COLLAPSED) {
+ wlb_prev = wlb;
+ }
+ }
+ }
+ if (wla->flag != ELEM_COLLAPSED) {
+ wla_prev = wla;
+ }
+ }
+ r_wp->len = poly_len;
+ *r_loop_kill += loop_kill;
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
+#endif
+ }
+}
+
+static void weld_poly_loop_ctx_setup(const MLoop *mloop,
+#ifdef USE_WELD_DEBUG
+ const MPoly *mpoly,
+ const uint mpoly_len,
+ const uint mloop_len,
+#endif
+ const uint vert_tot,
+ const uint *vert_dest_map,
+ const uint remain_edge_ctx_len,
+ struct WeldGroup *r_vlinks,
+ WeldMesh *r_weld_mesh)
+{
+ uint poly_kill_tot, loop_kill_tot, wpoly_len, wpoly_new_tot;
+
+ WeldPoly *wpoly_new, *wpoly, *wp;
+ WeldLoop *wloop, *wl;
+
+ wpoly = r_weld_mesh->wpoly;
+ wloop = r_weld_mesh->wloop;
+ wpoly_new = r_weld_mesh->wpoly_new;
+ wpoly_len = r_weld_mesh->wpoly_len;
+ wpoly_new_tot = 0;
+ poly_kill_tot = 0;
+ loop_kill_tot = 0;
+
+ const uint *loop_map = r_weld_mesh->loop_map;
+
+ if (remain_edge_ctx_len) {
+
+ /* Setup Poly/Loop. */
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_len; i--; wp++) {
+ const uint ctx_loops_len = wp->loops.len;
+ const uint ctx_loops_ofs = wp->loops.ofs;
+
+ uint poly_len = wp->len;
+ uint ctx_verts_len = 0;
+ wl = &wloop[ctx_loops_ofs];
+ for (uint l = ctx_loops_len; l--; wl++) {
+ const uint edge_dest = wl->edge;
+ if (edge_dest == ELEM_COLLAPSED) {
+ wl->flag = ELEM_COLLAPSED;
+ if (poly_len == 3) {
+ wp->flag = ELEM_COLLAPSED;
+ poly_kill_tot++;
+ loop_kill_tot += 3;
+ poly_len = 0;
+ break;
+ }
+ loop_kill_tot++;
+ poly_len--;
+ }
+ else {
+ const uint vert_dst = wl->vert;
+ if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
+ ctx_verts_len++;
+ }
+ }
+ }
+
+ if (poly_len) {
+ wp->len = poly_len;
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_len(wp, wloop);
+#endif
+
+ weld_poly_split_recursive(vert_dest_map,
+#ifdef USE_WELD_DEBUG
+ mloop,
+#endif
+ ctx_verts_len,
+ wp,
+ r_weld_mesh,
+ &poly_kill_tot,
+ &loop_kill_tot);
+
+ wpoly_new_tot = r_weld_mesh->wpoly_new_len;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ wpoly_new,
+ wpoly_new_tot,
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ mpoly_len,
+ mloop_len,
+ poly_kill_tot,
+ loop_kill_tot);
+#endif
+
+ /* Setup Polygon Overlap. */
+
+ uint wpoly_and_new_tot = wpoly_len + wpoly_new_tot;
+
+ struct WeldGroup *vl_iter, *v_links = r_vlinks;
+ memset(v_links, 0, sizeof(*v_links) * vert_tot);
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_and_new_tot; i--; wp++) {
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ v_links[iter.v].len++;
+ }
+ }
+ }
+
+ uint link_tot = 0;
+ vl_iter = &v_links[0];
+ for (uint i = vert_tot; i--; vl_iter++) {
+ vl_iter->ofs = link_tot;
+ link_tot += vl_iter->len;
+ }
+
+ if (link_tot) {
+ uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_tot, __func__);
+
+ wp = &wpoly[0];
+ for (uint i = 0; i < wpoly_and_new_tot; i++, wp++) {
+ WeldLoopOfPolyIter iter;
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ link_poly_buffer[v_links[iter.v].ofs++] = i;
+ }
+ }
+ }
+
+ vl_iter = &v_links[0];
+ for (uint i = vert_tot; i--; vl_iter++) {
+ /* Fix offset */
+ vl_iter->ofs -= vl_iter->len;
+ }
+
+ uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ polys_len_b = p_ctx_b = 0; /* silence warnings */
+
+ wp = &wpoly[0];
+ for (uint i = 0; i < wpoly_and_new_tot; i++, wp++) {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ /* No need to retest poly.
+ * (Already includes collapsed polygons). */
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter;
+ weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
+ weld_iter_loop_of_poly_next(&iter);
+ struct WeldGroup *link_a = &v_links[iter.v];
+ polys_len_a = link_a->len;
+ if (polys_len_a == 1) {
+ BLI_assert(link_poly_buffer[link_a->ofs] == i);
+ continue;
+ }
+ uint wp_len = wp->len;
+ polys_ctx_a = &link_poly_buffer[link_a->ofs];
+ for (; polys_len_a--; polys_ctx_a++) {
+ p_ctx_a = *polys_ctx_a;
+ if (p_ctx_a == i) {
+ continue;
+ }
+
+ WeldPoly *wp_tmp = &wpoly[p_ctx_a];
+ if (wp_tmp->len != wp_len) {
+ continue;
+ }
+
+ WeldLoopOfPolyIter iter_b = iter;
+ while (weld_iter_loop_of_poly_next(&iter_b)) {
+ struct WeldGroup *link_b = &v_links[iter_b.v];
+ polys_len_b = link_b->len;
+ if (polys_len_b == 1) {
+ BLI_assert(link_poly_buffer[link_b->ofs] == i);
+ polys_len_b = 0;
+ break;
+ }
+
+ polys_ctx_b = &link_poly_buffer[link_b->ofs];
+ for (; polys_len_b; polys_len_b--, polys_ctx_b++) {
+ p_ctx_b = *polys_ctx_b;
+ if (p_ctx_b < p_ctx_a) {
+ continue;
+ }
+ if (p_ctx_b >= p_ctx_a) {
+ if (p_ctx_b > p_ctx_a) {
+ polys_len_b = 0;
+ }
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ break;
+ }
+ }
+ if (polys_len_b == 0) {
+ continue;
+ }
+ BLI_assert(p_ctx_a > i);
+ BLI_assert(p_ctx_a == p_ctx_b);
+ BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
+ BLI_assert(wp_tmp != wp);
+ wp_tmp->poly_dst = wp->poly_orig;
+ loop_kill_tot += wp_tmp->len;
+ poly_kill_tot++;
+ }
+ }
+ MEM_freeN(link_poly_buffer);
+ }
+ }
+ else {
+ poly_kill_tot = r_weld_mesh->wpoly_len;
+ loop_kill_tot = r_weld_mesh->wloop_len;
+
+ wp = &wpoly[0];
+ for (uint i = wpoly_len; i--; wp++) {
+ wp->flag = ELEM_COLLAPSED;
+ }
+ }
+
+#ifdef USE_WELD_DEBUG
+ weld_assert_poly_and_loop_kill_len(wpoly,
+ wpoly_new,
+ wpoly_new_tot,
+ wloop,
+ mloop,
+ loop_map,
+ r_weld_mesh->poly_map,
+ mpoly,
+ mpoly_len,
+ mloop_len,
+ poly_kill_tot,
+ loop_kill_tot);
+#endif
+
+ r_weld_mesh->wpoly_new = wpoly_new;
+ r_weld_mesh->poly_kill_tot = poly_kill_tot;
+ r_weld_mesh->loop_kill_tot = loop_kill_tot;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Mesh API
+ * \{ */
+
+static void weld_mesh_context_create(const Mesh *mesh,
+ BVHTreeOverlap *overlap,
+ const uint overlap_tot,
+ WeldMesh *r_weld_mesh)
+{
+ const MEdge *medge = mesh->medge;
+ const MLoop *mloop = mesh->mloop;
+ const MPoly *mpoly = mesh->mpoly;
+ const uint vert_tot = mesh->totvert;
+ const uint edge_tot = mesh->totedge;
+ const uint mloop_len = mesh->totloop;
+ const uint mpoly_len = mesh->totpoly;
+
+ uint *vert_dest_map = MEM_mallocN(sizeof(*vert_dest_map) * vert_tot, __func__);
+ uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * edge_tot, __func__);
+ struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * vert_tot, __func__);
+
+ WeldVert *wvert;
+ uint wvert_len;
+ weld_vert_ctx_alloc_and_setup(vert_tot,
+ overlap,
+ overlap_tot,
+ vert_dest_map,
+ &wvert,
+ &wvert_len,
+ &r_weld_mesh->vert_kill_tot);
+
+ uint *edge_ctx_map;
+ WeldEdge *wedge;
+ uint wedge_len;
+ weld_edge_ctx_alloc(
+ medge, edge_tot, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
+
+ weld_edge_ctx_setup(
+ vert_tot, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_tot);
+
+ weld_poly_loop_ctx_alloc(
+ mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
+
+ weld_poly_loop_ctx_setup(mloop,
+#ifdef USE_WELD_DEBUG
+ mpoly,
+ mpoly_len,
+ mloop_len,
+#endif
+ vert_tot,
+ vert_dest_map,
+ wedge_len - r_weld_mesh->edge_kill_tot,
+ v_links,
+ r_weld_mesh);
+
+ weld_vert_groups_setup(vert_tot,
+ wvert_len,
+ wvert,
+ vert_dest_map,
+ vert_dest_map,
+ &r_weld_mesh->vert_groups_buffer,
+ &r_weld_mesh->vert_groups);
+
+ weld_edge_groups_setup(edge_tot,
+ r_weld_mesh->edge_kill_tot,
+ wedge_len,
+ wedge,
+ edge_ctx_map,
+ edge_dest_map,
+ &r_weld_mesh->edge_groups_buffer,
+ &r_weld_mesh->edge_groups);
+
+ r_weld_mesh->vert_groups_map = vert_dest_map;
+ r_weld_mesh->edge_groups_map = edge_dest_map;
+ MEM_freeN(v_links);
+ MEM_freeN(wvert);
+ MEM_freeN(edge_ctx_map);
+ MEM_freeN(wedge);
+}
+
+static void weld_mesh_context_free(WeldMesh *weld_mesh)
+{
+ MEM_freeN(weld_mesh->vert_groups);
+ MEM_freeN(weld_mesh->vert_groups_buffer);
+ MEM_freeN(weld_mesh->vert_groups_map);
+
+ MEM_freeN(weld_mesh->edge_groups);
+ MEM_freeN(weld_mesh->edge_groups_buffer);
+ MEM_freeN(weld_mesh->edge_groups_map);
+
+ MEM_freeN(weld_mesh->wloop);
+ MEM_freeN(weld_mesh->wpoly);
+ MEM_freeN(weld_mesh->loop_map);
+ MEM_freeN(weld_mesh->poly_map);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld CustomData
+ * \{ */
+
+static void customdata_weld(
+ const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
+{
+ if (count == 1) {
+ CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
+ return;
+ }
+
+ int src_i, dest_i;
+ int j;
+
+ float co[3] = {0.0f, 0.0f, 0.0f};
+#ifdef USE_WELD_NORMALS
+ float no[3] = {0.0f, 0.0f, 0.0f};
+#endif
+ uint crease = 0;
+ uint bweight = 0;
+ char flag = 0;
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for (src_i = 0; src_i < source->totlayer; src_i++) {
+ const int type = source->layers[src_i].type;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) {
+ dest_i++;
+ }
+
+ /* if there are no more dest layers, we're done */
+ if (dest_i == dest->totlayer) {
+ break;
+ }
+
+ /* if we found a matching layer, add the data */
+ if (dest->layers[dest_i].type == type) {
+ void *src_data = source->layers[src_i].data;
+
+ if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = dest->layers[dest_i].data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ for (j = 0; j < count; j++) {
+ CustomData_data_add(
+ type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ }
+ }
+ else if (type == CD_MVERT) {
+ for (j = 0; j < count; j++) {
+ MVert *mv_src = &((MVert *)src_data)[src_indices[j]];
+ add_v3_v3(co, mv_src->co);
+#ifdef USE_WELD_NORMALS
+ short *mv_src_no = mv_src->no;
+ no[0] += mv_src_no[0];
+ no[1] += mv_src_no[1];
+ no[2] += mv_src_no[2];
+#endif
+ bweight += mv_src->bweight;
+ flag |= mv_src->flag;
+ }
+ }
+ else if (type == CD_MEDGE) {
+ for (j = 0; j < count; j++) {
+ MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
+ crease += me_src->crease;
+ bweight += me_src->bweight;
+ flag |= me_src->flag;
+ }
+ }
+ else {
+ CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1);
+ }
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ dest_i++;
+ }
+ }
+
+ float fac = 1.0f / count;
+
+ for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
+ CustomDataLayer *layer_dst = &dest->layers[dest_i];
+ const int type = layer_dst->type;
+ if (CustomData_layer_has_math(dest, dest_i)) {
+ const int size = CustomData_sizeof(type);
+ void *dst_data = layer_dst->data;
+ void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ CustomData_data_multiply(type, v_dst, fac);
+ }
+ else if (type == CD_MVERT) {
+ MVert *mv = &((MVert *)layer_dst->data)[dest_index];
+ mul_v3_fl(co, fac);
+ bweight *= fac;
+ CLAMP_MAX(bweight, 255);
+
+ copy_v3_v3(mv->co, co);
+#ifdef USE_WELD_NORMALS
+ mul_v3_fl(no, fac);
+ short *mv_no = mv->no;
+ mv_no[0] = (short)no[0];
+ mv_no[1] = (short)no[1];
+ mv_no[2] = (short)no[2];
+#endif
+
+ mv->flag = flag;
+ mv->bweight = (char)bweight;
+ }
+ else if (type == CD_MEDGE) {
+ MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
+ crease *= fac;
+ bweight *= fac;
+ CLAMP_MAX(crease, 255);
+ CLAMP_MAX(bweight, 255);
+
+ me->crease = (char)crease;
+ me->bweight = (char)bweight;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Weld Modifier Main
+ * \{ */
+
+struct WeldOverlapData {
+ const MVert *mvert;
+ float merge_dist_sq;
+};
+static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
+{
+ if (index_a < index_b) {
+ struct WeldOverlapData *data = userdata;
+ const MVert *mvert = data->mvert;
+ const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co);
+ return dist_sq <= data->merge_dist_sq;
+ }
+ return false;
+}
+
+static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ Mesh *result = mesh;
+
+ Object *ob = ctx->object;
+ BLI_bitmap *v_mask = NULL;
+ int v_mask_act = 0;
+
+ const MVert *mvert;
+ const MLoop *mloop;
+ const MPoly *mpoly, *mp;
+ uint totvert, totedge, totloop, totpoly;
+ uint i;
+
+ mvert = mesh->mvert;
+ totvert = mesh->totvert;
+
+ /* Vertex Group. */
+ const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name);
+ if (defgrp_index != -1) {
+ MDeformVert *dvert, *dv;
+ dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ dv = &dvert[0];
+ v_mask = BLI_BITMAP_NEW(totvert, __func__);
+ for (i = 0; i < totvert; i++, dv++) {
+ const bool found = defvert_find_weight(dv, defgrp_index) > 0.0f;
+ if (found) {
+ BLI_BITMAP_ENABLE(v_mask, i);
+ v_mask_act++;
+ }
+ }
+ }
+
+ /* Get overlap map. */
+ /* TODO: For a better performanse use KD-Tree. */
+ struct BVHTreeFromMesh treedata;
+ BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(
+ &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist, 2, 6, 0, NULL);
+
+ struct WeldOverlapData data;
+ data.mvert = mvert;
+ data.merge_dist_sq = SQUARE(wmd->merge_dist);
+
+ uint overlap_tot;
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree,
+ bvhtree,
+ &overlap_tot,
+ bvhtree_weld_overlap_cb,
+ &data,
+ wmd->max_interactions,
+ BVH_OVERLAP_RETURN_PAIRS);
+
+ free_bvhtree_from_mesh(&treedata);
+
+ if (overlap_tot) {
+ WeldMesh weld_mesh;
+ weld_mesh_context_create(mesh, overlap, overlap_tot, &weld_mesh);
+
+ mloop = mesh->mloop;
+ mpoly = mesh->mpoly;
+
+ totedge = mesh->totedge;
+ totloop = mesh->totloop;
+ totpoly = mesh->totpoly;
+
+ const int result_nverts = totvert - weld_mesh.vert_kill_tot;
+ const int result_nedges = totedge - weld_mesh.edge_kill_tot;
+ const int result_nloops = totloop - weld_mesh.loop_kill_tot;
+ const int result_npolys = totpoly - weld_mesh.poly_kill_tot + weld_mesh.wpoly_new_len;
+
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+
+ /* Vertices */
+
+ uint *vert_final = weld_mesh.vert_groups_map;
+ uint *index_iter = &vert_final[0];
+ int dest_index = 0;
+ for (i = 0; i < totvert; i++, index_iter++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
+ *index_iter = dest_index + count;
+ index_iter++;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
+ dest_index += count;
+ }
+ if (i == totvert) {
+ break;
+ }
+ if (*index_iter != ELEM_MERGED) {
+ struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter];
+ customdata_weld(&mesh->vdata,
+ &result->vdata,
+ &weld_mesh.vert_groups_buffer[wgroup->ofs],
+ wgroup->len,
+ dest_index);
+ *index_iter = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nverts);
+
+ /* Edges */
+
+ uint *edge_final = weld_mesh.edge_groups_map;
+ index_iter = &edge_final[0];
+ dest_index = 0;
+ for (i = 0; i < totedge; i++, index_iter++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
+ *index_iter = dest_index + count;
+ index_iter++;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
+ MEdge *me = &result->medge[dest_index];
+ dest_index += count;
+ for (; count--; me++) {
+ me->v1 = vert_final[me->v1];
+ me->v2 = vert_final[me->v2];
+ }
+ }
+ if (i == totedge) {
+ break;
+ }
+ if (*index_iter != ELEM_MERGED) {
+ struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter];
+ customdata_weld(&mesh->edata,
+ &result->edata,
+ &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
+ wegrp->group.len,
+ dest_index);
+ MEdge *me = &result->medge[dest_index];
+ me->v1 = vert_final[wegrp->v1];
+ me->v2 = vert_final[wegrp->v2];
+ me->flag |= ME_LOOSEEDGE;
+
+ *index_iter = dest_index;
+ dest_index++;
+ }
+ }
+
+ BLI_assert(dest_index == result_nedges);
+
+ /* Polys/Loops */
+
+ mp = &mpoly[0];
+ MPoly *r_mp = &result->mpoly[0];
+ MLoop *r_ml = &result->mloop[0];
+ uint r_i = 0;
+ int loop_cur = 0;
+ uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
+ for (i = 0; i < totpoly; i++, mp++) {
+ int loop_start = loop_cur;
+ uint poly_ctx = weld_mesh.poly_map[i];
+ if (poly_ctx == OUT_OF_CONTEXT) {
+ uint mp_totloop = mp->totloop;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_totloop);
+ loop_cur += mp_totloop;
+ for (; mp_totloop--; r_ml++) {
+ r_ml->v = vert_final[r_ml->v];
+ r_ml->e = edge_final[r_ml->e];
+ }
+ }
+ else {
+ WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
+ uint v = vert_final[iter.v];
+ uint e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+ }
+
+ CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ WeldPoly *wp = &weld_mesh.wpoly_new[0];
+ for (i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
+ int loop_start = loop_cur;
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ continue;
+ }
+ else {
+ if (wp->poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
+ uint v = vert_final[iter.v];
+ uint e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+ }
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
+
+ BLI_assert((int)r_i == result_npolys);
+ BLI_assert(loop_cur == result_nloops);
+
+ /* is this needed? */
+ /* recalculate normals */
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ weld_mesh_context_free(&weld_mesh);
+ }
+
+ if (v_mask) {
+ MEM_freeN(v_mask);
+ }
+ MEM_freeN(overlap);
+ return result;
+}
+
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+ return weldModifier_doWeld(wmd, ctx, mesh);
+}
+
+static void initData(ModifierData *md)
+{
+ WeldModifierData *wmd = (WeldModifierData *)md;
+
+ wmd->merge_dist = 0.001f;
+ wmd->max_interactions = 1;
+ wmd->defgrp_name[0] = '\0';
+}
+
+ModifierTypeInfo modifierType_Weld = {
+ /* name */ "Weld",
+ /* structName */ "WeldModifierData",
+ /* structSize */ sizeof(WeldModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs,
+
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
+};
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f24b7826b01..1f2eb4e28fc 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -3727,12 +3727,12 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle
ScrArea *sa = handler->dynamic.user_data;
handler->keymap_tool = NULL;
bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
- if (tref_rt && tref_rt->keymap[0]) {
+ if (tref_rt && (tref_rt->keymap[0] || tref_rt->keymap_fallback[0])) {
const char *keymap_id = tref_rt->keymap;
/* Support for the gizmo owning the tool keymap. */
if (USER_EXPEREMENTAL_TEST(&U, use_tool_fallback)) {
- if (tref_rt->gizmo_group[0] != '\0') {
+ if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') {
wmGizmoMap *gzmap = NULL;
wmGizmoGroup *gzgroup = NULL;
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
@@ -3750,9 +3750,7 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle
if (gzgroup->use_fallback_keymap) {
wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap);
if (highlight == NULL) {
- if (tref_rt->keymap_fallback[0]) {
- keymap_id = tref_rt->keymap_fallback;
- }
+ keymap_id = tref_rt->keymap_fallback;
}
}
}
@@ -3760,15 +3758,18 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle
}
}
- wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
- &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
- /* We shouldn't use keymaps from unrelated spaces. */
- if (km != NULL) {
- handler->keymap_tool = sa->runtime.tool;
- return km;
- }
- else {
- printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ if (keymap_id[0]) {
+ wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
+ &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW);
+ /* We shouldn't use keymaps from unrelated spaces. */
+ if (km != NULL) {
+ handler->keymap_tool = sa->runtime.tool;
+ return km;
+ }
+ else {
+ printf(
+ "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname);
+ }
}
}
return NULL;