Blender V4.5
MOD_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_utildefines.h"
10
11#include "BLI_array_utils.hh"
12#include "BLI_listbase.h"
13
14#include "BLT_translation.hh"
15
16#include "DNA_armature_types.h"
17#include "DNA_defaults.h"
18#include "DNA_mesh_types.h"
19#include "DNA_meshdata_types.h"
20#include "DNA_modifier_types.h"
21#include "DNA_object_types.h"
22#include "DNA_screen_types.h"
23
24#include "BKE_action.hh" /* BKE_pose_channel_find_name */
25#include "BKE_customdata.hh"
26#include "BKE_deform.hh"
27#include "BKE_lib_query.hh"
28#include "BKE_mesh.hh"
29#include "BKE_modifier.hh"
30
31#include "UI_interface.hh"
32#include "UI_resources.hh"
33
34#include "RNA_access.hh"
35#include "RNA_prototypes.hh"
36
38
39#include "MOD_ui_common.hh"
40
41#include "BLI_array.hh"
43#include "BLI_vector.hh"
44
45using blender::Array;
46using blender::float3;
48using blender::int2;
51using blender::Span;
52using blender::Vector;
53
62
63static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
64{
65 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
66}
67
68static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
69{
70 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
71 walk(user_data, ob, (ID **)&mmd->ob_arm, IDWALK_CB_NOP);
72}
73
75{
76 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
77 if (mmd->ob_arm) {
78 bArmature *arm = (bArmature *)mmd->ob_arm->data;
79 /* Tag relationship in depsgraph, but also on the armature. */
80 /* TODO(sergey): Is it a proper relation here? */
81 DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
82 arm->flag |= ARM_HAS_VIZ_DEPS;
83 DEG_add_depends_on_transform_relation(ctx->node, "Mask Modifier");
84 }
85}
86
87/* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */
89 Mesh *mesh,
90 Object *armature_ob,
91 float threshold,
92 MutableSpan<bool> r_vertex_mask)
93{
94 /* Element i is true if there is a selected bone that uses vertex group i. */
95 Vector<bool> selected_bone_uses_group;
96
98 bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name);
99 bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED);
100 selected_bone_uses_group.append(bone_for_group_exists);
101 }
102 const int64_t total_size = selected_bone_uses_group.size();
103
104 for (int i : r_vertex_mask.index_range()) {
105 Span<MDeformWeight> weights(dvert[i].dw, dvert[i].totweight);
106 r_vertex_mask[i] = false;
107
108 /* check the groups that vertex is assigned to, and see if it was any use */
109 for (const MDeformWeight &dw : weights) {
110 if (dw.def_nr >= total_size) {
111 continue;
112 }
113 if (selected_bone_uses_group[dw.def_nr]) {
114 if (dw.weight > threshold) {
115 r_vertex_mask[i] = true;
116 break;
117 }
118 }
119 }
120 }
121}
122
123/* A vertex will be in the mask if the vertex group influences it more than a certain threshold. */
125 int defgrp_index,
126 float threshold,
127 MutableSpan<bool> r_vertex_mask)
128{
129 for (int i : r_vertex_mask.index_range()) {
130 const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > threshold;
131 r_vertex_mask[i] = found;
132 }
133}
134
135static void compute_masked_verts(Span<bool> vertex_mask,
136 MutableSpan<int> r_vertex_map,
137 uint *r_verts_masked_num)
138{
139 BLI_assert(vertex_mask.size() == r_vertex_map.size());
140
141 uint verts_masked_num = 0;
142 for (uint i_src : r_vertex_map.index_range()) {
143 if (vertex_mask[i_src]) {
144 r_vertex_map[i_src] = verts_masked_num;
145 verts_masked_num++;
146 }
147 else {
148 r_vertex_map[i_src] = -1;
149 }
150 }
151
152 *r_verts_masked_num = verts_masked_num;
153}
154
155static void computed_masked_edges(const Mesh *mesh,
156 Span<bool> vertex_mask,
157 MutableSpan<int> r_edge_map,
158 uint *r_edges_masked_num)
159{
160 BLI_assert(mesh->edges_num == r_edge_map.size());
161 const Span<int2> edges = mesh->edges();
162
163 uint edges_masked_num = 0;
164 for (int i : IndexRange(mesh->edges_num)) {
165 const int2 &edge = edges[i];
166
167 /* only add if both verts will be in new mesh */
168 if (vertex_mask[edge[0]] && vertex_mask[edge[1]]) {
169 r_edge_map[i] = edges_masked_num;
170 edges_masked_num++;
171 }
172 else {
173 r_edge_map[i] = -1;
174 }
175 }
176
177 *r_edges_masked_num = edges_masked_num;
178}
179
180static void computed_masked_edges_smooth(const Mesh *mesh,
181 Span<bool> vertex_mask,
182 MutableSpan<int> r_edge_map,
183 uint *r_edges_masked_num,
184 uint *r_verts_add_num)
185{
186 BLI_assert(mesh->edges_num == r_edge_map.size());
187 const Span<int2> edges = mesh->edges();
188
189 uint edges_masked_num = 0;
190 uint verts_add_num = 0;
191 for (int i : IndexRange(mesh->edges_num)) {
192 const int2 &edge = edges[i];
193
194 /* only add if both verts will be in new mesh */
195 bool v1 = vertex_mask[edge[0]];
196 bool v2 = vertex_mask[edge[1]];
197 if (v1 && v2) {
198 r_edge_map[i] = edges_masked_num;
199 edges_masked_num++;
200 }
201 else if (v1 != v2) {
202 r_edge_map[i] = -2;
203 verts_add_num++;
204 }
205 else {
206 r_edge_map[i] = -1;
207 }
208 }
209
210 edges_masked_num += verts_add_num;
211 *r_edges_masked_num = edges_masked_num;
212 *r_verts_add_num = verts_add_num;
213}
214
215static void computed_masked_faces(const Mesh *mesh,
216 Span<bool> vertex_mask,
217 Vector<int> &r_masked_face_indices,
218 Vector<int> &r_loop_starts,
219 uint *r_faces_masked_num,
220 uint *r_loops_masked_num)
221{
222 BLI_assert(mesh->verts_num == vertex_mask.size());
223 const blender::OffsetIndices faces = mesh->faces();
224 const Span<int> corner_verts = mesh->corner_verts();
225
226 r_masked_face_indices.reserve(mesh->faces_num);
227 r_loop_starts.reserve(mesh->faces_num);
228
229 uint loops_masked_num = 0;
230 for (int i : IndexRange(mesh->faces_num)) {
231 const blender::IndexRange face = faces[i];
232
233 bool all_verts_in_mask = true;
234 for (const int vert_i : corner_verts.slice(face)) {
235 if (!vertex_mask[vert_i]) {
236 all_verts_in_mask = false;
237 break;
238 }
239 }
240
241 if (all_verts_in_mask) {
242 r_masked_face_indices.append_unchecked(i);
243 r_loop_starts.append_unchecked(loops_masked_num);
244 loops_masked_num += face.size();
245 }
246 }
247
248 *r_faces_masked_num = r_masked_face_indices.size();
249 *r_loops_masked_num = loops_masked_num;
250}
251
252static void compute_interpolated_faces(const Mesh *mesh,
253 Span<bool> vertex_mask,
254 uint verts_add_num,
255 uint loops_masked_num,
256 Vector<int> &r_masked_face_indices,
257 Vector<int> &r_loop_starts,
258 uint *r_edges_add_num,
259 uint *r_faces_add_num,
260 uint *r_loops_add_num)
261{
262 BLI_assert(mesh->verts_num == vertex_mask.size());
263
264 /* Can't really know ahead of time how much space to use exactly. Estimate limit instead. */
265 /* NOTE: this reserve can only lift the capacity if there are ngons, which get split. */
266 r_masked_face_indices.reserve(r_masked_face_indices.size() + verts_add_num);
267 r_loop_starts.reserve(r_loop_starts.size() + verts_add_num);
268 const blender::OffsetIndices faces = mesh->faces();
269 const Span<int> corner_verts = mesh->corner_verts();
270
271 uint edges_add_num = 0;
272 uint faces_add_num = 0;
273 uint loops_add_num = 0;
274 for (int i : IndexRange(mesh->faces_num)) {
275 const blender::IndexRange face_src = faces[i];
276
277 int in_count = 0;
278 int start = -1;
279 int dst_totloop = -1;
280 const Span<int> face_verts_src = corner_verts.slice(face_src);
281 for (const int j : face_verts_src.index_range()) {
282 const int vert_i = face_verts_src[j];
283 if (vertex_mask[vert_i]) {
284 in_count++;
285 }
286 else if (start == -1) {
287 start = j;
288 }
289 }
290 if (0 < in_count && in_count < face_src.size()) {
291 /* Ring search starting at a vertex which is not included in the mask. */
292 int last_corner_vert = face_verts_src[start];
293 bool v_loop_in_mask_last = vertex_mask[last_corner_vert];
294 for (const int j : face_verts_src.index_range()) {
295 const int corner_vert = face_verts_src[(start + 1 + j) % face_src.size()];
296 const bool v_loop_in_mask = vertex_mask[corner_vert];
297 if (v_loop_in_mask && !v_loop_in_mask_last) {
298 dst_totloop = 3;
299 }
300 else if (!v_loop_in_mask && v_loop_in_mask_last) {
301 BLI_assert(dst_totloop > 2);
302 r_masked_face_indices.append(i);
303 r_loop_starts.append(loops_masked_num + loops_add_num);
304 loops_add_num += dst_totloop;
305 faces_add_num++;
306 edges_add_num++;
307 dst_totloop = -1;
308 }
309 else if (v_loop_in_mask && v_loop_in_mask_last) {
310 BLI_assert(dst_totloop > 2);
311 dst_totloop++;
312 }
313 last_corner_vert = corner_vert;
314 v_loop_in_mask_last = v_loop_in_mask;
315 }
316 }
317 }
318
319 *r_edges_add_num = edges_add_num;
320 *r_faces_add_num = faces_add_num;
321 *r_loops_add_num = loops_add_num;
322}
323
324static void copy_masked_verts_to_new_mesh(const Mesh &src_mesh,
325 Mesh &dst_mesh,
326 Span<int> vertex_map)
327{
328 BLI_assert(src_mesh.verts_num == vertex_map.size());
329 for (const int i_src : vertex_map.index_range()) {
330 const int i_dst = vertex_map[i_src];
331 if (i_dst == -1) {
332 continue;
333 }
334
335 CustomData_copy_data(&src_mesh.vert_data, &dst_mesh.vert_data, i_src, i_dst, 1);
336 }
337}
338
340 const MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
341{
342 /* NOTE: this calculation is done twice for every vertex,
343 * instead of storing it the first time and then reusing it. */
344 float value1 = BKE_defvert_find_weight(&dvert[v1], defgrp_index);
345 float value2 = BKE_defvert_find_weight(&dvert[v2], defgrp_index);
346 return (threshold - value1) / (value2 - value1);
347}
348
350 Mesh &dst_mesh,
351 Span<bool> vertex_mask,
352 Span<int> vertex_map,
353 const MDeformVert *dvert,
354 int defgrp_index,
355 float threshold,
356 uint edges_masked_num,
357 uint verts_add_num,
358 MutableSpan<int> r_edge_map)
359{
360 BLI_assert(src_mesh.verts_num == vertex_mask.size());
361 BLI_assert(src_mesh.edges_num == r_edge_map.size());
362 const Span<int2> src_edges = src_mesh.edges();
363 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
364
365 uint vert_index = dst_mesh.verts_num - verts_add_num;
366 uint edge_index = edges_masked_num - verts_add_num;
367 for (int i_src : IndexRange(src_mesh.edges_num)) {
368 if (r_edge_map[i_src] != -1) {
369 int i_dst = r_edge_map[i_src];
370 if (i_dst == -2) {
371 i_dst = edge_index;
372 }
373 const int2 &e_src = src_edges[i_src];
374 int2 &e_dst = dst_edges[i_dst];
375
376 CustomData_copy_data(&src_mesh.edge_data, &dst_mesh.edge_data, i_src, i_dst, 1);
377 e_dst = e_src;
378 e_dst[0] = vertex_map[e_src[0]];
379 e_dst[1] = vertex_map[e_src[1]];
380 }
381 if (r_edge_map[i_src] == -2) {
382 const int i_dst = edge_index++;
383 r_edge_map[i_src] = i_dst;
384 const int2 &e_src = src_edges[i_src];
385 /* Cut destination edge and make v1 the new vertex. */
386 int2 &e_dst = dst_edges[i_dst];
387 if (!vertex_mask[e_src[0]]) {
388 e_dst[0] = vert_index;
389 }
390 else {
391 BLI_assert(!vertex_mask[e_src[1]]);
392 e_dst[1] = e_dst[0];
393 e_dst[0] = vert_index;
394 }
395 /* Create the new vertex. */
397 dvert, defgrp_index, threshold, e_src[0], e_src[1]);
398
399 float weights[2] = {1.0f - fac, fac};
401 &dst_mesh.vert_data,
402 (int *)&e_src[0],
403 weights,
404 nullptr,
405 2,
406 vert_index);
407 vert_index++;
408 }
409 }
410 BLI_assert(vert_index == dst_mesh.verts_num);
411 BLI_assert(edge_index == edges_masked_num);
412}
413
414static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
415 Mesh &dst_mesh,
416 Span<int> vertex_map,
417 Span<int> edge_map)
418{
419 const Span<int2> src_edges = src_mesh.edges();
420 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
421
422 BLI_assert(src_mesh.verts_num == vertex_map.size());
423 BLI_assert(src_mesh.edges_num == edge_map.size());
424 for (const int i_src : IndexRange(src_mesh.edges_num)) {
425 const int i_dst = edge_map[i_src];
426 if (ELEM(i_dst, -1, -2)) {
427 continue;
428 }
429
430 CustomData_copy_data(&src_mesh.edge_data, &dst_mesh.edge_data, i_src, i_dst, 1);
431 dst_edges[i_dst][0] = vertex_map[src_edges[i_src][0]];
432 dst_edges[i_dst][1] = vertex_map[src_edges[i_src][1]];
433 }
434}
435
436static void copy_masked_faces_to_new_mesh(const Mesh &src_mesh,
437 Mesh &dst_mesh,
438 Span<int> vertex_map,
439 Span<int> edge_map,
440 Span<int> masked_face_indices,
441 Span<int> new_loop_starts,
442 int faces_masked_num)
443{
444 const blender::OffsetIndices src_faces = src_mesh.faces();
445 MutableSpan<int> dst_face_offsets = dst_mesh.face_offsets_for_write();
446 const Span<int> src_corner_verts = src_mesh.corner_verts();
447 const Span<int> src_corner_edges = src_mesh.corner_edges();
448 MutableSpan<int> dst_corner_verts = dst_mesh.corner_verts_for_write();
449 MutableSpan<int> dst_corner_edges = dst_mesh.corner_edges_for_write();
450
451 for (const int i_dst : IndexRange(faces_masked_num)) {
452 const int i_src = masked_face_indices[i_dst];
453 const blender::IndexRange src_face = src_faces[i_src];
454
455 dst_face_offsets[i_dst] = new_loop_starts[i_dst];
456
457 CustomData_copy_data(&src_mesh.face_data, &dst_mesh.face_data, i_src, i_dst, 1);
459 &dst_mesh.corner_data,
460 src_face.start(),
461 dst_face_offsets[i_dst],
462 src_face.size());
463
464 for (int i : IndexRange(src_face.size())) {
465 dst_corner_verts[new_loop_starts[i_dst] + i] = vertex_map[src_corner_verts[src_face[i]]];
466 dst_corner_edges[new_loop_starts[i_dst] + i] = edge_map[src_corner_edges[src_face[i]]];
467 }
468 }
469}
470
471static void add_interpolated_faces_to_new_mesh(const Mesh &src_mesh,
472 Mesh &dst_mesh,
473 Span<bool> vertex_mask,
474 Span<int> vertex_map,
475 Span<int> edge_map,
476 const MDeformVert *dvert,
477 int defgrp_index,
478 float threshold,
479 Span<int> masked_face_indices,
480 Span<int> new_loop_starts,
481 int faces_masked_num,
482 int edges_add_num)
483{
484 const blender::OffsetIndices src_faces = src_mesh.faces();
485 MutableSpan<int> dst_face_offsets = dst_mesh.face_offsets_for_write();
486 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
487 const Span<int> src_corner_verts = src_mesh.corner_verts();
488 const Span<int> src_corner_edges = src_mesh.corner_edges();
489 MutableSpan<int> dst_corner_verts = dst_mesh.corner_verts_for_write();
490 MutableSpan<int> dst_corner_edges = dst_mesh.corner_edges_for_write();
491
492 int edge_index = dst_mesh.edges_num - edges_add_num;
493 int sub_face_index = 0;
494 int last_i_src = -1;
495 for (const int i_dst :
496 IndexRange(faces_masked_num, masked_face_indices.size() - faces_masked_num))
497 {
498 const int i_src = masked_face_indices[i_dst];
499 if (i_src == last_i_src) {
500 sub_face_index++;
501 }
502 else {
503 sub_face_index = 0;
504 last_i_src = i_src;
505 }
506
507 const blender::IndexRange src_face = src_faces[i_src];
508 const int i_ml_src = src_face.start();
509 int i_ml_dst = new_loop_starts[i_dst];
510 CustomData_copy_data(&src_mesh.face_data, &dst_mesh.face_data, i_src, i_dst, 1);
511
512 dst_face_offsets[i_dst] = i_ml_dst;
513
514 /* Ring search starting at a vertex which is not included in the mask. */
515 int start = -sub_face_index - 1;
516 bool skip = false;
517 const Span<int> face_verts_src = src_corner_verts.slice(src_face);
518 const Span<int> face_edges_src = src_corner_edges.slice(src_face);
519 for (const int j : face_verts_src.index_range()) {
520 if (!vertex_mask[face_verts_src[j]]) {
521 if (start == -1) {
522 start = j;
523 break;
524 }
525 if (!skip) {
526 skip = true;
527 }
528 }
529 else if (skip) {
530 skip = false;
531 start++;
532 }
533 }
534
535 BLI_assert(start >= 0);
536 BLI_assert(edge_index < dst_mesh.edges_num);
537
538 int last_index = start;
539 bool v_loop_in_mask_last = vertex_mask[face_verts_src[last_index]];
540 for (const int j : face_verts_src.index_range()) {
541 const int index = (start + 1 + j) % src_face.size();
542 const bool v_loop_in_mask = vertex_mask[face_verts_src[index]];
543 if (v_loop_in_mask && !v_loop_in_mask_last) {
544 /* Start new cut. */
546 dvert, defgrp_index, threshold, face_verts_src[last_index], face_verts_src[index]);
547 float weights[2] = {1.0f - fac, fac};
548 int indices[2] = {i_ml_src + last_index, i_ml_src + index};
550 &src_mesh.corner_data, &dst_mesh.corner_data, indices, weights, nullptr, 2, i_ml_dst);
551 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[last_index]];
552 dst_corner_verts[i_ml_dst] = dst_edges[dst_corner_edges[i_ml_dst]][0];
553 i_ml_dst++;
554
556 &src_mesh.corner_data, &dst_mesh.corner_data, i_ml_src + index, i_ml_dst, 1);
557 dst_corner_verts[i_ml_dst] = vertex_map[face_verts_src[index]];
558 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[index]];
559 i_ml_dst++;
560 }
561 else if (!v_loop_in_mask && v_loop_in_mask_last) {
562 BLI_assert(i_ml_dst != dst_face_offsets[i_dst]);
563 /* End active cut. */
565 dvert, defgrp_index, threshold, face_verts_src[last_index], face_verts_src[index]);
566 float weights[2] = {1.0f - fac, fac};
567 int indices[2] = {i_ml_src + last_index, i_ml_src + index};
569 &src_mesh.corner_data, &dst_mesh.corner_data, indices, weights, nullptr, 2, i_ml_dst);
570 dst_corner_edges[i_ml_dst] = edge_index;
571 dst_corner_verts[i_ml_dst] = dst_edges[edge_map[face_edges_src[last_index]]][0];
572
573 /* Create closing edge. */
574 int2 &cut_edge = dst_edges[edge_index];
575 cut_edge[0] = dst_corner_verts[dst_face_offsets[i_dst]];
576 cut_edge[1] = dst_corner_verts[i_ml_dst];
577 BLI_assert(cut_edge[0] != cut_edge[1]);
578 edge_index++;
579 i_ml_dst++;
580
581 /* Only handle one of the cuts per iteration. */
582 break;
583 }
584 else if (v_loop_in_mask && v_loop_in_mask_last) {
585 BLI_assert(i_ml_dst != dst_face_offsets[i_dst]);
586 /* Extend active face. */
588 &src_mesh.corner_data, &dst_mesh.corner_data, i_ml_src + index, i_ml_dst, 1);
589 dst_corner_verts[i_ml_dst] = vertex_map[face_verts_src[index]];
590 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[index]];
591 i_ml_dst++;
592 }
593 last_index = index;
594 v_loop_in_mask_last = v_loop_in_mask;
595 }
596 }
597 BLI_assert(edge_index == dst_mesh.edges_num);
598}
599
600/* Components of the algorithm:
601 * 1. Figure out which vertices should be present in the output mesh.
602 * 2. Find edges and faces only using those vertices.
603 * 3. Create a new mesh that only uses the found vertices, edges and faces.
604 */
605static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, Mesh *mesh)
606{
607 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
608 const bool invert_mask = mmd->flag & MOD_MASK_INV;
609 const bool use_interpolation = mmd->mode == MOD_MASK_MODE_VGROUP &&
610 (mmd->flag & MOD_MASK_SMOOTH);
611
612 /* Return empty or input mesh when there are no vertex groups. */
613 const Span<MDeformVert> dverts = mesh->deform_verts();
614 if (dverts.is_empty()) {
615 return invert_mask ? mesh : BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0);
616 }
617
618 /* Quick test to see if we can return early. */
619 if (!ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP) || (mesh->verts_num == 0) ||
621 {
622 return mesh;
623 }
624
625 int defgrp_index = -1;
626
627 Array<bool> vertex_mask;
628 if (mmd->mode == MOD_MASK_MODE_ARM) {
629 Object *armature_ob = mmd->ob_arm;
630
631 /* Return input mesh if there is no armature with bones. */
632 if (ELEM(nullptr, armature_ob, armature_ob->pose)) {
633 return mesh;
634 }
635
636 vertex_mask = Array<bool>(mesh->verts_num);
638 dverts.data(), mesh, armature_ob, mmd->threshold, vertex_mask);
639 }
640 else {
642 defgrp_index = BKE_id_defgroup_name_index(&mesh->id, mmd->vgroup);
643
644 /* Return input mesh if the vertex group does not exist. */
645 if (defgrp_index == -1) {
646 return mesh;
647 }
648
649 vertex_mask = Array<bool>(mesh->verts_num);
651 dverts.data(), defgrp_index, mmd->threshold, vertex_mask);
652 }
653
654 if (invert_mask) {
656 }
657
658 Array<int> vertex_map(mesh->verts_num);
659 uint verts_masked_num;
660 compute_masked_verts(vertex_mask, vertex_map, &verts_masked_num);
661
662 Array<int> edge_map(mesh->edges_num);
663 uint edges_masked_num;
664 uint verts_add_num;
665 if (use_interpolation) {
666 computed_masked_edges_smooth(mesh, vertex_mask, edge_map, &edges_masked_num, &verts_add_num);
667 }
668 else {
669 computed_masked_edges(mesh, vertex_mask, edge_map, &edges_masked_num);
670 verts_add_num = 0;
671 }
672
673 Vector<int> masked_face_indices;
674 Vector<int> new_loop_starts;
675 uint faces_masked_num;
676 uint loops_masked_num;
678 vertex_mask,
679 masked_face_indices,
680 new_loop_starts,
681 &faces_masked_num,
682 &loops_masked_num);
683
684 uint edges_add_num = 0;
685 uint faces_add_num = 0;
686 uint loops_add_num = 0;
687 if (use_interpolation) {
689 vertex_mask,
690 verts_add_num,
691 loops_masked_num,
692 masked_face_indices,
693 new_loop_starts,
694 &edges_add_num,
695 &faces_add_num,
696 &loops_add_num);
697 }
698
700 verts_masked_num + verts_add_num,
701 edges_masked_num + edges_add_num,
702 faces_masked_num + faces_add_num,
703 loops_masked_num + loops_add_num);
704
705 copy_masked_verts_to_new_mesh(*mesh, *result, vertex_map);
706 if (use_interpolation) {
708 *result,
709 vertex_mask,
710 vertex_map,
711 dverts.data(),
712 defgrp_index,
713 mmd->threshold,
714 edges_masked_num,
715 verts_add_num,
716 edge_map);
717 }
718 else {
719 copy_masked_edges_to_new_mesh(*mesh, *result, vertex_map, edge_map);
720 }
722 *result,
723 vertex_map,
724 edge_map,
725 masked_face_indices,
726 new_loop_starts,
727 faces_masked_num);
728 if (use_interpolation) {
730 *result,
731 vertex_mask,
732 vertex_map,
733 edge_map,
734 dverts.data(),
735 defgrp_index,
736 mmd->threshold,
737 masked_face_indices,
738 new_loop_starts,
739 faces_masked_num,
740 edges_add_num);
741 }
742
743 return result;
744}
745
746static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
747{
748 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
749
750 /* The object type check is only needed here in case we have a placeholder
751 * object assigned (because the library containing the armature is missing).
752 *
753 * In other cases it should be impossible to have a type mismatch.
754 */
755 return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE;
756}
757
758static void panel_draw(const bContext * /*C*/, Panel *panel)
759{
760 uiLayout *sub, *row;
761 uiLayout *layout = panel->layout;
762
763 PointerRNA ob_ptr;
765
766 int mode = RNA_enum_get(ptr, "mode");
767
768 layout->prop(ptr, "mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
769
770 uiLayoutSetPropSep(layout, true);
771
772 if (mode == MOD_MASK_MODE_ARM) {
773 row = &layout->row(true);
774 row->prop(ptr, "armature", UI_ITEM_NONE, std::nullopt, ICON_NONE);
775 sub = &row->row(true);
776 uiLayoutSetPropDecorate(sub, false);
777 sub->prop(ptr, "invert_vertex_group", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
778 }
779 else if (mode == MOD_MASK_MODE_VGROUP) {
780 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", std::nullopt);
781 layout->prop(ptr, "use_smooth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
782 }
783
784 layout->prop(ptr, "threshold", UI_ITEM_NONE, std::nullopt, ICON_NONE);
785
787}
788
789static void panel_register(ARegionType *region_type)
790{
792}
793
795 /*idname*/ "Mask",
796 /*name*/ N_("Mask"),
797 /*struct_name*/ "MaskModifierData",
798 /*struct_size*/ sizeof(MaskModifierData),
799 /*srna*/ &RNA_MaskModifier,
801 /*flags*/
804 /*icon*/ ICON_MOD_MASK,
805
806 /*copy_data*/ BKE_modifier_copydata_generic,
807
808 /*deform_verts*/ nullptr,
809 /*deform_matrices*/ nullptr,
810 /*deform_verts_EM*/ nullptr,
811 /*deform_matrices_EM*/ nullptr,
812 /*modify_mesh*/ modify_mesh,
813 /*modify_geometry_set*/ nullptr,
814
815 /*init_data*/ init_data,
816 /*required_data_mask*/ required_data_mask,
817 /*free_data*/ nullptr,
818 /*is_disabled*/ is_disabled,
819 /*update_depsgraph*/ update_depsgraph,
820 /*depends_on_time*/ nullptr,
821 /*depends_on_normals*/ nullptr,
822 /*foreach_ID_link*/ foreach_ID_link,
823 /*foreach_tex_link*/ nullptr,
824 /*free_runtime_data*/ nullptr,
825 /*panel_register*/ panel_register,
826 /*blend_write*/ nullptr,
827 /*blend_read*/ nullptr,
828 /*foreach_cache*/ nullptr,
829};
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
CustomData interface, see also DNA_customdata_types.h.
void CustomData_interp(const CustomData *source, CustomData *dest, const int *src_indices, const float *weights, const float *sub_weights, int count, int dest_index)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:538
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:763
@ IDWALK_CB_NOP
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
unsigned int uint
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
@ BONE_SELECTED
@ ARM_HAS_VIZ_DEPS
#define DNA_struct_default_get(struct_name)
@ MOD_MASK_SMOOTH
@ MOD_MASK_INV
@ MOD_MASK_MODE_ARM
@ MOD_MASK_MODE_VGROUP
@ eModifierType_Mask
Object is a sort of wrapper for general info.
@ OB_ARMATURE
static bool is_disabled
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
static void panel_draw(const bContext *, Panel *panel)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void init_data(ModifierData *md)
Definition MOD_mask.cc:54
static void panel_register(ARegionType *region_type)
Definition MOD_mask.cc:789
static float get_interp_factor_from_vgroup(const MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
Definition MOD_mask.cc:339
static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< bool > vertex_mask, Span< int > vertex_map, const MDeformVert *dvert, int defgrp_index, float threshold, uint edges_masked_num, uint verts_add_num, MutableSpan< int > r_edge_map)
Definition MOD_mask.cc:349
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
Definition MOD_mask.cc:63
static void copy_masked_faces_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map, Span< int > edge_map, Span< int > masked_face_indices, Span< int > new_loop_starts, int faces_masked_num)
Definition MOD_mask.cc:436
static void computed_masked_faces(const Mesh *mesh, Span< bool > vertex_mask, Vector< int > &r_masked_face_indices, Vector< int > &r_loop_starts, uint *r_faces_masked_num, uint *r_loops_masked_num)
Definition MOD_mask.cc:215
static void add_interpolated_faces_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< bool > vertex_mask, Span< int > vertex_map, Span< int > edge_map, const MDeformVert *dvert, int defgrp_index, float threshold, Span< int > masked_face_indices, Span< int > new_loop_starts, int faces_masked_num, int edges_add_num)
Definition MOD_mask.cc:471
static void computed_masked_edges(const Mesh *mesh, Span< bool > vertex_mask, MutableSpan< int > r_edge_map, uint *r_edges_masked_num)
Definition MOD_mask.cc:155
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *, Mesh *mesh)
Definition MOD_mask.cc:605
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map, Span< int > edge_map)
Definition MOD_mask.cc:414
static void compute_masked_verts(Span< bool > vertex_mask, MutableSpan< int > r_vertex_map, uint *r_verts_masked_num)
Definition MOD_mask.cc:135
static void panel_draw(const bContext *, Panel *panel)
Definition MOD_mask.cc:758
static void copy_masked_verts_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map)
Definition MOD_mask.cc:324
static void compute_interpolated_faces(const Mesh *mesh, Span< bool > vertex_mask, uint verts_add_num, uint loops_masked_num, Vector< int > &r_masked_face_indices, Vector< int > &r_loop_starts, uint *r_edges_add_num, uint *r_faces_add_num, uint *r_loops_add_num)
Definition MOD_mask.cc:252
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
Definition MOD_mask.cc:68
static void compute_vertex_mask__armature_mode(const MDeformVert *dvert, Mesh *mesh, Object *armature_ob, float threshold, MutableSpan< bool > r_vertex_mask)
Definition MOD_mask.cc:88
static void compute_vertex_mask__vertex_group_mode(const MDeformVert *dvert, int defgrp_index, float threshold, MutableSpan< bool > r_vertex_mask)
Definition MOD_mask.cc:124
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition MOD_mask.cc:74
ModifierTypeInfo modifierType_Mask
Definition MOD_mask.cc:794
static void computed_masked_edges_smooth(const Mesh *mesh, Span< bool > vertex_mask, MutableSpan< int > r_edge_map, uint *r_edges_masked_num, uint *r_verts_add_num)
Definition MOD_mask.cc:180
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const StringRefNull vgroup_prop, const std::optional< StringRefNull > invert_vgroup_prop, const std::optional< StringRefNull > text)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
@ UI_ITEM_R_EXPAND
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
long long int int64_t
const T * data() const
Definition BLI_array.hh:301
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
static ushort indices[]
#define CD_MASK_MDEFORMVERT
static void update_depsgraph(tGraphSliderOp *gso)
static char faces[256]
void invert_booleans(MutableSpan< bool > span)
VecBase< int32_t, 2 > int2
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
VecBase< float, 3 > float3
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition DNA_ID.h:404
struct Object * ob_arm
CustomData edge_data
int edges_num
CustomData corner_data
CustomData face_data
ListBase vertex_group_names
CustomData vert_data
int faces_num
int verts_num
struct bPose * pose
struct uiLayout * layout
struct Bone * bone
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4226