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 <stdlib.h>
21 #include <string.h>
22
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gegl.h>
25
26 #include "libgimpbase/gimpbase.h"
27
28 #include "paint-types.h"
29
30 #include "gegl/gimp-gegl-apply-operation.h"
31 #include "gegl/gimp-gegl-loops.h"
32
33 #include "core/gimp.h"
34 #include "core/gimpdrawable.h"
35 #include "core/gimpdynamics.h"
36 #include "core/gimperror.h"
37 #include "core/gimpimage.h"
38 #include "core/gimppattern.h"
39 #include "core/gimppickable.h"
40 #include "core/gimpsymmetry.h"
41
42 #include "gimpclone.h"
43 #include "gimpcloneoptions.h"
44
45 #include "gimp-intl.h"
46
47
48 static gboolean gimp_clone_start (GimpPaintCore *paint_core,
49 GimpDrawable *drawable,
50 GimpPaintOptions *paint_options,
51 const GimpCoords *coords,
52 GError **error);
53
54 static void gimp_clone_motion (GimpSourceCore *source_core,
55 GimpDrawable *drawable,
56 GimpPaintOptions *paint_options,
57 const GimpCoords *coords,
58 GeglNode *op,
59 gdouble opacity,
60 GimpPickable *src_pickable,
61 GeglBuffer *src_buffer,
62 GeglRectangle *src_rect,
63 gint src_offset_x,
64 gint src_offset_y,
65 GeglBuffer *paint_buffer,
66 gint paint_buffer_x,
67 gint paint_buffer_y,
68 gint paint_area_offset_x,
69 gint paint_area_offset_y,
70 gint paint_area_width,
71 gint paint_area_height);
72
73 static gboolean gimp_clone_use_source (GimpSourceCore *source_core,
74 GimpSourceOptions *options);
75
76
G_DEFINE_TYPE(GimpClone,gimp_clone,GIMP_TYPE_SOURCE_CORE)77 G_DEFINE_TYPE (GimpClone, gimp_clone, GIMP_TYPE_SOURCE_CORE)
78
79 #define parent_class gimp_clone_parent_class
80
81
82 void
83 gimp_clone_register (Gimp *gimp,
84 GimpPaintRegisterCallback callback)
85 {
86 (* callback) (gimp,
87 GIMP_TYPE_CLONE,
88 GIMP_TYPE_CLONE_OPTIONS,
89 "gimp-clone",
90 _("Clone"),
91 "gimp-tool-clone");
92 }
93
94 static void
gimp_clone_class_init(GimpCloneClass * klass)95 gimp_clone_class_init (GimpCloneClass *klass)
96 {
97 GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
98 GimpSourceCoreClass *source_core_class = GIMP_SOURCE_CORE_CLASS (klass);
99
100 paint_core_class->start = gimp_clone_start;
101
102 source_core_class->use_source = gimp_clone_use_source;
103 source_core_class->motion = gimp_clone_motion;
104 }
105
106 static void
gimp_clone_init(GimpClone * clone)107 gimp_clone_init (GimpClone *clone)
108 {
109 }
110
111 static gboolean
gimp_clone_start(GimpPaintCore * paint_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,const GimpCoords * coords,GError ** error)112 gimp_clone_start (GimpPaintCore *paint_core,
113 GimpDrawable *drawable,
114 GimpPaintOptions *paint_options,
115 const GimpCoords *coords,
116 GError **error)
117 {
118 GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options);
119
120 if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
121 paint_options, coords,
122 error))
123 {
124 return FALSE;
125 }
126
127 if (options->clone_type == GIMP_CLONE_PATTERN)
128 {
129 if (! gimp_context_get_pattern (GIMP_CONTEXT (options)))
130 {
131 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
132 _("No patterns available for use with this tool."));
133 return FALSE;
134 }
135 }
136
137 return TRUE;
138 }
139
140 static void
gimp_clone_motion(GimpSourceCore * source_core,GimpDrawable * drawable,GimpPaintOptions * paint_options,const GimpCoords * coords,GeglNode * op,gdouble opacity,GimpPickable * src_pickable,GeglBuffer * src_buffer,GeglRectangle * src_rect,gint src_offset_x,gint src_offset_y,GeglBuffer * paint_buffer,gint paint_buffer_x,gint paint_buffer_y,gint paint_area_offset_x,gint paint_area_offset_y,gint paint_area_width,gint paint_area_height)141 gimp_clone_motion (GimpSourceCore *source_core,
142 GimpDrawable *drawable,
143 GimpPaintOptions *paint_options,
144 const GimpCoords *coords,
145 GeglNode *op,
146 gdouble opacity,
147 GimpPickable *src_pickable,
148 GeglBuffer *src_buffer,
149 GeglRectangle *src_rect,
150 gint src_offset_x,
151 gint src_offset_y,
152 GeglBuffer *paint_buffer,
153 gint paint_buffer_x,
154 gint paint_buffer_y,
155 gint paint_area_offset_x,
156 gint paint_area_offset_y,
157 gint paint_area_width,
158 gint paint_area_height)
159 {
160 GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core);
161 GimpBrushCore *brush_core = GIMP_BRUSH_CORE (source_core);
162 GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options);
163 GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options);
164 GimpContext *context = GIMP_CONTEXT (paint_options);
165 GimpDynamics *dynamics = brush_core->dynamics;
166 GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
167 gdouble fade_point;
168 gdouble force;
169
170 if (gimp_source_core_use_source (source_core, source_options))
171 {
172 if (! op)
173 {
174 gimp_gegl_buffer_copy (src_buffer,
175 GEGL_RECTANGLE (src_rect->x,
176 src_rect->y,
177 paint_area_width,
178 paint_area_height),
179 GEGL_ABYSS_NONE,
180 paint_buffer,
181 GEGL_RECTANGLE (paint_area_offset_x,
182 paint_area_offset_y,
183 0, 0));
184 }
185 else
186 {
187 gimp_gegl_apply_operation (src_buffer, NULL, NULL, op,
188 paint_buffer,
189 GEGL_RECTANGLE (paint_area_offset_x,
190 paint_area_offset_y,
191 paint_area_width,
192 paint_area_height),
193 FALSE);
194 }
195 }
196 else if (options->clone_type == GIMP_CLONE_PATTERN)
197 {
198 GimpPattern *pattern = gimp_context_get_pattern (context);
199 GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern);
200
201 src_offset_x += gegl_buffer_get_width (src_buffer) / 2;
202 src_offset_y += gegl_buffer_get_height (src_buffer) / 2;
203
204 gegl_buffer_set_pattern (paint_buffer,
205 GEGL_RECTANGLE (paint_area_offset_x,
206 paint_area_offset_y,
207 paint_area_width,
208 paint_area_height),
209 src_buffer,
210 - paint_buffer_x - src_offset_x,
211 - paint_buffer_y - src_offset_y);
212
213 g_object_unref (src_buffer);
214 }
215 else
216 {
217 g_return_if_reached ();
218 }
219
220 fade_point = gimp_paint_options_get_fade (paint_options, image,
221 paint_core->pixel_dist);
222
223 if (gimp_dynamics_is_output_enabled (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE))
224 force = gimp_dynamics_get_linear_value (dynamics,
225 GIMP_DYNAMICS_OUTPUT_FORCE,
226 coords,
227 paint_options,
228 fade_point);
229 else
230 force = paint_options->brush_force;
231
232 gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable,
233 coords,
234 MIN (opacity, GIMP_OPACITY_OPAQUE),
235 gimp_context_get_opacity (context),
236 gimp_context_get_paint_mode (context),
237 gimp_paint_options_get_brush_mode (paint_options),
238 force,
239
240 /* In fixed mode, paint incremental so the
241 * individual brushes are properly applied
242 * on top of each other.
243 * Otherwise the stuff we paint is seamless
244 * and we don't need intermediate masking.
245 */
246 source_options->align_mode ==
247 GIMP_SOURCE_ALIGN_FIXED ?
248 GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT);
249 }
250
251 static gboolean
gimp_clone_use_source(GimpSourceCore * source_core,GimpSourceOptions * options)252 gimp_clone_use_source (GimpSourceCore *source_core,
253 GimpSourceOptions *options)
254 {
255 return GIMP_CLONE_OPTIONS (options)->clone_type == GIMP_CLONE_IMAGE;
256 }
257