gimpdisplayshell-render.c 21.6 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
27
#include "libgimpwidgets/gimpwidgets.h"

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

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

33
#include "core/gimp.h"
34
#include "core/gimpimage.h"
35
#include "core/gimpimage-projection.h"
36

37
#include "gimpdisplay.h"
Michael Natterer's avatar
Michael Natterer committed
38
#include "gimpdisplayshell.h"
39
#include "gimpdisplayshell-filter.h"
40
#include "gimpdisplayshell-render.h"
41

Elliot Lee's avatar
Elliot Lee committed
42
43

typedef struct _RenderInfo  RenderInfo;
44
45

typedef void (* RenderFunc) (RenderInfo *info);
Elliot Lee's avatar
Elliot Lee committed
46
47
48

struct _RenderInfo
{
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  GimpDisplayShell *shell;
  TileManager      *src_tiles;
  guint            *alpha;
  guchar           *scale;
  guchar           *src;
  guchar           *dest;
  gint              x, y;
  gint              w, h;
  gfloat            scalex;
  gfloat            scaley;
  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
65
66
67
};


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


Elliot Lee's avatar
Elliot Lee committed
73
/*  accelerate transparency of image scaling  */
74
75
76
77
78
79
80
81
82
83
84
guchar *render_check_buf         = NULL;
guchar *render_empty_buf         = NULL;
guchar *render_temp_buf          = NULL;
guchar *render_blend_dark_check  = NULL;
guchar *render_blend_light_check = NULL;


static guchar *tile_buf           = NULL;
static guint   check_mod          = 0;
static guint   check_shift        = 0;
static guint   tile_shift         = 0;
Elliot Lee's avatar
Elliot Lee committed
85
86
87
88
static guchar  check_combos[6][2] =
{
  { 204, 255 },
  { 102, 153 },
89
  {   0,  51 },
Elliot Lee's avatar
Elliot Lee committed
90
91
  { 255, 255 },
  { 127, 127 },
92
  {   0,   0 }
Elliot Lee's avatar
Elliot Lee committed
93
94
95
96
};


void
97
98
99
100
render_init (Gimp *gimp)
{
  g_return_if_fail (GIMP_IS_GIMP (gimp));

101
  g_signal_connect (gimp->config, "notify::transparency-size",
102
103
                    G_CALLBACK (render_setup_notify),
                    gimp);
104
  g_signal_connect (gimp->config, "notify::transparency-type",
105
106
107
                    G_CALLBACK (render_setup_notify),
                    gimp);

108
  render_setup_notify (gimp->config, NULL, gimp);
109
110
111
112
113
114
115
}

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

116
  g_signal_handlers_disconnect_by_func (gimp->config,
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
                                        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;
    }

  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;
    }

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


static void
159
render_setup_notify (gpointer    config,
160
161
                     GParamSpec *param_spec,
                     Gimp       *gimp)
