Blender V4.5
grease_pencil/intern/grease_pencil_vertex_paint.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
8
9#include "BKE_brush.hh"
10#include "BKE_context.hh"
11#include "BKE_curves.hh"
12#include "BKE_grease_pencil.hh"
13#include "BKE_paint.hh"
14
15#include "DEG_depsgraph.hh"
16
17#include "RNA_access.hh"
18#include "RNA_define.hh"
19
20#include "ED_curves.hh"
21#include "ED_grease_pencil.hh"
22
24
26
27enum class VertexColorMode : int8_t {
28 Stroke = 0,
29 Fill = 1,
30 Both = 2,
31};
32
34 {int(VertexColorMode::Stroke), "STROKE", 0, "Stroke", ""},
35 {int(VertexColorMode::Fill), "FILL", 0, "Fill", ""},
36 {int(VertexColorMode::Both), "BOTH", 0, "Stroke & Fill", ""},
37 {0, nullptr, 0, nullptr, nullptr},
38};
39
40template<typename Fn>
42 Object &object,
44 const bool use_selection_mask,
45 Fn &&fn)
46{
47 bool changed = false;
48 IndexMaskMemory memory;
49 using namespace ed::greasepencil;
51 if (info.drawing.strokes().attributes().contains("vertex_color")) {
52 const IndexMask points = use_selection_mask ?
54 object, info.drawing, info.layer_index, memory) :
56 object, info.drawing, info.layer_index, memory);
57 if (!points.is_empty()) {
59 points.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
60 ColorGeometry4f &color = vertex_colors[point_i];
61 if (color.a > 0.0f) {
62 color = fn(color);
63 }
64 });
65 changed = true;
66 }
67 }
68 }
70 if (info.drawing.strokes().attributes().contains("fill_color")) {
71 const IndexMask strokes = use_selection_mask ?
73 object, info.drawing, info.layer_index, memory) :
75 object, info.drawing, info.layer_index, memory);
76 if (!strokes.is_empty()) {
78 strokes.foreach_index(GrainSize(1024), [&](const int64_t curve_i) {
79 ColorGeometry4f &color = fill_colors[curve_i];
80 if (color.a > 0.0f) {
81 color = fn(color);
82 }
83 });
84 changed = true;
85 }
86 }
87 }
88 return changed;
89}
90
92 wmOperator *op)
93{
94 const Scene &scene = *CTX_data_scene(C);
96 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
97 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
98 const float brightness = RNA_float_get(op->ptr, "brightness");
99 const float contrast = RNA_float_get(op->ptr, "contrast");
100 float delta = contrast / 2.0f;
101 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
103
104 /*
105 * The algorithm is by Werner D. Streidt
106 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
107 * Extracted of OpenCV `demhist.c`.
108 */
109 float gain, offset;
110 if (contrast > 0.0f) {
111 gain = 1.0f - delta * 2.0f;
112 gain = 1.0f / math::max(gain, FLT_EPSILON);
113 offset = gain * (brightness - delta);
114 }
115 else {
116 delta *= -1.0f;
117 gain = math::max(1.0f - delta * 2.0f, 0.0f);
118 offset = gain * brightness + delta;
119 }
120
121 std::atomic<bool> any_changed;
122 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
125 if (curves.is_empty()) {
126 return;
127 }
128 const bool changed = apply_color_operation_for_mode(
129 mode,
130 object,
131 info,
132 use_selection_mask,
133 [&](const ColorGeometry4f &color) -> ColorGeometry4f {
134 const float3 result = float3(color) * gain + offset;
135 return ColorGeometry4f(result[0], result[1], result[2], color.a);
136 });
137 any_changed.store(any_changed | changed, std::memory_order_relaxed);
138 });
139
140 if (any_changed) {
141 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
142 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
143 }
144 return OPERATOR_FINISHED;
145}
146
148{
149 /* identifiers */
150 ot->name = "Vertex Paint Brightness/Contrast";
151 ot->idname = "GREASE_PENCIL_OT_vertex_color_brightness_contrast";
152 ot->description = "Adjust vertex color brightness/contrast";
153
154 /* API callbacks. */
157
158 /* flags */
160
161 /* params */
162 ot->prop = RNA_def_enum(
163 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
164
165 RNA_def_float(ot->srna, "brightness", 0.0f, -1.0f, 1.0f, "Brightness", "", -1.0f, 1.0f);
166 RNA_def_float(ot->srna, "contrast", 0.0f, -1.0f, 1.0f, "Contrast", "", -1.0f, 1.0f);
167}
168
170{
171 const Scene &scene = *CTX_data_scene(C);
172 Object &object = *CTX_data_active_object(C);
173 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
174 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
175 const float hue = RNA_float_get(op->ptr, "h");
176 const float sat = RNA_float_get(op->ptr, "s");
177 const float val = RNA_float_get(op->ptr, "v");
178 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
180
181 std::atomic<bool> any_changed;
182 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
185 if (curves.is_empty()) {
186 return;
187 }
188 const bool changed = apply_color_operation_for_mode(
189 mode,
190 object,
191 info,
192 use_selection_mask,
193 [&](const ColorGeometry4f &color) -> ColorGeometry4f {
194 float3 hsv;
196
197 hsv[0] += (hue - 0.5f);
198 if (hsv[0] > 1.0f) {
199 hsv[0] -= 1.0f;
200 }
201 else if (hsv[0] < 0.0f) {
202 hsv[0] += 1.0f;
203 }
204 hsv[1] *= sat;
205 hsv[2] *= val;
206
207 float3 rgb_result;
208 hsv_to_rgb_v(hsv, rgb_result);
209 return ColorGeometry4f(rgb_result[0], rgb_result[1], rgb_result[2], color.a);
210 });
211 any_changed.store(any_changed | changed, std::memory_order_relaxed);
212 });
213
214 if (any_changed) {
215 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
216 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
217 }
218 return OPERATOR_FINISHED;
219}
220
222{
223 /* identifiers */
224 ot->name = "Vertex Paint Hue/Saturation/Value";
225 ot->idname = "GREASE_PENCIL_OT_vertex_color_hsv";
226 ot->description = "Adjust vertex color HSV values";
227
228 /* API callbacks. */
231
232 /* flags */
234
235 /* params */
236 ot->prop = RNA_def_enum(
237 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
238 RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
239 RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
240 RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
241}
242
244{
245 const Scene &scene = *CTX_data_scene(C);
246 Object &object = *CTX_data_active_object(C);
247 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
248 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
249 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
251
252 std::atomic<bool> any_changed;
253 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
256 if (curves.is_empty()) {
257 return;
258 }
259 const bool changed = apply_color_operation_for_mode(
260 mode,
261 object,
262 info,
263 use_selection_mask,
264 [&](const ColorGeometry4f &color) -> ColorGeometry4f {
265 /* Invert the color. */
266 return ColorGeometry4f(1.0f - color.r, 1.0f - color.g, 1.0f - color.b, color.a);
267 });
268 any_changed.store(any_changed | changed, std::memory_order_relaxed);
269 });
270
271 if (any_changed) {
272 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
273 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
274 }
275 return OPERATOR_FINISHED;
276}
277
279{
280 /* identifiers */
281 ot->name = "Vertex Paint Invert";
282 ot->idname = "GREASE_PENCIL_OT_vertex_color_invert";
283 ot->description = "Invert RGB values";
284
285 /* API callbacks. */
288
289 /* flags */
291
292 /* params */
293 ot->prop = RNA_def_enum(
294 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
295}
296
298{
299 const Scene &scene = *CTX_data_scene(C);
300 Object &object = *CTX_data_active_object(C);
301 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
302 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
303 const float gain = RNA_float_get(op->ptr, "gain");
304 const float offset = RNA_float_get(op->ptr, "offset");
305 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
307
308 std::atomic<bool> any_changed;
309 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
312 if (curves.is_empty()) {
313 return;
314 }
315 const bool changed = apply_color_operation_for_mode(
316 mode,
317 object,
318 info,
319 use_selection_mask,
320 [&](const ColorGeometry4f &color) -> ColorGeometry4f {
321 const float3 result = float3(color) * gain + offset;
322 return ColorGeometry4f(result[0], result[1], result[2], color.a);
323 });
324 any_changed.store(any_changed | changed, std::memory_order_relaxed);
325 });
326
327 if (any_changed) {
328 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
329 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
330 }
331 return OPERATOR_FINISHED;
332}
333
335{
336 /* identifiers */
337 ot->name = "Vertex Paint Levels";
338 ot->idname = "GREASE_PENCIL_OT_vertex_color_levels";
339 ot->description = "Adjust levels of vertex colors";
340
341 /* API callbacks. */
344
345 /* flags */
347
348 /* params */
349 ot->prop = RNA_def_enum(
350 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
351
353 ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
355 ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
356}
357
359{
360 const Scene &scene = *CTX_data_scene(C);
361 Object &object = *CTX_data_active_object(C);
363 const Brush &brush = *BKE_paint_brush(&paint);
364 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
365 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
366 const float factor = RNA_float_get(op->ptr, "factor");
367 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
369
370 float3 color_linear;
371 srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(&scene, &paint, &brush));
372 const ColorGeometry4f target_color(color_linear[0], color_linear[1], color_linear[2], 1.0f);
373
374 std::atomic<bool> any_changed;
375 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
378 if (curves.is_empty()) {
379 return;
380 }
381 /* Create the color attributes if they don't exist. */
383 curves.attributes_for_write().add<ColorGeometry4f>(
385 }
387 curves.attributes_for_write().add<ColorGeometry4f>(
389 }
390 const bool changed = apply_color_operation_for_mode(
391 mode,
392 object,
393 info,
394 use_selection_mask,
395 [&](const ColorGeometry4f &color) -> ColorGeometry4f {
396 /* Mix in the target color based on the factor. */
397 return math::interpolate(color, target_color, factor);
398 });
399 any_changed.store(any_changed | changed, std::memory_order_relaxed);
400 });
401
402 if (any_changed) {
403 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
404 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
405 }
406 return OPERATOR_FINISHED;
407}
408
410{
411 /* identifiers */
412 ot->name = "Vertex Paint Set Color";
413 ot->idname = "GREASE_PENCIL_OT_vertex_color_set";
414 ot->description = "Set active color to all selected vertex";
415
416 /* API callbacks. */
419
420 /* flags */
422
423 /* params */
424 ot->prop = RNA_def_enum(
425 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
426 RNA_def_float(ot->srna, "factor", 1.0f, 0.0f, 1.0f, "Factor", "Mix Factor", 0.0f, 1.0f);
427}
428
430{
431 const Scene &scene = *CTX_data_scene(C);
432 Object &object = *CTX_data_active_object(C);
433 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
434 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
435 const bool use_selection_mask = GPENCIL_ANY_VERTEX_MASK(
437
438 std::atomic<bool> any_changed;
439 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
442 if (curves.is_empty()) {
443 return;
444 }
445
446 bool changed = false;
447 if (use_selection_mask) {
449 mode,
450 object,
451 info,
452 use_selection_mask,
453 [&](const ColorGeometry4f & /*color*/) -> ColorGeometry4f {
454 return ColorGeometry4f(1.0, 1.0, 1.0, 1.0);
455 });
456 any_changed.store(any_changed | changed, std::memory_order_relaxed);
457 return;
458 }
459
460 /* Remove the color attributes. */
462 changed |= curves.attributes_for_write().remove("vertex_color");
463 }
465 changed |= curves.attributes_for_write().remove("fill_color");
466 }
467 any_changed.store(any_changed | changed, std::memory_order_relaxed);
468 });
469
470 if (any_changed) {
471 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
472 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
473 }
474 return OPERATOR_FINISHED;
475}
476
478{
479 /* identifiers */
480 ot->name = "Reset Vertex Color";
481 ot->idname = "GREASE_PENCIL_OT_stroke_reset_vertex_color";
482 ot->description = "Reset vertex color for all or selected strokes";
483
484 /* callbacks */
487
488 /* flags */
490
491 /* properties */
492 ot->prop = RNA_def_enum(
493 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
494}
495
496} // namespace blender::ed::greasepencil
497
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1128
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:467
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:636
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
#define GPENCIL_ANY_VERTEX_MASK(flag)
eGP_vertex_SelectMaskFlag
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_DATA
Definition WM_types.hh:506
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
long long int int64_t
bool contains(StringRef attribute_id) const
AttributeAccessor attributes() const
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
MutableSpan< ColorGeometry4f > fill_colors_for_write()
MutableSpan< ColorGeometry4f > vertex_colors_for_write()
void foreach_index(Fn &&fn) const
IndexMask retrieve_editable_and_selected_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask retrieve_editable_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
static void GREASE_PENCIL_OT_vertex_color_levels(wmOperatorType *ot)
bool grease_pencil_vertex_painting_poll(bContext *C)
static wmOperatorStatus grease_pencil_vertex_paint_set_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_vertex_paint_invert_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_vertex_paint_hsv_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_vertex_paint_brightness_contrast_exec(bContext *C, wmOperator *op)
IndexMask retrieve_editable_and_selected_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
static void GREASE_PENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
static void GREASE_PENCIL_OT_vertex_color_set(wmOperatorType *ot)
static wmOperatorStatus grease_pencil_vertex_paint_reset_exec(bContext *C, wmOperator *op)
static wmOperatorStatus grease_pencil_vertex_paint_levels_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_vertex_color_invert(wmOperatorType *ot)
static void GREASE_PENCIL_OT_vertex_color_hsv(wmOperatorType *ot)
static bool apply_color_operation_for_mode(const VertexColorMode mode, Object &object, MutableDrawingInfo &info, const bool use_selection_mask, Fn &&fn)
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)
T interpolate(const T &a, const T &b, const FactorT &t)
T max(const T &a, const T &b)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
VecBase< float, 3 > float3
float RNA_float_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
#define FLT_MAX
Definition stdcycles.h:14
struct ToolSettings * toolsettings
char gpencil_selectmode_vertex
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4226
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))