gimpdisplayshell-render.c 23.7 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
#include "gimpcanvas.h"
40
#include "gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "gimpdisplayshell.h"
42
#include "gimpdisplayshell-filter.h"
43
#include "gimpdisplayshell-render.h"
44

Elliot Lee's avatar
Elliot Lee committed
45
46

typedef struct _RenderInfo  RenderInfo;
47
48

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

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


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


Elliot Lee's avatar
Elliot Lee committed
76
/*  accelerate transparency of image scaling  */
77
78
guchar *render_check_buf         = NULL;
guchar *render_empty_buf         = NULL;
79
guchar *render_white_buf         = NULL;
80
guchar *render_temp_buf          = NULL;
81

82
83
guchar *render_blend_dark_check  = NULL;
guchar *render_blend_light_check = NULL;
84
guchar *render_blend_white       = NULL;
85
86
87


static guchar *tile_buf           = NULL;
88
static guint   tile_shift         = 0;
89
90
static guint   check_mod          = 0;
static guint   check_shift        = 0;
91

Elliot Lee's avatar
Elliot Lee committed
92
93

void
94
95
96
97
render_init (Gimp *gimp)
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

98
  g_signal_connect (gimp->config, "notify::transparency-size",
99
100
                    G_CALLBACK (render_setup_notify),
                    gimp);
101
  g_signal_connect (gimp->config, "notify::transparency-type",
102
103
104
                    G_CALLBACK (render_setup_notify),
                    gimp);

105
  render_setup_notify (gimp->config, NULL, gimp);
106
107
108
109
110
111
112
}

void
render_exit (Gimp *gimp)
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

113
  g_signal_handlers_disconnect_by_func (gimp->config,
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
                                        render_setup_notify,
                                        gimp);

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

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

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

135
136
137
138
139
140
  if (render_blend_white)
    {
      g_free (render_blend_white);
      render_blend_white = NULL;
    }

141
142
143
144
145
146
147
148
149
150
151
152
  if (render_check_buf)
    {
      g_free (render_check_buf);
      render_check_buf = NULL;
    }

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

153
154
155
156
157
158
  if (render_white_buf)
    {
      g_free (render_white_buf);
      render_white_buf = NULL;
    }

159
160
161
162
163
164
165
166
167
  if (render_temp_buf)
    {
      g_free (render_temp_buf);
      render_temp_buf = NULL;
    }
}


static void
168
render_setup_notify (gpointer    config,
169
170
                     GParamSpec *param_spec,
                     Gimp       *gimp)