Elliot Lee's avatar
Elliot Lee committed
162
{
163
164
165
  GimpCheckType check_type;
  GimpCheckSize check_size;
  gint          i, j;
166

167
168
169
170
  g_object_get (config,
                "transparency-type", &check_type,
                "transparency-size", &check_size,
                NULL);
Elliot Lee's avatar
Elliot Lee committed
171
172
173
174

  /*  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
175
176
177
  tile_shift = 0;
  while ((1 << tile_shift) < TILE_WIDTH)
    tile_shift++;
Elliot Lee's avatar
Elliot Lee committed
178
179

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

184
185
186
187
  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);
Elliot Lee's avatar
Elliot Lee committed
188
189
190
191

  for (i = 0; i < 256; i++)
    for (j = 0; j < 256; j++)
      {
192
	render_blend_dark_check [(i << 8) + j] = (guchar)
Elliot Lee's avatar
Elliot Lee committed
193
	  ((j * i + check_combos[check_type][0] * (255 - i)) / 255);
194
	render_blend_light_check [(i << 8) + j] = (guchar)
Elliot Lee's avatar
Elliot Lee committed
195
196
197
198
199
	  ((j * i + check_combos[check_type][1] * (255 - i)) / 255);
      }

  switch (check_size)
    {
200
    case GIMP_SMALL_CHECKS:
201
      check_mod   = 0x3;
Elliot Lee's avatar
Elliot Lee committed
202
203
      check_shift = 2;
      break;
204
    case GIMP_MEDIUM_CHECKS:
205
      check_mod   = 0x7;
Elliot Lee's avatar
Elliot Lee committed
206
207
      check_shift = 3;
      break;
208
    case GIMP_LARGE_CHECKS:
209
      check_mod   = 0xf;
Elliot Lee's avatar
Elliot Lee committed
210
211
212
213
      check_shift = 4;
      break;
    }

214
215
216
217
  g_free (render_check_buf);
  g_free (render_empty_buf);
  g_free (render_temp_buf);

218
219
220
221
#ifdef __GNUC__
#warning #define MAX_PREVIEW_SIZE 1024  /* GIMP_PREVIEW_MAX_SIZE (EEK) */
#endif
#define MAX_PREVIEW_SIZE 1024  /* GIMP_PREVIEW_MAX_SIZE (EEK) */
222

Elliot Lee's avatar
Elliot Lee committed
223
  /*  calculate check buffer for previews  */
224
  if (TRUE /* preview_size */)
Elliot Lee's avatar
Elliot Lee committed
225
    {
226
      render_check_buf = g_new (guchar, (MAX_PREVIEW_SIZE + 4) * 3);
227

228
      for (i = 0; i < (MAX_PREVIEW_SIZE + 4); i++)
Elliot Lee's avatar
Elliot Lee committed
229
230
231
	{
	  if (i & 0x4)
	    {
232
233
234
	      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];
Elliot Lee's avatar
Elliot Lee committed
235
236
237
	    }
	  else
	    {
238
239
240
	      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
241
242
	    }
	}
243

244
245
      render_empty_buf = g_new0 (guchar, (MAX_PREVIEW_SIZE + 4) * 3);
      render_temp_buf  = g_new  (guchar, (MAX_PREVIEW_SIZE + 4) * 3);
Elliot Lee's avatar
Elliot Lee committed
246
247
248
    }
  else
    {
249
250
251
      render_check_buf = NULL;
      render_empty_buf = NULL;
      render_temp_buf  = NULL;
Elliot Lee's avatar
Elliot Lee committed
252
253
254
    }
}

255

Elliot Lee's avatar
Elliot Lee committed
256
257
/*  Render Image functions  */

258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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,
						 gfloat            scalex);
static guchar * render_image_tile_fault         (RenderInfo       *info);
Elliot Lee's avatar
Elliot Lee committed
276
277


278
static RenderFunc render_funcs[6] =
Elliot Lee's avatar
Elliot Lee committed
279
{
280
281
282
283
284
285
  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
286
287
288
289
290
291
292
293
294
295
296
};


/*****************************************************************/
/*  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
297
298
299
300
301
gimp_display_shell_render (GimpDisplayShell *shell,
                           gint              x,
                           gint              y,
                           gint              w,
                           gint              h)
Elliot Lee's avatar
Elliot Lee committed
302
{
303
304
305
  RenderInfo     info;
  GimpImageType  image_type;
  GList         *list;
306
307

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

309
  image_type = gimp_image_projection_type (shell->gdisp->gimage);
310

311
  if ((image_type < GIMP_RGB_IMAGE) || (image_type > GIMP_INDEXEDA_IMAGE))
Elliot Lee's avatar
Elliot Lee committed
312
    {
Manish Singh's avatar
Manish Singh committed
313
      g_message ("unknown gimage projection type: %d",
314
		 gimp_image_projection_type (shell->gdisp->gimage));
Elliot Lee's avatar
Elliot Lee committed
315
316
317
318
319
      return;
    }

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

324
  /* Currently, only RGBA and GRAYA projection types are used - the rest
325
326
   * are in case of future need.  -- austin, 28th Nov 1998.
   */
