gimpdisplayshell-render.c 23.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
#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
  gint              src_x, src_y;
  gint              src_bpp;
  gint              dest_bpp;
  gint              dest_bpl;
  gint              dest_width;
Elliot Lee's avatar
Elliot Lee committed
67
68
69
};


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


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

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


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

Elliot Lee's avatar
Elliot Lee committed
91
92

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

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

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

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

112
  g_signal_handlers_disconnect_by_func (gimp->config,
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
                                        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;
    }

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

140
141
142
143
144
145
146
147
148
149
150
151
  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;
    }

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

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


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

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

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

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

193
194
195
196
  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);
197
198
  if (! render_blend_white)
    render_blend_white = g_new (guchar, 65536);
Elliot Lee's avatar
Elliot Lee committed
199

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

Elliot Lee's avatar
Elliot Lee committed
202
203
204
  for (i = 0; i < 256; i++)
    for (j = 0; j < 256; j++)
      {
205
206
207
208
209
210
	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
211
212
213
214
      }

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

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

234
235
236
237
238
239
240
#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);
241

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

  memset (render_white_buf, 255, BUF_SIZE * 3);

  for (i = 0; i < BUF_SIZE; i++)
Elliot Lee's avatar
Elliot Lee committed
247
    {
248
249
250
251
252
253
254
255
256
257
258
259
      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
260
    }
261
262

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

265

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

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


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


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

Sven Neumann's avatar
Sven Neumann committed
325
326
  g_return_if_fail (w > 0 && h > 0);

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

329
  type = gimp_projection_get_image_type (shell->gdisp->gimage->projection);
330

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

333
  /* Currently, only RGBA and GRAYA projection types are used - the rest
334
335
   * are in case of future need.  -- austin, 28th Nov 1998.
   */
336
337
  if (G_UNLIKELY (type != GIMP_RGBA_IMAGE && type != GIMP_GRAYA_IMAGE))
    g_warning ("using untested projection type %d", type);
338

339
  (* render_funcs[type]) (&info);
340
341

  /*  apply filters to the rendered projection  */
342
343
344
345
346
347
  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);
348

349
350
351
352
  /*  dim pixels outside the highlighted rectangle  */
  if (highlight)
    gimp_display_shell_render_highlight (shell, x, y, w, h, highlight);

353
  /*  put it to the screen  */
354
355
356
357
358
359
  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
360
361
362
}


363
364
365
366
367
368
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
#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
433
434
435
436
437
/*************************/
/*  8 Bit functions      */
/*************************/

static void
438
render_image_indexed (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
439
{
440
441
442
  const guchar *cmap;
  gint          y, ye;
  gint          x, xe;
443
  gboolean      initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
444

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

447
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
448
449
450
451
452
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
453
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
454
    {
455
456
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
457
458

      if (!initial && (error == 0))
459
460
461
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
462
463
      else
	{
464
465
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
Elliot Lee's avatar
Elliot Lee committed
466

467
468
	  for (x = info->x; x < xe; x++)
	    {
469
470
              guint  val = src[INDEXED_PIX] * 3;

471
	      src += 1;
472

473
474
475
	      dest[0] = cmap[val + 0];
	      dest[1] = cmap[val + 1];
	      dest[2] = cmap[val + 2];
476
477
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
478
479
	}

Sven Neumann's avatar
Sven Neumann committed
480
481
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
482

Sven Neumann's avatar
Sven Neumann committed
483
      info->dest += info->dest_bpl;
484

Sven Neumann's avatar
Sven Neumann committed
485
      if (error)
Elliot Lee's avatar
Elliot Lee committed
486
	{
487
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
488
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
489

490
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
491
	}
Sven Neumann's avatar
Sven Neumann committed
492
493
494
495
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
496
497
498
499
    }
}

static void
500
render_image_indexed_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
501
{
502
503
504
505
  const guint  *alpha = info->alpha;
  const guchar *cmap;
  gint          y, ye;
  gint          x, xe;
506
  gboolean      initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
507

508
  cmap = gimp_image_get_colormap (info->shell->gdisp->gimage);
509
  alpha = info->alpha;
Elliot Lee's avatar
Elliot Lee committed
510

511
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
512
513
514
515
516
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
517
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
518
    {
519
520
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
521
522

      if (!initial && (error == 0) && (y & check_mod))
523
524
525
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
526
527
      else
	{
528
529
530
          const guchar *src  = info->src;
          guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
531

532
533
534
535
	  dark_light = (y >> check_shift) + (info->x >> check_shift);

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

539
540
541
542
	      src += 2;

	      if (dark_light & 0x1)
		{
543
544
545
		  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])];
546
547
548
		}
	      else
		{
549
550
551
		  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])];
