gimpdisplayshell-render.c 20.4 KB
Newer Older
<
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
Sven Neumann's avatar
Sven Neumann committed
18 19 20

#include "config.h"

Elliot Lee's avatar
Elliot Lee committed
21 22
#include <stdlib.h>
#include <string.h>
23

Sven Neumann's avatar
Sven Neumann committed
24 25
#include <gtk/gtk.h>

26
#include "libgimpbase/gimpbase.h"
27 28
#include "libgimpwidgets/gimpwidgets.h"

29
#include "display-types.h"
Sven Neumann's avatar
Sven Neumann committed
30

Michael Natterer's avatar
Michael Natterer committed
31 32 33
#include "base/tile-manager.h"
#include "base/tile.h"

34
#include "core/gimp.h"
35
#include "core/gimpimage.h"
36
#include "core/gimpimage-colormap.h"
Michael Natterer's avatar
Michael Natterer committed
37
#include "core/gimpprojection.h"
38

39 40
#include "widgets/gimprender.h"

41
#include "gimpcanvas.h"
42
#include "gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
43
#include "gimpdisplayshell.h"
44
#include "gimpdisplayshell-filter.h"
45
#include "gimpdisplayshell-render.h"
46

Elliot Lee's avatar
Elliot Lee committed
47 48

typedef struct _RenderInfo  RenderInfo;
49 50

typedef void (* RenderFunc) (RenderInfo *info);
Elliot Lee's avatar
Elliot Lee committed
51 52 53

struct _RenderInfo
{
54 55 56 57 58 59 60 61
  GimpDisplayShell *shell;
  TileManager      *src_tiles;
  guint            *alpha;
  guchar           *scale;
  guchar           *src;
  guchar           *dest;
  gint              x, y;
  gint              w, h;
62 63
  gdouble           scalex;
  gdouble           scaley;
64 65 66 67 68
  gint              src_x, src_y;
  gint              src_bpp;
  gint              dest_bpp;
  gint              dest_bpl;
  gint              dest_width;
Elliot Lee's avatar
Elliot Lee committed
69 70 71
};


72
static void   render_setup_notify (gpointer    config,
73 74 75 76
                                   GParamSpec *param_spec,
                                   Gimp       *gimp);


77 78 79 80
static guchar *tile_buf    = NULL;
static guint   tile_shift  = 0;
static guint   check_mod   = 0;
static guint   check_shift = 0;
81

Elliot Lee's avatar
Elliot Lee committed
82 83

void
84
gimp_display_shell_render_init (Gimp *gimp)
85 86 87
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

88
  g_signal_connect (gimp->config, "notify::transparency-size",
89 90
                    G_CALLBACK (render_setup_notify),
                    gimp);
91
  g_signal_connect (gimp->config, "notify::transparency-type",
92 93 94
                    G_CALLBACK (render_setup_notify),
                    gimp);

95
  render_setup_notify (gimp->config, NULL, gimp);
96 97 98
}

void
99
gimp_display_shell_render_exit (Gimp *gimp)
100 101 102
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

103
  g_signal_handlers_disconnect_by_func (gimp->config,
104 105 106 107 108 109 110 111 112 113 114 115
                                        render_setup_notify,
                                        gimp);

  if (tile_buf)
    {
      g_free (tile_buf);
      tile_buf = NULL;
    }
}


static void
116
render_setup_notify (gpointer    config,
117 118
                     GParamSpec *param_spec,
                     Gimp       *gimp)
Elliot Lee's avatar
Elliot Lee committed
119
{
120
  GimpCheckSize check_size;
121

122 123 124
  g_object_get (config,
                "transparency-size", &check_size,
                NULL);
Elliot Lee's avatar
Elliot Lee committed
125 126 127 128

  /*  based on the tile size, determine the tile shift amount
   *  (assume here that tile_height and tile_width are equal)
   */
Daniel Egger's avatar
Daniel Egger committed
129 130 131
  tile_shift = 0;
  while ((1 << tile_shift) < TILE_WIDTH)
    tile_shift++;
Elliot Lee's avatar
Elliot Lee committed
132 133

  /*  allocate a buffer for arranging information from a row of tiles  */
134
  if (! tile_buf)
135
    tile_buf = g_new (guchar, GIMP_RENDER_BUF_WIDTH * MAX_CHANNELS);
Elliot Lee's avatar
Elliot Lee committed
136 137 138

  switch (check_size)
    {
139
    case GIMP_CHECK_SIZE_SMALL_CHECKS:
140
      check_mod   = 0x3;
Elliot Lee's avatar
Elliot Lee committed
141 142
      check_shift = 2;
      break;
143
    case GIMP_CHECK_SIZE_MEDIUM_CHECKS:
144
      check_mod   = 0x7;
Elliot Lee's avatar
Elliot Lee committed
145 146
      check_shift = 3;
      break;
147
    case GIMP_CHECK_SIZE_LARGE_CHECKS:
148
      check_mod   = 0xf;
Elliot Lee's avatar
Elliot Lee committed
149 150 151 152 153
      check_shift = 4;
      break;
    }
}