327
  if (image_type != GIMP_RGBA_IMAGE && image_type != GIMP_GRAYA_IMAGE)
328
    g_warning ("using untested projection type %d", image_type);
329

330
  (* render_funcs[image_type]) (&info);
331
332

  /*  apply filters to the rendered projection  */
333
  for (list = shell->filters; list; list = g_list_next (list))
334
    {
335
      GimpColorDisplay *filter;
336

337
      filter = (GimpColorDisplay *) list->data;
338

339
      gimp_color_display_convert (filter,
340
341
342
343
                                  shell->render_buf,
                                  w, h,
                                  3,
                                  3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH);
344
345
346
347
348
349
350
351
352
353
354
355
356
    }

  /*  put it to the screen  */
  gdk_draw_rgb_image_dithalign (shell->canvas->window,
                                shell->render_gc,
                                x + shell->disp_xoffset,
                                y + shell->disp_yoffset,
                                w, h,
                                GDK_RGB_DITHER_MAX,
                                shell->render_buf,
                                3 * GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH,
                                shell->offset_x,
                                shell->offset_y);
Elliot Lee's avatar
Elliot Lee committed
357
358
359
360
361
362
363
364
}


/*************************/
/*  8 Bit functions      */
/*************************/

static void
365
render_image_indexed (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
366
367
368
{
  guchar *src;
  guchar *dest;
369
  guchar *cmap;
370
371
372
373
374
375
376
  gulong  val;
  gint    byte_order;
  gint    y, ye;
  gint    x, xe;
  gint    initial;
  gfloat  error;
  gfloat  step;
Elliot Lee's avatar
Elliot Lee committed
377

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

380
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
381
382
383
  ye = info->y + info->h;
  xe = info->x + info->w;

384
385
  step = 1.0 / info->scaley;

386
387
  error  = y * step;
  error -= ((gint) error) - step;
388

Elliot Lee's avatar
Elliot Lee committed
389
390
391
392
393
394
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
395
      if (!initial && (error < 1.0))
396
397
398
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
399
400
401
402
403
      else
	{
	  src = info->src;
	  dest = info->dest;

404
	  g_return_if_fail (src != NULL);
405

406
407
408
409
	  for (x = info->x; x < xe; x++)
	    {
	      val = src[INDEXED_PIX] * 3;
	      src += 1;
410

411
412
413
414
415
	      dest[0] = cmap[val+0];
	      dest[1] = cmap[val+1];
	      dest[2] = cmap[val+2];
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
416
417
418
419
	}

      info->dest += info->dest_bpl;

420
421
422
      initial = FALSE;

      if (error >= 1.0)
Elliot Lee's avatar
Elliot Lee committed
423
	{
424
425
	  info->src_y += (int)error;
	  error -= (int)error;
Elliot Lee's avatar
Elliot Lee committed
426
	  info->src = render_image_tile_fault (info);
427
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
428
429
	}

430
      error += step;
Elliot Lee's avatar
Elliot Lee committed
431
432
433
434
    }
}

static void
435
render_image_indexed_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
436
437
438
{
  guchar *src;
  guchar *dest;
439
  guint  *alpha;
440
  guchar *cmap;
441
442
443
444
445
446
447
448
449
450
  gulong  r, g, b;
  gulong  val;
  guint   a;
  gint    dark_light;
  gint    byte_order;
  gint    y, ye;
  gint    x, xe;
  gint    initial;
  gfloat  error;
  gfloat  step;
Elliot Lee's avatar
Elliot Lee committed
451

452
  cmap = gimp_image_get_colormap (info->shell->gdisp->gimage);
453
  alpha = info->alpha;
Elliot Lee's avatar
Elliot Lee committed
454

455
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
456
457
458
  ye = info->y + info->h;
  xe = info->x + info->w;

459
460
  step = 1.0 / info->scaley;

461
462
  error  = y * step;
  error -= ((gint) error) - step;
463

Elliot Lee's avatar
Elliot Lee committed
464
465
466
467
468
469
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
470
      if (!initial && (error < 1.0) && (y & check_mod))
471
472
473
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
474
475
476
477
478
      else
	{
	  src = info->src;
	  dest = info->dest;

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

481
	  g_return_if_fail (src != NULL);
Elliot Lee's avatar
Elliot Lee committed
482

483
484
485
486
487
488
489
490
	  for (x = info->x; x < xe; x++)
	    {
	      a = alpha[src[ALPHA_I_PIX]];
	      val = src[INDEXED_PIX] * 3;
	      src += 2;

	      if (dark_light & 0x1)
		{
491
492
493
		  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])];
494
495
496
		}
	      else
		{
497
498
499
		  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])];
