~ubuntu-branches/ubuntu/vivid/gdk-pixbuf/vivid

« back to all changes in this revision

Viewing changes to gdk-pixbuf/pixops/pixops.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2004-10-06 22:10:04 UTC
  • Revision ID: james.westby@ubuntu.com-20041006221004-rma9deknj8qctu67
Tags: upstream-0.22.0
ImportĀ upstreamĀ versionĀ 0.22.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <math.h>
 
2
#include <glib.h>
 
3
#include "config.h"
 
4
 
 
5
#include "pixops.h"
 
6
#include "pixops-internal.h"
 
7
 
 
8
#define SUBSAMPLE_BITS 4
 
9
#define SUBSAMPLE (1 << SUBSAMPLE_BITS)
 
10
#define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1)
 
11
#define SCALE_SHIFT 16
 
12
 
 
13
typedef struct _PixopsFilter PixopsFilter;
 
14
 
 
15
struct _PixopsFilter
 
16
{
 
17
  int *weights;
 
18
  int n_x;
 
19
  int n_y;
 
20
  double x_offset;
 
21
  double y_offset;
 
22
}; 
 
23
 
 
24
typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
 
25
                                   guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
26
                                   guchar **src, int src_channels, gboolean src_has_alpha,
 
27
                                   int x_init, int x_step, int src_width,
 
28
                                   int check_size, guint32 color1, guint32 color2);
 
29
 
 
30
typedef void (*PixopsPixelFunc) (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
 
31
                                 int src_has_alpha, int check_size, guint32 color1,
 
32
                                 guint32 color2,
 
33
                                 guint r, guint g, guint b, guint a);
 
34
 
 
35
static int
 
36
get_check_shift (int check_size)
 
37
{
 
38
  int check_shift = 0;
 
39
  g_return_val_if_fail (check_size >= 0, 4);
 
40
 
 
41
  while (!(check_size & 1))
 
42
    {
 
43
      check_shift++;
 
44
      check_size >>= 1;
 
45
    }
 
46
 
 
47
  return check_shift;
 
48
}
 
49
 
 
50
static void
 
51
pixops_scale_nearest (guchar        *dest_buf,
 
52
                      int            render_x0,
 
53
                      int            render_y0,
 
54
                      int            render_x1,
 
55
                      int            render_y1,
 
56
                      int            dest_rowstride,
 
57
                      int            dest_channels,
 
58
                      gboolean       dest_has_alpha,
 
59
                      const guchar  *src_buf,
 
60
                      int            src_width,
 
61
                      int            src_height,
 
62
                      int            src_rowstride,
 
63
                      int            src_channels,
 
64
                      gboolean       src_has_alpha,
 
65
                      double         scale_x,
 
66
                      double         scale_y)
 
67
{
 
68
  int i, j;
 
69
  int x;
 
70
  int x_step = (1 << SCALE_SHIFT) / scale_x;
 
71
  int y_step = (1 << SCALE_SHIFT) / scale_y;
 
72
 
 
73
#define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS)                  \
 
74
      for (j=0; j < (render_x1 - render_x0); j++)               \
 
75
        {                                                       \
 
76
          const guchar *p = src + (x >> SCALE_SHIFT) * SRC_CHANNELS;    \
 
77
                                                                \
 
78
          dest[0] = p[0];                                       \
 
79
          dest[1] = p[1];                                       \
 
80
          dest[2] = p[2];                                       \
 
81
                                                                \
 
82
          if (DEST_CHANNELS == 4)                               \
 
83
            {                                                   \
 
84
              if (SRC_CHANNELS == 4)                            \
 
85
                dest[3] = p[3];                                 \
 
86
              else                                              \
 
87
                dest[3] = 0xff;                                 \
 
88
            }                                                   \
 
89
                                                                \
 
90
          dest += DEST_CHANNELS;                                \
 
91
          x += x_step;                                          \
 
92
        }
 
93
 
 
94
  for (i = 0; i < (render_y1 - render_y0); i++)
 
95
    {
 
96
      const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
 
97
      guchar       *dest = dest_buf + i * dest_rowstride;
 
98
 
 
99
      x = render_x0 * x_step + x_step / 2;
 
100
 
 
101
      if (src_channels == 3)
 
102
        {
 
103
          if (dest_channels == 3)
 
104
            {
 
105
              INNER_LOOP (3, 3);
 
106
            }
 
107
          else
 
108
            {
 
109
              INNER_LOOP (3, 4);
 
110
            }
 
111
        }
 
112
      else if (src_channels == 4)
 
113
        {
 
114
          if (dest_channels == 3)
 
115
            {
 
116
              INNER_LOOP (4, 3);
 
117
            }
 
118
          else
 
119
            {
 
120
              for (j=0; j < (render_x1 - render_x0); j++)
 
121
                {
 
122
                  const guchar *p = src + (x >> SCALE_SHIFT) * 4;
 
123
                  guint32 *p32;
 
124
 
 
125
                  p32 = (guint32 *) dest;
 
126
                  *p32 = *((guint32 *) p);
 
127
 
 
128
                  dest += 4;
 
129
                  x += x_step;
 
130
                }
 
131
            }
 
132
        }
 
133
    }
 
134
#undef INNER_LOOP
 
135
}
 
136
 
 
137
static void
 
138
pixops_composite_nearest (guchar        *dest_buf,
 
139
                          int            render_x0,
 
140
                          int            render_y0,
 
141
                          int            render_x1,
 
142
                          int            render_y1,
 
143
                          int            dest_rowstride,
 
144
                          int            dest_channels,
 
145
                          gboolean       dest_has_alpha,
 
146
                          const guchar  *src_buf,
 
147
                          int            src_width,
 
148
                          int            src_height,
 
149
                          int            src_rowstride,
 
150
                          int            src_channels,
 
151
                          gboolean       src_has_alpha,
 
152
                          double         scale_x,
 
153
                          double         scale_y,
 
154
                          int            overall_alpha)
 
155
{
 
156
  int i, j;
 
157
  int x;
 
158
  int x_step = (1 << SCALE_SHIFT) / scale_x;
 
159
  int y_step = (1 << SCALE_SHIFT) / scale_y;
 
160
 
 
161
  for (i = 0; i < (render_y1 - render_y0); i++)
 
162
    {
 
163
      const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
 
164
      guchar       *dest = dest_buf + i * dest_rowstride;
 
165
 
 
166
      x = render_x0 * x_step + x_step / 2;
 
167
      
 
168
      for (j=0; j < (render_x1 - render_x0); j++)
 
169
        {
 
170
          const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
 
171
          unsigned int  a0;
 
172
 
 
173
          if (src_has_alpha)
 
174
            a0 = (p[3] * overall_alpha) / 0xff;
 
175
          else
 
176
            a0 = overall_alpha;
 
177
 
 
178
          switch (a0)
 
179
            {
 
180
            case 0:
 
181
              break;
 
182
            case 255:
 
183
              dest[0] = p[0];
 
184
              dest[1] = p[1];
 
185
              dest[2] = p[2];
 
186
              if (dest_has_alpha)
 
187
                dest[3] = 0xff;
 
188
              break;
 
189
            default:
 
190
              if (dest_has_alpha)
 
191
                {
 
192
                  unsigned int w0 = 0xff * a0;
 
193
                  unsigned int w1 = (0xff - a0) * dest[3];
 
194
                  unsigned int w = w0 + w1;
 
195
 
 
196
                  dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
 
197
                  dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
 
198
                  dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
 
199
                  dest[3] = w / 0xff;
 
200
                }
 
201
              else
 
202
                {
 
203
                  unsigned int a1 = 0xff - a0;
 
204
                  unsigned int tmp;
 
205
 
 
206
                  tmp = a0 * p[0] + a1 * dest[0] + 0x80;
 
207
                  dest[0] = (tmp + (tmp >> 8)) >> 8;
 
208
                  tmp = a0 * p[1] + a1 * dest[1] + 0x80;
 
209
                  dest[1] = (tmp + (tmp >> 8)) >> 8;
 
210
                  tmp = a0 * p[2] + a1 * dest[2] + 0x80;
 
211
                  dest[2] = (tmp + (tmp >> 8)) >> 8;
 
212
                }
 
213
              break;
 
214
            }
 
215
          dest += dest_channels;
 
216
          x += x_step;
 
217
        }
 
218
    }
 
219
}
 
