Blender V5.0
grease_pencil_pen.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9
10#include "BKE_attribute.hh"
11#include "BKE_context.hh"
12#include "BKE_curves.hh"
13#include "BKE_curves_utils.hh"
14#include "BKE_deform.hh"
15#include "BKE_grease_pencil.hh"
16#include "BKE_material.hh"
17#include "BKE_report.hh"
18
19#include "BLI_array_utils.hh"
20
21#include "BLT_translation.hh"
22
23#include "WM_api.hh"
24#include "WM_types.hh"
25
26#include "RNA_access.hh"
27#include "RNA_define.hh"
28#include "RNA_enum_types.hh"
29
30#include "DEG_depsgraph.hh"
31
32#include "DNA_material_types.h"
33
34#include "ED_curves.hh"
35#include "ED_grease_pencil.hh"
36#include "ED_screen.hh"
37#include "ED_view3d.hh"
38
39#include "UI_resources.hh"
40
42
44 public:
47
48 /* Helper class to project screen space coordinates to 3D. */
50
51 float3 project(const float2 &screen_co) const
52 {
53 return this->placement.project(screen_co);
54 }
55
56 IndexMask all_selected_points(const int curves_index, IndexMaskMemory &memory) const
57 {
58 const MutableDrawingInfo &info = this->drawings[curves_index];
60 *this->vc.obact,
61 info.drawing,
62 info.layer_index,
63 this->vc.v3d->overlay.handle_display,
64 memory);
65 }
66
67 IndexMask visible_bezier_handle_points(const int curves_index, IndexMaskMemory &memory) const
68 {
69 const MutableDrawingInfo &info = this->drawings[curves_index];
71 *this->vc.obact,
72 info.drawing,
73 info.layer_index,
74 this->vc.v3d->overlay.handle_display,
75 memory);
76 }
77
78 IndexMask editable_curves(const int curves_index, IndexMaskMemory &memory) const
79 {
80 const MutableDrawingInfo &info = this->drawings[curves_index];
82 *this->vc.obact, info.drawing, info.layer_index, memory);
83 }
84
85 void tag_curve_changed(const int curves_index) const
86 {
87 const MutableDrawingInfo &info = this->drawings[curves_index];
89 }
90
91 bke::CurvesGeometry &get_curves(const int curves_index) const
92 {
93 const MutableDrawingInfo &info = this->drawings[curves_index];
94 return info.drawing.strokes_for_write();
95 }
96
98 {
99 return this->drawings.index_range();
100 }
101
102 void single_point_attributes(bke::CurvesGeometry &curves, const int curves_index) const
103 {
104 const MutableDrawingInfo &info = this->drawings[curves_index];
105 info.drawing.opacities_for_write().last() = 1.0f;
106 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
107
108 bke::SpanAttributeWriter<float> aspect_ratios = attributes.lookup_or_add_for_write_span<float>(
109 "aspect_ratio",
112 aspect_ratios.span.last() = 1.0f;
113 aspect_ratios.finish();
114
116 "u_scale",
119 u_scales.span.last() = 1.0f;
120 u_scales.finish();
121 }
122
124 {
125 if (!this->grease_pencil->has_active_layer()) {
126 BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
127 return false;
128 }
129
130 bke::greasepencil::Layer &layer = *this->grease_pencil->get_active_layer();
131 if (!layer.is_editable()) {
132 BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
133 return false;
134 }
135
136 const int material_index = this->vc.obact->actcol - 1;
137 Material *material = BKE_object_material_get(this->vc.obact, material_index + 1);
138 /* The editable materials are unlocked and not hidden. */
139 if (material != nullptr && material->gp_style != nullptr &&
140 ((material->gp_style->flag & GP_MATERIAL_LOCKED) != 0 ||
141 (material->gp_style->flag & GP_MATERIAL_HIDE) != 0))
142 {
143 BKE_report(op->reports, RPT_ERROR, "Active Material is locked or hidden");
144 return false;
145 }
146
147 /* Ensure a drawing at the current keyframe. */
148 bool inserted_keyframe = false;
150 *this->vc.scene, *this->grease_pencil, layer, false, inserted_keyframe))
151 {
152 BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
153 return false;
154 }
155
156 /* We should insert the keyframe when initializing not here. */
157 BLI_assert(!inserted_keyframe);
158 BLI_assert(this->active_drawing_index != std::nullopt);
159
160 return true;
161 }
162
163 void update_view(bContext *C) const
164 {
165 GreasePencil *grease_pencil = this->grease_pencil;
166
169
170 ED_region_tag_redraw(this->vc.region);
171 }
172
173 std::optional<wmOperatorStatus> initialize(bContext *C,
174 wmOperator *op,
175 const wmEvent * /*event*/)
176 {
177 if (this->vc.scene->toolsettings->gpencil_selectmode_edit != GP_SELECTMODE_POINT) {
178 BKE_report(op->reports, RPT_ERROR, "Selection Mode must be Points");
179 return OPERATOR_CANCELLED;
180 }
181
182 GreasePencil *grease_pencil = static_cast<GreasePencil *>(this->vc.obact->data);
183 this->grease_pencil = grease_pencil;
185
186 /* Initialize helper class for projecting screen space coordinates. */
188 *this->vc.region,
189 *view3d,
190 *this->vc.obact,
191 grease_pencil->get_active_layer());
192 if (placement.use_project_to_surface()) {
193 placement.cache_viewport_depths(CTX_data_depsgraph_pointer(C), this->vc.region, view3d);
194 }
195 else if (placement.use_project_to_stroke()) {
196 placement.cache_viewport_depths(CTX_data_depsgraph_pointer(C), this->vc.region, view3d);
197 }
198
199 bool inserted_keyframe = false;
200 /* For the pen tool, we don't want the auto-key to create an empty keyframe, so we
201 * duplicate the previous key. */
202 const bool use_duplicate_previous_key = true;
203 for (bke::greasepencil::Layer *layer : grease_pencil->layers_for_write()) {
204 if (layer->is_editable()) {
207 *layer,
208 use_duplicate_previous_key,
209 inserted_keyframe);
210 }
211 }
212
213 /* Update the view. */
214 if (inserted_keyframe) {
216 }
217
218 this->placement = placement;
219 this->drawings = retrieve_editable_drawings(*this->vc.scene, *this->grease_pencil);
220
221 for (const int drawing_index : this->drawings.index_range()) {
222 const MutableDrawingInfo &info = this->drawings[drawing_index];
223 const bke::greasepencil::Layer &layer = this->grease_pencil->layer(info.layer_index);
224 this->layer_to_object_per_curves.append(layer.local_transform());
225 this->layer_to_world_per_curves.append(layer.to_world_space(*this->vc.obact));
226 }
227
228 this->active_drawing_index = std::nullopt;
229 const bke::greasepencil::Layer *active_layer = this->grease_pencil->get_active_layer();
230
231 if (active_layer != nullptr) {
232 const bke::greasepencil::Drawing *active_drawing =
233 this->grease_pencil->get_editable_drawing_at(*active_layer, this->vc.scene->r.cfra);
234
235 for (const int drawing_index : this->drawings.index_range()) {
236 const MutableDrawingInfo &info = this->drawings[drawing_index];
237
238 if (active_drawing == &info.drawing) {
239 BLI_assert(this->active_drawing_index == std::nullopt);
240 this->active_drawing_index = drawing_index;
241 }
242 }
243 }
244
245 return std::nullopt;
246 }
247};
248
249/* Exit and free memory. */
251{
253
254 /* Clear status message area. */
255 ED_workspace_status_text(C, nullptr);
256
258
259 ptd->update_view(C);
260
261 MEM_delete(ptd);
262 /* Clear pointer. */
263 op->customdata = nullptr;
264}
265
266/* Invoke handler: Initialize the operator. */
268{
269 /* Allocate new data. */
270 GreasePencilPenToolOperation *ptd_pointer = MEM_new<GreasePencilPenToolOperation>(__func__);
271 op->customdata = ptd_pointer;
272 GreasePencilPenToolOperation &ptd = *ptd_pointer;
273
274 const wmOperatorStatus result = ptd.invoke(C, op, event);
277 }
278 return result;
279}
280
281/* Modal handler: Events handling during interactive part. */
283{
285 op->customdata);
286
287 const wmOperatorStatus result = ptd.modal(C, op, event);
290 }
291 return result;
292}
293
295{
296 /* Identifiers. */
297 ot->name = "Grease Pencil Pen";
298 ot->idname = "GREASE_PENCIL_OT_pen";
299 ot->description = "Construct and edit splines";
300
301 /* Callbacks. */
304
305 /* Flags. */
306 ot->flag = OPTYPE_UNDO;
307
308 /* Properties. */
310}
311
312} // namespace blender::ed::greasepencil
313
318
320{
322 WM_modalkeymap_assign(keymap, "GREASE_PENCIL_OT_pen");
323}
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
Low-level operations for curves.
Low-level operations for curves.
support for deformation groups and hooks.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ GP_MATERIAL_LOCKED
@ GP_MATERIAL_HIDE
@ GP_SELECTMODE_POINT
@ OPERATOR_CANCELLED
@ OPERATOR_RUNNING_MODAL
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
#define NA_EDITED
Definition WM_types.hh:584
#define NC_GPENCIL
Definition WM_types.hh:399
constexpr T & last(const int64_t n=0) const
Definition BLI_span.hh:689
static VArray from_single(T value, const int64_t size)
IndexRange index_range() const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
MutableSpan< float > opacities_for_write()
bke::CurvesGeometry & strokes_for_write()
float4x4 to_world_space(const Object &object) const
wmOperatorStatus invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmOperatorStatus modal(bContext *C, wmOperator *op, const wmEvent *event)
float3 project(float2 co, bool &clipped) const
IndexMask visible_bezier_handle_points(const int curves_index, IndexMaskMemory &memory) const
void single_point_attributes(bke::CurvesGeometry &curves, const int curves_index) const
IndexMask all_selected_points(const int curves_index, IndexMaskMemory &memory) const
bke::CurvesGeometry & get_curves(const int curves_index) const
std::optional< wmOperatorStatus > initialize(bContext *C, wmOperator *op, const wmEvent *)
IndexMask editable_curves(const int curves_index, IndexMaskMemory &memory) const
void ED_operatortypes_grease_pencil_pen()
void ED_grease_pencil_pentool_modal_keymap(wmKeyConfig *keyconf)
void pen_tool_common_props(wmOperatorType *ot)
wmKeyMap * ensure_keymap(wmKeyConfig *keyconf)
IndexMask retrieve_visible_bezier_handle_points(Object &object, const bke::greasepencil::Drawing &drawing, const int layer_index, const int handle_display, IndexMaskMemory &memory)
bool ensure_active_keyframe(const Scene &scene, GreasePencil &grease_pencil, bke::greasepencil::Layer &layer, const bool duplicate_previous_key, bool &r_inserted_keyframe)
IndexMask retrieve_editable_and_all_selected_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, int handle_display, IndexMaskMemory &memory)
static void grease_pencil_pen_exit(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_pen(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
IndexMask retrieve_editable_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
static wmOperatorStatus grease_pencil_pen_invoke(bContext *C, wmOperator *op, const wmEvent *event)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
struct MaterialGPencilStyle * gp_style
wmWindow * win
Definition ED_view3d.hh:79
struct ReportList * reports
void WM_cursor_modal_restore(wmWindow *win)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))