Blender V4.5
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
13#include "DNA_brush_enums.h"
14#include "DNA_brush_types.h"
15
16#include "GEO_smooth_curves.hh"
17
18#include "ED_grease_pencil.hh"
19#include "ED_view3d.hh"
20
21#include "WM_api.hh"
22#include "WM_types.hh"
23
25#include "paint_intern.hh"
26
28
30 private:
31 bool temp_smooth_;
32
33 /* Used when temporarily switching to smooth brush, save the previous active brush. */
34 Brush *saved_active_brush_;
35 char saved_mask_brush_tool_;
36 int saved_smooth_size_; /* Smooth tool copies the size of the current tool. */
37
38 void toggle_smooth_brush_on(const bContext &C);
39 void toggle_smooth_brush_off(const bContext &C);
40
41 public:
43
44 SmoothOperation(const BrushStrokeMode stroke_mode, const bool temp_smooth = false)
45 : GreasePencilStrokeOperationCommon(stroke_mode), temp_smooth_(temp_smooth)
46 {
47 }
48
49 void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
50 void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
51 void on_stroke_done(const bContext &C) override;
52};
53
54void SmoothOperation::toggle_smooth_brush_on(const bContext &C)
55{
57 Main *bmain = CTX_data_main(&C);
58 Scene *scene = CTX_data_scene(&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(scene, smooth_brush);
76
77 const int current_brush_size = BKE_brush_size_get(scene, current_brush);
78 BKE_brush_size_set(scene, smooth_brush, current_brush_size);
79 BKE_curvemapping_init(smooth_brush->curve);
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 Scene *scene = CTX_data_scene(&C);
96 BKE_brush_size_set(scene, &brush, saved_smooth_size_);
97 BKE_paint_brush_set(paint, saved_active_brush_);
98 saved_active_brush_ = nullptr;
99 }
100}
101
103{
104 if (temp_smooth_) {
105 toggle_smooth_brush_on(C);
106 this->start_mouse_position = start_sample.mouse_position;
107 this->prev_mouse_position = start_sample.mouse_position;
108 }
109 else {
110 this->init_stroke(C, start_sample);
111 }
112 this->init_auto_masking(C, start_sample);
113}
114
115void SmoothOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
116{
117 const Scene &scene = *CTX_data_scene(&C);
118 const Brush &brush = [&]() -> const Brush & {
119 if (temp_smooth_) {
122 BLI_assert(brush != nullptr);
123 return *brush;
124 }
126 return *BKE_paint_brush(&paint);
127 }();
128 const int sculpt_mode_flag = brush.gpencil_settings->sculpt_mode_flag;
129
131 C, [&](const GreasePencilStrokeParams &params, const IndexMask &point_mask) {
132 Array<float2> view_positions = calculate_view_positions(params, point_mask);
133 bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
134 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
135 const OffsetIndices points_by_curve = curves.points_by_curve();
136 const VArray<bool> cyclic = curves.cyclic();
137 const int iterations = 2;
138
139 const VArray<float> influences = VArray<float>::ForFunc(
140 view_positions.size(), [&](const int64_t point_) {
141 return brush_point_influence(scene,
142 brush,
143 view_positions[point_],
144 extension_sample,
145 params.multi_frame_falloff);
146 });
147 Array<bool> selection_array(curves.points_num());
148 point_mask.to_bools(selection_array);
149 const VArray<bool> selection_varray = VArray<bool>::ForSpan(selection_array);
150
151 bool changed = false;
152 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
154 curves.curves_range(),
155 selection_varray,
156 iterations,
157 influences,
158 false,
159 false);
160
161 params.drawing.tag_positions_changed();
162 changed = true;
163 }
164 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
165 MutableSpan<float> opacities = params.drawing.opacities_for_write();
167 points_by_curve,
168 selection_varray,
169 cyclic,
170 iterations,
171 influences,
172 true,
173 false,
174 opacities);
175 changed = true;
176 }
177 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) {
178 const MutableSpan<float> radii = params.drawing.radii_for_write();
180 points_by_curve,
181 selection_varray,
182 cyclic,
183 iterations,
184 influences,
185 true,
186 false,
187 radii);
188 curves.tag_radii_changed();
189 changed = true;
190 }
191 if (sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) {
192 if (bke::SpanAttributeWriter<float> rotations =
193 attributes.lookup_or_add_for_write_span<float>("rotation",
195 {
197 points_by_curve,
198 selection_varray,
199 cyclic,
200 iterations,
201 influences,
202 true,
203 false,
204 rotations.span);
205 rotations.finish();
206 changed = true;
207 }
208 }
209 return changed;
210 });
211 this->stroke_extended(extension_sample);
212}
213
215{
216 if (temp_smooth_) {
217 toggle_smooth_brush_off(C);
218 }
219}
220
221std::unique_ptr<GreasePencilStrokeOperation> new_smooth_operation(
222 const BrushStrokeMode stroke_mode, const bool temp_smooth)
223{
224 return std::make_unique<SmoothOperation>(stroke_mode, temp_smooth);
225}
226
227} // namespace blender::ed::sculpt_paint::greasepencil
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1210
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
Definition brush.cc:1194
void BKE_curvemapping_init(CurveMapping *cumap)
Scene * CTX_data_scene(const bContext *C)
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:1089
bool BKE_paint_brush_set(Paint *paint, Brush *brush)
Definition paint.cc:701
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:467
Brush * BKE_paint_brush_from_essentials(Main *bmain, eObjectMode ob_mode, const char *name)
Definition paint.cc:776
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
#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
@ OB_MODE_SCULPT_GREASE_PENCIL
#define C
Definition RandGen.cpp:29
long long int int64_t
int64_t size() const
Definition BLI_array.hh:245
static VArray ForSpan(Span< T > values)
static VArray ForFunc(const int64_t size, GetFunc get_func)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType 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
struct BrushGpencilSettings * gpencil_settings
char mask_tool