220
 
 
221
static void
 
222
pixops_composite_color_nearest (guchar        *dest_buf,
 
223
                                int            render_x0,
 
224
                                int            render_y0,
 
225
                                int            render_x1,
 
226
                                int            render_y1,
 
227
                                int            dest_rowstride,
 
228
                                int            dest_channels,
 
229
                                gboolean       dest_has_alpha,
 
230
                                const guchar  *src_buf,
 
231
                                int            src_width,
 
232
                                int            src_height,
 
233
                                int            src_rowstride,
 
234
                                int            src_channels,
 
235
                                gboolean       src_has_alpha,
 
236
                                double         scale_x,
 
237
                                double         scale_y,
 
238
                                int            overall_alpha,
 
239
                                int            check_x,
 
240
                                int            check_y,
 
241
                                int            check_size,
 
242
                                guint32        color1,
 
243
                                guint32        color2)
 
244
{
 
245
  int i, j;
 
246
  int x;
 
247
  int x_step = (1 << SCALE_SHIFT) / scale_x;
 
248
  int y_step = (1 << SCALE_SHIFT) / scale_y;
 
249
  int r1, g1, b1, r2, g2, b2;
 
250
  int check_shift = get_check_shift (check_size);
 
251
 
 
252
  for (i = 0; i < (render_y1 - render_y0); i++)
 
253
    {
 
254
      const guchar *src  = src_buf + (((i + render_y0) * y_step + y_step/2) >> SCALE_SHIFT) * src_rowstride;
 
255
      guchar       *dest = dest_buf + i * dest_rowstride;
 
256
 
 
257
      x = render_x0 * x_step + x_step / 2;
 
258
      
 
259
      if (((i + check_y) >> check_shift) & 1)
 
260
        {
 
261
          r1 = (color2 & 0xff0000) >> 16;
 
262
          g1 = (color2 & 0xff00) >> 8;
 
263
          b1 = color2 & 0xff;
 
264
 
 
265
          r2 = (color1 & 0xff0000) >> 16;
 
266
          g2 = (color1 & 0xff00) >> 8;
 
267
          b2 = color1 & 0xff;
 
268
        }
 
269
      else
 
270
        {
 
271
          r1 = (color1 & 0xff0000) >> 16;
 
272
          g1 = (color1 & 0xff00) >> 8;
 
273
          b1 = color1 & 0xff;
 
274
 
 
275
          r2 = (color2 & 0xff0000) >> 16;
 
276
          g2 = (color2 & 0xff00) >> 8;
 
277
          b2 = color2 & 0xff;
 
278
        }
 
279
 
 
280
      for (j=0 ; j < (render_x1 - render_x0); j++)
 
281
        {
 
282
          const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
 
283
          int a0;
 
284
          int tmp;
 
285
 
 
286
          if (src_has_alpha)
 
287
            a0 = (p[3] * overall_alpha + 0xff) >> 8;
 
288
          else
 
289
            a0 = overall_alpha;
 
290
 
 
291
          switch (a0)
 
292
            {
 
293
            case 0:
 
294
              if (((j + check_x) >> check_shift) & 1)
 
295
                {
 
296
                  dest[0] = r2; 
 
297
                  dest[1] = g2; 
 
298
                  dest[2] = b2;
 
299
                }
 
300
              else
 
301
                {
 
302
                  dest[0] = r1; 
 
303
                  dest[1] = g1; 
 
304
                  dest[2] = b1;
 
305
                }
 
306
            break;
 
307
            case 255:
 
308
              dest[0] = p[0];
 
309
              dest[1] = p[1];
 
310
              dest[2] = p[2];
 
311
              break;
 
312
            default:
 
313
              if (((j + check_x) >> check_shift) & 1)
 
314
                {
 
315
                  tmp = ((int) p[0] - r2) * a0;
 
316
                  dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
317
                  tmp = ((int) p[1] - g2) * a0;
 
318
                  dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
319
                  tmp = ((int) p[2] - b2) * a0;
 
320
                  dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
321
                }
 
322
              else
 
323
                {
 
324
                  tmp = ((int) p[0] - r1) * a0;
 
325
                  dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
326
                  tmp = ((int) p[1] - g1) * a0;
 
327
                  dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
328
                  tmp = ((int) p[2] - b1) * a0;
 
329
                  dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
 
330
                }
 
331
              break;
 
332
            }
 
333
          
 
334
          if (dest_channels == 4)
 
335
            dest[3] = 0xff;
 
336
 
 
337
          dest += dest_channels;
 
338
          x += x_step;
 
339
        }
 
340
    }
 
341
}
 
342
 
 
343
static void
 
344
composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
 
345
                 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
 
346
                 guint r, guint g, guint b, guint a)
 
347
{
 
348
  if (dest_has_alpha)
 
349
    {
 
350
      unsigned int w0 = a - (a >> 8);
 
351
      unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
 
352
      unsigned int w = w0 + w1;
 
353
      
 
354
      if (w != 0)
 
355
        {
 
356
          dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
 
357
          dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
 
358
          dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
 
359
          dest[3] = w / 0xff00;
 
360
        }
 
361
      else
 
362
        {
 
363
          dest[0] = 0;
 
364
          dest[1] = 0;
 
365
          dest[2] = 0;
 
366
          dest[3] = 0;
 
367
        }
 
368
    }
 
369
  else
 
370
    {
 
371
      dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
 
372
      dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
 
373
      dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
 
374
    }
 
375
}
 
376
 
 
377
static guchar *
 
378
composite_line (int *weights, int n_x, int n_y,
 
379
                guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
380
                guchar **src, int src_channels, gboolean src_has_alpha,
 
381
                int x_init, int x_step, int src_width,
 
382
                int check_size, guint32 color1, guint32 color2)
 
383
{
 
384
  int x = x_init;
 
385
  int i, j;
 
386
 
 
387
  while (dest < dest_end)
 
388
    {
 
389
      int x_scaled = x >> SCALE_SHIFT;
 
390
      unsigned int r = 0, g = 0, b = 0, a = 0;
 
391
      int *pixel_weights;
 
392
      
 
393
      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
 
394
      
 
395
      for (i=0; i<n_y; i++)
 
396
        {
 
397
          guchar *q = src[i] + x_scaled * src_channels;
 
398
          int *line_weights = pixel_weights + n_x * i;
 
399
          
 
400
          for (j=0; j<n_x; j++)
 
401
            {
 
402
              unsigned int ta;
 
403
 
 
404
              if (src_has_alpha)
 
405
                ta = q[3] * line_weights[j];
 
406
              else
 
407
                ta = 0xff * line_weights[j];
 
408
              
 
409
              r += ta * q[0];
 
410
              g += ta * q[1];
 
411
              b += ta * q[2];
 
412
              a += ta;
 
413
 
 
414
              q += src_channels;
 
415
            }
 
416
        }
 
417
 
 
418
      if (dest_has_alpha)
 
419
        {
 
420
          unsigned int w0 = a - (a >> 8);
 
421
          unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
 
422
          unsigned int w = w0 + w1;
 
423
 
 
424
          if (w != 0)
 
425
            {
 
426
              dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
 
427
              dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
 
428
              dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
 
429
              dest[3] = w / 0xff00;
 
430
            }
 
431
          else
 
432
            {
 
433
              dest[0] = 0;
 
434
              dest[1] = 0;
 
435
              dest[2] = 0;
 
436
              dest[3] = 0;
 
437
            }
 
438
        }
 
439
      else
 
440
        {
 
441
          dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
 
442
          dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
 
443
          dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
 
444
        }
 
445
      
 
446
      dest += dest_channels;
 
447
      x += x_step;
 
448
    }
 
449
 
 
450
  return dest;
 
451
}
 