Elliot Lee's avatar
Elliot Lee committed
171
{
172
173
  GimpCheckType check_type;
  GimpCheckSize check_size;
174
  guchar        light, dark;
175
  gint          i, j;
176

177
178
179
180
  g_object_get (config,
                "transparency-type", &check_type,
                "transparency-size", &check_size,
                NULL);
Elliot Lee's avatar
Elliot Lee committed
181
182
183
184

  /*  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
185
186
187
  tile_shift = 0;
  while ((1 << tile_shift) < TILE_WIDTH)
    tile_shift++;
Elliot Lee's avatar
Elliot Lee committed
188
189

  /*  allocate a buffer for arranging information from a row of tiles  */
190
  if (! tile_buf)
Sven Neumann's avatar
Sven Neumann committed
191
192
    tile_buf = g_new (guchar,
                      GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH * MAX_CHANNELS);
Elliot Lee's avatar
Elliot Lee committed
193

194
195
196
197
  if (! render_blend_dark_check)
    render_blend_dark_check = g_new (guchar, 65536);
  if (! render_blend_light_check)
    render_blend_light_check = g_new (guchar, 65536);
198
199
  if (! render_blend_white)
    render_blend_white = g_new (guchar, 65536);
Elliot Lee's avatar
Elliot Lee committed
200

201
202
  gimp_checks_get_shades (check_type, &light, &dark);

Elliot Lee's avatar
Elliot Lee committed
203
204
205
  for (i = 0; i < 256; i++)
    for (j = 0; j < 256; j++)
      {
206
207
208
209
210
211
	render_blend_dark_check [(i << 8) + j] =
	  (guchar) ((j * i + dark * (255 - i)) / 255);
	render_blend_light_check [(i << 8) + j] =
          (guchar) ((j * i + light * (255 - i)) / 255);
	render_blend_white [(i << 8) + j] =
          (guchar) ((j * i + 255 * (255 - i)) / 255);
Elliot Lee's avatar
Elliot Lee committed
212
213
214
215
      }

  switch (check_size)
    {
216
    case GIMP_CHECK_SIZE_SMALL_CHECKS:
217
      check_mod   = 0x3;
Elliot Lee's avatar
Elliot Lee committed
218
219
      check_shift = 2;
      break;
220
    case GIMP_CHECK_SIZE_MEDIUM_CHECKS:
221
      check_mod   = 0x7;
Elliot Lee's avatar
Elliot Lee committed
222
223
      check_shift = 3;
      break;
224
    case GIMP_CHECK_SIZE_LARGE_CHECKS:
225
      check_mod   = 0xf;
Elliot Lee's avatar
Elliot Lee committed
226
227
228
229
      check_shift = 4;
      break;
    }

230
231
  g_free (render_check_buf);
  g_free (render_empty_buf);
232
  g_free (render_white_buf);
233
234
  g_free (render_temp_buf);

235
236
237
238
239
240
241
#define BUF_SIZE (MAX (GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH, \
                       GIMP_VIEWABLE_MAX_PREVIEW_SIZE) + 4)

  render_check_buf = g_new  (guchar, BUF_SIZE * 3);
  render_empty_buf = g_new0 (guchar, BUF_SIZE * 3);
  render_white_buf = g_new  (guchar, BUF_SIZE * 3);
  render_temp_buf  = g_new  (guchar, BUF_SIZE * 3);
242

Elliot Lee's avatar
Elliot Lee committed
243
  /*  calculate check buffer for previews  */
244
245
246
247

  memset (render_white_buf, 255, BUF_SIZE * 3);

  for (i = 0; i < BUF_SIZE; i++)
Elliot Lee's avatar
Elliot Lee committed
248
    {
249
250
251
252
253
254
255
256
257
258
259
260
      if (i & 0x4)
        {
          render_check_buf[i * 3 + 0] = render_blend_dark_check[0];
          render_check_buf[i * 3 + 1] = render_blend_dark_check[0];
          render_check_buf[i * 3 + 2] = render_blend_dark_check[0];
        }
      else
        {
          render_check_buf[i * 3 + 0] = render_blend_light_check[0];
          render_check_buf[i * 3 + 1] = render_blend_light_check[0];
          render_check_buf[i * 3 + 2] = render_blend_light_check[0];
        }
Elliot Lee's avatar
Elliot Lee committed
261
    }
262
263

#undef BUF_SIZE
Elliot Lee's avatar
Elliot Lee committed
264
265
}

266

Elliot Lee's avatar
Elliot Lee committed
267
268
/*  Render Image functions  */

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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,
285
						 gdouble           scalex);
286
static guchar * render_image_tile_fault         (RenderInfo       *info);
Elliot Lee's avatar
Elliot Lee committed
287
288


289
static RenderFunc render_funcs[6] =
Elliot Lee's avatar
Elliot Lee committed
290
{
291
292
293
294
295
296
  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
297
298
299
};


300
301
302
303
304
305
306
307
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
308
309
310
311
312
313
314
315
/*****************************************************************/
/*  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
316
317
318
319
gimp_display_shell_render (GimpDisplayShell *shell,
                           gint              x,
                           gint              y,
                           gint              w,
320
321
                           gint              h,
                           GdkRectangle     *highlight)
Elliot Lee's avatar
Elliot Lee committed
322
{
323
324
  RenderInfo     info;
  GimpImageType  image_type;
325
326

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

Michael Natterer's avatar
Michael Natterer committed
328
  image_type = gimp_projection_get_image_type (shell->gdisp->gimage->projection);
329

330
  if ((image_type < GIMP_RGB_IMAGE) || (image_type > GIMP_INDEXEDA_IMAGE))
Elliot Lee's avatar
Elliot Lee committed
331
    {
332
      g_message ("unknown gimage projection type: %d", image_type);
Elliot Lee's avatar
Elliot Lee committed
333
334
335
336
337
      return;
    }

  if ((info.dest_bpp < 1) || (info.dest_bpp > 4))
    {
Manish Singh's avatar
Manish Singh committed
338
      g_message ("unsupported destination bytes per pixel: %d", info.dest_bpp);
Elliot Lee's avatar
Elliot Lee committed
339
340
341
      return;
    }

342
  /* Currently, only RGBA and GRAYA projection types are used - the rest
343
344
   * are in case of future need.  -- austin, 28th Nov 1998.
   */
