gimpadaptivesupersample.c 11.8 KB
Newer Older
1 2
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3
 *
4
 * This library is free software: you can redistribute it and/or
5 6
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
7
 * version 3 of the License, or (at your option) any later version.
8 9 10 11
 *
 * 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
12 13 14
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with this library.  If not, see
16
 * <https://www.gnu.org/licenses/>.
17 18 19 20
 */

#include "config.h"

21
#include <gegl.h>
22
#include <glib-object.h>
23

24
#include "libgimpmath/gimpmath.h"
25

26 27
#include "gimpcolortypes.h"

28
#include "gimpadaptivesupersample.h"
29
#include "gimprgb.h"
30 31


32
/**
33
 * SECTION: gimpadaptivesupersample
34 35 36 37 38 39 40 41
 * @title: GimpAdaptiveSupersample
 * @short_description: Functions to perform adaptive supersampling on
 *                     an area.
 *
 * Functions to perform adaptive supersampling on an area.
 **/


42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/*********************************************************************/
/* Sumpersampling code (Quartic)                                     */
/* This code is *largely* based on the sources for POV-Ray 3.0. I am */
/* grateful to the POV-Team for such a great program and for making  */
/* their sources available.  All comments / bug reports /            */
/* etc. regarding this code should be addressed to me, not to the    */
/* POV-Ray team.  Any bugs are my responsibility, not theirs.        */
/*********************************************************************/


typedef struct _GimpSampleType GimpSampleType;

struct _GimpSampleType
{
  guchar  ready;
  GimpRGB color;
};


static gulong
gimp_render_sub_pixel (gint             max_depth,
Sven Neumann's avatar
Sven Neumann committed
63 64 65 66 67 68 69 70 71 72 73 74 75
                       gint             depth,
                       GimpSampleType **block,
                       gint             x,
                       gint             y,
                       gint             x1,
                       gint             y1,
                       gint             x3,
                       gint             y3,
                       gdouble          threshold,
                       gint             sub_pixel_size,
                       GimpRGB         *color,
                       GimpRenderFunc   render_func,
                       gpointer         render_data)
76 77 78 79 80 81 82 83
{
  gint     x2, y2;          /* Coords of center sample */
  gdouble  dx1, dy1;        /* Delta to upper left sample */
  gdouble  dx3, dy3;        /* Delta to lower right sample */
  GimpRGB  c[4];            /* Sample colors */
  gulong   num_samples = 0;
  gint     cnt;

84 85
  g_return_val_if_fail (render_func != NULL, 0);

86 87 88 89 90 91 92 93 94 95 96 97 98 99
  /* Get offsets for corners */

  dx1 = (gdouble) (x1 - sub_pixel_size / 2) / sub_pixel_size;
  dx3 = (gdouble) (x3 - sub_pixel_size / 2) / sub_pixel_size;

  dy1 = (gdouble) (y1 - sub_pixel_size / 2) / sub_pixel_size;
  dy3 = (gdouble) (y3 - sub_pixel_size / 2) / sub_pixel_size;

  /* Render upper left sample */

  if (! block[y1][x1].ready)
    {
      num_samples++;

100
      render_func (x + dx1, y + dy1, &c[0], render_data);
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

      block[y1][x1].ready = TRUE;
      block[y1][x1].color = c[0];
    }
  else
    {
      c[0] = block[y1][x1].color;
    }

  /* Render upper right sample */

  if (! block[y1][x3].ready)
    {
      num_samples++;

116
      render_func (x + dx3, y + dy1, &c[1], render_data);
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131

      block[y1][x3].ready = TRUE;
      block[y1][x3].color = c[1];
    }
  else
    {
      c[1] = block[y1][x3].color;
    }

  /* Render lower left sample */

  if (! block[y3][x1].ready)
    {
      num_samples++;

132
      render_func (x + dx1, y + dy3, &c[2], render_data);
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

      block[y3][x1].ready = TRUE;
      block[y3][x1].color = c[2];
    }
  else
    {
      c[2] = block[y3][x1].color;
    }

  /* Render lower right sample */

  if (! block[y3][x3].ready)
    {
      num_samples++;

148
      render_func (x + dx3, y + dy3, &c[3], render_data);
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164

      block[y3][x3].ready = TRUE;
      block[y3][x3].color = c[3];
    }
  else
    {
      c[3] = block[y3][x3].color;
    }

  /* Check for supersampling */

  if (depth <= max_depth)
    {
      /* Check whether we have to supersample */

      if ((gimp_rgba_distance (&c[0], &c[1]) >= threshold) ||
Sven Neumann's avatar
Sven Neumann committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
          (gimp_rgba_distance (&c[0], &c[2]) >= threshold) ||
          (gimp_rgba_distance (&c[0], &c[3]) >= threshold) ||
          (gimp_rgba_distance (&c[1], &c[2]) >= threshold) ||
          (gimp_rgba_distance (&c[1], &c[3]) >= threshold) ||
          (gimp_rgba_distance (&c[2], &c[3]) >= threshold))
        {
          /* Calc coordinates of center subsample */

          x2 = (x1 + x3) / 2;
          y2 = (y1 + y3) / 2;

          /* Render sub-blocks */

          num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
                                                x, y, x1, y1, x2, y2,
                                                threshold, sub_pixel_size,
                                                &c[0],
                                                render_func, render_data);

          num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
                                                x, y, x2, y1, x3, y2,
                                                threshold, sub_pixel_size,
                                                &c[1],
                                                render_func, render_data);

          num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
                                                x, y, x1, y2, x2, y3,
                                                threshold, sub_pixel_size,
                                                &c[2],
                                                render_func, render_data);

          num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
                                                x, y, x2, y2, x3, y3,
                                                threshold, sub_pixel_size,
                                                &c[3],
                                                render_func, render_data);
        }
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
    }

  if (c[0].a == 0.0 || c[1].a == 0.0 || c[2].a == 0.0 || c[3].a == 0.0)
    {
      GimpRGB tmpcol;
      gdouble weight;

      gimp_rgb_set (&tmpcol, 0.0, 0.0, 0.0);

      weight = 2.0;

      for (cnt = 0; cnt < 4; cnt++)
        {
          if (c[cnt].a != 0.0)
            {
              tmpcol.r += c[cnt].r;
              tmpcol.g += c[cnt].g;
              tmpcol.b += c[cnt].b;

              weight /= 2.0;
            }
        }

      color->r = weight * tmpcol.r;
      color->g = weight * tmpcol.g;
      color->b = weight * tmpcol.b;
    }
  else
    {
      color->r = 0.25 * (c[0].r + c[1].r + c[2].r + c[3].r);
      color->g = 0.25 * (c[0].g + c[1].g + c[2].g + c[3].g);
      color->b = 0.25 * (c[0].b + c[1].b + c[2].b + c[3].b);
    }

  color->a = 0.25 * (c[0].a + c[1].a + c[2].a + c[3].a);

  return num_samples;
}