452
 
 
453
static guchar *
 
454
composite_line_22_4a4 (int *weights, int n_x, int n_y,
 
455
                       guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
456
                       guchar **src, int src_channels, gboolean src_has_alpha,
 
457
                       int x_init, int x_step, int src_width,
 
458
                       int check_size, guint32 color1, guint32 color2)
 
459
{
 
460
  int x = x_init;
 
461
  guchar *src0 = src[0];
 
462
  guchar *src1 = src[1];
 
463
 
 
464
  g_return_val_if_fail (src_channels != 3, dest);
 
465
  g_return_val_if_fail (src_has_alpha, dest);
 
466
  
 
467
  while (dest < dest_end)
 
468
    {
 
469
      int x_scaled = x >> SCALE_SHIFT;
 
470
      unsigned int r, g, b, a, ta;
 
471
      int *pixel_weights;
 
472
      guchar *q0, *q1;
 
473
      int w1, w2, w3, w4;
 
474
      
 
475
      q0 = src0 + x_scaled * 4;
 
476
      q1 = src1 + x_scaled * 4;
 
477
      
 
478
      pixel_weights = (int *)((char *)weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS - 4)) & (SUBSAMPLE_MASK << 4)));
 
479
      
 
480
      w1 = pixel_weights[0];
 
481
      w2 = pixel_weights[1];
 
482
      w3 = pixel_weights[2];
 
483
      w4 = pixel_weights[3];
 
484
 
 
485
      a = w1 * q0[3];
 
486
      r = a * q0[0];
 
487
      g = a * q0[1];
 
488
      b = a * q0[2];
 
489
 
 
490
      ta = w2 * q0[7];
 
491
      r += ta * q0[4];
 
492
      g += ta * q0[5];
 
493
      b += ta * q0[6];
 
494
      a += ta;
 
495
 
 
496
      ta = w3 * q1[3];
 
497
      r += ta * q1[0];
 
498
      g += ta * q1[1];
 
499
      b += ta * q1[2];
 
500
      a += ta;
 
501
 
 
502
      ta = w4 * q1[7];
 
503
      r += ta * q1[4];
 
504
      g += ta * q1[5];
 
505
      b += ta * q1[6];
 
506
      a += ta;
 
507
 
 
508
      dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
 
509
      dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
 
510
      dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
 
511
      dest[3] = a >> 16;
 
512
      
 
513
      dest += 4;
 
514
      x += x_step;
 
515
    }
 
516
 
 
517
  return dest;
 
518
}
 
519
 
 
520
#ifdef USE_MMX
 
521
static guchar *
 
522
composite_line_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
 
523
                                guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
524
                                guchar **src, int src_channels, gboolean src_has_alpha,
 
525
                                int x_init, int x_step, int src_width,
 
526
                                int check_size, guint32 color1, guint32 color2)
 
527
{
 
528
  guint32 mmx_weights[16][8];
 
529
  int j;
 
530
 
 
531
  for (j=0; j<16; j++)
 
532
    {
 
533
      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
 
534
      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
 
535
      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
 
536
      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
 
537
      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
 
538
      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
 
539
      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
 
540
      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
 
541
    }
 
542
 
 
543
  return pixops_composite_line_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
 
544
}
 
545
#endif /* USE_MMX */
 
546
 
 
547
static void
 
548
composite_pixel_color (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
 
549
                       int src_has_alpha, int check_size, guint32 color1, guint32 color2,
 
550
                       guint r, guint g, guint b, guint a)
 
551
{
 
552
  int dest_r, dest_g, dest_b;
 
553
  int check_shift = get_check_shift (check_size);
 
554
 
 
555
  if ((dest_x >> check_shift) & 1)
 
556
    {
 
557
      dest_r = (color2 & 0xff0000) >> 16;
 
558
      dest_g = (color2 & 0xff00) >> 8;
 
559
      dest_b = color2 & 0xff;
 
560
    }
 
561
  else
 
562
    {
 
563
      dest_r = (color1 & 0xff0000) >> 16;
 
564
      dest_g = (color1 & 0xff00) >> 8;
 
565
      dest_b = color1 & 0xff;
 
566
    }
 
567
 
 
568
  dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
 
569
  dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
 
570
  dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
 
571
 
 
572
  if (dest_has_alpha)
 
573
    dest[3] = 0xff;
 
574
  else if (dest_channels == 4)
 
575
    dest[3] = a >> 16;
 
576
}
 
577
 
 
578
static guchar *
 
579
composite_line_color (int *weights, int n_x, int n_y,
 
580
                      guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
581
                      guchar **src, int src_channels, gboolean src_has_alpha,
 
582
                      int x_init, int x_step, int src_width,
 
583
                      int check_size, guint32 color1, guint32 color2)
 
584
{
 
585
  int x = x_init;
 
586
  int i, j;
 
587
  int check_shift = get_check_shift (check_size);
 
588
  int dest_r1, dest_g1, dest_b1;
 
589
  int dest_r2, dest_g2, dest_b2;
 
590
 
 
591
  g_return_val_if_fail (check_size != 0, dest);
 
592
 
 
593
  dest_r1 = (color1 & 0xff0000) >> 16;
 
594
  dest_g1 = (color1 & 0xff00) >> 8;
 
595
  dest_b1 = color1 & 0xff;
 
596
 
 
597
  dest_r2 = (color2 & 0xff0000) >> 16;
 
598
  dest_g2 = (color2 & 0xff00) >> 8;
 
599
  dest_b2 = color2 & 0xff;
 
600
 
 
601
  while (dest < dest_end)
 
602
    {
 
603
      int x_scaled = x >> SCALE_SHIFT;
 
604
      unsigned int r = 0, g = 0, b = 0, a = 0;
 
605
      int *pixel_weights;
 
606
      
 
607
      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
 
608
 
 
609
      for (i=0; i<n_y; i++)
 
610
        {
 
611
          guchar *q = src[i] + x_scaled * src_channels;
 
612
          int *line_weights = pixel_weights + n_x * i;
 
613
          
 
614
          for (j=0; j<n_x; j++)
 
615
            {
 
616
              unsigned int ta;
 
617
              
 
618
              if (src_has_alpha)
 
619
                ta = q[3] * line_weights[j];
 
620
              else
 
621
                ta = 0xff * line_weights[j];
 
622
                  
 
623
              r += ta * q[0];
 
624
              g += ta * q[1];
 
625
              b += ta * q[2];
 
626
              a += ta;
 
627
 
 
628
              q += src_channels;
 
629
            }
 
630
        }
 
631
 
 
632
      if ((dest_x >> check_shift) & 1)
 
633
        {
 
634
          dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
 
635
          dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
 
636
          dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
 
637
        }
 
638
      else
 
639
        {
 
640
          dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
 
641
          dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
 
642
          dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
 
643
        }
 
644
 
 
645
      if (dest_has_alpha)
 
646
        dest[3] = 0xff;
 
647
      else if (dest_channels == 4)
 
648
        dest[3] = a >> 16;
 
649
        
 
650
      dest += dest_channels;
 
651
      x += x_step;
 
652
      dest_x++;
 
653
    }
 
654
 
 
655
  return dest;
 
656
}
 
657
 
 
658
#ifdef USE_MMX
 
659
static guchar *
 
660
composite_line_color_22_4a4_mmx_stub (int *weights, int n_x, int n_y,
 
661
                                      guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
662
                                      guchar **src, int src_channels, gboolean src_has_alpha,
 
663
                                      int x_init, int x_step, int src_width,
 
664
                                      int check_size, guint32 color1, guint32 color2)
 