345
  if (image_type != GIMP_RGBA_IMAGE && image_type != GIMP_GRAYA_IMAGE)
346
    g_warning ("using untested projection type %d", image_type);
347

348
  (* render_funcs[image_type]) (&info);
349
350

  /*  apply filters to the rendered projection  */
351
352
353
354
355
356
  if (shell->filter_stack)
    gimp_color_display_stack_convert (shell->filter_stack,
                                      shell->render_buf,
                                      w, h,
                                      3,
                                      3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH);
357

358
359
360
361
  /*  dim pixels outside the highlighted rectangle  */
  if (highlight)
    gimp_display_shell_render_highlight (shell, x, y, w, h, highlight);

362
  /*  put it to the screen  */
363
364
365
366
367
368
  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,
                        3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH,
                        shell->offset_x, shell->offset_y);
Elliot Lee's avatar
Elliot Lee committed
369
370
371
}


372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
#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)

          buf += 3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH;
        }

      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)

          buf += 3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH;
        }

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

          buf += 3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH;
        }
    }
  else
    {
      for (y = 0; y < h; y++)
        {
          for (x = 0; x < w; x++)
            GIMP_DISPLAY_SHELL_DIM_PIXEL (buf, x)

          buf += 3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH;
        }
    }
}


Elliot Lee's avatar
Elliot Lee committed
442
443
444
445
446
/*************************/
/*  8 Bit functions      */
/*************************/

static void
447
render_image_indexed (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
448
{
449
450
451
452
453
  const guchar *cmap;
  gint          byte_order;
  gint          y, ye;
  gint          x, xe;
  gboolean      initial;
Elliot Lee's avatar
Elliot Lee committed
454

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

457
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
458
459
460
461
462
463
464
465
466
  ye = info->y + info->h;
  xe = info->x + info->w;

  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
467
468
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
469
470

      if (!initial && (error == 0))
471
472
473
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
474
475
      else
	{
476
477
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
Elliot Lee's avatar
Elliot Lee committed
478

479
	  g_return_if_fail (src != NULL);
480

481
482
	  for (x = info->x; x < xe; x++)
	    {
483
484
              guint  val = src[INDEXED_PIX] * 3;

485
	      src += 1;
486

487
488
489
	      dest[0] = cmap[val + 0];
	      dest[1] = cmap[val + 1];
	      dest[2] = cmap[val + 2];
490
491
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
492
493
494
495
	}

      info->dest += info->dest_bpl;

496
497
      initial = FALSE;

498
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
499
	{
500
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
501
	  info->src = render_image_tile_fault (info);
502
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
503
504
505
506
507
	}
    }
}

static void
508
render_image_indexed_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
509
{
510
511
512
513
514
515
  const guint  *alpha = info->alpha;
  const guchar *cmap;
  gint          byte_order;
  gint          y, ye;
  gint          x, xe;
  gboolean      initial;
Elliot Lee's avatar
Elliot Lee committed
516

517
  cmap = gimp_image_get_colormap (info->shell->gdisp->gimage);
518
  alpha = info->alpha;
Elliot Lee's avatar
Elliot Lee committed
519

520
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
521
522
523
524
525
526
527
528
529
  ye = info->y + info->h;
  xe = info->x + info->w;

  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
530
531
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
532
533

      if (!initial && (error == 0) && (y & check_mod))
534
535
536
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
537
538
      else
	{
539
540
541
          const guchar *src  = info->src;
          guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
542

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

545
	  g_return_if_fail (src != NULL);
Elliot Lee's avatar
Elliot Lee committed
546

547
548
	  for (x = info->x; x < xe; x++)
	    {
549
550
551
	      guint r, g, b, a = alpha[src[ALPHA_I_PIX]];
              guint val        = src[INDEXED_PIX] * 3;

552
553
554
555
	      src += 2;

	      if (dark_light & 0x1)
		{
556
557
558
		  r = render_blend_dark_check[(a | cmap[val + 0])];
		  g = render_blend_dark_check[(a | cmap[val + 1])];
		  b = render_blend_dark_check[(a | cmap[val + 2])];
559
560
561
		}
	      else
		{
562
563
564
		  r = render_blend_light_check[(a | cmap[val + 0])];
		  g = render_blend_light_check[(a | cmap[val + 1])];
		  b = render_blend_light_check[(a | cmap[val + 2])];
565
566
567
568
569
		}

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

572
573
		if (((x + 1) & check_mod) == 0)
		  dark_light += 1;
Elliot Lee's avatar
Elliot Lee committed
574
575
576
577
578
	      }
	}

      info->dest += info->dest_bpl;

579
580
      initial = FALSE;

581
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
582
	{
583
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
584
	  info->src = render_image_tile_fault (info);
585
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
586
587
588
589
590
	}
    }
}

