1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <string.h>
21
22 #include <cairo.h>
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gegl.h>
25
26 #include <mypaint-brush.h>
27
28 #include "libgimpmath/gimpmath.h"
29 #include "libgimpcolor/gimpcolor.h"
30
31 #include "paint-types.h"
32
33 #include "gegl/gimp-gegl-utils.h"
34
35 #include "core/gimp.h"
36 #include "core/gimp-palettes.h"
37 #include "core/gimpdrawable.h"
38 #include "core/gimperror.h"
39 #include "core/gimpmybrush.h"
40 #include "core/gimppickable.h"
41 #include "core/gimpsymmetry.h"
42
43 #include "gimpmybrushcore.h"
44 #include "gimpmybrushsurface.h"
45 #include "gimpmybrushoptions.h"
46
47 #include "gimp-intl.h"
48
49
50 struct _GimpMybrushCorePrivate
51 {
52 GimpMybrush *mybrush;
53 GimpMybrushSurface *surface;
54 GList *brushes;
55 gboolean synthetic;
56 gint64 last_time;
57 };
58
59
60 /* local function prototypes */
61
62 static void gimp_mybrush_core_finalize (GObject *object);
63
64 static gboolean gimp_mybrush_core_start (GimpPaintCore *paint_core,
65 GimpDrawable *drawable,
66 GimpPaintOptions *paint_options,
67 const GimpCoords *coords,
68 GError **error);
69 static void gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
70 GimpDrawable *drawable,
71 GimpPaintOptions *paint_options,
72 guint32 time);
73 static void gimp_mybrush_core_paint (GimpPaintCore *paint_core,
74 GimpDrawable *drawable,
75 GimpPaintOptions *paint_options,
76 GimpSymmetry *sym,
77 GimpPaintState paint_state,
78 guint32 time);
79 static void gimp_mybrush_core_motion (GimpPaintCore *paint_core,
80 GimpDrawable *drawable,
81 GimpPaintOptions *paint_options,
82 GimpSymmetry *sym,
83 guint32 time);
84 static void gimp_mybrush_core_create_brushes (GimpMybrushCore *mybrush,
85 GimpDrawable *drawable,
86 GimpPaintOptions *paint_options,
87 GimpSymmetry *sym);
88
89
G_DEFINE_TYPE_WITH_PRIVATE(GimpMybrushCore,gimp_mybrush_core,GIMP_TYPE_PAINT_CORE)90 G_DEFINE_TYPE_WITH_PRIVATE (GimpMybrushCore, gimp_mybrush_core,
91 GIMP_TYPE_PAINT_CORE)
92
93 #define parent_class gimp_mybrush_core_parent_class
94
95
96 void
97 gimp_mybrush_core_register (Gimp *gimp,
98 GimpPaintRegisterCallback callback)
99 {
100 (* callback) (gimp,
101 GIMP_TYPE_MYBRUSH_CORE,
102 GIMP_TYPE_MYBRUSH_OPTIONS,
103 "gimp-mybrush",
104 _("Mybrush"),
105 "gimp-tool-mypaint-brush");
106 }
107
108 static void
gimp_mybrush_core_class_init(GimpMybrushCoreClass * klass)109 gimp_mybrush_core_class_init (GimpMybrushCoreClass *klass)
110 {
111 GObjectClass *object_class = G_OBJECT_CLASS (klass);
112 GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
113
114 object_class->finalize = gimp_mybrush_core_finalize;
115
116 paint_core_class->start = gimp_mybrush_core_start;
117 paint_core_class->paint = gimp_mybrush_core_paint;
118 paint_core_class->interpolate = gimp_mybrush_core_interpolate;
119 }
120
121 static void
gimp_mybrush_core_init(GimpMybrushCore * mybrush)122 gimp_mybrush_core_init (GimpMybrushCore *mybrush)
123 {
124 mybrush->private = gimp_mybrush_core_get_instance_private (mybrush);
125 }
126
127 static void
gimp_mybrush_core_finalize(GObject * object)128 gimp_mybrush_core_finalize (GObject *object)
129 {
130 GimpMybrushCore *core = GIMP_MYBRUSH_CORE (object);
131
132 if (core->private->brushes)
133 {
134 g_list_free_full (core->private->brushes,
135 (GDestroyNotify) mypaint_brush_unref);
136 core->private->brushes = NULL;
137 }
138
139 G_OBJECT_CLASS (parent_class)->finalize (object);
140 }
141
142 static gboolean
gimp_mybrush_core_start(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,const GimpCoords * coords,GError ** error)143 gimp_mybrush_core_start (GimpPaintCore *paint_core,
144 GimpDrawable *drawable,
145 GimpPaintOptions *paint_options,
146 const GimpCoords *coords,
147 GError **error)
148 {
149 GimpMybrushCore *core = GIMP_MYBRUSH_CORE (paint_core);
150 GimpContext *context = GIMP_CONTEXT (paint_options);
151
152 core->private->mybrush = gimp_context_get_mybrush (context);
153
154 if (! core->private->mybrush)
155 {
156 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
157 _("No MyPaint brushes available for use with this tool."));
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 static void
gimp_mybrush_core_interpolate(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,guint32 time)165 gimp_mybrush_core_interpolate (GimpPaintCore *paint_core,
166 GimpDrawable *drawable,
167 GimpPaintOptions *paint_options,
168 guint32 time)
169 {
170 GimpMybrushCore *mybrush = GIMP_MYBRUSH_CORE (paint_core);
171
172 /* If this is the first motion the brush has received then
173 * we're being asked to draw a synthetic stroke in line mode
174 */
175 if (mybrush->private->last_time < 0)
176 {
177 GimpCoords saved_coords = paint_core->cur_coords;
178
179 paint_core->cur_coords = paint_core->last_coords;
180
181 mybrush->private->synthetic = TRUE;
182
183 gimp_paint_core_paint (paint_core, drawable, paint_options,
184 GIMP_PAINT_STATE_MOTION, time);
185
186 paint_core->cur_coords = saved_coords;
187 }
188
189 gimp_paint_core_paint (paint_core, drawable, paint_options,
190 GIMP_PAINT_STATE_MOTION, time);
191
192 paint_core->last_coords = paint_core->cur_coords;
193 }
194
195 static void
gimp_mybrush_core_paint(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpSymmetry * sym,GimpPaintState paint_state,guint32 time)196 gimp_mybrush_core_paint (GimpPaintCore *paint_core,
197 GimpDrawable *drawable,
198 GimpPaintOptions *paint_options,
199 GimpSymmetry *sym,
200 GimpPaintState paint_state,
201 guint32 time)
202 {
203 GimpMybrushCore *mybrush = GIMP_MYBRUSH_CORE (paint_core);
204 GimpContext *context = GIMP_CONTEXT (paint_options);
205 GimpRGB fg;
206
207 switch (paint_state)
208 {
209 case GIMP_PAINT_STATE_INIT:
210 gimp_context_get_foreground (context, &fg);
211 gimp_palettes_add_color_history (context->gimp, &fg);
212 gimp_symmetry_set_stateful (sym, TRUE);
213
214 mybrush->private->surface =
215 gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawable),
216 gimp_drawable_get_active_mask (drawable),
217 paint_core->mask_buffer,
218 paint_core->mask_x_offset,
219 paint_core->mask_y_offset,
220 GIMP_MYBRUSH_OPTIONS (paint_options));
221
222 gimp_mybrush_core_create_brushes (mybrush, drawable, paint_options, sym);
223
224 mybrush->private->last_time = -1;
225 mybrush->private->synthetic = FALSE;
226 break;
227
228 case GIMP_PAINT_STATE_MOTION:
229 gimp_mybrush_core_motion (paint_core, drawable, paint_options,
230 sym, time);
231 break;
232
233 case GIMP_PAINT_STATE_FINISH:
234 gimp_symmetry_set_stateful (sym, FALSE);
235 mypaint_surface_unref ((MyPaintSurface *) mybrush->private->surface);
236 mybrush->private->surface = NULL;
237
238 g_list_free_full (mybrush->private->brushes,
239 (GDestroyNotify) mypaint_brush_unref);
240 mybrush->private->brushes = NULL;
241 break;
242 }
243 }
244
245 static void
gimp_mybrush_core_motion(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpSymmetry * sym,guint32 time)246 gimp_mybrush_core_motion (GimpPaintCore *paint_core,
247 GimpDrawable *drawable,
248 GimpPaintOptions *paint_options,
249 GimpSymmetry *sym,
250 guint32 time)
251 {
252 GimpMybrushCore *mybrush = GIMP_MYBRUSH_CORE (paint_core);
253 MyPaintRectangle rect;
254 GList *iter;
255 gdouble dt = 0.0;
256 gint n_strokes;
257 gint i;
258
259 n_strokes = gimp_symmetry_get_size (sym);
260
261 /* The number of strokes may change during a motion, depending on
262 * the type of symmetry. When that happens, reset the brushes.
263 */
264 if (g_list_length (mybrush->private->brushes) != n_strokes)
265 {
266 gimp_mybrush_core_create_brushes (mybrush, drawable, paint_options, sym);
267 }
268
269 mypaint_surface_begin_atomic ((MyPaintSurface *) mybrush->private->surface);
270
271 if (mybrush->private->last_time < 0)
272 {
273 /* First motion, so we need zero pressure events to start the strokes */
274 for (iter = mybrush->private->brushes, i = 0;
275 iter;
276 iter = g_list_next (iter), i++)
277 {
278 MyPaintBrush *brush = iter->data;
279 GimpCoords *coords = gimp_symmetry_get_coords (sym, i);
280
281 mypaint_brush_stroke_to (brush,
282 (MyPaintSurface *) mybrush->private->surface,
283 coords->x,
284 coords->y,
285 0.0f,
286 coords->xtilt,
287 coords->ytilt,
288 1.0f /* Pretend the cursor hasn't moved in a while */);
289 }
290
291 dt = 0.015;
292 }
293 else if (mybrush->private->synthetic)
294 {
295 GimpVector2 v = { paint_core->cur_coords.x - paint_core->last_coords.x,
296 paint_core->cur_coords.y - paint_core->last_coords.y };
297
298 dt = 0.0005 * gimp_vector2_length_val (v);
299 }
300 else
301 {
302 dt = (time - mybrush->private->last_time) * 0.001;
303 }
304
305 for (iter = mybrush->private->brushes, i = 0;
306 iter;
307 iter = g_list_next (iter), i++)
308 {
309 MyPaintBrush *brush = iter->data;
310 GimpCoords *coords = gimp_symmetry_get_coords (sym, i);
311 gdouble pressure = coords->pressure;
312
313 /* libmypaint expects non-extended devices to default to 0.5 pressure */
314 if (! coords->extended)
315 pressure = 0.5f;
316
317 mypaint_brush_stroke_to (brush,
318 (MyPaintSurface *) mybrush->private->surface,
319 coords->x,
320 coords->y,
321 pressure,
322 coords->xtilt,
323 coords->ytilt,
324 dt);
325 }
326
327 mybrush->private->last_time = time;
328
329 mypaint_surface_end_atomic ((MyPaintSurface *) mybrush->private->surface,
330 &rect);
331
332 if (rect.width > 0 && rect.height > 0)
333 {
334 paint_core->x1 = MIN (paint_core->x1, rect.x);
335 paint_core->y1 = MIN (paint_core->y1, rect.y);
336 paint_core->x2 = MAX (paint_core->x2, rect.x + rect.width);
337 paint_core->y2 = MAX (paint_core->y2, rect.y + rect.height);
338
339 gimp_drawable_update (drawable, rect.x, rect.y, rect.width, rect.height);
340 }
341 }
342
343 static void
gimp_mybrush_core_create_brushes(GimpMybrushCore * mybrush,GimpDrawable * drawable,GimpPaintOptions * paint_options,GimpSymmetry * sym)344 gimp_mybrush_core_create_brushes (GimpMybrushCore *mybrush,
345 GimpDrawable *drawable,
346 GimpPaintOptions *paint_options,
347 GimpSymmetry *sym)
348 {
349 GimpMybrushOptions *options = GIMP_MYBRUSH_OPTIONS (paint_options);
350 GimpContext *context = GIMP_CONTEXT (paint_options);
351 GimpRGB fg;
352 GimpHSV hsv;
353 gint n_strokes;
354 gint i;
355
356 if (mybrush->private->brushes)
357 {
358 g_list_free_full (mybrush->private->brushes,
359 (GDestroyNotify) mypaint_brush_unref);
360 mybrush->private->brushes = NULL;
361 }
362
363 if (options->eraser)
364 gimp_context_get_background (context, &fg);
365 else
366 gimp_context_get_foreground (context, &fg);
367
368 gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
369 &fg, &fg);
370 gimp_rgb_to_hsv (&fg, &hsv);
371
372 n_strokes = gimp_symmetry_get_size (sym);
373
374 for (i = 0; i < n_strokes; i++)
375 {
376 MyPaintBrush *brush = mypaint_brush_new ();
377 const gchar *brush_data;
378
379 mypaint_brush_from_defaults (brush);
380 brush_data = gimp_mybrush_get_brush_json (mybrush->private->mybrush);
381 if (brush_data)
382 mypaint_brush_from_string (brush, brush_data);
383
384 if (! mypaint_brush_get_base_value (brush,
385 MYPAINT_BRUSH_SETTING_RESTORE_COLOR))
386 {
387 mypaint_brush_set_base_value (brush,
388 MYPAINT_BRUSH_SETTING_COLOR_H,
389 hsv.h);
390 mypaint_brush_set_base_value (brush,
391 MYPAINT_BRUSH_SETTING_COLOR_S,
392 hsv.s);
393 mypaint_brush_set_base_value (brush,
394 MYPAINT_BRUSH_SETTING_COLOR_V,
395 hsv.v);
396 }
397
398 mypaint_brush_set_base_value (brush,
399 MYPAINT_BRUSH_SETTING_RADIUS_LOGARITHMIC,
400 options->radius);
401 mypaint_brush_set_base_value (brush,
402 MYPAINT_BRUSH_SETTING_OPAQUE,
403 options->opaque *
404 gimp_context_get_opacity (context));
405 mypaint_brush_set_base_value (brush,
406 MYPAINT_BRUSH_SETTING_HARDNESS,
407 options->hardness);
408 mypaint_brush_set_base_value (brush,
409 MYPAINT_BRUSH_SETTING_ERASER,
410 (options->eraser &&
411 gimp_drawable_has_alpha (drawable)) ?
412 1.0f : 0.0f);
413
414 mypaint_brush_new_stroke (brush);
415
416 mybrush->private->brushes = g_list_prepend (mybrush->private->brushes,
417 brush);
418 }
419
420 mybrush->private->brushes = g_list_reverse (mybrush->private->brushes);
421 }
422