Blender V4.3
sculpt_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 by Nicholas Bishop. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include "MEM_guardedalloc.h"
11
12#include "BLI_array_utils.hh"
14#include "BLI_ghash.h"
15#include "BLI_math_matrix.hh"
16#include "BLI_math_vector.hh"
17#include "BLI_task.h"
18#include "BLI_utildefines.h"
19
20#include "BLT_translation.hh"
21
22#include "DNA_brush_types.h"
23#include "DNA_listBase.h"
24#include "DNA_node_types.h"
25#include "DNA_object_types.h"
26#include "DNA_scene_types.h"
27
28#include "BKE_attribute.hh"
29#include "BKE_brush.hh"
30#include "BKE_ccg.hh"
31#include "BKE_context.hh"
32#include "BKE_layer.hh"
33#include "BKE_main.hh"
34#include "BKE_mesh.hh"
35#include "BKE_mesh_mirror.hh"
36#include "BKE_multires.hh"
37#include "BKE_object.hh"
38#include "BKE_paint.hh"
39#include "BKE_pbvh_api.hh"
40#include "BKE_report.hh"
41#include "BKE_scene.hh"
42#include "BKE_subdiv_ccg.hh"
43
44#include "DEG_depsgraph.hh"
45
47
48#include "WM_api.hh"
49#include "WM_message.hh"
50#include "WM_toolsystem.hh"
51#include "WM_types.hh"
52
53#include "ED_image.hh"
54#include "ED_object.hh"
55#include "ED_screen.hh"
56#include "ED_sculpt.hh"
57
58#include "mesh_brush_common.hh"
59#include "paint_intern.hh"
60#include "paint_mask.hh"
61#include "sculpt_automask.hh"
62#include "sculpt_color.hh"
63#include "sculpt_dyntopo.hh"
64#include "sculpt_face_set.hh"
65#include "sculpt_flood_fill.hh"
66#include "sculpt_intern.hh"
67#include "sculpt_islands.hh"
68#include "sculpt_undo.hh"
69
70#include "RNA_access.hh"
71#include "RNA_define.hh"
72
73#include "UI_interface.hh"
74#include "UI_resources.hh"
75
76#include "CLG_log.h"
77#include "bmesh.hh"
78
79#include <cmath>
80#include <cstdlib>
81#include <cstring>
82
84
85/* -------------------------------------------------------------------- */
90{
93 SculptSession *ss = ob.sculpt;
94
95 const View3D *v3d = CTX_wm_view3d(C);
96 const Base *base = CTX_data_active_base(C);
97 if (!BKE_base_is_visible(v3d, base)) {
98 return OPERATOR_CANCELLED;
99 }
100
101 if (!ss) {
102 return OPERATOR_CANCELLED;
103 }
104
105 /* Only mesh geometry supports attributes properly. */
106 if (bke::object::pbvh_get(ob)->type() != bke::pbvh::Type::Mesh) {
107 return OPERATOR_CANCELLED;
108 }
109
111
112 Mesh &mesh = *static_cast<Mesh *>(ob.data);
113 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
114 attributes.remove(".sculpt_persistent_co");
115 attributes.remove(".sculpt_persistent_no");
116 attributes.remove(".sculpt_persistent_disp");
117
118 const bke::AttributeReader positions = attributes.lookup<float3>("position");
119 if (positions.sharing_info && positions.varray.is_span()) {
120 attributes.add<float3>(".sculpt_persistent_co",
122 bke::AttributeInitShared(positions.varray.get_internal_span().data(),
123 *positions.sharing_info));
124 }
125 else {
126 attributes.add<float3>(".sculpt_persistent_co",
128 bke::AttributeInitVArray(positions.varray));
129 }
130
131 const Span<float3> vert_normals = bke::pbvh::vert_normals_eval(*depsgraph, ob);
132 attributes.add<float3>(".sculpt_persistent_no",
135
136 return OPERATOR_FINISHED;
137}
138
140{
141 ot->name = "Set Persistent Base";
142 ot->idname = "SCULPT_OT_set_persistent_base";
143 ot->description = "Reset the copy of the mesh that is being sculpted on";
144
147
149}
150
153/* -------------------------------------------------------------------- */
157static int optimize_exec(bContext *C, wmOperator * /*op*/)
158{
160
163
165
166 return OPERATOR_FINISHED;
167}
168
169/* The BVH gets less optimal more quickly with dynamic topology than
170 * regular sculpting. There is no doubt more clever stuff we can do to
171 * optimize it on the fly, but for now this gives the user a nicer way
172 * to recalculate it than toggling modes. */
174{
175 ot->name = "Rebuild BVH";
176 ot->idname = "SCULPT_OT_optimize";
177 ot->description = "Recalculate the sculpt BVH to improve performance";
178
181
183}
184
187/* -------------------------------------------------------------------- */
192{
194 if (!ob) {
195 return false;
196 }
197 if (ob->type != OB_MESH) {
198 return false;
199 }
200 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(*ob);
201 if (SCULPT_mode_poll(C) && ob->sculpt && pbvh) {
202 return pbvh->type() != bke::pbvh::Type::Grids;
203 }
204 return false;
205}
206
208{
209 Main *bmain = CTX_data_main(C);
210 const Scene &scene = *CTX_data_scene(C);
211 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(C);
213 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
214 SculptSession &ss = *ob.sculpt;
215 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(ob);
216 const float dist = RNA_float_get(op->ptr, "merge_tolerance");
217
218 if (!pbvh) {
219 return OPERATOR_CANCELLED;
220 }
221
222 const View3D *v3d = CTX_wm_view3d(C);
223 const Base *base = CTX_data_active_base(C);
224 if (!BKE_base_is_visible(v3d, base)) {
225 return OPERATOR_CANCELLED;
226 }
227
228 switch (pbvh->type()) {
230 /* Dyntopo Symmetrize. */
231
232 /* To simplify undo for symmetrize, all BMesh elements are logged
233 * as deleted, then after symmetrize operation all BMesh elements
234 * are logged as added (as opposed to attempting to store just the
235 * parts that symmetrize modifies). */
236 undo::push_begin(scene, ob, op);
239
240 BM_mesh_toolflags_set(ss.bm, true);
241
242 /* Symmetrize and re-triangulate. */
243 BMO_op_callf(ss.bm,
245 "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
247 dist,
248 true);
250
251 /* Bisect operator flags edges (keep tags clean for edge queue). */
253
254 BM_mesh_toolflags_set(ss.bm, false);
255
256 /* Finish undo. */
257 BM_log_all_added(ss.bm, ss.bm_log);
258 undo::push_end(ob);
259
260 break;
261 }
263 /* Mesh Symmetrize. */
264 undo::geometry_begin(scene, ob, op);
265 Mesh *mesh = static_cast<Mesh *>(ob.data);
266
268
271
272 break;
273 }
275 return OPERATOR_CANCELLED;
276 }
277
281
282 return OPERATOR_FINISHED;
283}
284
286{
287 ot->name = "Symmetrize";
288 ot->idname = "SCULPT_OT_symmetrize";
289 ot->description = "Symmetrize the topology modifications";
290
293
295 "merge_tolerance",
296 0.0005f,
297 0.0f,
298 std::numeric_limits<float>::max(),
299 "Merge Distance",
300 "Distance within which symmetrical vertices are merged",
301 0.0f,
302 1.0f);
303
304 RNA_def_property_ui_range(prop, 0.0, std::numeric_limits<float>::max(), 0.001, 5);
305}
306
309/* -------------------------------------------------------------------- */
313static void init_sculpt_mode_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
314{
315 /* Create persistent sculpt mode data. */
317
318 /* Create sculpt mode session data. */
319 if (ob.sculpt != nullptr) {
321 }
322 ob.sculpt = MEM_new<SculptSession>(__func__);
324
325 /* Trigger evaluation of modifier stack to ensure
326 * multires modifier sets .runtime.ccg in
327 * the evaluated mesh.
328 */
330
332
333 /* This function expects a fully evaluated depsgraph. */
335
336 Mesh &mesh = *static_cast<Mesh *>(ob.data);
337 if (mesh.attributes().contains(".sculpt_face_set")) {
338 /* Here we can detect geometry that was just added to Sculpt Mode as it has the
339 * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
340 /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
341 * initialized, which is used is some operators that modify the mesh topology to perform
342 * certain actions in the new faces. After these operations are finished, all faces should have
343 * a valid face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their
344 * visibility correctly. */
345 /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
346 * objects, like moving the transform pivot position to the new area or masking existing
347 * geometry. */
348 const int new_face_set = face_set::find_next_available_id(ob);
349 face_set::initialize_none_to_id(static_cast<Mesh *>(ob.data), new_face_set);
350 }
351}
352
353void ensure_valid_pivot(const Object &ob, Scene &scene)
354{
355 UnifiedPaintSettings &ups = scene.toolsettings->unified_paint_settings;
356 const bke::pbvh::Tree *pbvh = bke::object::pbvh_get(ob);
357
358 /* Account for the case where no objects are evaluated. */
359 if (!pbvh) {
360 return;
361 }
362
363 /* No valid pivot? Use bounding box center. */
364 if (ups.average_stroke_counter == 0 || !ups.last_stroke_valid) {
365 const Bounds<float3> bounds = bke::pbvh::bounds_get(*pbvh);
366 const float3 center = math::midpoint(bounds.min, bounds.max);
367 const float3 location = math::transform_point(ob.object_to_world(), center);
368
369 copy_v3_v3(ups.average_stroke_accum, location);
371
372 /* Update last stroke position. */
373 ups.last_stroke_valid = true;
374 }
375}
376
378 Depsgraph &depsgraph,
379 Scene &scene,
380 Object &ob,
381 const bool force_dyntopo,
382 ReportList *reports)
383{
384 const int mode_flag = OB_MODE_SCULPT;
385 Mesh *mesh = BKE_mesh_from_object(&ob);
386
387 /* Re-triangulating the mesh for position changes in sculpt mode isn't worth the performance
388 * impact, so delay triangulation updates until the user exits sculpt mode. */
389 mesh->runtime->corner_tris_cache.freeze();
390
391 /* Enter sculpt mode. */
392 ob.mode |= mode_flag;
393
394 init_sculpt_mode_session(bmain, depsgraph, scene, ob);
395
396 if (!(fabsf(ob.scale[0] - ob.scale[1]) < 1e-4f && fabsf(ob.scale[1] - ob.scale[2]) < 1e-4f)) {
398 reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
399 }
400 else if (is_negative_m4(ob.object_to_world().ptr())) {
401 BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
402 }
403
406
408
409 /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
410 * As long as no data was added that is not supported. */
411 if (mesh->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
413
414 const char *message_unsupported = nullptr;
415 if (mesh->corners_num != mesh->faces_num * 3) {
416 message_unsupported = RPT_("non-triangle face");
417 }
418 else if (mmd != nullptr) {
419 message_unsupported = RPT_("multi-res modifier");
420 }
421 else {
423 if (flag == 0) {
424 /* pass */
425 }
426 else if (flag & dyntopo::VDATA) {
427 message_unsupported = RPT_("vertex data");
428 }
429 else if (flag & dyntopo::EDATA) {
430 message_unsupported = RPT_("edge data");
431 }
432 else if (flag & dyntopo::LDATA) {
433 message_unsupported = RPT_("face data");
434 }
435 else if (flag & dyntopo::MODIFIER) {
436 message_unsupported = RPT_("constructive modifier");
437 }
438 else {
440 }
441 }
442
443 if ((message_unsupported == nullptr) || force_dyntopo) {
444 /* Needed because we may be entering this mode before the undo system loads. */
445 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain.wm.first);
446 const bool has_undo = wm->undo_stack != nullptr;
447 /* Undo push is needed to prevent memory leak. */
448 if (has_undo) {
449 undo::push_begin_ex(scene, ob, "Dynamic topology enable");
450 }
451 dyntopo::enable_ex(bmain, depsgraph, ob);
452 if (has_undo) {
454 undo::push_end(ob);
455 }
456 }
457 else {
459 reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
460 mesh->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
461 }
462 }
463
464 ensure_valid_pivot(ob, scene);
465
466 /* Flush object mode. */
468}
469
471{
472 Main &bmain = *CTX_data_main(C);
473 Scene &scene = *CTX_data_scene(C);
474 ViewLayer &view_layer = *CTX_data_view_layer(C);
475 BKE_view_layer_synced_ensure(&scene, &view_layer);
476 Object &ob = *BKE_view_layer_active_object_get(&view_layer);
477 object_sculpt_mode_enter(bmain, depsgraph, scene, ob, false, reports);
478}
479
480void object_sculpt_mode_exit(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
481{
482 const int mode_flag = OB_MODE_SCULPT;
483 Mesh *mesh = BKE_mesh_from_object(&ob);
484
485 mesh->runtime->corner_tris_cache.unfreeze();
486
488
489 /* Not needed for now. */
490#if 0
492 const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
493#endif
494
495 /* Always for now, so leaving sculpt mode always ensures scene is in
496 * a consistent state. */
497 if (true || /* flush_recalc || */ (ob.sculpt && ob.sculpt->bm)) {
499 }
500
501 if (mesh->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
502 /* Dynamic topology must be disabled before exiting sculpt
503 * mode to ensure the undo stack stays in a consistent
504 * state. */
505 dyntopo::disable_with_undo(bmain, depsgraph, scene, ob);
506
507 /* Store so we know to re-enable when entering sculpt mode. */
508 mesh->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
509 }
510
511 /* Leave sculpt mode. */
512 ob.mode &= ~mode_flag;
513
515
517
518 /* Never leave derived meshes behind. */
520
521 /* Flush object mode. */
523}
524
526{
527 Main &bmain = *CTX_data_main(C);
528 Scene &scene = *CTX_data_scene(C);
529 ViewLayer &view_layer = *CTX_data_view_layer(C);
530 BKE_view_layer_synced_ensure(&scene, &view_layer);
531 Object &ob = *BKE_view_layer_active_object_get(&view_layer);
532 object_sculpt_mode_exit(bmain, depsgraph, scene, ob);
533}
534
536{
537 wmMsgBus *mbus = CTX_wm_message_bus(C);
538 Main &bmain = *CTX_data_main(C);
540 Scene &scene = *CTX_data_scene(C);
541 ToolSettings &ts = *scene.toolsettings;
542 ViewLayer &view_layer = *CTX_data_view_layer(C);
543 BKE_view_layer_synced_ensure(&scene, &view_layer);
544 Object &ob = *BKE_view_layer_active_object_get(&view_layer);
545 const int mode_flag = OB_MODE_SCULPT;
546 const bool is_mode_set = (ob.mode & mode_flag) != 0;
547
548 if (!is_mode_set) {
549 if (!object::mode_compat_set(C, &ob, eObjectMode(mode_flag), op->reports)) {
550 return OPERATOR_CANCELLED;
551 }
552 }
553
554 if (is_mode_set) {
555 object_sculpt_mode_exit(bmain, *depsgraph, scene, ob);
556 }
557 else {
558 if (depsgraph) {
560 }
561 object_sculpt_mode_enter(bmain, *depsgraph, scene, ob, false, op->reports);
563
564 if (ob.mode & mode_flag) {
565 Mesh *mesh = static_cast<Mesh *>(ob.data);
566 /* Dyntopo adds its own undo step. */
567 if ((mesh->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
568 /* Without this the memfile undo step is used,
569 * while it works it causes lag when undoing the first undo step, see #71564. */
571 if (wm->op_undo_depth <= 1) {
572 undo::push_begin(scene, ob, op);
573 undo::push_end(ob);
574 }
575 }
576 }
577 }
578
580
581 WM_msg_publish_rna_prop(mbus, &ob.id, &ob, Object, mode);
582
584
585 return OPERATOR_FINISHED;
586}
587
589{
590 ot->name = "Sculpt Mode";
591 ot->idname = "SCULPT_OT_sculptmode_toggle";
592 ot->description = "Toggle sculpt mode in 3D view";
593
596
598}
599
602/* -------------------------------------------------------------------- */
606static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
607{
609 Scene &scene = *CTX_data_scene(C);
611 Brush &brush = *BKE_paint_brush(&sd.paint);
612 SculptSession &ss = *ob.sculpt;
613
615 return OPERATOR_CANCELLED;
616 }
617
618 const View3D *v3d = CTX_wm_view3d(C);
619 const Base *base = CTX_data_active_base(C);
620 if (!BKE_base_is_visible(v3d, base)) {
621 return OPERATOR_CANCELLED;
622 }
623
625
626 const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
627 const OffsetIndices<int> faces = mesh.faces();
628 const Span<int> corner_verts = mesh.corner_verts();
629 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
630 const bke::GAttributeReader color_attribute = color::active_color_attribute(mesh);
631
632 float4 active_vertex_color;
633 if (!color_attribute || std::holds_alternative<std::monostate>(ss.active_vert())) {
634 active_vertex_color = float4(1.0f);
635 }
636 else {
637 const GVArraySpan colors = *color_attribute;
638 active_vertex_color = color::color_vert_get(faces,
639 corner_verts,
640 vert_to_face_map,
641 colors,
642 color_attribute.domain,
643 std::get<int>(ss.active_vert()));
644 }
645
646 float color_srgb[3];
647 IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb, active_vertex_color);
648 BKE_brush_color_set(&scene, &sd.paint, &brush, color_srgb);
649
651
652 return OPERATOR_FINISHED;
653}
654
656{
657 ot->name = "Sample Color";
658 ot->idname = "SCULPT_OT_sample_color";
659 ot->description = "Sample the vertex color of the active vertex";
660
663
665}
666
669namespace mask {
670
671/* -------------------------------------------------------------------- */
684#define MASK_BY_COLOR_SLOPE 0.25f
685
686static float color_delta_get(const float3 &color_a,
687 const float3 &color_b,
688 const float threshold,
689 const bool invert)
690{
691 float len = math::distance(color_a, color_b);
692 /* Normalize len to the (0, 1) range. */
694
695 if (len < threshold - MASK_BY_COLOR_SLOPE) {
696 len = 1.0f;
697 }
698 else if (len >= threshold) {
699 len = 0.0f;
700 }
701 else {
702 len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
703 }
704
705 if (invert) {
706 return 1.0f - len;
707 }
708 return len;
709}
710
711static float final_mask_get(const float current_mask,
712 const float new_mask,
713 const bool invert,
714 const bool preserve_mask)
715{
716 if (preserve_mask) {
717 if (invert) {
718 return std::min(current_mask, new_mask);
719 }
720 return std::max(current_mask, new_mask);
721 }
722 return new_mask;
723}
724
725static void mask_by_color_contiguous_mesh(const Depsgraph &depsgraph,
726 Object &object,
727 const int vert,
728 const float threshold,
729 const bool invert,
730 const bool preserve_mask)
731{
732 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
733 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
734 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
735 const bke::AttributeAccessor attributes = mesh.attributes();
736 const VArraySpan colors = *attributes.lookup_or_default<ColorGeometry4f>(
737 mesh.active_color_attribute, bke::AttrDomain::Point, {});
738 const float4 active_color = float4(colors[vert]);
739
740 Array<float> new_mask(mesh.verts_num, invert ? 1.0f : 0.0f);
741
742 flood_fill::FillDataMesh flood(mesh.verts_num);
743 flood.add_initial(vert);
744
745 flood.execute(object, vert_to_face_map, [&](int /*from_v*/, int to_v) {
746 const float4 current_color = float4(colors[to_v]);
747
748 float new_vertex_mask = color_delta_get(
749 current_color.xyz(), active_color.xyz(), threshold, invert);
750 new_mask[to_v] = new_vertex_mask;
751
752 float len = math::distance(current_color.xyz(), active_color.xyz());
754 return len <= threshold;
755 });
756
757 IndexMaskMemory memory;
758 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
759
761 depsgraph, object, node_mask, [&](MutableSpan<float> node_masks, const Span<int> verts) {
762 for (const int i : verts.index_range()) {
763 node_masks[i] = final_mask_get(node_masks[i], new_mask[verts[i]], invert, preserve_mask);
764 }
765 });
766}
767
768static void mask_by_color_full_mesh(const Depsgraph &depsgraph,
769 Object &object,
770 const int vert,
771 const float threshold,
772 const bool invert,
773 const bool preserve_mask)
774{
775 const bke::pbvh::Tree &pbvh = *bke::object::pbvh_get(object);
776 const Mesh &mesh = *static_cast<const Mesh *>(object.data);
777 const bke::AttributeAccessor attributes = mesh.attributes();
778 const VArraySpan colors = *attributes.lookup_or_default<ColorGeometry4f>(
779 mesh.active_color_attribute, bke::AttrDomain::Point, {});
780 const float4 active_color = float4(colors[vert]);
781
782 IndexMaskMemory memory;
783 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
784
786 depsgraph, object, node_mask, [&](MutableSpan<float> node_masks, const Span<int> verts) {
787 for (const int i : verts.index_range()) {
788 const float4 current_color = float4(colors[verts[i]]);
789 const float current_mask = node_masks[i];
790 const float new_mask = color_delta_get(
791 active_color.xyz(), current_color.xyz(), threshold, invert);
792 node_masks[i] = final_mask_get(current_mask, new_mask, invert, preserve_mask);
793 }
794 });
795}
796
797static int mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
798{
799 const Scene &scene = *CTX_data_scene(C);
802 SculptSession &ss = *ob.sculpt;
803 View3D *v3d = CTX_wm_view3d(C);
804
805 {
806 if (v3d && v3d->shading.type == OB_SOLID) {
808 }
809 }
810
811 const Base *base = CTX_data_active_base(C);
812 if (!BKE_base_is_visible(v3d, base)) {
813 return OPERATOR_CANCELLED;
814 }
815
816 /* Color data is not available in multi-resolution or dynamic topology. */
818 return OPERATOR_CANCELLED;
819 }
820
822
823 /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
824 * so it needs to be updated here. */
826 const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])};
827 SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
828
829 undo::push_begin(scene, ob, op);
831
832 const float threshold = RNA_float_get(op->ptr, "threshold");
833 const bool invert = RNA_boolean_get(op->ptr, "invert");
834 const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
835
836 const int active_vert = std::get<int>(ss.active_vert());
837 if (RNA_boolean_get(op->ptr, "contiguous")) {
838 mask_by_color_contiguous_mesh(*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
839 }
840 else {
841 mask_by_color_full_mesh(*depsgraph, ob, active_vert, threshold, invert, preserve_mask);
842 }
843
844 undo::push_end(ob);
845
848
849 return OPERATOR_FINISHED;
850}
851
853{
854 ot->name = "Mask by Color";
855 ot->idname = "SCULPT_OT_mask_by_color";
856 ot->description = "Creates a mask based on the active color attribute";
857
860
862
864 ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
865
866 ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
868 ot->srna,
869 "preserve_previous_mask",
870 false,
871 "Preserve Previous Mask",
872 "Preserve the previous mask and add or subtract the new one generated by the colors");
873
875 "threshold",
876 0.35f,
877 0.0f,
878 1.0f,
879 "Threshold",
880 "How much changes in color affect the mask generation",
881 0.0f,
882 1.0f);
883}
884
887/* -------------------------------------------------------------------- */
891enum class ApplyMaskMode : int8_t {
892 Mix,
893 Multiply,
894 Divide,
895 Add,
896 Subtract,
897};
898
900 {int(ApplyMaskMode::Mix), "MIX", ICON_NONE, "Mix", ""},
901 {int(ApplyMaskMode::Multiply), "MULTIPLY", ICON_NONE, "Multiply", ""},
902 {int(ApplyMaskMode::Divide), "DIVIDE", ICON_NONE, "Divide", ""},
903 {int(ApplyMaskMode::Add), "ADD", ICON_NONE, "Add", ""},
904 {int(ApplyMaskMode::Subtract), "SUBTRACT", ICON_NONE, "Subtract", ""},
905 {0, nullptr, 0, nullptr, nullptr},
906};
907
909
912 "OPERATOR",
913 ICON_NONE,
914 "Operator",
915 "Use settings from operator properties"},
916 {int(MaskSettingsSource::Brush), "BRUSH", ICON_NONE, "Brush", "Use settings from brush"},
917 {int(MaskSettingsSource::Scene), "SCENE", ICON_NONE, "Scene", "Use settings from scene"},
918 {0, nullptr, 0, nullptr, nullptr}};
919
925
926static void calc_new_masks(const ApplyMaskMode mode,
927 const Span<float> node_mask,
928 const MutableSpan<float> new_mask)
929{
930 switch (mode) {
932 break;
934 for (const int i : node_mask.index_range()) {
935 new_mask[i] = node_mask[i] * new_mask[i];
936 }
937 break;
939 for (const int i : node_mask.index_range()) {
940 new_mask[i] = new_mask[i] > 0.00001f ? node_mask[i] / new_mask[i] : 0.0f;
941 }
942 break;
944 for (const int i : node_mask.index_range()) {
945 new_mask[i] = node_mask[i] + new_mask[i];
946 }
947 break;
949 for (const int i : node_mask.index_range()) {
950 new_mask[i] = node_mask[i] - new_mask[i];
951 }
952 break;
953 }
954 mask::clamp_mask(new_mask);
955}
956
957static void apply_mask_mesh(const Depsgraph &depsgraph,
958 const Object &object,
959 const Span<bool> hide_vert,
960 const auto_mask::Cache &automasking,
961 const ApplyMaskMode mode,
962 const float factor,
963 const bool invert_automask,
964 const bke::pbvh::MeshNode &node,
965 LocalData &tls,
966 const MutableSpan<float> mask)
967{
968 const Span<int> verts = node.verts();
969
970 tls.factors.resize(verts.size());
971 const MutableSpan<float> factors = tls.factors;
972 fill_factor_from_hide(hide_vert, verts, factors);
973 scale_factors(factors, factor);
974
975 tls.new_mask.resize(verts.size());
976 const MutableSpan<float> new_mask = tls.new_mask;
977 new_mask.fill(1.0f);
978 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, new_mask);
979
980 if (invert_automask) {
981 mask::invert_mask(new_mask);
982 }
983
984 tls.mask.resize(verts.size());
985 const MutableSpan<float> node_mask = tls.mask;
986 gather_data_mesh(mask.as_span(), verts, node_mask);
987
988 calc_new_masks(mode, node_mask, new_mask);
989 mix_new_masks(new_mask, factors, node_mask);
990
991 scatter_data_mesh(node_mask.as_span(), verts, mask);
992}
993
994static void apply_mask_grids(const Depsgraph &depsgraph,
995 Object &object,
996 const auto_mask::Cache &automasking,
997 const ApplyMaskMode mode,
998 const float factor,
999 const bool invert_automask,
1000 const bke::pbvh::GridsNode &node,
1001 LocalData &tls)
1002{
1003 SculptSession &ss = *object.sculpt;
1004 SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
1005 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1006
1007 const Span<int> grids = node.grids();
1008 const int grid_verts_num = grids.size() * key.grid_area;
1009
1010 tls.factors.resize(grid_verts_num);
1011 const MutableSpan<float> factors = tls.factors;
1012 fill_factor_from_hide(subdiv_ccg, grids, factors);
1013 scale_factors(factors, factor);
1014
1015 tls.new_mask.resize(grid_verts_num);
1016 const MutableSpan<float> new_mask = tls.new_mask;
1017 new_mask.fill(1.0f);
1018 auto_mask::calc_grids_factors(depsgraph, object, automasking, node, grids, new_mask);
1019
1020 if (invert_automask) {
1021 mask::invert_mask(new_mask);
1022 }
1023
1024 tls.mask.resize(grid_verts_num);
1025 const MutableSpan<float> node_mask = tls.mask;
1026 gather_mask_grids(subdiv_ccg, grids, node_mask);
1027
1028 calc_new_masks(mode, node_mask, new_mask);
1029 mix_new_masks(new_mask, factors, node_mask);
1030
1031 scatter_mask_grids(node_mask.as_span(), subdiv_ccg, grids);
1032}
1033
1034static void apply_mask_bmesh(const Depsgraph &depsgraph,
1035 Object &object,
1036 const auto_mask::Cache &automasking,
1037 const ApplyMaskMode mode,
1038 const float factor,
1039 const float invert_automask,
1041 LocalData &tls)
1042{
1043 const SculptSession &ss = *object.sculpt;
1045
1046 tls.factors.resize(verts.size());
1047 const MutableSpan<float> factors = tls.factors;
1048 fill_factor_from_hide(verts, factors);
1049 scale_factors(factors, factor);
1050
1051 tls.new_mask.resize(verts.size());
1052 const MutableSpan<float> new_mask = tls.new_mask;
1053 new_mask.fill(1.0f);
1054 auto_mask::calc_vert_factors(depsgraph, object, automasking, node, verts, new_mask);
1055
1056 if (invert_automask) {
1057 mask::invert_mask(new_mask);
1058 }
1059
1060 tls.mask.resize(verts.size());
1061 const MutableSpan<float> node_mask = tls.mask;
1062 gather_mask_bmesh(*ss.bm, verts, node_mask);
1063
1064 calc_new_masks(mode, node_mask, new_mask);
1065 mix_new_masks(new_mask, factors, node_mask);
1066
1067 scatter_mask_bmesh(node_mask.as_span(), *ss.bm, verts);
1068}
1069
1070static void apply_mask_from_settings(const Depsgraph &depsgraph,
1071 Object &object,
1072 bke::pbvh::Tree &pbvh,
1073 const IndexMask &node_mask,
1074 const auto_mask::Cache &automasking,
1075 const ApplyMaskMode mode,
1076 const float factor,
1077 const bool invert_automask)
1078{
1080 switch (pbvh.type()) {
1081 case bke::pbvh::Type::Mesh: {
1082 Mesh &mesh = *static_cast<Mesh *>(object.data);
1083 bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
1084 bke::SpanAttributeWriter mask = attributes.lookup_or_add_for_write_span<float>(
1085 ".sculpt_mask", bke::AttrDomain::Point);
1086 const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1088 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1089 LocalData &tls = all_tls.local();
1091 object,
1092 hide_vert,
1093 automasking,
1094 mode,
1095 factor,
1096 invert_automask,
1097 nodes[i],
1098 tls,
1099 mask.span);
1100 bke::pbvh::node_update_mask_mesh(mask.span, nodes[i]);
1101 });
1102 mask.finish();
1103 break;
1104 }
1106 SubdivCCG &subdiv_ccg = *object.sculpt->subdiv_ccg;
1107 const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
1108 MutableSpan<float> masks = subdiv_ccg.masks;
1110 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1111 LocalData &tls = all_tls.local();
1113 depsgraph, object, automasking, mode, factor, invert_automask, nodes[i], tls);
1114 bke::pbvh::node_update_mask_grids(key, masks, nodes[i]);
1115 });
1116 break;
1117 }
1119 const int mask_offset = CustomData_get_offset_named(
1120 &object.sculpt->bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
1122 node_mask.foreach_index(GrainSize(1), [&](const int i) {
1123 LocalData &tls = all_tls.local();
1125 depsgraph, object, automasking, mode, factor, invert_automask, nodes[i], tls);
1126 bke::pbvh::node_update_mask_bmesh(mask_offset, nodes[i]);
1127 });
1128 break;
1129 }
1130 }
1131}
1132
1134{
1135 const Scene &scene = *CTX_data_scene(C);
1136 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
1138 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
1139 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1140
1141 const View3D *v3d = CTX_wm_view3d(C);
1142 const Base *base = CTX_data_active_base(C);
1143 if (!BKE_base_is_visible(v3d, base)) {
1144 return OPERATOR_CANCELLED;
1145 }
1146
1149
1152
1153 const ApplyMaskMode mode = ApplyMaskMode(RNA_enum_get(op->ptr, "mix_mode"));
1154 const float factor = RNA_float_get(op->ptr, "mix_factor");
1155
1157
1158 IndexMaskMemory memory;
1159 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1160
1161 /* Set up automasking settings. */
1162 Sculpt scene_copy = sd;
1163
1164 MaskSettingsSource src = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
1165 switch (src) {
1167 if (RNA_boolean_get(op->ptr, "invert")) {
1169 }
1170 else {
1172 }
1173
1174 if (RNA_boolean_get(op->ptr, "use_curve")) {
1176 }
1177
1178 scene_copy.automasking_cavity_blur_steps = RNA_int_get(op->ptr, "blur_steps");
1179 scene_copy.automasking_cavity_factor = RNA_float_get(op->ptr, "factor");
1180
1182 break;
1184 if (brush) {
1185 scene_copy.automasking_flags = brush->automasking_flags;
1189
1190 /* Ensure only cavity masking is enabled. */
1193 }
1194 else {
1195 scene_copy.automasking_flags = 0;
1196 BKE_report(op->reports, RPT_WARNING, "No active brush");
1197
1198 return OPERATOR_CANCELLED;
1199 }
1200
1201 break;
1203 /* Ensure only cavity masking is enabled. */
1206 break;
1207 }
1208
1209 /* Ensure cavity mask is actually enabled. */
1210 if (!(scene_copy.automasking_flags & BRUSH_AUTOMASKING_CAVITY_ALL)) {
1212 }
1213
1214 /* Create copy of brush with cleared automasking settings. */
1215 Brush brush_copy = dna::shallow_copy(*brush);
1216 /* Set a brush type that doesn't change topology so automasking isn't "disabled". */
1218 brush_copy.automasking_flags = 0;
1220 brush_copy.automasking_cavity_curve = scene_copy.automasking_cavity_curve;
1221
1222 std::unique_ptr<auto_mask::Cache> automasking = auto_mask::cache_init(
1223 *depsgraph, scene_copy, &brush_copy, ob);
1224
1225 if (!automasking) {
1226 return OPERATOR_CANCELLED;
1227 }
1228
1229 undo::push_begin(scene, ob, op);
1231
1232 apply_mask_from_settings(*depsgraph, ob, pbvh, node_mask, *automasking, mode, factor, false);
1233
1234 undo::push_end(ob);
1235
1236 pbvh.tag_masks_changed(node_mask);
1239
1240 return OPERATOR_FINISHED;
1241}
1242
1244{
1245 uiLayout *layout = op->layout;
1246 Scene *scene = CTX_data_scene(C);
1247 Sculpt *sd = scene->toolsettings ? scene->toolsettings->sculpt : nullptr;
1248
1249 uiLayoutSetPropSep(layout, true);
1250 uiLayoutSetPropDecorate(layout, false);
1251 MaskSettingsSource source = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
1252
1253 if (!sd) {
1255 }
1256
1257 switch (source) {
1259 uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
1260 uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1261 uiItemR(layout, op->ptr, "factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1262 uiItemR(layout, op->ptr, "blur_steps", UI_ITEM_NONE, nullptr, ICON_NONE);
1263 uiItemR(layout, op->ptr, "invert", UI_ITEM_NONE, nullptr, ICON_NONE);
1264 uiItemR(layout, op->ptr, "use_curve", UI_ITEM_NONE, nullptr, ICON_NONE);
1265
1266 if (sd && RNA_boolean_get(op->ptr, "use_curve")) {
1267 PointerRNA sculpt_ptr = RNA_pointer_create(&scene->id, &RNA_Sculpt, sd);
1269 layout, &sculpt_ptr, "automasking_cavity_curve_op", 'v', false, false, false, false);
1270 }
1271 break;
1272 }
1275 uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
1276 uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1277
1278 break;
1279 }
1280}
1281
1283{
1284 ot->name = "Mask From Cavity";
1285 ot->idname = "SCULPT_OT_mask_from_cavity";
1286 ot->description = "Creates a mask based on the curvature of the surface";
1287
1291
1293
1294 RNA_def_enum(ot->srna, "mix_mode", mix_modes, int(ApplyMaskMode::Mix), "Mode", "Mix mode");
1295 RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 5.0f, "Mix Factor", "", 0.0f, 1.0f);
1297 "settings_source",
1300 "Settings",
1301 "Use settings from here");
1303 "factor",
1304 0.5f,
1305 0.0f,
1306 5.0f,
1307 "Factor",
1308 "The contrast of the cavity mask",
1309 0.0f,
1310 1.0f);
1312 "blur_steps",
1313 2,
1314 0,
1315 25,
1316 "Blur",
1317 "The number of times the cavity mask is blurred",
1318 0,
1319 25);
1320 RNA_def_boolean(ot->srna, "use_curve", false, "Custom Curve", "");
1321 RNA_def_boolean(ot->srna, "invert", false, "Cavity (Inverted)", "");
1322}
1323
1325
1327{
1328 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
1330 const Sculpt &sd = *CTX_data_tool_settings(C)->sculpt;
1331 const Scene &scene = *CTX_data_scene(C);
1332 const Brush *brush = BKE_paint_brush_for_read(&sd.paint);
1333
1334 const View3D *v3d = CTX_wm_view3d(C);
1335 const Base *base = CTX_data_active_base(C);
1336 if (!BKE_base_is_visible(v3d, base)) {
1337 return OPERATOR_CANCELLED;
1338 }
1339
1342
1345
1346 const ApplyMaskMode mode = ApplyMaskMode(RNA_enum_get(op->ptr, "mix_mode"));
1347 const float factor = RNA_float_get(op->ptr, "mix_factor");
1348
1350
1351 IndexMaskMemory memory;
1352 const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
1353
1354 /* Set up automasking settings. */
1355 Sculpt scene_copy = sd;
1356
1357 MaskSettingsSource src = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
1358 switch (src) {
1360 const MaskBoundaryMode boundary_mode = MaskBoundaryMode(
1361 RNA_enum_get(op->ptr, "boundary_mode"));
1362 switch (boundary_mode) {
1365 break;
1368 break;
1369 }
1371 "propagation_steps");
1372 break;
1373 }
1375 if (brush) {
1376 scene_copy.automasking_flags = brush->automasking_flags;
1379
1382 }
1383 else {
1384 scene_copy.automasking_flags = 0;
1385 BKE_report(op->reports, RPT_WARNING, "No active brush");
1386
1387 return OPERATOR_CANCELLED;
1388 }
1389
1390 break;
1394 break;
1395 }
1396
1397 /* Create copy of brush with cleared automasking settings. */
1398 Brush brush_copy = dna::shallow_copy(*brush);
1399 /* Set a brush type that doesn't change topology so automasking isn't "disabled". */
1401 brush_copy.automasking_flags = 0;
1403
1404 std::unique_ptr<auto_mask::Cache> automasking = auto_mask::cache_init(
1405 *depsgraph, scene_copy, &brush_copy, ob);
1406
1407 if (!automasking) {
1408 return OPERATOR_CANCELLED;
1409 }
1410
1411 undo::push_begin(scene, ob, op);
1413
1414 apply_mask_from_settings(*depsgraph, ob, pbvh, node_mask, *automasking, mode, factor, true);
1415
1416 undo::push_end(ob);
1417
1418 pbvh.tag_masks_changed(node_mask);
1421
1422 return OPERATOR_FINISHED;
1423}
1424
1426{
1427 uiLayout *layout = op->layout;
1428 Scene *scene = CTX_data_scene(C);
1429 Sculpt *sd = scene->toolsettings ? scene->toolsettings->sculpt : nullptr;
1430
1431 uiLayoutSetPropSep(layout, true);
1432 uiLayoutSetPropDecorate(layout, false);
1433 MaskSettingsSource source = (MaskSettingsSource)RNA_enum_get(op->ptr, "settings_source");
1434
1435 if (!sd) {
1437 }
1438
1439 switch (source) {
1441 uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
1442 uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1443 uiItemR(layout, op->ptr, "boundary_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
1444 uiItemR(layout, op->ptr, "propagation_steps", UI_ITEM_NONE, nullptr, ICON_NONE);
1445 break;
1446 }
1449 uiItemR(layout, op->ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
1450 uiItemR(layout, op->ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
1451 break;
1452 }
1453}
1454
1456{
1457 ot->name = "Mask From Boundary";
1458 ot->idname = "SCULPT_OT_mask_from_boundary";
1459 ot->description = "Creates a mask based on the boundaries of the surface";
1460
1464
1466
1467 RNA_def_enum(ot->srna, "mix_mode", mix_modes, int(ApplyMaskMode::Mix), "Mode", "Mix mode");
1468 RNA_def_float(ot->srna, "mix_factor", 1.0f, 0.0f, 5.0f, "Mix Factor", "", 0.0f, 1.0f);
1470 "settings_source",
1473 "Settings",
1474 "Use settings from here");
1475
1476 static EnumPropertyItem mask_boundary_modes[] = {
1478 "MESH",
1479 ICON_NONE,
1480 "Mesh",
1481 "Calculate the boundary mask based on disconnected mesh topology islands"},
1483 "FACE_SETS",
1484 ICON_NONE,
1485 "Face Sets",
1486 "Calculate the boundary mask between face sets"},
1487 {0, nullptr, 0, nullptr, nullptr}};
1488
1490 "boundary_mode",
1491 mask_boundary_modes,
1493 "Mode",
1494 "Boundary type to mask");
1495 RNA_def_int(ot->srna, "propagation_steps", 1, 1, 20, "Propagation Steps", "", 1, 20);
1496}
1497
1500} // namespace mask
1501
1503{
1530
1536
1540}
1541
1543{
1544 filter::modal_keymap(keyconf);
1545}
1546
1547} // namespace blender::ed::sculpt_paint
void BKE_brush_color_set(Scene *scene, const Paint *paint, Brush *brush, const float color[3])
Definition brush.cc:1047
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)
Base * CTX_data_active_base(const bContext *C)
Main * CTX_data_main(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
Depsgraph * CTX_data_depsgraph_on_load(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
wmMsgBus * CTX_wm_message_bus(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
bool BKE_base_is_visible(const View3D *v3d, const Base *base)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
void BKE_mesh_batch_cache_dirty_tag(Mesh *mesh, eMeshBatchDirtyMode mode)
Mesh * BKE_mesh_from_object(Object *ob)
@ BKE_MESH_BATCH_DIRTY_ALL
Definition BKE_mesh.h:38
void BKE_mesh_mirror_apply_mirror_on_axis(Main *bmain, Mesh *mesh, int axis, float dist)
void multires_flush_sculpt_updates(Object *object)
Definition multires.cc:394
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(Object *ob)
void BKE_sculptsession_free(Object *ob)
Definition paint.cc:2145
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
Paint * BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
Definition paint.cc:371
void BKE_paint_init(Main *bmain, Scene *sce, PaintMode mode, const uchar col[3], bool ensure_brushes=true)
Definition paint.cc:1779
MultiresModifierData * BKE_sculpt_multires_active(const Scene *scene, Object *ob)
Definition paint.cc:2316
void BKE_sculpt_update_object_for_edit(Depsgraph *depsgraph, Object *ob_orig, bool is_paint_tool)
Definition paint.cc:2601
void BKE_sculpt_color_layer_create_if_needed(Object *object)
Definition paint.cc:2577
const uchar PAINT_CURSOR_SCULPT[3]
Definition paint.cc:243
void BKE_sculptsession_free_pbvh(Object &object)
Definition paint.cc:2099
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
void BKE_sculpt_toolsettings_data_ensure(Main *bmain, Scene *scene)
Definition paint.cc:2678
void BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, Main *bmain, Object *ob, MultiresModifierData *mmd)
Definition paint.cc:2610
void BKE_paint_brushes_validate(Main *bmain, Paint *paint)
Definition paint.cc:1108
A BVH for high poly meshes.
const blender::Set< BMVert *, 0 > & BKE_pbvh_bmesh_node_unique_verts(blender::bke::pbvh::BMeshNode *node)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_scene_graph_evaluated_ensure(Depsgraph *depsgraph, Main *bmain)
Definition scene.cc:2573
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
bool is_negative_m4(const float mat[4][4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define RPT_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ BRUSH_AUTOMASKING_CAVITY_NORMAL
@ BRUSH_AUTOMASKING_BOUNDARY_EDGES
@ BRUSH_AUTOMASKING_CAVITY_USE_CURVE
@ BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS
@ BRUSH_AUTOMASKING_CAVITY_ALL
@ BRUSH_AUTOMASKING_CAVITY_INVERTED
@ SCULPT_BRUSH_TYPE_SMOOTH
@ CD_PROP_FLOAT
These structs are the foundation for all linked lists in the library system.
@ ME_SCULPT_DYNAMIC_TOPOLOGY
@ OB_SOLID
eObjectMode
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
@ OB_MESH
@ V3D_SHADING_VERTEX_COLOR
void ED_paint_cursor_start(Paint *paint, bool(*poll)(bContext *C))
bool ED_operator_object_active_editable_mesh(bContext *C)
BLI_INLINE void IMB_colormanagement_scene_linear_to_srgb_v3(float srgb[3], const float scene_linear[3])
Read Guarded memory(de)allocation.
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DRAW
Definition WM_types.hh:428
#define NC_BRUSH
Definition WM_types.hh:352
#define ND_MODE
Definition WM_types.hh:412
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
#define NC_OBJECT
Definition WM_types.hh:346
@ BM_ELEM_TAG
void BM_log_all_added(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:874
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:902
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags)
#define BM_EDGE
bool BMO_op_callf(BMesh *bm, int flag, const char *fmt,...)
#define BMO_FLAG_DEFAULTS
@ BMO_FLAG_RESPECT_HIDE
constexpr void fill(const T &value) const
Definition BLI_span.hh:518
constexpr Span< T > as_span() const
Definition BLI_span.hh:662
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void resize(const int64_t new_size)
bool remove(const StringRef attribute_id)
Span< NodeT > nodes() const
void tag_masks_changed(const IndexMask &node_mask)
Definition pbvh.cc:586
void foreach_index(Fn &&fn) const
const Depsgraph * depsgraph
#define fabsf(x)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
static float verts[][3]
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
pbvh::Tree * pbvh_get(Object &object)
Definition paint.cc:2846
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
Definition pbvh.cc:2612
void node_update_mask_bmesh(int mask_offset, BMeshNode &node)
Definition pbvh.cc:1277
void node_update_mask_mesh(Span< float > mask, MeshNode &node)
Definition pbvh.cc:1219
void node_update_mask_grids(const CCGKey &key, Span< float > masks, GridsNode &node)
Definition pbvh.cc:1247
Bounds< float3 > bounds_get(const Tree &pbvh)
Definition pbvh.cc:1480
Span< float3 > vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
Definition pbvh.cc:2502
bool mode_compat_set(bContext *C, Object *ob, eObjectMode mode, ReportList *reports)
void calc_grids_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::GridsNode &node, Span< int > grids, MutableSpan< float > factors)
std::unique_ptr< Cache > cache_init(const Depsgraph &depsgraph, const Sculpt &sd, Object &ob)
void calc_vert_factors(const Depsgraph &depsgraph, const Object &object, const Cache &cache, const bke::pbvh::MeshNode &node, Span< int > verts, MutableSpan< float > factors)
void SCULPT_OT_cloth_filter(wmOperatorType *ot)
float4 color_vert_get(OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, GSpan color_attribute, bke::AttrDomain color_domain, int vert)
void SCULPT_OT_color_filter(wmOperatorType *ot)
bke::GAttributeReader active_color_attribute(const Mesh &mesh)
void enable_ex(Main &bmain, Depsgraph &depsgraph, Object &ob)
void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
void disable_with_undo(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
WarnFlag check_attribute_warning(Scene &scene, Object &ob)
void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot)
void SCULPT_OT_expand(wmOperatorType *ot)
void SCULPT_OT_face_set_lasso_gesture(wmOperatorType *ot)
void initialize_none_to_id(Mesh *mesh, int new_id)
void SCULPT_OT_face_set_line_gesture(wmOperatorType *ot)
void SCULPT_OT_face_set_polyline_gesture(wmOperatorType *ot)
void SCULPT_OT_face_sets_init(wmOperatorType *ot)
void SCULPT_OT_face_sets_create(wmOperatorType *ot)
void SCULPT_OT_face_set_change_visibility(wmOperatorType *ot)
void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
void SCULPT_OT_face_sets_edit(wmOperatorType *ot)
void SCULPT_OT_face_set_box_gesture(wmOperatorType *ot)
void SCULPT_OT_mesh_filter(wmOperatorType *ot)
wmKeyMap * modal_keymap(wmKeyConfig *keyconf)
static float color_delta_get(const float3 &color_a, const float3 &color_b, const float threshold, const bool invert)
static void apply_mask_from_settings(const Depsgraph &depsgraph, Object &object, bke::pbvh::Tree &pbvh, const IndexMask &node_mask, const auto_mask::Cache &automasking, const ApplyMaskMode mode, const float factor, const bool invert_automask)
void SCULPT_OT_mask_filter(wmOperatorType *ot)
void scatter_mask_grids(const Span< float > mask, SubdivCCG &subdiv_ccg, const Span< int > grids)
static void apply_mask_mesh(const Depsgraph &depsgraph, const Object &object, const Span< bool > hide_vert, const auto_mask::Cache &automasking, const ApplyMaskMode mode, const float factor, const bool invert_automask, const bke::pbvh::MeshNode &node, LocalData &tls, const MutableSpan< float > mask)
static void apply_mask_grids(const Depsgraph &depsgraph, Object &object, const auto_mask::Cache &automasking, const ApplyMaskMode mode, const float factor, const bool invert_automask, const bke::pbvh::GridsNode &node, LocalData &tls)
static EnumPropertyItem mix_modes[]
static void mask_from_cavity_ui(bContext *C, wmOperator *op)
static int mask_from_cavity_exec(bContext *C, wmOperator *op)
void mix_new_masks(const Span< float > new_masks, const Span< float > factors, const MutableSpan< float > masks)
Definition paint_mask.cc:98
static int mask_from_boundary_exec(bContext *C, wmOperator *op)
void update_mask_mesh(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, FunctionRef< void(MutableSpan< float >, Span< int >)> update_fn)
void SCULPT_OT_mask_init(wmOperatorType *ot)
static int mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
void scatter_mask_bmesh(const Span< float > mask, const BMesh &bm, const Set< BMVert *, 0 > &verts)
void gather_mask_bmesh(const BMesh &bm, const Set< BMVert *, 0 > &verts, const MutableSpan< float > r_mask)
static void mask_by_color_full_mesh(const Depsgraph &depsgraph, Object &object, const int vert, const float threshold, const bool invert, const bool preserve_mask)
static void calc_new_masks(const ApplyMaskMode mode, const Span< float > node_mask, const MutableSpan< float > new_mask)
static void mask_from_boundary_ui(bContext *C, wmOperator *op)
static void apply_mask_bmesh(const Depsgraph &depsgraph, Object &object, const auto_mask::Cache &automasking, const ApplyMaskMode mode, const float factor, const float invert_automask, bke::pbvh::BMeshNode &node, LocalData &tls)
static void mask_by_color_contiguous_mesh(const Depsgraph &depsgraph, Object &object, const int vert, const float threshold, const bool invert, const bool preserve_mask)
void invert_mask(const MutableSpan< float > masks)
void gather_mask_grids(const SubdivCCG &subdiv_ccg, const Span< int > grids, const MutableSpan< float > r_mask)
static void SCULPT_OT_mask_from_cavity(wmOperatorType *ot)
static EnumPropertyItem settings_sources[]
static void SCULPT_OT_mask_from_boundary(wmOperatorType *ot)
static float final_mask_get(const float current_mask, const float new_mask, const bool invert, const bool preserve_mask)
void clamp_mask(const MutableSpan< float > masks)
void SCULPT_OT_project_line_gesture(wmOperatorType *ot)
void SCULPT_OT_trim_lasso_gesture(wmOperatorType *ot)
void SCULPT_OT_trim_box_gesture(wmOperatorType *ot)
void SCULPT_OT_trim_line_gesture(wmOperatorType *ot)
void SCULPT_OT_trim_polyline_gesture(wmOperatorType *ot)
void push_nodes(const Depsgraph &depsgraph, Object &object, const IndexMask &node_mask, const Type type)
void push_node(const Depsgraph &depsgraph, const Object &object, const bke::pbvh::Node *node, Type type)
void push_begin_ex(const Scene &, Object &ob, const char *name)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
void push_begin(const Scene &scene, Object &ob, const wmOperator *op)
void object_sculpt_mode_enter(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob, bool force_dyntopo, ReportList *reports)
static bool no_multires_poll(bContext *C)
static void init_sculpt_mode_session(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
static void SCULPT_OT_symmetrize(wmOperatorType *ot)
void keymap_sculpt(wmKeyConfig *keyconf)
void flush_update_done(const bContext *C, Object &ob, UpdateType update_type)
Definition sculpt.cc:5055
static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
void ensure_valid_pivot(const Object &ob, Scene &scene)
void scale_factors(MutableSpan< float > factors, float strength)
Definition sculpt.cc:7227
static void SCULPT_OT_sample_color(wmOperatorType *ot)
void object_sculpt_mode_exit(Main &bmain, Depsgraph &depsgraph, Scene &scene, Object &ob)
static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void SCULPT_OT_optimize(wmOperatorType *ot)
static int symmetrize_exec(bContext *C, wmOperator *op)
void scatter_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6122
void SCULPT_OT_brush_stroke(wmOperatorType *ot)
Definition sculpt.cc:5473
static int set_persistent_base_exec(bContext *C, wmOperator *)
Definition sculpt_ops.cc:89
void gather_data_mesh(Span< T > src, Span< int > indices, MutableSpan< T > dst)
Definition sculpt.cc:6082
static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int optimize_exec(bContext *C, wmOperator *)
void fill_factor_from_hide(Span< bool > hide_vert, Span< int > verts, MutableSpan< float > r_factors)
Definition sculpt.cc:6442
void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
T distance(const T &a, const T &b)
T midpoint(const T &a, const T &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
VecBase< float, 4 > float4
void paint_cursor_delete_textures()
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
bool SCULPT_brush_cursor_poll(bContext *C)
Definition sculpt.cc:3617
bool SCULPT_cursor_geometry_info_update(bContext *C, SculptCursorGeometryInfo *out, const float mval[2], bool use_sampled_normal)
Definition sculpt.cc:4580
void SCULPT_vertex_random_access_ensure(Object &object)
Definition sculpt.cc:144
bool SCULPT_mode_poll(bContext *C)
Definition sculpt.cc:3560
bool SCULPT_handles_colors_report(const Object &object, ReportList *reports)
Definition sculpt.cc:5177
void SCULPT_tag_update_overlays(bContext *C)
Definition sculpt.cc:735
#define MASK_BY_COLOR_SLOPE
signed char int8_t
Definition stdint.h:75
float automasking_cavity_factor
char sculpt_brush_type
int automasking_flags
int automasking_cavity_blur_steps
int automasking_boundary_edges_propagation_steps
struct CurveMapping * automasking_cavity_curve
int grid_area
Definition BKE_ccg.hh:35
void * first
ListBase wm
Definition BKE_main.hh:239
float scale[3]
struct SculptSession * sculpt
BMLog * bm_log
Definition BKE_paint.hh:402
SubdivCCG * subdiv_ccg
Definition BKE_paint.hh:405
ActiveVert active_vert() const
Definition paint.cc:2180
eObjectMode mode_type
Definition BKE_paint.hh:487
int automasking_boundary_edges_propagation_steps
float automasking_cavity_factor
int automasking_cavity_blur_steps
int symmetrize_direction
struct CurveMapping * automasking_cavity_curve_op
struct CurveMapping * automasking_cavity_curve
int automasking_flags
blender::Array< float > masks
View3DShading shading
VecBase< T, 3 > xyz() const
int mval[2]
Definition WM_types.hh:728
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(* 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
void(* ui)(bContext *C, wmOperator *op)
Definition WM_types.hh:1053
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct ReportList * reports
struct uiLayout * layout
struct PointerRNA * ptr
struct UndoStack * undo_stack
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
void WM_toolsystem_update_from_context_view3d(bContext *C)
uint8_t flag
Definition wm_window.cc:138