665
{
 
666
  guint32 mmx_weights[16][8];
 
667
  int check_shift = get_check_shift (check_size);
 
668
  int colors[4];
 
669
  int j;
 
670
 
 
671
  for (j=0; j<16; j++)
 
672
    {
 
673
      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
 
674
      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
 
675
      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
 
676
      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
 
677
      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
 
678
      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
 
679
      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
 
680
      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
 
681
    }
 
682
 
 
683
  colors[0] = (color1 & 0xff00) << 8 | (color1 & 0xff);
 
684
  colors[1] = (color1 & 0xff0000) >> 16;
 
685
  colors[2] = (color2 & 0xff00) << 8 | (color2 & 0xff);
 
686
  colors[3] = (color2 & 0xff0000) >> 16;
 
687
 
 
688
  return pixops_composite_line_color_22_4a4_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init,
 
689
                                                 dest_x, check_shift, colors);
 
690
}
 
691
#endif /* USE_MMX */
 
692
 
 
693
static void
 
694
scale_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
 
695
             int src_has_alpha, int check_size, guint32 color1, guint32 color2,
 
696
             guint r, guint g, guint b, guint a)
 
697
{
 
698
  if (src_has_alpha)
 
699
    {
 
700
      if (a)
 
701
        {
 
702
          dest[0] = r / a;
 
703
          dest[1] = g / a;
 
704
          dest[2] = b / a;
 
705
          dest[3] = a >> 16;
 
706
        }
 
707
      else
 
708
        {
 
709
          dest[0] = 0;
 
710
          dest[1] = 0;
 
711
          dest[2] = 0;
 
712
          dest[3] = 0;
 
713
        }
 
714
    }
 
715
  else
 
716
    {
 
717
      dest[0] = (r + 0xffffff) >> 24;
 
718
      dest[1] = (g + 0xffffff) >> 24;
 
719
      dest[2] = (b + 0xffffff) >> 24;
 
720
      
 
721
      if (dest_has_alpha)
 
722
        dest[3] = 0xff;
 
723
    }
 
724
}
 
725
 
 
726
static guchar *
 
727
scale_line (int *weights, int n_x, int n_y,
 
728
            guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
729
            guchar **src, int src_channels, gboolean src_has_alpha,
 
730
            int x_init, int x_step, int src_width,
 
731
            int check_size, guint32 color1, guint32 color2)
 
732
{
 
733
  int x = x_init;
 
734
  int i, j;
 
735
 
 
736
  while (dest < dest_end)
 
737
    {
 
738
      int x_scaled = x >> SCALE_SHIFT;
 
739
      int *pixel_weights;
 
740
 
 
741
      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * n_x * n_y;
 
742
 
 
743
      if (src_has_alpha)
 
744
        {
 
745
          unsigned int r = 0, g = 0, b = 0, a = 0;
 
746
          for (i=0; i<n_y; i++)
 
747
            {
 
748
              guchar *q = src[i] + x_scaled * src_channels;
 
749
              int *line_weights  = pixel_weights + n_x * i;
 
750
              
 
751
              for (j=0; j<n_x; j++)
 
752
                {
 
753
                  unsigned int ta;
 
754
                  
 
755
                  ta = q[3] * line_weights[j];
 
756
                  r += ta * q[0];
 
757
                  g += ta * q[1];
 
758
                  b += ta * q[2];
 
759
                  a += ta;
 
760
                  
 
761
                  q += src_channels;
 
762
                }
 
763
            }
 
764
 
 
765
          if (a)
 
766
            {
 
767
              dest[0] = r / a;
 
768
              dest[1] = g / a;
 
769
              dest[2] = b / a;
 
770
              dest[3] = a >> 16;
 
771
            }
 
772
          else
 
773
            {
 
774
              dest[0] = 0;
 
775
              dest[1] = 0;
 
776
              dest[2] = 0;
 
777
              dest[3] = 0;
 
778
            }
 
779
        }
 
780
      else
 
781
        {
 
782
          unsigned int r = 0, g = 0, b = 0;
 
783
          for (i=0; i<n_y; i++)
 
784
            {
 
785
              guchar *q = src[i] + x_scaled * src_channels;
 
786
              int *line_weights  = pixel_weights + n_x * i;
 
787
              
 
788
              for (j=0; j<n_x; j++)
 
789
                {
 
790
                  unsigned int ta = line_weights[j];
 
791
                  
 
792
                  r += ta * q[0];
 
793
                  g += ta * q[1];
 
794
                  b += ta * q[2];
 
795
 
 
796
                  q += src_channels;
 
797
                }
 
798
            }
 
799
 
 
800
          dest[0] = (r + 0xffff) >> 16;
 
801
          dest[1] = (g + 0xffff) >> 16;
 
802
          dest[2] = (b + 0xffff) >> 16;
 
803
          
 
804
          if (dest_has_alpha)
 
805
            dest[3] = 0xff;
 
806
        }
 
807
 
 
808
      dest += dest_channels;
 
809
      
 
810
      x += x_step;
 
811
    }
 
812
 
 
813
  return dest;
 
814
}
 
815
 
 
816
#ifdef USE_MMX 
 
817
static guchar *
 
818
scale_line_22_33_mmx_stub (int *weights, int n_x, int n_y,
 
819
                           guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
820
                           guchar **src, int src_channels, gboolean src_has_alpha,
 
821
                           int x_init, int x_step, int src_width,
 
822
                           int check_size, guint32 color1, guint32 color2)
 
823
{
 
824
  guint32 mmx_weights[16][8];
 
825
  int j;
 
826
 
 
827
  for (j=0; j<16; j++)
 
828
    {
 
829
      mmx_weights[j][0] = 0x00010001 * (weights[4*j] >> 8);
 
830
      mmx_weights[j][1] = 0x00010001 * (weights[4*j] >> 8);
 
831
      mmx_weights[j][2] = 0x00010001 * (weights[4*j + 1] >> 8);
 
832
      mmx_weights[j][3] = 0x00010001 * (weights[4*j + 1] >> 8);
 
833
      mmx_weights[j][4] = 0x00010001 * (weights[4*j + 2] >> 8);
 
834
      mmx_weights[j][5] = 0x00010001 * (weights[4*j + 2] >> 8);
 
835
      mmx_weights[j][6] = 0x00010001 * (weights[4*j + 3] >> 8);
 
836
      mmx_weights[j][7] = 0x00010001 * (weights[4*j + 3] >> 8);
 
837
    }
 
838
 
 
839
  return pixops_scale_line_22_33_mmx (mmx_weights, dest, src[0], src[1], x_step, dest_end, x_init);
 
840
}
 
841
#endif /* USE_MMX */
 
842
 
 
843
static guchar *
 
844
scale_line_22_33 (int *weights, int n_x, int n_y,
 
845
                  guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
 
846
                  guchar **src, int src_channels, gboolean src_has_alpha,
 
847
                  int x_init, int x_step, int src_width,
 
848
                  int check_size, guint32 color1, guint32 color2)
 
849
{
 
850
  int x = x_init;
 
851
  guchar *src0 = src[0];
 
852
  guchar *src1 = src[1];
 
853
  
 
854
  while (dest < dest_end)
 
855
    {
 
856
      unsigned int r, g, b;
 
857
      int x_scaled = x >> SCALE_SHIFT;
 
858
      int *pixel_weights;
 
859
      guchar *q0, *q1;
 
860
      int w1, w2, w3, w4;
 
861
 
 
862
      q0 = src0 + x_scaled * 3;
 
863
      q1 = src1 + x_scaled * 3;
 
864
      
 
865
      pixel_weights = weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * 4;
 
866
 
 
867
      w1 = pixel_weights[0];
 
868
      w2 = pixel_weights[1];
 
869
      w3 = pixel_weights[2];
 
870
      w4 = pixel_weights[3];
 
871
 
 
872
      r = w1 * q0[0];
 
873
      g = w1 * q0[1];
 
874
      b = w1 * q0[2];
 
875
 
 
876
      r += w2 * q0[3];
 
877
      g += w2 * q0[4];
 
878
      b += w2 * q0[5];
 
879
 
 
880
      r += w3 * q1[0];
 
881
      g += w3 * q1[1];
 
882
      b += w3 * q1[2];
 
883
 
 
884
      r += w4 * q1[3];
 
885
      g += w4 * q1[4];
 
886
      b += w4 * q1[5];
 
887
 
 
888
      dest[0] = (r + 0x8000) >> 16;
 
889
      dest[1] = (g + 0x8000) >> 16;
 
890
      dest[2] = (b + 0x8000) >> 16;
 
891
      
 
892
      dest += 3;
 
893
      x += x_step;
 
894
    }
 
895
  
 
896
  return dest;
 
897
}
 