static void
591
render_image_gray (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
592
{
593
594
595
596
  gint      byte_order;
  gint      y, ye;
  gint      x, xe;
  gboolean  initial;
597
598

  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
599
600
601
602
603
604
605
606
607
  ye = info->y + info->h;
  xe = info->x + info->w;

  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
608
609
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
610
611

      if (!initial && (error == 0))
612
613
614
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
615
616
      else
	{
617
618
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
619

620
621
	  g_return_if_fail (src != NULL);

622
623
	  for (x = info->x; x < xe; x++)
	    {
624
625
	      guint val = src[GRAY_PIX];

626
	      src += 1;
Elliot Lee's avatar
Elliot Lee committed
627

628
629
630
631
632
	      dest[0] = val;
	      dest[1] = val;
	      dest[2] = val;
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
633
634
635
636
	}

      info->dest += info->dest_bpl;

637
638
      initial = FALSE;

639
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
640
	{
641
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
642
	  info->src = render_image_tile_fault (info);
643
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
644
645
646
647
648
	}
    }
}

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

657
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
658
659
660
661
662
663
664
665
666
  ye = info->y + info->h;
  xe = info->x + info->w;

  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
667
668
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
669
670

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

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

682
683
	  g_return_if_fail (src != NULL);

684
685
	  for (x = info->x; x < xe; x++)
	    {
686
687
688
	      guint a = alpha[src[ALPHA_G_PIX]];
              guint val;

689
	      if (dark_light & 0x1)
690
		val = render_blend_dark_check[(a | src[GRAY_PIX])];
691
	      else
692
		val = render_blend_light_check[(a | src[GRAY_PIX])];
693

694
695
696
697
698
699
700
701
702
703
	      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
704
705
706
707
	}

      info->dest += info->dest_bpl;

708
709
      initial = FALSE;

710
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
711
	{
712
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
713
	  info->src = render_image_tile_fault (info);
714
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
715
716
717
718
719
	}
    }
}

static void
720
render_image_rgb (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
721
{
722
723
724
725
  gint      byte_order;
  gint      y, ye;
  gint      xe;
  gboolean  initial;
726
727

  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
728
729
730
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
731
  initial = TRUE;
Daniel Egger's avatar
Daniel Egger committed
732
  byte_order = info->byte_order;
Elliot Lee's avatar
Elliot Lee committed
733
734
735
736
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
737
738
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
739
740

      if (!initial && (error == 0))
741
742
743
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
744
745
      else
	{
746
	  g_return_if_fail (info->src != NULL);
747

748
          memcpy (info->dest, info->src, 3 * info->w);
Elliot Lee's avatar
Elliot Lee committed
749
750
751
752
	}

      info->dest += info->dest_bpl;

753
754
      initial = FALSE;

755
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
756
	{
757
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
758
	  info->src = render_image_tile_fault (info);
759
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
760
761
762
763
764
	}
    }
}