552
553
554
555
556
		}

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

559
560
		if (((x + 1) & check_mod) == 0)
		  dark_light += 1;
Elliot Lee's avatar
Elliot Lee committed
561
562
563
	      }
	}

Sven Neumann's avatar
Sven Neumann committed
564
565
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
566

Sven Neumann's avatar
Sven Neumann committed
567
      info->dest += info->dest_bpl;
568

Sven Neumann's avatar
Sven Neumann committed
569
      if (error)
Elliot Lee's avatar
Elliot Lee committed
570
	{
571
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
572
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
573

574
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
575
	}
Sven Neumann's avatar
Sven Neumann committed
576
577
578
579
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
580
581
582
583
    }
}

static void
584
render_image_gray (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
585
{
586
587
  gint      y, ye;
  gint      x, xe;
588
  gboolean  initial = TRUE;
589
590

  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
591
592
593
594
595
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
596
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
597
    {
598
599
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
600
601

      if (!initial && (error == 0))
602
603
604
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
605
606
      else
	{
607
608
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
609

610
611
	  for (x = info->x; x < xe; x++)
	    {
612
613
	      guint val = src[GRAY_PIX];

614
	      src += 1;
Elliot Lee's avatar
Elliot Lee committed
615

616
617
618
619
620
	      dest[0] = val;
	      dest[1] = val;
	      dest[2] = val;
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
621
622
	}

Sven Neumann's avatar
Sven Neumann committed
623
624
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
625

Sven Neumann's avatar
Sven Neumann committed
626
      info->dest += info->dest_bpl;
627

Sven Neumann's avatar
Sven Neumann committed
628
      if (error)
Elliot Lee's avatar
Elliot Lee committed
629
	{
630
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
631
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
632

633
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
634
	}
Sven Neumann's avatar
Sven Neumann committed
635
636
637
638
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
639
640
641
642
    }
}

static void
643
render_image_gray_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
644
{
645
646
647
  const guint *alpha = info->alpha;
  gint         y, ye;
  gint         x, xe;
648
  gboolean     initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
649

650
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
651
652
653
654
655
  ye = info->y + info->h;
  xe = info->x + info->w;

  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
656
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
657
    {
658
659
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
660
661

      if (!initial && (error == 0) && (y & check_mod))
662
663
664
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
665
666
      else
	{
667
668
669
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
670
671
672

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

673
674
	  for (x = info->x; x < xe; x++)
	    {
675
676
677
	      guint a = alpha[src[ALPHA_G_PIX]];
              guint val;

678
	      if (dark_light & 0x1)
679
		val = render_blend_dark_check[(a | src[GRAY_PIX])];
680
	      else
681
		val = render_blend_light_check[(a | src[GRAY_PIX])];
682

683
684
685
686
687
688
689
690
691
692
	      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
693
694
	}

Sven Neumann's avatar
Sven Neumann committed
695
696
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
697

Sven Neumann's avatar
Sven Neumann committed
698
      info->dest += info->dest_bpl;
699

Sven Neumann's avatar
Sven Neumann committed
700
      if (error)
Elliot Lee's avatar
Elliot Lee committed
701
	{
702
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
703
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
704

705
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
706
	}
Sven Neumann's avatar
Sven Neumann committed
707
708
709
710
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
711
712
713
714
    }
}

static void
715
render_image_rgb (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
716
{
717
718
  gint      y, ye;
  gint      xe;
719
  gboolean  initial = TRUE;
720
721

  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
722
723
724
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
725
726
  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
727
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
728
    {
729
730
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
731
732

      if (!initial && (error == 0))
733
734
735
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
736
737
      else
	{
738
          memcpy (info->dest, info->src, 3 * info->w);
Elliot Lee's avatar
Elliot Lee committed
739
740
	}

Sven Neumann's avatar
Sven Neumann committed
741
742
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
743

Sven Neumann's avatar
Sven Neumann committed
744
      info->dest += info->dest_bpl;
745

746
      if (error)
Elliot Lee's avatar
Elliot Lee committed
747
	{
748
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
749
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
750

751
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
752
	}
Sven Neumann's avatar
Sven Neumann committed
753
754
755
756
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
757
758
759
760
    }
}

static void
761
render_image_rgb_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
762
{
763
764
765
  const guint *alpha = info->alpha;
  gint         y, ye;
  gint         x, xe;
766
  gint         initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
767

768
  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
769
770
771
  ye = info->y + info->h;
  xe = info->x + info->w;

Elliot Lee's avatar
Elliot Lee committed
772
773
  info->src = render_image_tile_fault (info);

Sven Neumann's avatar
Sven Neumann committed
774
  while (TRUE)
Elliot Lee's avatar
Elliot Lee committed
775
    {
776
777
      gint error =
        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
778
779

      if (!initial && (error == 0) && (y & check_mod))
780
781
782
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
783
784
      else
	{
785
786
787
	  const guchar *src  = info->src;
	  guchar       *dest = info->dest;
          guint         dark_light;
Elliot Lee's avatar
Elliot Lee committed
788
789
790

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

791
792
	  for (x = info->x; x < xe; x++)
	    {
793
794
              guint r, g, b, a = alpha[src[ALPHA_PIX]];

795
796
	      if (dark_light & 0x1)
		{
797
798
799
		  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])];
800
801
802
		}
	      else
		{
803
804
805
		  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])];
806
		}
Elliot Lee's avatar
Elliot Lee committed
807

808
	      src += 4;
Elliot Lee's avatar
Elliot Lee committed
809

810
811
812
813
	      dest[0] = r;
	      dest[1] = g;
	      dest[2] = b;
	      dest += 3;
Elliot Lee's avatar
Elliot Lee committed
814

815
816
817
	      if (((x + 1) & check_mod) == 0)
		dark_light += 1;
	    }
Elliot Lee's avatar
Elliot Lee committed
818
819
	}

