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 #include <gegl.h>
20 
21 #include <mypaint-surface.h>
22 
23 #include "paint-types.h"
24 
25 #include "libgimpmath/gimpmath.h"
26 
27 #include <cairo.h>
28 #include <gdk-pixbuf/gdk-pixbuf.h>
29 #include "libgimpcolor/gimpcolor.h"
30 
31 #include "gimpmybrushoptions.h"
32 #include "gimpmybrushsurface.h"
33 
34 
35 struct _GimpMybrushSurface
36 {
37   MyPaintSurface surface;
38   GeglBuffer *buffer;
39   GeglBuffer *paint_mask;
40   gint        paint_mask_x;
41   gint        paint_mask_y;
42   GeglRectangle dirty;
43   GimpComponentMask component_mask;
44   GimpMybrushOptions *options;
45 };
46 
47 /* --- Taken from mypaint-tiled-surface.c --- */
48 static inline float
calculate_rr(int xp,int yp,float x,float y,float aspect_ratio,float sn,float cs,float one_over_radius2)49 calculate_rr (int   xp,
50               int   yp,
51               float x,
52               float y,
53               float aspect_ratio,
54               float sn,
55               float cs,
56               float one_over_radius2)
57 {
58     /* code duplication, see brush::count_dabs_to() */
59     const float yy = (yp + 0.5f - y);
60     const float xx = (xp + 0.5f - x);
61     const float yyr=(yy*cs-xx*sn)*aspect_ratio;
62     const float xxr=yy*sn+xx*cs;
63     const float rr = (yyr*yyr + xxr*xxr) * one_over_radius2;
64     /* rr is in range 0.0..1.0*sqrt(2) */
65     return rr;
66 }
67 
68 static inline float
calculate_r_sample(float x,float y,float aspect_ratio,float sn,float cs)69 calculate_r_sample (float x,
70                     float y,
71                     float aspect_ratio,
72                     float sn,
73                     float cs)
74 {
75     const float yyr=(y*cs-x*sn)*aspect_ratio;
76     const float xxr=y*sn+x*cs;
77     const float r = (yyr*yyr + xxr*xxr);
78     return r;
79 }
80 
81 static inline float
sign_point_in_line(float px,float py,float vx,float vy)82 sign_point_in_line (float px,
83                     float py,
84                     float vx,
85                     float vy)
86 {
87     return (px - vx) * (-vy) - (vx) * (py - vy);
88 }
89 
90 static inline void
closest_point_to_line(float lx,float ly,float px,float py,float * ox,float * oy)91 closest_point_to_line (float  lx,
92                        float  ly,
93                        float  px,
94                        float  py,
95                        float *ox,
96                        float *oy)
97 {
98     const float l2 = lx*lx + ly*ly;
99     const float ltp_dot = px*lx + py*ly;
100     const float t = ltp_dot / l2;
101     *ox = lx * t;
102     *oy = ly * t;
103 }
104 
105 
106 /* This works by taking the visibility at the nearest point
107  * and dividing by 1.0 + delta.
108  *
109  * - nearest point: point where the dab has more influence
110  * - farthest point: point at a fixed distance away from
111  *                   the nearest point
112  * - delta: how much occluded is the farthest point relative
113  *          to the nearest point
114  */
115 static inline float
calculate_rr_antialiased(int xp,int yp,float x,float y,float aspect_ratio,float sn,float cs,float one_over_radius2,float r_aa_start)116 calculate_rr_antialiased (int  xp,
117                           int  yp,
118                           float x,
119                           float y,
120                           float aspect_ratio,
121                           float sn,
122                           float cs,
123                           float one_over_radius2,
124                           float r_aa_start)
125 {
126     /* calculate pixel position and borders in a way
127      * that the dab's center is always at zero */
128     float pixel_right = x - (float)xp;
129     float pixel_bottom = y - (float)yp;
130     float pixel_center_x = pixel_right - 0.5f;
131     float pixel_center_y = pixel_bottom - 0.5f;
132     float pixel_left = pixel_right - 1.0f;
133     float pixel_top = pixel_bottom - 1.0f;
134 
135     float nearest_x, nearest_y; /* nearest to origin, but still inside pixel */
136     float farthest_x, farthest_y; /* farthest from origin, but still inside pixel */
137     float r_near, r_far, rr_near, rr_far;
138     float center_sign, rad_area_1, visibilityNear, delta, delta2;
139 
140     /* Dab's center is inside pixel? */
141     if( pixel_left<0 && pixel_right>0 &&
142         pixel_top<0 && pixel_bottom>0 )
143     {
144         nearest_x = 0;
145         nearest_y = 0;
146         r_near = rr_near = 0;
147     }
148     else
149     {
150         closest_point_to_line( cs, sn, pixel_center_x, pixel_center_y, &nearest_x, &nearest_y );
151         nearest_x = CLAMP( nearest_x, pixel_left, pixel_right );
152         nearest_y = CLAMP( nearest_y, pixel_top, pixel_bottom );
153         /* XXX: precision of "nearest" values could be improved
154          * by intersecting the line that goes from nearest_x/Y to 0
155          * with the pixel's borders here, however the improvements
156          * would probably not justify the perdormance cost.
157          */
158         r_near = calculate_r_sample( nearest_x, nearest_y, aspect_ratio, sn, cs );
159         rr_near = r_near * one_over_radius2;
160     }
161 
162     /* out of dab's reach? */
163     if( rr_near > 1.0f )
164         return rr_near;
165 
166     /* check on which side of the dab's line is the pixel center */
167     center_sign = sign_point_in_line( pixel_center_x, pixel_center_y, cs, -sn );
168 
169     /* radius of a circle with area=1
170      *   A = pi * r * r
171      *   r = sqrt(1/pi)
172      */
173     rad_area_1 = sqrtf( 1.0f / M_PI );
174 
175     /* center is below dab */
176     if( center_sign < 0 )
177     {
178         farthest_x = nearest_x - sn*rad_area_1;
179         farthest_y = nearest_y + cs*rad_area_1;
180     }
181     /* above dab */
182     else
183     {
184         farthest_x = nearest_x + sn*rad_area_1;
185         farthest_y = nearest_y - cs*rad_area_1;
186     }
187 
188     r_far = calculate_r_sample( farthest_x, farthest_y, aspect_ratio, sn, cs );
189     rr_far = r_far * one_over_radius2;
190 
191     /* check if we can skip heavier AA */
192     if( r_far < r_aa_start )
193         return (rr_far+rr_near) * 0.5f;
194 
195     /* calculate AA approximate */
196     visibilityNear = 1.0f - rr_near;
197     delta = rr_far - rr_near;
198     delta2 = 1.0f + delta;
199     visibilityNear /= delta2;
200 
201     return 1.0f - visibilityNear;
202 }
203 /* -- end mypaint code */
204 
205 static inline float
calculate_alpha_for_rr(float rr,float hardness,float slope1,float slope2)206 calculate_alpha_for_rr (float rr,
207                         float hardness,
208                         float slope1,
209                         float slope2)
210 {
211   if (rr > 1.0f)
212     return 0.0f;
213   else if (rr <= hardness)
214     return 1.0f + rr * slope1;
215   else
216     return rr * slope2 - slope2;
217 }
218 
219 static GeglRectangle
calculate_dab_roi(float x,float y,float radius)220 calculate_dab_roi (float x,
221                    float y,
222                    float radius)
223 {
224   int x0 = floor (x - radius);
225   int x1 = ceil (x + radius);
226   int y0 = floor (y - radius);
227   int y1 = ceil (y + radius);
228 
229   return *GEGL_RECTANGLE (x0, y0, x1 - x0, y1 - y0);
230 }
231 
232 static void
gimp_mypaint_surface_get_color(MyPaintSurface * base_surface,float x,float y,float radius,float * color_r,float * color_g,float * color_b,float * color_a)233 gimp_mypaint_surface_get_color (MyPaintSurface *base_surface,
234                                 float           x,
235                                 float           y,
236                                 float           radius,
237                                 float          *color_r,
238                                 float          *color_g,
239                                 float          *color_b,
240                                 float          *color_a)
241 {
242   GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
243   GeglRectangle dabRect;
244 
245   if (radius < 1.0f)
246     radius = 1.0f;
247 
248   dabRect = calculate_dab_roi (x, y, radius);
249 
250   *color_r = 0.0f;
251   *color_g = 0.0f;
252   *color_b = 0.0f;
253   *color_a = 0.0f;
254 
255   if (dabRect.width > 0 || dabRect.height > 0)
256   {
257     const float one_over_radius2 = 1.0f / (radius * radius);
258     float sum_weight = 0.0f;
259     float sum_r = 0.0f;
260     float sum_g = 0.0f;
261     float sum_b = 0.0f;
262     float sum_a = 0.0f;
263 
264      /* Read in clamp mode to avoid transparency bleeding in at the edges */
265     GeglBufferIterator *iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
266                                                          babl_format ("R'aG'aB'aA float"),
267                                                          GEGL_BUFFER_READ,
268                                                          GEGL_ABYSS_CLAMP, 2);
269     if (surface->paint_mask)
270       {
271         GeglRectangle mask_roi = dabRect;
272         mask_roi.x -= surface->paint_mask_x;
273         mask_roi.y -= surface->paint_mask_y;
274         gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
275                                   babl_format ("Y float"),
276                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
277       }
278 
279     while (gegl_buffer_iterator_next (iter))
280       {
281         float *pixel = (float *)iter->items[0].data;
282         float *mask;
283         int iy, ix;
284 
285         if (surface->paint_mask)
286           mask = iter->items[1].data;
287         else
288           mask = NULL;
289 
290         for (iy = iter->items[0].roi.y; iy < iter->items[0].roi.y + iter->items[0].roi.height; iy++)
291           {
292             float yy = (iy + 0.5f - y);
293             for (ix = iter->items[0].roi.x; ix < iter->items[0].roi.x +  iter->items[0].roi.width; ix++)
294               {
295                 /* pixel_weight == a standard dab with hardness = 0.5, aspect_ratio = 1.0, and angle = 0.0 */
296                 float xx = (ix + 0.5f - x);
297                 float rr = (yy * yy + xx * xx) * one_over_radius2;
298                 float pixel_weight = 0.0f;
299                 if (rr <= 1.0f)
300                   pixel_weight = 1.0f - rr;
301                 if (mask)
302                   pixel_weight *= *mask;
303 
304                 sum_r += pixel_weight * pixel[RED];
305                 sum_g += pixel_weight * pixel[GREEN];
306                 sum_b += pixel_weight * pixel[BLUE];
307                 sum_a += pixel_weight * pixel[ALPHA];
308                 sum_weight += pixel_weight;
309 
310                 pixel += 4;
311                 if (mask)
312                   mask += 1;
313               }
314           }
315       }
316 
317     if (sum_a > 0.0f && sum_weight > 0.0f)
318       {
319         sum_r /= sum_weight;
320         sum_g /= sum_weight;
321         sum_b /= sum_weight;
322         sum_a /= sum_weight;
323 
324         sum_r /= sum_a;
325         sum_g /= sum_a;
326         sum_b /= sum_a;
327 
328         /* FIXME: Clamping is wrong because GEGL allows alpha > 1, this should probably re-multipy things */
329         *color_r = CLAMP(sum_r, 0.0f, 1.0f);
330         *color_g = CLAMP(sum_g, 0.0f, 1.0f);
331         *color_b = CLAMP(sum_b, 0.0f, 1.0f);
332         *color_a = CLAMP(sum_a, 0.0f, 1.0f);
333       }
334   }
335 
336 }
337 
338 static int
gimp_mypaint_surface_draw_dab(MyPaintSurface * base_surface,float x,float y,float radius,float color_r,float color_g,float color_b,float opaque,float hardness,float color_a,float aspect_ratio,float angle,float lock_alpha,float colorize)339 gimp_mypaint_surface_draw_dab (MyPaintSurface *base_surface,
340                                float           x,
341                                float           y,
342                                float           radius,
343                                float           color_r,
344                                float           color_g,
345                                float           color_b,
346                                float           opaque,
347                                float           hardness,
348                                float           color_a,
349                                float           aspect_ratio,
350                                float           angle,
351                                float           lock_alpha,
352                                float           colorize)
353 {
354   GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
355   GeglBufferIterator *iter;
356   GeglRectangle       dabRect;
357   GimpComponentMask   component_mask = surface->component_mask;
358 
359   const float one_over_radius2 = 1.0f / (radius * radius);
360   const double angle_rad = angle / 360 * 2 * M_PI;
361   const float cs = cos(angle_rad);
362   const float sn = sin(angle_rad);
363   float normal_mode;
364   float segment1_slope;
365   float segment2_slope;
366   float r_aa_start;
367 
368   hardness = CLAMP (hardness, 0.0f, 1.0f);
369   segment1_slope = -(1.0f / hardness - 1.0f);
370   segment2_slope = -hardness / (1.0f - hardness);
371   aspect_ratio = MAX (1.0f, aspect_ratio);
372 
373   r_aa_start = radius - 1.0f;
374   r_aa_start = MAX (r_aa_start, 0);
375   r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio;
376 
377   normal_mode = opaque * (1.0f - colorize);
378   colorize = opaque * colorize;
379 
380   /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
381   dabRect = calculate_dab_roi (x, y, radius);
382   gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));
383 
384   if (dabRect.width <= 0 || dabRect.height <= 0)
385     return 0;
386 
387   gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect);
388 
389   iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
390                                    babl_format ("R'G'B'A float"),
391                                    GEGL_BUFFER_READWRITE,
392                                    GEGL_ABYSS_NONE, 2);
393   if (surface->paint_mask)
394     {
395       GeglRectangle mask_roi = dabRect;
396       mask_roi.x -= surface->paint_mask_x;
397       mask_roi.y -= surface->paint_mask_y;
398       gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
399                                 babl_format ("Y float"),
400                                 GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
401     }
402 
403   while (gegl_buffer_iterator_next (iter))
404     {
405       float *pixel = (float *)iter->items[0].data;
406       float *mask;
407       int iy, ix;
408 
409       if (surface->paint_mask)
410         mask = iter->items[1].data;
411       else
412         mask = NULL;
413 
414       for (iy = iter->items[0].roi.y; iy < iter->items[0].roi.y + iter->items[0].roi.height; iy++)
415         {
416           for (ix = iter->items[0].roi.x; ix < iter->items[0].roi.x +  iter->items[0].roi.width; ix++)
417             {
418               float rr, base_alpha, alpha, dst_alpha, r, g, b, a;
419               if (radius < 3.0f)
420                 rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2, r_aa_start);
421               else
422                 rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2);
423               base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope);
424               alpha = base_alpha * normal_mode;
425               if (mask)
426                 alpha *= *mask;
427               dst_alpha = pixel[ALPHA];
428               /* a = alpha * color_a + dst_alpha * (1.0f - alpha);
429                * which converts to: */
430               a = alpha * (color_a - dst_alpha) + dst_alpha;
431               r = pixel[RED];
432               g = pixel[GREEN];
433               b = pixel[BLUE];
434 
435               if (a > 0.0f)
436                 {
437                   /* By definition the ratio between each color[] and pixel[] component in a non-pre-multipled blend always sums to 1.0f.
438                    * Originally this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * (1.0f - alpha)) / a",
439                    * instead we only calculate the cheaper term. */
440                   float src_term = (alpha * color_a) / a;
441                   float dst_term = 1.0f - src_term;
442                   r = color_r * src_term + r * dst_term;
443                   g = color_g * src_term + g * dst_term;
444                   b = color_b * src_term + b * dst_term;
445                 }
446 
447               if (colorize > 0.0f && base_alpha > 0.0f)
448                 {
449                   alpha = base_alpha * colorize;
450                   a = alpha + dst_alpha - alpha * dst_alpha;
451                   if (a > 0.0f)
452                     {
453                       GimpHSL pixel_hsl, out_hsl;
454                       GimpRGB pixel_rgb = {color_r, color_g, color_b};
455                       GimpRGB out_rgb   = {r, g, b};
456                       float src_term = alpha / a;
457                       float dst_term = 1.0f - src_term;
458 
459                       gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl);
460                       gimp_rgb_to_hsl (&out_rgb, &out_hsl);
461 
462                       out_hsl.h = pixel_hsl.h;
463                       out_hsl.s = pixel_hsl.s;
464                       gimp_hsl_to_rgb (&out_hsl, &out_rgb);
465 
466                       r = (float)out_rgb.r * src_term + r * dst_term;
467                       g = (float)out_rgb.g * src_term + g * dst_term;
468                       b = (float)out_rgb.b * src_term + b * dst_term;
469                     }
470                 }
471 
472               if (surface->options->no_erasing)
473                 a = MAX (a, pixel[ALPHA]);
474 
475               if (component_mask != GIMP_COMPONENT_MASK_ALL)
476                 {
477                   if (component_mask & GIMP_COMPONENT_MASK_RED)
478                     pixel[RED]   = r;
479                   if (component_mask & GIMP_COMPONENT_MASK_GREEN)
480                     pixel[GREEN] = g;
481                   if (component_mask & GIMP_COMPONENT_MASK_BLUE)
482                     pixel[BLUE]  = b;
483                   if (component_mask & GIMP_COMPONENT_MASK_ALPHA)
484                     pixel[ALPHA] = a;
485                 }
486               else
487                 {
488                   pixel[RED]   = r;
489                   pixel[GREEN] = g;
490                   pixel[BLUE]  = b;
491                   pixel[ALPHA] = a;
492                 }
493 
494               pixel += 4;
495               if (mask)
496                 mask += 1;
497             }
498         }
499     }
500 
501   return 1;
502 }
503 
504 static void
gimp_mypaint_surface_begin_atomic(MyPaintSurface * base_surface)505 gimp_mypaint_surface_begin_atomic (MyPaintSurface *base_surface)
506 {
507 
508 }
509 
510 static void
gimp_mypaint_surface_end_atomic(MyPaintSurface * base_surface,MyPaintRectangle * roi)511 gimp_mypaint_surface_end_atomic (MyPaintSurface   *base_surface,
512                                  MyPaintRectangle *roi)
513 {
514   GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
515 
516   roi->x         = surface->dirty.x;
517   roi->y         = surface->dirty.y;
518   roi->width     = surface->dirty.width;
519   roi->height    = surface->dirty.height;
520   surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
521 }
522 
523 static void
gimp_mypaint_surface_destroy(MyPaintSurface * base_surface)524 gimp_mypaint_surface_destroy (MyPaintSurface *base_surface)
525 {
526   GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface;
527 
528   g_clear_object (&surface->buffer);
529   g_clear_object (&surface->paint_mask);
530 }
531 
532 GimpMybrushSurface *
gimp_mypaint_surface_new(GeglBuffer * buffer,GimpComponentMask component_mask,GeglBuffer * paint_mask,gint paint_mask_x,gint paint_mask_y,GimpMybrushOptions * options)533 gimp_mypaint_surface_new (GeglBuffer         *buffer,
534                           GimpComponentMask   component_mask,
535                           GeglBuffer         *paint_mask,
536                           gint                paint_mask_x,
537                           gint                paint_mask_y,
538                           GimpMybrushOptions *options)
539 {
540   GimpMybrushSurface *surface = g_malloc0 (sizeof (GimpMybrushSurface));
541 
542   mypaint_surface_init ((MyPaintSurface *)surface);
543 
544   surface->surface.get_color    = gimp_mypaint_surface_get_color;
545   surface->surface.draw_dab     = gimp_mypaint_surface_draw_dab;
546   surface->surface.begin_atomic = gimp_mypaint_surface_begin_atomic;
547   surface->surface.end_atomic   = gimp_mypaint_surface_end_atomic;
548   surface->surface.destroy      = gimp_mypaint_surface_destroy;
549   surface->component_mask       = component_mask;
550   surface->options              = options;
551   surface->buffer               = g_object_ref (buffer);
552   if (paint_mask)
553     surface->paint_mask         = g_object_ref (paint_mask);
554 
555   surface->paint_mask_x         = paint_mask_x;
556   surface->paint_mask_y         = paint_mask_y;
557   surface->dirty                = *GEGL_RECTANGLE (0, 0, 0, 0);
558 
559   return surface;
560 }
561