static void
765
render_image_rgb_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
766
{
767
768
769
770
771
  const guint *alpha = info->alpha;
  gint         byte_order;
  gint         y, ye;
  gint         x, xe;
  gint         initial;
Elliot Lee's avatar
Elliot Lee committed
772

773
  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
774
775
776
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
777
778
779
780
781
782
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
783
784
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
785
786

      if (!initial && (error == 0) && (y & check_mod))
787
788
789
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
790
791
      else
	{
792
793
794
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
795
796
797

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

798
799
	  g_return_if_fail (src != NULL);

800
801
	  for (x = info->x; x < xe; x++)
	    {
802
803
              guint r, g, b, a = alpha[src[ALPHA_PIX]];

804
805
	      if (dark_light & 0x1)
		{
806
807
808
		  r = render_blend_dark_check[(a | src[RED_PIX])];
		  g = render_blend_dark_check[(a | src[GREEN_PIX])];
		  b = render_blend_dark_check[(a | src[BLUE_PIX])];
809
810
811
		}
	      else
		{
812
813
814
		  r = render_blend_light_check[(a | src[RED_PIX])];
		  g = render_blend_light_check[(a | src[GREEN_PIX])];
		  b = render_blend_light_check[(a | src[BLUE_PIX])];
815
		}
Elliot Lee's avatar
Elliot Lee committed
816

817
	      src += 4;
Elliot Lee's avatar
Elliot Lee committed
818

819
820
821
822
	      dest[0] = r;
	      dest[1] = g;
	      dest[2] = b;
	      dest += 3;
Elliot Lee's avatar
Elliot Lee committed
823

824
825
826
	      if (((x + 1) & check_mod) == 0)
		dark_light += 1;
	    }
Elliot Lee's avatar
Elliot Lee committed
827
828
829
830
	}

      info->dest += info->dest_bpl;

831
832
      initial = FALSE;

833
      if (error >= 1)
Elliot Lee's avatar
Elliot Lee committed
834
	{
835
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
836
	  info->src = render_image_tile_fault (info);
837
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
838
839
840
841
842
	}
    }
}

static void
843
844
845
846
847
848
render_image_init_info (RenderInfo       *info,
			GimpDisplayShell *shell,
			gint              x,
			gint              y,
			gint              w,
			gint              h)
Elliot Lee's avatar
Elliot Lee committed
849
{
Michael Natterer's avatar
Michael Natterer committed
850
851
  GimpImage *gimage = shell->gdisp->gimage;

852
  info->shell      = shell;
Michael Natterer's avatar
Michael Natterer committed
853
  info->src_tiles  = gimp_projection_get_tiles (gimage->projection);
854
855
  info->x          = x + shell->offset_x;
  info->y          = y + shell->offset_y;
856
857
  info->w          = w;
  info->h          = h;
858
859
  info->scalex     = SCALEFACTOR_X (shell);
  info->scaley     = SCALEFACTOR_Y (shell);
860
861
  info->src_x      = (gdouble) info->x / info->scalex;
  info->src_y      = (gdouble) info->y / info->scaley;
Michael Natterer's avatar
Michael Natterer committed
862
  info->src_bpp    = gimp_projection_get_bytes (gimage->projection);
863
864
865
  info->dest       = shell->render_buf;
  info->dest_bpp   = 3;
  info->dest_bpl   = info->dest_bpp * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH;
Elliot Lee's avatar
Elliot Lee committed
866
  info->dest_width = info->w * info->dest_bpp;
867
  info->byte_order = GDK_MSB_FIRST;
Sven Neumann's avatar
Sven Neumann committed
868
869
  info->scale      = render_image_accelerate_scaling (w,
                                                      info->x, info->scalex);
870
  info->alpha      = NULL;
Elliot Lee's avatar
Elliot Lee committed
871

Michael Natterer's avatar
Michael Natterer committed
872
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_projection_get_image_type (gimage->projection)))
Elliot Lee's avatar
Elliot Lee committed
873
    {
874
      info->alpha =
Michael Natterer's avatar
Michael Natterer committed
875
	render_image_init_alpha (gimp_projection_get_opacity (gimage->projection) * 255.999);
Elliot Lee's avatar
Elliot Lee committed
876
877
878
    }
}