500
501
502
503
504
		}

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

507
508
		if (((x + 1) & check_mod) == 0)
		  dark_light += 1;
Elliot Lee's avatar
Elliot Lee committed
509
510
511
512
513
	      }
	}

      info->dest += info->dest_bpl;

514
515
516
      initial = FALSE;

      if (error >= 1.0)
Elliot Lee's avatar
Elliot Lee committed
517
	{
518
519
	  info->src_y += (int)error;
	  error -= (int)error;
Elliot Lee's avatar
Elliot Lee committed
520
	  info->src = render_image_tile_fault (info);
521
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
522
523
	}

524
      error += step;
Elliot Lee's avatar
Elliot Lee committed
525
526
527
528
    }
}

static void
529
render_image_gray (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
530
531
532
{
  guchar *src;
  guchar *dest;
533
534
535
536
537
538
539
540
541
  gulong  val;
  gint    byte_order;
  gint    y, ye;
  gint    x, xe;
  gint    initial;
  gfloat  error;
  gfloat  step;

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

545
546
  step = 1.0 / info->scaley;

547
548
  error  = y * step;
  error -= ((gint) error) - step;
549

Elliot Lee's avatar
Elliot Lee committed
550
551
552
553
554
555
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
556
      if (!initial && (error < 1.0))
557
558
559
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
560
561
562
563
      else
	{
	  src = info->src;
	  dest = info->dest;
564
	  
565
566
	  g_return_if_fail (src != NULL);

567
568
569
570
	  for (x = info->x; x < xe; x++)
	    {
	      val = src[GRAY_PIX];
	      src += 1;
Elliot Lee's avatar
Elliot Lee committed
571

572
573
574
575
576
	      dest[0] = val;
	      dest[1] = val;
	      dest[2] = val;
	      dest += 3;
	    }
Elliot Lee's avatar
Elliot Lee committed
577
578
579
580
	}

      info->dest += info->dest_bpl;

581
582
583
      initial = FALSE;

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

591
      error += step;
Elliot Lee's avatar
Elliot Lee committed
592
593
594
595
    }
}