154

Elliot Lee's avatar
Elliot Lee committed
155 156
/*  Render Image functions  */

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
static void     render_image_rgb                (RenderInfo       *info);
static void     render_image_rgb_a              (RenderInfo       *info);
static void     render_image_gray               (RenderInfo       *info);
static void     render_image_gray_a             (RenderInfo       *info);
static void     render_image_indexed            (RenderInfo       *info);
static void     render_image_indexed_a          (RenderInfo       *info);

static void     render_image_init_info          (RenderInfo       *info,
						 GimpDisplayShell *shell,
						 gint              x,
						 gint              y,
						 gint              w,
						 gint              h);
static guint  * render_image_init_alpha         (gint              mult);
static guchar * render_image_accelerate_scaling (gint              width,
						 gint              start,
173
						 gdouble           scalex);
174
static guchar * render_image_tile_fault         (RenderInfo       *info);
Elliot Lee's avatar
Elliot Lee committed
175 176


177
static RenderFunc render_funcs[6] =
Elliot Lee's avatar
Elliot Lee committed
178
{
179 180 181 182 183 184
  render_image_rgb,
  render_image_rgb_a,
  render_image_gray,
  render_image_gray_a,
  render_image_indexed,
  render_image_indexed_a,
Elliot Lee's avatar
Elliot Lee committed
185 186 187
};


188 189 190 191 192 193 194 195
static void  gimp_display_shell_render_highlight (GimpDisplayShell *shell,
                                                  gint              x,
                                                  gint              y,
                                                  gint              w,
                                                  gint              h,
                                                  GdkRectangle     *highlight);


Elliot Lee's avatar
Elliot Lee committed
196 197 198 199 200 201 202 203
/*****************************************************************/
/*  This function is the core of the display--it offsets and     */
/*  scales the image according to the current parameters in the  */
/*  gdisp object.  It handles color, grayscale, 8, 15, 16, 24,   */
/*  & 32 bit output depths.                                      */
/*****************************************************************/

void
204 205 206 207
gimp_display_shell_render (GimpDisplayShell *shell,
                           gint              x,
                           gint              y,
                           gint              w,
208 209
                           gint              h,
                           GdkRectangle     *highlight)
Elliot Lee's avatar
Elliot Lee committed
210
{
211
  RenderInfo     info;
212
  GimpImageType  type;
213

Sven Neumann's avatar
Sven Neumann committed
214 215
  g_return_if_fail (w > 0 && h > 0);

216
  render_image_init_info (&info, shell, x, y, w, h);
Elliot Lee's avatar
Elliot Lee committed
217

218
  type = gimp_projection_get_image_type (shell->gdisp->gimage->projection);
219

220
  g_return_if_fail ((info.dest_bpp >= 1) && (info.dest_bpp <= 4));
Elliot Lee's avatar
Elliot Lee committed
221

222
  /* Currently, only RGBA and GRAYA projection types are used - the rest
223 224
   * are in case of future need.  -- austin, 28th Nov 1998.
   */
225 226
  if (G_UNLIKELY (type != GIMP_RGBA_IMAGE && type != GIMP_GRAYA_IMAGE))
    g_warning ("using untested projection type %d", type);
227

228
  (* render_funcs[type]) (&info);
229 230

  /*  apply filters to the rendered projection  */
231 232 233 234 235
  if (shell->filter_stack)
    gimp_color_display_stack_convert (shell->filter_stack,
                                      shell->render_buf,
                                      w, h,
                                      3,
236
                                      3 * GIMP_RENDER_BUF_WIDTH);
237

238 239 240 241
  /*  dim pixels outside the highlighted rectangle  */
  if (highlight)
    gimp_display_shell_render_highlight (shell, x, y, w, h, highlight);

242
  /*  put it to the screen  */
243 244 245 246
  gimp_canvas_draw_rgb (GIMP_CANVAS (shell->canvas), GIMP_CANVAS_STYLE_RENDER,
                        x + shell->disp_xoffset, y + shell->disp_yoffset,
                        w, h,
                        shell->render_buf,
247
                        3 * GIMP_RENDER_BUF_WIDTH,
248
                        shell->offset_x, shell->offset_y);
Elliot Lee's avatar
Elliot Lee committed
249 250 251
}


