Blender V4.3
grease_pencil_draw_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
5#include "ANIM_keyframing.hh"
6
7#include "BKE_brush.hh"
8#include "BKE_colortools.hh"
9#include "BKE_context.hh"
10#include "BKE_curves.hh"
11#include "BKE_deform.hh"
12#include "BKE_geometry_set.hh"
13#include "BKE_grease_pencil.hh"
14#include "BKE_material.h"
15#include "BKE_object_deform.h"
16#include "BKE_paint.hh"
17#include "BKE_report.hh"
18#include "BKE_screen.hh"
19
20#include "BLI_array_utils.hh"
21#include "BLI_assert.h"
22#include "BLI_color.hh"
23#include "BLI_index_mask.hh"
24#include "BLI_kdopbvh.h"
25#include "BLI_kdtree.h"
26#include "BLI_math_matrix.hh"
27#include "BLI_math_vector.hh"
28#include "BLI_offset_indices.hh"
29#include "BLI_rect.h"
30
31#include "DNA_brush_enums.h"
32#include "DNA_brush_types.h"
33#include "DNA_scene_types.h"
34#include "DNA_view3d_types.h"
36
38
40#include "GEO_smooth_curves.hh"
41
42#include "ED_grease_pencil.hh"
43#include "ED_image.hh"
44#include "ED_object.hh"
45#include "ED_screen.hh"
46#include "ED_space_api.hh"
47#include "ED_view3d.hh"
48
49#include "MEM_guardedalloc.h"
50
51#include "RNA_access.hh"
52#include "RNA_define.hh"
53
54#include "UI_interface.hh"
55
56#include "BLT_translation.hh"
57
58#include "WM_api.hh"
59#include "WM_toolsystem.hh"
60#include "WM_types.hh"
61
63#include "paint_intern.hh"
64#include "wm_event_types.hh"
65
66#include <algorithm>
67#include <fmt/format.h>
68#include <optional>
69
71
72/* -------------------------------------------------------------------- */
75
76static bool stroke_get_location(bContext * /*C*/,
77 float out[3],
78 const float mouse[2],
79 bool /*force_original*/)
80{
81 out[0] = mouse[0];
82 out[1] = mouse[1];
83 out[2] = 0;
84 return true;
85}
86
87static std::unique_ptr<GreasePencilStrokeOperation> get_stroke_operation(bContext &C,
88 wmOperator *op)
89{
91 const Brush &brush = *BKE_paint_brush_for_read(paint);
93 const BrushStrokeMode stroke_mode = BrushStrokeMode(RNA_enum_get(op->ptr, "mode"));
94
95 if (mode == PaintMode::GPencil) {
97 stroke_mode == BRUSH_STROKE_ERASE)
98 {
99 /* Special case: We're using the draw tool but with the eraser mode, so create an erase
100 * operation. */
102 }
103 /* FIXME: Somehow store the unique_ptr in the PaintStroke. */
104 switch (eBrushGPaintType(brush.gpencil_brush_type)) {
110 /* Fill tool keymap uses the paint operator as alternative mode. */
114 }
115 }
116 else if (mode == PaintMode::SculptGreasePencil) {
117 if (stroke_mode == BRUSH_STROKE_SMOOTH) {
118 return greasepencil::new_smooth_operation(stroke_mode, true);
119 }
122 return greasepencil::new_smooth_operation(stroke_mode);
124 return greasepencil::new_thickness_operation(stroke_mode);
126 return greasepencil::new_strength_operation(stroke_mode);
128 return greasepencil::new_grab_operation(stroke_mode);
130 return greasepencil::new_push_operation(stroke_mode);
132 return greasepencil::new_twist_operation(stroke_mode);
134 return greasepencil::new_pinch_operation(stroke_mode);
136 return greasepencil::new_randomize_operation(stroke_mode);
138 return greasepencil::new_clone_operation(stroke_mode);
139 }
140 }
141 else if (mode == PaintMode::WeightGPencil) {
151 }
152 }
153 else if (mode == PaintMode::VertexGPencil) {
166 /* Unused. */
168 return nullptr;
169 }
170 }
171 return nullptr;
172}
173
174static bool stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
175{
176 UNUSED_VARS(C, op, mouse);
177 return true;
178}
179
181 wmOperator *op,
182 PaintStroke *stroke,
183 PointerRNA *stroke_element)
184{
186 paint_stroke_mode_data(stroke));
187
189 RNA_float_get_array(stroke_element, "mouse", sample.mouse_position);
190 sample.pressure = RNA_float_get(stroke_element, "pressure");
191
192 if (!operation) {
193 std::unique_ptr<GreasePencilStrokeOperation> new_operation = get_stroke_operation(*C, op);
194 BLI_assert(new_operation != nullptr);
195 new_operation->on_stroke_begin(*C, sample);
196 paint_stroke_set_mode_data(stroke, std::move(new_operation));
197 }
198 else {
199 operation->on_stroke_extended(*C, sample);
200 }
201}
202
203static void stroke_redraw(const bContext *C, PaintStroke * /*stroke*/, bool /*final*/)
204{
206}
207
208static void stroke_done(const bContext *C, PaintStroke *stroke)
209{
211 paint_stroke_mode_data(stroke));
212 if (operation != nullptr) {
213 operation->on_stroke_done(*C);
214 }
215}
216
218
219/* -------------------------------------------------------------------- */
222
224{
226 return false;
227 }
229 return false;
230 }
231 return true;
232}
233
235{
236 if (event->tablet.active == EVT_TABLET_ERASER) {
237 RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_ERASE);
238 }
239
240 const bool use_duplicate_previous_key = [&]() -> bool {
242 const Brush &brush = *BKE_paint_brush_for_read(paint);
244 const BrushStrokeMode stroke_mode = BrushStrokeMode(RNA_enum_get(op->ptr, "mode"));
245
246 if (mode == PaintMode::GPencil) {
247 /* For the eraser and tint tool, we don't want auto-key to create an empty keyframe, so we
248 * duplicate the previous frame. */
252 {
253 return true;
254 }
255 /* Same for the temporary eraser when using the draw tool. */
257 stroke_mode == BRUSH_STROKE_ERASE)
258 {
259 return true;
260 }
261 }
262 return false;
263 }();
265 C, op, use_duplicate_previous_key);
266 if (return_value != OPERATOR_RUNNING_MODAL) {
267 return return_value;
268 }
269
271 op,
277 event->type);
278
279 return_value = op->type->modal(C, op, event);
280 if (return_value == OPERATOR_FINISHED) {
281 return OPERATOR_FINISHED;
282 }
283
286}
287
289{
290 return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
291}
292
294{
295 paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
296}
297
299{
300 ot->name = "Grease Pencil Draw";
301 ot->idname = "GREASE_PENCIL_OT_brush_stroke";
302 ot->description = "Draw a new stroke in the active Grease Pencil object";
303
308
310
312}
313
315
316/* -------------------------------------------------------------------- */
319
321{
323 return false;
324 }
326 return false;
327 }
328 return true;
329}
330
332{
333 const Scene *scene = CTX_data_scene(C);
334 const Object *object = CTX_data_active_object(C);
335 if (!object || object->type != OB_GREASE_PENCIL) {
336 return OPERATOR_CANCELLED;
337 }
338
339 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
340 if (!grease_pencil.has_active_layer()) {
341 BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
342 return OPERATOR_CANCELLED;
343 }
344
346 const Brush *brush = BKE_paint_brush_for_read(paint);
347 if (brush == nullptr) {
348 return OPERATOR_CANCELLED;
349 }
350
351 bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
352 if (!active_layer.is_editable()) {
353 BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
354 return OPERATOR_CANCELLED;
355 }
356
357 /* Ensure a drawing at the current keyframe. */
358 bool inserted_keyframe = false;
359 /* For the sculpt tools, we don't want the auto-key to create an empty keyframe, so we duplicate
360 * the previous key. */
361 const bool use_duplicate_previous_key = true;
362 for (bke::greasepencil::Layer *layer : grease_pencil.layers_for_write()) {
363 if (layer->is_editable() &&
365 *scene, grease_pencil, *layer, use_duplicate_previous_key, inserted_keyframe))
366 {
367 inserted_keyframe = true;
368 }
369 }
370 if (!inserted_keyframe) {
371 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
372 return OPERATOR_CANCELLED;
373 }
375
377 op,
383 event->type);
384
385 const int return_value = op->type->modal(C, op, event);
386 if (return_value == OPERATOR_FINISHED) {
387 return OPERATOR_FINISHED;
388 }
389
392}
393
395{
396 return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
397}
398
400{
401 paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
402}
403
405{
406 ot->name = "Grease Pencil Sculpt";
407 ot->idname = "GREASE_PENCIL_OT_sculpt_paint";
408 ot->description = "Sculpt strokes in the active Grease Pencil object";
409
414
416
418}
419
421
422/* -------------------------------------------------------------------- */
425
427{
429 return false;
430 }
432 return false;
433 }
434 return true;
435}
436
438 wmOperator *op,
439 const wmEvent *event)
440{
441 const Scene *scene = CTX_data_scene(C);
442 const Object *object = CTX_data_active_object(C);
443 if (!object || object->type != OB_GREASE_PENCIL) {
444 return OPERATOR_CANCELLED;
445 }
446
447 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
449 const Brush *brush = BKE_paint_brush_for_read(paint);
450 if (brush == nullptr) {
451 return OPERATOR_CANCELLED;
452 }
453
456 if (drawings.is_empty()) {
457 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw weight on");
458 return OPERATOR_CANCELLED;
459 }
460
461 const int active_defgroup_nr = BKE_object_defgroup_active_index_get(object) - 1;
462 if (active_defgroup_nr >= 0 && BKE_object_defgroup_active_is_locked(object)) {
463 BKE_report(op->reports, RPT_WARNING, "Active group is locked, aborting");
464 return OPERATOR_CANCELLED;
465 }
466
468 op,
474 event->type);
475
476 const int return_value = op->type->modal(C, op, event);
477 if (return_value == OPERATOR_FINISHED) {
478 return OPERATOR_FINISHED;
479 }
480
483}
484
486 wmOperator *op,
487 const wmEvent *event)
488{
489 return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
490}
491
496
498{
499 ot->name = "Grease Pencil Paint Weight";
500 ot->idname = "GREASE_PENCIL_OT_weight_brush_stroke";
501 ot->description = "Draw weight on stroke points in the active Grease Pencil object";
502
507
509
511}
512
514
515/* -------------------------------------------------------------------- */
518
520{
522 return false;
523 }
525 return false;
526 }
527 return true;
528}
529
531 wmOperator *op,
532 const wmEvent *event)
533{
534 const Scene *scene = CTX_data_scene(C);
535 const Object *object = CTX_data_active_object(C);
536 if (!object || object->type != OB_GREASE_PENCIL) {
537 return OPERATOR_CANCELLED;
538 }
539
540 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
541 if (!grease_pencil.has_active_layer()) {
542 BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
543 return OPERATOR_CANCELLED;
544 }
545
546 bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
547 if (!active_layer.is_editable()) {
548 BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
549 return OPERATOR_CANCELLED;
550 }
551
553 const Brush *brush = BKE_paint_brush_for_read(paint);
554 if (brush == nullptr) {
555 return OPERATOR_CANCELLED;
556 }
557
558 /* Ensure a drawing at the current keyframe. */
559 bool inserted_keyframe = false;
560 /* For the vertex paint tools, we don't want the auto-key to create an empty keyframe, so we
561 * duplicate the previous key. */
562 const bool use_duplicate_previous_key = true;
564 *scene, grease_pencil, active_layer, use_duplicate_previous_key, inserted_keyframe))
565 {
566 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
567 return OPERATOR_CANCELLED;
568 }
569 if (inserted_keyframe) {
571 }
572
574 op,
580 event->type);
581
582 const int return_value = op->type->modal(C, op, event);
583 if (return_value == OPERATOR_FINISHED) {
584 return OPERATOR_FINISHED;
585 }
586
589}
590
592 wmOperator *op,
593 const wmEvent *event)
594{
595 return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
596}
597
602
604{
605 ot->name = "Grease Pencil Paint Vertex";
606 ot->idname = "GREASE_PENCIL_OT_vertex_brush_stroke";
607 ot->description = "Draw on vertex colors in the active Grease Pencil object";
608
613
615
617}
618
620
621/* -------------------------------------------------------------------- */
624
627
628 /* Material of the generated stroke. */
630 /* Toggle inverse filling. */
631 bool invert = false;
632 /* Toggle precision mode. */
633 bool precision = false;
634
635 /* Methods for gap filling. */
637 /* Length of extension lines. */
639 /* Cut off extension lines at first intersection. */
641
642 /* Draw boundaries stroke overlay. */
644 /* Draw extension lines overlay. */
646
647 /* Mouse position where fill was initialized */
649 /* Extension lines drag mode is enabled (middle mouse button). */
651 /* Mouse position where the extension mode was enabled. */
653
654 /* Overlay draw callback for helper lines, etc. */
656
659 const int material_index,
660 const bool invert,
661 const bool precision)
662 {
664
666 const Brush &brush = *BKE_paint_brush(&ts.gp_paint->paint);
674 const bool brush_invert = brush.gpencil_settings->fill_direction == BRUSH_DIR_IN;
675 /* Both operator properties and brush properties can invert. Actual invert is XOR of both. */
676 const bool combined_invert = (invert != brush_invert);
677
678 return {layer,
680 combined_invert,
681 precision,
687 }
688};
689
690/* Find and cut extension lines at intersections with other lines and strokes. */
692 ed::greasepencil::ExtensionData &extension_data,
693 Span<int> origin_drawings,
694 Span<int> origin_points)
695{
696 const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
697 const Scene &scene = *CTX_data_scene(&C);
698 const Object &object = *CTX_data_active_object(&C);
699 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
700
701 const float4x4 view_matrix = float4x4(rv3d.viewmat);
702
704 ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
705
706 const IndexRange bvh_extension_range = extension_data.lines.starts.index_range();
707 Array<int> bvh_curve_offsets_data(drawings.size() + 1);
708 for (const int i : drawings.index_range()) {
709 bvh_curve_offsets_data[i] = drawings[i].drawing.strokes().points_num();
710 }
712 bvh_curve_offsets_data, bvh_extension_range.size());
713
714 /* Upper bound for segment count. Arrays are sized for easy index mapping, exact count isn't
715 * necessary. Not all entries are added to the BVH tree. */
716 const int max_bvh_lines = bvh_curve_offsets.data().last();
717 /* Cached view positions for lines. */
718 Array<float2> view_starts(max_bvh_lines);
719 Array<float2> view_ends(max_bvh_lines);
720
721 BVHTree *tree = BLI_bvhtree_new(max_bvh_lines, 0.0f, 4, 6);
723
724 /* Insert extension lines for intersection.
725 * Note: These are added first, so that the extension index matches its index in BVH data. */
726 for (const int i_line : bvh_extension_range.index_range()) {
727 const float2 start =
728 math::transform_point(view_matrix, extension_data.lines.starts[i_line]).xy();
729 const float2 end = math::transform_point(view_matrix, extension_data.lines.ends[i_line]).xy();
730
731 const int bvh_index = bvh_extension_range[i_line];
732 view_starts[bvh_index] = start;
733 view_ends[bvh_index] = end;
734
735 const float bb[6] = {start.x, start.y, 0.0f, end.x, end.y, 0.0f};
736 BLI_bvhtree_insert(tree, bvh_index, bb, 2);
737 }
738
739 /* Insert segments for cutting extensions on stroke intersection. */
740 for (const int i_drawing : drawings.index_range()) {
741 const ed::greasepencil::DrawingInfo &info = drawings[i_drawing];
743 const OffsetIndices points_by_curve = curves.points_by_curve();
744 const Span<float3> positions = curves.positions();
745 const VArray<bool> cyclic = curves.cyclic();
746 const bke::greasepencil::Layer &layer = grease_pencil.layer(info.layer_index);
747 const float4x4 layer_to_view = view_matrix * layer.to_world_space(object);
748
749 for (const int i_curve : curves.curves_range()) {
750 const bool is_cyclic = cyclic[i_curve];
751 const IndexRange points = points_by_curve[i_curve];
752
753 for (const int i_point : points.drop_back(1)) {
754 const float2 start = math::transform_point(layer_to_view, positions[i_point]).xy();
755 const float2 end = math::transform_point(layer_to_view, positions[i_point + 1]).xy();
756
757 const int bvh_index = bvh_curve_offsets[i_drawing][i_point];
758 view_starts[bvh_index] = start;
759 view_ends[bvh_index] = end;
760
761 const float bb[6] = {start.x, start.y, 0.0f, end.x, end.y, 0.0f};
762 BLI_bvhtree_insert(tree, bvh_index, bb, 2);
763 }
764 /* Last->first point segment only used for cyclic curves. */
765 if (is_cyclic) {
766 const float2 start = math::transform_point(layer_to_view, positions[points.last()]).xy();
767 const float2 end = math::transform_point(layer_to_view, positions[points.first()]).xy();
768
769 const int bvh_index = bvh_curve_offsets[i_drawing][points.last()];
770 view_starts[bvh_index] = start;
771 view_ends[bvh_index] = end;
772
773 const float bb[6] = {start.x, start.y, 0.0f, end.x, end.y, 0.0f};
774 BLI_bvhtree_insert(tree, bvh_index, bb, 2);
775 }
776 }
777 }
778
780
781 struct RaycastArgs {
782 Span<float2> starts;
783 Span<float2> ends;
784 /* Indices that may need to be ignored to avoid self-intersection. */
785 int ignore_index1;
786 int ignore_index2;
787 };
788 BVHTree_RayCastCallback callback =
789 [](void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) {
790 using Result = math::isect_result<float2>;
791
792 const RaycastArgs &args = *static_cast<const RaycastArgs *>(userdata);
793 if (ELEM(index, args.ignore_index1, args.ignore_index2)) {
794 return;
795 }
796
797 const float2 ray_start = float2(ray->origin);
798 const float2 ray_end = ray_start + float2(ray->direction) * ray->radius;
799 const float2 &line_start = args.starts[index];
800 const float2 &line_end = args.ends[index];
801 Result result = math::isect_seg_seg(ray_start, ray_end, line_start, line_end);
802 if (result.kind <= 0) {
803 return;
804 }
805 const float dist = result.lambda * math::distance(ray_start, ray_end);
806 if (dist >= hit->dist) {
807 return;
808 }
809 /* These always need to be calculated for the BVH traversal function. */
810 hit->index = index;
811 hit->dist = result.lambda * math::distance(ray_start, ray_end);
812 /* Don't need the hit point, only the lambda. */
813 hit->no[0] = result.lambda;
814 };
815
816 /* Store intersections first before applying to the data, so that subsequent ray-casts use
817 * original end points until all intersections are found. */
818 Vector<float3> new_extension_ends(extension_data.lines.ends.size());
819 for (const int i_line : extension_data.lines.starts.index_range()) {
820 const float2 start =
821 math::transform_point(view_matrix, extension_data.lines.starts[i_line]).xy();
822 const float2 end = math::transform_point(view_matrix, extension_data.lines.ends[i_line]).xy();
823 float length;
824 const float2 dir = math::normalize_and_get_length(end - start, length);
825
826 const int bvh_index = i_line;
827 const int origin_drawing = origin_drawings[i_line];
828 const int origin_point = origin_points[i_line];
829 const int bvh_origin_index = bvh_curve_offsets[origin_drawing][origin_point];
830
831 RaycastArgs args = {view_starts, view_ends, bvh_index, bvh_origin_index};
832 BVHTreeRayHit hit;
833 hit.index = -1;
834 hit.dist = FLT_MAX;
836 tree, float3(start, 0.0f), float3(dir, 0.0f), length, &hit, callback, &args);
837
838 if (hit.index >= 0) {
839 const float lambda = hit.no[0];
840 new_extension_ends[i_line] = math::interpolate(
841 extension_data.lines.starts[i_line], extension_data.lines.ends[i_line], lambda);
842 }
843 else {
844 new_extension_ends[i_line] = extension_data.lines.ends[i_line];
845 }
846 }
847
848 extension_data.lines.ends = std::move(new_extension_ends);
849}
850
851/* Find closest point in each circle and generate extension lines between such pairs. */
853 const bContext &C,
854 ed::greasepencil::ExtensionData &extension_data,
855 Span<int> /*origin_drawings*/,
856 Span<int> /*origin_points*/)
857{
858 const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
859 const Scene &scene = *CTX_data_scene(&C);
860 const Object &object = *CTX_data_active_object(&C);
861 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
862
863 const float4x4 view_matrix = float4x4(rv3d.viewmat);
864
866 ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
867
868 const IndexRange circles_range = extension_data.circles.centers.index_range();
869 /* TODO Include high-curvature feature points. */
870 const IndexRange feature_points_range = circles_range.after(0);
871 const IndexRange kd_points_range = IndexRange(circles_range.size() +
872 feature_points_range.size());
873
874 /* Upper bound for segment count. Arrays are sized for easy index mapping, exact count isn't
875 * necessary. Not all entries are added to the BVH tree. */
876 const int max_kd_entries = kd_points_range.size();
877 /* Cached view positions for lines. */
878 Array<float2> view_centers(max_kd_entries);
879 Array<float> view_radii(max_kd_entries);
880
881 KDTree_2d *kdtree = BLI_kdtree_2d_new(max_kd_entries);
882
883 /* Insert points for overlap tests. */
884 for (const int point_i : circles_range.index_range()) {
885 const float2 center =
886 math::transform_point(view_matrix, extension_data.circles.centers[point_i]).xy();
887 const float radius = math::average(math::to_scale(view_matrix)) *
888 extension_data.circles.radii[point_i];
889
890 const int kd_index = circles_range[point_i];
891 view_centers[kd_index] = center;
892 view_radii[kd_index] = radius;
893
894 BLI_kdtree_2d_insert(kdtree, kd_index, center);
895 }
896 for (const int i_point : feature_points_range.index_range()) {
897 /* TODO Insert feature points into the KDTree. */
898 UNUSED_VARS(i_point);
899 }
900 BLI_kdtree_2d_balance(kdtree);
901
902 struct {
903 Vector<float3> starts;
904 Vector<float3> ends;
905 } connection_lines;
906 /* Circles which can be kept because they generate no extension lines. */
907 Vector<int> keep_circle_indices;
908 keep_circle_indices.reserve(circles_range.size());
909
910 for (const int point_i : circles_range.index_range()) {
911 const int kd_index = circles_range[point_i];
912 const float2 center = view_centers[kd_index];
913 const float radius = view_radii[kd_index];
914
915 bool found = false;
916 BLI_kdtree_2d_range_search_cb_cpp(
917 kdtree,
918 center,
919 radius,
920 [&](const int other_point_i, const float * /*co*/, float /*dist_sq*/) {
921 if (other_point_i == kd_index) {
922 return true;
923 }
924
925 found = true;
926 connection_lines.starts.append(extension_data.circles.centers[point_i]);
927 if (circles_range.contains(other_point_i)) {
928 connection_lines.ends.append(extension_data.circles.centers[other_point_i]);
929 }
930 else if (feature_points_range.contains(other_point_i)) {
931 /* TODO copy feature point to connection_lines (beware of start index!). */
932 connection_lines.ends.append(float3(0));
933 }
934 else {
936 }
937 return true;
938 });
939 /* Keep the circle if no extension line was found. */
940 if (!found) {
941 keep_circle_indices.append(point_i);
942 }
943 }
944
945 BLI_kdtree_2d_free(kdtree);
946
947 /* Add new extension lines. */
948 extension_data.lines.starts.extend(connection_lines.starts);
949 extension_data.lines.ends.extend(connection_lines.ends);
950 /* Remove circles that formed extension lines. */
951 Vector<float3> old_centers = std::move(extension_data.circles.centers);
952 Vector<float> old_radii = std::move(extension_data.circles.radii);
953 extension_data.circles.centers.resize(keep_circle_indices.size());
954 extension_data.circles.radii.resize(keep_circle_indices.size());
955 array_utils::gather(old_centers.as_span(),
956 keep_circle_indices.as_span(),
957 extension_data.circles.centers.as_mutable_span());
958 array_utils::gather(old_radii.as_span(),
959 keep_circle_indices.as_span(),
960 extension_data.circles.radii.as_mutable_span());
961}
962
964 const bContext &C, const GreasePencilFillOpData &op_data)
965{
966 const Scene &scene = *CTX_data_scene(&C);
967 const Object &object = *CTX_data_active_object(&C);
968 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
969
971 ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
972
973 ed::greasepencil::ExtensionData extension_data;
974 Vector<int> origin_points;
975 Vector<int> origin_drawings;
976 for (const int i_drawing : drawings.index_range()) {
977 const ed::greasepencil::DrawingInfo &info = drawings[i_drawing];
979 const OffsetIndices points_by_curve = curves.points_by_curve();
980 const Span<float3> positions = curves.positions();
981 const VArray<bool> cyclic = curves.cyclic();
982 const float4x4 layer_to_world = grease_pencil.layer(info.layer_index).to_world_space(object);
983
984 for (const int i_curve : curves.curves_range()) {
985 const IndexRange points = points_by_curve[i_curve];
986 /* No extension lines on cyclic curves. */
987 if (cyclic[i_curve]) {
988 continue;
989 }
990 /* Can't compute directions for single-point curves. */
991 if (points.size() < 2) {
992 continue;
993 }
994
995 const float3 pos_head = math::transform_point(layer_to_world, positions[points[0]]);
996 const float3 pos_tail = math::transform_point(layer_to_world, positions[points.last()]);
997 const float3 pos_head_next = math::transform_point(layer_to_world, positions[points[1]]);
998 const float3 pos_tail_prev = math::transform_point(layer_to_world,
999 positions[points.last(1)]);
1000 const float3 dir_head = math::normalize(pos_head - pos_head_next);
1001 const float3 dir_tail = math::normalize(pos_tail - pos_tail_prev);
1002 /* Initial length before intersection tests. */
1003 const float length = op_data.extension_length;
1004
1005 switch (op_data.extension_mode) {
1007 extension_data.lines.starts.append(pos_head);
1008 extension_data.lines.ends.append(pos_head + dir_head * length);
1009 origin_drawings.append(i_drawing);
1010 origin_points.append(points.first());
1011
1012 extension_data.lines.starts.append(pos_tail);
1013 extension_data.lines.ends.append(pos_tail + dir_tail * length);
1014 origin_drawings.append(i_drawing);
1015 /* Segment index is the start point. */
1016 origin_points.append(points.last() - 1);
1017 break;
1019 extension_data.circles.centers.append(pos_head);
1020 extension_data.circles.radii.append(length);
1021 origin_drawings.append(i_drawing);
1022 origin_points.append(points.first());
1023
1024 extension_data.circles.centers.append(pos_tail);
1025 extension_data.circles.radii.append(length);
1026 origin_drawings.append(i_drawing);
1027 /* Segment index is the start point. */
1028 origin_points.append(points.last() - 1);
1029 break;
1030 }
1031 }
1032 }
1033
1034 switch (op_data.extension_mode) {
1036 /* Intersection test against strokes and other extension lines. */
1037 if (op_data.extension_cut) {
1038 grease_pencil_fill_extension_cut(C, extension_data, origin_drawings, origin_points);
1039 }
1040 break;
1043 C, extension_data, origin_drawings, origin_points);
1044 break;
1045 }
1046
1047 return extension_data;
1048}
1049
1051 const GreasePencilFillOpData &op_data)
1052{
1053 const bool is_extend = (op_data.extension_mode == GP_FILL_EMODE_EXTEND);
1054
1055 const std::string status_str = fmt::format(
1056 IFACE_("Fill: ESC/RMB cancel, LMB Fill, MMB Adjust Extension, S: "
1057 "Switch Mode, D: Stroke Collision | Mode: {}, Collision {}, Length: {:.3f}"),
1058 (is_extend) ? IFACE_("Extend") : IFACE_("Radius"),
1059 (is_extend && op_data.extension_cut) ? IFACE_("ON") : IFACE_("OFF"),
1060 op_data.extension_length);
1061
1062 ED_workspace_status_text(&C, status_str.c_str());
1063}
1064
1065/* Draw callback for fill tool overlay. */
1066static void grease_pencil_fill_overlay_cb(const bContext *C, ARegion * /*region*/, void *arg)
1067{
1068 const ARegion &region = *CTX_wm_region(C);
1069 const RegionView3D &rv3d = *CTX_wm_region_view3d(C);
1070 const Scene &scene = *CTX_data_scene(C);
1071 const Object &object = *CTX_data_active_object(C);
1072 const GreasePencil &grease_pencil = *static_cast<const GreasePencil *>(object.data);
1073 auto &op_data = *static_cast<GreasePencilFillOpData *>(arg);
1074
1075 const float4x4 world_to_view = float4x4(rv3d.viewmat);
1076 /* Note; the initial view matrix is already set, clear to draw in view space. */
1078
1079 const ColorGeometry4f stroke_curves_color = ColorGeometry4f(1, 0, 0, 1);
1080 const ColorGeometry4f extension_lines_color = ColorGeometry4f(0, 1, 1, 1);
1081 const ColorGeometry4f extension_circles_color = ColorGeometry4f(1, 0.5, 0, 1);
1082
1084 ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
1085
1086 if (op_data.show_boundaries) {
1088 ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
1089
1090 for (const ed::greasepencil::DrawingInfo &info : drawings) {
1091 const IndexMask curve_mask = info.drawing.strokes().curves_range();
1093 stroke_curves_color, info.drawing.strokes().points_num());
1094 const float4x4 layer_to_world = grease_pencil.layer(info.layer_index).to_world_space(object);
1095 const bool use_xray = false;
1096 const float radius_scale = 1.0f;
1097
1099 int2(region.winx, region.winy),
1100 object,
1101 info.drawing,
1102 layer_to_world,
1103 curve_mask,
1104 colors,
1105 use_xray,
1106 radius_scale);
1107 }
1108 }
1109
1110 if (op_data.show_extension) {
1112 *C, op_data);
1113
1114 const float line_width = 2.0f;
1115
1116 const IndexRange lines_range = extensions.lines.starts.index_range();
1117 if (!lines_range.is_empty()) {
1119 extension_lines_color, lines_range.size());
1120
1122 lines_range,
1123 extensions.lines.starts,
1124 extensions.lines.ends,
1125 line_colors,
1126 line_width);
1127 }
1128 const IndexRange circles_range = extensions.circles.centers.index_range();
1129 if (!circles_range.is_empty()) {
1131 extension_circles_color, circles_range.size());
1132
1134 world_to_view,
1135 circles_range,
1136 extensions.circles.centers,
1138 circle_colors,
1139 float2(region.winx, region.winy),
1140 line_width,
1141 false);
1142 }
1143 }
1144}
1145
1147 GreasePencilFillOpData &op_data)
1148{
1149 const bool needs_overlay = op_data.show_boundaries || op_data.show_extension;
1150
1151 if (needs_overlay) {
1152 if (op_data.overlay_cb_handle == nullptr) {
1155 }
1156 }
1157 else {
1158 if (op_data.overlay_cb_handle) {
1160 op_data.overlay_cb_handle = nullptr;
1161 }
1162 }
1163}
1164
1171
1172/* Layer mode defines layers where only marked boundary strokes are used. */
1174 eGP_FillLayerModes fill_layer_mode)
1175{
1176 BLI_assert(grease_pencil.has_active_layer());
1177 const IndexRange all_layers = grease_pencil.layers().index_range();
1178 const int active_layer_index = *grease_pencil.get_layer_index(*grease_pencil.get_active_layer());
1179
1180 switch (fill_layer_mode) {
1182 return VArray<bool>::ForFunc(all_layers.size(), [active_layer_index](const int index) {
1183 return index != active_layer_index;
1184 });
1186 return VArray<bool>::ForFunc(all_layers.size(), [active_layer_index](const int index) {
1187 return index != active_layer_index + 1;
1188 });
1190 return VArray<bool>::ForFunc(all_layers.size(), [active_layer_index](const int index) {
1191 return index != active_layer_index - 1;
1192 });
1194 return VArray<bool>::ForFunc(all_layers.size(), [active_layer_index](const int index) {
1195 return index <= active_layer_index;
1196 });
1198 return VArray<bool>::ForFunc(all_layers.size(), [active_layer_index](const int index) {
1199 return index >= active_layer_index;
1200 });
1202 return VArray<bool>::ForFunc(all_layers.size(), [grease_pencil](const int index) {
1203 return !grease_pencil.layers()[index]->is_visible();
1204 });
1205 }
1206 return {};
1207}
1208
1209/* Array of visible drawings to use as borders for generating a stroke in the editable drawing on
1210 * the active layer. This is provided for every frame in the multi-frame edit range. */
1215
1217 GreasePencil &grease_pencil,
1218 bke::greasepencil::Layer &target_layer)
1219{
1220 using namespace bke::greasepencil;
1223
1224 const ToolSettings *toolsettings = scene.toolsettings;
1225 const bool use_multi_frame_editing = (toolsettings->gpencil_flags &
1227 const bool use_autokey = blender::animrig::is_autokey_on(&scene);
1228 const bool use_duplicate_frame = (scene.toolsettings->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST);
1229 const int target_layer_index = *grease_pencil.get_layer_index(target_layer);
1230
1231 VectorSet<int> target_frames;
1232 /* Add drawing on the current frame. */
1233 target_frames.add(scene.r.cfra);
1234 /* Multi-frame edit: Add drawing on frames that are selected in any layer. */
1235 if (use_multi_frame_editing) {
1236 for (const Layer *layer : grease_pencil.layers()) {
1237 for (const auto [frame_number, frame] : layer->frames().items()) {
1238 if (frame.is_selected()) {
1239 target_frames.add(frame_number);
1240 }
1241 }
1242 }
1243 }
1244
1245 /* Create new drawings when autokey is enabled. */
1246 if (use_autokey) {
1247 for (const int frame_number : target_frames) {
1248 if (!target_layer.frames().contains(frame_number)) {
1249 if (use_duplicate_frame) {
1250 grease_pencil.insert_duplicate_frame(
1251 target_layer, *target_layer.start_frame_at(frame_number), frame_number, false);
1252 }
1253 else {
1254 grease_pencil.insert_frame(target_layer, frame_number);
1255 }
1256 }
1257 }
1258 }
1259
1261 for (const int frame_number : target_frames) {
1262 if (Drawing *target_drawing = grease_pencil.get_editable_drawing_at(target_layer,
1263 frame_number))
1264 {
1265 MutableDrawingInfo target = {*target_drawing, target_layer_index, frame_number, 1.0f};
1266
1267 Vector<DrawingInfo> sources;
1268 for (const Layer *source_layer : grease_pencil.layers()) {
1269 if (const Drawing *source_drawing = grease_pencil.get_drawing_at(*source_layer,
1270 frame_number))
1271 {
1272 const int source_layer_index = *grease_pencil.get_layer_index(*source_layer);
1273 sources.append({*source_drawing, source_layer_index, frame_number, 0});
1274 }
1275 }
1276
1277 drawings.append({std::move(target), std::move(sources)});
1278 }
1279 }
1280
1281 return drawings;
1282}
1283
1285{
1286 const int iterations = 20;
1287 if (curves.points_num() == 0) {
1288 return;
1289 }
1290 if (stroke_mask.is_empty()) {
1291 return;
1292 }
1293
1294 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
1295 const OffsetIndices points_by_curve = curves.points_by_curve();
1296 const VArray<bool> cyclic = curves.cyclic();
1297 const VArray<bool> point_selection = VArray<bool>::ForSingle(true, curves.points_num());
1298
1299 bke::GSpanAttributeWriter positions = attributes.lookup_for_write_span("position");
1301 points_by_curve,
1302 point_selection,
1303 cyclic,
1304 iterations,
1305 1.0f,
1306 false,
1307 true,
1308 positions.span);
1309 positions.finish();
1310 curves.tag_positions_changed();
1311}
1312
1314{
1315 const OffsetIndices points_by_curve = curves.points_by_curve();
1316 const Array<int> point_to_curve_map = curves.point_to_curve_map();
1317
1318 IndexMaskMemory memory;
1319 IndexMask points_to_keep = IndexMask::from_predicate(
1320 curves.points_range(), GrainSize(2048), memory, [&](const int64_t i) {
1321 const int curve_i = point_to_curve_map[i];
1322 const IndexRange points = points_by_curve[curve_i];
1323 if (points.size() <= 2) {
1324 return true;
1325 }
1326 const int local_i = i - points.start();
1327 return (local_i % int(math::pow(2.0f, float(step))) == 0) || points.last() == i;
1328 });
1329
1330 return bke::curves_copy_point_selection(curves, points_to_keep, {});
1331}
1332
1333static bool grease_pencil_apply_fill(bContext &C, wmOperator &op, const wmEvent &event)
1334{
1338
1339 constexpr const ed::greasepencil::FillToolFitMethod fit_method =
1341 /* Debug setting: keep image data blocks for inspection. */
1342 constexpr const bool keep_images = false;
1343
1344 ARegion &region = *CTX_wm_region(&C);
1345 /* Perform bounds check. */
1346 const bool in_bounds = BLI_rcti_isect_pt_v(&region.winrct, event.xy);
1347 if (!in_bounds) {
1348 return false;
1349 }
1350
1351 wmWindow &win = *CTX_wm_window(&C);
1353 const Scene &scene = *CTX_data_scene(&C);
1354 Object &object = *CTX_data_active_object(&C);
1355 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
1356 auto &op_data = *static_cast<GreasePencilFillOpData *>(op.customdata);
1357 const ToolSettings &ts = *CTX_data_tool_settings(&C);
1358 Brush &brush = *BKE_paint_brush(&ts.gp_paint->paint);
1359 const float2 mouse_position = float2(event.mval);
1360 const int simplify_levels = brush.gpencil_settings->fill_simplylvl;
1361 const std::optional<float> alpha_threshold =
1363 std::nullopt :
1364 std::make_optional(brush.gpencil_settings->fill_threshold);
1365 const bool on_back = (ts.gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK);
1366
1367 if (!grease_pencil.has_active_layer()) {
1368 return false;
1369 }
1370 /* Add drawings in the active layer if autokey is enabled. */
1372 scene, grease_pencil, *grease_pencil.get_active_layer());
1373
1374 const VArray<bool> boundary_layers = get_fill_boundary_layers(
1375 grease_pencil, eGP_FillLayerModes(brush.gpencil_settings->fill_layer_mode));
1376
1377 for (const FillToolTargetInfo &info : target_drawings) {
1378 const Layer &layer = *grease_pencil.layers()[info.target.layer_index];
1379
1381 C, op_data);
1382
1383 bke::CurvesGeometry fill_curves = fill_strokes(view_context,
1384 brush,
1385 scene,
1386 layer,
1387 boundary_layers,
1388 info.sources,
1389 op_data.invert,
1390 alpha_threshold,
1391 mouse_position,
1392 extensions,
1393 fit_method,
1394 op_data.material_index,
1395 keep_images);
1396
1397 smooth_fill_strokes(fill_curves, fill_curves.curves_range());
1398
1399 if (simplify_levels > 0) {
1400 fill_curves = simplify_fixed(fill_curves, brush.gpencil_settings->fill_simplylvl);
1401 }
1402
1403 bke::CurvesGeometry &dst_curves = info.target.drawing.strokes_for_write();
1404 /* If the `fill_strokes` function creates the "fill_opacity" attribute, make sure that we
1405 * initialize this to full opacity on the target geometry. */
1406 if (fill_curves.attributes().contains("fill_opacity") &&
1407 !dst_curves.attributes().contains("fill_opacity"))
1408 {
1409 bke::SpanAttributeWriter<float> fill_opacities =
1411 "fill_opacity",
1414 fill_opacities.finish();
1415 }
1416
1417 Curves *dst_curves_id = curves_new_nomain(dst_curves);
1418 Curves *fill_curves_id = curves_new_nomain(fill_curves);
1419 const Array<bke::GeometrySet> geometry_sets = {
1420 bke::GeometrySet::from_curves(on_back ? fill_curves_id : dst_curves_id),
1421 bke::GeometrySet::from_curves(on_back ? dst_curves_id : fill_curves_id)};
1422 const int num_new_curves = fill_curves.curves_num();
1423 const IndexRange new_curves_range = (on_back ?
1424 IndexRange(num_new_curves) :
1425 dst_curves.curves_range().after(num_new_curves));
1426
1427 bke::GeometrySet joined_geometry_set = geometry::join_geometries(geometry_sets, {});
1428 if (joined_geometry_set.has_curves()) {
1429 dst_curves = joined_geometry_set.get_curves_for_write()->geometry.wrap();
1430 info.target.drawing.tag_topology_changed();
1431
1432 /* Compute texture matrix for the new curves. */
1433 const ed::greasepencil::DrawingPlacement placement(
1434 scene, region, *view_context.v3d, object, &layer);
1436 &scene, &region, mouse_position, placement);
1437 Array<float4x2> texture_matrices(num_new_curves, texture_space);
1438 info.target.drawing.set_texture_matrices(texture_matrices, new_curves_range);
1439 }
1440 }
1441
1443
1444 /* Save extend value for next operation. */
1445 brush.gpencil_settings->fill_extend_fac = op_data.extension_length /
1448
1449 return true;
1450}
1451
1453{
1455
1456 Main &bmain = *CTX_data_main(&C);
1457 Scene &scene = *CTX_data_scene(&C);
1459 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob.data);
1461 Brush &brush = *BKE_paint_brush(&paint);
1462
1463 Layer *layer = grease_pencil.get_active_layer();
1464 /* Cannot paint in locked layer. */
1465 if (layer && layer->is_locked()) {
1466 return false;
1467 }
1468 if (layer == nullptr) {
1469 layer = &grease_pencil.add_layer("GP_Layer");
1470 }
1471
1472 if (brush.gpencil_settings == nullptr) {
1474 }
1484
1486 &bmain, &ob, &brush);
1487 const int material_index = BKE_object_material_index_get(&ob, material);
1488
1489 const bool invert = RNA_boolean_get(op.ptr, "invert");
1490 const bool precision = RNA_boolean_get(op.ptr, "precision");
1491
1492 op.customdata = MEM_new<GreasePencilFillOpData>(
1493 __func__,
1494 GreasePencilFillOpData::from_context(C, *layer, material_index, invert, precision));
1495 return true;
1496}
1497
1499{
1500 const ARegion &region = *CTX_wm_region(&C);
1502 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob.data);
1503
1505
1506 if (op.customdata) {
1507 auto &op_data = *static_cast<GreasePencilFillOpData *>(op.customdata);
1508
1509 if (op_data.overlay_cb_handle) {
1510 ED_region_draw_cb_exit(region.type, op_data.overlay_cb_handle);
1511 op_data.overlay_cb_handle = nullptr;
1512 }
1513
1514 MEM_delete(static_cast<GreasePencilFillOpData *>(op.customdata));
1515 op.customdata = nullptr;
1516 }
1517
1518 /* Clear status message area. */
1519 ED_workspace_status_text(&C, nullptr);
1520
1522
1525}
1526
1527static int grease_pencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
1528{
1529 const ARegion &region = *CTX_wm_region(C);
1531 Brush &brush = *BKE_paint_brush(&ts.gp_paint->paint);
1533 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob.data);
1534
1535 /* Fill tool needs a material (cannot use default material). */
1537 brush.gpencil_settings->material == nullptr)
1538 {
1539 BKE_report(op->reports, RPT_ERROR, "Fill tool needs active material");
1540 return OPERATOR_CANCELLED;
1541 }
1542 if (BKE_object_material_get(&ob, ob.actcol) == nullptr) {
1543 BKE_report(op->reports, RPT_ERROR, "Fill tool needs active material");
1544 return OPERATOR_CANCELLED;
1545 }
1546 if (!grease_pencil_fill_init(*C, *op)) {
1548 return OPERATOR_CANCELLED;
1549 }
1550 auto &op_data = *static_cast<GreasePencilFillOpData *>(op->customdata);
1551
1554 grease_pencil_fill_update_overlay(region, op_data);
1555
1558
1559 /* Add a modal handler for this operator. */
1561
1563}
1564
1576
1578{
1579 auto &op_data = *static_cast<GreasePencilFillOpData *>(op->customdata);
1580 /* Extension line length increment, for normal and precise mode respectively. */
1581 const float extension_delta = (op_data.precision ? 0.002f : 0.02f);
1582
1583 switch (event->val) {
1585 return OPERATOR_CANCELLED;
1586
1588 /* Ignore in extension mode. */
1589 if (op_data.is_extension_drag_active) {
1590 break;
1591 }
1592
1593 op_data.fill_mouse_pos = float2(event->mval);
1595 }
1596
1598 if (op_data.show_extension) {
1599 /* Toggle mode. */
1600 if (op_data.extension_mode == GP_FILL_EMODE_EXTEND) {
1601 op_data.extension_mode = GP_FILL_EMODE_RADIUS;
1602 }
1603 else {
1604 op_data.extension_mode = GP_FILL_EMODE_EXTEND;
1605 }
1606 grease_pencil_update_extend(*C, op_data);
1607 }
1608 break;
1609
1611 op_data.extension_length = std::max(op_data.extension_length - extension_delta, 0.0f);
1612 grease_pencil_update_extend(*C, op_data);
1613 break;
1614
1616 op_data.extension_length = std::min(op_data.extension_length + extension_delta, 10.0f);
1617 grease_pencil_update_extend(*C, op_data);
1618 break;
1619
1621 if (event->val == KM_PRESS) {
1622 /* Consider initial offset as zero position. */
1623 op_data.is_extension_drag_active = true;
1624 /* TODO This is the GPv2 logic and it's weird. Should be reconsidered, for now use the
1625 * same method. */
1626 const float2 base_pos = float2(event->mval);
1627 constexpr const float gap = 300.0f;
1628 op_data.extension_mouse_pos = (math::distance(base_pos, op_data.fill_mouse_pos) >= gap ?
1629 base_pos :
1630 base_pos - float2(gap, 0));
1632 }
1633 if (event->val == KM_RELEASE) {
1635 op_data.is_extension_drag_active = false;
1636 }
1637 /* Update cursor line. */
1640 break;
1641 }
1642
1644 if (op_data.show_extension) {
1645 op_data.extension_cut = !op_data.extension_cut;
1646 grease_pencil_update_extend(*C, op_data);
1647 }
1648 break;
1649
1651 op_data.invert = !op_data.invert;
1652 break;
1653
1655 op_data.precision = !op_data.precision;
1656 break;
1657
1658 default:
1660 break;
1661 }
1663}
1664
1666{
1667 const RegionView3D &rv3d = *CTX_wm_region_view3d(C);
1668
1669 auto &op_data = *static_cast<GreasePencilFillOpData *>(op->customdata);
1670
1671 int estate = OPERATOR_RUNNING_MODAL;
1672 switch (event->type) {
1673 case EVT_MODAL_MAP:
1674 estate = grease_pencil_fill_event_modal_map(C, op, event);
1675 break;
1676 case MOUSEMOVE: {
1677 if (!op_data.is_extension_drag_active) {
1678 break;
1679 }
1680
1681 const Object &ob = *CTX_data_active_object(C);
1682 const float pixel_size = ED_view3d_pixel_size(&rv3d, ob.loc);
1683 const float2 mouse_pos = float2(event->mval);
1684 const float initial_dist = math::distance(op_data.extension_mouse_pos,
1685 op_data.fill_mouse_pos);
1686 const float current_dist = math::distance(mouse_pos, op_data.fill_mouse_pos);
1687
1688 float delta = (current_dist - initial_dist) * pixel_size * 0.5f;
1689 op_data.extension_length = std::clamp(op_data.extension_length + delta, 0.0f, 10.0f);
1690
1691 /* Update cursor line and extend lines. */
1694
1695 grease_pencil_update_extend(*C, op_data);
1696 break;
1697 }
1698 default:
1699 break;
1700 }
1701 /* Process last operations before exiting. */
1702 switch (estate) {
1703 case OPERATOR_FINISHED:
1706 break;
1707
1708 case OPERATOR_CANCELLED:
1710 break;
1711
1712 default:
1713 break;
1714 }
1715
1716 return estate;
1717}
1718
1720{
1722}
1723
1725{
1726 PropertyRNA *prop;
1727
1728 ot->name = "Grease Pencil Fill";
1729 ot->idname = "GREASE_PENCIL_OT_fill";
1730 ot->description = "Fill with color the shape formed by strokes";
1731
1733 ot->invoke = grease_pencil_fill_invoke;
1735 ot->cancel = grease_pencil_fill_cancel;
1736
1737 ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
1738
1739 prop = RNA_def_boolean(
1740 ot->srna, "invert", false, "Invert", "Find boundary of unfilled instead of filled regions");
1742
1743 prop = RNA_def_boolean(
1744 ot->srna, "precision", false, "Precision", "Use precision movement for extension lines");
1746}
1747
1749
1750} // namespace blender::ed::sculpt_paint
1751
1752/* -------------------------------------------------------------------- */
1755
1765
1767{
1768 using namespace blender::ed::greasepencil;
1770
1771 static const EnumPropertyItem modal_items[] = {
1772 {int(FillToolModalKey::Cancel), "CANCEL", 0, "Cancel", ""},
1773 {int(FillToolModalKey::Confirm), "CONFIRM", 0, "Confirm", ""},
1775 "EXTENSION_MODE_TOGGLE",
1776 0,
1777 "Toggle Extension Mode",
1778 ""},
1780 "EXTENSION_LENGTHEN",
1781 0,
1782 "Lengthen Extensions",
1783 ""},
1784 {int(FillToolModalKey::ExtensionShorten), "EXTENSION_SHORTEN", 0, "Shorten Extensions", ""},
1785 {int(FillToolModalKey::ExtensionDrag), "EXTENSION_DRAG", 0, "Drag Extensions", ""},
1786 {int(FillToolModalKey::ExtensionCollide), "EXTENSION_COLLIDE", 0, "Collide Extensions", ""},
1787 {int(FillToolModalKey::Invert), "INVERT", 0, "Invert", ""},
1788 {int(FillToolModalKey::Precision), "PRECISION", 0, "Precision", ""},
1789 {0, nullptr, 0, nullptr, nullptr},
1790 };
1791
1792 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Fill Tool Modal Map");
1793
1794 /* This function is called for each space-type, only needs to add map once. */
1795 if (keymap && keymap->modal_items) {
1796 return;
1797 }
1798
1799 keymap = WM_modalkeymap_ensure(keyconf, "Fill Tool Modal Map", modal_items);
1800
1801 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_fill");
1802}
1803
Functions to insert, delete or modify keyframes.
void BKE_brush_init_gpencil_settings(Brush *brush)
Definition brush.cc:563
void BKE_brush_tag_unsaved_changes(Brush *brush)
Definition brush.cc:621
void BKE_curvemapping_init(CurveMapping *cumap)
wmWindow * CTX_wm_window(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)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Low-level operations for curves.
support for deformation groups and hooks.
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:601
Low-level operations for grease pencil.
Material * BKE_grease_pencil_object_material_ensure_from_active_input_brush(Main *bmain, Object *ob, Brush *brush)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
int BKE_object_material_index_get(Object *ob, const Material *ma)
Functions for dealing with objects and deform verts, used by painting and tools.
bool BKE_object_defgroup_active_is_locked(const struct Object *ob)
PaintMode
Definition BKE_paint.hh:99
@ SculptGreasePencil
Definition BKE_paint.hh:116
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:477
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
Definition paint.cc:506
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
BVHTree * BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
void BLI_bvhtree_balance(BVHTree *tree)
void BLI_bvhtree_free(BVHTree *tree)
void(* BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints)
int BLI_bvhtree_ray_cast(const BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
A KD-tree for nearest neighbor search.
#define BLI_SCOPED_DEFER(function_to_defer)
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
#define UNUSED_VARS(...)
#define ELEM(...)
#define IFACE_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
eBrushGPVertexType
@ GPVERTEX_BRUSH_TYPE_BLUR
@ GPVERTEX_BRUSH_TYPE_DRAW
@ GPVERTEX_BRUSH_TYPE_TINT
@ GPVERTEX_BRUSH_TYPE_REPLACE
@ GPVERTEX_BRUSH_TYPE_AVERAGE
@ GPVERTEX_BRUSH_TYPE_SMEAR
eBrushGPaintType
@ GPAINT_BRUSH_TYPE_TINT
@ GPAINT_BRUSH_TYPE_FILL
@ GPAINT_BRUSH_TYPE_DRAW
@ GPAINT_BRUSH_TYPE_ERASE
eGP_FillExtendModes
@ GP_FILL_EMODE_RADIUS
@ GP_FILL_EMODE_EXTEND
@ GP_BRUSH_FILL_SHOW_HELPLINES
@ GP_BRUSH_FILL_HIDE
@ GP_BRUSH_FILL_STROKE_COLLIDE
@ GP_BRUSH_MATERIAL_PINNED
@ GP_BRUSH_FILL_SHOW_EXTENDLINES
@ BRUSH_DIR_IN
eBrushGPWeightType
@ GPWEIGHT_BRUSH_TYPE_AVERAGE
@ GPWEIGHT_BRUSH_TYPE_DRAW
@ GPWEIGHT_BRUSH_TYPE_SMEAR
@ GPWEIGHT_BRUSH_TYPE_BLUR
eBrushGPSculptType
@ GPSCULPT_BRUSH_TYPE_SMOOTH
@ GPSCULPT_BRUSH_TYPE_PUSH
@ GPSCULPT_BRUSH_TYPE_CLONE
@ GPSCULPT_BRUSH_TYPE_TWIST
@ GPSCULPT_BRUSH_TYPE_RANDOMIZE
@ GPSCULPT_BRUSH_TYPE_GRAB
@ GPSCULPT_BRUSH_TYPE_PINCH
@ GPSCULPT_BRUSH_TYPE_THICKNESS
@ GPSCULPT_BRUSH_TYPE_STRENGTH
eGP_FillLayerModes
@ GP_FILL_GPLMODE_ABOVE
@ GP_FILL_GPLMODE_ALL_ABOVE
@ GP_FILL_GPLMODE_VISIBLE
@ GP_FILL_GPLMODE_ALL_BELOW
@ GP_FILL_GPLMODE_BELOW
@ GP_FILL_GPLMODE_ACTIVE
@ OB_GREASE_PENCIL
@ GP_TOOL_FLAG_RETAIN_LAST
@ GP_TOOL_FLAG_PAINT_ONBACK
@ GP_USE_MULTI_FRAME_EDITING
@ OPERATOR_RUNNING_MODAL
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
float ED_view3d_pixel_size(const RegionView3D *rv3d, const float co[3])
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
Read Guarded memory(de)allocation.
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NA_EDITED
Definition WM_types.hh:550
#define NC_GPENCIL
Definition WM_types.hh:366
@ KM_PRESS
Definition WM_types.hh:284
@ KM_RELEASE
Definition WM_types.hh:285
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
bool contains(const Key &key) const
Definition BLI_map.hh:329
void append(const T &value)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t first() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr IndexRange after(int64_t n) const
constexpr int64_t start() const
constexpr bool contains(int64_t value) const
constexpr IndexRange index_range() const
static VArray ForSingle(T value, const int64_t size)
static VArray ForSpan(Span< T > values)
static VArray ForFunc(const int64_t size, GetFunc get_func)
bool add(const Key &key)
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void reserve(const int64_t min_capacity)
Span< T > as_span() const
bool contains(const StringRef attribute_id) const
IndexRange curves_range() const
MutableAttributeAccessor attributes_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
const bke::CurvesGeometry & strokes() const
float4x4 to_world_space(const Object &object) const
const Map< FramesMapKeyT, GreasePencilFrame > & frames() const
std::optional< int > start_frame_at(int frame_number) const
virtual void on_stroke_extended(const bContext &C, const InputSample &extension_sample)=0
virtual void on_stroke_done(const bContext &C)=0
static bool is_cyclic(const Nurb *nu)
KDTree_3d * tree
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
void ED_filltool_modal_keymap(wmKeyConfig *keyconf)
void ED_operatortypes_grease_pencil_draw()
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
bool is_autokey_on(const Scene *scene)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
constexpr float LEGACY_RADIUS_CONVERSION_FACTOR
CurvesGeometry curves_copy_point_selection(const CurvesGeometry &curves, const IndexMask &points_to_copy, const AttributeFilter &attribute_filter)
void draw_lines(const float4x4 &transform, IndexRange indices, Span< float3 > start_positions, Span< float3 > end_positions, const VArray< ColorGeometry4f > &colors, float line_width)
void draw_grease_pencil_strokes(const RegionView3D &rv3d, const int2 &win_size, const Object &object, const bke::greasepencil::Drawing &drawing, const float4x4 &transform, const IndexMask &strokes_mask, const VArray< ColorGeometry4f > &colors, const bool use_xray, const float radius_scale)
void draw_circles(const float4x4 &transform, const IndexRange indices, Span< float3 > centers, const VArray< float > &radii, const VArray< ColorGeometry4f > &colors, const float2 &viewport_size, const float line_width, const bool fill)
int grease_pencil_draw_operator_invoke(bContext *C, wmOperator *op, const bool use_duplicate_previous_key)
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const bool duplicate_previous_key, bool &r_inserted_keyframe)
bool grease_pencil_vertex_painting_poll(bContext *C)
Vector< DrawingInfo > retrieve_visible_drawings(const Scene &scene, const GreasePencil &grease_pencil, const bool do_onion_skinning)
bool grease_pencil_sculpting_poll(bContext *C)
bool grease_pencil_weight_painting_poll(bContext *C)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
float4x2 calculate_texture_space(const Scene *scene, const ARegion *region, const float2 &mouse, const DrawingPlacement &placement)
bool grease_pencil_painting_poll(bContext *C)
std::unique_ptr< GreasePencilStrokeOperation > new_vertex_replace_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_erase_operation(const bool temp_eraser)
std::unique_ptr< GreasePencilStrokeOperation > new_weight_paint_average_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_strength_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_grab_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_weight_paint_blur_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_vertex_paint_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_clone_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_randomize_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_vertex_blur_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_tint_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_thickness_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_pinch_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_weight_paint_draw_operation(const BrushStrokeMode &brush_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_push_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_weight_paint_smear_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_vertex_average_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_twist_operation(BrushStrokeMode stroke_mode)
std::unique_ptr< GreasePencilStrokeOperation > new_smooth_operation(BrushStrokeMode stroke_mode, bool temp_smooth=false)
std::unique_ptr< GreasePencilStrokeOperation > new_vertex_smear_operation()
std::unique_ptr< GreasePencilStrokeOperation > new_paint_operation(bool temp_draw=false)
static void grease_pencil_fill_extension_lines_from_circles(const bContext &C, ed::greasepencil::ExtensionData &extension_data, Span< int >, Span< int >)
static bool stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static bool grease_pencil_weight_brush_stroke_poll(bContext *C)
static void grease_pencil_sculpt_paint_cancel(bContext *C, wmOperator *op)
static int grease_pencil_vertex_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void grease_pencil_fill_exit(bContext &C, wmOperator &op)
static int grease_pencil_weight_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void stroke_update_step(bContext *C, wmOperator *op, PaintStroke *, PointerRNA *stroke_element)
static bool grease_pencil_sculpt_paint_poll(bContext *C)
static int grease_pencil_weight_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void grease_pencil_fill_cancel(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_weight_brush_stroke(wmOperatorType *ot)
static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool stroke_get_location(bContext *C, float out[3], const float mouse[2], bool)
static void grease_pencil_brush_stroke_cancel(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_brush_stroke(wmOperatorType *ot)
void paint_stroke_cancel(bContext *C, wmOperator *op, PaintStroke *stroke)
static int grease_pencil_vertex_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void GREASE_PENCIL_OT_vertex_brush_stroke(wmOperatorType *ot)
static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void stroke_done(const bContext *C, PaintStroke *stroke)
static void GREASE_PENCIL_OT_sculpt_paint(wmOperatorType *ot)
static void grease_pencil_fill_status_indicators(bContext &C, const GreasePencilFillOpData &op_data)
static bool grease_pencil_vertex_brush_stroke_poll(bContext *C)
static void grease_pencil_vertex_brush_stroke_cancel(bContext *C, wmOperator *op)
static bke::CurvesGeometry simplify_fixed(bke::CurvesGeometry &curves, const int step)
static int grease_pencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *)
static int grease_pencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void stroke_redraw(const bContext *C, PaintStroke *, bool)
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintStroke **stroke_p)
static VArray< bool > get_fill_boundary_layers(const GreasePencil &grease_pencil, eGP_FillLayerModes fill_layer_mode)
static Vector< FillToolTargetInfo > ensure_editable_drawings(const Scene &scene, GreasePencil &grease_pencil, bke::greasepencil::Layer &target_layer)
static void grease_pencil_weight_brush_stroke_cancel(bContext *C, wmOperator *op)
static int grease_pencil_fill_event_modal_map(bContext *C, wmOperator *op, const wmEvent *event)
static void GREASE_PENCIL_OT_fill(wmOperatorType *ot)
static void grease_pencil_fill_overlay_cb(const bContext *C, ARegion *, void *arg)
void * paint_stroke_mode_data(PaintStroke *stroke)
static bool grease_pencil_apply_fill(bContext &C, wmOperator &op, const wmEvent &event)
static void grease_pencil_fill_update_overlay(const ARegion &region, GreasePencilFillOpData &op_data)
PaintStroke * paint_stroke_new(bContext *C, wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type)
static ed::greasepencil::ExtensionData grease_pencil_fill_get_extension_data(const bContext &C, const GreasePencilFillOpData &op_data)
static int grease_pencil_brush_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void grease_pencil_fill_extension_cut(const bContext &C, ed::greasepencil::ExtensionData &extension_data, Span< int > origin_drawings, Span< int > origin_points)
static void smooth_fill_strokes(bke::CurvesGeometry &curves, const IndexMask &stroke_mask)
static std::unique_ptr< GreasePencilStrokeOperation > get_stroke_operation(bContext &C, wmOperator *op)
static bool grease_pencil_brush_stroke_poll(bContext *C)
static void grease_pencil_update_extend(bContext &C, GreasePencilFillOpData &op_data)
static int grease_pencil_sculpt_paint_modal(bContext *C, wmOperator *op, const wmEvent *event)
void paint_stroke_set_mode_data(PaintStroke *stroke, std::unique_ptr< PaintModeData > mode_data)
static bool grease_pencil_fill_init(bContext &C, wmOperator &op)
void smooth_curve_attribute(const IndexMask &curves_to_smooth, const OffsetIndices< int > points_by_curve, const VArray< bool > &point_selection, const VArray< bool > &cyclic, int iterations, float influence, bool smooth_ends, bool keep_shape, GMutableSpan attribute_data)
bke::GeometrySet join_geometries(Span< bke::GeometrySet > geometries, const bke::AttributeFilter &attribute_filter, const std::optional< Span< bke::GeometryComponent::Type > > &component_types_to_join=std::nullopt)
T pow(const T &x, const T &power)
isect_result< VecBase< T, Size > > isect_seg_seg(const VecBase< T, Size > &v1, const VecBase< T, Size > &v2, const VecBase< T, Size > &v3, const VecBase< T, Size > &v4)
T distance(const T &a, const T &b)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T average(const VecBase< T, Size > &a)
T interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 4, 2 > float4x2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
BrushStrokeMode
@ BRUSH_STROKE_SMOOTH
@ BRUSH_STROKE_ERASE
void paint_stroke_operator_properties(wmOperatorType *ot)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
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_flag(PropertyRNA *prop, PropertyFlag flag)
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75
struct ARegionType * type
float no[3]
Definition BLI_kdopbvh.h:71
struct CurveMapping * curve_sensitivity
struct CurveMapping * curve_strength
struct CurveMapping * curve_jitter
struct CurveMapping * curve_rand_pressure
struct CurveMapping * curve_rand_strength
struct CurveMapping * curve_rand_saturation
struct CurveMapping * curve_rand_hue
struct CurveMapping * curve_rand_uv
struct Material * material
struct CurveMapping * curve_rand_value
char gpencil_sculpt_brush_type
char gpencil_weight_brush_type
struct BrushGpencilSettings * gpencil_settings
char gpencil_vertex_brush_type
char gpencil_brush_type
CurvesGeometry geometry
float loc[3]
float viewmat[4][4]
struct ToolSettings * toolsettings
struct RenderData r
View3D * v3d
Definition ED_view3d.hh:74
VecBase< T, 2 > xy() const
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
const bke::greasepencil::Drawing & drawing
struct blender::ed::greasepencil::ExtensionData::@205371017122172163221357243254300330236141263101 lines
struct blender::ed::greasepencil::ExtensionData::@370226035113122023045100175347052120024364305045 circles
Vector< ed::greasepencil::DrawingInfo > sources
static GreasePencilFillOpData from_context(bContext &C, blender::bke::greasepencil::Layer &layer, const int material_index, const bool invert, const bool precision)
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
int mval[2]
Definition WM_types.hh:728
wmTabletData tablet
Definition WM_types.hh:751
short type
Definition WM_types.hh:722
const void * modal_items
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_set(wmWindow *win, int curs)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_PAINT_BRUSH
Definition wm_cursors.hh:33
@ WM_CURSOR_EW_ARROW
Definition wm_cursors.hh:45
void WM_main_add_notifier(uint type, void *reference)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_TABLET_ERASER
@ EVT_MODAL_MAP
@ MOUSEMOVE
wmOperatorType * ot
Definition wm_files.cc:4125
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_toolsystem_active_tool_is_brush(const bContext *C)