1 /* This file is part of GEGL
2  *
3  * GEGL is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as
5  * published by the Free Software Foundation; either version 3 of the
6  * License, or (at your option) any later version.
7  *
8  * GEGL is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
11  * Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with GEGL; if not, see
15  * <https://www.gnu.org/licenses/>.
16  *
17  * 2007 © Øyvind Kolås
18  * 2009,2012 © Nicolas Robidoux
19  * 2011 © Adam Turcotte
20  */
21 #include "config.h"
22 
23 #include <glib-object.h>
24 #include <string.h>
25 #include <math.h>
26 
27 #include "gegl-buffer.h"
28 #include "gegl-buffer-types.h"
29 #include "gegl-buffer-private.h"
30 
31 #include "gegl-sampler-nearest.h"
32 #include "gegl-sampler-linear.h"
33 #include "gegl-sampler-cubic.h"
34 #include "gegl-sampler-nohalo.h"
35 #include "gegl-sampler-lohalo.h"
36 #include "gegl-buffer-formats.h"
37 
38 
39 enum
40 {
41   PROP_0,
42   PROP_BUFFER,
43   PROP_FORMAT,
44   PROP_LEVEL,
45   PROP_CONTEXT_RECT,
46   PROP_LAST
47 };
48 
49 static void gegl_sampler_class_init (GeglSamplerClass    *klass);
50 
51 static void gegl_sampler_init       (GeglSampler         *self);
52 
53 static void finalize                (GObject             *gobject);
54 
55 static void dispose                 (GObject             *gobject);
56 
57 static void get_property            (GObject             *gobject,
58                                      guint                property_id,
59                                      GValue              *value,
60                                      GParamSpec          *pspec);
61 
62 static void set_property            (GObject             *gobject,
63                                      guint                property_id,
64                                      const GValue        *value,
65                                      GParamSpec          *pspec);
66 
67 static void set_buffer              (GeglSampler         *self,
68                                      GeglBuffer          *buffer);
69 
70 static void buffer_contents_changed (GeglBuffer          *buffer,
71                                      const GeglRectangle *changed_rect,
72                                      gpointer             userdata);
73 
74 static void constructed (GObject *sampler);
75 
76 static GType gegl_sampler_gtype_from_enum  (GeglSamplerType      sampler_type);
77 
G_DEFINE_TYPE(GeglSampler,gegl_sampler,G_TYPE_OBJECT)78 G_DEFINE_TYPE (GeglSampler, gegl_sampler, G_TYPE_OBJECT)
79 
80 static void
81 gegl_sampler_class_init (GeglSamplerClass *klass)
82 {
83   GObjectClass *object_class = G_OBJECT_CLASS (klass);
84 
85   object_class->finalize = finalize;
86   object_class->dispose  = dispose;
87   object_class->constructed  = constructed;
88 
89   klass->prepare     = NULL;
90   klass->get         = NULL;
91   klass->interpolate = NULL;
92   klass->set_buffer  = set_buffer;
93 
94   object_class->set_property = set_property;
95   object_class->get_property = get_property;
96 
97   g_object_class_install_property (
98                  object_class,
99                  PROP_FORMAT,
100                  g_param_spec_pointer ("format",
101                                        "format",
102                                        "babl format",
103                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
104 
105   g_object_class_install_property (
106                  object_class,
107                  PROP_LEVEL,
108                  g_param_spec_int ("level",
109                                    "level",
110                                    "mimmap level to sample from",
111                                    0, 100, 0,
112                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
113 
114   g_object_class_install_property (
115                    object_class,
116                    PROP_BUFFER,
117                    g_param_spec_object ("buffer",
118                                         "Buffer",
119                                         "Input pad, for image buffer input.",
120                                         GEGL_TYPE_BUFFER,
121                                         G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
122 }
123 
124 static void
gegl_sampler_init(GeglSampler * sampler)125 gegl_sampler_init (GeglSampler *sampler)
126 {
127   gint i = 0;
128   sampler->buffer = NULL;
129   do {
130     GeglRectangle context_rect      = {0,0,1,1};
131     GeglRectangle sampler_rectangle = {0,0,0,0};
132     sampler->level[i].sampler_buffer = NULL;
133     sampler->level[i].context_rect   = context_rect;
134     sampler->level[i].sampler_rectangle = sampler_rectangle;
135   } while ( ++i<GEGL_SAMPLER_MIPMAP_LEVELS );
136 
137   sampler->level[0].sampler_buffer =
138     g_malloc (GEGL_SAMPLER_MAXIMUM_WIDTH *
139               GEGL_SAMPLER_MAXIMUM_HEIGHT * 5 * 4); // XXX : maxes out at 5 components
140 }
141 
142 static void
constructed(GObject * self)143 constructed (GObject *self)
144 {
145   GeglSampler *sampler = (void*)(self);
146   GeglSamplerClass *klass = GEGL_SAMPLER_GET_CLASS (sampler);
147 
148   sampler->get         = klass->get;
149   sampler->interpolate = klass->interpolate;
150 
151   if (sampler->buffer)
152     {
153       GeglSamplerLevel *level = &sampler->level[0];
154 
155       level->abyss_rect = sampler->buffer->abyss;
156 
157       level->abyss_rect.x      -= level->context_rect.x +
158                                   level->context_rect.width;
159       level->abyss_rect.y      -= level->context_rect.y +
160                                   level->context_rect.height;
161       level->abyss_rect.width  += level->context_rect.width  + 1;
162       level->abyss_rect.height += level->context_rect.height + 1;
163     }
164 }
165 
166 void
gegl_sampler_get(GeglSampler * self,gdouble x,gdouble y,GeglBufferMatrix2 * scale,void * output,GeglAbyssPolicy repeat_mode)167 gegl_sampler_get (GeglSampler       *self,
168                   gdouble            x,
169                   gdouble            y,
170                   GeglBufferMatrix2 *scale,
171                   void              *output,
172                   GeglAbyssPolicy    repeat_mode)
173 {
174   if (G_UNLIKELY(!isfinite (x)))
175     x = 0.0;
176   if (G_UNLIKELY(!isfinite (y)))
177     y = 0.0;
178 
179   if (G_UNLIKELY (self->lvel))
180   {
181     double factor = 1.0 / (1 << self->lvel);
182     GeglRectangle rect={int_floorf (x * factor), int_floorf (y * factor),1,1};
183     gegl_buffer_get (self->buffer, &rect, factor, self->format, output, GEGL_AUTO_ROWSTRIDE, repeat_mode);
184     return;
185   }
186 
187   if (G_UNLIKELY (gegl_buffer_ext_flush))
188     {
189       GeglRectangle rect={x,y,1,1};
190       gegl_buffer_ext_flush (self->buffer, &rect);
191     }
192   self->get (self, x, y, scale, output, repeat_mode);
193 }
194 
195 void
gegl_sampler_prepare(GeglSampler * self)196 gegl_sampler_prepare (GeglSampler *self)
197 {
198   GeglSamplerClass *klass;
199 
200   g_return_if_fail (GEGL_IS_SAMPLER (self));
201 
202   klass = GEGL_SAMPLER_GET_CLASS (self);
203 
204   if (!self->buffer) /* happens when extent of sampler is queried */
205     return;
206   if (!self->format)
207     self->format = self->buffer->soft_format;
208 
209   if (klass->prepare)
210     klass->prepare (self);
211 
212   {
213     const Babl *model = babl_format_get_model (self->format);
214 
215     if (babl_model_is (model, "Y")||
216         babl_model_is (model, "Y'")||
217         babl_model_is (model, "Y~")||
218         babl_model_is (model, "YA")||
219         babl_model_is (model, "YaA")||
220         babl_model_is (model, "Y'aA")||
221         babl_model_is (model, "Y'A")||
222         babl_model_is (model, "Y~A"))
223     {
224        self->interpolate_format = babl_format_with_space ("YaA float",
225                                      gegl_buffer_get_format(self->buffer));
226     }
227     else if (babl_model_is (model, "cmyk")||
228              babl_model_is (model, "cmykA") ||
229              babl_model_is (model, "camayakaA"))
230     {
231        self->interpolate_format = babl_format_with_space ("camayakaA float",
232                                      gegl_buffer_get_format(self->buffer));
233     }
234     else if (
235         babl_model_is (model, "CMYK")||
236         babl_model_is (model, "CMYKA") ||
237         babl_model_is (model, "CaMaYaKaA"))
238     {
239        self->interpolate_format = babl_format_with_space ("CaMaYaKaA float",
240                                      gegl_buffer_get_format(self->buffer));
241     }
242 #if 0
243     else if (babl_model_is (model, "RGB")||
244         babl_model_is (model, "R'G'B'")||
245         babl_model_is (model, "R~G~B~") ||
246         babl_model_is (model, "RGBA")||
247         babl_model_is (model, "R'G'B'A")||
248         babl_model_is (model, "R~G~B~A")||
249         babl_model_is (model, "RaGaBaA")||
250         babl_model_is (model, "R'aG'aB'aA")||
251         babl_model_is (model, "R~aG~aB~aA"))
252     {
253        self->interpolate_format = babl_format_with_space ("RaGaBaA float",
254                                      gegl_buffer_get_format(self->buffer));
255     }
256 #endif
257     else
258     {
259        self->interpolate_format = babl_format_with_space ("RaGaBaA float",
260                                      gegl_buffer_get_format(self->buffer));
261     }
262 
263     self->interpolate_bpp = babl_format_get_bytes_per_pixel (self->interpolate_format);
264     self->interpolate_components = babl_format_get_n_components (self->interpolate_format);
265   }
266 
267   if (!self->fish)
268     self->fish = babl_fish (self->interpolate_format, self->format);
269 
270   /*
271    * This makes the cache rect invalid, in case the data in the buffer
272    * has changed:
273    */
274   self->level[0].sampler_rectangle.width = 0;
275   self->level[0].sampler_rectangle.height = 0;
276 }
277 
278 void
gegl_sampler_set_buffer(GeglSampler * self,GeglBuffer * buffer)279 gegl_sampler_set_buffer (GeglSampler *self, GeglBuffer *buffer)
280 {
281   GeglSamplerClass *klass;
282 
283   g_return_if_fail (GEGL_IS_SAMPLER (self));
284 
285   klass = GEGL_SAMPLER_GET_CLASS (self);
286 
287   if (klass->set_buffer)
288     klass->set_buffer (self, buffer);
289 }
290 
291 static void
finalize(GObject * gobject)292 finalize (GObject *gobject)
293 {
294   GeglSampler *sampler = GEGL_SAMPLER (gobject);
295   int i = 0;
296   do {
297     if (sampler->level[i].sampler_buffer)
298       {
299         g_free (sampler->level[i].sampler_buffer);
300         sampler->level[i].sampler_buffer = NULL;
301       }
302   } while ( ++i<GEGL_SAMPLER_MIPMAP_LEVELS );
303   G_OBJECT_CLASS (gegl_sampler_parent_class)->finalize (gobject);
304 }
305 
306 static void
dispose(GObject * gobject)307 dispose (GObject *gobject)
308 {
309   GeglSampler *sampler = GEGL_SAMPLER (gobject);
310 
311   /* This call handles unreffing the buffer and disconnecting signals */
312   set_buffer (sampler, NULL);
313 
314   G_OBJECT_CLASS (gegl_sampler_parent_class)->dispose (gobject);
315 }
316 
317 
318 gfloat *
gegl_sampler_get_from_mipmap(GeglSampler * sampler,gint x,gint y,gint level_no,GeglAbyssPolicy repeat_mode)319 gegl_sampler_get_from_mipmap (GeglSampler    *sampler,
320                               gint            x,
321                               gint            y,
322                               gint            level_no,
323                               GeglAbyssPolicy repeat_mode)
324 {
325   GeglSamplerLevel *level = &sampler->level[level_no];
326   guchar *buffer_ptr;
327   gint    dx;
328   gint    dy;
329   gint    sof;
330 
331   const gdouble scale = 1. / ((gdouble) (1 << level_no));
332 
333   const gint maximum_width  = GEGL_SAMPLER_MAXIMUM_WIDTH;
334   const gint maximum_height = GEGL_SAMPLER_MAXIMUM_HEIGHT;
335 
336   if (G_UNLIKELY (gegl_buffer_ext_flush))
337     {
338       GeglRectangle rect = {x, y, 1, 1};
339       gegl_buffer_ext_flush (sampler->buffer, &rect);
340     }
341 
342   g_assert (level_no >= 0 && level_no < GEGL_SAMPLER_MIPMAP_LEVELS);
343   g_assert (level->context_rect.width  <= maximum_width);
344   g_assert (level->context_rect.height <= maximum_height);
345 
346   if ((level->sampler_buffer == NULL)                               ||
347       (x + level->context_rect.x < level->sampler_rectangle.x)      ||
348       (y + level->context_rect.y < level->sampler_rectangle.y)      ||
349       (x + level->context_rect.x + level->context_rect.width >
350        level->sampler_rectangle.x + level->sampler_rectangle.width) ||
351       (y + level->context_rect.y + level->context_rect.height >
352        level->sampler_rectangle.y + level->sampler_rectangle.height))
353     {
354       /*
355        * fetch_rectangle will become the value of
356        * sampler->sampler_rectangle[level]:
357        */
358       level->sampler_rectangle = _gegl_sampler_compute_rectangle (sampler, x, y,
359                                                                   level_no);
360       if (!level->sampler_buffer)
361         level->sampler_buffer =
362           g_malloc (GEGL_SAMPLER_MAXIMUM_WIDTH * sampler->interpolate_bpp * GEGL_SAMPLER_MAXIMUM_HEIGHT);
363 
364       gegl_buffer_get (sampler->buffer,
365                        &level->sampler_rectangle,
366                        scale,
367                        sampler->interpolate_format,
368                        level->sampler_buffer,
369                        GEGL_SAMPLER_MAXIMUM_WIDTH * sampler->interpolate_bpp,
370                        repeat_mode);
371     }
372 
373   dx         = x - level->sampler_rectangle.x;
374   dy         = y - level->sampler_rectangle.y;
375   buffer_ptr = (guchar *) level->sampler_buffer;
376   sof        = (dx + dy * GEGL_SAMPLER_MAXIMUM_WIDTH) * sampler->interpolate_bpp;
377 
378   return (gfloat*) (buffer_ptr + sof);
379 }
380 
381 static void
get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)382 get_property (GObject    *object,
383               guint       property_id,
384               GValue     *value,
385               GParamSpec *pspec)
386 {
387   GeglSampler *self = GEGL_SAMPLER (object);
388 
389   switch (property_id)
390     {
391       case PROP_BUFFER:
392         g_value_set_object (value, self->buffer);
393         break;
394 
395       case PROP_FORMAT:
396         g_value_set_pointer (value, (void*)self->format);
397         break;
398 
399       case PROP_LEVEL:
400         g_value_set_int (value, self->lvel);
401         break;
402 
403       default:
404         break;
405     }
406 }
407 
408 static void
set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)409 set_property (GObject      *object,
410               guint         property_id,
411               const GValue *value,
412               GParamSpec   *pspec)
413 {
414   GeglSampler *self = GEGL_SAMPLER (object);
415 
416   switch (property_id)
417     {
418       case PROP_BUFFER:
419         gegl_sampler_set_buffer (self, GEGL_BUFFER (g_value_get_object (value)));
420         break;
421 
422       case PROP_FORMAT:
423         self->format = g_value_get_pointer (value);
424         break;
425 
426       case PROP_LEVEL:
427         self->lvel = g_value_get_int  (value);
428         break;
429 
430       default:
431         break;
432     }
433 }
434 
435 static void
set_buffer(GeglSampler * self,GeglBuffer * buffer)436 set_buffer (GeglSampler *self, GeglBuffer *buffer)
437 {
438   if (self->buffer != buffer)
439     {
440       if (GEGL_IS_BUFFER (self->buffer))
441         {
442           g_signal_handlers_disconnect_by_func (self->buffer,
443                                                 G_CALLBACK (buffer_contents_changed),
444                                                 self);
445           self->buffer->changed_signal_connections--;
446           g_object_remove_weak_pointer ((GObject*) self->buffer, (void**) &self->buffer);
447         }
448 
449       if (GEGL_IS_BUFFER (buffer))
450         {
451           self->buffer = buffer;
452           g_object_add_weak_pointer ((GObject*) self->buffer, (void**) &self->buffer);
453           gegl_buffer_signal_connect (buffer, "changed",
454                                       G_CALLBACK (buffer_contents_changed),
455                                       self);
456         }
457       else
458         self->buffer = NULL;
459 
460       buffer_contents_changed (buffer, NULL, self);
461     }
462 }
463 
464 static inline GType
gegl_sampler_gtype_from_enum(GeglSamplerType sampler_type)465 gegl_sampler_gtype_from_enum (GeglSamplerType sampler_type)
466 {
467   switch (sampler_type)
468     {
469       case GEGL_SAMPLER_NEAREST:
470         return GEGL_TYPE_SAMPLER_NEAREST;
471       case GEGL_SAMPLER_LINEAR:
472         return GEGL_TYPE_SAMPLER_LINEAR;
473       case GEGL_SAMPLER_CUBIC:
474         return GEGL_TYPE_SAMPLER_CUBIC;
475       case GEGL_SAMPLER_NOHALO:
476         return GEGL_TYPE_SAMPLER_NOHALO;
477       case GEGL_SAMPLER_LOHALO:
478         return GEGL_TYPE_SAMPLER_LOHALO;
479       default:
480         return GEGL_TYPE_SAMPLER_LINEAR;
481     }
482 }
483 
484 static inline void
_gegl_buffer_sample_at_level(GeglBuffer * buffer,gdouble x,gdouble y,GeglBufferMatrix2 * scale,gpointer dest,const Babl * format,gint level,GeglSamplerType sampler_type,GeglAbyssPolicy repeat_mode)485 _gegl_buffer_sample_at_level (GeglBuffer        *buffer,
486                               gdouble            x,
487                               gdouble            y,
488                               GeglBufferMatrix2 *scale,
489                               gpointer           dest,
490                               const Babl        *format,
491                               gint               level,
492                               GeglSamplerType    sampler_type,
493                               GeglAbyssPolicy    repeat_mode)
494 {
495   GeglSampler *sampler;
496 
497   if (sampler_type == GEGL_SAMPLER_NEAREST &&
498       level == 0)
499     {
500       GeglRectangle rect = {x, y, 1, 1};
501       gegl_buffer_get (buffer, &rect, 1.0,
502                        format, dest, GEGL_AUTO_ROWSTRIDE,
503                        repeat_mode);
504       return;
505     }
506 
507   if (G_UNLIKELY (!format))
508     format = buffer->soft_format;
509 
510   sampler = gegl_buffer_sampler_new_at_level (buffer,
511                                               format, sampler_type, level);
512 
513   gegl_sampler_get (sampler, x, y, scale, dest, repeat_mode);
514 
515   g_object_unref (sampler);
516 }
517 
518 void
gegl_buffer_sample_at_level(GeglBuffer * buffer,gdouble x,gdouble y,GeglBufferMatrix2 * scale,gpointer dest,const Babl * format,gint level,GeglSamplerType sampler_type,GeglAbyssPolicy repeat_mode)519 gegl_buffer_sample_at_level (GeglBuffer        *buffer,
520                              gdouble            x,
521                              gdouble            y,
522                              GeglBufferMatrix2 *scale,
523                              gpointer           dest,
524                              const Babl        *format,
525                              gint               level,
526                              GeglSamplerType    sampler_type,
527                              GeglAbyssPolicy    repeat_mode)
528 {
529   _gegl_buffer_sample_at_level (buffer, x, y, scale, dest,
530                                 format, level, sampler_type, repeat_mode);
531 }
532 
533 
534 void
gegl_buffer_sample(GeglBuffer * buffer,gdouble x,gdouble y,GeglBufferMatrix2 * scale,gpointer dest,const Babl * format,GeglSamplerType sampler_type,GeglAbyssPolicy repeat_mode)535 gegl_buffer_sample (GeglBuffer        *buffer,
536                     gdouble            x,
537                     gdouble            y,
538                     GeglBufferMatrix2 *scale,
539                     gpointer           dest,
540                     const Babl        *format,
541                     GeglSamplerType    sampler_type,
542                     GeglAbyssPolicy    repeat_mode)
543 {
544   _gegl_buffer_sample_at_level (buffer, x, y, scale, dest, format, 0, sampler_type, repeat_mode);
545 }
546 
547 void
gegl_buffer_sample_cleanup(GeglBuffer * buffer)548 gegl_buffer_sample_cleanup (GeglBuffer *buffer)
549 {
550   /* this is a nop.  we used to have a per-buffer cached sampler, for use by
551    * gegl_buffer_sample[_at_level](), which this function would clear, but we
552    * don't anymore.
553    */
554 }
555 
556 GeglSampler *
gegl_buffer_sampler_new_at_level(GeglBuffer * buffer,const Babl * format,GeglSamplerType sampler_type,gint level)557 gegl_buffer_sampler_new_at_level (GeglBuffer      *buffer,
558                                   const Babl      *format,
559                                   GeglSamplerType  sampler_type,
560                                   gint             level)
561 {
562   GeglSampler *sampler;
563   GType        desired_type;
564 
565   if (format == NULL)
566   {
567     format = gegl_babl_rgbA_linear_float ();
568   }
569 
570   desired_type = gegl_sampler_gtype_from_enum (sampler_type);
571 
572   sampler = g_object_new (desired_type,
573                           "buffer", buffer,
574                           "format", format,
575                           "level", level,
576                           NULL);
577 
578   gegl_sampler_prepare (sampler);
579 
580   return sampler;
581 }
582 
583 GeglSampler *
gegl_buffer_sampler_new(GeglBuffer * buffer,const Babl * format,GeglSamplerType sampler_type)584 gegl_buffer_sampler_new (GeglBuffer      *buffer,
585                          const Babl      *format,
586                          GeglSamplerType  sampler_type)
587 {
588   return gegl_buffer_sampler_new_at_level (buffer, format, sampler_type, 0);
589 }
590 
591 
592 const GeglRectangle*
gegl_sampler_get_context_rect(GeglSampler * sampler)593 gegl_sampler_get_context_rect (GeglSampler *sampler)
594 {
595   return &(sampler->level[0].context_rect);
596 }
597 
598 static void
buffer_contents_changed(GeglBuffer * buffer,const GeglRectangle * changed_rect,gpointer userdata)599 buffer_contents_changed (GeglBuffer          *buffer,
600                          const GeglRectangle *changed_rect,
601                          gpointer             userdata)
602 {
603   GeglSampler *self = GEGL_SAMPLER (userdata);
604   int i;
605 
606   /*
607    * Invalidate all mipmap levels by setting the width and height of the
608    * rectangles to zero. The x and y coordinates do not matter any more, so we
609    * can just call memset to do this.
610    * XXX: it might be faster to only invalidate rects that intersect
611    *      changed_rect
612    */
613   for (i = 0; i < GEGL_SAMPLER_MIPMAP_LEVELS; i++)
614     memset (&self->level[i].sampler_rectangle, 0, sizeof (self->level[0].sampler_rectangle));
615 
616   return;
617 }
618 
gegl_sampler_get_fun(GeglSampler * sampler)619 GeglSamplerGetFun gegl_sampler_get_fun (GeglSampler *sampler)
620 {
621   /* this flushes the buffer in preparation for the use of the sampler,
622    * thus one can consider the handed out sampler function only temporarily
623    * available*/
624   if (gegl_buffer_ext_flush)
625     gegl_buffer_ext_flush (sampler->buffer, NULL);
626   return sampler->get;
627 }
628 
629