898
 
 
899
static void
 
900
process_pixel (int *weights, int n_x, int n_y,
 
901
               guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
 
902
               guchar **src, int src_channels, gboolean src_has_alpha,
 
903
               int x_start, int src_width,
 
904
               int check_size, guint32 color1, guint32 color2,
 
905
               PixopsPixelFunc pixel_func)
 
906
{
 
907
  unsigned int r = 0, g = 0, b = 0, a = 0;
 
908
  int i, j;
 
909
  
 
910
  for (i=0; i<n_y; i++)
 
911
    {
 
912
      int *line_weights  = weights + n_x * i;
 
913
 
 
914
      for (j=0; j<n_x; j++)
 
915
        {
 
916
          unsigned int ta;
 
917
          guchar *q;
 
918
 
 
919
          if (x_start + j < 0)
 
920
            q = src[i];
 
921
          else if (x_start + j < src_width)
 
922
            q = src[i] + (x_start + j) * src_channels;
 
923
          else
 
924
            q = src[i] + (src_width - 1) * src_channels;
 
925
 
 
926
          if (src_has_alpha)
 
927
            ta = q[3] * line_weights[j];
 
928
          else
 
929
            ta = 0xff * line_weights[j];
 
930
 
 
931
          r += ta * q[0];
 
932
          g += ta * q[1];
 
933
          b += ta * q[2];
 
934
          a += ta;
 
935
        }
 
936
    }
 
937
 
 
938
  (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a);
 
939
}
 
940
 
 
941
static void
 
942
pixops_process (guchar         *dest_buf,
 
943
                int             render_x0,
 
944
                int             render_y0,
 
945
                int             render_x1,
 
946
                int             render_y1,
 
947
                int             dest_rowstride,
 
948
                int             dest_channels,
 
949
                gboolean        dest_has_alpha,
 
950
                const guchar   *src_buf,
 
951
                int             src_width,
 
952
                int             src_height,
 
953
                int             src_rowstride,
 
954
                int             src_channels,
 
955
                gboolean        src_has_alpha,
 
956
                double          scale_x,
 
957
                double          scale_y,
 
958
                int             check_x,
 
959
                int             check_y,
 
960
                int             check_size,
 
961
                guint32         color1,
 
962
                guint32         color2,
 
963
                PixopsFilter   *filter,
 
964
                PixopsLineFunc  line_func,
 
965
                PixopsPixelFunc pixel_func)
 
