Ticket #8368: edge3x.cpp

File edge3x.cpp, 22.0 KB (added by SF/ewelsh42, 18 years ago)
Line 
1/* ScummVM - Scumm Interpreter
2 * Copyright (C) 2001 Ludvig Strigeus
3 * Copyright (C) 2001-2004 The ScummVM project
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * $Header: /cvsroot/scummvm/scummvm/common/scaler/hq3x.h,v 1.2 2004/01/06 12:45:28 fingolfin Exp $
20 *
21 */
22
23/* Another edge-directed 3x anti-aliasing scaler for ScummVM
24 *
25 * Author: Eric A. Welsh
26 *
27 * Features:
28 *
29 * More anti-aliasing than advmame3x, but at the cost of some blurriness
30 * Low contrast areas are sharper than hq3x (which is very blurry)
31 * High contrast areas aren't as nice as hq3x (which is VERY nice)
32 * Overall, it strikes a good balance between sharpness and blurriness
33 * It could probably use some further speed optimization
34 * It's a bit slow... but ScummVM runs everything fine on my 1.53 Gz Athlon
35 */
36
37#include "common/stdafx.h"
38#include "common/scummsys.h"
39#include "common/system.h"
40
41#define SIN45 0.7071067811865 /* sin of 45 degrees */
42#define LUMA_SHIFT 13
43
44int32 luma_table[65536] = {0};
45int edge3x_init_flag = 0;
46const uint16 *src_addr_min; /* start of src screen array */
47const uint16 *src_addr_max; /* end of src screen array */
48uint16 div3[189]; /* tables for pixel interpolation */
49uint16 div9[567];
50
51/* faster than FPU atan(), nearly as accurate as single precision */
52double fast_atan(double v0)
53{
54 double v2;
55 double v;
56
57 v = fabs(v0);
58 v2 = v*v;
59 if (v > 1)
60 {
61 v2 = 1.570796326795 -
62 v * (0.446350590597 + v2) /
63 ((0.0900271979249 + v2) * (0.689454091687 + v2));
64 if (v0 < 0) return -v2;
65 return v2;
66 }
67 v2 = v * (16.11094124024 + 7.191128136096 * v2) /
68 ((1.450422895714 + v2) * (11.10775435761 + v2));
69
70 if (v0 < 0) return -v2;
71 return v2;
72}
73
74/* More complicated and slower than most algorithms, but it fails far less
75 * often (ie. assigning diagonal when it should be horizontal, or 90 degrees
76 * from what it should be). Slow, but necessary to avoid artifacts.
77 *
78 * Edge detection takes up a whopping 53% of the CPU time spent in ScummVM.
79 * Perhaps this could be optimized a bit more ... ?
80 */
81char convolve_edges_compass_luma(uint16 *pixels, int x_orig, int y_orig,
82 int w)
83{
84 int32 *bptr;
85 uint16 *pptr;
86 int32 bplane[9];
87 int32 sums_dir1, sums_dir2, sums_dir3, sums_dir4; /* NE E SE S */
88 int32 max_sums;
89 int32 mag, mag1, mag2;
90 double angle;
91 double new_angle = 999;
92 int n;
93
94 /* fill the 9 pixel window with luma values */
95 bptr = bplane;
96 pptr = pixels;
97 for (n = 0; n < 9; n++)
98 *bptr++ = luma_table[*pptr++];
99 bptr = bplane;
100
101 /* bi-directional edge detection */
102 /* mis-detections are easier to correct than the vector-based method */
103 mag = (bptr[2] + bptr[4] + bptr[6]) << 1;
104 mag1 = labs((3 * (bptr[1] + bptr[3]) - mag) >> 1);
105 mag2 = labs((3 * (bptr[5] + bptr[7]) - mag) >> 1);
106 mag = mag1;
107 if (mag2 > mag) mag = mag2;
108 sums_dir1 = mag;
109
110 mag = bptr[3] + bptr[4] + bptr[5];
111 mag1 = labs(bptr[0] + bptr[1] + bptr[2] - mag);
112 mag2 = labs(bptr[6] + bptr[7] + bptr[8] - mag);
113 mag = mag1;
114 if (mag2 > mag) mag = mag2;
115 sums_dir2 = mag;
116
117 mag = (bptr[0] + bptr[4] + bptr[8]) << 1;
118 mag1 = labs((3 * (bptr[1] + bptr[5]) - mag) >> 1);
119 mag2 = labs((3 * (bptr[3] + bptr[7]) - mag) >> 1);
120 mag = mag1;
121 if (mag2 > mag) mag = mag2;
122 sums_dir3 = mag;
123
124 mag = bptr[1] + bptr[4] + bptr[7];
125 mag1 = labs(bptr[0] + bptr[3] + bptr[6] - mag);
126 mag2 = labs(bptr[2] + bptr[5] + bptr[8] - mag);
127 mag = mag1;
128 if (mag2 > mag) mag = mag2;
129 sums_dir4 = mag;
130
131 /* find the strongest edge */
132 max_sums = sums_dir1;
133 if (sums_dir2 > max_sums) max_sums = sums_dir2;
134 if (sums_dir3 > max_sums) max_sums = sums_dir3;
135 if (sums_dir4 > max_sums) max_sums = sums_dir4;
136
137 n = 0;
138 if (max_sums == sums_dir1)
139 {
140 new_angle = 135;
141 n++;
142 }
143 if (max_sums == sums_dir2)
144 {
145 new_angle = 0;
146 n++;
147 }
148 if (max_sums == sums_dir3)
149 {
150 new_angle = 45;
151 n++;
152 }
153 if (max_sums == sums_dir4)
154 {
155 new_angle = 90;
156 n++;
157 }
158
159 if (max_sums == 0) /* grid of solid color */
160 return 0;
161 if (max_sums && n == 1) /* we found a strong edge */
162 {
163 angle = new_angle;
164 }
165 else if (n == 4) /* x, +, . type patterns */
166 {
167 return '*';
168 }
169 else /* difficult edge, try vector method */
170 {
171 double x, y;
172
173 sums_dir1 = (3 * (bptr[1] - bptr[3] + bptr[5] - bptr[7])) >> 1;
174
175 sums_dir2 = bptr[0] + bptr[1] + bptr[2] -
176 bptr[6] - bptr[7] - bptr[8];
177
178 sums_dir3 = (3 * (bptr[1] + bptr[3] - bptr[5] - bptr[7])) >> 1;
179
180 sums_dir4 = bptr[0] - bptr[2] + bptr[3] -
181 bptr[5] + bptr[6] - bptr[8];
182
183 /* add the vectors in x,y space, North points up */ /* NE E SE S */
184 x = sums_dir1 * SIN45;
185 x += sums_dir2;
186 x += sums_dir3 * SIN45;
187 y = sums_dir1 * SIN45;
188 y -= sums_dir3 * SIN45;
189 y -= sums_dir4;
190
191 if (x)
192 {
193 angle = 57.29577951307 * fast_atan(y / x);
194 if (x < 0) angle += 180;
195 }
196 else
197 {
198 if (y > 0) angle = 90;
199 else if (y < 0) angle = -90;
200 else return '*';
201 }
202 }
203
204 /* fix detection errors that are off by 90 degrees */
205 {
206 int32 dist1, dist2;
207 int32 dist_good, dist_bad;
208
209 if (angle < 0) angle += 360;
210
211 /* horizontal */
212 if ((angle > (180 - 22.5) && angle < (180 + 22.5)) ||
213 angle < 22.5 || angle > (360 - 22.5))
214 {
215 dist1 = bptr[4] - bptr[3];
216 dist2 = bptr[4] - bptr[5];
217 dist_good = dist1*dist1 + dist2*dist2;
218
219 dist1 = bptr[4] - bptr[1];
220 dist2 = bptr[4] - bptr[7];
221 dist_bad = dist1*dist1 + dist2*dist2;
222
223 if (dist_good <= dist_bad)
224 return '-';
225
226 return '|';
227 }
228
229 /* vertical */
230 if ((angle > (90 - 22.5) && angle < (90 + 22.5)) ||
231 (angle > (90 - 22.5 + 180) && angle < (90 + 22.5 + 180)))
232 {
233 dist1 = bptr[4] - bptr[1];
234 dist2 = bptr[4] - bptr[7];
235 dist_good = dist1*dist1 + dist2*dist2;
236
237 dist1 = bptr[4] - bptr[3];
238 dist2 = bptr[4] - bptr[5];
239 dist_bad = dist1*dist1 + dist2*dist2;
240
241 if (dist_good <= dist_bad)
242 return '|';
243
244 return '-';
245 }
246
247 /* 45 */
248 if ((angle > (45 - 22.5) && angle < (45 + 22.5)) ||
249 (angle > (45 - 22.5 + 180) && angle < (45 + 22.5 + 180)))
250 {
251 dist1 = bptr[4] - bptr[0];
252 dist2 = bptr[4] - bptr[8];
253 dist_good = dist1*dist1 + dist2*dist2;
254
255 /* side diags */
256 dist1 = bptr[1] - bptr[5];
257 dist2 = bptr[3] - bptr[7];
258 dist_good += dist1*dist1 + dist2*dist2;
259
260 dist1 = bptr[4] - bptr[2];
261 dist2 = bptr[4] - bptr[6];
262 dist_bad = dist1*dist1 + dist2*dist2;
263
264 /* side diags */
265 dist1 = bptr[1] - bptr[3];
266 dist2 = bptr[5] - bptr[7];
267 dist_bad += dist1*dist1 + dist2*dist2;
268
269 if (dist_good <= dist_bad)
270 return '\\';
271
272 return '/';
273 }
274
275 /* 135 */
276 if ((angle > (135 - 22.5) && angle < (135 + 22.5)) ||
277 (angle > (135 - 22.5 + 180) && angle < (135 + 22.5 + 180)))
278 {
279 dist1 = bptr[4] - bptr[2];
280 dist2 = bptr[4] - bptr[6];
281 dist_good = dist1*dist1 + dist2*dist2;
282
283 /* side diags */
284 dist1 = bptr[1] - bptr[3];
285 dist2 = bptr[5] - bptr[7];
286 dist_good += dist1*dist1 + dist2*dist2;
287
288 dist1 = bptr[4] - bptr[0];
289 dist2 = bptr[4] - bptr[8];
290 dist_bad = dist1*dist1 + dist2*dist2;
291
292 /* side diags */
293 dist1 = bptr[1] - bptr[5];
294 dist2 = bptr[3] - bptr[7];
295 dist_bad += dist1*dist1 + dist2*dist2;
296
297 if (dist_good <= dist_bad)
298 return '/';
299
300 return '\\';
301 }
302 }
303
304 return '*';
305}
306
307/* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */
308#define highBits 0xF7DEF7DE
309#define lowBits 0x08210821
310#define qhighBits 0xE79CE79C
311#define qlowBits 0x18631863
312#define redblueMask 0xF81F
313#define greenMask 0x07E0
314
315/* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */
316/**
317 * Interpolate two 16 bit pixel pairs at once with equal weights 1.
318 * In particular, A and B can contain two pixels/each in the upper
319 * and lower halves.
320 */
321uint32 INTERPOLATE(uint32 A, uint32 B)
322{
323 return (((A & highBits) >> 1) + ((B & highBits) >> 1) + (A & B & lowBits));
324}
325
326/* From ScummVM hq2x/hq3x scalers (Maxim Stepin and Max Horn) */
327/**
328 * Interpolate four 16 bit pixel pairs at once with equal weights 1.
329 * In particular, A and B can contain two pixels/each in the upper
330 * and lower halves.
331 */
332uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
333{
334 uint32 x = ((A & qhighBits) >> 2) + ((B & qhighBits) >> 2) + ((C & qhighBits) >> 2) + ((D & qhighBits) >> 2);
335 uint32 y = ((A & qlowBits) + (B & qlowBits) + (C & qlowBits) + (D & qlowBits)) >> 2;
336
337 y &= qlowBits;
338 return x + y;
339}
340
341uint16 average_three_pixels(uint16 pixel1, uint16 pixel2, uint16 pixel3)
342{
343 uint32 rsum, gsum, bsum;
344
345 rsum = (pixel1 & 0xF800);
346 rsum += (pixel2 & 0xF800);
347 rsum += (pixel3 & 0xF800);
348 rsum = div3[rsum >> 11];
349
350 gsum = (pixel1 & 0x07E0);
351 gsum += (pixel2 & 0x07E0);
352 gsum += (pixel3 & 0x07E0);
353 gsum = div3[gsum >> 5];
354
355 bsum = (pixel1 & 0x001F);
356 bsum += (pixel2 & 0x001F);
357 bsum += (pixel3 & 0x001F);
358 bsum = div3[bsum];
359
360 return ((rsum << 11) | (gsum << 5) | bsum);
361}
362
363uint16 average_one_third(uint16 pixel1, uint16 pixel2)
364{
365 uint32 rsum, gsum, bsum;
366
367 rsum = (pixel1 & 0xF800) << 1;
368 rsum += (pixel2 & 0xF800);
369 rsum = div3[rsum >> 11];
370
371 gsum = (pixel1 & 0x07E0) << 1;
372 gsum += (pixel2 & 0x07E0);
373 gsum = div3[gsum >> 5];
374
375 bsum = (pixel1 & 0x001F) << 1;
376 bsum += (pixel2 & 0x001F);
377 bsum = div3[bsum];
378
379 return ((rsum << 11) | (gsum << 5) | bsum);
380}
381
382/* interpolate a diagnoal pixel for linear interpolation on a 3x3 grid */
383uint16 average_four_pixels_radial(uint16 pixel1, uint16 pixel2,
384 uint16 pixel3, uint16 pixel4)
385{
386 uint32 rsum, gsum, bsum;
387
388 rsum = (pixel1 & 0xF800) << 2;
389 rsum += (pixel2 & 0xF800) << 1;
390 rsum += (pixel3 & 0xF800) << 1;
391 rsum += (pixel4 & 0xF800);
392 rsum = div9[rsum >> 11];
393
394 gsum = (pixel1 & 0x07E0) << 2;
395 gsum += (pixel2 & 0x07E0) << 1;
396 gsum += (pixel3 & 0x07E0) << 1;
397 gsum += (pixel4 & 0x07E0);
398 gsum = div9[gsum >> 5];
399
400 bsum = (pixel1 & 0x001F) << 2;
401 bsum += (pixel2 & 0x001F) << 1;
402 bsum += (pixel3 & 0x001F) << 1;
403 bsum += (pixel4 & 0x001F);
404 bsum = div9[bsum];
405
406 return ((rsum << 11) | (gsum << 5) | bsum);
407}
408
409/* perform different interpolations depending on the detected edge */
410void anti_alias_grid(uint8 *dptr, int dstPitch,
411 uint16 *pixels, char edge_type)
412{
413 uint16 *dptr2;
414 uint16 tmp_pixel;
415 uint16 center = pixels[4];
416 static uint16 tmp[9];
417 uint16 *ptmp;
418
419 switch (edge_type)
420 {
421 case 0:
422 dptr2 = ((uint16 *) (dptr - dstPitch)) - 1;
423 *dptr2++ = center;
424 *dptr2++ = center;
425 *dptr2 = center;
426 dptr2 = ((uint16 *) dptr) - 1;
427 *dptr2++ = center;
428 *dptr2++ = center;
429 *dptr2 = center;
430 dptr2 = ((uint16 *) (dptr + dstPitch)) - 1;
431 *dptr2++ = center;
432 *dptr2++ = center;
433 *dptr2 = center;
434
435 return;
436
437 break;
438
439 case '-':
440 tmp[0] = tmp[3] = tmp[6] = average_one_third(center, pixels[3]);
441 tmp[1] = tmp[4] = tmp[7] = center;
442 tmp[2] = tmp[5] = tmp[8] = average_one_third(center, pixels[5]);
443
444 if (center == pixels[0]) tmp[0] = center;
445 if (center == pixels[2]) tmp[2] = center;
446 if (center == pixels[6]) tmp[6] = center;
447 if (center == pixels[8]) tmp[8] = center;
448
449 if (center == pixels[0] || center == pixels[6])
450 tmp[3] = INTERPOLATE(tmp[0], tmp[6]);
451 if (center == pixels[2] || center == pixels[8])
452 tmp[5] = INTERPOLATE(tmp[2], tmp[8]);
453
454 break;
455
456 case '|':
457 tmp[0] = tmp[1] = tmp[2] = average_one_third(center, pixels[1]);
458 tmp[3] = tmp[4] = tmp[5] = center;
459 tmp[6] = tmp[7] = tmp[8] = average_one_third(center, pixels[7]);
460
461 if (center == pixels[0]) tmp[0] = center;
462 if (center == pixels[2]) tmp[2] = center;
463 if (center == pixels[6]) tmp[6] = center;
464 if (center == pixels[8]) tmp[8] = center;
465
466 if (center == pixels[0] || center == pixels[2])
467 tmp[1] = INTERPOLATE(tmp[0], tmp[2]);
468 if (center == pixels[6] || center == pixels[8])
469 tmp[7] = INTERPOLATE(tmp[6], tmp[8]);
470
471 break;
472
473 case '/':
474 if (pixels[1] == center && center == pixels[6])
475 tmp[0] = Q_INTERPOLATE(pixels[1], pixels[3],
476 center, pixels[6]);
477 else if (pixels[2] == pixels[3] && pixels[3] == center)
478 tmp[0] = Q_INTERPOLATE(pixels[1], pixels[2],
479 pixels[3], center);
480 else
481 tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
482
483 tmp[2] = average_one_third(center, pixels[2]);
484
485 if (pixels[1] == center)
486 tmp[1] = center;
487 else
488 {
489 tmp_pixel = average_one_third(pixels[1], center);
490 tmp[1] = Q_INTERPOLATE(tmp_pixel, center,
491 tmp[0],
492 tmp[2]);
493 }
494
495 tmp[6] = average_one_third(center, pixels[6]);
496 if (pixels[2] == center && center == pixels[7])
497 tmp[8] = Q_INTERPOLATE(pixels[2], center,
498 pixels[5], pixels[7]);
499 else if (center == pixels[5] && pixels[5] == pixels[6])
500 tmp[8] = Q_INTERPOLATE(center, pixels[5],
501 pixels[6], pixels[7]);
502 else
503 tmp[8] = average_three_pixels(center, pixels[5], pixels[7]);
504
505 if (pixels[7] == center)
506 tmp[7] = center;
507 else
508 {
509 tmp_pixel = average_one_third(pixels[7], center);
510 tmp[7] = Q_INTERPOLATE(tmp_pixel, center,
511 tmp[6],
512 tmp[8]);
513 }
514
515 if (pixels[3] == center)
516 tmp[3] = center;
517 else
518 {
519 tmp_pixel = average_one_third(pixels[3], center);
520 tmp[3] = Q_INTERPOLATE(tmp_pixel, center,
521 tmp[0],
522 tmp[6]);
523 }
524
525 tmp[4] = center;
526
527 if (pixels[5] == center)
528 tmp[5] = center;
529 else
530 {
531 tmp_pixel = average_one_third(pixels[5], center);
532 tmp[5] = Q_INTERPOLATE(tmp_pixel, center,
533 tmp[2],
534 tmp[8]);
535 }
536
537 break;
538
539 case '\\':
540 tmp[0] = average_one_third(center, pixels[0]);
541
542 if (pixels[1] == center && center == pixels[8])
543 tmp[2] = Q_INTERPOLATE(pixels[1], center,
544 pixels[5], pixels[8]);
545 else if (pixels[0] == center && center == pixels[5])
546 tmp[2] = Q_INTERPOLATE(pixels[0], pixels[1],
547 center, pixels[5]);
548 else
549 tmp[2] = average_three_pixels(pixels[1], center, pixels[5]);
550
551 if (pixels[1] == center)
552 tmp[1] = center;
553 else
554 {
555 tmp_pixel = average_one_third(pixels[1], center);
556 tmp[1] = Q_INTERPOLATE(tmp_pixel, center,
557 tmp[0],
558 tmp[2]);
559 }
560
561 if (pixels[0] == center && center == pixels[7])
562 tmp[6] = Q_INTERPOLATE(pixels[0], pixels[3],
563 center, pixels[7]);
564 else if (pixels[3] == center && center == pixels[8])
565 tmp[6] = Q_INTERPOLATE(pixels[3], center,
566 pixels[7], pixels[8]);
567 else
568 tmp[6] = average_three_pixels(pixels[3], center, pixels[7]);
569
570 tmp[8] = average_one_third(center, pixels[8]);
571
572 if (pixels[7] == center)
573 tmp[7] = center;
574 else
575 {
576 tmp_pixel = average_one_third(pixels[7], center);
577 tmp[7] = Q_INTERPOLATE(tmp_pixel, center,
578 tmp[6],
579 tmp[8]);
580 }
581
582 if (pixels[3] == center)
583 tmp[3] = center;
584 else
585 {
586 tmp_pixel = average_one_third(pixels[3], center);
587 tmp[3] = Q_INTERPOLATE(tmp_pixel, center,
588 tmp[0],
589 tmp[6]);
590 }
591
592 tmp[4] = center;
593
594 if (pixels[5] == center)
595 tmp[5] = center;
596 else
597 {
598 tmp_pixel = average_one_third(pixels[5], center);
599 tmp[5] = Q_INTERPOLATE(tmp_pixel, center,
600 tmp[2],
601 tmp[8]);
602 }
603
604 break;
605
606 case '*':
607 tmp[0] = average_four_pixels_radial(center, pixels[1],
608 pixels[3], pixels[0]);
609 tmp[1] = average_one_third(center, pixels[1]);
610 tmp[2] = average_four_pixels_radial(center, pixels[1],
611 pixels[5], pixels[2]);
612 tmp[3] = average_one_third(center, pixels[3]);
613 tmp[4] = center;
614 tmp[5] = average_one_third(center, pixels[5]);
615 tmp[6] = average_four_pixels_radial(center, pixels[3],
616 pixels[7], pixels[6]);
617 tmp[7] = average_one_third(center, pixels[7]);
618 tmp[8] = average_four_pixels_radial(center, pixels[5],
619 pixels[7], pixels[8]);
620
621
622 if (center == pixels[1])
623 tmp[0] = tmp[2] = center;
624 if (center == pixels[3])
625 tmp[0] = tmp[6] = center;
626 if (center == pixels[5])
627 tmp[2] = tmp[8] = center;
628 if (center == pixels[7])
629 tmp[6] = tmp[8] = center;
630
631 if (center == pixels[0])
632 tmp[0] = center;
633 if (center == pixels[2])
634 tmp[2] = center;
635 if (center == pixels[6])
636 tmp[6] = center;
637 if (center == pixels[8])
638 tmp[8] = center;
639
640 break;
641
642 default:
643 return;
644
645 break;
646 }
647
648 ptmp = tmp;
649 dptr2 = ((uint16 *) (dptr - dstPitch)) - 1;
650 *dptr2++ = *ptmp++;
651 *dptr2++ = *ptmp++;
652 *dptr2 = *ptmp++;
653 dptr2 = ((uint16 *) dptr) - 1;
654 *dptr2++ = *ptmp++;
655 *dptr2++ = *ptmp++;
656 *dptr2 = *ptmp++;
657 dptr2 = ((uint16 *) (dptr + dstPitch)) - 1;
658 *dptr2++ = *ptmp++;
659 *dptr2++ = *ptmp++;
660 *dptr2 = *ptmp;
661}
662
663/* perform edge detection, then interpolate */
664void anti_alias_pass(const uint8 *src, uint8 *dst,
665 int w, int h, int w_new, int h_new,
666 int srcPitch, int dstPitch)
667{
668 int x, y;
669 const uint16 *sptr16;
670 uint16 *dptr16;
671
672 for (y = 0; y < h; y++)
673 {
674 sptr16 = ((const uint16 *) (src + y * srcPitch)) + 0;
675 dptr16 = ((uint16 *) (dst + y * dstPitch * 3 + dstPitch)) + 1 + 0;
676 for (x = 0; x < w; x++, sptr16++, dptr16 += 3)
677 {
678 const uint16 *sptr2, *addr3;
679 static uint16 pixels[9];
680 uint16 *pptr = pixels;
681 char edge_type;
682
683 sptr2 = ((const uint16 *) ((const uint8 *) sptr16 - srcPitch)) - 1;
684 addr3 = ((const uint16 *) ((const uint8 *) sptr16 + srcPitch)) + 1;
685
686 /* fill the 3x3 grid */
687 if (sptr2 >= src_addr_min && addr3 <= src_addr_max)
688 {
689 memcpy(pixels, sptr2, 3*sizeof(uint16));
690 memcpy(pixels+3, sptr16 - 1, 3*sizeof(uint16));
691 memcpy(pixels+6, addr3 - 2, 3*sizeof(uint16));
692 }
693 else /* if we go off the screen, set the pixel to 0 */
694 {
695 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
696 *pptr++ = *sptr2++;
697 else {
698 *pptr++ = 0;
699 sptr2++;
700 }
701 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
702 *pptr++ = *sptr2++;
703 else {
704 *pptr++ = 0;
705 sptr2++;
706 }
707 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
708 *pptr++ = *sptr2;
709 else
710 *pptr++ = 0;
711
712 sptr2 = sptr16 - 1;
713 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
714 *pptr++ = *sptr2++;
715 else {
716 *pptr++ = 0;
717 sptr2++;
718 }
719 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
720 *pptr++ = *sptr2++;
721 else {
722 *pptr++ = 0;
723 sptr2++;
724 }
725 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
726 *pptr++ = *sptr2;
727 else
728 *pptr++ = 0;
729
730 sptr2 = addr3 - 2;
731 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
732 *pptr++ = *sptr2++;
733 else {
734 *pptr++ = 0;
735 sptr2++;
736 }
737 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
738 *pptr++ = *sptr2++;
739 else {
740 *pptr++ = 0;
741 sptr2++;
742 }
743 if (sptr2 >= src_addr_min && sptr2 <= src_addr_max)
744 *pptr = *sptr2;
745 else
746 *pptr = 0;
747 }
748
749 edge_type = convolve_edges_compass_luma(pixels, x, y, w);
750 anti_alias_grid((uint8 *) dptr16, dstPitch, pixels, edge_type);
751 }
752 }
753}
754
755void initialize_tables(const uint8 *srcPtr, uint32 srcPitch,
756 uint8 *dstPtr, uint32 dstPitch,
757 int width, int height)
758{
759 double r_float, g_float, b_float, luma;
760 int r, g, b;
761
762 /* initialize luma table */
763 for (r = 0; r < 32; r++)
764 {
765 r_float = r / 31.0;
766
767 for (g = 0; g < 64; g++)
768 {
769 g_float = g / 63.0;
770
771 for (b = 0; b < 32; b++)
772 {
773 b_float = b / 31.0;
774
775 luma = 0.299*r_float + 0.587*g_float + 0.114*b_float;
776 luma_table[(r << 11) | (g << 5) | b] =
777 (int32)(luma * (1 << LUMA_SHIFT) + 0.5);
778 }
779 }
780 }
781
782 /* initialize interpolation division tables */
783 for (r = 0; r <= 189; r++)
784 div3[r] = ((r<<1)+1) / 6;
785 for (r = 0; r <= 567; r++)
786 div9[r] = ((r<<1)+1) / 18;
787
788 /* set initial best guess on min/max screen addresses */
789 src_addr_min = (const uint16 *) srcPtr;
790 src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
791 (width - 1);
792}
793
794void Edge3x(const uint8 *srcPtr, uint32 srcPitch,
795 uint8 *dstPtr, uint32 dstPitch, int width, int height)
796{
797 if (!edge3x_init_flag)
798 {
799 initialize_tables(srcPtr, srcPitch, dstPtr, dstPitch, width, height);
800 edge3x_init_flag = 1;
801 }
802
803 if (width == g_system->getWidth() &&
804 height == g_system->getHeight())
805 {
806 src_addr_min = (const uint16 *) srcPtr;
807 src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
808 (width - 1);
809 }
810
811 anti_alias_pass(srcPtr, dstPtr, width, height,
812 3*width, 3*height, srcPitch, dstPitch);
813}