static void
596
render_image_gray_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
597
598
599
{
  guchar *src;
  guchar *dest;
600
601
602
603
604
605
606
607
608
609
  guint  *alpha;
  gulong  val;
  guint   a;
  gint    dark_light;
  gint    byte_order;
  gint    y, ye;
  gint    x, xe;
  gint    initial;
  gfloat  error;
  gfloat  step;
Elliot Lee's avatar
Elliot Lee committed
610
611
612

  alpha = info->alpha;

613
  y  = info->y;
Elliot Lee's avatar
Elliot Lee committed
614
615
616
  ye = info->y + info->h;
  xe = info->x + info->w;

617
618
  step = 1.0 / info->scaley;

619
620
  error  = y * step;
  error -= ((gint) error) - step;
621

Elliot Lee's avatar
Elliot Lee committed
622
623
624
625
626
627
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
628
      if (!initial && (error < 1.0) && (y & check_mod))
629
630
631
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
632
633
634
635
636
637
638
      else
	{
	  src = info->src;
	  dest = info->dest;

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

639
640
	  g_return_if_fail (src != NULL);

641
642
643
644
	  for (x = info->x; x < xe; x++)
	    {
	      a = alpha[src[ALPHA_G_PIX]];
	      if (dark_light & 0x1)
645
		val = render_blend_dark_check[(a | src[GRAY_PIX])];
646
	      else
647
		val = render_blend_light_check[(a | src[GRAY_PIX])];
648
649
650
651
652
653
654
655
656
657
	      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
658
659
660
661
	}

      info->dest += info->dest_bpl;

662
663
664
      initial = FALSE;

      if (error >= 1.0)
Elliot Lee's avatar
Elliot Lee committed
665
	{
666
667
	  info->src_y += (int)error;
	  error -= (int)error;
Elliot Lee's avatar
Elliot Lee committed
668
	  info->src = render_image_tile_fault (info);
669
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
670
671
	}

672
      error += step;
Elliot Lee's avatar
Elliot Lee committed
673
674
675
676
    }
}

static void
677
render_image_rgb (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
678
{
679
680
  gint    byte_order;
  gint    y, ye;
681
  gint    xe;
682
683
684
685
686
  gint    initial;
  gfloat  error;
  gfloat  step;

  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
687
688
689
690
  ye = info->y + info->h;
  xe = info->x + info->w;

  step = 1.0 / info->scaley;
691

692
693
  error  = y * step;
  error -= (gint) error - step;
694

Elliot Lee's avatar
Elliot Lee committed
695
  initial = TRUE;
Daniel Egger's avatar
Daniel Egger committed
696
  byte_order = info->byte_order;
Elliot Lee's avatar
Elliot Lee committed
697
698
699
700
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
701
      if (!initial && (error < 1.0))
702
703
704
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
705
706
      else
	{
707
	  g_return_if_fail (info->src != NULL);
708

709
          memcpy (info->dest, info->src, 3 * info->w);
Elliot Lee's avatar
Elliot Lee committed
710
711
712
713
	}

      info->dest += info->dest_bpl;

714
715
716
      initial = FALSE;

      if (error >= 1.0)
Elliot Lee's avatar
Elliot Lee committed
717
	{
718
719
	  info->src_y += (int)error;
	  error -= (int)error;
Elliot Lee's avatar
Elliot Lee committed
720
	  info->src = render_image_tile_fault (info);
721
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
722
723
	}

724
      error += step;
Elliot Lee's avatar
Elliot Lee committed
725
726
727
728
    }
}

static void
729
render_image_rgb_a (RenderInfo *info)
Elliot Lee's avatar
Elliot Lee committed
730
731
732
{
  guchar *src;
  guchar *dest;
733
734
735
736
737
738
739
740
741
742
  guint  *alpha;
  gulong  r, g, b;
  guint   a;
  gint    dark_light;
  gint    byte_order;
  gint    y, ye;
  gint    x, xe;
  gint    initial;
  gfloat  error;
  gfloat  step;
Elliot Lee's avatar
Elliot Lee committed
743
744
745

  alpha = info->alpha;

746
  y  = info->y;
Daniel Egger's avatar
Daniel Egger committed
747
748
749
750
  ye = info->y + info->h;
  xe = info->x + info->w;

  step = 1.0 / info->scaley;
751

752
753
  error  = y * step;
  error -= ((gint) error) - step;
754

Elliot Lee's avatar
Elliot Lee committed
755
756
757
758
759
760
  initial = TRUE;
  byte_order = info->byte_order;
  info->src = render_image_tile_fault (info);

  for (; y < ye; y++)
    {
761
      if (!initial && (error < 1.0) && (y & check_mod))
762
763
764
	{
	  memcpy (info->dest, info->dest - info->dest_bpl, info->dest_width);
	}
Elliot Lee's avatar
Elliot Lee committed
765
766
767
768
769
770
771
      else
	{
	  src = info->src;
	  dest = info->dest;

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

772
773
	  g_return_if_fail (src != NULL);

774
775
776
777
778
	  for (x = info->x; x < xe; x++)
	    {
	      a = alpha[src[ALPHA_PIX]];
	      if (dark_light & 0x1)
		{
779
780
781
		  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])];
782
783
784
		}
	      else
		{
785
786
787
		  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])];