gulong
gimp_adaptive_supersample_area (gint              x1,
Sven Neumann's avatar
Sven Neumann committed
243 244 245 246 247 248 249 250 251 252 253
                                gint              y1,
                                gint              x2,
                                gint              y2,
                                gint              max_depth,
                                gdouble           threshold,
                                GimpRenderFunc    render_func,
                                gpointer          render_data,
                                GimpPutPixelFunc  put_pixel_func,
                                gpointer          put_pixel_data,
                                GimpProgressFunc  progress_func,
                                gpointer          progress_data)
254 255 256 257 258 259 260 261 262 263
{
  gint             x, y, width;                 /* Counters, width of region */
  gint             xt, xtt, yt;                 /* Temporary counters */
  gint             sub_pixel_size;              /* Number of samples per pixel (1D) */
  GimpRGB          color;                       /* Rendered pixel's color */
  GimpSampleType   tmp_sample;                  /* For swapping samples */
  GimpSampleType  *top_row, *bot_row, *tmp_row; /* Sample rows */
  GimpSampleType **block;                       /* Sample block matrix */
  gulong           num_samples;

264 265 266
  g_return_val_if_fail (render_func != NULL, 0);
  g_return_val_if_fail (put_pixel_func != NULL, 0);

267 268 269 270 271 272 273 274 275 276 277 278
  /* Initialize color */

  gimp_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);

  /* Calculate sub-pixel size */

  sub_pixel_size = 1 << max_depth;

  /* Create row arrays */

  width = x2 - x1 + 1;

279 280
  top_row = gegl_scratch_new (GimpSampleType, sub_pixel_size * width + 1);
  bot_row = gegl_scratch_new (GimpSampleType, sub_pixel_size * width + 1);
281 282 283 284 285 286 287 288 289 290 291 292 293 294

  for (x = 0; x < (sub_pixel_size * width + 1); x++)
    {
      top_row[x].ready = FALSE;

      gimp_rgba_set (&top_row[x].color, 0.0, 0.0, 0.0, 0.0);

      bot_row[x].ready = FALSE;

      gimp_rgba_set (&bot_row[x].color, 0.0, 0.0, 0.0, 0.0);
    }

  /* Allocate block matrix */