966
{
 
967
  int i, j;
 
968
  int x, y;                     /* X and Y position in source (fixed_point) */
 
969
  guchar **line_bufs = g_new (guchar *, filter->n_y);
 
970
 
 
971
  int x_step = (1 << SCALE_SHIFT) / scale_x; /* X step in source (fixed point) */
 
972
  int y_step = (1 << SCALE_SHIFT) / scale_y; /* Y step in source (fixed point) */
 
973
 
 
974
  int check_shift = check_size ? get_check_shift (check_size) : 0;
 
975
 
 
976
  int scaled_x_offset = floor (filter->x_offset * (1 << SCALE_SHIFT));
 
977
 
 
978
  /* Compute the index where we run off the end of the source buffer. The furthest
 
979
   * source pixel we access at index i is:
 
980
   *
 
981
   *  ((render_x0 + i) * x_step + scaled_x_offset) >> SCALE_SHIFT + filter->n_x - 1
 
982
   *
 
983
   * So, run_end_index is the smallest i for which this pixel is src_width, i.e, for which:
 
984
   *
 
985
   *  (i + render_x0) * x_step >= ((src_width - filter->n_x + 1) << SCALE_SHIFT) - scaled_x_offset
 
986
   *
 
987
   */
 
988
#define MYDIV(a,b) ((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b))    /* Division so that -1/5 = -1 */
 
989
  
 
990
  int run_end_x = (((src_width - filter->n_x + 1) << SCALE_SHIFT) - scaled_x_offset);
 
991
  int run_end_index = MYDIV (run_end_x + x_step - 1, x_step) - render_x0;
 
992
  run_end_index = MIN (run_end_index, render_x1 - render_x0);
 
993
 
 
994
  y = render_y0 * y_step + floor (filter->y_offset * (1 << SCALE_SHIFT));
 
995
  for (i = 0; i < (render_y1 - render_y0); i++)
 
996
    {
 
997
      int dest_x;
 
998
      int y_start = y >> SCALE_SHIFT;
 
999
      int x_start;
 
1000
      int *run_weights = filter->weights + ((y >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * filter->n_x * filter->n_y * SUBSAMPLE;
 
1001
      guchar *new_outbuf;
 
1002
      guint32 tcolor1, tcolor2;
 
1003
      
 
1004
      guchar *outbuf = dest_buf + dest_rowstride * i;
 
1005
      guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
 
1006
 
 
1007
      if (((i + check_y) >> check_shift) & 1)
 
1008
        {
 
1009
          tcolor1 = color2;
 
1010
          tcolor2 = color1;
 
1011
        }
 
1012
      else
 
1013
        {
 
1014
          tcolor1 = color1;
 
1015
          tcolor2 = color2;
 
1016
        }
 
1017
 
 
1018
      for (j=0; j<filter->n_y; j++)
 
1019
        {
 
1020
          if (y_start <  0)
 
1021
            line_bufs[j] = (guchar *)src_buf;
 
1022
          else if (y_start < src_height)
 
1023
            line_bufs[j] = (guchar *)src_buf + src_rowstride * y_start;
 
1024
          else
 
1025
            line_bufs[j] = (guchar *)src_buf + src_rowstride * (src_height - 1);
 
1026
 
 
1027
          y_start++;
 
1028
        }
 
1029
 
 
1030
      dest_x = check_x;
 
1031
      x = render_x0 * x_step + scaled_x_offset;
 
1032
      x_start = x >> SCALE_SHIFT;
 
1033
 
 
1034
      while (x_start < 0 && outbuf < outbuf_end)
 
1035
        {
 
1036
          process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
 
1037
                         outbuf, dest_x, dest_channels, dest_has_alpha,
 
1038
                         line_bufs, src_channels, src_has_alpha,
 
1039
                         x >> SCALE_SHIFT, src_width,
 
1040
                         check_size, tcolor1, tcolor2, pixel_func);
 
1041
          
 
1042
          x += x_step;
 
1043
          x_start = x >> SCALE_SHIFT;
 
1044
          dest_x++;
 
1045
          outbuf += dest_channels;
 
1046
        }
 
1047
 
 
1048
      new_outbuf = (*line_func) (run_weights, filter->n_x, filter->n_y,
 
1049
                                 outbuf, dest_x,
 
1050
                                 dest_buf + dest_rowstride * i + run_end_index * dest_channels,
 
1051
                                 dest_channels, dest_has_alpha,
 
1052
                                 line_bufs, src_channels, src_has_alpha,
 
1053
                                 x, x_step, src_width, check_size, tcolor1, tcolor2);
 
1054
 
 
1055
      dest_x += (new_outbuf - outbuf) / dest_channels;
 
1056
 
 
1057
      x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
 
1058
      outbuf = new_outbuf;
 
1059
 
 
1060
      while (outbuf < outbuf_end)
 
1061
        {
 
1062
          process_pixel (run_weights + ((x >> (SCALE_SHIFT - SUBSAMPLE_BITS)) & SUBSAMPLE_MASK) * (filter->n_x * filter->n_y), filter->n_x, filter->n_y,
 
1063
                         outbuf, dest_x, dest_channels, dest_has_alpha,
 
1064
                         line_bufs, src_channels, src_has_alpha,
 
1065
                         x >> SCALE_SHIFT, src_width,
 
1066
                         check_size, tcolor1, tcolor2, pixel_func);
 
1067
          
 
1068
          x += x_step;
 
1069
          dest_x++;
 
1070
          outbuf += dest_channels;
 
1071
        }
 
1072
 
 
1073
      y += y_step;
 
1074
    }
 
1075
 
 
1076
  g_free (line_bufs);
 
1077
}
 
1078
 
 
1079
static void 
 
1080
correct_total (int    *weights, 
 
1081
               int    n_x, 
 
1082
               int    n_y,
 
1083
               int    total, 
 
1084
               double overall_alpha)
 
1085
{
 
1086
  int correction = (int)(0.5 + 65536 * overall_alpha) - total;
 
1087
  int i;
 
1088
  for (i = n_x * n_y - 1; i >= 0; i--) 
 
1089
    {
 
1090
      if (*(weights + i) + correction >= 0) 
 
1091
        {
 
1092
          *(weights + i) += correction;
 
1093
          break;
 
1094
        }
 
1095
    }
 
1096
}  
 
1097
 
 
1098
static void
 
1099
tile_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 
1100
{
 
1101
  int i_offset, j_offset;
 
1102
 
 
1103
  int n_x = ceil(1/x_scale + 1);
 
1104
  int n_y = ceil(1/y_scale + 1);
 
1105
 
 
1106
  filter->x_offset = 0;
 
1107
  filter->y_offset = 0;
 
1108
  filter->n_x = n_x;
 
1109
  filter->n_y = n_y;
 
1110
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
 
1111
 
 
1112
  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
 
1113
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
 
1114
      {
 
1115
        int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
 
1116
        double x = (double)j_offset / SUBSAMPLE;
 
1117
        double y = (double)i_offset / SUBSAMPLE;
 
1118
        int i,j;
 
1119
        int total = 0;
 
1120
          
 
1121
        for (i = 0; i < n_y; i++)
 
1122
          {
 
1123
            double tw, th;
 
1124
                
 
1125
            if (i < y)
 
1126
              {
 
1127
 
 
1128
                if (i + 1 > y)
 
1129
                  th = MIN(i+1, y + 1/y_scale) - y;
 
1130
                else
 
1131
                  th = 0;
 
1132
              }
 
1133
            else
 
1134
              {
 
1135
                if (y + 1/y_scale > i)
 
1136
                  th = MIN(i+1, y + 1/y_scale) - i;
 
1137
                else
 
1138
                  th = 0;
 
1139
              }
 
1140
                
 
1141
            for (j = 0; j < n_x; j++)
 
1142
              {
 
1143
                int weight;
 
1144
                
 
1145
                if (j < x)
 
1146
                  {
 
1147
                    if (j + 1 > x)
 
1148
                      tw = MIN(j+1, x + 1/x_scale) - x;
 
1149
                    else
 
1150
                      tw = 0;
 
1151
                  }
 
1152
                else
 
1153
                  {
 
1154
                    if (x + 1/x_scale > j)
 
1155
                      tw = MIN(j+1, x + 1/x_scale) - j;
 
1156
                    else
 
1157
                      tw = 0;
 
1158
                  }
 
1159
 
 
1160
                weight = 65536 * tw * x_scale * th * y_scale * overall_alpha + 0.5;
 
1161
                total += weight;
 
1162
                *(pixel_weights + n_x * i + j) = weight;
 
1163
              }
 
1164
          }
 
1165
        
 
1166
        correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
 
1167
      }
 
1168
}
 
1169
 
 
1170
static void
 
1171
bilinear_make_fast_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 
1172
{
 
1173
  int i_offset, j_offset;
 
1174
  double *x_weights, *y_weights;
 
1175
  int n_x, n_y;
 
1176
 
 
1177
  if (x_scale > 1.0)            /* Bilinear */
 
1178
    {
 
1179
      n_x = 2;
 
1180
      filter->x_offset = 0.5 * (1/x_scale - 1);
 
1181
    }
 
1182
  else                          /* Tile */
 
1183
    {
 
1184
      n_x = ceil(1.0 + 1.0/x_scale);
 
1185
      filter->x_offset = 0.0;
 
1186
    }
 
1187
 
 
1188
  if (y_scale > 1.0)            /* Bilinear */
 
1189
    {
 
1190
      n_y = 2;
 
1191
      filter->y_offset = 0.5 * (1/y_scale - 1);
 
1192
    }
 
1193
  else                          /* Tile */
 
1194
    {
 
1195
      n_y = ceil(1.0 + 1.0/y_scale);
 
1196
      filter->y_offset = 0.0;
 
1197
    }
 
1198
 
 
1199
  filter->n_y = n_y;
 
1200
  filter->n_x = n_x;
 
1201
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
 
1202
 
 
1203
  x_weights = g_new (double, n_x);
 
1204
  y_weights = g_new (double, n_y);
 
1205
 
 
1206
  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
 
1207
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
 
1208
      {
 
1209
        int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
 
1210
        double x = (double)j_offset / SUBSAMPLE;
 
1211
        double y = (double)i_offset / SUBSAMPLE;
 
1212
        int i,j;
 
1213
        int total = 0;
 
1214
 
 
1215
        if (x_scale > 1.0)      /* Bilinear */
 
1216
          {
 
1217
            for (i = 0; i < n_x; i++)
 
1218
              {
 
1219
                x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale;
 
1220
              }
 
1221
          }
 
1222
        else                    /* Tile */
 
1223
          {
 
1224
            /*           x
 
1225
             * ---------|--.-|----|--.-|-------  SRC
 
1226
             * ------------|---------|---------  DEST
 
1227
             */
 
1228
            for (i = 0; i < n_x; i++)
 
1229
              {
 
1230
                if (i < x)
 
1231
                  {
 
1232
                    if (i + 1 > x)
 
1233
                      x_weights[i] = MIN(i+1, x + 1/x_scale) - x;
 
1234
                    else
 
1235
                      x_weights[i] = 0;
 
1236
                  }
 
1237
                else
 
1238
                  {
 
1239
                    if (x + 1/x_scale > i)
 
1240
                      x_weights[i] = MIN(i+1, x + 1/x_scale) - i;
 
1241
                    else
 
1242
                      x_weights[i] = 0;
 
1243
                  }
 
1244
              }
 
1245
          }
 
1246
 
 
1247
        if (y_scale > 1.0)      /* Bilinear */
 
1248
          {
 
1249
            for (i = 0; i < n_y; i++)
 
1250
              {
 
1251
                y_weights[i] = ((i == 0) ? (1 - y) : y) / y_scale;
 
1252
              }
 
1253
          }
 
1254
        else                    /* Tile */
 
1255
          {
 
1256
            /*           y
 
1257
             * ---------|--.-|----|--.-|-------  SRC
 
1258
             * ------------|---------|---------  DEST
 
1259
             */
 
1260
            for (i = 0; i < n_y; i++)
 
1261
              {
 
1262
                if (i < y)
 
1263
                  {
 
1264
                    if (i + 1 > y)
 
1265
                      y_weights[i] = MIN(i+1, y + 1/y_scale) - y;
 
1266
                    else
 
1267
                      y_weights[i] = 0;
 
1268
                  }
 
1269
                else
 
1270
                  {
 
1271
                    if (y + 1/y_scale > i)
 
1272
                      y_weights[i] = MIN(i+1, y + 1/y_scale) - i;
 
1273
                    else
 
1274
                      y_weights[i] = 0;
 
1275
                  }
 
1276
              }
 
1277
          }
 
1278
 
 
1279
        for (i = 0; i < n_y; i++)
 
1280
          for (j = 0; j < n_x; j++)
 
1281
            {
 
1282
              int weight = 65536 * x_weights[j] * x_scale * y_weights[i] * y_scale * overall_alpha + 0.5;
 
1283
              *(pixel_weights + n_x * i + j) = weight;
 
1284
              total += weight;
 
1285
            }
 
1286
 
 
1287
        correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
 
1288
      }
 
1289
 
 
1290
  g_free (x_weights);
 
1291
  g_free (y_weights);
 
1292
}
 
1293
 
 
1294
static double
 
1295
bilinear_quadrant (double bx0, double bx1, double by0, double by1)
 
1296
{
 
1297
  double ax0, ax1, ay0, ay1;
 
1298
  double x0, x1, y0, y1;
 
1299
 
 
1300
  ax0 = 0.;
 
1301
  ax1 = 1.;
 
1302
  ay0 = 0.;
 
1303
  ay1 = 1.;
 
1304
 
 
1305
  if (ax0 < bx0)
 
1306
    {
 
1307
      if (ax1 > bx0)
 
1308
        {
 
1309
          x0 = bx0;
 
1310
          x1 = MIN (ax1, bx1);
 
1311
        }
 
1312
      else
 
1313
        return 0;
 
1314
    }
 
1315
  else
 
1316
    {
 
1317
      if (bx1 > ax0)
 
1318
        {
 
1319
          x0 = ax0;
 
1320
          x1 = MIN (ax1, bx1);
 
1321
        }
 
1322
      else
 
1323
        return 0;
 
1324
    }
 
1325
 
 
1326
  if (ay0 < by0)
 
1327
    {
 
1328
      if (ay1 > by0)
 
1329
        {
 
1330
          y0 = by0;
 
1331
          y1 = MIN (ay1, by1);
 
1332
        }
 
1333
      else
 
1334
        return 0;
 
1335
    }
 
1336
  else
 
1337
    {
 
1338
      if (by1 > ay0)
 
1339
        {
 
1340
          y0 = ay0;
 
1341
          y1 = MIN (ay1, by1);
 
1342
        }
 
1343
      else
 
1344
        return 0;
 
1345
    }
 
1346
 
 
1347
  return 0.25 * (x1*x1 - x0*x0) * (y1*y1 - y0*y0);
 
1348
}
 
1349
 
 
1350
static void
 
1351
bilinear_make_weights (PixopsFilter *filter, double x_scale, double y_scale, double overall_alpha)
 
1352
{
 
1353
  int i_offset, j_offset;
 
1354
 
 
1355
  int n_x = ceil(1/x_scale + 2.0);
 
1356
  int n_y = ceil(1/y_scale + 2.0);
 
1357
 
 
1358
  filter->x_offset = -1.0;
 
1359
  filter->y_offset = -1.0;
 
1360
  filter->n_x = n_x;
 
1361
  filter->n_y = n_y;
 
1362
  
 
1363
  filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y);
 
1364
 
 
1365
  for (i_offset=0; i_offset<SUBSAMPLE; i_offset++)
 
1366
    for (j_offset=0; j_offset<SUBSAMPLE; j_offset++)
 
1367
      {
 
1368
        int *pixel_weights = filter->weights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y;
 
1369
        double x = (double)j_offset / SUBSAMPLE;
 
1370
        double y = (double)i_offset / SUBSAMPLE;
 
1371
        int i,j;
 
1372
        int total = 0;
 
1373
 
 
1374
        for (i = 0; i < n_y; i++)
 
1375
          for (j = 0; j < n_x; j++)
 
1376
            {
 
1377
              double w;
 
1378
              int weight;
 
1379
              
 
1380
              w = bilinear_quadrant  (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
 
1381
              w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 0.5 + i - (y + 1 / y_scale), 0.5 + i - y);
 
1382
              w += bilinear_quadrant (0.5 + j - (x + 1 / x_scale), 0.5 + j - x, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
 
1383
              w += bilinear_quadrant (1.5 + x - j, 1.5 + (x + 1 / x_scale) - j, 1.5 + y - i, 1.5 + (y + 1 / y_scale) - i);
 
1384
              weight = 65536 * w * x_scale * y_scale * overall_alpha + 0.5;
 
1385
              *(pixel_weights + n_x * i + j) = weight;
 
1386
              total += weight;
 
1387
            }
 
1388
        
 
1389
        correct_total (pixel_weights, n_x, n_y, total, overall_alpha);
 
1390
      }
 
1391
}
 
1392
 
 
1393
void
 
1394
pixops_composite_color (guchar         *dest_buf,
 
1395
                        int             render_x0,
 
1396
                        int             render_y0,
 
1397
                        int             render_x1,
 
1398
                        int             render_y1,
 
1399
                        int             dest_rowstride,
 
1400
                        int             dest_channels,
 
1401
                        gboolean        dest_has_alpha,
 
1402
                        const guchar   *src_buf,
 
1403
                        int             src_width,
 
1404
                        int             src_height,
 
1405
                        int             src_rowstride,
 
1406
                        int             src_channels,
 
1407
                        gboolean        src_has_alpha,
 
1408
                        double          scale_x,
 
1409
                        double          scale_y,
 
1410
                        PixopsInterpType   interp_type,
 
1411
                        int             overall_alpha,
 
1412
                        int             check_x,
 
1413
                        int             check_y,
 
1414
                        int             check_size,
 
1415
                        guint32         color1,
 
1416
                        guint32         color2)
 
1417
{
 
1418
  PixopsFilter filter;
 
1419
  PixopsLineFunc line_func;
 
1420
  
 
1421
#ifdef USE_MMX
 
1422
  gboolean found_mmx = pixops_have_mmx();
 
1423
#endif
 
1424
 
 
1425
  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
 
1426
  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
 
1427
 
 
1428
  if (scale_x == 0 || scale_y == 0)
 
1429
    return;
 
1430
 
 
1431
  if (!src_has_alpha && overall_alpha == 255)
 
1432
    {
 
1433
    pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1434
                  dest_rowstride, dest_channels, dest_has_alpha,
 
1435
                  src_buf, src_width, src_height, src_rowstride, src_channels,
 
1436
                  src_has_alpha, scale_x, scale_y, interp_type);
 
1437
      return;
 
1438
    }
 
1439
 
 
1440
  switch (interp_type)
 
1441
    {
 
1442
    case PIXOPS_INTERP_NEAREST:
 
1443
      pixops_composite_color_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1444
                                      dest_rowstride, dest_channels, dest_has_alpha,
 
1445
                                      src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
 
1446
                                      scale_x, scale_y, overall_alpha,
 
1447
                                      check_x, check_y, check_size, color1, color2);
 
1448
      return;
 
1449
 
 
1450
    case PIXOPS_INTERP_TILES:
 
1451
      tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1452
      break;
 
1453
      
 
1454
    case PIXOPS_INTERP_BILINEAR:
 
1455
      bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1456
      break;
 
1457
      
 
1458
    case PIXOPS_INTERP_HYPER:
 
1459
      bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1460
      break;
 
1461
    }
 