788
		}
Elliot Lee's avatar
Elliot Lee committed
789

790
	      src += 4;
Elliot Lee's avatar
Elliot Lee committed
791

792
793
794
795
	      dest[0] = r;
	      dest[1] = g;
	      dest[2] = b;
	      dest += 3;
Elliot Lee's avatar
Elliot Lee committed
796

797
798
799
	      if (((x + 1) & check_mod) == 0)
		dark_light += 1;
	    }
Elliot Lee's avatar
Elliot Lee committed
800
801
802
803
	}

      info->dest += info->dest_bpl;

804
805
806
      initial = FALSE;

      if (error >= 1.0)
Elliot Lee's avatar
Elliot Lee committed
807
	{
808
809
	  info->src_y += (int)error;
	  error -= (int)error;
Elliot Lee's avatar
Elliot Lee committed
810
	  info->src = render_image_tile_fault (info);
811
	  initial = TRUE;
Elliot Lee's avatar
Elliot Lee committed
812
813
	}

814
      error += step;
Elliot Lee's avatar
Elliot Lee committed
815
816
817
818
    }
}

static void
819
820
821
822
823
824
render_image_init_info (RenderInfo       *info,
			GimpDisplayShell *shell,
			gint              x,
			gint              y,
			gint              w,
			gint              h)
Elliot Lee's avatar
Elliot Lee committed
825
{
826
827
828
829
  info->shell      = shell;
  info->src_tiles  = gimp_image_projection (shell->gdisp->gimage);
  info->x          = x + shell->offset_x;
  info->y          = y + shell->offset_y;
830
831
  info->w          = w;
  info->h          = h;
832
833
834
835
  info->scalex     = SCALEFACTOR_X (shell);
  info->scaley     = SCALEFACTOR_Y (shell);
  info->src_x      = UNSCALEX (shell, info->x);
  info->src_y      = UNSCALEY (shell, info->y);
836
837
838
839
  info->src_bpp    = gimp_image_projection_bytes (shell->gdisp->gimage);
  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
840
  info->dest_width = info->w * info->dest_bpp;
841
  info->byte_order = GDK_MSB_FIRST;
Sven Neumann's avatar
Sven Neumann committed
842
843
  info->scale      = render_image_accelerate_scaling (w,
                                                      info->x, info->scalex);
844
  info->alpha      = NULL;
Elliot Lee's avatar
Elliot Lee committed
845

846
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_image_projection_type (shell->gdisp->gimage)))
Elliot Lee's avatar
Elliot Lee committed
847
    {
848
      info->alpha =
849
	render_image_init_alpha (gimp_image_projection_opacity (shell->gdisp->gimage) * 255.999);
Elliot Lee's avatar
Elliot Lee committed
850
851
852
853
    }
}