Sven Neumann's avatar
Sven Neumann committed
820
821
      if (++y == ye)
        break;
Elliot Lee's avatar
Elliot Lee committed
822

Sven Neumann's avatar
Sven Neumann committed
823
      info->dest += info->dest_bpl;
824

Sven Neumann's avatar
Sven Neumann committed
825
      if (error)
Elliot Lee's avatar
Elliot Lee committed
826
	{
827
	  info->src_y += error;
Elliot Lee's avatar
Elliot Lee committed
828
	  info->src = render_image_tile_fault (info);
Sven Neumann's avatar
Sven Neumann committed
829

830
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
831
	}
Sven Neumann's avatar
Sven Neumann committed
832
833
834
835
      else
        {
          initial = FALSE;
        }
Elliot Lee's avatar
Elliot Lee committed
836
837
838
839
    }
}

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

849
  info->shell      = shell;
Michael Natterer's avatar
Michael Natterer committed
850
  info->src_tiles  = gimp_projection_get_tiles (gimage->projection);
851
852
  info->x          = x + shell->offset_x;
  info->y          = y + shell->offset_y;
853
854
  info->w          = w;
  info->h          = h;
855
856
  info->scalex     = SCALEFACTOR_X (shell);
  info->scaley     = SCALEFACTOR_Y (shell);
857
858
  info->src_x      = (gdouble) info->x / info->scalex;
  info->src_y      = (gdouble) info->y / info->scaley;
Michael Natterer's avatar
Michael Natterer committed
859
  info->src_bpp    = gimp_projection_get_bytes (gimage->projection);
860
861
862
  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
863
  info->dest_width = info->w * info->dest_bpp;
Sven Neumann's avatar
Sven Neumann committed
864
865
  info->scale      = render_image_accelerate_scaling (w,
                                                      info->x, info->scalex);
866
  info->alpha      = NULL;
Elliot Lee's avatar
Elliot Lee committed
867

Michael Natterer's avatar
Michael Natterer committed
868
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_projection_get_image_type (gimage->projection)))
Elliot Lee's avatar
Elliot Lee committed
869
    {
870
      info->alpha =
Michael Natterer's avatar
Michael Natterer committed
871
	render_image_init_alpha (gimp_projection_get_opacity (gimage->projection) * 255.999);
Elliot Lee's avatar
Elliot Lee committed
872
873
874
    }
}

