gegl-tile-handler-zoom.c 5.9 KB
Newer Older
1 2 3 4 5
/* This file is part of GEGL.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
6
 * version 3 of the License, or (at your option) any later version.
7 8 9 10 11 12 13
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
14
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
15
 *
16
 * Copyright 2006,2007 Øyvind Kolås <pippin@gimp.org>
17
 */
18

19
#include "config.h"
20

21 22
#include <string.h>

23 24 25
#include <babl/babl.h>
#include <glib-object.h>

26 27 28
#include "gegl-types.h"
#include "gegl-buffer-types.h"
#include "gegl-buffer-private.h"
29 30
#include "gegl-tile-handler.h"
#include "gegl-tile-handler-cache.h"
31 32
#include "gegl-tile-handler-private.h"
#include "gegl-tile-handler-zoom.h"
33
#include "gegl-tile-backend.h"
34
#include "gegl-tile-storage.h"
35
#include "gegl-algorithms.h"
36

37 38 39 40

G_DEFINE_TYPE (GeglTileHandlerZoom, gegl_tile_handler_zoom,
               GEGL_TYPE_TILE_HANDLER)

41 42 43 44 45 46
static inline void set_blank (GeglTile   *dst_tile,
                              gint        width,
                              gint        height,
                              const Babl *format,
                              gint        i,
                              gint        j)
47
{
48
  guchar *dst_data  = gegl_tile_get_data (dst_tile);
49
  gint    bpp       = babl_format_get_bytes_per_pixel (format);
50 51 52 53 54
  gint    rowstride = width * bpp;
  gint    scanline;

  gint    bytes = width * bpp / 2;
  guchar *dst   = dst_data + j * height / 2 * rowstride + i * rowstride / 2;
55

56
  for (scanline = 0; scanline < height / 2; scanline++)
57
    {
58
      memset (dst, 0x0, bytes);
59
      dst += rowstride;
60 61 62
    }
}

63 64
static inline void set_half (GeglTileHandlerZoom *zoom,
                             GeglTile   * dst_tile,
65 66 67 68
                             GeglTile   * src_tile,
                             gint         width,
                             gint         height,
                             const Babl * format,
69 70
                             gint i,
                             gint j)
71
{
72 73 74
  guchar     *dst_data   = gegl_tile_get_data (dst_tile);
  guchar     *src_data   = gegl_tile_get_data (src_tile);
  gint        bpp        = babl_format_get_bytes_per_pixel (format);
75

76 77
  if (i) dst_data += bpp * width / 2;
  if (j) dst_data += bpp * width * height / 2;
78

79 80 81 82
  if (!zoom->downscale_2x2)
    zoom->downscale_2x2 = gegl_downscale_2x2_get_fun (format);

  zoom->downscale_2x2 (format, width, height, src_data, width * bpp, dst_data, width * bpp);
83 84 85
}

static GeglTile *
86 87 88 89
get_tile (GeglTileSource *gegl_tile_source,
          gint            x,
          gint            y,
          gint            z)
90
{
91 92
  GeglTileSource      *source = ((GeglTileHandler *) gegl_tile_source)->source;
  GeglTileHandlerZoom *zoom   = (GeglTileHandlerZoom *) gegl_tile_source;
93
  GeglTile            *tile   = NULL;
94
  GeglTileStorage     *tile_storage;
95 96
  gint                 tile_width;
  gint                 tile_height;
97

98
  if (source)
99
    tile = gegl_tile_source_get_tile (source, x, y, z);
100

101
  if (tile || (z == 0))
102
    return tile;
103

104
  tile_storage = _gegl_tile_handler_get_tile_storage ((GeglTileHandler *) zoom);
105

106 107 108
  if (z > tile_storage->seen_zoom)
    tile_storage->seen_zoom = z;

109 110
  tile_width = tile_storage->tile_width;
  tile_height = tile_storage->tile_height;
111 112

  {
113 114 115
    gint        i, j;
    const Babl *format = gegl_tile_backend_get_format (zoom->backend);
    GeglTile   *source_tile[2][2] = { { NULL, NULL }, { NULL, NULL } };
116 117 118

    for (i = 0; i < 2; i++)
      for (j = 0; j < 2; j++)
119
        {
120 121
          /* we get the tile from ourselves, to make successive rescales work
           * correctly */
122
            source_tile[i][j] = gegl_tile_source_get_tile (gegl_tile_source,
123
                                                          x * 2 + i, y * 2 + j, z - 1);
124
        }
125

126 127 128 129 130
    if (source_tile[0][0] == NULL &&
        source_tile[0][1] == NULL &&
        source_tile[1][0] == NULL &&
        source_tile[1][1] == NULL)
      {
131
        return NULL;   /* no data from level below, return NULL and let GeglTileHandlerEmpty
132 133 134
                          fill in the shared empty tile */
      }

135
    g_assert (tile == NULL);
136

137
    tile = gegl_tile_handler_create_tile (GEGL_TILE_HANDLER (zoom), x, y, z);
138

139 140 141 142
    gegl_tile_lock (tile);

    for (i = 0; i < 2; i++)
      for (j = 0; j < 2; j++)
143
        {
144
          if (source_tile[i][j])
145
            {
146
              set_half (zoom, tile, source_tile[i][j], tile_width, tile_height, format, i, j);
147
              gegl_tile_unref (source_tile[i][j]);
148
            }
149
          else
150 151 152
            {
              set_blank (tile, tile_width, tile_height, format, i, j);
            }
153
        }
154 155
    gegl_tile_unlock (tile);
  }
156

157 158 159
  return tile;
}

160
static gpointer
161 162 163 164 165 166
gegl_tile_handler_zoom_command (GeglTileSource  *tile_store,
                                GeglTileCommand  command,
                                gint             x,
                                gint             y,
                                gint             z,
                                gpointer         data)
167 168
{
  GeglTileHandler *handler  = (void*)tile_store;
169

170 171 172 173
  if (command == GEGL_TILE_GET)
    return get_tile (tile_store, x, y, z);
  else
    return gegl_tile_handler_source_command (handler, command, x, y, z, data);
174 175
}

176
static void
177
gegl_tile_handler_zoom_class_init (GeglTileHandlerZoomClass *klass)
178 179 180 181
{
}

static void
182
gegl_tile_handler_zoom_init (GeglTileHandlerZoom *self)
183
{
184
  ((GeglTileSource *) self)->command = gegl_tile_handler_zoom_command;
185
}
186 187

GeglTileHandler *
188
gegl_tile_handler_zoom_new (GeglTileBackend *backend)
189
{
190
  GeglTileHandlerZoom *ret = g_object_new (GEGL_TYPE_TILE_HANDLER_ZOOM, NULL);
191

192
  ret->backend = backend;
193

194 195
  return (void*)ret;
}