static guint*
854
render_image_init_alpha (gint mult)
Elliot Lee's avatar
Elliot Lee committed
855
856
{
  static guint *alpha_mult = NULL;
857
858
859
  static gint   alpha_val  = -1;

  gint i;
Elliot Lee's avatar
Elliot Lee committed
860
861
862
863

  if (alpha_val != mult)
    {
      if (!alpha_mult)
864
	alpha_mult = g_new (guint, 256);
Elliot Lee's avatar
Elliot Lee committed
865
866
867
868
869
870
871
872
873

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

  return alpha_mult;
}

874
static guchar *
875
876
877
render_image_accelerate_scaling (gint   width,
				 gint   start,
				 gfloat scalex)
Elliot Lee's avatar
Elliot Lee committed
878
879
{
  static guchar *scale = NULL;
880
881
882
883

  gfloat error;
  gfloat step;
  gint   i;
Elliot Lee's avatar
Elliot Lee committed
884

885
886
  if (! scale)
    scale = g_new (guchar, GIMP_DISPLAY_SHELL_RENDER_BUF_WIDTH + 1);
Elliot Lee's avatar
Elliot Lee committed
887

888
  step = 1.0 / scalex;
Elliot Lee's avatar
Elliot Lee committed
889

890
  error = start * step;
891
  error -= ((gint) error) - step;
892
893

  for (i = 0; i <= width; i++)
894
895
896
897
    {
      scale[i] = ((gint) error);
      error += step - (gint) error;
    }
Elliot Lee's avatar
Elliot Lee committed
898
899
900
901

  return scale;
}

902
static guchar *
Elliot Lee's avatar
Elliot Lee committed
903
904
render_image_tile_fault (RenderInfo *info)
{
905
  Tile   *tile;
Elliot Lee's avatar
Elliot Lee committed
906
907
908
  guchar *data;
  guchar *dest;
  guchar *scale;
909
910
911
912
913
914
  gint    width;
  gint    tilex;
  gint    tiley;
  gint    step;
  gint    bpp = info->src_bpp;
  gint    x, b;
Elliot Lee's avatar
Elliot Lee committed
915
916
917
918

  tilex = info->src_x / TILE_WIDTH;
  tiley = info->src_y / TILE_HEIGHT;

919
  tile = tile_manager_get_tile (info->src_tiles,
Sven Neumann's avatar
Sven Neumann committed
920
				info->src_x, info->src_y,
921
				TRUE, FALSE);
Elliot Lee's avatar
Elliot Lee committed
922
923
924
  if (!tile)
    return NULL;

scott's avatar
scott committed
925
926
927
  data = tile_data_pointer (tile, 
			    info->src_x % TILE_WIDTH,
			    info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
928
  scale = info->scale;
929
  dest  = tile_buf;
Elliot Lee's avatar
Elliot Lee committed
930

931
  x     = info->src_x;
Elliot Lee's avatar
Elliot Lee committed
932
933
934
935
  width = info->w;

  while (width--)
    {
936
      for (b = 0; b < bpp; b++)
Elliot Lee's avatar
Elliot Lee committed
937
938
	*dest++ = data[b];

939
940
      step = *scale++;
      if (step != 0)
Elliot Lee's avatar
Elliot Lee committed
941
	{
942
943
	  x += step;
	  data += step * bpp;
Elliot Lee's avatar
Elliot Lee committed
944

Daniel Egger's avatar
Daniel Egger committed
945
	  if ((x >> tile_shift) != tilex)
Elliot Lee's avatar
Elliot Lee committed
946
	    {
947
	      tile_release (tile, FALSE);
Elliot Lee's avatar
Elliot Lee committed
948
949
	      tilex += 1;

Sven Neumann's avatar
Sven Neumann committed
950
951
952
953
	      tile = tile_manager_get_tile (info->src_tiles,
                                            x, info->src_y,
                                            TRUE, FALSE);

Daniel Egger's avatar
Daniel Egger committed
954
955
956
	      if (!tile)
		return tile_buf;

scott's avatar
scott committed
957
	      data = tile_data_pointer (tile, 
Sven Neumann's avatar
Sven Neumann committed
958
959
                                        x % TILE_WIDTH,
                                        info->src_y % TILE_HEIGHT);
Elliot Lee's avatar
Elliot Lee committed
960
961
962
963
	    }
	}
    }

964
  tile_release (tile, FALSE);
965

Elliot Lee's avatar
Elliot Lee committed
966
967
  return tile_buf;
}