252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
#define GIMP_DISPLAY_SHELL_DIM_PIXEL(buf,x) \
{ \
  buf[3 * (x) + 0] >>= 1; \
  buf[3 * (x) + 1] >>= 1; \
  buf[3 * (x) + 2] >>= 1; \
}

/*  This function highlights the given area by dimming all pixels outside. */

static void
gimp_display_shell_render_highlight (GimpDisplayShell *shell,
                                     gint              x,
                                     gint              y,
                                     gint              w,
                                     gint              h,
                                     GdkRectangle     *highlight)
{
  guchar       *buf  = shell->render_buf;
  GdkRectangle  rect;

  rect.x      = shell->offset_x + x;
  rect.y      = shell->offset_y + y;
  rect.width  = w;
  rect.height = h;

  if (gdk_rectangle_intersect (highlight, &rect, &rect))
    {
      rect.x -= shell->offset_x + x;
      rect.y -= shell->offset_y + y;

      for (y = 0; y < rect.y; y++)
        {
          for (x = 0; x < w; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

287
          buf += 3 * GIMP_RENDER_BUF_WIDTH;
288 289 290 291 292 293 294 295 296 297
        }

      for ( ; y < rect.y + rect.height; y++)
        {
          for (x = 0; x < rect.x; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

          for (x += rect.width; x < w; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

298
          buf += 3 * GIMP_RENDER_BUF_WIDTH;
299 300 301 302 303 304 305
        }

      for ( ; y < h; y++)
        {
          for (x = 0; x < w; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

306
          buf += 3 * GIMP_RENDER_BUF_WIDTH;
307 308 309 310 311 312 313 314 315
        }
    }
  else
    {
      for (y = 0; y < h; y++)
        {
          for (x = 0; x < w; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

316
          buf += 3 * GIMP_RENDER_BUF_WIDTH;
317 318 319 320 321
        }
    }
}


Elliot Lee's avatar
Elliot Lee committed
322 323 324 325 326
/*************************/
/*  8 Bit functions      */
/*************************/

static void
327
render_image_indexed (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
328
{
329 330 331
  const guchar *cmap;
  gint          y, ye;
  gint          x, xe;
332
  gboolean      initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
333

334
  cmap = gimp_image_get_colormap (info->shell->gdisp->gimage);
Elliot Lee's avatar
Elliot Lee committed
335

336
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
337 338 339 340 341
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
342
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
343
    {
344 345
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
346 347

      if (!initial && (error == 0))
348 349 350
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
351 352
      else
	{
353 354
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
Elliot Lee's avatar
Elliot Lee committed
355

356 357
	  for (x = info->x; x < xe; x++)
	    {
358 359
              guint  val = src[INDEXED_PIX] * 3;

360
	      src += 1;
361

362 363 364
	      dest[0] = cmap[val + 0];
	      dest[1] = cmap[val + 1];
	      dest[2] = cmap[val + 2];
365 366
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
367 368
	}

Sven Neumann's avatar
Sven Neumann committed
369 370
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
371

Sven Neumann's avatar
Sven Neumann committed
372
      info->dest += info->dest_bpl;
373

Sven Neumann's avatar
Sven Neumann committed
374
      if (error)
Elliot Lee's avatar
Elliot Lee committed
375
	{
376
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
377
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
378

379
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
380
	}
Sven Neumann's avatar
Sven Neumann committed
381 382 383 384
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
385 386 387 388
    }
}

static void
389
render_image_indexed_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
390
{
391 392 393 394
  const guint  *alpha = info->alpha;
  const guchar *cmap;
  gint          y, ye;
  gint          x, xe;
395
  gboolean      initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
396

397
  cmap = gimp_image_get_colormap (info->shell->gdisp->gimage);
398
  alpha = info->alpha;
Elliot Lee's avatar
Elliot Lee committed
399

400
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
401 402 403 404 405
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
406
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
407
    {
408 409
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
410 411

      if (!initial && (error == 0) && (y & check_mod))
412 413 414
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
415 416
      else
	{
417 418 419
          const guchar *src  = info->src;
          guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
420

421 422 423 424
	  dark_light = (y >> check_shift) + (info->x >> check_shift);

	  for (x = info->x; x < xe; x++)
	    {
425 426 427
	      guint r, g, b, a = alpha[src[ALPHA_I_PIX]];
              guint val        = src[INDEXED_PIX] * 3;

428 429 430 431
	      src += 2;

	      if (dark_light & 0x1)
		{
432 433 434
		  r = gimp_render_blend_dark_check[(a | cmap[val + 0])];
		  g = gimp_render_blend_dark_check[(a | cmap[val + 1])];
		  b = gimp_render_blend_dark_check[(a | cmap[val + 2])];
435 436 437
		}
	      else
		{
438 439 440
		  r = gimp_render_blend_light_check[(a | cmap[val + 0])];
		  g = gimp_render_blend_light_check[(a | cmap[val + 1])];
		  b = gimp_render_blend_light_check[(a | cmap[val + 2])];
441 442 443 444 445
		}

		dest[0] = r;
		dest[1] = g;
		dest[2] = b;
Elliot Lee's avatar
Elliot Lee committed
446 447
		dest += 3;

448 449
		if (((x + 1) & check_mod) == 0)
		  dark_light += 1;
Elliot Lee's avatar
Elliot Lee committed
450 451 452
	      }
	}

Sven Neumann's avatar
Sven Neumann committed
453 454
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
455

Sven Neumann's avatar
Sven Neumann committed
456
      info->dest += info->dest_bpl;
457

Sven Neumann's avatar
Sven Neumann committed
458
      if (error)
Elliot Lee's avatar
Elliot Lee committed
459
	{
460
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
461
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
462

463
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
464
	}
Sven Neumann's avatar
Sven Neumann committed
465 466 467 468
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
469 470 471 472
    }
}

static void
473
render_image_gray (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
474
{
475 476
  gint      y, ye;
  gint      x, xe;
477
  gboolean  initial = TRUE;
478 479

  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
480 481 482 483 484
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
485
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
486
    {
487 488
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
489 490

      if (!initial && (error == 0))
491 492 493
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
494 495
      else
	{
496 497
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
498

499 500
	  for (x = info->x; x < xe; x++)
	    {
501 502
	      guint val = src[GRAY_PIX];

503
	      src += 1;
Elliot Lee's avatar
Elliot Lee committed
504

505 506 507 508 509
	      dest[0] = val;
	      dest[1] = val;
	      dest[2] = val;
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
510 511
	}

Sven Neumann's avatar
Sven Neumann committed
512 513
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
514

Sven Neumann's avatar
Sven Neumann committed
515
      info->dest += info->dest_bpl;
516

Sven Neumann's avatar
Sven Neumann committed
517
      if (error)
Elliot Lee's avatar
Elliot Lee committed
518
	{
519
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
520
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
521

522
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
523
	}
Sven Neumann's avatar
Sven Neumann committed
524 525 526 527
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
528 529 530 531
    }
}

static void
532
render_image_gray_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
533
{
534 535 536
  const guint *alpha = info->alpha;
  gint         y, ye;
  gint         x, xe;
537
  gboolean     initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
538

539
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
540 541 542 543 544
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
545
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
546
    {
547 548
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
549 550

      if (!initial && (error == 0) && (y & check_mod))
551 552 553
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
554 555
      else
	{
556 557 558
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
559 560 561

	  dark_light = (y >> check_shift) + (info->x >> check_shift);

562 563
	  for (x = info->x; x < xe; x++)
	    {
564 565 566
	      guint a = alpha[src[ALPHA_G_PIX]];
              guint val;

567
	      if (dark_light & 0x1)
568
		val = gimp_render_blend_dark_check[(a | src[GRAY_PIX])];
569
	      else
570
		val = gimp_render_blend_light_check[(a | src[GRAY_PIX])];
571

572 573 574 575 576 577 578 579 580 581
	      src += 2;

	      dest[0] = val;
	      dest[1] = val;
	      dest[2] = val;
	      dest += 3;

	      if (((x + 1) & check_mod) == 0)
		dark_light += 1;
	    }
Elliot Lee's avatar
Elliot Lee committed
582 583
	}

Sven Neumann's avatar
Sven Neumann committed
584 585
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
586

Sven Neumann's avatar
Sven Neumann committed
587
      info->dest += info->dest_bpl;
588

Sven Neumann's avatar
Sven Neumann committed
589
      if (error)
Elliot Lee's avatar
Elliot Lee committed
590
	{
591
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
592
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
593

594
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
595
	}
Sven Neumann's avatar
Sven Neumann committed
596 597 598 599
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
600 601 602 603
    }
}

static void
604
render_image_rgb (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
605
{
606 607
  gint      y, ye;
  gint      xe;
608
  gboolean  initial = TRUE;
609 610

  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
611 612 613
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
614 615
  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
616
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
617
    {
618 619
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
620 621

      if (!initial && (error == 0))
622 623 624
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
625 626
      else
	{
627
          memcpy (info->dest, info->src, 3 * info->w);
Elliot Lee's avatar
Elliot Lee committed
628 629
	}

Sven Neumann's avatar
Sven Neumann committed
630 631
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
632

Sven Neumann's avatar
Sven Neumann committed
633
      info->dest += info->dest_bpl;
634

635
      if (error)
Elliot Lee's avatar
Elliot Lee committed
636
	{
637
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
638
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
639

640
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
641
	}
Sven Neumann's avatar
Sven Neumann committed
642 643 644 645
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
646 647 648 649
    }
}

static void
650
render_image_rgb_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
651
{
652 653 654
  const guint *alpha = info->alpha;
  gint         y, ye;
  gint         x, xe;
655
  gint         initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
656

657
  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
658 659 660
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
661 662
  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
663
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
664
    {
665 666
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
667 668

      if (!initial && (error == 0) && (y & check_mod))
669 670 671
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
672 673
      else
	{
674 675 676
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
677 678 679

	  dark_light = (y >> check_shift) + (info->x >> check_shift);

680 681
	  for (x = info->x; x < xe; x++)
	    {
682 683
              guint r, g, b, a = alpha[src[ALPHA_PIX]];

684 685
	      if (dark_light & 0x1)
		{
686 687 688
		  r = gimp_render_blend_dark_check[(a | src[RED_PIX])];
		  g = gimp_render_blend_dark_check[(a | src[GREEN_PIX])];
		  b = gimp_render_blend_dark_check[(a | src[BLUE_PIX])];
689 690 691
		}
	      else
		{
692 693 694
		  r = gimp_render_blend_light_check[(a | src[RED_PIX])];
		  g = gimp_render_blend_light_check[(a | src[GREEN_PIX])];
		  b = gimp_render_blend_light_check[(a | src[BLUE_PIX])];
695
		}
Elliot Lee's avatar
Elliot Lee committed
696

697
	      src += 4;
Elliot Lee's avatar
Elliot Lee committed
698

699 700 701 702
	      dest[0] = r;
	      dest[1] = g;
	      dest[2] = b;
	      dest += 3;
Elliot Lee's avatar
Elliot Lee committed
703

704 705 706
	      if (((x + 1) & check_mod) == 0)
		dark_light += 1;
	    }
Elliot Lee's avatar
Elliot Lee committed
707 708
	}

Sven Neumann's avatar
Sven Neumann committed
709 710
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
711

Sven Neumann's avatar
Sven Neumann committed
712
      info->dest += info->dest_bpl;
713

Sven Neumann's avatar
Sven Neumann committed
714
      if (error)
Elliot Lee's avatar
Elliot Lee committed
715
	{
716
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
717
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
718

719
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
720
	}
Sven Neumann's avatar
Sven Neumann committed
721 722 723 724
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
725 726 727 728
    }
}

static void
729 730 731 732 733 734
render_image_init_info (RenderInfo       *info,
			GimpDisplayShell *shell,
			gint              x,
			gint              y,
			gint              w,
			gint              h)
Elliot Lee's avatar
Elliot Lee committed
735
{
Michael Natterer's avatar
Michael Natterer committed
736 737
  GimpImage *gimage = shell->gdisp->gimage;

738
  info->shell      = shell;
Michael Natterer's avatar
Michael Natterer committed
739
  info->src_tiles  = gimp_projection_get_tiles (gimage->projection);
740 741
  info->x          = x + shell->offset_x;
  info->y          = y + shell->offset_y;
742 743
  info->w          = w;
  info->h          = h;
744 745
  info->scalex     = SCALEFACTOR_X (shell);
  info->scaley     = SCALEFACTOR_Y (shell);
746 747
  info->src_x      = (gdouble) info->x / info->scalex;
  info->src_y      = (gdouble) info->y / info->scaley;
Michael Natterer's avatar
Michael Natterer committed
748
  info->src_bpp    = gimp_projection_get_bytes (gimage->projection);
749 750
  info->dest       = shell->render_buf;
  info->dest_bpp   = 3;
751
  info->dest_bpl   = info->dest_bpp * GIMP_RENDER_BUF_WIDTH;
Elliot Lee's avatar
Elliot Lee committed
752
  info->dest_width = info->w * info->dest_bpp;
Sven Neumann's avatar
Sven Neumann committed
753 754
  info->scale      = render_image_accelerate_scaling (w,
                                                      info->x, info->scalex);
755
  info->alpha      = NULL;
Elliot Lee's avatar
Elliot Lee committed
756

Michael Natterer's avatar
Michael Natterer committed
757
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_projection_get_image_type (gimage->projection)))
Elliot Lee's avatar
Elliot Lee committed
758
    {
759
      info->alpha =
Michael Natterer's avatar
Michael Natterer committed
760
	render_image_init_alpha (gimp_projection_get_opacity (gimage->projection) * 255.999);
Elliot Lee's avatar
Elliot Lee committed
761 762 763
    }
}

764
static guint *
765
render_image_init_alpha (gint mult)
Elliot Lee's avatar
Elliot Lee committed
766 767
{
  static guint *alpha_mult = NULL;
768 769 770
  static gint   alpha_val  = -1;

  gint i;
Elliot Lee's avatar
Elliot Lee committed
771 772 773 774

  if (alpha_val != mult)
    {
      if (!alpha_mult)
775
	alpha_mult = g_new (guint, 256);
Elliot Lee's avatar
Elliot Lee committed
776 777 778 779 780 781 782 783 784

      alpha_val = mult;
      for (i = 0; i < 256; i++)
	alpha_mult[i] = ((mult * i) / 255) << 8;
    }

  return alpha_mult;
}

785
static guchar *
786 787 788
render_image_accelerate_scaling (gint    width,
				 gint    start,
				 gdouble scalex)
Elliot Lee's avatar
Elliot Lee committed
789 790
{
  static guchar *scale = NULL;
791

792
  gint  i;
Elliot Lee's avatar
Elliot Lee committed
793

794
  if (! scale)
795
    scale = g_new (guchar, GIMP_RENDER_BUF_WIDTH + 1);
Elliot Lee's avatar
Elliot Lee committed
796

797
  for (i = 0; i <= width; i++)
798
    {
799 800
      scale[i] = RINT (floor ((start + 1) / scalex) - floor (start / scalex));
      start++;
801
    }
Elliot Lee's avatar
Elliot Lee committed
802 803 804 805

  return scale;
}

806
static guchar *
Elliot Lee's avatar
Elliot Lee committed
807 808
render_image_tile_fault (RenderInfo *info)
{
809
  Tile         *tile;
Sven Neumann's avatar
Sven Neumann committed
810
  const guchar *src;
811 812 813 814 815 816
  const guchar *scale;
  guchar       *dest;
  gint          width;
  gint          tilex;
  gint          step;
  gint          bpp = info->src_bpp;
Sven Neumann's avatar
Sven Neumann committed
817
  gint          x;
Elliot Lee's avatar
Elliot Lee committed
818

819
  tile = tile_manager_get_tile (info->src_tiles,
820 821
				info->src_x, info->src_y, TRUE, FALSE);

Sven Neumann's avatar
Sven Neumann committed
822
  g_return_val_if_fail (tile != NULL, tile_buf);
Elliot Lee's avatar
Elliot Lee committed
823

Sven Neumann's avatar
Sven Neumann committed
824 825 826
  src = tile_data_pointer (tile,
                           info->src_x % TILE_WIDTH,
                           info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
827
  scale = info->scale;
828
  dest  = tile_buf;
Elliot Lee's avatar
Elliot Lee committed
829

830
  x     = info->src_x;
Elliot Lee's avatar
Elliot Lee committed
831 832
  width = info->w;

833 834
  tilex = info->src_x / TILE_WIDTH;

Sven Neumann's avatar
Sven Neumann committed
835
  do
Elliot Lee's avatar
Elliot Lee committed
836
    {
Sven Neumann's avatar
Sven Neumann committed
837 838 839 840 841 842 843 844 845 846 847 848 849
      const guchar *s = src;

      switch (bpp)
        {
        case 4:
          *dest++ = *s++;
        case 3:
          *dest++ = *s++;
        case 2:
          *dest++ = *s++;
        case 1:
          *dest++ = *s++;
        }