Blender V4.3
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
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#include "BKE_report.hh"
15
17
18#include "RNA_access.hh"
19#include "RNA_define.hh"
20
21#include "ED_curves.hh"
22#include "ED_grease_pencil.hh"
23
25
26enum class VertexColorMode : int8_t {
27 Stroke = 0,
28 Fill = 1,
29 Both = 2,
30};
31
33 {int(VertexColorMode::Stroke), "STROKE", 0, "Stroke", ""},
34 {int(VertexColorMode::Fill), "FILL", 0, "Fill", ""},
35 {int(VertexColorMode::Both), "BOTH", 0, "Stroke & Fill", ""},
36 {0, nullptr, 0, nullptr, nullptr},
37};
38
39template<typename Fn>
41 Object &object,
43 Fn &&fn)
44{
45 bool changed = false;
46 IndexMaskMemory memory;
48 if (info.drawing.strokes().attributes().contains("vertex_color")) {
50 object, info.drawing, info.layer_index, memory);
51 if (!points.is_empty()) {
53 points.foreach_index(GrainSize(4096), [&](const int64_t point_i) {
54 ColorGeometry4f &color = vertex_colors[point_i];
55 if (color.a > 0.0f) {
56 color = fn(color);
57 }
58 });
59 changed = true;
60 }
61 }
62 }
64 if (info.drawing.strokes().attributes().contains("fill_color")) {
66 object, info.drawing, info.layer_index, memory);
67 if (!strokes.is_empty()) {
69 strokes.foreach_index(GrainSize(1024), [&](const int64_t curve_i) {
70 ColorGeometry4f &color = fill_colors[curve_i];
71 if (color.a > 0.0f) {
72 color = fn(color);
73 }
74 });
75 changed = true;
76 }
77 }
78 }
79 return changed;
80}
81
83{
84 const Scene &scene = *CTX_data_scene(C);
85 Object &object = *CTX_data_active_object(C);
86 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
87 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
88 const float brightness = RNA_float_get(op->ptr, "brightness");
89 const float contrast = RNA_float_get(op->ptr, "contrast");
90 float delta = contrast / 2.0f;
91 /*
92 * The algorithm is by Werner D. Streidt
93 * (http://visca.com/ffactory/archives/5-99/msg00021.html)
94 * Extracted of OpenCV `demhist.c`.
95 */
96 float gain, offset;
97 if (contrast > 0.0f) {
98 gain = 1.0f - delta * 2.0f;
99 gain = 1.0f / math::max(gain, FLT_EPSILON);
100 offset = gain * (brightness - delta);
101 }
102 else {
103 delta *= -1.0f;
104 gain = math::max(1.0f - delta * 2.0f, 0.0f);
105 offset = gain * brightness + delta;
106 }
107
108 std::atomic<bool> any_changed;
109 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
112 if (curves.curves_num() == 0) {
113 return;
114 }
115 const bool changed = apply_color_operation_for_mode(
116 mode, object, info, [&](const ColorGeometry4f &color) -> ColorGeometry4f {
117 const float3 result = float3(color) * gain + offset;
118 return ColorGeometry4f(result[0], result[1], result[2], color.a);
119 });
120 any_changed.store(any_changed | changed, std::memory_order_relaxed);
121 });
122
123 if (any_changed) {
124 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
125 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
126 }
127 return OPERATOR_FINISHED;
128}
129
131{
132 /* identifiers */
133 ot->name = "Vertex Paint Brightness/Contrast";
134 ot->idname = "GREASE_PENCIL_OT_vertex_color_brightness_contrast";
135 ot->description = "Adjust vertex color brightness/contrast";
136
137 /* api callbacks */
140
141 /* flags */
143
144 /* params */
146 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
147
148 RNA_def_float(ot->srna, "brightness", 0.0f, -1.0f, 1.0f, "Brightness", "", -1.0f, 1.0f);
149 RNA_def_float(ot->srna, "contrast", 0.0f, -1.0f, 1.0f, "Contrast", "", -1.0f, 1.0f);
150}
151
153{
154 const Scene &scene = *CTX_data_scene(C);
155 Object &object = *CTX_data_active_object(C);
156 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
157 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
158 const float hue = RNA_float_get(op->ptr, "h");
159 const float sat = RNA_float_get(op->ptr, "s");
160 const float val = RNA_float_get(op->ptr, "v");
161
162 std::atomic<bool> any_changed;
163 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
166 if (curves.curves_num() == 0) {
167 return;
168 }
169 const bool changed = apply_color_operation_for_mode(
170 mode, object, info, [&](const ColorGeometry4f &color) -> ColorGeometry4f {
171 float3 hsv;
172 rgb_to_hsv_v(float3(color), hsv);
173
174 hsv[0] += (hue - 0.5f);
175 if (hsv[0] > 1.0f) {
176 hsv[0] -= 1.0f;
177 }
178 else if (hsv[0] < 0.0f) {
179 hsv[0] += 1.0f;
180 }
181 hsv[1] *= sat;
182 hsv[2] *= val;
183
184 float3 rgb_result;
185 hsv_to_rgb_v(hsv, rgb_result);
186 return ColorGeometry4f(rgb_result[0], rgb_result[1], rgb_result[2], color.a);
187 });
188 any_changed.store(any_changed | changed, std::memory_order_relaxed);
189 });
190
191 if (any_changed) {
192 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
193 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
194 }
195 return OPERATOR_FINISHED;
196}
197
199{
200 /* identifiers */
201 ot->name = "Vertex Paint Hue/Saturation/Value";
202 ot->idname = "GREASE_PENCIL_OT_vertex_color_hsv";
203 ot->description = "Adjust vertex color HSV values";
204
205 /* api callbacks */
208
209 /* flags */
211
212 /* params */
214 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
215 RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
216 RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
217 RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
218}
219
221{
222 const Scene &scene = *CTX_data_scene(C);
223 Object &object = *CTX_data_active_object(C);
224 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
225 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
226
227 std::atomic<bool> any_changed;
228 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
231 if (curves.curves_num() == 0) {
232 return;
233 }
234 const bool changed = apply_color_operation_for_mode(
235 mode, object, info, [&](const ColorGeometry4f &color) -> ColorGeometry4f {
236 /* Invert the color. */
237 return ColorGeometry4f(1.0f - color.r, 1.0f - color.g, 1.0f - color.b, color.a);
238 });
239 any_changed.store(any_changed | changed, std::memory_order_relaxed);
240 });
241
242 if (any_changed) {
243 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
244 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
245 }
246 return OPERATOR_FINISHED;
247}
248
250{
251 /* identifiers */
252 ot->name = "Vertex Paint Invert";
253 ot->idname = "GREASE_PENCIL_OT_vertex_color_invert";
254 ot->description = "Invert RGB values";
255
256 /* api callbacks */
259
260 /* flags */
262
263 /* params */
265 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
266}
267
269{
270 const Scene &scene = *CTX_data_scene(C);
271 Object &object = *CTX_data_active_object(C);
272 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
273 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
274 const float gain = RNA_float_get(op->ptr, "gain");
275 const float offset = RNA_float_get(op->ptr, "offset");
276
277 std::atomic<bool> any_changed;
278 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
281 if (curves.curves_num() == 0) {
282 return;
283 }
284 const bool changed = apply_color_operation_for_mode(
285 mode, object, info, [&](const ColorGeometry4f &color) -> ColorGeometry4f {
286 const float3 result = float3(color) * gain + offset;
287 return ColorGeometry4f(result[0], result[1], result[2], color.a);
288 });
289 any_changed.store(any_changed | changed, std::memory_order_relaxed);
290 });
291
292 if (any_changed) {
293 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
294 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
295 }
296 return OPERATOR_FINISHED;
297}
298
300{
301 /* identifiers */
302 ot->name = "Vertex Paint Levels";
303 ot->idname = "GREASE_PENCIL_OT_vertex_color_levels";
304 ot->description = "Adjust levels of vertex colors";
305
306 /* api callbacks */
309
310 /* flags */
312
313 /* params */
315 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
316
318 ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
320 ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
321}
322
324{
325 const Scene &scene = *CTX_data_scene(C);
326 Object &object = *CTX_data_active_object(C);
328 const Brush &brush = *BKE_paint_brush(&paint);
329 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
330 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
331 const float factor = RNA_float_get(op->ptr, "factor");
332
333 float3 color_linear;
334 srgb_to_linearrgb_v3_v3(color_linear, BKE_brush_color_get(&scene, &paint, &brush));
335 const ColorGeometry4f target_color(color_linear[0], color_linear[1], color_linear[2], 1.0f);
336
337 std::atomic<bool> any_changed;
338 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
341 if (curves.curves_num() == 0) {
342 return;
343 }
344 /* Create the color attributes if they don't exist. */
346 curves.attributes_for_write().add<ColorGeometry4f>(
348 }
350 curves.attributes_for_write().add<ColorGeometry4f>(
352 }
353 const bool changed = apply_color_operation_for_mode(
354 mode, object, info, [&](const ColorGeometry4f &color) -> ColorGeometry4f {
355 /* Mix in the target color based on the factor. */
356 return math::interpolate(color, target_color, factor);
357 });
358 any_changed.store(any_changed | changed, std::memory_order_relaxed);
359 });
360
361 if (any_changed) {
362 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
363 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
364 }
365 return OPERATOR_FINISHED;
366}
367
369{
370 /* identifiers */
371 ot->name = "Vertex Paint Set Color";
372 ot->idname = "GREASE_PENCIL_OT_vertex_color_set";
373 ot->description = "Set active color to all selected vertex";
374
375 /* api callbacks */
378
379 /* flags */
381
382 /* params */
384 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
385 RNA_def_float(ot->srna, "factor", 1.0f, 0.0f, 1.0f, "Factor", "Mix Factor", 0.0f, 1.0f);
386}
387
389{
390 const Scene &scene = *CTX_data_scene(C);
391 Object &object = *CTX_data_active_object(C);
392 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
393 const VertexColorMode mode = VertexColorMode(RNA_enum_get(op->ptr, "mode"));
394
395 std::atomic<bool> any_changed;
396 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
399 if (curves.curves_num() == 0) {
400 return;
401 }
402 /* Remove the color attributes. */
403 bool changed = false;
405 changed |= curves.attributes_for_write().remove("vertex_color");
406 }
408 changed |= curves.attributes_for_write().remove("fill_color");
409 }
410 any_changed.store(any_changed | changed, std::memory_order_relaxed);
411 });
412
413 if (any_changed) {
414 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
415 WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
416 }
417 return OPERATOR_FINISHED;
418}
419
421{
422 /* identifiers */
423 ot->name = "Reset Vertex Color";
424 ot->idname = "GREASE_PENCIL_OT_stroke_reset_vertex_color";
425 ot->description = "Reset vertex color for all or selected strokes";
426
427 /* callbacks */
430
431 /* flags */
433
434 /* properties */
436 ot->srna, "mode", prop_grease_pencil_vertex_mode, int(VertexColorMode::Both), "Mode", "");
437}
438
439} // namespace blender::ed::greasepencil
440
442{
443 using namespace blender::ed::greasepencil;
444 WM_operatortype_append(GREASE_PENCIL_OT_vertex_color_brightness_contrast);
445 WM_operatortype_append(GREASE_PENCIL_OT_vertex_color_hsv);
446 WM_operatortype_append(GREASE_PENCIL_OT_vertex_color_invert);
447 WM_operatortype_append(GREASE_PENCIL_OT_vertex_color_levels);
448 WM_operatortype_append(GREASE_PENCIL_OT_vertex_color_set);
449 WM_operatortype_append(GREASE_PENCIL_OT_stroke_reset_vertex_color);
450}
const float * BKE_brush_color_get(const Scene *scene, const Paint *paint, const Brush *brush)
Definition brush.cc:1029
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:477
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
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:1041
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
bool contains(const StringRef attribute_id) const
MutableAttributeAccessor attributes_for_write()
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
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
static int grease_pencil_vertex_paint_invert_exec(bContext *C, wmOperator *op)
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 int grease_pencil_vertex_paint_reset_exec(bContext *C, wmOperator *op)
static int grease_pencil_vertex_paint_levels_exec(bContext *C, wmOperator *op)
static int grease_pencil_vertex_paint_hsv_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot)
static void GREASE_PENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
static void GREASE_PENCIL_OT_vertex_color_set(wmOperatorType *ot)
static void GREASE_PENCIL_OT_vertex_color_invert(wmOperatorType *ot)
static int grease_pencil_vertex_paint_set_exec(bContext *C, wmOperator *op)
static void GREASE_PENCIL_OT_vertex_color_hsv(wmOperatorType *ot)
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 int grease_pencil_vertex_paint_brightness_contrast_exec(bContext *C, wmOperator *op)
static bool apply_color_operation_for_mode(const VertexColorMode mode, Object &object, MutableDrawingInfo &info, Fn &&fn)
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:58
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
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
__int64 int64_t
Definition stdint.h:89
signed char int8_t
Definition stdint.h:75
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
struct PointerRNA * ptr
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))