Blender V4.3
paint_vertex_weight_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_bitmap.h"
12#include "BLI_math_geom.h"
13#include "BLI_math_vector.h"
14
15#include "DNA_brush_types.h"
16#include "DNA_mesh_types.h"
17#include "DNA_meshdata_types.h"
18#include "DNA_object_types.h"
19#include "DNA_scene_types.h"
20
21#include "RNA_access.hh"
22#include "RNA_define.hh"
23
24#include "BKE_attribute.hh"
25#include "BKE_brush.hh"
26#include "BKE_colortools.hh"
27#include "BKE_context.hh"
28#include "BKE_deform.hh"
29#include "BKE_mesh.hh"
30#include "BKE_mesh_iterators.hh"
31#include "BKE_modifier.hh"
32#include "BKE_object.hh"
33#include "BKE_object_deform.h"
34#include "BKE_paint.hh"
35#include "BKE_report.hh"
36
37#include "DEG_depsgraph.hh"
39
40#include "WM_api.hh"
41#include "WM_types.hh"
42
43#include "ED_armature.hh"
44#include "ED_mesh.hh"
45#include "ED_screen.hh"
46#include "ED_view3d.hh"
47
48#include "UI_interface.hh"
49#include "UI_resources.hh"
50
51#include "paint_intern.hh" /* own include */
52
53/* -------------------------------------------------------------------- */
59struct WPaintPrev {
60 /* previous vertex weights */
62 /* allocation size of prev buffers */
63 int tot;
64};
65
67{
68 wpp->wpaint_prev = nullptr;
69 wpp->tot = 0;
70}
71
72static void wpaint_prev_create(WPaintPrev *wpp, MDeformVert *dverts, int dcount)
73{
75
76 if (dverts && dcount) {
77 wpp->wpaint_prev = static_cast<MDeformVert *>(
78 MEM_malloc_arrayN(dcount, sizeof(MDeformVert), __func__));
79 wpp->tot = dcount;
80 BKE_defvert_array_copy(wpp->wpaint_prev, dverts, dcount);
81 }
82}
83
85{
86 if (wpp->wpaint_prev) {
88 }
89 wpp->wpaint_prev = nullptr;
90 wpp->tot = 0;
91}
92
95/* -------------------------------------------------------------------- */
100{
102
104}
105
107{
109 Scene *scene = CTX_data_scene(C);
112 Mesh *mesh = static_cast<Mesh *>(ob->data);
113 int type = RNA_enum_get(op->ptr, "type");
114
116 op->reports, depsgraph, scene, ob, armob, type, (mesh->symmetry & ME_SYMMETRY_X));
117
118 DEG_id_tag_update(&mesh->id, 0);
121
122 return OPERATOR_FINISHED;
123}
124
126{
127 static const EnumPropertyItem type_items[] = {
128 {ARM_GROUPS_AUTO, "AUTOMATIC", 0, "Automatic", "Automatic weights from bones"},
130 "ENVELOPES",
131 0,
132 "From Envelopes",
133 "Weights from envelopes with user defined radius"},
134 {0, nullptr, 0, nullptr, nullptr},
135 };
136
137 /* identifiers */
138 ot->name = "Weight from Bones";
139 ot->idname = "PAINT_OT_weight_from_bones";
140 ot->description =
141 ("Set the weights of the groups matching the attached armature's selected bones, "
142 "using the distance between the vertices and the bones");
143
144 /* api callbacks */
148
149 /* flags */
151
152 /* properties */
154 ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights");
155}
156
159/* -------------------------------------------------------------------- */
168static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
169{
171 Mesh *mesh;
172 bool changed = false;
173
175 mesh = BKE_mesh_from_object(vc.obact);
176 const MDeformVert *dvert = mesh->deform_verts().data();
177
178 if (mesh && dvert && vc.v3d && vc.rv3d && (mesh->vertex_group_active_index != 0)) {
179 const bool use_vert_sel = (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
180 int v_idx_best = -1;
181 uint index;
182
185
186 if (use_vert_sel) {
188 C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index))
189 {
190 v_idx_best = index;
191 }
192 }
193 else {
195 {
196 v_idx_best = index;
197 }
198 else if (ED_mesh_pick_face(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index))
199 {
200 /* This relies on knowing the internal workings of #ED_mesh_pick_face_vert() */
202 op->reports, RPT_WARNING, "The modifier used does not support deformed locations");
203 }
204 }
205
206 if (v_idx_best != -1) { /* should always be valid */
208 Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
209 const int vgroup_active = mesh->vertex_group_active_index - 1;
210 float vgroup_weight = BKE_defvert_find_weight(&dvert[v_idx_best], vgroup_active);
211 const int defbase_tot = BLI_listbase_count(&mesh->vertex_group_names);
212 bool use_lock_relative = ts->wpaint_lock_relative;
213 bool *defbase_locked = nullptr, *defbase_unlocked = nullptr;
214
215 if (use_lock_relative) {
216 defbase_locked = BKE_object_defgroup_lock_flags_get(vc.obact, defbase_tot);
217 defbase_unlocked = BKE_object_defgroup_validmap_get(vc.obact, defbase_tot);
218
219 use_lock_relative = BKE_object_defgroup_check_lock_relative(
220 defbase_locked, defbase_unlocked, vgroup_active);
221 }
222
223 /* use combined weight in multipaint mode,
224 * since that's what is displayed to the user in the colors */
225 if (ts->multipaint) {
226 int defbase_tot_sel;
227 bool *defbase_sel = BKE_object_defgroup_selected_get(
228 vc.obact, defbase_tot, &defbase_tot_sel);
229
230 if (defbase_tot_sel > 1) {
233 vc.obact, defbase_tot, defbase_sel, defbase_sel, &defbase_tot_sel);
234 }
235
236 use_lock_relative = use_lock_relative &&
238 defbase_tot, defbase_locked, defbase_sel, defbase_tot_sel);
239
240 bool is_normalized = ts->auto_normalize || use_lock_relative;
242 &dvert[v_idx_best], defbase_tot, defbase_sel, defbase_tot_sel, is_normalized);
243 }
244
245 MEM_freeN(defbase_sel);
246 }
247
248 if (use_lock_relative) {
250 defbase_tot, defbase_locked, defbase_unlocked, defbase_locked, defbase_unlocked);
251
252 vgroup_weight = BKE_defvert_lock_relative_weight(
253 vgroup_weight, &dvert[v_idx_best], defbase_tot, defbase_locked, defbase_unlocked);
254 }
255
256 MEM_SAFE_FREE(defbase_locked);
257 MEM_SAFE_FREE(defbase_unlocked);
258
259 CLAMP(vgroup_weight, 0.0f, 1.0f);
260 BKE_brush_weight_set(vc.scene, brush, vgroup_weight);
261 changed = true;
262 }
263 }
264
265 if (changed) {
266 /* not really correct since the brush didn't change, but redraws the toolbar */
267 WM_main_add_notifier(NC_BRUSH | NA_EDITED, nullptr); /* ts->wpaint->paint.brush */
268
269 return OPERATOR_FINISHED;
270 }
271 return OPERATOR_CANCELLED;
272}
273
275{
276 /* identifiers */
277 ot->name = "Weight Paint Sample Weight";
278 ot->idname = "PAINT_OT_weight_sample";
279 ot->description = "Use the mouse to sample a weight in the 3D view";
280
281 /* api callbacks */
284
285 /* flags */
287}
288
291/* -------------------------------------------------------------------- */
301{
302 bool found = false;
303 int i = dvert->totweight;
304 MDeformWeight *dw;
305 for (dw = dvert->dw; i > 0; dw++, i--) {
306 if (UNLIKELY(dw->def_nr >= groups.size())) {
307 continue;
308 }
309 groups[dw->def_nr] = true;
310 found = true;
311 }
312 return found;
313}
314
315static int weight_sample_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
316{
319 BLI_assert(vc.v3d && vc.rv3d); /* Ensured by poll. */
320
321 Mesh *mesh = BKE_mesh_from_object(vc.obact);
322 const MDeformVert *dverts = mesh->deform_verts().data();
323 if (BLI_listbase_is_empty(&mesh->vertex_group_names) || (dverts == nullptr)) {
324 BKE_report(op->reports, RPT_WARNING, "No vertex group data");
325 return OPERATOR_CANCELLED;
326 }
327
328 const bool use_vert_sel = (mesh->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
329 blender::Array<bool> groups(BLI_listbase_count(&mesh->vertex_group_names), false);
330
331 bool found = false;
332
335
336 if (use_vert_sel) {
337 /* Extract from the vertex. */
338 uint index;
339 if (ED_mesh_pick_vert(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index))
340 {
341 const MDeformVert *dvert = &dverts[index];
342 found |= weight_paint_sample_mark_groups(dvert, groups);
343 }
344 }
345 else {
346 /* Extract from the face. */
347 const blender::OffsetIndices faces = mesh->faces();
348 const blender::Span<int> corner_verts = mesh->corner_verts();
349 uint index;
350 if (ED_mesh_pick_face(C, vc.obact, event->mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
351 for (const int vert : corner_verts.slice(faces[index])) {
352 found |= weight_paint_sample_mark_groups(&dverts[vert], groups);
353 }
354 }
355 }
356
357 if (found == false) {
358 BKE_report(op->reports, RPT_WARNING, "No vertex groups found");
359 return OPERATOR_CANCELLED;
360 }
361
363 C, WM_operatortype_name(op->type, op->ptr).c_str(), ICON_NONE);
364 uiLayout *layout = UI_popup_menu_layout(pup);
365 wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_vertex_group_set_active", false);
367 uiLayoutSetOperatorContext(layout, opcontext);
368 int i = 0;
369 LISTBASE_FOREACH_INDEX (bDeformGroup *, dg, &mesh->vertex_group_names, i) {
370 if (groups[i] == false) {
371 continue;
372 }
373 PointerRNA op_ptr;
375 layout, ot, dg->name, ICON_NONE, nullptr, WM_OP_EXEC_DEFAULT, UI_ITEM_NONE, &op_ptr);
376 RNA_property_enum_set(&op_ptr, ot->prop, i);
377 }
378 UI_popup_menu_end(C, pup);
379
380 return OPERATOR_INTERFACE;
381}
382
384{
385 /* identifiers */
386 ot->name = "Weight Paint Sample Group";
387 ot->idname = "PAINT_OT_weight_sample_group";
388 ot->description = "Select one of the vertex groups available under current mouse position";
389
390 /* api callbacks */
393
394 /* flags */
396}
397
400/* -------------------------------------------------------------------- */
404/* fills in the selected faces with the current weight and vertex group */
405static bool weight_paint_set(Object *ob, float paintweight)
406{
407 using namespace blender;
408 Mesh *mesh = static_cast<Mesh *>(ob->data);
409 MDeformWeight *dw, *dw_prev;
410 int vgroup_active, vgroup_mirror = -1;
411 const bool topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
412
413 /* mutually exclusive, could be made into a */
414 const short paint_selmode = ME_EDIT_PAINT_SEL_MODE(mesh);
415
416 const blender::OffsetIndices faces = mesh->faces();
417 const blender::Span<int> corner_verts = mesh->corner_verts();
418 MDeformVert *dvert = mesh->deform_verts_for_write().data();
419
420 if (mesh->faces_num == 0 || dvert == nullptr) {
421 return false;
422 }
423
424 vgroup_active = BKE_object_defgroup_active_index_get(ob) - 1;
425
426 /* if mirror painting, find the other group */
428 vgroup_mirror = ED_wpaint_mirror_vgroup_ensure(ob, vgroup_active);
429 }
430
431 WPaintPrev wpp;
432 wpaint_prev_create(&wpp, dvert, mesh->verts_num);
433
434 const bke::AttributeAccessor attributes = mesh->attributes();
435 const VArraySpan select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
436 const VArraySpan select_poly = *attributes.lookup<bool>(".select_poly", bke::AttrDomain::Face);
437
438 for (const int i : faces.index_range()) {
439 if ((paint_selmode == SCE_SELECT_FACE) && !(!select_poly.is_empty() && select_poly[i])) {
440 continue;
441 }
442
443 for (const int vert : corner_verts.slice(faces[i])) {
444 if (!dvert[vert].flag) {
445 if ((paint_selmode == SCE_SELECT_VERTEX) &&
446 !(!select_vert.is_empty() && select_vert[vert]))
447 {
448 continue;
449 }
450
451 dw = BKE_defvert_ensure_index(&dvert[vert], vgroup_active);
452 if (dw) {
453 dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + vert, vgroup_active);
454 dw_prev->weight = dw->weight; /* set the undo weight */
455 dw->weight = paintweight;
456
457 if (mesh->symmetry & ME_SYMMETRY_X) {
458 /* x mirror painting */
459 int j = mesh_get_x_mirror_vert(ob, nullptr, vert, topology);
460 if (j >= 0) {
461 /* copy, not paint again */
462 if (vgroup_mirror != -1) {
463 dw = BKE_defvert_ensure_index(dvert + j, vgroup_mirror);
464 dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_mirror);
465 }
466 else {
467 dw = BKE_defvert_ensure_index(dvert + j, vgroup_active);
468 dw_prev = BKE_defvert_ensure_index(wpp.wpaint_prev + j, vgroup_active);
469 }
470 dw_prev->weight = dw->weight; /* set the undo weight */
471 dw->weight = paintweight;
472 }
473 }
474 }
475 dvert[vert].flag = 1;
476 }
477 }
478 }
479
480 {
481 MDeformVert *dv = dvert;
482 for (int index = mesh->verts_num; index != 0; index--, dv++) {
483 dv->flag = 0;
484 }
485 }
486
488
489 DEG_id_tag_update(&mesh->id, 0);
490
491 return true;
492}
493
495{
496 Scene *scene = CTX_data_scene(C);
497 Object *obact = CTX_data_active_object(C);
499 Brush *brush = BKE_paint_brush(&ts->wpaint->paint);
500 float vgroup_weight = BKE_brush_weight_get(scene, brush);
501
502 if (ED_wpaint_ensure_data(C, op->reports, WPAINT_ENSURE_MIRROR, nullptr) == false) {
503 return OPERATOR_CANCELLED;
504 }
505
506 if (weight_paint_set(obact, vgroup_weight)) {
507 ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
508 return OPERATOR_FINISHED;
509 }
510 return OPERATOR_CANCELLED;
511}
512
514{
515 /* identifiers */
516 ot->name = "Set Weight";
517 ot->idname = "PAINT_OT_weight_set";
518 ot->description = "Fill the active vertex group with the current paint weight";
519
520 /* api callbacks */
523
524 /* flags */
526}
527
530/* -------------------------------------------------------------------- */
534/* *** VGroups Gradient *** */
546
551
560 const float *sco_start; /* [2] */
561 const float *sco_end; /* [2] */
562 float sco_line_div; /* store (1.0f / len_v2v2(sco_start, sco_end)) */
566 /* only for init */
568
569 /* options */
572 short type;
574};
575
576static void gradientVert_update(WPGradient_userData *grad_data, int index)
577{
578 WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
579
580 /* Optionally restrict to assigned vertices only. */
581 if (grad_data->use_vgroup_restrict &&
583 {
584 /* In this case the vertex will never have been touched. */
586 return;
587 }
588
589 float alpha;
590 if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
591 alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
592 }
593 else {
595 alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
596 }
597 /* no need to clamp 'alpha' yet */
598
599 /* adjust weight */
600 alpha = BKE_brush_curve_strength_clamped(grad_data->brush, alpha, 1.0f);
601
602 if (alpha != 0.0f) {
603 MDeformVert *dv = &grad_data->dvert[index];
604 MDeformWeight *dw = BKE_defvert_ensure_index(dv, grad_data->def_nr);
605 // dw->weight = alpha; // testing
606 int tool = grad_data->brush->blend;
607 float testw;
608
609 /* init if we just added */
610 testw = ED_wpaint_blend_tool(
611 tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
612 CLAMP(testw, 0.0f, 1.0f);
613 dw->weight = testw;
615 }
616 else {
617 MDeformVert *dv = &grad_data->dvert[index];
619 /* normally we nullptr check, but in this case we know it exists */
620 MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
621 dw->weight = vs->weight_orig;
622 }
623 else {
624 /* wasn't originally existing, remove */
625 MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
626 if (dw) {
628 }
629 }
630 vs->flag &= ~WPGradient_vertStore::VGRAD_STORE_IS_MODIFIED;
631 }
632}
633
634static void gradientVertUpdate__mapFunc(void *user_data,
635 int index,
636 const float /*co*/[3],
637 const float /*no*/[3])
638{
639 WPGradient_userData *grad_data = static_cast<WPGradient_userData *>(user_data);
640 WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
641
642 if (vs->sco[0] == FLT_MAX) {
643 return;
644 }
645
646 gradientVert_update(grad_data, index);
647}
648
649static void gradientVertInit__mapFunc(void *user_data,
650 int index,
651 const float co[3],
652 const float /*no*/[3])
653{
654 WPGradient_userData *grad_data = static_cast<WPGradient_userData *>(user_data);
655 WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
656
657 if (grad_data->hide_vert[index] ||
658 (grad_data->use_select &&
659 (!grad_data->select_vert.is_empty() && !grad_data->select_vert[index])))
660 {
661 copy_v2_fl(vs->sco, FLT_MAX);
662 return;
663 }
664
665 /* run first pass only,
666 * the screen coords of the verts need to be cached because
667 * updating the mesh may move them about (entering feedback loop) */
668 if (BLI_BITMAP_TEST(grad_data->vert_visit, index)) {
669 /* Do not copy FLT_MAX here, for generative modifiers we are getting here
670 * multiple times with the same orig index. */
671 return;
672 }
673
677 {
678 copy_v2_fl(vs->sco, FLT_MAX);
679 return;
680 }
681
682 MDeformVert *dv = &grad_data->dvert[index];
683 const MDeformWeight *dw = BKE_defvert_find_index(dv, grad_data->def_nr);
684 if (dw) {
685 vs->weight_orig = dw->weight;
687 }
688 else {
689 vs->weight_orig = 0.0f;
691 }
692 BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
693 gradientVert_update(grad_data, index);
694}
695
697{
698 wmGesture *gesture = static_cast<wmGesture *>(op->customdata);
699 WPGradient_vertStoreBase *vert_cache = static_cast<WPGradient_vertStoreBase *>(
700 gesture->user_data.data);
702 int ret;
703
705 BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
707 }
708 else {
709 ret = WM_gesture_straightline_modal(C, op, event);
710 }
711
713 if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { /* XXX, hardcoded */
714 /* generally crap! redo! */
716 ret &= ~OPERATOR_RUNNING_MODAL;
718 }
719 }
720
721 if (ret & OPERATOR_CANCELLED) {
722 if (vert_cache != nullptr) {
723 Mesh *mesh = static_cast<Mesh *>(ob->data);
724 if (vert_cache->wpp.wpaint_prev) {
725 MDeformVert *dvert = mesh->deform_verts_for_write().data();
726 BKE_defvert_array_free_elems(dvert, mesh->verts_num);
727 BKE_defvert_array_copy(dvert, vert_cache->wpp.wpaint_prev, mesh->verts_num);
728 wpaint_prev_destroy(&vert_cache->wpp);
729 }
730 MEM_freeN(vert_cache);
731 }
732
735 }
736 else if (ret & OPERATOR_FINISHED) {
737 wpaint_prev_destroy(&vert_cache->wpp);
738 MEM_freeN(vert_cache);
739 }
740
741 return ret;
742}
743
745{
746 using namespace blender;
747 wmGesture *gesture = static_cast<wmGesture *>(op->customdata);
748 WPGradient_vertStoreBase *vert_cache;
749 ARegion *region = CTX_wm_region(C);
750 Scene *scene = CTX_data_scene(C);
752 Mesh *mesh = static_cast<Mesh *>(ob->data);
753 MDeformVert *dverts = mesh->deform_verts_for_write().data();
754 int x_start = RNA_int_get(op->ptr, "xstart");
755 int y_start = RNA_int_get(op->ptr, "ystart");
756 int x_end = RNA_int_get(op->ptr, "xend");
757 int y_end = RNA_int_get(op->ptr, "yend");
758 const float sco_start[2] = {float(x_start), float(y_start)};
759 const float sco_end[2] = {float(x_end), float(y_end)};
760 const bool is_interactive = (gesture != nullptr);
761
763
764 WPGradient_userData data = {nullptr};
765
766 if (is_interactive) {
767 if (gesture->user_data.data == nullptr) {
769 (sizeof(WPGradient_vertStore) * mesh->verts_num),
770 __func__);
771 gesture->user_data.use_free = false;
772 data.is_init = true;
773
775 &((WPGradient_vertStoreBase *)gesture->user_data.data)->wpp, dverts, mesh->verts_num);
776
777 /* On initialization only, convert face -> vert sel. */
778 if (mesh->editflag & ME_EDIT_PAINT_FACE_SEL) {
779 bke::mesh_select_face_flush(*mesh);
780 }
781 }
782
783 vert_cache = static_cast<WPGradient_vertStoreBase *>(gesture->user_data.data);
784 }
785 else {
786 if (ED_wpaint_ensure_data(C, op->reports, eWPaintFlag(0), nullptr) == false) {
787 return OPERATOR_CANCELLED;
788 }
789
790 data.is_init = true;
791 vert_cache = static_cast<WPGradient_vertStoreBase *>(MEM_mallocN(
792 sizeof(WPGradient_vertStoreBase) + (sizeof(WPGradient_vertStore) * mesh->verts_num),
793 __func__));
794 }
795
796 const blender::bke::AttributeAccessor attributes = mesh->attributes();
797
798 data.region = region;
799 data.scene = scene;
800 data.mesh = mesh;
801 data.dvert = dverts;
802 data.select_vert = *attributes.lookup<bool>(".select_vert", bke::AttrDomain::Point);
803 data.hide_vert = *attributes.lookup_or_default<bool>(
804 ".hide_vert", bke::AttrDomain::Point, false);
805 data.sco_start = sco_start;
806 data.sco_end = sco_end;
807 data.sco_line_div = 1.0f / len_v2v2(sco_start, sco_end);
808 data.def_nr = BKE_object_defgroup_active_index_get(ob) - 1;
809 data.use_select = (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
810 data.vert_cache = vert_cache;
811 data.vert_visit = nullptr;
812 data.type = RNA_enum_get(op->ptr, "type");
813
814 {
816 VPaint *wp = ts->wpaint;
817 Brush *brush = BKE_paint_brush(&wp->paint);
818
820
821 data.brush = brush;
822 data.weightpaint = BKE_brush_weight_get(scene, brush);
823 data.use_vgroup_restrict = (ts->wpaint->flag & VP_FLAG_VGROUP_RESTRICT) != 0;
824 }
825
826 ED_view3d_init_mats_rv3d(ob, static_cast<RegionView3D *>(region->regiondata));
827
828 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
829 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
830 if (data.is_init) {
831 data.vert_visit = BLI_BITMAP_NEW(mesh->verts_num, __func__);
832
834
835 MEM_freeN(data.vert_visit);
836 data.vert_visit = nullptr;
837 }
838 else {
840 }
841
844
845 if (is_interactive == false) {
846 MEM_freeN(vert_cache);
847 }
848
849 if (scene->toolsettings->auto_normalize) {
850 const int vgroup_num = BLI_listbase_count(&mesh->vertex_group_names);
851 bool *lock_flags = BKE_object_defgroup_lock_flags_get(ob, vgroup_num);
852 bool *vgroup_validmap = BKE_object_defgroup_validmap_get(ob, vgroup_num);
853 if (vgroup_validmap != nullptr) {
854 MDeformVert *dvert = dverts;
855 for (int i = 0; i < mesh->verts_num; i++) {
856 if ((data.vert_cache->elem[i].flag & WPGradient_vertStore::VGRAD_STORE_IS_MODIFIED) != 0) {
857 if (lock_flags != nullptr) {
859 &dvert[i], vgroup_validmap, vgroup_num, lock_flags, vgroup_num);
860 }
861 else {
862 BKE_defvert_normalize_lock_single(&dvert[i], vgroup_validmap, vgroup_num, data.def_nr);
863 }
864 }
865 }
866 MEM_freeN(vgroup_validmap);
867 }
868 }
869
870 return OPERATOR_FINISHED;
871}
872
874{
875 int ret;
876
877 if (ED_wpaint_ensure_data(C, op->reports, eWPaintFlag(0), nullptr) == false) {
878 return OPERATOR_CANCELLED;
879 }
880
881 ret = WM_gesture_straightline_invoke(C, op, event);
883 ARegion *region = CTX_wm_region(C);
884 if (region->regiontype == RGN_TYPE_WINDOW) {
885 /* TODO: hard-coded, extend `WM_gesture_straightline_*`. */
886 if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
887 wmGesture *gesture = static_cast<wmGesture *>(op->customdata);
888 gesture->is_active = true;
889 }
890 }
891 }
892 return ret;
893}
894
896{
897 /* defined in DNA_space_types.h */
898 static const EnumPropertyItem gradient_types[] = {
899 {WPAINT_GRADIENT_TYPE_LINEAR, "LINEAR", 0, "Linear", ""},
900 {WPAINT_GRADIENT_TYPE_RADIAL, "RADIAL", 0, "Radial", ""},
901 {0, nullptr, 0, nullptr, nullptr},
902 };
903
904 PropertyRNA *prop;
905
906 /* identifiers */
907 ot->name = "Weight Gradient";
908 ot->idname = "PAINT_OT_weight_gradient";
909 ot->description = "Draw a line to apply a weight gradient to selected vertices";
910
911 /* api callbacks */
917
918 /* flags */
920
921 prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
923
925}
926
void BKE_brush_weight_set(const Scene *scene, Brush *brush, float value)
Definition brush.cc:1167
float BKE_brush_weight_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1160
float BKE_brush_curve_strength_clamped(const Brush *br, float p, float len)
Definition brush.cc:1444
void BKE_curvemapping_init(CurveMapping *cumap)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
support for deformation groups and hooks.
void BKE_defvert_array_free(MDeformVert *dvert, int totvert)
Definition deform.cc:1066
void BKE_defvert_array_copy(MDeformVert *dst, const MDeformVert *src, int totvert)
Definition deform.cc:1029
void BKE_defvert_normalize_lock_single(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num, uint def_nr_lock)
Definition deform.cc:301
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:601
float BKE_defvert_lock_relative_weight(float weight, const MDeformVert *dv, int defbase_num, const bool *defbase_locked, const bool *defbase_unlocked)
Definition deform.cc:1008
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
void BKE_defvert_array_free_elems(MDeformVert *dvert, int totvert)
Definition deform.cc:1048
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:795
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
void BKE_defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
Definition deform.cc:871
void BKE_defvert_normalize_lock_map(MDeformVert *dvert, const bool *vgroup_subset, int vgroup_num, const bool *lock_flags, int defbase_num)
Definition deform.cc:355
float BKE_defvert_multipaint_collective_weight(const MDeformVert *dv, int defbase_num, const bool *defbase_sel, int defbase_sel_num, bool is_normalized)
Definition deform.cc:963
Mesh * BKE_mesh_from_object(Object *ob)
@ MESH_FOREACH_NOP
void BKE_mesh_foreach_mapped_vert(const Mesh *mesh, void(*func)(void *user_data, int index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
Object * BKE_modifiers_is_deformed_by_armature(Object *ob)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
Functions for dealing with objects and deform verts, used by painting and tools.
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags, const bool *validmap, int index)
void BKE_object_defgroup_split_locked_validmap(int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
bool * BKE_object_defgroup_validmap_get(struct Object *ob, int defbase_tot)
bool * BKE_object_defgroup_lock_flags_get(struct Object *ob, int defbase_tot)
void BKE_object_defgroup_mirror_selection(struct Object *ob, int defbase_tot, const bool *selection, bool *dg_flags_sel, int *r_dg_flags_sel_tot)
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot, const bool *lock_flags, const bool *selected, int sel_tot)
bool BKE_object_defgroup_active_is_locked(const struct Object *ob)
bool * BKE_object_defgroup_selected_get(struct Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2])
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_fl(float r[2], float f)
unsigned int uint
#define CLAMP(a, b, c)
#define ENUM_OPERATORS(_type, _max)
#define UNLIKELY(x)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ME_SYMMETRY_X
@ ME_EDIT_PAINT_VERT_SEL
@ ME_EDIT_PAINT_FACE_SEL
@ ME_EDIT_MIRROR_TOPO
#define ME_USING_MIRROR_X_VERTEX_GROUPS(_me)
#define ME_EDIT_PAINT_SEL_MODE(_me)
@ OB_MODE_WEIGHT_PAINT
Object is a sort of wrapper for general info.
@ VP_FLAG_VGROUP_RESTRICT
@ SCE_SELECT_FACE
@ SCE_SELECT_VERTEX
@ RGN_TYPE_WINDOW
@ OPERATOR_RUNNING_MODAL
#define ARM_GROUPS_ENVELOPE
#define ARM_GROUPS_AUTO
#define ED_MESH_PICK_DEFAULT_VERT_DIST
Definition ED_mesh.hh:582
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, bool use_topology)
Definition meshtools.cc:901
bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
#define ED_MESH_PICK_DEFAULT_FACE_DIST
Definition ED_mesh.hh:583
bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
@ V3D_PROJ_TEST_CLIP_NEAR
Definition ED_view3d.hh:269
@ V3D_PROJ_TEST_CLIP_BB
Definition ED_view3d.hh:267
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:243
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
void view3d_operator_needs_opengl(const bContext *C)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_ITEM_NONE
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DRAW
Definition WM_types.hh:428
#define NC_BRUSH
Definition WM_types.hh:352
#define ND_DATA
Definition WM_types.hh:475
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
#define NA_EDITED
Definition WM_types.hh:550
wmOperatorCallContext
Definition WM_types.hh:216
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
#define NC_OBJECT
Definition WM_types.hh:346
void ED_object_vgroup_calc_from_armature(ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, Object *par, const int mode, const bool mirror)
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr bool is_empty() const
Definition BLI_span.hh:261
const Depsgraph * depsgraph
draw_view in_light_buf[] float
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha)
int ED_wpaint_mirror_vgroup_ensure(Object *ob, int vgroup_active)
@ WPAINT_GRADIENT_TYPE_RADIAL
@ WPAINT_GRADIENT_TYPE_LINEAR
bool weight_paint_mode_poll(bContext *C)
bool weight_paint_mode_region_view3d_poll(bContext *C)
eWPaintFlag
@ WPAINT_ENSURE_MIRROR
bool weight_paint_poll_ignore_tool(bContext *C)
bool ED_wpaint_ensure_data(bContext *C, ReportList *reports, enum eWPaintFlag flag, WPaintVGroupIndex *vgroup_index)
static bool weight_paint_sample_mark_groups(const MDeformVert *dvert, blender::MutableSpan< bool > groups)
void PAINT_OT_weight_set(wmOperatorType *ot)
static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
static bool weight_paint_set(Object *ob, float paintweight)
static int weight_from_bones_exec(bContext *C, wmOperator *op)
static int weight_paint_set_exec(bContext *C, wmOperator *op)
static int paint_weight_gradient_modal(bContext *C, wmOperator *op, const wmEvent *event)
void PAINT_OT_weight_sample(wmOperatorType *ot)
static int paint_weight_gradient_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void wpaint_prev_init(WPaintPrev *wpp)
static void gradientVertInit__mapFunc(void *user_data, int index, const float co[3], const float[3])
static int weight_sample_group_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool weight_from_bones_poll(bContext *C)
static void gradientVertUpdate__mapFunc(void *user_data, int index, const float[3], const float[3])
void PAINT_OT_weight_from_bones(wmOperatorType *ot)
void PAINT_OT_weight_gradient(wmOperatorType *ot)
static void wpaint_prev_destroy(WPaintPrev *wpp)
static void wpaint_prev_create(WPaintPrev *wpp, MDeformVert *dverts, int dcount)
void PAINT_OT_weight_sample_group(wmOperatorType *ot)
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return ret
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
int RNA_int_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define FLT_MAX
Definition stdcycles.h:14
float alpha
struct CurveMapping * curve
short blend
struct MDeformWeight * dw
unsigned int def_nr
struct ToolSettings * toolsettings
RegionView3D * rv3d
Definition ED_view3d.hh:76
Scene * scene
Definition ED_view3d.hh:69
View3D * v3d
Definition ED_view3d.hh:74
Object * obact
Definition ED_view3d.hh:71
blender::VArray< bool > hide_vert
WPGradient_vertStoreBase * vert_cache
blender::VArraySpan< bool > select_vert
MDeformVert * wpaint_prev
short val
Definition WM_types.hh:724
int mval[2]
Definition WM_types.hh:728
short type
Definition WM_types.hh:722
wmGenericUserData user_data
Definition WM_types.hh:632
uint is_active
Definition WM_types.hh:605
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ LEFTMOUSE
wmOperatorType * ot
Definition wm_files.cc:4125
int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_straightline_cancel(bContext *C, wmOperator *op)
int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
std::string WM_operatortype_name(wmOperatorType *ot, PointerRNA *properties)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
uint8_t flag
Definition wm_window.cc:138