875
static guint *
876
render_image_init_alpha (gint mult)
Elliot Lee's avatar
Elliot Lee committed
877
878
{
  static guint *alpha_mult = NULL;
879
880
881
  static gint   alpha_val  = -1;

  gint i;
Elliot Lee's avatar
Elliot Lee committed
882
883
884
885

  if (alpha_val != mult)
    {
      if (!alpha_mult)
886
	alpha_mult = g_new (guint, 256);
Elliot Lee's avatar
Elliot Lee committed
887
888
889
890
891
892
893
894
895

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

  return alpha_mult;
}

896
static guchar *
897
898
899
render_image_accelerate_scaling (gint    width,
				 gint    start,
				 gdouble scalex)
Elliot Lee's avatar
Elliot Lee committed
900
901
{
  static guchar *scale = NULL;
902

903
  gint  i;
Elliot Lee's avatar
Elliot Lee committed
904

905
906
  if (! scale)
    scale = g_new (guchar, GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH + 1);
Elliot Lee's avatar
Elliot Lee committed
907

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

  return scale;
}

917
static guchar *
Elliot Lee's avatar
Elliot Lee committed
918
919
render_image_tile_fault (RenderInfo *info)
{
920
  Tile         *tile;
Sven Neumann's avatar
Sven Neumann committed
921
  const guchar *src;
922
923
924
925
926
927
  const guchar *scale;
  guchar       *dest;
  gint          width;
  gint          tilex;
  gint          step;
  gint          bpp = info->src_bpp;
Sven Neumann's avatar
Sven Neumann committed
928
  gint          x;
Elliot Lee's avatar
Elliot Lee committed
929

930
  tile = tile_manager_get_tile (info->src_tiles,
931
932
				info->src_x, info->src_y, TRUE, FALSE);

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

Sven Neumann's avatar
Sven Neumann committed
935
936
937
  src = tile_data_pointer (tile,
                           info->src_x % TILE_WIDTH,
                           info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
938
  scale = info->scale;
939
  dest  = tile_buf;
Elliot Lee's avatar
Elliot Lee committed
940

941
  x     = info->src_x;
Elliot Lee's avatar
Elliot Lee committed
942
943
  width = info->w;

944
945
  tilex = info->src_x / TILE_WIDTH;

Sven Neumann's avatar
Sven Neumann committed
946
  do
Elliot Lee's avatar
Elliot Lee committed
947
    {
Sven Neumann's avatar
Sven Neumann committed
948
949
950
951
952
953
954
955
956
957
958
959
960
      const guchar *s = src;

      switch (bpp)
        {
        case 4:
          *dest++ = *s++;
        case 3:
          *dest++ = *s++;
        case 2:
          *dest++ = *s++;
        case 1:
          *dest++ = *s++;
        }
Elliot Lee's avatar
Elliot Lee committed
961

962
      step = *scale++;
963

964
      if (step)
Elliot Lee's avatar
Elliot Lee committed
965
	{
966
	  x += step;
Sven Neumann's avatar
Sven Neumann committed
967
	  src += step * bpp;
Elliot Lee's avatar
Elliot Lee committed
968

Daniel Egger's avatar
Daniel Egger committed
969
	  if ((x >> tile_shift) != tilex)
Elliot Lee's avatar
Elliot Lee committed
970
	    {
971
	      tile_release (tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
972
973
	      tilex += 1;

Sven Neumann's avatar
Sven Neumann committed
974
	      tile = tile_manager_get_tile (info->src_tiles,
975
                                            x, info->src_y, TRUE, FALSE);
976
977
	      if (!tile)
		return tile_buf;
Daniel Egger's avatar
Daniel Egger committed
978

Sven Neumann's avatar
Sven Neumann committed
979
	      src = tile_data_pointer (tile,
980
981
                                       x % TILE_WIDTH,
                                       info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
982
983
984
	    }
	}
    }
Sven Neumann's avatar
Sven Neumann committed
985
  while (--width);
Elliot Lee's avatar
Elliot Lee committed
986

987
  tile_release (tile, FALSE);
988

Elliot Lee's avatar
Elliot Lee committed
989
990
  return tile_buf;
}