879
static guint *
880
render_image_init_alpha (gint mult)
Elliot Lee's avatar
Elliot Lee committed
881
882
{
  static guint *alpha_mult = NULL;
883
884
885
  static gint   alpha_val  = -1;

  gint i;
Elliot Lee's avatar
Elliot Lee committed
886
887
888
889

  if (alpha_val != mult)
    {
      if (!alpha_mult)
890
	alpha_mult = g_new (guint, 256);
Elliot Lee's avatar
Elliot Lee committed
891
892
893
894
895
896
897
898
899

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

  return alpha_mult;
}

900
static guchar *
901
902
903
render_image_accelerate_scaling (gint    width,
				 gint    start,
				 gdouble scalex)
Elliot Lee's avatar
Elliot Lee committed
904
905
{
  static guchar *scale = NULL;
906

907
  gint  i;
Elliot Lee's avatar
Elliot Lee committed
908

909
910
  if (! scale)
    scale = g_new (guchar, GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH + 1);
Elliot Lee's avatar
Elliot Lee committed
911

912
  for (i = 0; i <= width; i++)
913
    {
914
915
      scale[i] = RINT (floor ((start + 1) / scalex) - floor (start / scalex));
      start++;
916
    }
Elliot Lee's avatar
Elliot Lee committed
917
918
919
920

  return scale;
}

921
static guchar *
Elliot Lee's avatar
Elliot Lee committed
922
923
render_image_tile_fault (RenderInfo *info)
{
924
925
926
927
928
929
930
931
932
  Tile         *tile;
  const guchar *data;
  const guchar *scale;
  guchar       *dest;
  gint          width;
  gint          tilex;
  gint          step;
  gint          bpp = info->src_bpp;
  gint          x, b;
Elliot Lee's avatar
Elliot Lee committed
933

934
  tile = tile_manager_get_tile (info->src_tiles,
Sven Neumann's avatar
Sven Neumann committed
935
				info->src_x, info->src_y,
936
				TRUE, FALSE);
Elliot Lee's avatar
Elliot Lee committed
937
938
939
  if (!tile)
    return NULL;

940
  data = tile_data_pointer (tile,
scott's avatar
scott committed
941
942
			    info->src_x % TILE_WIDTH,
			    info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
943
  scale = info->scale;
944
  dest  = tile_buf;
Elliot Lee's avatar
Elliot Lee committed
945

946
  x     = info->src_x;
Elliot Lee's avatar
Elliot Lee committed
947
948
  width = info->w;

949
950
  tilex = info->src_x / TILE_WIDTH;

Elliot Lee's avatar
Elliot Lee committed
951
952
  while (width--)
    {
953
      for (b = 0; b < bpp; b++)
Elliot Lee's avatar
Elliot Lee committed
954
955
	*dest++ = data[b];

956
957
      step = *scale++;
      if (step != 0)
Elliot Lee's avatar
Elliot Lee committed
958
	{
959
960
	  x += step;
	  data += step * bpp;
Elliot Lee's avatar
Elliot Lee committed
961

Daniel Egger's avatar
Daniel Egger committed
962
	  if ((x >> tile_shift) != tilex)
Elliot Lee's avatar
Elliot Lee committed
963
	    {
964
	      tile_release (tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
965
966
	      tilex += 1;

Sven Neumann's avatar
Sven Neumann committed
967
968
969
970
	      tile = tile_manager_get_tile (info->src_tiles,
                                            x, info->src_y,
                                            TRUE, FALSE);

Daniel Egger's avatar
Daniel Egger committed
971
972
973
	      if (!tile)
		return tile_buf;

974
	      data = tile_data_pointer (tile,
Sven Neumann's avatar
Sven Neumann committed
975
976
                                        x % TILE_WIDTH,
                                        info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
977
978
979
980
	    }
	}
    }

981
  tile_release (tile, FALSE);
982

Elliot Lee's avatar
Elliot Lee committed
983
984
  return tile_buf;
}