295
  block = gegl_scratch_new (GimpSampleType *, sub_pixel_size + 1); /* Rows */
296 297 298

  for (y = 0; y < (sub_pixel_size + 1); y++)
    {
299
      block[y] = gegl_scratch_new (GimpSampleType, sub_pixel_size + 1); /* Columns */
300 301

      for (x = 0; x < (sub_pixel_size + 1); x++)
Sven Neumann's avatar
Sven Neumann committed
302 303
        {
          block[y][x].ready = FALSE;
304

Sven Neumann's avatar
Sven Neumann committed
305 306
          gimp_rgba_set (&block[y][x].color, 0.0, 0.0, 0.0, 0.0);
        }
307 308 309 310 311 312 313 314 315 316 317
    }

  /* Render region */

  num_samples = 0;

  for (y = y1; y <= y2; y++)
    {
      /* Clear the bottom row */

      for (xt = 0; xt < (sub_pixel_size * width + 1); xt++)
Sven Neumann's avatar
Sven Neumann committed
318
        bot_row[xt].ready = FALSE;
319 320 321 322

      /* Clear first column */

      for (yt = 0; yt < (sub_pixel_size + 1); yt++)
Sven Neumann's avatar
Sven Neumann committed
323
        block[yt][0].ready = FALSE;
324 325 326 327

      /* Render row */

      for (x = x1; x <= x2; x++)
Sven Neumann's avatar
Sven Neumann committed
328 329
        {
          /* Initialize block by clearing all but first row/column */
330

Sven Neumann's avatar
Sven Neumann committed
331 332 333
          for (yt = 1; yt < (sub_pixel_size + 1); yt++)
            for (xt = 1; xt < (sub_pixel_size + 1); xt++)
              block[yt][xt].ready = FALSE;
334

Sven Neumann's avatar
Sven Neumann committed
335
          /* Copy samples from top row to block */
336

Sven Neumann's avatar
Sven Neumann committed
337 338 339 340
          for (xtt = 0, xt = (x - x1) * sub_pixel_size;
               xtt < (sub_pixel_size + 1);
               xtt++, xt++)
            block[0][xtt] = top_row[xt];
341

Sven Neumann's avatar
Sven Neumann committed
342
          /* Render pixel on (x, y) */
343

Sven Neumann's avatar
Sven Neumann committed
344 345 346 347 348
          num_samples += gimp_render_sub_pixel (max_depth, 1, block, x, y, 0, 0,
                                                sub_pixel_size, sub_pixel_size,
                                                threshold, sub_pixel_size,
                                                &color,
                                                render_func, render_data);
349

Sven Neumann's avatar
Sven Neumann committed
350 351
          if (put_pixel_func)
            (* put_pixel_func) (x, y, &color, put_pixel_data);
352

Sven Neumann's avatar
Sven Neumann committed
353
          /* Copy block information to rows */
354

Sven Neumann's avatar
Sven Neumann committed
355
          top_row[(x - x1 + 1) * sub_pixel_size] = block[0][sub_pixel_size];
356

Sven Neumann's avatar
Sven Neumann committed
357 358 359 360
          for (xtt = 0, xt = (x - x1) * sub_pixel_size;
               xtt < (sub_pixel_size + 1);
               xtt++, xt++)
            bot_row[xt] = block[sub_pixel_size][xtt];
361

Sven Neumann's avatar
Sven Neumann committed
362
          /* Swap first and last columns */
363

Sven Neumann's avatar
Sven Neumann committed
364 365 366 367 368 369 370
          for (yt = 0; yt < (sub_pixel_size + 1); yt++)
            {
              tmp_sample                = block[yt][0];
              block[yt][0]              = block[yt][sub_pixel_size];
              block[yt][sub_pixel_size] = tmp_sample;
            }
        }
371 372 373 374 375 376 377 378 379 380

      /* Swap rows */

      tmp_row = top_row;
      top_row = bot_row;
      bot_row = tmp_row;

      /* Call progress display function (if any) */

      if (progress_func != NULL)
Sven Neumann's avatar
Sven Neumann committed
381
        (* progress_func) (y1, y2, y, progress_data);
382 383 384 385 386
    }

  /* Free memory */

  for (y = 0; y < (sub_pixel_size + 1); y++)
387
    gegl_scratch_free (block[y]);
388

389 390 391
  gegl_scratch_free (block);
  gegl_scratch_free (top_row);
  gegl_scratch_free (bot_row);
392 393 394

  return num_samples;
}