Blame gegl/buffer/gegl-tile-handler-zoom.c

Packit Service 2781ba
/* This file is part of GEGL.
Packit Service 2781ba
 *
Packit Service 2781ba
 * This library is free software; you can redistribute it and/or
Packit Service 2781ba
 * modify it under the terms of the GNU Lesser General Public
Packit Service 2781ba
 * License as published by the Free Software Foundation; either
Packit Service 2781ba
 * version 3 of the License, or (at your option) any later version.
Packit Service 2781ba
 *
Packit Service 2781ba
 * This library is distributed in the hope that it will be useful,
Packit Service 2781ba
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2781ba
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2781ba
 * Lesser General Public License for more details.
Packit Service 2781ba
 *
Packit Service 2781ba
 * You should have received a copy of the GNU Lesser General Public
Packit Service 2781ba
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Copyright 2006,2007 Øyvind Kolås <pippin@gimp.org>
Packit Service 2781ba
 */
Packit Service 2781ba
#include "config.h"
Packit Service 2781ba
#include <glib.h>
Packit Service 2781ba
#include <glib-object.h>
Packit Service 2781ba
#include <string.h>
Packit Service 2781ba
Packit Service 2781ba
#include "gegl-types.h"
Packit Service 2781ba
#include "gegl-matrix.h"
Packit Service 2781ba
#include "gegl-buffer-types.h"
Packit Service 2781ba
#include "gegl-buffer-private.h"
Packit Service 2781ba
#include "gegl-tile-handler.h"
Packit Service 2781ba
#include "gegl-tile-handler-zoom.h"
Packit Service 2781ba
#include "gegl-tile-handler-cache.h"
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
G_DEFINE_TYPE (GeglTileHandlerZoom, gegl_tile_handler_zoom, GEGL_TYPE_TILE_HANDLER)
Packit Service 2781ba
Packit Service 2781ba
#include <babl/babl.h>
Packit Service 2781ba
#include "gegl-tile-backend.h"
Packit Service 2781ba
#include "gegl-tile-storage.h"
Packit Service 2781ba
Packit Service 2781ba
void gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
Packit Service 2781ba
                                     GeglTile             *tile,
Packit Service 2781ba
                                     gint                  x,
Packit Service 2781ba
                                     gint                  y,
Packit Service 2781ba
                                     gint                  z);
Packit Service 2781ba
static inline void set_blank (GeglTile   *dst_tile,
Packit Service 2781ba
                              gint        width,
Packit Service 2781ba
                              gint        height,
Packit Service 2781ba
                              const Babl *format,
Packit Service 2781ba
                              gint        i,
Packit Service 2781ba
                              gint        j)