1462
 
 
1463
#ifdef USE_MMX
 
1464
  if (filter.n_x == 2 && filter.n_y == 2 &&
 
1465
      dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha && found_mmx)
 
1466
    line_func = composite_line_color_22_4a4_mmx_stub;
 
1467
  else
 
1468
#endif
 
1469
    line_func = composite_line_color;
 
1470
  
 
1471
  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1472
                  dest_rowstride, dest_channels, dest_has_alpha,
 
1473
                  src_buf, src_width, src_height, src_rowstride, src_channels,
 
1474
                  src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
 
1475
                  &filter, line_func, composite_pixel_color);
 
1476
 
 
1477
  g_free (filter.weights);
 
1478
}
 
1479
 
 
1480
/**
 
1481
 * pixops_composite:
 
1482
 * @dest_buf: pointer to location to store result
 
1483
 * @render_x0: x0 of region of scaled source to store into @dest_buf
 
1484
 * @render_y0: y0 of region of scaled source to store into @dest_buf
 
1485
 * @render_x1: x1 of region of scaled source to store into @dest_buf
 
1486
 * @render_y1: y1 of region of scaled source to store into @dest_buf
 
1487
 * @dest_rowstride: rowstride of @dest_buf
 
1488
 * @dest_channels: number of channels in @dest_buf
 
1489
 * @dest_has_alpha: whether @dest_buf has alpha
 
1490
 * @src_buf: pointer to source pixels
 
1491
 * @src_width: width of source (used for clipping)
 
1492
 * @src_height: height of source (used for clipping)
 
1493
 * @src_rowstride: rowstride of source
 
1494
 * @src_channels: number of channels in @src_buf
 
1495
 * @src_has_alpha: whether @src_buf has alpha
 
1496
 * @scale_x: amount to scale source by in X direction
 
1497
 * @scale_y: amount to scale source by in Y direction
 
1498
 * @interp_type: type of enumeration
 
1499
 * @overall_alpha: overall alpha factor to multiply source by
 
1500
 * 
 
1501
 * Scale source buffer by scale_x / scale_y, then composite a given rectangle
 
1502
 * of the result into the destination buffer.
 
1503
 **/
 
