Blender V5.0
grease_pencil_sculpt_smooth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_attribute.hh"
6#include "BKE_brush.hh"
7#include "BKE_colortools.hh"
8#include "BKE_context.hh"
9#include "BKE_curves.hh"
10#include "BKE_grease_pencil.hh"
11#include "BKE_paint.hh"
12#include "BKE_paint_types.hh"
13
14#include "DNA_brush_enums.h"
15#include "DNA_brush_types.h"
16
17#include "GEO_smooth_curves.hh"
18
19#include "ED_grease_pencil.hh"
20#include "ED_view3d.hh"
21
22#include "WM_api.hh"
23#include "WM_types.hh"
24
26#include "paint_intern.hh"
27
29
31 private:
32 bool temp_smooth_;
33
34 /* Used when temporarily switching to smooth brush, save the previous active brush. */
35 Brush *saved_active_brush_;
36 char saved_mask_brush_tool_;
37 int saved_smooth_size_; /* Smooth tool copies the size of the current tool. */
38
39 void toggle_smooth_brush_on(const bContext &C);
40 void toggle_smooth_brush_off(const bContext &C);
41
42 public:
44
45 SmoothOperation(const BrushStrokeMode stroke_mode, const bool temp_smooth = false)
46 : GreasePencilStrokeOperationCommon(stroke_mode), temp_smooth_(temp_smooth)
47 {
48 }
49
50 void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
51 void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
52 void on_stroke_done(const bContext &C) override;
53};
54
55void SmoothOperation::toggle_smooth_brush_on(const bContext &C)
56{
58 Main *bmain = CTX_data_main(&C);
59 Brush *current_brush = BKE_paint_brush(paint);
60
61 if (current_brush->sculpt_brush_type == SCULPT_BRUSH_TYPE_MASK) {
62 saved_mask_brush_tool_ = current_brush->mask_tool;
63 current_brush->mask_tool = BRUSH_MASK_SMOOTH;
64 return;
65 }
66
67 /* Switch to the smooth brush if possible. */
68 BKE_paint_brush_set_essentials(bmain, paint, "Smooth");
69 Brush *smooth_brush = BKE_paint_brush(paint);
70 BLI_assert(smooth_brush != nullptr);
71
72 init_brush(*smooth_brush);
73
74 saved_active_brush_ = current_brush;
75 saved_smooth_size_ = BKE_brush_size_get(paint, smooth_brush);
76
77 const int current_brush_size = BKE_brush_size_get(paint, current_brush);
78 BKE_brush_size_set(paint, smooth_brush, current_brush_size);
80}
81
82void SmoothOperation::toggle_smooth_brush_off(const bContext &C)
83{
85 Brush &brush = *BKE_paint_brush(paint);
86
88 brush.mask_tool = saved_mask_brush_tool_;
89 return;
90 }
91
92 /* If saved_active_brush is not set, brush was not switched/affected in
93 * toggle_temp_on(). */
94 if (saved_active_brush_) {
95 BKE_brush_size_set(paint, &brush, saved_smooth_size_);
96 BKE_paint_brush_set(paint, saved_active_brush_);
97 saved_active_brush_ = nullptr;
98 }
99}
100
102{
103 if (temp_smooth_) {
104 toggle_smooth_brush_on(C);
105 this->start_mouse_position = start_sample.mouse_position;
106 this->prev_mouse_position = start_sample.mouse_position;
107 }
108 else {
109 this->init_stroke(C, start_sample);
110 }
111 this->init_auto_masking(C, start_sample);
112}
113
114void SmoothOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
115{
117 const Brush &brush = [&]() -> const Brush & {
118 if (temp_smooth_) {
121 BLI_assert(brush != nullptr);
122 return *brush;
123 }
124 return *BKE_paint_brush(&paint);
125 }();
126 const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
127
129 C, [&](const GreasePencilStrokeParams &params, const IndexMask &point_mask) {
130 Array<float2> view_positions = calculate_view_positions(params, point_mask);
131 bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
132 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
133 const OffsetIndices points_by_curve = curves.points_by_curve();
134 const VArray<bool> cyclic = curves.cyclic();
135 const int iterations = 2;
136
137 const VArray<float> influences = VArray<float>::from_func(
138 view_positions.size(), [&](const int64_t point_) {
139 return brush_point_influence(paint,
140 brush,
141 view_positions[point_],
142 extension_sample,
143 params.multi_frame_falloff);
144 });
145 Array<bool> selection_array(curves.points_num());
146 point_mask.to_bools(selection_array);
147 const VArray<bool> selection_varray = VArray<bool>::from_span(selection_array);
148
149 bool changed = false;
150 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
152 curves.curves_range(),
153 selection_varray,
154 iterations,
155 influences,
156 false,
157 false);
158
159 params.drawing.tag_positions_changed();
160 changed = true;
161 }
162 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
163 MutableSpan<float> opacities = params.drawing.opacities_for_write();
165 points_by_curve,
166 selection_varray,
167 cyclic,
168 iterations,
169 influences,
170 true,
171 false,
172 opacities);
173 changed = true;
174 }
175 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
176 const MutableSpan<float> radii = params.drawing.radii_for_write();
178 points_by_curve,
179 selection_varray,
180 cyclic,
181 iterations,
182 influences,
183 true,
184 false,
185 radii);
186 curves.tag_radii_changed();
187 changed = true;
188 }
189 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
190 if (bke::SpanAttributeWriter<float> rotations =
191 attributes.lookup_or_add_for_write_span<float>("rotation",
193 {
195 points_by_curve,
196 selection_varray,
197 cyclic,
198 iterations,
199 influences,
200 true,
201 false,
202 rotations.span);
203 rotations.finish();
204 changed = true;
205 }
206 }
207 return changed;
208 });
209 this->stroke_extended(extension_sample);
210}
211
213{
214 if (temp_smooth_) {
215 toggle_smooth_brush_off(C);
216 }
217}
218
219std::unique_ptr<GreasePencilStrokeOperation> new_smooth_operation(
220 const BrushStrokeMode stroke_mode, const bool temp_smooth)
221{
222 return std::make_unique<SmoothOperation>(stroke_mode, temp_smooth);
223}
224
225} // namespace blender::ed::sculpt_paint::greasepencil
void BKE_brush_size_set(Paint *paint, Brush *brush, int size)
Definition brush.cc:1248
int BKE_brush_size_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1264
void BKE_curvemapping_init(CurveMapping *cumap)
Main * CTX_data_main(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
bool BKE_paint_brush_set_essentials(Main *bmain, Paint *paint, const char *name)
Definition paint.cc:1105
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:710
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:476
Brush * BKE_paint_brush_from_essentials(Main *bmain, PaintMode paint_mode, const char *name)
Definition paint.cc:791
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
#define BLI_assert(a)
Definition BLI_assert.h:46
@ GP_SCULPT_FLAGMODE_APPLY_UV
@ GP_SCULPT_FLAGMODE_APPLY_POSITION
@ GP_SCULPT_FLAGMODE_APPLY_THICKNESS
@ GP_SCULPT_FLAGMODE_APPLY_STRENGTH
@ SCULPT_BRUSH_TYPE_MASK
@ BRUSH_MASK_SMOOTH
#define C
Definition RandGen.cpp:29
long long int int64_t
int64_t size() const
Definition BLI_array.hh:256
static VArray from_func(const int64_t size, GetFunc get_func)
static VArray from_span(Span< T > values)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
void foreach_editable_drawing_with_automask(const bContext &C, FunctionRef< bool(const GreasePencilStrokeParams &params, const IndexMask &points)> fn) const
void init_auto_masking(const bContext &C, const InputSample &start_sample)
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override
SmoothOperation(const BrushStrokeMode stroke_mode, const bool temp_smooth=false)
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override
void to_bools(MutableSpan< bool > r_bools) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Array< float2 > calculate_view_positions(const GreasePencilStrokeParams &params, const IndexMask &selection)
std::unique_ptr< CurvesSculptStrokeOperation > new_smooth_operation()
void smooth_curve_positions(bke::CurvesGeometry &curves, const IndexMask &curves_to_smooth, const VArray< bool > &point_selection, int iterations, const VArray< float > &influence_by_point, bool smooth_ends, bool keep_shape)
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)
BrushStrokeMode
char sculpt_brush_type
struct CurveMapping * curve_distance_falloff
struct BrushGpencilSettings * gpencil_settings
char mask_tool