Packit Service 2781ba
{
Packit Service 2781ba
  guchar *dst_data  = gegl_tile_get_data (dst_tile);
Packit Service 2781ba
  gint    bpp       = babl_format_get_bytes_per_pixel (format);
Packit Service 2781ba
  gint    rowstride = width * bpp;
Packit Service 2781ba
  gint    scanline;
Packit Service 2781ba
Packit Service 2781ba
  gint    bytes = width * bpp / 2;
Packit Service 2781ba
  guchar *dst   = dst_data + j * height / 2 * rowstride + i * rowstride / 2;
Packit Service 2781ba
Packit Service 2781ba
  for (scanline = 0; scanline < height / 2; scanline++)
Packit Service 2781ba
    {
Packit Service 2781ba
      memset (dst, 0x0, bytes);
Packit Service 2781ba
      dst += rowstride;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* fixme: make the api of this, as well as blank be the
Packit Service 2781ba
 * same as the downscale functions */
Packit Service 2781ba
static inline void set_half_nearest (GeglTile   *dst_tile,
Packit Service 2781ba
                                     GeglTile   *src_tile,
Packit Service 2781ba
                                     gint        width,
Packit Service 2781ba
                                     gint        height,
Packit Service 2781ba
                                     const Babl *format,
Packit Service 2781ba
                                     gint        i,
Packit Service 2781ba
                                     gint        j)
Packit Service 2781ba
{
Packit Service 2781ba
  guchar *dst_data = gegl_tile_get_data (dst_tile);
Packit Service 2781ba
  guchar *src_data = gegl_tile_get_data (src_tile);
Packit Service 2781ba
  gint    bpp      = babl_format_get_bytes_per_pixel (format);
Packit Service 2781ba
  gint    x, y;
Packit Service 2781ba
Packit Service 2781ba
  for (y = 0; y < height / 2; y++)
Packit Service 2781ba
    {
Packit Service 2781ba
      guchar *dst = dst_data +
Packit Service 2781ba
                    (
Packit Service 2781ba
        (
Packit Service 2781ba
          (y + j * (height / 2)) * width
Packit Service 2781ba
        ) + i * (width / 2)
Packit Service 2781ba
                    ) * bpp;
Packit Service 2781ba
Packit Service 2781ba
      guchar *src = src_data + (y * 2 * width) * bpp;
Packit Service 2781ba
Packit Service 2781ba
      for (x = 0; x < width / 2; x++)
Packit Service 2781ba
        {
Packit Service 2781ba
          memcpy (dst, src, bpp);
Packit Service 2781ba
          dst += bpp;
Packit Service 2781ba
          src += bpp * 2;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static inline void
Packit Service 2781ba
downscale_float (gint    components,
Packit Service 2781ba
                 gint    width,
Packit Service 2781ba
                 gint    height,
Packit Service 2781ba
                 gint    rowstride,
Packit Service 2781ba
                 guchar *src_data,
Packit Service 2781ba
                 guchar *dst_data)
Packit Service 2781ba
{
Packit Service 2781ba
  gint y;
Packit Service 2781ba
Packit Service 2781ba
  if (!src_data || !dst_data)
Packit Service 2781ba
    return;
Packit Service 2781ba
  for (y = 0; y < height / 2; y++)
Packit Service 2781ba
    {
Packit Service 2781ba
      gint    x;
Packit Service 2781ba
      gfloat *dst = (gfloat *) (dst_data + y * rowstride);
Packit Service 2781ba
      gfloat *src = (gfloat *) (src_data + y * 2 * rowstride);
Packit Service 2781ba
Packit Service 2781ba
      for (x = 0; x < width / 2; x++)
Packit Service 2781ba
        {
Packit Service 2781ba
          int i;
Packit Service 2781ba
          for (i = 0; i < components; i++)
Packit Service 2781ba
            dst[i] = (src[i] +
Packit Service 2781ba
                      src[i + components] +
Packit Service 2781ba
                      src[i + (width * components)] +
Packit Service 2781ba
                      src[i + (width + 1) * components]) /
Packit Service 2781ba
                     4.0;
Packit Service 2781ba
Packit Service 2781ba
          dst += components;
Packit Service 2781ba
          src += components * 2;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static inline void
Packit Service 2781ba
downscale_u8 (gint    components,
Packit Service 2781ba
              gint    width,
Packit Service 2781ba
              gint    height,
Packit Service 2781ba
              gint    rowstride,
Packit Service 2781ba
              guchar *src_data,
Packit Service 2781ba
              guchar *dst_data)
Packit Service 2781ba
{
Packit Service 2781ba
  gint y;
Packit Service 2781ba
Packit Service 2781ba
  if (!src_data || !dst_data)
Packit Service 2781ba
    return;
Packit Service 2781ba
  for (y = 0; y < height / 2; y++)
Packit Service 2781ba
    {
Packit Service 2781ba
      gint    x;
Packit Service 2781ba
      guchar *dst = dst_data + y * rowstride;
Packit Service 2781ba
      guchar *src = src_data + y * 2 * rowstride;
Packit Service 2781ba
Packit Service 2781ba
      for (x = 0; x < width / 2; x++)
Packit Service 2781ba
        {
Packit Service 2781ba
          int i;
Packit Service 2781ba
          for (i = 0; i < components; i++)
Packit Service 2781ba
            dst[i] = (src[i] +
Packit Service 2781ba
                      src[i + components] +
Packit Service 2781ba
                      src[i + rowstride] +
Packit Service 2781ba
                      src[i + rowstride + components]) /
Packit Service 2781ba
                     4;
Packit Service 2781ba
Packit Service 2781ba
          dst += components;
Packit Service 2781ba
          src += components * 2;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static inline void set_half (GeglTile   * dst_tile,
Packit Service 2781ba
                             GeglTile   * src_tile,
Packit Service 2781ba
                             gint         width,
Packit Service 2781ba
                             gint         height,
Packit Service 2781ba
                             const Babl * format,
Packit Service 2781ba
                             gint i,
Packit Service 2781ba
                             gint j)
Packit Service 2781ba
{
Packit Service 2781ba
  guchar *dst_data   = gegl_tile_get_data (dst_tile);
Packit Service 2781ba
  guchar *src_data   = gegl_tile_get_data (src_tile);
Packit Service 2781ba
  gint    components = babl_format_get_n_components (format);
Packit Service 2781ba
  gint    bpp        = babl_format_get_bytes_per_pixel (format);
Packit Service 2781ba
Packit Service 2781ba
  if (i) dst_data += bpp * width / 2;
Packit Service 2781ba
  if (j) dst_data += bpp * width * height / 2;
Packit Service 2781ba
Packit Service 2781ba
  if (babl_format_get_type (format, 0) == babl_type ("float"))
Packit Service 2781ba
    {
Packit Service 2781ba
      downscale_float (components, width, height, width * bpp, src_data, dst_data);
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (babl_format_get_type (format, 0) == babl_type ("u8"))
Packit Service 2781ba
    {
Packit Service 2781ba
      downscale_u8 (components, width, height, width * bpp, src_data, dst_data);
Packit Service 2781ba
    }
Packit Service 2781ba
  else
Packit Service 2781ba
    {
Packit Service 2781ba
      set_half_nearest (dst_tile, src_tile, width, height, format, i, j);
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static GeglTile *
Packit Service 2781ba
get_tile (GeglTileSource *gegl_tile_source,
Packit Service 2781ba
          gint            x,
Packit Service 2781ba
          gint            y,
Packit Service 2781ba
          gint            z)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglTileSource      *source = ((GeglTileHandler*)(gegl_tile_source))->source;
Packit Service 2781ba
  GeglTileHandlerZoom *zoom   = (GeglTileHandlerZoom*)(gegl_tile_source);
Packit Service 2781ba
  GeglTile            *tile   = NULL;
Packit Service 2781ba
  const Babl          *format = gegl_tile_backend_get_format (zoom->backend);
Packit Service 2781ba
  gint                 tile_width;
Packit Service 2781ba
  gint                 tile_height;
Packit Service 2781ba
  gint                 tile_size;
Packit Service 2781ba
Packit Service 2781ba
  if (source)
Packit Service 2781ba
    {
Packit Service 2781ba
      tile = gegl_tile_source_get_tile (source, x, y, z);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (tile)
Packit Service 2781ba
    return tile;
Packit Service 2781ba
Packit Service 2781ba
  if (z == 0)/* at base level with no tile found->send null, and shared empty
Packit Service 2781ba
               tile will be used instead */
Packit Service 2781ba
    {
Packit Service 2781ba
      return NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (z>zoom->tile_storage->seen_zoom)
Packit Service 2781ba
    zoom->tile_storage->seen_zoom = z;
Packit Service 2781ba
Packit Service 2781ba
  g_assert (zoom->backend);
Packit Service 2781ba
  g_object_get (zoom->backend, "tile-width", &tile_width,
Packit Service 2781ba
                "tile-height", &tile_height,
Packit Service 2781ba
                "tile-size", &tile_size,
Packit Service 2781ba
                NULL);
Packit Service 2781ba
Packit Service 2781ba
  {
Packit Service 2781ba
    gint      i, j;
Packit Service 2781ba
    GeglTile *source_tile[2][2] = { { NULL, NULL }, { NULL, NULL } };
Packit Service 2781ba
Packit Service 2781ba
    for (i = 0; i < 2; i++)
Packit Service 2781ba
      for (j = 0; j < 2; j++)
Packit Service 2781ba
        {
Packit Service 2781ba
          /* we get the tile from ourselves, to make successive rescales work
Packit Service 2781ba
           * correctly */
Packit Service 2781ba
            source_tile[i][j] = gegl_tile_source_get_tile (gegl_tile_source,
Packit Service 2781ba
                                                          x * 2 + i, y * 2 + j, z - 1);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
    if (source_tile[0][0] == NULL &&
Packit Service 2781ba
        source_tile[0][1] == NULL &&
Packit Service 2781ba
        source_tile[1][0] == NULL &&
Packit Service 2781ba
        source_tile[1][1] == NULL)
Packit Service 2781ba
      {
Packit Service 2781ba
        return NULL;   /* no data from level below, return NULL and let GeglTileHandlerEmpty
Packit Service 2781ba
                          fill in the shared empty tile */
Packit Service 2781ba
      }
Packit Service 2781ba
Packit Service 2781ba
    g_assert (tile == NULL);
Packit Service 2781ba
    if (tile == NULL)
Packit Service 2781ba
      {
Packit Service 2781ba
        tile = gegl_tile_new (tile_size);
Packit Service 2781ba
Packit Service 2781ba
        tile->x = x;
Packit Service 2781ba
        tile->y = y;
Packit Service 2781ba
        tile->z = z;
Packit Service 2781ba
        tile->tile_storage = zoom->tile_storage;
Packit Service 2781ba
Packit Service 2781ba
        if (zoom->cache)
Packit Service 2781ba
          gegl_tile_handler_cache_insert (zoom->cache, tile, x, y, z);
Packit Service 2781ba
      }
Packit Service 2781ba
    gegl_tile_lock (tile);
Packit Service 2781ba
Packit Service 2781ba
    for (i = 0; i < 2; i++)
Packit Service 2781ba
      for (j = 0; j < 2; j++)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (source_tile[i][j])
Packit Service 2781ba
            {
Packit Service 2781ba
              set_half (tile, source_tile[i][j], tile_width, tile_height, format, i, j);
Packit Service 2781ba
              gegl_tile_unref (source_tile[i][j]);
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              set_blank (tile, tile_width, tile_height, format, i, j);
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
    gegl_tile_unlock (tile);
Packit Service 2781ba
  }
Packit Service 2781ba
Packit Service 2781ba
  return tile;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static gpointer
Packit Service 2781ba
gegl_tile_handler_zoom_command (GeglTileSource  *tile_store,
Packit Service 2781ba
                                GeglTileCommand  command,
Packit Service 2781ba
                                gint             x,
Packit Service 2781ba
                                gint             y,
Packit Service 2781ba
                                gint             z,
Packit Service 2781ba
                                gpointer         data)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglTileHandler *handler  = (void*)tile_store;
Packit Service 2781ba
Packit Service 2781ba
  if (command == GEGL_TILE_GET)
Packit Service 2781ba
    return get_tile (tile_store, x, y, z);
Packit Service 2781ba
  else
Packit Service 2781ba
    return gegl_tile_handler_source_command (handler, command, x, y, z, data);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_tile_handler_zoom_class_init (GeglTileHandlerZoomClass *klass)
Packit Service 2781ba
{
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_tile_handler_zoom_init (GeglTileHandlerZoom *self)
Packit Service 2781ba
{
Packit Service 2781ba
  ((GeglTileSource*)self)->command = gegl_tile_handler_zoom_command;
Packit Service 2781ba
  self->backend = NULL;
Packit Service 2781ba
  self->tile_storage = NULL;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
GeglTileHandler *
Packit Service 2781ba
gegl_tile_handler_zoom_new (GeglTileBackend      *backend,
Packit Service 2781ba
                            GeglTileStorage      *tile_storage,
Packit Service 2781ba
                            GeglTileHandlerCache *cache)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglTileHandlerZoom *ret = g_object_new (GEGL_TYPE_TILE_HANDLER_ZOOM, NULL);
Packit Service 2781ba
  ((GeglTileSource*)ret)->command = gegl_tile_handler_zoom_command;
Packit Service 2781ba
  ret->backend = backend;
Packit Service 2781ba
  ret->tile_storage = tile_storage;
Packit Service 2781ba
  ret->cache = cache;
Packit Service 2781ba
  return (void*)ret;
Packit Service 2781ba
}