1504
void
 
1505
pixops_composite (guchar        *dest_buf,
 
1506
                  int            render_x0,
 
1507
                  int            render_y0,
 
1508
                  int            render_x1,
 
1509
                  int            render_y1,
 
1510
                  int            dest_rowstride,
 
1511
                  int            dest_channels,
 
1512
                  gboolean       dest_has_alpha,
 
1513
                  const guchar  *src_buf,
 
1514
                  int            src_width,
 
1515
                  int            src_height,
 
1516
                  int            src_rowstride,
 
1517
                  int            src_channels,
 
1518
                  gboolean       src_has_alpha,
 
1519
                  double         scale_x,
 
1520
                  double         scale_y,
 
1521
                  PixopsInterpType  interp_type,
 
1522
                  int            overall_alpha)
 
1523
{
 
1524
  PixopsFilter filter;
 
1525
  PixopsLineFunc line_func;
 
1526
  
 
1527
#ifdef USE_MMX
 
1528
  gboolean found_mmx = pixops_have_mmx();
 
1529
#endif
 
1530
 
 
1531
  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
 
1532
  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
 
1533
 
 
1534
  if (scale_x == 0 || scale_y == 0)
 
1535
    return;
 
1536
 
 
1537
  if (!src_has_alpha && overall_alpha == 255)
 
1538
    {
 
1539
    pixops_scale (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1540
                  dest_rowstride, dest_channels, dest_has_alpha,
 
1541
                  src_buf, src_width, src_height, src_rowstride, src_channels,
 
1542
                  src_has_alpha, scale_x, scale_y, interp_type);
 
1543
      return;
 
1544
    }
 
1545
 
 
1546
  switch (interp_type)
 
1547
    {
 
1548
    case PIXOPS_INTERP_NEAREST:
 
1549
      pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1550
                                dest_rowstride, dest_channels, dest_has_alpha,
 
1551
                                src_buf, src_width, src_height, src_rowstride, src_channels,
 
1552
                                src_has_alpha, scale_x, scale_y, overall_alpha);
 
1553
      return;
 
1554
 
 
1555
    case PIXOPS_INTERP_TILES:
 
1556
      tile_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1557
      break;
 
1558
      
 
1559
    case PIXOPS_INTERP_BILINEAR:
 
1560
      bilinear_make_fast_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1561
      break;
 
1562
      
 
1563
    case PIXOPS_INTERP_HYPER:
 
1564
      bilinear_make_weights (&filter, scale_x, scale_y, overall_alpha / 255.);
 
1565
      break;
 
1566
    }
 
1567
 
 
1568
  if (filter.n_x == 2 && filter.n_y == 2 &&
 
1569
      dest_channels == 4 && src_channels == 4 && src_has_alpha && !dest_has_alpha)
 
1570
    {
 
1571
#ifdef USE_MMX
 
1572
      if (found_mmx)
 
1573
        line_func = composite_line_22_4a4_mmx_stub;
 
1574
      else
 
1575
#endif  
 
1576
        line_func = composite_line_22_4a4;
 
1577
    }
 
1578
  else
 
1579
    line_func = composite_line;
 
1580
  
 
1581
  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1582
                  dest_rowstride, dest_channels, dest_has_alpha,
 
1583
                  src_buf, src_width, src_height, src_rowstride, src_channels,
 
1584
                  src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0, 
 
1585
                  &filter, line_func, composite_pixel);
 
1586
 
 
1587
  g_free (filter.weights);
 
1588
}
 
1589
 
 
1590
void
 
1591
pixops_scale (guchar        *dest_buf,
 
1592
              int            render_x0,
 
1593
              int            render_y0,
 
1594
              int            render_x1,
 
1595
              int            render_y1,
 
1596
              int            dest_rowstride,
 
1597
              int            dest_channels,
 
1598
              gboolean       dest_has_alpha,
 
1599
              const guchar  *src_buf,
 
1600
              int            src_width,
 
1601
              int            src_height,
 
1602
              int            src_rowstride,
 
1603
              int            src_channels,
 
1604
              gboolean       src_has_alpha,
 
1605
              double         scale_x,
 
1606
              double         scale_y,
 
1607
              PixopsInterpType  interp_type)
 
1608
{
 
1609
  PixopsFilter filter;
 
1610
  PixopsLineFunc line_func;
 
1611
 
 
1612
#ifdef USE_MMX
 
1613
  gboolean found_mmx = pixops_have_mmx();
 
1614
#endif
 
1615
 
 
1616
  g_return_if_fail (!(dest_channels == 3 && dest_has_alpha));
 
1617
  g_return_if_fail (!(src_channels == 3 && src_has_alpha));
 
1618
  g_return_if_fail (!(src_has_alpha && !dest_has_alpha));
 
1619
 
 
1620
  if (scale_x == 0 || scale_y == 0)
 
1621
    return;
 
1622
 
 
1623
  switch (interp_type)
 
1624
    {
 
1625
    case PIXOPS_INTERP_NEAREST:
 
1626
      pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1627
                            dest_rowstride, dest_channels, dest_has_alpha,
 
1628
                            src_buf, src_width, src_height, src_rowstride, src_channels, src_has_alpha,
 
1629
                            scale_x, scale_y);
 
1630
      return;
 
1631
 
 
1632
    case PIXOPS_INTERP_TILES:
 
1633
      tile_make_weights (&filter, scale_x, scale_y, 1.0);
 
1634
      break;
 
1635
      
 
1636
    case PIXOPS_INTERP_BILINEAR:
 
1637
      bilinear_make_fast_weights (&filter, scale_x, scale_y, 1.0);
 
1638
      break;
 
1639
      
 
1640
    case PIXOPS_INTERP_HYPER:
 
1641
      bilinear_make_weights (&filter, scale_x, scale_y, 1.0);
 
1642
      break;
 
1643
    }
 
1644
 
 
1645
  if (filter.n_x == 2 && filter.n_y == 2 && dest_channels == 3 && src_channels == 3)
 
1646
    {
 
1647
#ifdef USE_MMX
 
1648
      if (found_mmx)
 
1649
        line_func = scale_line_22_33_mmx_stub;
 
1650
      else
 
1651
#endif
 
1652
        line_func = scale_line_22_33;
 
1653
    }
 
1654
  else
 
1655
    line_func = scale_line;
 
1656
  
 
1657
  pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
 
1658
                  dest_rowstride, dest_channels, dest_has_alpha,
 
1659
                  src_buf, src_width, src_height, src_rowstride, src_channels,
 
1660
                  src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
 
1661
                  &filter, line_func, scale_pixel);
 
1662
 
 
1663
  g_free (filter.weights);
 
1664
}
 
1665