Ticket #8578: edge3x.dif

File edge3x.dif, 141.4 KB (added by SF/ewelsh42, 18 years ago)

diff to add new Edge3x/2x anti-aliasing resizer filter

Line 
1diff -ruN -b backup_version/backends/platform/sdl/graphics.cpp new_version/backends/platform/sdl/graphics.cpp
2--- backup_version/backends/platform/sdl/graphics.cpp 2006-07-30 00:48:50.000000000 -0500
3+++ new_version/backends/platform/sdl/graphics.cpp 2006-07-31 22:21:00.000000000 -0500
4@@ -43,6 +43,9 @@
5 #endif
6 {"tv2x", "TV2x", GFX_TV2X},
7 {"dotmatrix", "DotMatrix", GFX_DOTMATRIX},
8+ {"edge2x", "Edge2x", GFX_EDGE2X},
9+ {"edge2xi", "Edge2x_Interp", GFX_EDGE2X_INTERP},
10+ {"edge3x", "Edge3x", GFX_EDGE3X},
11 {0, 0, 0}
12 };
13
14@@ -50,7 +53,7 @@
15 // [definedScale - 1][_scaleFactor - 1]
16 static ScalerProc *scalersMagn[3][3] = {
17 #ifndef DISABLE_SCALERS
18- { Normal1x, AdvMame2x, AdvMame3x },
19+ { Normal1x, Edge2x_Interp, Edge3x },
20 { Normal1x, Normal1x, Normal1o5x },
21 { Normal1x, Normal1x, Normal1x }
22 #else // remove dependencies on other scalers
23@@ -68,7 +71,8 @@
24 { GFX_NORMAL, GFX_SUPER2XSAI, -1, -1 },
25 { GFX_NORMAL, GFX_SUPEREAGLE, -1, -1 },
26 { GFX_NORMAL, GFX_TV2X, -1, -1 },
27- { GFX_NORMAL, GFX_DOTMATRIX, -1, -1 }
28+ { GFX_NORMAL, GFX_DOTMATRIX, -1, -1 },
29+ { GFX_NORMAL, GFX_EDGE2X_INTERP, GFX_EDGE3X, -1 }
30 };
31
32 #ifndef DISABLE_SCALERS
33@@ -201,6 +205,18 @@
34 newScaleFactor = 2;
35 newScalerProc = DotMatrix;
36 break;
37+ case GFX_EDGE2X:
38+ newScaleFactor = 2;
39+ newScalerProc = Edge2x;
40+ break;
41+ case GFX_EDGE2X_INTERP:
42+ newScaleFactor = 2;
43+ newScalerProc = Edge2x_Interp;
44+ break;
45+ case GFX_EDGE3X:
46+ newScaleFactor = 3;
47+ newScalerProc = Edge3x;
48+ break;
49 #endif // DISABLE_SCALERS
50
51 default:
52diff -ruN -b backup_version/backends/platform/sdl/sdl-common.h new_version/backends/platform/sdl/sdl-common.h
53--- backup_version/backends/platform/sdl/sdl-common.h 2006-07-30 00:48:50.000000000 -0500
54+++ new_version/backends/platform/sdl/sdl-common.h 2006-07-31 04:25:16.000000000 -0500
55@@ -51,7 +51,10 @@
56 GFX_HQ2X = 8,
57 GFX_HQ3X = 9,
58 GFX_TV2X = 10,
59- GFX_DOTMATRIX = 11
60+ GFX_DOTMATRIX = 11,
61+ GFX_EDGE2X = 12,
62+ GFX_EDGE2X_INTERP = 13,
63+ GFX_EDGE3X = 14
64 };
65
66
67diff -ruN -b backup_version/base/commandLine.cpp new_version/base/commandLine.cpp
68--- backup_version/base/commandLine.cpp 2006-07-30 00:48:42.000000000 -0500
69+++ new_version/base/commandLine.cpp 2006-07-31 04:23:46.000000000 -0500
70@@ -82,7 +82,7 @@
71 " -F, --no-fullscreen Force windowed mode\n"
72 " -g, --gfx-mode=MODE Select graphics scaler (normal,2x,3x,2xsai,\n"
73 " super2xsai,supereagle,advmame2x,advmame3x,hq2x,\n"
74- " hq3x,tv2x,dotmatrix)\n"
75+ " hq3x,tv2x,dotmatrix,edge2x,edge2xi,edge3x)\n"
76 " --gui-theme=THEME Select GUI theme (default, modern, classic)\n"
77 " --themepath=PATH Path to where GUI themes are stored\n"
78 " -e, --music-driver=MODE Select music driver (see README for details)\n"
79diff -ruN -b backup_version/graphics/module.mk new_version/graphics/module.mk
80--- backup_version/graphics/module.mk 2006-07-30 00:48:00.000000000 -0500
81+++ new_version/graphics/module.mk 2006-07-31 04:56:50.000000000 -0500
82@@ -25,7 +25,8 @@
83 scaler/aspect.o \
84 scaler/scale2x.o \
85 scaler/scale3x.o \
86- scaler/scalebit.o
87+ scaler/scalebit.o \
88+ scaler/edge3x.o
89
90 ifndef DISABLE_HQ_SCALERS
91 MODULE_OBJS += \
92diff -ruN -b backup_version/graphics/scaler/edge3x.cpp new_version/graphics/scaler/edge3x.cpp
93--- backup_version/graphics/scaler/edge3x.cpp 1969-12-31 18:00:00.000000000 -0600
94+++ new_version/graphics/scaler/edge3x.cpp 2006-10-03 23:03:26.000000000 -0500
95@@ -0,0 +1,4564 @@
96+/* ScummVM - Scumm Interpreter
97+ * Copyright (C) 2001 Ludvig Strigeus
98+ * Copyright (C) 2001-2006 The ScummVM project
99+ *
100+ * This program is free software; you can redistribute it and/or
101+ * modify it under the terms of the GNU General Public License
102+ * as published by the Free Software Foundation; either version 2
103+ * of the License, or (at your option) any later version.
104+ *
105+ * This program is distributed in the hope that it will be useful,
106+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
107+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
108+ * GNU General Public License for more details.
109+ *
110+ * You should have received a copy of the GNU General Public License
111+ * along with this program; if not, write to the Free Software
112+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
113+ *
114+ */
115+
116+/*
117+ * Another edge-directed 2x/3x anti-aliasing scaler for ScummVM
118+ *
119+ * Author: Eric A. Welsh
120+ *
121+ * INTERPOLATE/Q_INTERPOLATE macros taken from HQ2x/HQ3x scalers
122+ * (Authors: Maxim Stepin and Max Horn)
123+ *
124+ *
125+ * Sharp, clean, anti-aliased image with very few artifacts.
126+ * Detects and appropriately handles mouse overlays with transparent pixels.
127+ * The Edge3x filter detects unchanged pixels and does not redraw them,
128+ * resulting in a considerable gain in speed when there are even a moderate
129+ * number of unchanged pixels. Edge3x and Edge2x anti-alias using nearest-
130+ * neighbor methods. Edge2xi interpolates.
131+ *
132+ * The really slow speed is mainly due to the edge detection algorithm. In
133+ * order to accurately detect the edge direction (and thus avoid artifacts
134+ * caused by mis-detection), the edge detection and refinement process is
135+ * rather long and involved. Speed must be sacrificed in order to avoid
136+ * artifacts :( If anyone is tempted to optimize using lower precision
137+ * math, such as converting some of the double math to fixed-point integer,
138+ * or lowering the number of significant bits used in the existing integer
139+ * math to squeeze it into accelerated 16-bit vector instructions, please do
140+ * not do this. Any loss in precision results in visibly degraded image
141+ * quality. I've tried integer conversions of various double math, and tried
142+ * reducing the number of significant digits I use in the integer math, and
143+ * it always results in less accurate edge detection and lower image quality.
144+ * If you're going to optimize, make sure you don't sacrifice any precision.
145+ * There may be a few places I could change the variable types from
146+ * int32 to int16 without introducing overflows, though. I should also
147+ * probably change some of the flags and arrays to bools or chars, rather
148+ * than ints, since they are only 0 or 1.
149+ *
150+ * It's a bit slow... but ScummVM runs most things fine on my 1.53 GHz Athlon.
151+ * Increasing the Win32 thread priority can help by forcing Windows not to
152+ * twiddle its thumbs and idle as much during heavy CPU load. The Dig
153+ * cutscene when the asteroid is activated is a little jerky, pans/fades in
154+ * Amazon Queen and Beneath a Steel Sky are slow. Faster machines probably
155+ * won't have a problem. I remember a time when my home machine was too slow
156+ * to run SNES emulators with 2xSaI filters, so I don't think speed is such a
157+ * big issue here. It won't be too long before the average home computer is
158+ * plenty fast enough to run this filter.
159+ *
160+ */
161+
162+/*
163+ * Notes on handling overlays, mouse, transparencies, etc.:
164+ *
165+ * As I write this, the SDL backend does not call different filters based on
166+ * whether or not the bitmaps contain transparency. Bitmaps with transparency
167+ * need to be treated differently. 1) Interpolation needs to be disabled,
168+ * since interpolating with transparent pixels produces ugly smears around the
169+ * transparent areas. 2) Transparent pixels need to be treated differently
170+ * during edge detection, so that they appear to be as if they were colors
171+ * that would give maximal contrast in the current 3x3 window.
172+ *
173+ * Currently, the SDL backend calls anti-aliasing resize filters to either
174+ * resize the game screen or resize the mouse. The filter stores the src
175+ * array bounds whenever the width and height of the area to be resized are
176+ * equal to the width and height of the current game screen. If the current
177+ * src array is outside these bounds, then it is assumed that the mouse or
178+ * menu overlay is being drawn. This works perfectly for the current SDL
179+ * backend, but it is still a hack. If, in the future, the filter were to
180+ * to be used to resize a transparent overlay with dimensions equal to those
181+ * of the current game screen, that overlay would be resized without any
182+ * special transparency consideration. The same goes for a mouse pointer
183+ * that is equal to the size of the screen, but I don't forsee this ever
184+ * being a problem.... The correct solution would be to rewrite the backends
185+ * to call filters differently depending on whether or not the bitmap contains
186+ * transparent pixels, and whether or not the end result should be
187+ * interpolated or resized using nearest-neighbor. Until then, the array
188+ * bounds checking hack will have to do.
189+ *
190+ */
191+
192+#include <math.h>
193+#include "common/stdafx.h"
194+#include "common/scummsys.h"
195+#include "common/system.h"
196+
197+/* Randomly XORs one of 2x2 or 3x3 resized pixels in order to indicate
198+ * which pixels have been redrawn. Useful for seeing which areas of
199+ * the screen are being redrawn. Good for seeing dirty rects, full screen
200+ * refreshes, etc.. Also good for seeing if the unchanged pixel detection is
201+ * working correctly or not :)
202+ */
203+#define DEBUG_REFRESH_RANDOM_XOR 0 /* debug redraws */
204+
205+/* Use with DEBUG_REFRESH_RANDOM_XOR. Randomize the borders of the drawing
206+ * area, whether they are unchanged or not. Useful for visualizing the
207+ * borders of the drawing area. You might be surprised at which areas of the
208+ * screen get redraw requests, even areas with absolutely nothing moving,
209+ * or color cycling, or anything that would cause a dirty rect or require a
210+ * redraw....
211+ */
212+#define DEBUG_DRAW_REFRESH_BORDERS 0 /* more redraw debug */
213+
214+#define INCREASE_WIN32_PRIORITY 0 /* 1 for slow CPUs */
215+#define PARANOID_KNIGHTS 1 /* avoid artifacts */
216+#define PARANOID_ARROWS 1 /* avoid artifacts */
217+#define HANDLE_TRANSPARENT_OVERLAYS 1 /* as it says */
218+
219+#define SIN45 0.7071067811865 /* sin of 45 degrees */
220+#define GREY_SHIFT 12 /* bit shift for greyscale precision */
221+#define RGB_SHIFT 13 /* bit shift for RGB precision */
222+
223+const int16 one_sqrt2 = (int16) (((int16)1<<GREY_SHIFT) / sqrt(2.0) + 0.5);
224+int16 rgb_table[65536][3] = {0}; /* table lookup for RGB */
225+int16 greyscale_table[3][65536] = {0}; /* greyscale tables */
226+int16 *chosen_greyscale; /* pointer to chosen greyscale table */
227+int16 *bptr_global; /* too awkward to pass variables */
228+int8 sim_sum; /* sum of similarity matrix */
229+
230+uint16 div3[189]; /* tables for pixel interpolation */
231+uint16 div9[567];
232+
233+int32 max_old_src_size = 0; /* maximum observed rectangle size */
234+int32 max_overlay_size = 0; /* maximum observed overlay size */
235+int32 max_old_dst_size = 0;
236+int32 max_dst_overlay_size = 0;
237+uint16 *old_src = NULL; /* old src array */
238+uint16 *old_overlay = NULL; /* holds the old overlay */
239+uint16 *old_dst = NULL; /* old dst array */
240+uint16 *old_dst_overlay = NULL; /* old dst overlay array */
241+
242+int cur_screen_width = 0; /* current game screen w and h */
243+int cur_screen_height = 0;
244+int old_screen_width = 0; /* previous game screen w and h */
245+int old_screen_height = 0;
246+int cur_dst_screen_width = 0; /* scaled dst w and h */
247+int cur_dst_screen_height = 0;
248+int old_dst_screen_width = 0;
249+int old_dst_screen_height = 0;
250+int cur_overlay_width = 0;
251+int cur_overlay_height = 0;
252+int old_overlay_width = 0;
253+int old_overlay_height = 0;
254+int cur_dst_overlay_width = 0;
255+int cur_dst_overlay_height = 0;
256+int old_dst_overlay_width = 0;
257+int old_dst_overlay_height = 0;
258+int max_scale = -1; /* used for dst buffer arrays */
259+
260+int init_flag = 0; /* have the tables been initialized? */
261+const uint16 *src_addr_min = NULL; /* start of src screen array */
262+const uint16 *src_addr_max = NULL; /* end of src screen array */
263+
264+const int16 int32_sqrt3 = (int16) (((int16)1<<GREY_SHIFT) * sqrt(3.0) + 0.5);
265+
266+
267+
268+#if DEBUG_REFRESH_RANDOM_XOR
269+/* Random number generators with very good randomness properties, far better
270+ * than the simple linear congruential generator in the ScummVM utils.
271+ * The RNG algorithms were developed by George Marsaglia, as published in his
272+ * "Xorshift RNGs" paper and various USENET postings.
273+ *
274+ * Marsaglia, George, 2003, "Xorshift RNGs", Journal of Statistical Software,
275+ * Volume 7, Issue 14
276+ *
277+ * Note the comments in the code below about how many of the triplet and shift
278+ * combinations published in his paper and various USENET postings don't quite
279+ * work as expected (yes, I exhaustively tested all 648 of them with his test
280+ * suite). Only a few "magic" combinations actually produce good random
281+ * numbers. I suspect this is due to the numbers being shifted too far off
282+ * the ends of the registers?
283+ *
284+ * While numbers this highly random are overkill for our purposes, I already
285+ * had this code written for various scientific analysis programs, and I've
286+ * tested the generators with Marsaglia's comprehensive randomness test
287+ * suite, so I know that they have very good randomness. The simple single
288+ * seed algorithm does fail a few minor tests, but it is still LOADS better
289+ * than a linear congruential generator. The 4 seed RNG passes all tests
290+ * with flying colors and has a pretty big period to boot. I actually use
291+ * a 4096 seed RNG for my scientific work, but that is MAJOR overkill for
292+ * the simple purposes we require here, so I've not included it :)
293+ */
294+
295+uint32 seed0, seed1, seed2, seed3;
296+
297+/* period 2^32 - 1 */
298+/* fails Gorilla test, binary rank matrix */
299+/* the ONLY good triplet and shift combinations out of the list of 648:
300+ *
301+ * 3 7 13 >> >> <<
302+ * 3 7 13 << << >>
303+ * 7 3 13 >> >> <<
304+ * 7 3 13 << << >>
305+ *
306+ * 5 6 13 >> >> <<
307+ * 5 6 13 << << >>
308+ * 6 5 13 >> >> <<
309+ * 6 5 13 << << >> seems to be slightly "better" than the others?
310+ *
311+ * all others, including the "favorite" (13, 17, 5), fail some Monkey tests
312+ */
313+uint32 xorshift_32(void)
314+{
315+ seed0 ^= seed0 << 6;
316+ seed0 ^= seed0 << 5;
317+ seed0 ^= seed0 >> 13;
318+
319+ return(seed0);
320+}
321+
322+/* period 2^128 - 1 */
323+/* None of the other published 2^128-1 xorshift RNGs passed OPERM5 */
324+uint32 xorshift_128(void)
325+{
326+ uint32 temp;
327+
328+ temp = (seed0 ^ (seed0 << 20)) ^ (seed1 ^ (seed1 >> 11)) ^
329+ (seed2 ^ (seed2 << 27)) ^ (seed3 ^ (seed3 >> 6));
330+ seed0 = seed1;
331+ seed1 = seed2;
332+ seed2 = seed3;
333+ seed3 = temp;
334+
335+ return (temp);
336+}
337+
338+/* return a random fraction over the range [0, 1) */
339+double dxorshift_128(void)
340+{
341+ uint32 temp;
342+
343+ temp = (seed0 ^ (seed0 << 20)) ^ (seed1 ^ (seed1 >> 11)) ^
344+ (seed2 ^ (seed2 << 27)) ^ (seed3 ^ (seed3 >> 6));
345+ seed0 = seed1;
346+ seed1 = seed2;
347+ seed2 = seed3;
348+ seed3 = temp;
349+
350+ return (temp / 4294967296.0);
351+}
352+
353+void initialize_xorshift_128(uint32 seed)
354+{
355+ /* seed0 needs to be initialized prior to calling xorshift_32() */
356+ seed0 = seed;
357+
358+ /* initialize with xorshift_32() */
359+ seed0 = xorshift_32();
360+ seed1 = xorshift_32();
361+ seed2 = xorshift_32();
362+ seed3 = xorshift_32();
363+}
364+#endif
365+
366+
367+
368+/*
369+ * Faster than standard double atan(), |error| < 7E-6
370+ *
371+ * Original equation from Ranko Bojanic in StuChat37:
372+ *
373+ * |x| <= 1:
374+ *
375+ * x + A*x3 A = 0.43157974, B = 0.76443945, C = 0.05831938
376+ * ---------------
377+ * 1 + B*x2 + C*x4
378+ *
379+ *
380+ *
381+ * After some optimizations:
382+ *
383+ * |x| <= 1:
384+ *
385+ * x * (E + F*x2) E = 1/C, F = A/C
386+ * ---------------- G = (B/C + sqrt(B2/C2 - 4/C)) / 2
387+ * (G + x2)(H + x2) H = (B/C - sqrt(B2/C2 - 4/C)) / 2
388+ *
389+ * E = 17.14695869537, F = 7.400279975541
390+ * G = 11.63393762882, H = 1.473874045440
391+ *
392+ * |x| > 1: pi/2 -
393+ *
394+ * x * (I + x2) I = A
395+ * ---------------- J = (B + sqrt(B2 - 4C)) / 2
396+ * (J + x2)(K + x2) K = (B - sqrt(B2 - 4C)) / 2
397+ *
398+ * I = 0.43157974
399+ * J = 0.6784840295980, K = 0.0859554204018
400+ *
401+ */
402+double fast_atan(double x0)
403+{
404+ double x2;
405+ double x;
406+
407+ x = fabs(x0);
408+ x2 = x*x;
409+ if (x > 1)
410+ {
411+ x2 = 1.570796326795 -
412+ x * (0.43157974 + x2) /
413+ ((0.6784840295980 + x2) * (0.0859554204018 + x2));
414+ if (x0 < 0) return -x2;
415+ return x2;
416+ }
417+
418+ return x0 * (17.14695869537 + 7.400279975541 * x2) /
419+ ((11.63393762882 + x2) * (1.473874045440 + x2));
420+}
421+
422+
423+
424+/*
425+ * Choose greyscale bitplane to use, return diff array. Exit early and
426+ * return NULL for a block of solid color (all diffs zero).
427+ *
428+ * No matter how you do it, mapping 3 bitplanes into a single greyscale
429+ * bitplane will always result in colors which are very different mapping to
430+ * the same greyscale value. Inevitably, these pixels will appear next to
431+ * each other at some point in some image, and edge detection on a single
432+ * bitplane will behave quite strangely due to them having the same or nearly
433+ * the same greyscale values. Calculating distances between pixels using all
434+ * three RGB bitplanes is *way* too time consuming, so single bitplane
435+ * edge detection is used for speed's sake. In order to try to avoid the
436+ * color mapping problems of using a single bitplane, 3 different greyscale
437+ * mappings are tested for each 3x3 grid, and the one with the most "signal"
438+ * (sum of squares difference from center pixel) is chosen. This usually
439+ * results in useable contrast within the 3x3 grid.
440+ *
441+ * This results in a whopping 25% increase in overall runtime of the filter
442+ * over simply using luma or some other single greyscale bitplane, but it
443+ * does greatly reduce the amount of errors due to greyscale mapping
444+ * problems. I think this is the best compromise between accuracy and
445+ * speed, and is still a lot faster than edge detecting over all three RGB
446+ * bitplanes. The increase in image quality is well worth the speed hit.
447+ *
448+ */
449+int16 * choose_greyscale(uint16 *pixels)
450+{
451+ static int16 greyscale_diffs[3][8];
452+ static int16 bplanes[3][9];
453+ int i, j;
454+ int32 scores[3];
455+
456+ for (i = 0; i < 3; i++)
457+ {
458+ int16 *diff_ptr;
459+ int16 *bptr;
460+ uint16 *pptr;
461+ int16 *grey_ptr;
462+ int16 center;
463+ int32 sum_diffs;
464+
465+ sum_diffs = 0;
466+
467+ grey_ptr = greyscale_table[i];
468+
469+ /* fill the 9 pixel window with greyscale values */
470+ bptr = bplanes[i];
471+ pptr = pixels;
472+ for (j = 9; j; --j)
473+ *bptr++ = grey_ptr[*pptr++];
474+ bptr = bplanes[i];
475+
476+ center = grey_ptr[pixels[4]];
477+ diff_ptr = greyscale_diffs[i];
478+
479+ /* calculate the delta from center pixel */
480+ diff_ptr[0] = bptr[0] - center;
481+ diff_ptr[1] = bptr[1] - center;
482+ diff_ptr[2] = bptr[2] - center;
483+ diff_ptr[3] = bptr[3] - center;
484+ diff_ptr[4] = bptr[5] - center;
485+ diff_ptr[5] = bptr[6] - center;
486+ diff_ptr[6] = bptr[7] - center;
487+ diff_ptr[7] = bptr[8] - center;
488+
489+ /* calculate sum of squares distance */
490+ for (j = 8; j; --j)
491+ sum_diffs += *diff_ptr * *diff_ptr++;
492+
493+ scores[i] = sum_diffs;
494+ }
495+
496+ /* choose greyscale with highest score, ties decided in GRB order */
497+
498+ if (scores[1] >= scores[0] && scores[1] >= scores[2])
499+ {
500+ if (!scores[1]) return NULL;
501+
502+ chosen_greyscale = greyscale_table[1];
503+ bptr_global = bplanes[1];
504+ return greyscale_diffs[1];
505+ }
506+
507+ if (scores[0] >= scores[1] && scores[0] >= scores[2])
508+ {
509+ if (!scores[0]) return NULL;
510+
511+ chosen_greyscale = greyscale_table[0];
512+ bptr_global = bplanes[0];
513+ return greyscale_diffs[0];
514+ }
515+
516+ if (!scores[2]) return NULL;
517+
518+ chosen_greyscale = greyscale_table[2];
519+ bptr_global = bplanes[2];
520+ return greyscale_diffs[2];
521+}
522+
523+
524+
525+/*
526+ * Calculate the distance between pixels in RGB space. Greyscale isn't
527+ * accurate enough for choosing nearest-neighbors :( Luma-like weighting
528+ * of the individual bitplane distances prior to squaring gives the most
529+ * useful results.
530+ *
531+ */
532+int32 calc_pixel_diff_nosqrt(uint16 pixel1, uint16 pixel2)
533+{
534+
535+#if 1 /* distance between pixels, weighted by roughly luma proportions */
536+ int32 sum = 0;
537+ int16 *rgb_ptr1 = rgb_table[pixel1];
538+ int16 *rgb_ptr2 = rgb_table[pixel2];
539+ int16 diff;
540+
541+ diff = (*rgb_ptr1++ - *rgb_ptr2++) << 1;
542+ sum += diff * diff;
543+ diff = (*rgb_ptr1++ - *rgb_ptr2++) << 2;
544+ sum += diff * diff;
545+ diff = (*rgb_ptr1 - *rgb_ptr2);
546+ sum += diff * diff;
547+
548+ return sum;
549+#endif
550+
551+#if 0 /* distance between pixels, weighted by chosen greyscale proportions */
552+ int32 sum = 0;
553+ int16 *rgb_ptr1 = rgb_table[pixel1];
554+ int16 *rgb_ptr2 = rgb_table[pixel2];
555+ int16 diff;
556+ int r_shift, g_shift, b_shift;
557+
558+ if (chosen_greyscale == greyscale_table[1])
559+ {
560+ r_shift = 1;
561+ g_shift = 2;
562+ b_shift = 0;
563+ }
564+ else if (chosen_greyscale == greyscale_table[0])
565+ {
566+ r_shift = 2;
567+ g_shift = 1;
568+ b_shift = 0;
569+ }
570+ else
571+ {
572+ r_shift = 0;
573+ g_shift = 1;
574+ b_shift = 2;
575+ }
576+
577+ diff = (*rgb_ptr1++ - *rgb_ptr2++) << r_shift;
578+ sum += diff * diff;
579+ diff = (*rgb_ptr1++ - *rgb_ptr2++) << g_shift;
580+ sum += diff * diff;
581+ diff = (*rgb_ptr1 - *rgb_ptr2) << b_shift;
582+ sum += diff * diff;
583+
584+ return sum;
585+#endif
586+
587+#if 0 /* distance between pixels, unweighted */
588+ int32 sum = 0;
589+ int16 *rgb_ptr1 = rgb_table[pixel1];
590+ int16 *rgb_ptr2 = rgb_table[pixel2];
591+ int16 diff;
592+
593+ diff = *rgb_ptr1++ - *rgb_ptr2++;
594+ sum += diff * diff;
595+ diff = *rgb_ptr1++ - *rgb_ptr2++;
596+ sum += diff * diff;
597+ diff = *rgb_ptr1 - *rgb_ptr2;
598+ sum += diff * diff;
599+
600+ return sum;
601+#endif
602+
603+#if 0 /* use the greyscale directly */
604+ return labs(chosen_greyscale[pixel1] - chosen_greyscale[pixel2]);
605+#endif
606+}
607+
608+
609+
610+/*
611+ * Create vectors of all delta grey values from center pixel, with magnitudes
612+ * ranging from [1.0, 0.0] (zero difference, maximum difference). Find
613+ * the two principle axes of the grid by calculating the eigenvalues and
614+ * eigenvectors of the inertia tensor. Use the eigenvectors to calculate the
615+ * edge direction. In other words, find the angle of the line that optimally
616+ * passes through the 3x3 pattern of pixels.
617+ *
618+ * Return horizontal (-), vertical (|), diagonal (/,\), multi (*), or none '0'
619+ *
620+ * Don't replace any of the double math with integer-based approximations,
621+ * since everything I have tried has lead to slight mis-detection errors.
622+ *
623+ */
624+int find_principle_axis(uint16 *pixels, int16 *diffs, int16 *bplane,
625+ int8 *sim,
626+ int32 *return_angle)
627+{
628+ struct xy_point
629+ {
630+ int16 x, y;
631+ };
632+
633+ int i;
634+ int16 centx = 0, centy = 0;
635+ struct xy_point xy_points[9];
636+ int angle;
637+ int reverse_flag = 1;
638+ int16 cutoff;
639+ int16 max_diff;
640+
641+ double x, y;
642+ int32 half_matrix[3] = {0};
643+
644+ double eigenval1, eigenval2;
645+ double best_val;
646+ double a, b, c;
647+ double ratio;
648+ int32 scale;
649+
650+ /* absolute value of differences */
651+ for (i = 0; i < 8; i++)
652+ diffs[i] = labs(diffs[i]);
653+
654+ /* find the max difference */
655+ max_diff = *diffs;
656+ for (i = 1; i < 8; i++)
657+ if (diffs[i] > max_diff) max_diff = diffs[i];
658+
659+ /* exit early on uniform window */
660+ /* already taken care of earlier elsewhere after greyscale assignment */
661+ /* if (max_diff == 0) return '0'; */
662+
663+ /* normalize the differences */
664+ scale = (1L<<(GREY_SHIFT+GREY_SHIFT)) / max_diff;
665+ for (i = 0; i < 8; i++)
666+ diffs[i] = (diffs[i] * scale + ((int16)1<<(GREY_SHIFT-1))) >> GREY_SHIFT;
667+
668+ /*
669+ * Some pixel patterns need to NOT be reversed, since the pixels of
670+ * interest that form the edge to be detected are off-center.
671+ *
672+ */
673+
674+ /* calculate yes/no similarity matrix to center pixel */
675+ /* store the number of similar pixels */
676+ cutoff = ((int16)1<<(GREY_SHIFT-3));
677+ for (i = 0, sim_sum = 0; i < 8; i++)
678+ sim_sum += (sim[i] = (diffs[i] < cutoff));
679+
680+ /* don't reverse pattern for off-center knights and sharp corners */
681+ if (sim_sum >= 3 && sim_sum <= 5)
682+ {
683+ /* |. */ /* '- */
684+ if (sim[1] && sim[4] && sim[5] && !sim[3] && !sim[6] &&
685+ (!sim[0] ^ !sim[7]))
686+ reverse_flag = 0;
687+
688+ /* -. */ /* '| */
689+ else if (sim[2] && sim[3] && sim[6] && !sim[1] && !sim[4] &&
690+ (!sim[0] ^ !sim[7]))
691+ reverse_flag = 0;
692+
693+ /* .- */ /* |' */
694+ else if (sim[4] && sim[6] && sim[0] && !sim[1] && !sim[3] &&
695+ (!sim[2] ^ !sim[5]))
696+ reverse_flag = 0;
697+
698+ /* .| */ /* -' */
699+ else if (sim[1] && sim[3] && sim[7] && !sim[4] && !sim[6] &&
700+ (!sim[2] ^ !sim[5]))
701+ reverse_flag = 0;
702+
703+ /* 90 degree corners */
704+ else if (sim_sum == 3)
705+ {
706+ if ((sim[0] && sim[1] && sim[3]) ||
707+ (sim[1] && sim[2] && sim[4]) ||
708+ (sim[3] && sim[5] && sim[6]) ||
709+ (sim[4] && sim[6] && sim[7]))
710+ reverse_flag = 0;
711+ }
712+ }
713+
714+ /* redo similarity array, less stringent for later checks */
715+ cutoff = ((int16)1<<(GREY_SHIFT-1));
716+ for (i = 0, sim_sum = 0; i < 8; i++)
717+ sim_sum += (sim[i] = (diffs[i] < cutoff));
718+
719+ /* center pixel is different from all the others, not an edge */
720+ if (sim_sum == 0) return '0';
721+
722+ /* reverse the difference array, so most similar is closest to 1 */
723+ if (reverse_flag)
724+ {
725+ diffs[0] = ((int16)1<<GREY_SHIFT) - diffs[0];
726+ diffs[1] = ((int16)1<<GREY_SHIFT) - diffs[1];
727+ diffs[2] = ((int16)1<<GREY_SHIFT) - diffs[2];
728+ diffs[3] = ((int16)1<<GREY_SHIFT) - diffs[3];
729+ diffs[4] = ((int16)1<<GREY_SHIFT) - diffs[4];
730+ diffs[5] = ((int16)1<<GREY_SHIFT) - diffs[5];
731+ diffs[6] = ((int16)1<<GREY_SHIFT) - diffs[6];
732+ diffs[7] = ((int16)1<<GREY_SHIFT) - diffs[7];
733+ }
734+
735+ /* scale diagonals for projection onto axes */
736+ diffs[0] = (diffs[0] * one_sqrt2 + ((int16)1<<(GREY_SHIFT-1))) >> GREY_SHIFT;
737+ diffs[2] = (diffs[2] * one_sqrt2 + ((int16)1<<(GREY_SHIFT-1))) >> GREY_SHIFT;
738+ diffs[5] = (diffs[5] * one_sqrt2 + ((int16)1<<(GREY_SHIFT-1))) >> GREY_SHIFT;
739+ diffs[7] = (diffs[7] * one_sqrt2 + ((int16)1<<(GREY_SHIFT-1))) >> GREY_SHIFT;
740+
741+ /* create the vectors, centered at 0,0 */
742+ xy_points[0].x = -diffs[0];
743+ xy_points[0].y = diffs[0];
744+ xy_points[1].x = 0;
745+ xy_points[1].y = diffs[1];
746+ xy_points[2].x = xy_points[2].y = diffs[2];
747+ xy_points[3].x = -diffs[3];
748+ xy_points[3].y = 0;
749+ xy_points[4].x = 0;
750+ xy_points[4].y = 0;
751+ xy_points[5].x = diffs[4];
752+ xy_points[5].y = 0;
753+ xy_points[6].x = xy_points[6].y = -diffs[5];
754+ xy_points[7].x = 0;
755+ xy_points[7].y = -diffs[6];
756+ xy_points[8].x = diffs[7];
757+ xy_points[8].y = -diffs[7];
758+
759+ /* calculate the centroid of the points */
760+ for (i = 0; i < 9; i++)
761+ {
762+ centx += xy_points[i].x;
763+ centy += xy_points[i].y;
764+ }
765+ centx /= 9;
766+ centy /= 9;
767+
768+ /* translate centroid to 0,0 */
769+ for (i = 0; i < 9; i++)
770+ {
771+ xy_points[i].x -= centx;
772+ xy_points[i].y -= centy;
773+ }
774+
775+ /* fill inertia tensor 3x3 matrix */
776+ for (i = 0; i < 9; i++)
777+ {
778+ half_matrix[0] += xy_points[i].x * xy_points[i].x;
779+ half_matrix[1] += xy_points[i].y * xy_points[i].x;
780+ half_matrix[2] += xy_points[i].y * xy_points[i].y;
781+ }
782+
783+ /* calculate eigenvalues */
784+ a = half_matrix[0] - half_matrix[2];
785+ b = half_matrix[1] << 1;
786+ b = sqrt(b*b + a*a);
787+ a = half_matrix[0] + half_matrix[2];
788+ eigenval1 = (a + b);
789+ eigenval2 = (a - b);
790+
791+ /* find largest eigenvalue */
792+ if (eigenval1 == eigenval2) /* X and + shapes */
793+ return '*';
794+ else if (eigenval1 > eigenval2)
795+ best_val = eigenval1;
796+ else
797+ best_val = eigenval2;
798+
799+ /* white center pixel, black background */
800+ if (!best_val)
801+ return '*';
802+
803+ /* divide eigenvalue by 2, postponed from when it should have been
804+ done during the eigenvalue calculation but was delayed for
805+ another early exit opportunity */
806+ best_val *= 0.5;
807+
808+ /* calculate eigenvectors */
809+ c = best_val + half_matrix[1];
810+ a = c - half_matrix[0];
811+ b = c - half_matrix[2];
812+ if (b)
813+ {
814+ x = 1.0;
815+ ratio = y = a / b;
816+ }
817+ else if (a)
818+ {
819+ y = 1.0;
820+ x = b / a;
821+ ratio = a / b;
822+ }
823+ else if (a == b)
824+ {
825+ *return_angle = 13500;
826+ return '\\';
827+ }
828+ else
829+ return '*';
830+
831+ /* calculate angle in degrees * 100 */
832+ if (x)
833+ {
834+ angle = (int32) floor(5729.577951307 * fast_atan(ratio) + 0.5);
835+ if (x < 0.0) angle += 18000;
836+ }
837+ else
838+ {
839+ if (y > 0.0) angle = 9000;
840+ else if (y < 0.0) angle = -9000;
841+ else return '0';
842+ }
843+
844+ /* force angle to lie between 0 to 360 */
845+ if (angle < 0) angle += 36000;
846+ if (angle > 18000) angle -= 18000;
847+ *return_angle = angle;
848+
849+ if (angle <= 2250)
850+ return '-';
851+
852+ if (angle < 6750)
853+ return '/';
854+
855+ if (angle <= 11250)
856+ return '|';
857+
858+ if (angle < 15750)
859+ return '\\';
860+
861+ return '-';
862+}
863+
864+
865+
866+/* Check for mis-detected arrow patterns. Return 1 (good), 0 (bad). */
867+int check_arrows(int best_dir, uint16 *pixels, int8 *sim, int half_flag)
868+{
869+ uint16 center = pixels[4];
870+
871+ if (center == pixels[0] && center == pixels[2] &&
872+ center == pixels[6] && center == pixels[8])
873+ {
874+ switch(best_dir)
875+ {
876+ case 5:
877+ if (center != pixels[5]) /* < */
878+ return 0;
879+ break;
880+ case 6:
881+ if (center != pixels[3]) /* > */
882+ return 0;
883+ break;
884+ case 7:
885+ if (center != pixels[7]) /* ^ */
886+ return 0;
887+ break;
888+ case 8:
889+ if (center != pixels[1]) /* v */
890+ return 0;
891+ break;
892+ }
893+ }
894+
895+ switch(best_dir)
896+ {
897+ case 5: /* < */
898+ if (center == pixels[2] && center == pixels[8] &&
899+ pixels[1] == pixels[5] && pixels[5] == pixels[7] &&
900+ (((center == pixels[0]) ^ (center == pixels[6])) ||
901+ (center == pixels[0] && center == pixels[6] &&
902+ pixels[1] != pixels[3])))
903+ return 0;
904+ break;
905+
906+ case 6: /* > */
907+ if (center == pixels[0] && center == pixels[6] &&
908+ pixels[1] == pixels[3] && pixels[3] == pixels[7] &&
909+ (((center == pixels[2]) ^ (center == pixels[8])) ||
910+ (center == pixels[2] && center == pixels[8] &&
911+ pixels[1] != pixels[5])))
912+ return 0;
913+ break;
914+
915+ case 7: /* ^ */
916+ if (center == pixels[6] && center == pixels[8] &&
917+ pixels[3] == pixels[7] && pixels[7] == pixels[5] &&
918+ (((center == pixels[0]) ^ (center == pixels[2])) ||
919+ (center == pixels[0] && center == pixels[2] &&
920+ pixels[3] != pixels[1])))
921+ return 0;
922+ break;
923+
924+ case 8: /* v */
925+ if (center == pixels[0] && center == pixels[2] &&
926+ pixels[1] == pixels[3] && pixels[1] == pixels[5] &&
927+ (((center == pixels[6]) ^ (center == pixels[8])) ||
928+ (center == pixels[6] && center == pixels[8] &&
929+ pixels[3] != pixels[7])))
930+ return 0;
931+ break;
932+ }
933+
934+ switch(best_dir)
935+ {
936+ case 5:
937+ if (sim[0] == sim[5] &&
938+ sim[1] == sim[3] &&
939+ sim[3] == sim[6] &&
940+ ((sim[2] && sim[7]) ||
941+ (half_flag && sim_sum == 2 && sim[4] &&
942+ (sim[2] || sim[7])))) /* < */
943+ return 1;
944+ break;
945+ case 6:
946+ if (sim[2] == sim[7] &&
947+ sim[1] == sim[4] &&
948+ sim[4] == sim[6] &&
949+ ((sim[0] && sim[5]) ||
950+ (half_flag && sim_sum == 2 && sim[3] &&
951+ (sim[0] || sim[5])))) /* > */
952+ return 1;
953+ break;
954+ case 7:
955+ if (sim[0] == sim[2] &&
956+ sim[1] == sim[3] &&
957+ sim[3] == sim[4] &&
958+ ((sim[5] && sim[7]) ||
959+ (half_flag && sim_sum == 2 && sim[6] &&
960+ (sim[5] || sim[7])))) /* ^ */
961+ return 1;
962+ break;
963+ case 8:
964+ if (sim[5] == sim[7] &&
965+ sim[3] == sim[6] &&
966+ sim[4] == sim[6] &&
967+ ((sim[0] && sim[2]) ||
968+ (half_flag && sim_sum == 2 && sim[1] &&
969+ (sim[0] || sim[2])))) /* v */
970+ return 1;
971+ break;
972+ }
973+
974+ return 0;
975+}
976+
977+
978+
979+/*
980+ * Take original direction, refine it by testing different pixel difference
981+ * patterns based on the initial gross edge direction.
982+ *
983+ * The angle value is not currently used, but may be useful for future
984+ * refinement algorithms.
985+ *
986+ */
987+int refine_direction(char edge_type, uint16 *pixels, int16 *bptr,
988+ int8 *sim, double angle)
989+{
990+ int32 sums_dir[9] = { 0 };
991+ int32 sum;
992+ int32 best_sum;
993+ int i, n, best_dir;
994+ int16 diff_array[26];
995+ int ok_arrow_flag = 1;
996+
997+ /*
998+ * - '- -. \ '| |. | |' .| / -' .- < > ^ v
999+ *
1000+ * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1001+ *
1002+ * \' .\ '/ /.
1003+ *
1004+ * 16 17 18 19
1005+ *
1006+ */
1007+
1008+ switch(edge_type)
1009+ {
1010+ case '|':
1011+ diff_array[0] = labs(bptr[4] - bptr[1]);
1012+ diff_array[1] = labs(bptr[4] - bptr[7]);
1013+ diff_array[2] = labs(bptr[3] - bptr[0]);
1014+ diff_array[3] = labs(bptr[3] - bptr[6]);
1015+ diff_array[4] = labs(bptr[5] - bptr[2]);
1016+ diff_array[5] = labs(bptr[5] - bptr[8]);
1017+ diff_array[6] = labs(bptr[4] - bptr[2]);
1018+ diff_array[7] = labs(bptr[4] - bptr[8]);
1019+ diff_array[8] = labs(bptr[3] - bptr[1]);
1020+ diff_array[9] = labs(bptr[3] - bptr[7]);
1021+ diff_array[10] = labs(bptr[4] - bptr[0]);
1022+ diff_array[11] = labs(bptr[4] - bptr[6]);
1023+ diff_array[12] = labs(bptr[5] - bptr[1]);
1024+ diff_array[13] = labs(bptr[5] - bptr[7]);
1025+ diff_array[14] = labs(bptr[0] - bptr[6]);
1026+ diff_array[15] = labs(bptr[2] - bptr[8]);
1027+ diff_array[16] = labs(bptr[1] - bptr[7]);
1028+ diff_array[17] = labs(bptr[0] - bptr[1]);
1029+ diff_array[18] = labs(bptr[2] - bptr[1]);
1030+ diff_array[19] = labs(bptr[0] - bptr[2]);
1031+ diff_array[20] = labs(bptr[3] - bptr[5]);
1032+ diff_array[21] = labs(bptr[6] - bptr[8]);
1033+ diff_array[22] = labs(bptr[6] - bptr[7]);
1034+ diff_array[23] = labs(bptr[8] - bptr[7]);
1035+
1036+ /* | vertical */
1037+ sums_dir[0] = diff_array[0] + diff_array[1] + diff_array[2] +
1038+ diff_array[3] + diff_array[4] + diff_array[5];
1039+
1040+ /* << top */
1041+ sum = diff_array[8] + diff_array[9] +
1042+ ((diff_array[6] + diff_array[7] +
1043+ diff_array[12] + diff_array[13]) << 1) +
1044+ diff_array[14] + diff_array[16] + diff_array[15];
1045+ sum = (sum * 6) / 13;
1046+ sums_dir[5] = sum;
1047+
1048+ /* >> top */
1049+ sum = diff_array[12] + diff_array[13] +
1050+ ((diff_array[10] + diff_array[11] +
1051+ diff_array[8] + diff_array[9]) << 1) +
1052+ diff_array[15] + diff_array[16] + diff_array[14];
1053+ sum = (sum * 6) / 13;
1054+ sums_dir[6] = sum;
1055+
1056+ /* ^ bottom */
1057+ sum = diff_array[8] + diff_array[12] +
1058+ ((diff_array[11] + diff_array[7]) << 1) +
1059+ (diff_array[1] << 2) +
1060+ diff_array[19] + diff_array[20] + diff_array[21];
1061+ sum = (sum * 6) / 13;
1062+ sums_dir[7] = sum;
1063+
1064+ /* v bottom */
1065+ sum = diff_array[9] + diff_array[13] +
1066+ ((diff_array[10] + diff_array[6]) << 1) +
1067+ (diff_array[0] << 2) +
1068+ diff_array[21] + diff_array[20] + diff_array[19];
1069+ sum = (sum * 6) / 13;
1070+ sums_dir[8] = sum;
1071+
1072+ /* '| */
1073+ sums_dir[1] = diff_array[1] + diff_array[5] + diff_array[10] +
1074+ diff_array[12] + (diff_array[3] << 1);
1075+ /* '| alt */
1076+ sum = diff_array[10] + diff_array[1] + diff_array[18] +
1077+ diff_array[4] + diff_array[5] + diff_array[14];
1078+ if (sum < sums_dir[1])
1079+ sums_dir[1] = sum;
1080+
1081+ /* |. */
1082+ sums_dir[2] = diff_array[0] + diff_array[2] + diff_array[7] +
1083+ diff_array[9] + (diff_array[4] << 1);
1084+ /* |. alt */
1085+ sum = diff_array[0] + diff_array[7] + diff_array[22] +
1086+ diff_array[3] + diff_array[2] + diff_array[15];
1087+ if (sum < sums_dir[2])
1088+ sums_dir[2] = sum;
1089+
1090+ /* |' */
1091+ sums_dir[3] = diff_array[1] + diff_array[3] + diff_array[6] +
1092+ diff_array[8] + (diff_array[5] << 1);
1093+ /* |' alt */
1094+ sum = diff_array[6] + diff_array[1] + diff_array[17] +
1095+ diff_array[2] + diff_array[3] + diff_array[15];
1096+ if (sum < sums_dir[3])
1097+ sums_dir[3] = sum;
1098+
1099+ /* .| */
1100+ sums_dir[4] = diff_array[0] + diff_array[4] + diff_array[11] +
1101+ diff_array[13] + (diff_array[2] << 1);
1102+ /* .| alt */
1103+ sum = diff_array[11] + diff_array[0] + diff_array[23] +
1104+ diff_array[5] + diff_array[4] + diff_array[14];
1105+ if (sum < sums_dir[4])
1106+ sums_dir[4] = sum;
1107+
1108+ best_sum = sums_dir[0];
1109+ for (i = 1; i < 9; i++)
1110+ if (sums_dir[i] < best_sum) best_sum = sums_dir[i];
1111+ if (best_sum == sums_dir[0]) return 6; /* | */
1112+
1113+ best_dir = 0;
1114+ for (i = 0, n = 0; i < 9; i++)
1115+ {
1116+ if (sums_dir[i] == best_sum)
1117+ {
1118+ best_dir = i;
1119+ n++;
1120+ }
1121+ }
1122+
1123+ /* best direction uncertain, return original direction */
1124+ if (n > 1) return 6; /* | */
1125+
1126+ if (best_dir >= 5)
1127+ ok_arrow_flag = check_arrows(best_dir, pixels, sim, 1);
1128+
1129+ switch(best_dir)
1130+ {
1131+ case 1:
1132+ return 4; /* '| */
1133+ break;
1134+ case 2:
1135+ return 5; /* |. */
1136+ break;
1137+ case 3:
1138+ return 7; /* |' */
1139+ break;
1140+ case 4:
1141+ return 8; /* .| */
1142+ break;
1143+ case 5:
1144+ if (ok_arrow_flag)
1145+ return 12; /* < */
1146+ break;
1147+ case 6:
1148+ if (ok_arrow_flag)
1149+ return 13; /* > */
1150+ break;
1151+ case 7:
1152+ if (ok_arrow_flag)
1153+ return 14; /* ^ */
1154+ break;
1155+ case 8:
1156+ if (ok_arrow_flag)
1157+ return 15; /* V */
1158+ break;
1159+ case 0:
1160+ default:
1161+ return 6; /* | */
1162+ break;
1163+ }
1164+
1165+ break;
1166+
1167+ case '-':
1168+ diff_array[0] = labs(bptr[4] - bptr[3]);
1169+ diff_array[1] = labs(bptr[4] - bptr[5]);
1170+ diff_array[2] = labs(bptr[0] - bptr[1]);
1171+ diff_array[3] = labs(bptr[1] - bptr[2]);
1172+ diff_array[4] = labs(bptr[7] - bptr[6]);
1173+ diff_array[5] = labs(bptr[7] - bptr[8]);
1174+ diff_array[6] = labs(bptr[4] - bptr[6]);
1175+ diff_array[7] = labs(bptr[4] - bptr[8]);
1176+ diff_array[8] = labs(bptr[1] - bptr[3]);
1177+ diff_array[9] = labs(bptr[1] - bptr[5]);
1178+ diff_array[10] = labs(bptr[4] - bptr[0]);
1179+ diff_array[11] = labs(bptr[4] - bptr[2]);
1180+ diff_array[12] = labs(bptr[7] - bptr[3]);
1181+ diff_array[13] = labs(bptr[7] - bptr[5]);
1182+ diff_array[14] = labs(bptr[0] - bptr[2]);
1183+ diff_array[15] = labs(bptr[6] - bptr[8]);
1184+ diff_array[16] = labs(bptr[3] - bptr[5]);
1185+ diff_array[17] = labs(bptr[0] - bptr[3]);
1186+ diff_array[18] = labs(bptr[6] - bptr[3]);
1187+ diff_array[19] = labs(bptr[0] - bptr[6]);
1188+ diff_array[20] = labs(bptr[1] - bptr[7]);
1189+ diff_array[21] = labs(bptr[2] - bptr[8]);
1190+ diff_array[22] = labs(bptr[2] - bptr[5]);
1191+ diff_array[23] = labs(bptr[8] - bptr[5]);
1192+
1193+ /* - horizontal */
1194+ sums_dir[0] = diff_array[0] + diff_array[1] + diff_array[2] +
1195+ diff_array[3] + diff_array[4] + diff_array[5];
1196+
1197+ /* << bottom */
1198+ sum = diff_array[8] + diff_array[12] +
1199+ ((diff_array[11] + diff_array[7]) << 1) +
1200+ (diff_array[1] << 2) +
1201+ diff_array[19] + diff_array[20] + diff_array[21];
1202+ sum = (sum * 6) / 13;
1203+ sums_dir[5] = sum;
1204+
1205+ /* >> bottom */
1206+ sum = diff_array[9] + diff_array[13] +
1207+ ((diff_array[10] + diff_array[6]) << 1) +
1208+ (diff_array[0] << 2) +
1209+ diff_array[21] + diff_array[20] + diff_array[19];
1210+ sum = (sum * 6) / 13;
1211+ sums_dir[6] = sum;
1212+
1213+ /* ^ top */
1214+ sum = diff_array[8] + diff_array[9] +
1215+ ((diff_array[6] + diff_array[7] +
1216+ diff_array[12] + diff_array[13]) << 1) +
1217+ diff_array[14] + diff_array[16] + diff_array[15];
1218+ sum = (sum * 6) / 13;
1219+ sums_dir[7] = sum;
1220+
1221+ /* v top */
1222+ sum = diff_array[12] + diff_array[13] +
1223+ ((diff_array[10] + diff_array[11] +
1224+ diff_array[8] + diff_array[9]) << 1) +
1225+ diff_array[15] + diff_array[16] + diff_array[14];
1226+ sum = (sum * 6) / 13;
1227+ sums_dir[8] = sum;
1228+
1229+ /* '- */
1230+ sums_dir[1] = diff_array[1] + diff_array[5] + diff_array[10] +
1231+ diff_array[12] + (diff_array[3] << 1);
1232+ /* '- alt */
1233+ sum = diff_array[10] + diff_array[1] + diff_array[18] +
1234+ diff_array[4] + diff_array[5] + diff_array[14];
1235+ if (sum < sums_dir[1])
1236+ sums_dir[1] = sum;
1237+
1238+ /* -. */
1239+ sums_dir[2] = diff_array[0] + diff_array[2] + diff_array[7] +
1240+ diff_array[9] + (diff_array[4] << 1);
1241+ /* -. alt */
1242+ sum = diff_array[0] + diff_array[7] + diff_array[22] +
1243+ diff_array[3] + diff_array[2] + diff_array[15];
1244+ if (sum < sums_dir[2])
1245+ sums_dir[2] = sum;
1246+
1247+ /* -' */
1248+ sums_dir[3] = diff_array[0] + diff_array[4] + diff_array[11] +
1249+ diff_array[13] + (diff_array[2] << 1);
1250+ /* -' alt */
1251+ sum = diff_array[11] + diff_array[0] + diff_array[23] +
1252+ diff_array[5] + diff_array[4] + diff_array[14];
1253+ if (sum < sums_dir[3])
1254+ sums_dir[3] = sum;
1255+
1256+ /* .- */
1257+ sums_dir[4] = diff_array[1] + diff_array[3] + diff_array[6] +
1258+ diff_array[8] + (diff_array[5] << 1);
1259+ /* .- alt */
1260+ sum = diff_array[6] + diff_array[1] + diff_array[17] +
1261+ diff_array[2] + diff_array[3] + diff_array[15];
1262+ if (sum < sums_dir[4])
1263+ sums_dir[4] = sum;
1264+
1265+ best_sum = sums_dir[0];
1266+ for (i = 1; i < 9; i++)
1267+ if (sums_dir[i] < best_sum) best_sum = sums_dir[i];
1268+ if (best_sum == sums_dir[0]) return 0; /* - */
1269+
1270+ best_dir = 0;
1271+ for (i = 0, n = 0; i < 9; i++)
1272+ {
1273+ if (sums_dir[i] == best_sum)
1274+ {
1275+ best_dir = i;
1276+ n++;
1277+ }
1278+ }
1279+
1280+ /* best direction uncertain, return original direction */
1281+ if (n > 1) return 0; /* - */
1282+
1283+ if (best_dir >= 5)
1284+ ok_arrow_flag = check_arrows(best_dir, pixels, sim, 1);
1285+
1286+ switch(best_dir)
1287+ {
1288+ case 1:
1289+ return 1; /* '- */
1290+ break;
1291+ case 2:
1292+ return 2; /* -. */
1293+ break;
1294+ case 3:
1295+ return 10; /* -' */
1296+ break;
1297+ case 4:
1298+ return 11; /* .- */
1299+ break;
1300+ case 5:
1301+ if (ok_arrow_flag)
1302+ return 12; /* < */
1303+ break;
1304+ case 6:
1305+ if (ok_arrow_flag)
1306+ return 13; /* > */
1307+ break;
1308+ case 7:
1309+ if (ok_arrow_flag)
1310+ return 14; /* ^ */
1311+ break;
1312+ case 8:
1313+ if (ok_arrow_flag)
1314+ return 15; /* V */
1315+ break;
1316+ case 0:
1317+ default:
1318+ return 0; /* - */
1319+ break;
1320+ }
1321+
1322+ break;
1323+
1324+ case '\\':
1325+
1326+ /* CHECK -- handle noisy half-diags */
1327+ if (sim_sum == 1)
1328+ {
1329+ if (pixels[1] == pixels[3] && pixels[3] == pixels[5] &&
1330+ pixels[5] == pixels[7])
1331+ {
1332+ if (pixels[2] != pixels[1] && pixels[6] != pixels[1])
1333+ {
1334+ sum = labs(bptr[2] - bptr[4]) +
1335+ labs(bptr[6] - bptr[4]);
1336+
1337+ if (sim[0] && sum < (labs(bptr[8] - bptr[4]) << 1))
1338+ {
1339+ if (bptr[4] > bptr[8])
1340+ {
1341+ if (bptr[2] > bptr[4] &&
1342+ bptr[6] > bptr[4])
1343+ return 18; /* '/ */
1344+ }
1345+ else
1346+ {
1347+ if (bptr[2] < bptr[4] &&
1348+ bptr[6] < bptr[4])
1349+ return 18; /* '/ */
1350+ }
1351+ }
1352+
1353+ if (sim[7] && sum < (labs(bptr[0] - bptr[4]) << 1))
1354+ {
1355+ if (bptr[4] > bptr[0])
1356+ {
1357+ if (bptr[2] > bptr[4] &&
1358+ bptr[6] > bptr[4])
1359+ return 19; /* /. */
1360+ }
1361+ else
1362+ {
1363+ if (bptr[2] < bptr[4] &&
1364+ bptr[6] < bptr[4])
1365+ return 19; /* /. */
1366+ }
1367+ }
1368+ }
1369+ }
1370+
1371+ if (sim[0] &&
1372+ labs(bptr[4] - bptr[0]) < ((int16)1<<(GREY_SHIFT-3)))
1373+ return 3; /* \ */
1374+ if (sim[7] &&
1375+ labs(bptr[4] - bptr[8]) < ((int16)1<<(GREY_SHIFT-3)))
1376+ return 3; /* \ */
1377+ }
1378+
1379+ diff_array[0] = labs(bptr[4] - bptr[0]);
1380+ diff_array[1] = labs(bptr[4] - bptr[5]);
1381+ diff_array[2] = labs(bptr[3] - bptr[7]);
1382+ diff_array[3] = labs(bptr[7] - bptr[8]);
1383+ diff_array[4] = labs(bptr[1] - bptr[2]);
1384+ diff_array[5] = labs(bptr[4] - bptr[3]);
1385+ diff_array[6] = labs(bptr[4] - bptr[8]);
1386+ diff_array[7] = labs(bptr[0] - bptr[1]);
1387+ diff_array[8] = labs(bptr[1] - bptr[5]);
1388+ diff_array[9] = labs(bptr[6] - bptr[7]);
1389+ diff_array[10] = labs(bptr[4] - bptr[7]);
1390+ diff_array[11] = labs(bptr[5] - bptr[8]);
1391+ diff_array[12] = labs(bptr[3] - bptr[6]);
1392+ diff_array[13] = labs(bptr[4] - bptr[1]);
1393+ diff_array[14] = labs(bptr[0] - bptr[3]);
1394+ diff_array[15] = labs(bptr[2] - bptr[5]);
1395+ diff_array[20] = labs(bptr[0] - bptr[2]);
1396+ diff_array[21] = labs(bptr[6] - bptr[8]);
1397+ diff_array[22] = labs(bptr[0] - bptr[6]);
1398+ diff_array[23] = labs(bptr[2] - bptr[8]);
1399+ diff_array[16] = labs(bptr[4] - bptr[2]);
1400+ diff_array[18] = labs(bptr[4] - bptr[6]);
1401+
1402+ /* '- */
1403+ sums_dir[1] = diff_array[0] + diff_array[1] + diff_array[2] +
1404+ diff_array[3] + (diff_array[4] << 1);
1405+ /* '- alt */
1406+ sum = diff_array[0] + diff_array[1] + diff_array[12] +
1407+ diff_array[9] + diff_array[3] + diff_array[20];
1408+ if (sum < sums_dir[1])
1409+ sums_dir[1] = sum;
1410+
1411+ /* -. */
1412+ sums_dir[2] = diff_array[5] + diff_array[6] + diff_array[7] +
1413+ diff_array[8] + (diff_array[9] << 1);
1414+ /* -. alt */
1415+ sum = diff_array[6] + diff_array[5] + diff_array[15] +
1416+ diff_array[4] + diff_array[7] + diff_array[21];
1417+ if (sum < sums_dir[2])
1418+ sums_dir[2] = sum;
1419+
1420+ /* '| */
1421+ sums_dir[3] = diff_array[0] + diff_array[8] + diff_array[10] +
1422+ diff_array[11] + (diff_array[12] << 1);
1423+ /* '| alt */
1424+ sum = diff_array[0] + diff_array[10] + diff_array[4] +
1425+ diff_array[15] + diff_array[11] + diff_array[22];
1426+ if (sum < sums_dir[3])
1427+ sums_dir[3] = sum;
1428+
1429+ /* |. */
1430+ sums_dir[4] = diff_array[2] + diff_array[6] + diff_array[13] +
1431+ diff_array[14] + (diff_array[15] << 1);
1432+ /* |. alt */
1433+ sum = diff_array[13] + diff_array[6] + diff_array[9] +
1434+ diff_array[12] + diff_array[14] + diff_array[23];
1435+ if (sum < sums_dir[4])
1436+ sums_dir[4] = sum;
1437+
1438+ /* \ 45 */
1439+ sums_dir[0] = diff_array[0] + diff_array[6] +
1440+ (diff_array[2] << 1) + (diff_array[8] << 1);
1441+
1442+ /* << top */
1443+ sum = labs(bptr[3] - bptr[1]) + labs(bptr[3] - bptr[7]) +
1444+ ((labs(bptr[4] - bptr[2]) + labs(bptr[4] - bptr[8]) +
1445+ labs(bptr[5] - bptr[1]) + labs(bptr[5] - bptr[7])) << 1) +
1446+ labs(bptr[0] - bptr[6]) + labs(bptr[1] - bptr[7]) +
1447+ labs(bptr[2] - bptr[8]);
1448+ sum = (sum * 6) / 13;
1449+ sums_dir[5] = sum;
1450+
1451+ /* >> top */
1452+ sum = labs(bptr[5] - bptr[1]) + labs(bptr[5] - bptr[7]) +
1453+ ((labs(bptr[4] - bptr[0]) + labs(bptr[4] - bptr[6]) +
1454+ labs(bptr[3] - bptr[1]) + labs(bptr[3] - bptr[7])) << 1) +
1455+ labs(bptr[2] - bptr[8]) + labs(bptr[1] - bptr[7]) +
1456+ labs(bptr[0] - bptr[6]);
1457+ sum = (sum * 6) / 13;
1458+ sums_dir[6] = sum;
1459+
1460+ /* ^ top */
1461+ sum = labs(bptr[1] - bptr[3]) + labs(bptr[1] - bptr[5]) +
1462+ ((labs(bptr[4] - bptr[6]) + labs(bptr[4] - bptr[8]) +
1463+ labs(bptr[7] - bptr[3]) + labs(bptr[7] - bptr[5])) << 1) +
1464+ labs(bptr[0] - bptr[2]) + labs(bptr[3] - bptr[5]) +
1465+ labs(bptr[6] - bptr[8]);
1466+ sum = (sum * 6) / 13;
1467+ sums_dir[7] = sum;
1468+
1469+ /* v top */
1470+ sum = labs(bptr[7] - bptr[3]) + labs(bptr[7] - bptr[5]) +
1471+ ((labs(bptr[4] - bptr[0]) + labs(bptr[4] - bptr[2]) +
1472+ labs(bptr[1] - bptr[3]) + labs(bptr[1] - bptr[5])) << 1) +
1473+ labs(bptr[6] - bptr[8]) + labs(bptr[3] - bptr[5]) +
1474+ labs(bptr[0] - bptr[2]);
1475+ sum = (sum * 6) / 13;
1476+ sums_dir[8] = sum;
1477+
1478+ best_sum = sums_dir[0];
1479+ for (i = 1; i < 9; i++)
1480+ if (sums_dir[i] < best_sum) best_sum = sums_dir[i];
1481+
1482+ best_dir = 0;
1483+ for (i = 0, n = 0; i < 9; i++)
1484+ {
1485+ if (sums_dir[i] == best_sum)
1486+ {
1487+ best_dir = i;
1488+ n++;
1489+ }
1490+ }
1491+
1492+ /* CHECK -- handle zig-zags */
1493+ if (sim_sum == 3)
1494+ {
1495+ if ((best_dir == 0 || best_dir == 1) &&
1496+ sim[0] && sim[1] && sim[4])
1497+ return 1; /* '- */
1498+ if ((best_dir == 0 || best_dir == 2) &&
1499+ sim[3] && sim[6] && sim[7])
1500+ return 2; /* -. */
1501+ if ((best_dir == 0 || best_dir == 3) &&
1502+ sim[0] && sim[3] && sim[6])
1503+ return 4; /* '| */
1504+ if ((best_dir == 0 || best_dir == 4) &&
1505+ sim[1] && sim[4] && sim[7])
1506+ return 5; /* |. */
1507+ }
1508+
1509+ if (n > 1 && best_sum == sums_dir[0]) return 3; /* \ */
1510+
1511+ /* best direction uncertain, return non-edge to avoid artifacts */
1512+ if (n > 1) return -1;
1513+
1514+ /* CHECK -- diagonal intersections */
1515+ if (best_dir == 0 &&
1516+ (sim[1] == sim[4] || sim[3] == sim[6]) &&
1517+ (sim[1] == sim[3] || sim[4] == sim[6]))
1518+ {
1519+ if ((pixels[1] == pixels[3] || pixels[5] == pixels[7]) ||
1520+ ((pixels[0] == pixels[4]) ^ (pixels[8] == pixels[4])))
1521+ {
1522+ if (pixels[2] == pixels[4])
1523+ return 16; /* \' */
1524+ if (pixels[6] == pixels[4])
1525+ return 17; /* .\ */
1526+ }
1527+
1528+ if (sim_sum == 3 && sim[0] && sim[7] &&
1529+ pixels[1] == pixels[3] && pixels[3] == pixels[5] &&
1530+ pixels[5] == pixels[7])
1531+ {
1532+ if (sim[2])
1533+ return 16; /* \' */
1534+ if (sim[5])
1535+ return 17; /* .\ */
1536+ }
1537+
1538+ if (sim_sum == 3 && sim[2] && sim[5])
1539+ {
1540+ if (sim[0])
1541+ return 18; /* '/ */
1542+ if (sim[7])
1543+ return 19; /* /. */
1544+ }
1545+ }
1546+
1547+ if (best_dir >= 5)
1548+ ok_arrow_flag = check_arrows(best_dir, pixels, sim, 0);
1549+
1550+ switch(best_dir)
1551+ {
1552+ case 1:
1553+ return 1; /* '- */
1554+ break;
1555+ case 2:
1556+ return 2; /* -. */
1557+ break;
1558+ case 3:
1559+ return 4; /* '| */
1560+ break;
1561+ case 4:
1562+ return 5; /* |. */
1563+ break;
1564+ case 5:
1565+ if (ok_arrow_flag)
1566+ return 12; /* < */
1567+ break;
1568+ case 6:
1569+ if (ok_arrow_flag)
1570+ return 13; /* > */
1571+ break;
1572+ case 7:
1573+ if (ok_arrow_flag)
1574+ return 14; /* ^ */
1575+ break;
1576+ case 8:
1577+ if (ok_arrow_flag)
1578+ return 15; /* V */
1579+ break;
1580+ case 0:
1581+ default:
1582+ return 3; /* \ */
1583+ break;
1584+ }
1585+
1586+ break;
1587+
1588+ case '/':
1589+
1590+ /* CHECK -- handle noisy half-diags */
1591+ if (sim_sum == 1)
1592+ {
1593+ if (pixels[1] == pixels[3] && pixels[3] == pixels[5] &&
1594+ pixels[5] == pixels[7])
1595+ {
1596+ if (pixels[0] != pixels[1] && pixels[8] != pixels[1])
1597+ {
1598+ sum = labs(bptr[0] - bptr[4]) +
1599+ labs(bptr[8] - bptr[4]);
1600+
1601+ if (sim[2] && sum < (labs(bptr[6] - bptr[4]) << 1))
1602+ {
1603+ if (bptr[4] > bptr[6])
1604+ {
1605+ if (bptr[0] > bptr[4] &&
1606+ bptr[8] > bptr[4])
1607+ return 16; /* \' */
1608+ }
1609+ else
1610+ {
1611+ if (bptr[0] < bptr[4] &&
1612+ bptr[8] < bptr[4])
1613+ return 16; /* \' */
1614+ }
1615+ }
1616+
1617+ if (sim[5] && sum < (labs(bptr[2] - bptr[4]) << 1))
1618+ {
1619+ if (bptr[4] > bptr[2])
1620+ {
1621+ if (bptr[0] > bptr[4] &&
1622+ bptr[8] > bptr[4])
1623+ {
1624+ if (pixels[6] == pixels[4])
1625+ return 17; /* .\ */
1626+ return 3; /* \ */
1627+ }
1628+ }
1629+ else
1630+ {
1631+ if (bptr[0] < bptr[4] &&
1632+ bptr[8] < bptr[4])
1633+ {
1634+ if (pixels[6] == pixels[4])
1635+ return 17; /* .\ */
1636+ return 3; /* \ */
1637+ }
1638+ }
1639+ }
1640+ }
1641+ }
1642+
1643+ if (sim[2] &&
1644+ labs(bptr[4] - bptr[2]) < ((int16)1<<(GREY_SHIFT-3)))
1645+ return 9; /* / */
1646+ if (sim[5] &&
1647+ labs(bptr[4] - bptr[6]) < ((int16)1<<(GREY_SHIFT-3)))
1648+ return 9; /* / */
1649+ }
1650+
1651+ diff_array[0] = labs(bptr[4] - bptr[0]);
1652+ diff_array[1] = labs(bptr[4] - bptr[5]);
1653+ diff_array[3] = labs(bptr[7] - bptr[8]);
1654+ diff_array[4] = labs(bptr[1] - bptr[2]);
1655+ diff_array[5] = labs(bptr[4] - bptr[3]);
1656+ diff_array[6] = labs(bptr[4] - bptr[8]);
1657+ diff_array[7] = labs(bptr[0] - bptr[1]);
1658+ diff_array[9] = labs(bptr[6] - bptr[7]);
1659+ diff_array[10] = labs(bptr[4] - bptr[7]);
1660+ diff_array[11] = labs(bptr[5] - bptr[8]);
1661+ diff_array[12] = labs(bptr[3] - bptr[6]);
1662+ diff_array[13] = labs(bptr[4] - bptr[1]);
1663+ diff_array[14] = labs(bptr[0] - bptr[3]);
1664+ diff_array[15] = labs(bptr[2] - bptr[5]);
1665+ diff_array[16] = labs(bptr[4] - bptr[2]);
1666+ diff_array[17] = labs(bptr[1] - bptr[3]);
1667+ diff_array[18] = labs(bptr[4] - bptr[6]);
1668+ diff_array[19] = labs(bptr[5] - bptr[7]);
1669+ diff_array[20] = labs(bptr[0] - bptr[2]);
1670+ diff_array[21] = labs(bptr[6] - bptr[8]);
1671+ diff_array[22] = labs(bptr[0] - bptr[6]);
1672+ diff_array[23] = labs(bptr[2] - bptr[8]);
1673+
1674+ /* |' */
1675+ sums_dir[1] = diff_array[10] + diff_array[12] + diff_array[16] +
1676+ diff_array[17] + (diff_array[11] << 1);
1677+ /* |' alt */
1678+ sum = diff_array[16] + diff_array[10] + diff_array[7] +
1679+ diff_array[14] + diff_array[12] + diff_array[23];
1680+ if (sum < sums_dir[1])
1681+ sums_dir[1] = sum;
1682+
1683+ /* .| */
1684+ sums_dir[2] = diff_array[13] + diff_array[15] + diff_array[18] +
1685+ diff_array[19] + (diff_array[14] << 1);
1686+ /* .| alt */
1687+ sum = diff_array[18] + diff_array[13] + diff_array[3] +
1688+ diff_array[11] + diff_array[15] + diff_array[22];
1689+ if (sum < sums_dir[2])
1690+ sums_dir[2] = sum;
1691+
1692+ /* -' */
1693+ sums_dir[3] = diff_array[5] + diff_array[9] + diff_array[16] +
1694+ diff_array[19] + (diff_array[7] << 1);
1695+ /* -' alt */
1696+ sum = diff_array[16] + diff_array[5] + diff_array[11] +
1697+ diff_array[3] + diff_array[9] + diff_array[20];
1698+ if (sum < sums_dir[3])
1699+ sums_dir[3] = sum;
1700+
1701+ /* .- */
1702+ sums_dir[4] = diff_array[1] + diff_array[4] + diff_array[17] +
1703+ diff_array[18] + (diff_array[3] << 1);
1704+ /* .- alt */
1705+ sum = diff_array[18] + diff_array[1] + diff_array[14] +
1706+ diff_array[7] + diff_array[4] + diff_array[21];
1707+ if (sum < sums_dir[4])
1708+ sums_dir[4] = sum;
1709+
1710+ /* / 135 */
1711+ sums_dir[0] = diff_array[16] + diff_array[18] +
1712+ (diff_array[17] << 1) + (diff_array[19] << 1);
1713+
1714+ /* << top */
1715+ sum = labs(bptr[3] - bptr[1]) + labs(bptr[3] - bptr[7]) +
1716+ ((labs(bptr[4] - bptr[2]) + labs(bptr[4] - bptr[8]) +
1717+ labs(bptr[5] - bptr[1]) + labs(bptr[5] - bptr[7])) << 1) +
1718+ labs(bptr[0] - bptr[6]) + labs(bptr[1] - bptr[7]) +
1719+ labs(bptr[2] - bptr[8]);
1720+ sum = (sum * 6) / 13;
1721+ sums_dir[5] = sum;
1722+
1723+ /* >> top */
1724+ sum = labs(bptr[5] - bptr[1]) + labs(bptr[5] - bptr[7]) +
1725+ ((labs(bptr[4] - bptr[0]) + labs(bptr[4] - bptr[6]) +
1726+ labs(bptr[3] - bptr[1]) + labs(bptr[3] - bptr[7])) << 1) +
1727+ labs(bptr[2] - bptr[8]) + labs(bptr[1] - bptr[7]) +
1728+ labs(bptr[0] - bptr[6]);
1729+ sum = (sum * 6) / 13;
1730+ sums_dir[6] = sum;
1731+
1732+ /* ^ top */
1733+ sum = labs(bptr[1] - bptr[3]) + labs(bptr[1] - bptr[5]) +
1734+ ((labs(bptr[4] - bptr[6]) + labs(bptr[4] - bptr[8]) +
1735+ labs(bptr[7] - bptr[3]) + labs(bptr[7] - bptr[5])) << 1) +
1736+ labs(bptr[0] - bptr[2]) + labs(bptr[3] - bptr[5]) +
1737+ labs(bptr[6] - bptr[8]);
1738+ sum = (sum * 6) / 13;
1739+ sums_dir[7] = sum;
1740+
1741+ /* v top */
1742+ sum = labs(bptr[7] - bptr[3]) + labs(bptr[7] - bptr[5]) +
1743+ ((labs(bptr[4] - bptr[0]) + labs(bptr[4] - bptr[2]) +
1744+ labs(bptr[1] - bptr[3]) + labs(bptr[1] - bptr[5])) << 1) +
1745+ labs(bptr[6] - bptr[8]) + labs(bptr[3] - bptr[5]) +
1746+ labs(bptr[0] - bptr[2]);
1747+ sum = (sum * 6) / 13;
1748+ sums_dir[8] = sum;
1749+
1750+ best_sum = sums_dir[0];
1751+ for (i = 1; i < 9; i++)
1752+ if (sums_dir[i] < best_sum) best_sum = sums_dir[i];
1753+
1754+ best_dir = 0;
1755+ for (i = 0, n = 0; i < 9; i++)
1756+ {
1757+ if (sums_dir[i] == best_sum)
1758+ {
1759+ best_dir = i;
1760+ n++;
1761+ }
1762+ }
1763+
1764+ /* CHECK -- handle zig-zags */
1765+ if (sim_sum == 3)
1766+ {
1767+ if ((best_dir == 0 || best_dir == 1) &&
1768+ sim[2] && sim[4] && sim[6])
1769+ return 7; /* |' */
1770+ if ((best_dir == 0 || best_dir == 2) &&
1771+ sim[1] && sim[3] && sim[5])
1772+ return 8; /* .| */
1773+ if ((best_dir == 0 || best_dir == 3) &&
1774+ sim[1] && sim[2] && sim[3])
1775+ return 10; /* -' */
1776+ if ((best_dir == 0 || best_dir == 4) &&
1777+ sim[4] && sim[5] && sim[6])
1778+ return 11; /* .- */
1779+ }
1780+
1781+ if (n > 1 && best_sum == sums_dir[0]) return 9; /* / */
1782+
1783+ /* best direction uncertain, return non-edge to avoid artifacts */
1784+ if (n > 1) return -1;
1785+
1786+ /* CHECK -- diagonal intersections */
1787+ if (best_dir == 0 &&
1788+ (sim[1] == sim[3] || sim[4] == sim[6]) &&
1789+ (sim[1] == sim[4] || sim[3] == sim[6]))
1790+ {
1791+ if ((pixels[1] == pixels[5] || pixels[3] == pixels[7]) ||
1792+ ((pixels[2] == pixels[4]) ^ (pixels[6] == pixels[4])))
1793+ {
1794+ if (pixels[0] == pixels[4])
1795+ return 18; /* '/ */
1796+ if (pixels[8] == pixels[4])
1797+ return 19; /* /. */
1798+ }
1799+
1800+ if (sim_sum == 3 && sim[2] && sim[5] &&
1801+ pixels[1] == pixels[3] && pixels[3] == pixels[5] &&
1802+ pixels[5] == pixels[7])
1803+ {
1804+ if (sim[0])
1805+ return 18; /* '/ */
1806+ if (sim[7])
1807+ return 19; /* /. */
1808+ }
1809+
1810+ if (sim_sum == 3 && sim[0] && sim[7])
1811+ {
1812+ if (sim[2])
1813+ return 16; /* \' */
1814+ if (sim[5])
1815+ return 17; /* .\ */
1816+ }
1817+ }
1818+
1819+ if (best_dir >= 5)
1820+ ok_arrow_flag = check_arrows(best_dir, pixels, sim, 0);
1821+
1822+ switch(best_dir)
1823+ {
1824+ case 1:
1825+ return 7; /* |' */
1826+ break;
1827+ case 2:
1828+ return 8; /* .| */
1829+ break;
1830+ case 3:
1831+ return 10; /* -' */
1832+ break;
1833+ case 4:
1834+ return 11; /* .- */
1835+ break;
1836+ case 5:
1837+ if (ok_arrow_flag)
1838+ return 12; /* < */
1839+ break;
1840+ case 6:
1841+ if (ok_arrow_flag)
1842+ return 13; /* > */
1843+ break;
1844+ case 7:
1845+ if (ok_arrow_flag)
1846+ return 14; /* ^ */
1847+ break;
1848+ case 8:
1849+ if (ok_arrow_flag)
1850+ return 15; /* V */
1851+ break;
1852+ break;
1853+ case 0:
1854+ default:
1855+ return 9; /* / */
1856+ break;
1857+ }
1858+
1859+ break;
1860+
1861+ case '*':
1862+ return 127;
1863+ break;
1864+
1865+ case '0':
1866+ default:
1867+ return -1;
1868+ break;
1869+ }
1870+
1871+ return -1;
1872+}
1873+
1874+
1875+
1876+/* "Chess Knight" patterns can be mis-detected, fix easy cases. */
1877+int fix_knights(int sub_type, uint16 *pixels, int8 *sim)
1878+{
1879+ uint16 center = pixels[4];
1880+ int dir = sub_type;
1881+ int n = 0;
1882+ int flags[12] = {0};
1883+ int ok_orig_flag = 0;
1884+
1885+ /*
1886+ * - '- -. \ '| |. | |' .| / -' .-
1887+ *
1888+ * 0 1 2 3 4 5 6 7 8 9 10 11
1889+ *
1890+ */
1891+
1892+ /* check to see if original knight is ok */
1893+ switch(sub_type)
1894+ {
1895+ case 1: /* '- */
1896+ if (sim[0] && sim[4] &&
1897+ !(sim_sum == 3 && sim[5] &&
1898+ pixels[0] == pixels[4] && pixels[6] == pixels[4]))
1899+ ok_orig_flag = 1;
1900+ break;
1901+
1902+ case 2: /* -. */
1903+ if (sim[3] && sim[7] &&
1904+ !(sim_sum == 3 && sim[2] &&
1905+ pixels[2] == pixels[4] && pixels[8] == pixels[4]))
1906+ ok_orig_flag = 1;
1907+ break;
1908+
1909+ case 4: /* '| */
1910+ if (sim[0] && sim[6] &&
1911+ !(sim_sum == 3 && sim[2] &&
1912+ pixels[0] == pixels[4] && pixels[2] == pixels[4]))
1913+ ok_orig_flag = 1;
1914+ break;
1915+
1916+ case 5: /* |. */
1917+ if (sim[1] && sim[7] &&
1918+ !(sim_sum == 3 && sim[5] &&
1919+ pixels[6] == pixels[4] && pixels[8] == pixels[4]))
1920+ ok_orig_flag = 1;
1921+ break;
1922+
1923+ case 7: /* |' */
1924+ if (sim[2] && sim[6] &&
1925+ !(sim_sum == 3 && sim[0] &&
1926+ pixels[0] == pixels[4] && pixels[2] == pixels[4]))
1927+ ok_orig_flag = 1;
1928+ break;
1929+
1930+ case 8: /* .| */
1931+ if (sim[1] && sim[5] &&
1932+ !(sim_sum == 3 && sim[7] &&
1933+ pixels[6] == pixels[4] && pixels[8] == pixels[4]))
1934+ ok_orig_flag = 1;
1935+ break;
1936+
1937+ case 10: /* -' */
1938+ if (sim[2] && sim[3] &&
1939+ !(sim_sum == 3 && sim[7] &&
1940+ pixels[2] == pixels[4] && pixels[8] == pixels[4]))
1941+ ok_orig_flag = 1;
1942+ break;
1943+
1944+ case 11: /* .- */
1945+ if (sim[4] && sim[5] &&
1946+ !(sim_sum == 3 && sim[0] &&
1947+ pixels[0] == pixels[4] && pixels[6] == pixels[4]))
1948+ ok_orig_flag = 1;
1949+ break;
1950+
1951+ default: /* not a knight */
1952+ return sub_type;
1953+ break;
1954+ }
1955+
1956+ /* look for "better" knights */
1957+ if (center == pixels[0] && center == pixels[5]) /* '- */
1958+ {
1959+ dir = 1;
1960+ flags[dir] = 1;
1961+ n++;
1962+ }
1963+ if (center == pixels[3] && center == pixels[8]) /* -. */
1964+ {
1965+ dir = 2;
1966+ flags[dir] = 1;
1967+ n++;
1968+ }
1969+ if (center == pixels[0] && center == pixels[7]) /* '| */
1970+ {
1971+ dir = 4;
1972+ flags[dir] = 1;
1973+ n++;
1974+ }
1975+ if (center == pixels[1] && center == pixels[8]) /* |. */
1976+ {
1977+ dir = 5;
1978+ flags[dir] = 1;
1979+ n++;
1980+ }
1981+ if (center == pixels[2] && center == pixels[7]) /* |' */
1982+ {
1983+ dir = 7;
1984+ flags[dir] = 1;
1985+ n++;
1986+ }
1987+ if (center == pixels[1] && center == pixels[6]) /* .| */
1988+ {
1989+ dir = 8;
1990+ flags[dir] = 1;
1991+ n++;
1992+ }
1993+ if (center == pixels[3] && center == pixels[2]) /* -' */
1994+ {
1995+ dir = 10;
1996+ flags[dir] = 1;
1997+ n++;
1998+ }
1999+ if (center == pixels[6] && center == pixels[5]) /* .- */
2000+ {
2001+ dir = 11;
2002+ flags[dir] = 1;
2003+ n++;
2004+ }
2005+
2006+ if (n == 0)
2007+ {
2008+ if (ok_orig_flag) return sub_type;
2009+ return -1;
2010+ }
2011+ if (n == 1) return dir;
2012+ if (n == 2)
2013+ {
2014+ /* slanted W patterns */
2015+ if (flags[1] && flags[5]) return 3; /* \ */
2016+ if (flags[2] && flags[4]) return 3; /* \ */
2017+ if (flags[7] && flags[11]) return 9; /* / */
2018+ if (flags[8] && flags[10]) return 9; /* / */
2019+ }
2020+ if (flags[sub_type] && ok_orig_flag) return sub_type;
2021+
2022+ return -1;
2023+}
2024+
2025+
2026+
2027+/* From ScummVM HQ2x/HQ3x scalers (Maxim Stepin and Max Horn) */
2028+#define highBits 0xF7DEF7DE
2029+#define lowBits 0x08210821
2030+#define qhighBits 0xE79CE79C
2031+#define qlowBits 0x18631863
2032+#define redblueMask 0xF81F
2033+#define greenMask 0x07E0
2034+
2035+/* From ScummVM HQ2x/HQ3x scalers (Maxim Stepin and Max Horn) */
2036+/**
2037+ * Interpolate two 16 bit pixel pairs at once with equal weights 1.
2038+ * In particular, A and B can contain two pixels/each in the upper
2039+ * and lower halves.
2040+ */
2041+uint32 INTERPOLATE(uint32 A, uint32 B)
2042+{
2043+ return (((A & highBits) >> 1) + ((B & highBits) >> 1) + (A & B & lowBits));
2044+}
2045+
2046+/* From ScummVM HQ2x/HQ3x scalers (Maxim Stepin and Max Horn) */
2047+/**
2048+ * Interpolate four 16 bit pixel pairs at once with equal weights 1.
2049+ * In particular, A and B can contain two pixels/each in the upper
2050+ * and lower halves.
2051+ */
2052+uint32 Q_INTERPOLATE(uint32 A, uint32 B, uint32 C, uint32 D)
2053+{
2054+ uint32 x = ((A & qhighBits) >> 2) + ((B & qhighBits) >> 2) + ((C & qhighBits) >> 2) + ((D & qhighBits) >> 2);
2055+ uint32 y = ((A & qlowBits) + (B & qlowBits) + (C & qlowBits) + (D & qlowBits)) >> 2;
2056+
2057+ y &= qlowBits;
2058+ return x + y;
2059+}
2060+
2061+
2062+
2063+/* Average three pixels together */
2064+uint16 average_three_pixels(uint16 pixel1, uint16 pixel2, uint16 pixel3)
2065+{
2066+ uint32 rsum;
2067+ uint16 gsum, bsum;
2068+
2069+ rsum = (pixel1 & 0xF800);
2070+ rsum += (pixel2 & 0xF800);
2071+ rsum += (pixel3 & 0xF800);
2072+ rsum = div3[rsum >> 11];
2073+
2074+ gsum = (pixel1 & 0x07E0);
2075+ gsum += (pixel2 & 0x07E0);
2076+ gsum += (pixel3 & 0x07E0);
2077+ gsum = div3[gsum >> 5];
2078+
2079+ bsum = (pixel1 & 0x001F);
2080+ bsum += (pixel2 & 0x001F);
2081+ bsum += (pixel3 & 0x001F);
2082+ bsum = div3[bsum];
2083+
2084+ return ((rsum << 11) | (gsum << 5) | bsum);
2085+}
2086+
2087+
2088+
2089+/* Interpolate 1/3rd of the way between two pixels */
2090+uint16 average_one_third(uint16 pixel1, uint16 pixel2)
2091+{
2092+ uint32 rsum;
2093+ uint16 gsum, bsum;
2094+
2095+ rsum = (pixel1 & 0xF800) << 1;
2096+ rsum += (pixel2 & 0xF800);
2097+ rsum = div3[rsum >> 11];
2098+
2099+ gsum = (pixel1 & 0x07E0) << 1;
2100+ gsum += (pixel2 & 0x07E0);
2101+ gsum = div3[gsum >> 5];
2102+
2103+ bsum = (pixel1 & 0x001F) << 1;
2104+ bsum += (pixel2 & 0x001F);
2105+ bsum = div3[bsum];
2106+
2107+ return ((rsum << 11) | (gsum << 5) | bsum);
2108+}
2109+
2110+
2111+
2112+/* Fill pixel grid without interpolation, using the detected edge */
2113+void anti_alias_grid_clean_3x(uint8 *dptr, int dstPitch,
2114+ uint16 *pixels, int sub_type, int16 *bptr)
2115+{
2116+ uint16 *dptr2;
2117+ int16 tmp_grey;
2118+ uint16 center = pixels[4];
2119+ int32 diff1, diff2, diff3;
2120+ uint16 tmp[9];
2121+ uint16 *ptmp;
2122+ int i;
2123+
2124+ switch (sub_type)
2125+ {
2126+ case 1: /* '- */
2127+ for (i = 0; i < 9; i++)
2128+ tmp[i] = center;
2129+
2130+ tmp[6] = average_three_pixels(pixels[3], pixels[7], center);
2131+ tmp_grey = chosen_greyscale[tmp[6]];
2132+#if PARANOID_KNIGHTS
2133+ diff1 = labs(bptr[4] - bptr[3]);
2134+ diff2 = labs(bptr[4] - bptr[7]);
2135+ diff3 = labs(bptr[4] - tmp_grey);
2136+ if (diff1 < diff3 || diff2 < diff3)
2137+ tmp[6] = center;
2138+ else /* choose nearest pixel */
2139+#endif
2140+ {
2141+ diff1 = calc_pixel_diff_nosqrt(tmp[6], pixels[3]);
2142+ diff2 = calc_pixel_diff_nosqrt(tmp[6], pixels[7]);
2143+ diff3 = calc_pixel_diff_nosqrt(tmp[6], pixels[4]);
2144+ if (diff1 <= diff2 && diff1 <= diff3)
2145+ tmp[6] = pixels[3];
2146+ else if (diff2 <= diff1 && diff2 <= diff3)
2147+ tmp[6] = pixels[7];
2148+ else
2149+ tmp[6] = pixels[4];
2150+
2151+ tmp_grey = chosen_greyscale[tmp[6]];
2152+ diff1 = labs(bptr[4] - tmp_grey);
2153+ diff2 = labs(bptr[4] - bptr[8]);
2154+ if (diff1 <= diff2)
2155+ tmp[7] = tmp[6];
2156+ }
2157+
2158+ break;
2159+
2160+ case 2: /* -. */
2161+ for (i = 0; i < 9; i++)
2162+ tmp[i] = center;
2163+
2164+ tmp[2] = average_three_pixels(pixels[1], pixels[5], center);
2165+ tmp_grey = chosen_greyscale[tmp[2]];
2166+#if PARANOID_KNIGHTS
2167+ diff1 = labs(bptr[4] - bptr[5]);
2168+ diff2 = labs(bptr[4] - bptr[1]);
2169+ diff3 = labs(bptr[4] - tmp_grey);
2170+ if (diff1 < diff3 || diff2 < diff3)
2171+ tmp[2] = center;
2172+ else /* choose nearest pixel */
2173+#endif
2174+ {
2175+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[1]);
2176+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[5]);
2177+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2178+ if (diff1 <= diff2 && diff1 <= diff3)
2179+ tmp[2] = pixels[1];
2180+ else if (diff2 <= diff1 && diff2 <= diff3)
2181+ tmp[2] = pixels[5];
2182+ else
2183+ tmp[2] = pixels[4];
2184+
2185+ tmp_grey = chosen_greyscale[tmp[2]];
2186+ diff1 = labs(bptr[4] - tmp_grey);
2187+ diff2 = labs(bptr[4] - bptr[0]);
2188+ if (diff1 <= diff2)
2189+ tmp[1] = tmp[2];
2190+ }
2191+
2192+ break;
2193+
2194+ case 3: /* \ */
2195+ case 16: /* \' */
2196+ case 17: /* .\ */
2197+ for (i = 0; i < 9; i++)
2198+ tmp[i] = center;
2199+
2200+ if (sub_type != 16)
2201+ {
2202+ tmp[2] = average_three_pixels(pixels[1], pixels[5], center);
2203+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[1]);
2204+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[5]);
2205+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2206+ if (diff1 <= diff2 && diff1 <= diff3)
2207+ tmp[2] = pixels[1];
2208+ else if (diff2 <= diff1 && diff2 <= diff3)
2209+ tmp[2] = pixels[5];
2210+ else
2211+ tmp[2] = pixels[4];
2212+ }
2213+
2214+ if (sub_type != 17)
2215+ {
2216+ tmp[6] = average_three_pixels(pixels[3], pixels[7], center);
2217+ diff1 = calc_pixel_diff_nosqrt(tmp[6], pixels[3]);
2218+ diff2 = calc_pixel_diff_nosqrt(tmp[6], pixels[7]);
2219+ diff3 = calc_pixel_diff_nosqrt(tmp[6], pixels[4]);
2220+ if (diff1 <= diff2 && diff1 <= diff3)
2221+ tmp[6] = pixels[3];
2222+ else if (diff2 <= diff1 && diff2 <= diff3)
2223+ tmp[6] = pixels[7];
2224+ else
2225+ tmp[6] = pixels[4];
2226+ }
2227+
2228+ break;
2229+
2230+ case 4: /* '| */
2231+ for (i = 0; i < 9; i++)
2232+ tmp[i] = center;
2233+
2234+ tmp[2] = average_three_pixels(pixels[1], pixels[5], center);
2235+ tmp_grey = chosen_greyscale[tmp[2]];
2236+#if PARANOID_KNIGHTS
2237+ diff1 = labs(bptr[4] - bptr[1]);
2238+ diff2 = labs(bptr[4] - bptr[5]);
2239+ diff3 = labs(bptr[4] - tmp_grey);
2240+ if (diff1 < diff3 || diff2 < diff3)
2241+ tmp[2] = center;
2242+ else /* choose nearest pixel */
2243+#endif
2244+ {
2245+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[1]);
2246+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[5]);
2247+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2248+ if (diff1 <= diff2 && diff1 <= diff3)
2249+ tmp[2] = pixels[1];
2250+ else if (diff2 <= diff1 && diff2 <= diff3)
2251+ tmp[2] = pixels[5];
2252+ else
2253+ tmp[2] = pixels[4];
2254+
2255+ tmp_grey = chosen_greyscale[tmp[2]];
2256+ diff1 = labs(bptr[4] - tmp_grey);
2257+ diff2 = labs(bptr[4] - bptr[8]);
2258+ if (diff1 <= diff2)
2259+ tmp[5] = tmp[2];
2260+ }
2261+
2262+ break;
2263+
2264+ case 5: /* |. */
2265+ for (i = 0; i < 9; i++)
2266+ tmp[i] = center;
2267+
2268+ tmp[6] = average_three_pixels(pixels[3], pixels[7], center);
2269+ tmp_grey = chosen_greyscale[tmp[6]];
2270+#if PARANOID_KNIGHTS
2271+ diff1 = labs(bptr[4] - bptr[7]);
2272+ diff2 = labs(bptr[4] - bptr[3]);
2273+ diff3 = labs(bptr[4] - tmp_grey);
2274+ if (diff1 < diff3 || diff2 < diff3)
2275+ tmp[6] = center;
2276+ else /* choose nearest pixel */
2277+#endif
2278+ {
2279+ diff1 = calc_pixel_diff_nosqrt(tmp[6], pixels[3]);
2280+ diff2 = calc_pixel_diff_nosqrt(tmp[6], pixels[7]);
2281+ diff3 = calc_pixel_diff_nosqrt(tmp[6], pixels[4]);
2282+ if (diff1 <= diff2 && diff1 <= diff3)
2283+ tmp[6] = pixels[3];
2284+ else if (diff2 <= diff1 && diff2 <= diff3)
2285+ tmp[6] = pixels[7];
2286+ else
2287+ tmp[6] = pixels[4];
2288+
2289+ tmp_grey = chosen_greyscale[tmp[6]];
2290+ diff1 = labs(bptr[4] - tmp_grey);
2291+ diff2 = labs(bptr[4] - bptr[0]);
2292+ if (diff1 <= diff2)
2293+ tmp[3] = tmp[6];
2294+ }
2295+
2296+ break;
2297+
2298+ case 7: /* |' */
2299+ for (i = 0; i < 9; i++)
2300+ tmp[i] = center;
2301+
2302+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
2303+ tmp_grey = chosen_greyscale[tmp[0]];
2304+#if PARANOID_KNIGHTS
2305+ diff1 = labs(bptr[4] - bptr[1]);
2306+ diff2 = labs(bptr[4] - bptr[3]);
2307+ diff3 = labs(bptr[4] - tmp_grey);
2308+ if (diff1 < diff3 || diff2 < diff3)
2309+ tmp[0] = center;
2310+ else /* choose nearest pixel */
2311+#endif
2312+ {
2313+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
2314+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
2315+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
2316+ if (diff1 <= diff2 && diff1 <= diff3)
2317+ tmp[0] = pixels[1];
2318+ else if (diff2 <= diff1 && diff2 <= diff3)
2319+ tmp[0] = pixels[3];
2320+ else
2321+ tmp[0] = pixels[4];
2322+
2323+ tmp_grey = chosen_greyscale[tmp[0]];
2324+ diff1 = labs(bptr[4] - tmp_grey);
2325+ diff2 = labs(bptr[4] - bptr[6]);
2326+ if (diff1 <= diff2)
2327+ tmp[3] = tmp[0];
2328+ }
2329+
2330+ break;
2331+
2332+ case 8: /* .| */
2333+ for (i = 0; i < 9; i++)
2334+ tmp[i] = center;
2335+
2336+ tmp[8] = average_three_pixels(pixels[5], pixels[7], center);
2337+ tmp_grey = chosen_greyscale[tmp[8]];
2338+#if PARANOID_KNIGHTS
2339+ diff1 = labs(bptr[4] - bptr[7]);
2340+ diff2 = labs(bptr[4] - bptr[5]);
2341+ diff3 = labs(bptr[4] - tmp_grey);
2342+ if (diff1 < diff3 || diff2 < diff3)
2343+ tmp[8] = center;
2344+ else /* choose nearest pixel */
2345+#endif
2346+ {
2347+ diff1 = calc_pixel_diff_nosqrt(tmp[8], pixels[5]);
2348+ diff2 = calc_pixel_diff_nosqrt(tmp[8], pixels[7]);
2349+ diff3 = calc_pixel_diff_nosqrt(tmp[8], pixels[4]);
2350+ if (diff1 <= diff2 && diff1 <= diff3)
2351+ tmp[8] = pixels[5];
2352+ else if (diff2 <= diff1 && diff2 <= diff3)
2353+ tmp[8] = pixels[7];
2354+ else
2355+ tmp[8] = pixels[4];
2356+
2357+ tmp_grey = chosen_greyscale[tmp[8]];
2358+ diff1 = labs(bptr[4] - tmp_grey);
2359+ diff2 = labs(bptr[4] - bptr[2]);
2360+ if (diff1 <= diff2)
2361+ tmp[5] = tmp[8];
2362+ }
2363+
2364+ break;
2365+
2366+ case 9: /* / */
2367+ case 18: /* '/ */
2368+ case 19: /* /. */
2369+ for (i = 0; i < 9; i++)
2370+ tmp[i] = center;
2371+
2372+ if (sub_type != 18)
2373+ {
2374+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
2375+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
2376+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
2377+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
2378+ if (diff1 <= diff2 && diff1 <= diff3)
2379+ tmp[0] = pixels[1];
2380+ else if (diff2 <= diff1 && diff2 <= diff3)
2381+ tmp[0] = pixels[3];
2382+ else
2383+ tmp[0] = pixels[4];
2384+ }
2385+
2386+ if (sub_type != 19)
2387+ {
2388+ tmp[8] = average_three_pixels(pixels[5], pixels[7], center);
2389+ diff1 = calc_pixel_diff_nosqrt(tmp[8], pixels[5]);
2390+ diff2 = calc_pixel_diff_nosqrt(tmp[8], pixels[7]);
2391+ diff3 = calc_pixel_diff_nosqrt(tmp[8], pixels[4]);
2392+ if (diff1 <= diff2 && diff1 <= diff3)
2393+ tmp[8] = pixels[5];
2394+ else if (diff2 <= diff1 && diff2 <= diff3)
2395+ tmp[8] = pixels[7];
2396+ else
2397+ tmp[8] = pixels[4];
2398+ }
2399+
2400+ break;
2401+
2402+ case 10: /* -' */
2403+ for (i = 0; i < 9; i++)
2404+ tmp[i] = center;
2405+
2406+ tmp[8] = average_three_pixels(pixels[5], pixels[7], center);
2407+ tmp_grey = chosen_greyscale[tmp[8]];
2408+#if PARANOID_KNIGHTS
2409+ diff1 = labs(bptr[4] - bptr[5]);
2410+ diff2 = labs(bptr[4] - bptr[7]);
2411+ diff3 = labs(bptr[4] - tmp_grey);
2412+ if (diff1 < diff3 || diff2 < diff3)
2413+ tmp[8] = center;
2414+ else /* choose nearest pixel */
2415+#endif
2416+ {
2417+ diff1 = calc_pixel_diff_nosqrt(tmp[8], pixels[5]);
2418+ diff2 = calc_pixel_diff_nosqrt(tmp[8], pixels[7]);
2419+ diff3 = calc_pixel_diff_nosqrt(tmp[8], pixels[4]);
2420+ if (diff1 <= diff2 && diff1 <= diff3)
2421+ tmp[8] = pixels[5];
2422+ else if (diff2 <= diff1 && diff2 <= diff3)
2423+ tmp[8] = pixels[7];
2424+ else
2425+ tmp[8] = pixels[4];
2426+
2427+ tmp_grey = chosen_greyscale[tmp[8]];
2428+ diff1 = labs(bptr[4] - tmp_grey);
2429+ diff2 = labs(bptr[4] - bptr[6]);
2430+ if (diff1 <= diff2)
2431+ tmp[7] = tmp[8];
2432+ }
2433+
2434+ break;
2435+
2436+ case 11: /* .- */
2437+ for (i = 0; i < 9; i++)
2438+ tmp[i] = center;
2439+
2440+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
2441+ tmp_grey = chosen_greyscale[tmp[0]];
2442+#if PARANOID_KNIGHTS
2443+ diff1 = labs(bptr[4] - bptr[3]);
2444+ diff2 = labs(bptr[4] - bptr[1]);
2445+ diff3 = labs(bptr[4] - tmp_grey);
2446+ if (diff1 < diff3 || diff2 < diff3)
2447+ tmp[0] = center;
2448+ else /* choose nearest pixel */
2449+#endif
2450+ {
2451+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
2452+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
2453+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
2454+ if (diff1 <= diff2 && diff1 <= diff3)
2455+ tmp[0] = pixels[1];
2456+ else if (diff2 <= diff1 && diff2 <= diff3)
2457+ tmp[0] = pixels[3];
2458+ else
2459+ tmp[0] = pixels[4];
2460+
2461+ tmp_grey = chosen_greyscale[tmp[0]];
2462+ diff1 = labs(bptr[4] - tmp_grey);
2463+ diff2 = labs(bptr[4] - bptr[2]);
2464+ if (diff1 <= diff2)
2465+ tmp[1] = tmp[0];
2466+ }
2467+
2468+ break;
2469+
2470+ case 12: /* < */
2471+ for (i = 0; i < 9; i++)
2472+ tmp[i] = center;
2473+
2474+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
2475+ tmp_grey = chosen_greyscale[tmp[0]];
2476+#if PARANOID_ARROWS
2477+ diff1 = labs(bptr[4] - bptr[1]);
2478+ diff2 = labs(bptr[4] - bptr[3]);
2479+ diff3 = labs(bptr[4] - tmp_grey);
2480+ if (diff1 < diff3 || diff2 < diff3)
2481+ tmp[0] = center;
2482+ else /* choose nearest pixel */
2483+#endif
2484+ {
2485+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
2486+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
2487+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
2488+ if (diff1 <= diff2 && diff1 <= diff3)
2489+ tmp[0] = pixels[1];
2490+ else if (diff2 <= diff1 && diff2 <= diff3)
2491+ tmp[0] = pixels[3];
2492+ else
2493+ tmp[0] = pixels[4];
2494+ }
2495+
2496+ tmp[6] = average_three_pixels(pixels[3], pixels[7], center);
2497+ tmp_grey = chosen_greyscale[tmp[6]];
2498+#if PARANOID_ARROWS
2499+ diff1 = labs(bptr[4] - bptr[3]);
2500+ diff2 = labs(bptr[4] - bptr[7]);
2501+ diff3 = labs(bptr[4] - tmp_grey);
2502+ if (diff1 < diff3 || diff2 < diff3)
2503+ tmp[6] = center;
2504+ else /* choose nearest pixel */
2505+#endif
2506+ {
2507+ diff1 = calc_pixel_diff_nosqrt(tmp[6], pixels[3]);
2508+ diff2 = calc_pixel_diff_nosqrt(tmp[6], pixels[7]);
2509+ diff3 = calc_pixel_diff_nosqrt(tmp[6], pixels[4]);
2510+ if (diff1 <= diff2 && diff1 <= diff3)
2511+ tmp[6] = pixels[3];
2512+ else if (diff2 <= diff1 && diff2 <= diff3)
2513+ tmp[6] = pixels[7];
2514+ else
2515+ tmp[6] = pixels[4];
2516+ }
2517+
2518+ break;
2519+
2520+ case 13: /* > */
2521+ for (i = 0; i < 9; i++)
2522+ tmp[i] = center;
2523+
2524+ tmp[2] = average_three_pixels(pixels[1], pixels[5], center);
2525+ tmp_grey = chosen_greyscale[tmp[2]];
2526+#if PARANOID_ARROWS
2527+ diff1 = labs(bptr[4] - bptr[5]);
2528+ diff2 = labs(bptr[4] - bptr[1]);
2529+ diff3 = labs(bptr[4] - tmp_grey);
2530+ if (diff1 < diff3 || diff2 < diff3)
2531+ tmp[2] = center;
2532+ else /* choose nearest pixel */
2533+#endif
2534+ {
2535+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[1]);
2536+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[5]);
2537+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2538+ if (diff1 <= diff2 && diff1 <= diff3)
2539+ tmp[2] = pixels[1];
2540+ else if (diff2 <= diff1 && diff2 <= diff3)
2541+ tmp[2] = pixels[5];
2542+ else
2543+ tmp[2] = pixels[4];
2544+ }
2545+
2546+ tmp[8] = average_three_pixels(pixels[5], pixels[7], center);
2547+ tmp_grey = chosen_greyscale[tmp[8]];
2548+#if PARANOID_ARROWS
2549+ diff1 = labs(bptr[4] - bptr[7]);
2550+ diff2 = labs(bptr[4] - bptr[5]);
2551+ diff3 = labs(bptr[4] - tmp_grey);
2552+ if (diff1 < diff3 || diff2 < diff3)
2553+ tmp[8] = center;
2554+ else /* choose nearest pixel */
2555+#endif
2556+ {
2557+ diff1 = calc_pixel_diff_nosqrt(tmp[8], pixels[5]);
2558+ diff2 = calc_pixel_diff_nosqrt(tmp[8], pixels[7]);
2559+ diff3 = calc_pixel_diff_nosqrt(tmp[8], pixels[4]);
2560+ if (diff1 <= diff2 && diff1 <= diff3)
2561+ tmp[8] = pixels[5];
2562+ else if (diff2 <= diff1 && diff2 <= diff3)
2563+ tmp[8] = pixels[7];
2564+ else
2565+ tmp[8] = pixels[4];
2566+ }
2567+
2568+ break;
2569+
2570+ case 14: /* ^ */
2571+ for (i = 0; i < 9; i++)
2572+ tmp[i] = center;
2573+
2574+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
2575+ tmp_grey = chosen_greyscale[tmp[0]];
2576+#if PARANOID_ARROWS
2577+ diff1 = labs(bptr[4] - bptr[1]);
2578+ diff2 = labs(bptr[4] - bptr[3]);
2579+ diff3 = labs(bptr[4] - tmp_grey);
2580+ if (diff1 < diff3 || diff2 < diff3)
2581+ tmp[0] = center;
2582+ else /* choose nearest pixel */
2583+#endif
2584+ {
2585+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
2586+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
2587+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
2588+ if (diff1 <= diff2 && diff1 <= diff3)
2589+ tmp[0] = pixels[1];
2590+ else if (diff2 <= diff1 && diff2 <= diff3)
2591+ tmp[0] = pixels[3];
2592+ else
2593+ tmp[0] = pixels[4];
2594+ }
2595+
2596+ tmp[2] = average_three_pixels(pixels[1], pixels[5], center);
2597+ tmp_grey = chosen_greyscale[tmp[2]];
2598+#if PARANOID_ARROWS
2599+ diff1 = labs(bptr[4] - bptr[5]);
2600+ diff2 = labs(bptr[4] - bptr[1]);
2601+ diff3 = labs(bptr[4] - tmp_grey);
2602+ if (diff1 < diff3 || diff2 < diff3)
2603+ tmp[2] = center;
2604+ else /* choose nearest pixel */
2605+#endif
2606+ {
2607+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[1]);
2608+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[5]);
2609+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2610+ if (diff1 <= diff2 && diff1 <= diff3)
2611+ tmp[2] = pixels[1];
2612+ else if (diff2 <= diff1 && diff2 <= diff3)
2613+ tmp[2] = pixels[5];
2614+ else
2615+ tmp[2] = pixels[4];
2616+ }
2617+
2618+ break;
2619+
2620+ case 15: /* v */
2621+ for (i = 0; i < 9; i++)
2622+ tmp[i] = center;
2623+
2624+ tmp[6] = average_three_pixels(pixels[3], pixels[7], center);
2625+ tmp_grey = chosen_greyscale[tmp[6]];
2626+#if PARANOID_ARROWS
2627+ diff1 = labs(bptr[4] - bptr[3]);
2628+ diff2 = labs(bptr[4] - bptr[7]);
2629+ diff3 = labs(bptr[4] - tmp_grey);
2630+ if (diff1 < diff3 || diff2 < diff3)
2631+ tmp[6] = center;
2632+ else /* choose nearest pixel */
2633+#endif
2634+ {
2635+ diff1 = calc_pixel_diff_nosqrt(tmp[6], pixels[3]);
2636+ diff2 = calc_pixel_diff_nosqrt(tmp[6], pixels[7]);
2637+ diff3 = calc_pixel_diff_nosqrt(tmp[6], pixels[4]);
2638+ if (diff1 <= diff2 && diff1 <= diff3)
2639+ tmp[6] = pixels[3];
2640+ else if (diff2 <= diff1 && diff2 <= diff3)
2641+ tmp[6] = pixels[7];
2642+ else
2643+ tmp[6] = pixels[4];
2644+ }
2645+
2646+ tmp[8] = average_three_pixels(pixels[5], pixels[7], center);
2647+ tmp_grey = chosen_greyscale[tmp[8]];
2648+#if PARANOID_ARROWS
2649+ diff1 = labs(bptr[4] - bptr[7]);
2650+ diff2 = labs(bptr[4] - bptr[5]);
2651+ diff3 = labs(bptr[4] - tmp_grey);
2652+ if (diff1 < diff3 || diff2 < diff3)
2653+ tmp[8] = center;
2654+ else /* choose nearest pixel */
2655+#endif
2656+ {
2657+ diff1 = calc_pixel_diff_nosqrt(tmp[8], pixels[5]);
2658+ diff2 = calc_pixel_diff_nosqrt(tmp[8], pixels[7]);
2659+ diff3 = calc_pixel_diff_nosqrt(tmp[8], pixels[4]);
2660+ if (diff1 <= diff2 && diff1 <= diff3)
2661+ tmp[8] = pixels[5];
2662+ else if (diff2 <= diff1 && diff2 <= diff3)
2663+ tmp[8] = pixels[7];
2664+ else
2665+ tmp[8] = pixels[4];
2666+ }
2667+
2668+ break;
2669+
2670+ case 127: /* * */
2671+ case -1: /* no edge */
2672+ case 0: /* - */
2673+ case 6: /* | */
2674+ default:
2675+ dptr2 = ((uint16 *) (dptr - dstPitch)) - 1;
2676+ *dptr2++ = center;
2677+ *dptr2++ = center;
2678+ *dptr2 = center;
2679+ dptr2 = ((uint16 *) dptr) - 1;
2680+ *dptr2++ = center;
2681+ *dptr2++ = center;
2682+#if DEBUG_REFRESH_RANDOM_XOR
2683+ *dptr2 = center ^ (uint16) (dxorshift_128() * (1L<<16));
2684+#else
2685+ *dptr2 = center;
2686+#endif
2687+ dptr2 = ((uint16 *) (dptr + dstPitch)) - 1;
2688+ *dptr2++ = center;
2689+ *dptr2++ = center;
2690+ *dptr2 = center;
2691+
2692+ return;
2693+
2694+ break;
2695+ }
2696+
2697+ ptmp = tmp;
2698+ dptr2 = ((uint16 *) (dptr - dstPitch)) - 1;
2699+ *dptr2++ = *ptmp++;
2700+ *dptr2++ = *ptmp++;
2701+ *dptr2 = *ptmp++;
2702+ dptr2 = ((uint16 *) dptr) - 1;
2703+ *dptr2++ = *ptmp++;
2704+ *dptr2++ = *ptmp++;
2705+#if DEBUG_REFRESH_RANDOM_XOR
2706+ *dptr2 = *ptmp++ ^ (uint16) (dxorshift_128() * (1L<<16));
2707+#else
2708+ *dptr2 = *ptmp++;
2709+#endif
2710+ dptr2 = ((uint16 *) (dptr + dstPitch)) - 1;
2711+ *dptr2++ = *ptmp++;
2712+ *dptr2++ = *ptmp++;
2713+ *dptr2 = *ptmp;
2714+}
2715+
2716+
2717+
2718+/* Fill pixel grid with or without interpolation, using the detected edge */
2719+void anti_alias_grid_2x(uint8 *dptr, int dstPitch,
2720+ uint16 *pixels, int sub_type, int16 *bptr,
2721+ int8 *sim,
2722+ int interpolate_2x)
2723+{
2724+ uint16 *dptr2;
2725+ uint16 center = pixels[4];
2726+ int32 diff1, diff2, diff3;
2727+ int16 tmp_grey;
2728+ uint16 tmp[4];
2729+ uint16 *ptmp;
2730+
2731+ switch (sub_type)
2732+ {
2733+ case 1: /* '- */
2734+ tmp[0] = tmp[1] = tmp[3] = center;
2735+
2736+ tmp[2] = average_three_pixels(pixels[3], pixels[7], center);
2737+ tmp_grey = chosen_greyscale[tmp[2]];
2738+#if PARANOID_KNIGHTS
2739+ diff1 = labs(bptr[4] - bptr[3]);
2740+ diff2 = labs(bptr[4] - bptr[7]);
2741+ diff3 = labs(bptr[4] - tmp_grey);
2742+ if (diff1 < diff3 || diff2 < diff3)
2743+ tmp[2] = center;
2744+ else /* choose nearest pixel */
2745+#endif
2746+ {
2747+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[3]);
2748+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[7]);
2749+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2750+ if (diff1 <= diff2 && diff1 <= diff3)
2751+ tmp[2] = pixels[3];
2752+ else if (diff2 <= diff1 && diff2 <= diff3)
2753+ tmp[2] = pixels[7];
2754+ else
2755+ tmp[2] = pixels[4];
2756+
2757+ tmp_grey = chosen_greyscale[tmp[2]];
2758+ diff1 = labs(bptr[4] - tmp_grey);
2759+ diff2 = labs(bptr[4] - bptr[8]);
2760+ if (diff1 <= diff2)
2761+ {
2762+ if (interpolate_2x)
2763+ {
2764+ uint16 tmp_pixel = tmp[2];
2765+ tmp[2] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
2766+ tmp_pixel, center);
2767+ tmp[3] = Q_INTERPOLATE(center, center, center, tmp_pixel);
2768+ }
2769+ }
2770+ else
2771+ {
2772+ if (interpolate_2x)
2773+ {
2774+ tmp[2] = INTERPOLATE(tmp[2], center);
2775+ }
2776+ else
2777+ {
2778+ if (bptr[4] > chosen_greyscale[tmp[2]])
2779+ tmp[2] = center;
2780+ }
2781+ }
2782+ }
2783+
2784+ break;
2785+
2786+ case 2: /* -. */
2787+ tmp[0] = tmp[2] = tmp[3] = center;
2788+
2789+ tmp[1] = average_three_pixels(pixels[1], pixels[5], center);
2790+ tmp_grey = chosen_greyscale[tmp[1]];
2791+#if PARANOID_KNIGHTS
2792+ diff1 = labs(bptr[4] - bptr[5]);
2793+ diff2 = labs(bptr[4] - bptr[1]);
2794+ diff3 = labs(bptr[4] - tmp_grey);
2795+ if (diff1 < diff3 || diff2 < diff3)
2796+ tmp[1] = center;
2797+ else /* choose nearest pixel */
2798+#endif
2799+ {
2800+ diff1 = calc_pixel_diff_nosqrt(tmp[1], pixels[1]);
2801+ diff2 = calc_pixel_diff_nosqrt(tmp[1], pixels[5]);
2802+ diff3 = calc_pixel_diff_nosqrt(tmp[1], pixels[4]);
2803+ if (diff1 <= diff2 && diff1 <= diff3)
2804+ tmp[1] = pixels[1];
2805+ else if (diff2 <= diff1 && diff2 <= diff3)
2806+ tmp[1] = pixels[5];
2807+ else
2808+ tmp[1] = pixels[4];
2809+
2810+ tmp_grey = chosen_greyscale[tmp[1]];
2811+ diff1 = labs(bptr[4] - tmp_grey);
2812+ diff2 = labs(bptr[4] - bptr[0]);
2813+ if (diff1 <= diff2)
2814+ {
2815+ if (interpolate_2x)
2816+ {
2817+ uint16 tmp_pixel = tmp[1];
2818+ tmp[1] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
2819+ tmp_pixel, center);
2820+ tmp[0] = Q_INTERPOLATE(center, center, center, tmp_pixel);
2821+ }
2822+ }
2823+ else
2824+ {
2825+ if (interpolate_2x)
2826+ {
2827+ tmp[1] = INTERPOLATE(tmp[1], center);
2828+ }
2829+ else
2830+ {
2831+ if (bptr[4] > chosen_greyscale[tmp[1]])
2832+ tmp[1] = center;
2833+ }
2834+ }
2835+ }
2836+
2837+ break;
2838+
2839+ case 3: /* \ */
2840+ case 16: /* \' */
2841+ case 17: /* .\ */
2842+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
2843+
2844+ if (sub_type != 16)
2845+ {
2846+ tmp[1] = average_three_pixels(pixels[1], pixels[5], center);
2847+ diff1 = calc_pixel_diff_nosqrt(tmp[1], pixels[1]);
2848+ diff2 = calc_pixel_diff_nosqrt(tmp[1], pixels[5]);
2849+ diff3 = calc_pixel_diff_nosqrt(tmp[1], pixels[4]);
2850+ if (diff1 <= diff2 && diff1 <= diff3)
2851+ tmp[1] = pixels[1];
2852+ else if (diff2 <= diff1 && diff2 <= diff3)
2853+ tmp[1] = pixels[5];
2854+ else
2855+ tmp[1] = pixels[4];
2856+
2857+ if (interpolate_2x)
2858+ {
2859+ tmp[1] = INTERPOLATE(tmp[1], center);
2860+ }
2861+ /* sim test is for hyper-cephalic kitten eyes and squeeze toy
2862+ * mouse pointer in Sam&Max. Half-diags can be too thin in 2x
2863+ * nearest-neighbor, so detect them and don't anti-alias them.
2864+ */
2865+ else if (bptr[4] > chosen_greyscale[tmp[1]] ||
2866+ (sim_sum == 1 && (sim[0] || sim[7]) &&
2867+ pixels[1] == pixels[3] && pixels[5] == pixels[7]))
2868+ tmp[1] = center;
2869+ }
2870+
2871+ if (sub_type != 17)
2872+ {
2873+ tmp[2] = average_three_pixels(pixels[3], pixels[7], center);
2874+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[3]);
2875+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[7]);
2876+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2877+ if (diff1 <= diff2 && diff1 <= diff3)
2878+ tmp[2] = pixels[3];
2879+ else if (diff2 <= diff1 && diff2 <= diff3)
2880+ tmp[2] = pixels[7];
2881+ else
2882+ tmp[2] = pixels[4];
2883+
2884+ if (interpolate_2x)
2885+ {
2886+ tmp[2] = INTERPOLATE(tmp[2], center);
2887+ }
2888+ /* sim test is for hyper-cephalic kitten eyes and squeeze toy
2889+ * mouse pointer in Sam&Max. Half-diags can be too thin in 2x
2890+ * nearest-neighbor, so detect them and don't anti-alias them.
2891+ */
2892+ else if (bptr[4] > chosen_greyscale[tmp[2]] ||
2893+ (sim_sum == 1 && (sim[0] || sim[7]) &&
2894+ pixels[1] == pixels[3] && pixels[5] == pixels[7]))
2895+ tmp[2] = center;
2896+ }
2897+
2898+ break;
2899+
2900+ case 4: /* '| */
2901+ tmp[0] = tmp[2] = tmp[3] = center;
2902+
2903+ tmp[1] = average_three_pixels(pixels[1], pixels[5], center);
2904+ tmp_grey = chosen_greyscale[tmp[1]];
2905+#if PARANOID_KNIGHTS
2906+ diff1 = labs(bptr[4] - bptr[1]);
2907+ diff2 = labs(bptr[4] - bptr[5]);
2908+ diff3 = labs(bptr[4] - tmp_grey);
2909+ if (diff1 < diff3 || diff2 < diff3)
2910+ tmp[1] = center;
2911+ else /* choose nearest pixel */
2912+#endif
2913+ {
2914+ diff1 = calc_pixel_diff_nosqrt(tmp[1], pixels[1]);
2915+ diff2 = calc_pixel_diff_nosqrt(tmp[1], pixels[5]);
2916+ diff3 = calc_pixel_diff_nosqrt(tmp[1], pixels[4]);
2917+ if (diff1 <= diff2 && diff1 <= diff3)
2918+ tmp[1] = pixels[1];
2919+ else if (diff2 <= diff1 && diff2 <= diff3)
2920+ tmp[1] = pixels[5];
2921+ else
2922+ tmp[1] = pixels[4];
2923+
2924+ tmp_grey = chosen_greyscale[tmp[1]];
2925+ diff1 = labs(bptr[4] - tmp_grey);
2926+ diff2 = labs(bptr[4] - bptr[8]);
2927+ if (diff1 <= diff2)
2928+ {
2929+ if (interpolate_2x)
2930+ {
2931+ uint16 tmp_pixel = tmp[1];
2932+ tmp[1] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
2933+ tmp_pixel, center);
2934+ tmp[3] = Q_INTERPOLATE(center, center, center, tmp_pixel);
2935+ }
2936+ }
2937+ else
2938+ {
2939+ if (interpolate_2x)
2940+ {
2941+ tmp[1] = INTERPOLATE(tmp[1], center);
2942+ }
2943+ else
2944+ {
2945+ if (bptr[4] > chosen_greyscale[tmp[1]])
2946+ tmp[1] = center;
2947+ }
2948+ }
2949+ }
2950+
2951+ break;
2952+
2953+ case 5: /* |. */
2954+ tmp[0] = tmp[1] = tmp[3] = center;
2955+
2956+ tmp[2] = average_three_pixels(pixels[3], pixels[7], center);
2957+ tmp_grey = chosen_greyscale[tmp[2]];
2958+#if PARANOID_KNIGHTS
2959+ diff1 = labs(bptr[4] - bptr[7]);
2960+ diff2 = labs(bptr[4] - bptr[3]);
2961+ diff3 = labs(bptr[4] - tmp_grey);
2962+ if (diff1 < diff3 || diff2 < diff3)
2963+ tmp[2] = center;
2964+ else /* choose nearest pixel */
2965+#endif
2966+ {
2967+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[3]);
2968+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[7]);
2969+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
2970+ if (diff1 <= diff2 && diff1 <= diff3)
2971+ tmp[2] = pixels[3];
2972+ else if (diff2 <= diff1 && diff2 <= diff3)
2973+ tmp[2] = pixels[7];
2974+ else
2975+ tmp[2] = pixels[4];
2976+
2977+ tmp_grey = chosen_greyscale[tmp[2]];
2978+ diff1 = labs(bptr[4] - tmp_grey);
2979+ diff2 = labs(bptr[4] - bptr[0]);
2980+ if (diff1 <= diff2)
2981+ {
2982+ if (interpolate_2x)
2983+ {
2984+ uint16 tmp_pixel = tmp[2];
2985+ tmp[2] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
2986+ tmp_pixel, center);
2987+ tmp[0] = Q_INTERPOLATE(center, center, center, tmp_pixel);
2988+ }
2989+ }
2990+ else
2991+ {
2992+ if (interpolate_2x)
2993+ {
2994+ tmp[2] = INTERPOLATE(tmp[2], center);
2995+ }
2996+ else
2997+ {
2998+ if (bptr[4] > chosen_greyscale[tmp[2]])
2999+ tmp[2] = center;
3000+ }
3001+ }
3002+ }
3003+
3004+ break;
3005+
3006+ case 7: /* |' */
3007+ tmp[1] = tmp[2] = tmp[3] = center;
3008+
3009+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
3010+ tmp_grey = chosen_greyscale[tmp[0]];
3011+#if PARANOID_KNIGHTS
3012+ diff1 = labs(bptr[4] - bptr[1]);
3013+ diff2 = labs(bptr[4] - bptr[3]);
3014+ diff3 = labs(bptr[4] - tmp_grey);
3015+ if (diff1 < diff3 || diff2 < diff3)
3016+ tmp[0] = center;
3017+ else /* choose nearest pixel */
3018+#endif
3019+ {
3020+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
3021+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
3022+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
3023+ if (diff1 <= diff2 && diff1 <= diff3)
3024+ tmp[0] = pixels[1];
3025+ else if (diff2 <= diff1 && diff2 <= diff3)
3026+ tmp[0] = pixels[3];
3027+ else
3028+ tmp[0] = pixels[4];
3029+
3030+ tmp_grey = chosen_greyscale[tmp[0]];
3031+ diff1 = labs(bptr[4] - tmp_grey);
3032+ diff2 = labs(bptr[4] - bptr[6]);
3033+ if (diff1 <= diff2)
3034+ {
3035+ if (interpolate_2x)
3036+ {
3037+ uint16 tmp_pixel = tmp[0];
3038+ tmp[0] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
3039+ tmp_pixel, center);
3040+ tmp[2] = Q_INTERPOLATE(center, center, center, tmp_pixel);
3041+ }
3042+ }
3043+ else
3044+ {
3045+ if (interpolate_2x)
3046+ {
3047+ tmp[0] = INTERPOLATE(tmp[0], center);
3048+ }
3049+ else
3050+ {
3051+ if (bptr[4] > chosen_greyscale[tmp[0]])
3052+ tmp[0] = center;
3053+ }
3054+ }
3055+ }
3056+
3057+ break;
3058+
3059+ case 8: /* .| */
3060+ tmp[0] = tmp[1] = tmp[2] = center;
3061+
3062+ tmp[3] = average_three_pixels(pixels[5], pixels[7], center);
3063+ tmp_grey = chosen_greyscale[tmp[3]];
3064+#if PARANOID_KNIGHTS
3065+ diff1 = labs(bptr[4] - bptr[7]);
3066+ diff2 = labs(bptr[4] - bptr[5]);
3067+ diff3 = labs(bptr[4] - tmp_grey);
3068+ if (diff1 < diff3 || diff2 < diff3)
3069+ tmp[3] = center;
3070+ else /* choose nearest pixel */
3071+#endif
3072+ {
3073+ diff1 = calc_pixel_diff_nosqrt(tmp[3], pixels[5]);
3074+ diff2 = calc_pixel_diff_nosqrt(tmp[3], pixels[7]);
3075+ diff3 = calc_pixel_diff_nosqrt(tmp[3], pixels[4]);
3076+ if (diff1 <= diff2 && diff1 <= diff3)
3077+ tmp[3] = pixels[5];
3078+ else if (diff2 <= diff1 && diff2 <= diff3)
3079+ tmp[3] = pixels[7];
3080+ else
3081+ tmp[3] = pixels[4];
3082+
3083+ tmp_grey = chosen_greyscale[tmp[3]];
3084+ diff1 = labs(bptr[4] - tmp_grey);
3085+ diff2 = labs(bptr[4] - bptr[2]);
3086+ if (diff1 <= diff2)
3087+ {
3088+ if (interpolate_2x)
3089+ {
3090+ uint16 tmp_pixel = tmp[3];
3091+ tmp[3] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
3092+ tmp_pixel, center);
3093+ tmp[1] = Q_INTERPOLATE(center, center, center, tmp_pixel);
3094+ }
3095+ }
3096+ else
3097+ {
3098+ if (interpolate_2x)
3099+ {
3100+ tmp[3] = INTERPOLATE(tmp[3], center);
3101+ }
3102+ else
3103+ {
3104+ if (bptr[4] > chosen_greyscale[tmp[3]])
3105+ tmp[3] = center;
3106+ }
3107+ }
3108+ }
3109+
3110+ break;
3111+
3112+ case 9: /* / */
3113+ case 18: /* '/ */
3114+ case 19: /* /. */
3115+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
3116+
3117+ if (sub_type != 18)
3118+ {
3119+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
3120+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
3121+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
3122+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
3123+ if (diff1 <= diff2 && diff1 <= diff3)
3124+ tmp[0] = pixels[1];
3125+ else if (diff2 <= diff1 && diff2 <= diff3)
3126+ tmp[0] = pixels[3];
3127+ else
3128+ tmp[0] = pixels[4];
3129+
3130+ if (interpolate_2x)
3131+ {
3132+ tmp[0] = INTERPOLATE(tmp[0], center);
3133+ }
3134+ /* sim test is for hyper-cephalic kitten eyes and squeeze toy
3135+ * mouse pointer in Sam&Max. Half-diags can be too thin in 2x
3136+ * nearest-neighbor, so detect them and don't anti-alias them.
3137+ */
3138+ else if (bptr[4] > chosen_greyscale[tmp[0]] ||
3139+ (sim_sum == 1 && (sim[2] || sim[5]) &&
3140+ pixels[1] == pixels[5] && pixels[3] == pixels[7]))
3141+ tmp[0] = center;
3142+ }
3143+
3144+ if (sub_type != 19)
3145+ {
3146+ tmp[3] = average_three_pixels(pixels[5], pixels[7], center);
3147+ diff1 = calc_pixel_diff_nosqrt(tmp[3], pixels[5]);
3148+ diff2 = calc_pixel_diff_nosqrt(tmp[3], pixels[7]);
3149+ diff3 = calc_pixel_diff_nosqrt(tmp[3], pixels[4]);
3150+ if (diff1 <= diff2 && diff1 <= diff3)
3151+ tmp[3] = pixels[5];
3152+ else if (diff2 <= diff1 && diff2 <= diff3)
3153+ tmp[3] = pixels[7];
3154+ else
3155+ tmp[3] = pixels[4];
3156+
3157+ if (interpolate_2x)
3158+ {
3159+ tmp[3] = INTERPOLATE(tmp[3], center);
3160+ }
3161+ /* sim test is for hyper-cephalic kitten eyes and squeeze toy
3162+ * mouse pointer in Sam&Max. Half-diags can be too thin in 2x
3163+ * nearest-neighbor, so detect them and don't anti-alias them.
3164+ */
3165+ else if (bptr[4] > chosen_greyscale[tmp[3]] ||
3166+ (sim_sum == 1 && (sim[2] || sim[5]) &&
3167+ pixels[1] == pixels[5] && pixels[3] == pixels[7]))
3168+ tmp[3] = center;
3169+ }
3170+
3171+ break;
3172+
3173+ case 10: /* -' */
3174+ tmp[0] = tmp[1] = tmp[2] = center;
3175+
3176+ tmp[3] = average_three_pixels(pixels[5], pixels[7], center);
3177+ tmp_grey = chosen_greyscale[tmp[3]];
3178+#if PARANOID_KNIGHTS
3179+ diff1 = labs(bptr[4] - bptr[5]);
3180+ diff2 = labs(bptr[4] - bptr[7]);
3181+ diff3 = labs(bptr[4] - tmp_grey);
3182+ if (diff1 < diff3 || diff2 < diff3)
3183+ tmp[3] = center;
3184+ else /* choose nearest pixel */
3185+#endif
3186+ {
3187+ diff1 = calc_pixel_diff_nosqrt(tmp[3], pixels[5]);
3188+ diff2 = calc_pixel_diff_nosqrt(tmp[3], pixels[7]);
3189+ diff3 = calc_pixel_diff_nosqrt(tmp[3], pixels[4]);
3190+ if (diff1 <= diff2 && diff1 <= diff3)
3191+ tmp[3] = pixels[5];
3192+ else if (diff2 <= diff1 && diff2 <= diff3)
3193+ tmp[3] = pixels[7];
3194+ else
3195+ tmp[3] = pixels[4];
3196+
3197+ tmp_grey = chosen_greyscale[tmp[3]];
3198+ diff1 = labs(bptr[4] - tmp_grey);
3199+ diff2 = labs(bptr[4] - bptr[6]);
3200+ if (diff1 <= diff2)
3201+ {
3202+ if (interpolate_2x)
3203+ {
3204+ uint16 tmp_pixel = tmp[3];
3205+ tmp[3] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
3206+ tmp_pixel, center);
3207+ tmp[2] = Q_INTERPOLATE(center, center, center, tmp_pixel);
3208+ }
3209+ }
3210+ else
3211+ {
3212+ if (interpolate_2x)
3213+ {
3214+ tmp[3] = INTERPOLATE(tmp[3], center);
3215+ }
3216+ else
3217+ {
3218+ if (bptr[4] > chosen_greyscale[tmp[3]])
3219+ tmp[3] = center;
3220+ }
3221+ }
3222+ }
3223+
3224+ break;
3225+
3226+ case 11: /* .- */
3227+ tmp[1] = tmp[2] = tmp[3] = center;
3228+
3229+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
3230+ tmp_grey = chosen_greyscale[tmp[0]];
3231+#if PARANOID_KNIGHTS
3232+ diff1 = labs(bptr[4] - bptr[3]);
3233+ diff2 = labs(bptr[4] - bptr[1]);
3234+ diff3 = labs(bptr[4] - tmp_grey);
3235+ if (diff1 < diff3 || diff2 < diff3)
3236+ tmp[0] = center;
3237+ else /* choose nearest pixel */
3238+#endif
3239+ {
3240+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
3241+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
3242+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
3243+ if (diff1 <= diff2 && diff1 <= diff3)
3244+ tmp[0] = pixels[1];
3245+ else if (diff2 <= diff1 && diff2 <= diff3)
3246+ tmp[0] = pixels[3];
3247+ else
3248+ tmp[0] = pixels[4];
3249+
3250+ tmp_grey = chosen_greyscale[tmp[0]];
3251+ diff1 = labs(bptr[4] - tmp_grey);
3252+ diff2 = labs(bptr[4] - bptr[2]);
3253+ if (diff1 <= diff2)
3254+ {
3255+ if (interpolate_2x)
3256+ {
3257+ uint16 tmp_pixel = tmp[0];
3258+ tmp[0] = Q_INTERPOLATE(tmp_pixel, tmp_pixel,
3259+ tmp_pixel, center);
3260+ tmp[1] = Q_INTERPOLATE(center, center, center, tmp_pixel);
3261+ }
3262+ }
3263+ else
3264+ {
3265+ if (interpolate_2x)
3266+ {
3267+ tmp[0] = INTERPOLATE(tmp[0], center);
3268+ }
3269+ else
3270+ {
3271+ if (bptr[4] > chosen_greyscale[tmp[0]])
3272+ tmp[0] = center;
3273+ }
3274+ }
3275+ }
3276+
3277+ break;
3278+
3279+ case 12: /* < */
3280+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
3281+
3282+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
3283+ tmp_grey = chosen_greyscale[tmp[0]];
3284+#if PARANOID_ARROWS
3285+ diff1 = labs(bptr[4] - bptr[1]);
3286+ diff2 = labs(bptr[4] - bptr[3]);
3287+ diff3 = labs(bptr[4] - tmp_grey);
3288+ if (diff1 < diff3 || diff2 < diff3)
3289+ tmp[0] = center;
3290+ else /* choose nearest pixel */
3291+#endif
3292+ {
3293+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
3294+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
3295+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
3296+ if (diff1 <= diff2 && diff1 <= diff3)
3297+ tmp[0] = pixels[1];
3298+ else if (diff2 <= diff1 && diff2 <= diff3)
3299+ tmp[0] = pixels[3];
3300+ else
3301+ tmp[0] = pixels[4];
3302+
3303+ /* check for half-arrow */
3304+ if (sim_sum == 2 && sim[4] && sim[2])
3305+ {
3306+ if (interpolate_2x)
3307+ {
3308+ tmp[0] = INTERPOLATE(center, tmp[0]);
3309+ tmp[2] = average_one_third(center, tmp[0]);
3310+ }
3311+ else
3312+ {
3313+ if (bptr[4] > chosen_greyscale[tmp[0]])
3314+ tmp[0] = center;
3315+ }
3316+
3317+ break;
3318+ }
3319+
3320+ if (interpolate_2x)
3321+ tmp[0] = average_one_third(center, tmp[0]);
3322+ else
3323+ tmp[0] = center;
3324+ }
3325+
3326+ tmp[2] = average_three_pixels(pixels[3], pixels[7], center);
3327+ tmp_grey = chosen_greyscale[tmp[2]];
3328+#if PARANOID_ARROWS
3329+ diff1 = labs(bptr[4] - bptr[3]);
3330+ diff2 = labs(bptr[4] - bptr[7]);
3331+ diff3 = labs(bptr[4] - tmp_grey);
3332+ if (diff1 < diff3 || diff2 < diff3)
3333+ tmp[2] = center;
3334+ else /* choose nearest pixel */
3335+#endif
3336+ {
3337+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[3]);
3338+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[7]);
3339+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
3340+ if (diff1 <= diff2 && diff1 <= diff3)
3341+ tmp[2] = pixels[3];
3342+ else if (diff2 <= diff1 && diff2 <= diff3)
3343+ tmp[2] = pixels[7];
3344+ else
3345+ tmp[2] = pixels[4];
3346+
3347+ /* check for half-arrow */
3348+ if (sim_sum == 2 && sim[4] && sim[7])
3349+ {
3350+ if (interpolate_2x)
3351+ {
3352+ tmp[2] = INTERPOLATE(center, tmp[2]);
3353+ tmp[0] = average_one_third(center, tmp[2]);
3354+ }
3355+ else
3356+ {
3357+ if (bptr[4] > chosen_greyscale[tmp[2]])
3358+ tmp[2] = center;
3359+ }
3360+
3361+ break;
3362+ }
3363+
3364+ if (interpolate_2x)
3365+ tmp[2] = average_one_third(center, tmp[2]);
3366+ else
3367+ tmp[2] = center;
3368+ }
3369+
3370+ break;
3371+
3372+ case 13: /* > */
3373+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
3374+
3375+ tmp[1] = average_three_pixels(pixels[1], pixels[5], center);
3376+ tmp_grey = chosen_greyscale[tmp[1]];
3377+#if PARANOID_ARROWS
3378+ diff1 = labs(bptr[4] - bptr[5]);
3379+ diff2 = labs(bptr[4] - bptr[1]);
3380+ diff3 = labs(bptr[4] - tmp_grey);
3381+ if (diff1 < diff3 || diff2 < diff3)
3382+ tmp[1] = center;
3383+ else /* choose nearest pixel */
3384+#endif
3385+ {
3386+ diff1 = calc_pixel_diff_nosqrt(tmp[1], pixels[1]);
3387+ diff2 = calc_pixel_diff_nosqrt(tmp[1], pixels[5]);
3388+ diff3 = calc_pixel_diff_nosqrt(tmp[1], pixels[4]);
3389+ if (diff1 <= diff2 && diff1 <= diff3)
3390+ tmp[1] = pixels[1];
3391+ else if (diff2 <= diff1 && diff2 <= diff3)
3392+ tmp[1] = pixels[5];
3393+ else
3394+ tmp[1] = pixels[4];
3395+
3396+ /* check for half-arrow */
3397+ if (sim_sum == 2 && sim[3] && sim[0])
3398+ {
3399+ if (interpolate_2x)
3400+ {
3401+ tmp[1] = INTERPOLATE(center, tmp[1]);
3402+ tmp[3] = average_one_third(center, tmp[1]);
3403+ }
3404+ else
3405+ {
3406+ if (bptr[4] > chosen_greyscale[tmp[1]])
3407+ tmp[1] = center;
3408+ }
3409+
3410+ break;
3411+ }
3412+
3413+ if (interpolate_2x)
3414+ tmp[1] = average_one_third(center, tmp[1]);
3415+ else
3416+ tmp[1] = center;
3417+ }
3418+
3419+ tmp[3] = average_three_pixels(pixels[5], pixels[7], center);
3420+ tmp_grey = chosen_greyscale[tmp[3]];
3421+#if PARANOID_ARROWS
3422+ diff1 = labs(bptr[4] - bptr[7]);
3423+ diff2 = labs(bptr[4] - bptr[5]);
3424+ diff3 = labs(bptr[4] - tmp_grey);
3425+ if (diff1 < diff3 || diff2 < diff3)
3426+ tmp[3] = center;
3427+ else /* choose nearest pixel */
3428+#endif
3429+ {
3430+ diff1 = calc_pixel_diff_nosqrt(tmp[3], pixels[5]);
3431+ diff2 = calc_pixel_diff_nosqrt(tmp[3], pixels[7]);
3432+ diff3 = calc_pixel_diff_nosqrt(tmp[3], pixels[4]);
3433+ if (diff1 <= diff2 && diff1 <= diff3)
3434+ tmp[3] = pixels[5];
3435+ else if (diff2 <= diff1 && diff2 <= diff3)
3436+ tmp[3] = pixels[7];
3437+ else
3438+ tmp[3] = pixels[4];
3439+
3440+ /* check for half-arrow */
3441+ if (sim_sum == 2 && sim[3] && sim[5])
3442+ {
3443+ if (interpolate_2x)
3444+ {
3445+ tmp[3] = INTERPOLATE(center, tmp[3]);
3446+ tmp[1] = average_one_third(center, tmp[3]);
3447+ }
3448+ else
3449+ {
3450+ if (bptr[4] > chosen_greyscale[tmp[3]])
3451+ tmp[3] = center;
3452+ }
3453+
3454+ break;
3455+ }
3456+
3457+ if (interpolate_2x)
3458+ tmp[3] = average_one_third(center, tmp[3]);
3459+ else
3460+ tmp[3] = center;
3461+ }
3462+
3463+ break;
3464+
3465+ case 14: /* ^ */
3466+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
3467+
3468+ tmp[0] = average_three_pixels(pixels[1], pixels[3], center);
3469+ tmp_grey = chosen_greyscale[tmp[0]];
3470+#if PARANOID_ARROWS
3471+ diff1 = labs(bptr[4] - bptr[1]);
3472+ diff2 = labs(bptr[4] - bptr[3]);
3473+ diff3 = labs(bptr[4] - tmp_grey);
3474+ if (diff1 < diff3 || diff2 < diff3)
3475+ tmp[0] = center;
3476+ else /* choose nearest pixel */
3477+#endif
3478+ {
3479+ diff1 = calc_pixel_diff_nosqrt(tmp[0], pixels[1]);
3480+ diff2 = calc_pixel_diff_nosqrt(tmp[0], pixels[3]);
3481+ diff3 = calc_pixel_diff_nosqrt(tmp[0], pixels[4]);
3482+ if (diff1 <= diff2 && diff1 <= diff3)
3483+ tmp[0] = pixels[1];
3484+ else if (diff2 <= diff1 && diff2 <= diff3)
3485+ tmp[0] = pixels[3];
3486+ else
3487+ tmp[0] = pixels[4];
3488+
3489+ /* check for half-arrow */
3490+ if (sim_sum == 2 && sim[6] && sim[5])
3491+ {
3492+ if (interpolate_2x)
3493+ {
3494+ tmp[0] = INTERPOLATE(center, tmp[0]);
3495+ tmp[1] = average_one_third(center, tmp[0]);
3496+ }
3497+ else
3498+ {
3499+ if (bptr[4] > chosen_greyscale[tmp[0]])
3500+ tmp[0] = center;
3501+ }
3502+
3503+ break;
3504+ }
3505+
3506+ if (interpolate_2x)
3507+ tmp[0] = average_one_third(center, tmp[0]);
3508+ else
3509+ tmp[0] = center;
3510+ }
3511+
3512+ tmp[1] = average_three_pixels(pixels[1], pixels[5], center);
3513+ tmp_grey = chosen_greyscale[tmp[1]];
3514+#if PARANOID_ARROWS
3515+ diff1 = labs(bptr[4] - bptr[5]);
3516+ diff2 = labs(bptr[4] - bptr[1]);
3517+ diff3 = labs(bptr[4] - tmp_grey);
3518+ if (diff1 < diff3 || diff2 < diff3)
3519+ tmp[1] = center;
3520+ else /* choose nearest pixel */
3521+#endif
3522+ {
3523+ diff1 = calc_pixel_diff_nosqrt(tmp[1], pixels[1]);
3524+ diff2 = calc_pixel_diff_nosqrt(tmp[1], pixels[5]);
3525+ diff3 = calc_pixel_diff_nosqrt(tmp[1], pixels[4]);
3526+ if (diff1 <= diff2 && diff1 <= diff3)
3527+ tmp[1] = pixels[1];
3528+ else if (diff2 <= diff1 && diff2 <= diff3)
3529+ tmp[1] = pixels[5];
3530+ else
3531+ tmp[1] = pixels[4];
3532+
3533+ /* check for half-arrow */
3534+ if (sim_sum == 2 && sim[6] && sim[7])
3535+ {
3536+ if (interpolate_2x)
3537+ {
3538+ tmp[1] = INTERPOLATE(center, tmp[1]);
3539+ tmp[0] = average_one_third(center, tmp[1]);
3540+ }
3541+ else
3542+ {
3543+ if (bptr[4] > chosen_greyscale[tmp[1]])
3544+ tmp[1] = center;
3545+ }
3546+
3547+ break;
3548+ }
3549+
3550+ if (interpolate_2x)
3551+ tmp[1] = average_one_third(center, tmp[1]);
3552+ else
3553+ tmp[1] = center;
3554+ }
3555+
3556+ break;
3557+
3558+ case 15: /* v */
3559+ tmp[0] = tmp[1] = tmp[2] = tmp[3] = center;
3560+
3561+ tmp[2] = average_three_pixels(pixels[3], pixels[7], center);
3562+ tmp_grey = chosen_greyscale[tmp[2]];
3563+#if PARANOID_ARROWS
3564+ diff1 = labs(bptr[4] - bptr[3]);
3565+ diff2 = labs(bptr[4] - bptr[7]);
3566+ diff3 = labs(bptr[4] - tmp_grey);
3567+ if (diff1 < diff3 || diff2 < diff3)
3568+ tmp[2] = center;
3569+ else /* choose nearest pixel */
3570+#endif
3571+ {
3572+ diff1 = calc_pixel_diff_nosqrt(tmp[2], pixels[3]);
3573+ diff2 = calc_pixel_diff_nosqrt(tmp[2], pixels[7]);
3574+ diff3 = calc_pixel_diff_nosqrt(tmp[2], pixels[4]);
3575+ if (diff1 <= diff2 && diff1 <= diff3)
3576+ tmp[2] = pixels[3];
3577+ else if (diff2 <= diff1 && diff2 <= diff3)
3578+ tmp[2] = pixels[7];
3579+ else
3580+ tmp[2] = pixels[4];
3581+
3582+ /* check for half-arrow */
3583+ if (sim_sum == 2 && sim[1] && sim[0])
3584+ {
3585+ if (interpolate_2x)
3586+ {
3587+ tmp[2] = INTERPOLATE(center, tmp[2]);
3588+ tmp[3] = average_one_third(center, tmp[2]);
3589+ }
3590+ else
3591+ {
3592+ if (bptr[4] > chosen_greyscale[tmp[2]])
3593+ tmp[2] = center;
3594+ }
3595+
3596+ break;
3597+ }
3598+
3599+ if (interpolate_2x)
3600+ tmp[2] = average_one_third(center, tmp[2]);
3601+ else
3602+ tmp[2] = center;
3603+ }
3604+
3605+ tmp[3] = average_three_pixels(pixels[5], pixels[7], center);
3606+ tmp_grey = chosen_greyscale[tmp[3]];
3607+#if PARANOID_ARROWS
3608+ diff1 = labs(bptr[4] - bptr[7]);
3609+ diff2 = labs(bptr[4] - bptr[5]);
3610+ diff3 = labs(bptr[4] - tmp_grey);
3611+ if (diff1 < diff3 || diff2 < diff3)
3612+ tmp[3] = center;
3613+ else /* choose nearest pixel */
3614+#endif
3615+ {
3616+ diff1 = calc_pixel_diff_nosqrt(tmp[3], pixels[5]);
3617+ diff2 = calc_pixel_diff_nosqrt(tmp[3], pixels[7]);
3618+ diff3 = calc_pixel_diff_nosqrt(tmp[3], pixels[4]);
3619+ if (diff1 <= diff2 && diff1 <= diff3)
3620+ tmp[3] = pixels[5];
3621+ else if (diff2 <= diff1 && diff2 <= diff3)
3622+ tmp[3] = pixels[7];
3623+ else
3624+ tmp[3] = pixels[4];
3625+
3626+ /* check for half-arrow */
3627+ if (sim_sum == 2 && sim[1] && sim[2])
3628+ {
3629+ if (interpolate_2x)
3630+ {
3631+ tmp[3] = INTERPOLATE(center, tmp[3]);
3632+ tmp[2] = average_one_third(center, tmp[3]);
3633+ }
3634+ else
3635+ {
3636+ if (bptr[4] > chosen_greyscale[tmp[3]])
3637+ tmp[3] = center;
3638+ }
3639+
3640+ break;
3641+ }
3642+
3643+ if (interpolate_2x)
3644+ tmp[3] = average_one_third(center, tmp[3]);
3645+ else
3646+ tmp[3] = center;
3647+ }
3648+
3649+ break;
3650+
3651+ case -1: /* no edge */
3652+ case 0: /* - */
3653+ case 6: /* | */
3654+ case 127: /* * */
3655+ default: /* no edge */
3656+ dptr2 = (uint16 *) dptr;
3657+ *dptr2++ = center;
3658+#if DEBUG_REFRESH_RANDOM_XOR
3659+ *dptr2 = center ^ (uint16) (dxorshift_128() * (1L<<16));
3660+#else
3661+ *dptr2 = center;
3662+#endif
3663+ dptr2 = (uint16 *) (dptr + dstPitch);
3664+ *dptr2++ = center;
3665+ *dptr2 = center;
3666+
3667+ return;
3668+
3669+ break;
3670+ }
3671+
3672+ ptmp = tmp;
3673+ dptr2 = (uint16 *) dptr;
3674+ *dptr2++ = *ptmp++;
3675+#if DEBUG_REFRESH_RANDOM_XOR
3676+ *dptr2 = *ptmp++ ^ (uint16) (dxorshift_128() * (1L<<16));
3677+#else
3678+ *dptr2 = *ptmp++;
3679+#endif
3680+ dptr2 = (uint16 *) (dptr + dstPitch);
3681+ *dptr2++ = *ptmp++;
3682+ *dptr2 = *ptmp;
3683+}
3684+
3685+
3686+
3687+#if HANDLE_TRANSPARENT_OVERLAYS
3688+/* Deal with transparent pixels */
3689+void handle_transparent_overlay(uint16 transp, uint16 *pixels,
3690+ int16 *bplane, int16 *diffs)
3691+{
3692+ int16 tmp_grey;
3693+ int16 max_diff;
3694+ int16 min_grey = ((int16)1<<RGB_SHIFT);
3695+ int16 max_grey = 0;
3696+ int i;
3697+
3698+ /* find min and max grey values in window */
3699+ for (i = 0; i < 9; i++)
3700+ {
3701+ if (bplane[i] < min_grey) min_grey = bplane[i];
3702+ if (bplane[i] > max_grey) max_grey = bplane[i];
3703+ }
3704+
3705+ /* treat transparent pixels as the average of min_grey and max_grey */
3706+ /* set diff from center pixel to maximum difference within the window */
3707+ tmp_grey = (min_grey + max_grey + 1) >> 1;
3708+ max_diff = max_grey - min_grey;
3709+
3710+ if (pixels[4] == transp) /* center pixel is transparent */
3711+ {
3712+ /* set all transparent pixels to middle grey */
3713+ if (pixels[0] == transp) bplane[0] = tmp_grey;
3714+ if (pixels[1] == transp) bplane[1] = tmp_grey;
3715+ if (pixels[2] == transp) bplane[2] = tmp_grey;
3716+ if (pixels[3] == transp) bplane[3] = tmp_grey;
3717+ if (pixels[4] == transp) bplane[4] = tmp_grey;
3718+ if (pixels[5] == transp) bplane[5] = tmp_grey;
3719+ if (pixels[6] == transp) bplane[6] = tmp_grey;
3720+ if (pixels[7] == transp) bplane[7] = tmp_grey;
3721+ if (pixels[8] == transp) bplane[8] = tmp_grey;
3722+
3723+ /* set all diffs to non-transparent pixels to max diff */
3724+ if (pixels[0] != transp) diffs[0] = max_diff;
3725+ if (pixels[1] != transp) diffs[1] = max_diff;
3726+ if (pixels[2] != transp) diffs[2] = max_diff;
3727+ if (pixels[3] != transp) diffs[3] = max_diff;
3728+ if (pixels[5] != transp) diffs[4] = max_diff;
3729+ if (pixels[6] != transp) diffs[5] = max_diff;
3730+ if (pixels[7] != transp) diffs[6] = max_diff;
3731+ if (pixels[8] != transp) diffs[7] = max_diff;
3732+ }
3733+ else /* center pixel is non-transparent */
3734+ {
3735+ /* choose transparent grey value to give largest contrast */
3736+ tmp_grey = (bplane[4] >= tmp_grey) ? min_grey : max_grey;
3737+
3738+ /* set new transparent pixel values and diffs */
3739+ if (pixels[0] == transp)
3740+ {
3741+ bplane[0] = tmp_grey;
3742+ diffs[0] = max_diff;
3743+ }
3744+ if (pixels[1] == transp)
3745+ {
3746+ bplane[1] = tmp_grey;
3747+ diffs[1] = max_diff;
3748+ }
3749+ if (pixels[2] == transp)
3750+ {
3751+ bplane[2] = tmp_grey;
3752+ diffs[2] = max_diff;
3753+ }
3754+ if (pixels[3] == transp)
3755+ {
3756+ bplane[3] = tmp_grey;
3757+ diffs[3] = max_diff;
3758+ }
3759+ if (pixels[5] == transp)
3760+ {
3761+ bplane[5] = tmp_grey;
3762+ diffs[4] = max_diff;
3763+ }
3764+ if (pixels[6] == transp)
3765+ {
3766+ bplane[6] = tmp_grey;
3767+ diffs[5] = max_diff;
3768+ }
3769+ if (pixels[7] == transp)
3770+ {
3771+ bplane[7] = tmp_grey;
3772+ diffs[6] = max_diff;
3773+ }
3774+ if (pixels[8] == transp)
3775+ {
3776+ bplane[8] = tmp_grey;
3777+ diffs[7] = max_diff;
3778+ }
3779+ }
3780+}
3781+#endif
3782+
3783+
3784+
3785+/* Check for changed pixel grid, return 1 if unchanged. */
3786+int check_unchanged_pixels(uint16 *old_src_ptr, uint16 *pixels, int w)
3787+{
3788+ uint16 *dptr16;
3789+
3790+ dptr16 = old_src_ptr - w - 1;
3791+ if (*dptr16++ != pixels[0]) return 0;
3792+ if (*dptr16++ != pixels[1]) return 0;
3793+ if (*dptr16 != pixels[2]) return 0;
3794+
3795+ dptr16 += w - 2;
3796+ if (*dptr16 != pixels[3]) return 0;
3797+ dptr16 += 2;
3798+ if (*dptr16 != pixels[5]) return 0;
3799+
3800+ dptr16 += w - 2;
3801+ if (*dptr16++ != pixels[6]) return 0;
3802+ if (*dptr16++ != pixels[7]) return 0;
3803+ if (*dptr16 != pixels[8]) return 0;
3804+
3805+ return 1;
3806+}
3807+
3808+
3809+/* Draw unchanged pixel grid, 3x */
3810+/* old_dptr16 starts in top left of grid, dptr16 in center */
3811+void draw_unchanged_grid_3x(uint16 *dptr16, int dstPitch,
3812+ uint16 *old_dptr16, int old_dst_inc)
3813+{
3814+ uint16 *sptr;
3815+ uint16 *dptr;
3816+ uint8 *dptr8 = (uint8 *) dptr16;
3817+
3818+ sptr = old_dptr16;
3819+ dptr = (uint16 *) (dptr8 - dstPitch) - 1;
3820+ *dptr++ = *sptr++;
3821+ *dptr++ = *sptr++;
3822+ *dptr = *sptr;
3823+
3824+ sptr = old_dptr16 + old_dst_inc;
3825+ dptr = dptr16 - 1;
3826+ *dptr++ = *sptr++;
3827+ *dptr++ = *sptr++;
3828+ *dptr = *sptr;
3829+
3830+ sptr = old_dptr16 + old_dst_inc + old_dst_inc;
3831+ dptr = (uint16 *) (dptr8 + dstPitch) - 1;
3832+ *dptr++ = *sptr++;
3833+ *dptr++ = *sptr++;
3834+ *dptr = *sptr;
3835+}
3836+
3837+
3838+
3839+/* Draw unchanged pixel grid, 2x */
3840+void draw_unchanged_grid_2x(uint16 *dptr16, int dstPitch,
3841+ uint16 *old_dptr16, int old_dst_inc)
3842+{
3843+ uint16 *sptr;
3844+ uint16 *dptr;
3845+ uint8 *dptr8 = (uint8 *) dptr16;
3846+
3847+ sptr = old_dptr16;
3848+ dptr = dptr16;
3849+ *dptr++ = *sptr++;
3850+ *dptr = *sptr;
3851+
3852+ sptr = old_dptr16 + old_dst_inc;
3853+ dptr = (uint16 *) (dptr8 + dstPitch);
3854+ *dptr++ = *sptr++;
3855+ *dptr = *sptr;
3856+}
3857+
3858+
3859+/* Perform edge detection, draw the new 3x pixels */
3860+void anti_alias_pass_3x(const uint8 *src, uint8 *dst,
3861+ int w, int h, int w_new, int h_new,
3862+ int srcPitch, int dstPitch,
3863+ int overlay_flag)
3864+{
3865+ int x, y;
3866+ int w2 = w + 2;
3867+ const uint8 *sptr8 = src;
3868+ uint8 *dptr8 = dst + dstPitch + 2;
3869+ const uint16 *sptr16;
3870+ uint16 *dptr16;
3871+ int16 *bplane;
3872+ int8 sim[8];
3873+ int sub_type;
3874+ int32 angle;
3875+ int16 *diffs;
3876+ int dstPitch3 = dstPitch * 3;
3877+
3878+ uint16 *old_src_ptr, *old_dst_ptr;
3879+ uint16 *old_sptr16, *old_dptr16;
3880+ int32 dist, old_src_y, old_src_x;
3881+ int old_src_inc;
3882+ int old_dst_inc, old_dst_inc3;
3883+
3884+ if (overlay_flag)
3885+ {
3886+ old_src_ptr = old_overlay + w2 + 1;
3887+ old_src_inc = w2;
3888+
3889+ old_dst_ptr = old_dst_overlay;
3890+ old_dst_inc = w_new;
3891+ }
3892+ else
3893+ {
3894+ dist = src - (const uint8 *) src_addr_min;
3895+ old_src_y = dist / srcPitch;
3896+ old_src_x = (dist - old_src_y * srcPitch) >> 1;
3897+
3898+ old_src_inc = cur_screen_width + 2;
3899+ old_src_ptr = old_src + (old_src_y + 1) * old_src_inc + old_src_x + 1;
3900+
3901+ old_dst_inc = 3 * cur_screen_width;
3902+ old_dst_ptr = old_dst + 3 * (old_src_y * old_dst_inc + old_src_x);
3903+ }
3904+
3905+ old_dst_inc3 = 3 * old_dst_inc;
3906+
3907+#if HANDLE_TRANSPARENT_OVERLAYS
3908+ uint16 transp = 0; /* transparent color */
3909+
3910+ /* assume bitmap is padded by a transparent border, take src-1 pixel */
3911+ if (overlay_flag) transp = *((const uint16 *) src - 1);
3912+#endif
3913+
3914+ /* The dirty rects optimizer in the SDL backend is helpful for frames
3915+ * with few changes, but _REALLY_ bogs things down when the whole screen
3916+ * changes. Overall, the dirty rects optimizer isn't worth it, since
3917+ * the Edge2x/3x unchanged pixel detection is far faster than full blown
3918+ * dirty rects optimization.
3919+ */
3920+ g_system->setFeatureState(g_system->kFeatureAutoComputeDirtyRects, 0);
3921+
3922+ for (y = 0; y < h; y++, sptr8 += srcPitch, dptr8 += dstPitch3,
3923+ old_src_ptr += old_src_inc, old_dst_ptr += old_dst_inc3)
3924+ {
3925+ for (x = 0,
3926+ sptr16 = (const uint16 *) sptr8,
3927+ dptr16 = (uint16 *) dptr8,
3928+ old_sptr16 = old_src_ptr,
3929+ old_dptr16 = old_dst_ptr;
3930+ x < w; x++, sptr16++, dptr16 += 3, old_sptr16++, old_dptr16 += 3)
3931+ {
3932+ const uint16 *sptr2, *addr3;
3933+ uint16 pixels[9];
3934+ char edge_type;
3935+
3936+ sptr2 = ((const uint16 *) ((const uint8 *) sptr16 - srcPitch)) - 1;
3937+ addr3 = ((const uint16 *) ((const uint8 *) sptr16 + srcPitch)) + 1;
3938+
3939+ /* fill the 3x3 grid */
3940+ memcpy(pixels, sptr2, 3*sizeof(uint16));
3941+ memcpy(pixels+3, sptr16 - 1, 3*sizeof(uint16));
3942+ memcpy(pixels+6, addr3 - 2, 3*sizeof(uint16));
3943+
3944+ /* skip interior unchanged 3x3 blocks */
3945+ if (*sptr16 == *old_sptr16 &&
3946+#if DEBUG_DRAW_REFRESH_BORDERS
3947+ x > 0 && x < w - 1 && y > 0 && y < h - 1 &&
3948+#endif
3949+ check_unchanged_pixels(old_sptr16, pixels, old_src_inc))
3950+ {
3951+ draw_unchanged_grid_3x(dptr16, dstPitch, old_dptr16,
3952+ old_dst_inc);
3953+
3954+#if DEBUG_REFRESH_RANDOM_XOR
3955+ *(dptr16 + 1) = 0;
3956+#endif
3957+ continue;
3958+ }
3959+
3960+ diffs = choose_greyscale(pixels);
3961+
3962+ /* block of solid color */
3963+ if (!diffs)
3964+ {
3965+ anti_alias_grid_clean_3x((uint8 *) dptr16, dstPitch, pixels,
3966+ 0, NULL);
3967+ continue;
3968+ }
3969+
3970+ bplane = bptr_global;
3971+
3972+#if HANDLE_TRANSPARENT_OVERLAYS
3973+ if (overlay_flag)
3974+ handle_transparent_overlay(transp, pixels, bplane, diffs);
3975+#endif
3976+
3977+ edge_type = find_principle_axis(pixels, diffs, bplane,
3978+ sim, &angle);
3979+ sub_type = refine_direction(edge_type, pixels, bplane,
3980+ sim, angle);
3981+ if (sub_type >= 0)
3982+ sub_type = fix_knights(sub_type, pixels, sim);
3983+
3984+ anti_alias_grid_clean_3x((uint8 *) dptr16, dstPitch, pixels,
3985+ sub_type, bplane);
3986+ }
3987+ }
3988+}
3989+
3990+
3991+
3992+/* Perform edge detection, draw the new 2x pixels */
3993+void anti_alias_pass_2x(const uint8 *src, uint8 *dst,
3994+ int w, int h, int w_new, int h_new,
3995+ int srcPitch, int dstPitch,
3996+ int overlay_flag,
3997+ int interpolate_2x)
3998+{
3999+ int x, y;
4000+ int w2 = w + 2;
4001+ const uint8 *sptr8 = src;
4002+ uint8 *dptr8 = dst;
4003+ const uint16 *sptr16;
4004+ uint16 *dptr16;
4005+ int16 *bplane;
4006+ int8 sim[8];
4007+ int sub_type;
4008+ int32 angle;
4009+ int16 *diffs;
4010+ int dstPitch2 = dstPitch << 1;
4011+
4012+ uint16 *old_src_ptr, *old_dst_ptr;
4013+ uint16 *old_sptr16, *old_dptr16;
4014+ int32 dist, old_src_y, old_src_x;
4015+ int old_src_inc;
4016+ int old_dst_inc, old_dst_inc2;
4017+
4018+ if (overlay_flag)
4019+ {
4020+ old_src_ptr = old_overlay + w2 + 1;
4021+ old_src_inc = w2;
4022+
4023+ old_dst_ptr = old_dst_overlay;
4024+ old_dst_inc = w_new;
4025+ }
4026+ else
4027+ {
4028+ dist = src - (const uint8 *) src_addr_min;
4029+ old_src_y = dist / srcPitch;
4030+ old_src_x = (dist - old_src_y * srcPitch) >> 1;
4031+
4032+ old_src_inc = cur_screen_width + 2;
4033+ old_src_ptr = old_src + (old_src_y + 1) * old_src_inc + old_src_x + 1;
4034+
4035+ old_dst_inc = 2 * cur_screen_width;
4036+ old_dst_ptr = old_dst + 2 * (old_src_y * old_dst_inc + old_src_x);
4037+ }
4038+
4039+ old_dst_inc2 = 2 * old_dst_inc;
4040+
4041+#if HANDLE_TRANSPARENT_OVERLAYS
4042+ uint16 transp = 0; /* transparent color */
4043+
4044+ /* assume bitmap is padded by a transparent border, take src-1 pixel */
4045+ if (overlay_flag) transp = *((const uint16 *) src - 1);
4046+#endif
4047+
4048+ /* The dirty rects optimizer in the SDL backend is helpful for frames
4049+ * with few changes, but _REALLY_ bogs things down when the whole screen
4050+ * changes. Overall, the dirty rects optimizer isn't worth it, since
4051+ * the Edge2x/3x unchanged pixel detection is far faster than full blown
4052+ * dirty rects optimization.
4053+ */
4054+ g_system->setFeatureState(g_system->kFeatureAutoComputeDirtyRects, 0);
4055+
4056+ for (y = 0; y < h; y++, sptr8 += srcPitch, dptr8 += dstPitch2,
4057+ old_src_ptr += old_src_inc, old_dst_ptr += old_dst_inc2)
4058+ {
4059+ for (x = 0,
4060+ sptr16 = (const uint16 *) sptr8,
4061+ dptr16 = (uint16 *) dptr8,
4062+ old_sptr16 = old_src_ptr,
4063+ old_dptr16 = old_dst_ptr;
4064+ x < w; x++, sptr16++, dptr16 += 2, old_sptr16++, old_dptr16 += 2)
4065+ {
4066+ const uint16 *sptr2, *addr3;
4067+ uint16 pixels[9];
4068+ char edge_type;
4069+
4070+ sptr2 = ((const uint16 *) ((const uint8 *) sptr16 - srcPitch)) - 1;
4071+ addr3 = ((const uint16 *) ((const uint8 *) sptr16 + srcPitch)) + 1;
4072+
4073+ /* fill the 3x3 grid */
4074+ memcpy(pixels, sptr2, 3*sizeof(uint16));
4075+ memcpy(pixels+3, sptr16 - 1, 3*sizeof(uint16));
4076+ memcpy(pixels+6, addr3 - 2, 3*sizeof(uint16));
4077+
4078+ /* skip interior unchanged 3x3 blocks */
4079+ if (*sptr16 == *old_sptr16 &&
4080+#if DEBUG_DRAW_REFRESH_BORDERS
4081+ x > 0 && x < w - 1 && y > 0 && y < h - 1 &&
4082+#endif
4083+ check_unchanged_pixels(old_sptr16, pixels, old_src_inc))
4084+ {
4085+ draw_unchanged_grid_2x(dptr16, dstPitch, old_dptr16,
4086+ old_dst_inc);
4087+
4088+#if DEBUG_REFRESH_RANDOM_XOR
4089+ *(dptr16 + 1) = 0;
4090+#endif
4091+ continue;
4092+ }
4093+
4094+ diffs = choose_greyscale(pixels);
4095+
4096+ /* block of solid color */
4097+ if (!diffs)
4098+ {
4099+ anti_alias_grid_2x((uint8 *) dptr16, dstPitch, pixels,
4100+ 0, NULL, NULL, 0);
4101+ continue;
4102+ }
4103+
4104+ bplane = bptr_global;
4105+
4106+#if HANDLE_TRANSPARENT_OVERLAYS
4107+ if (overlay_flag)
4108+ handle_transparent_overlay(transp, pixels, bplane, diffs);
4109+#endif
4110+
4111+ edge_type = find_principle_axis(pixels, diffs, bplane,
4112+ sim, &angle);
4113+ sub_type = refine_direction(edge_type, pixels, bplane,
4114+ sim, angle);
4115+ if (sub_type >= 0)
4116+ sub_type = fix_knights(sub_type, pixels, sim);
4117+
4118+ anti_alias_grid_2x((uint8 *) dptr16, dstPitch, pixels,
4119+ sub_type, bplane, sim,
4120+ interpolate_2x);
4121+ }
4122+ }
4123+}
4124+
4125+
4126+
4127+/* Initialize various lookup tables */
4128+void init_tables(const uint8 *srcPtr, uint32 srcPitch,
4129+ int width, int height)
4130+{
4131+ double r_float, g_float, b_float;
4132+ int r, g, b;
4133+ uint16 i;
4134+ double val[3];
4135+ double intensity;
4136+ int16 *rgb_ptr;
4137+
4138+#if DEBUG_REFRESH_RANDOM_XOR
4139+ /* seed the random number generator, we don't care if the seed is random */
4140+ initialize_xorshift_128(42);
4141+#endif
4142+
4143+ /* initialize greyscale table */
4144+ for (r = 0; r < 32; r++)
4145+ {
4146+ r_float = r / 31.0;
4147+
4148+ for (g = 0; g < 64; g++)
4149+ {
4150+ g_float = g / 63.0;
4151+
4152+ for (b = 0; b < 32; b++)
4153+ {
4154+ b_float = b / 31.0;
4155+
4156+ intensity = (r_float + g_float + b_float) / 3;
4157+
4158+ i = (r << 11) | (g << 5) | b;
4159+
4160+ /* use luma-like weights for each color, 2x increments */
4161+ val[0] = 0.571 * r_float + 0.286 * g_float + 0.143 * b_float;
4162+ val[1] = 0.286 * r_float + 0.571 * g_float + 0.143 * b_float;
4163+ val[2] = 0.143 * r_float + 0.286 * g_float + 0.571 * b_float;
4164+
4165+ /* factor in a little intensity too, it helps */
4166+ val[0] = (intensity + 9*val[0]) / 10;
4167+ val[1] = (intensity + 9*val[1]) / 10;
4168+ val[2] = (intensity + 9*val[2]) / 10;
4169+
4170+ /* store the greyscale tables */
4171+ greyscale_table[0][i] = (int16) (val[0] * ((int16)1<<GREY_SHIFT) + 0.5);
4172+ greyscale_table[1][i] = (int16) (val[1] * ((int16)1<<GREY_SHIFT) + 0.5);
4173+ greyscale_table[2][i] = (int16) (val[2] * ((int16)1<<GREY_SHIFT) + 0.5);
4174+
4175+ /* normalized RGB channel lookups */
4176+ rgb_ptr = rgb_table[(r << 11) | (g << 5) | b];
4177+ rgb_ptr[0] = (int16) (r_float * ((int16)1<<RGB_SHIFT) + 0.5);
4178+ rgb_ptr[1] = (int16) (g_float * ((int16)1<<RGB_SHIFT) + 0.5);
4179+ rgb_ptr[2] = (int16) (b_float * ((int16)1<<RGB_SHIFT) + 0.5);
4180+ }
4181+ }
4182+ }
4183+
4184+ /* initialize interpolation division tables */
4185+ for (r = 0; r <= 189; r++)
4186+ div3[r] = ((r<<1)+3) / 6;
4187+ for (r = 0; r <= 567; r++)
4188+ div9[r] = ((r<<1)+9) / 18;
4189+
4190+#if INCREASE_WIN32_PRIORITY
4191+/*
4192+ * Greatly increase thread and process priority under Win32.
4193+ *
4194+ * -- WARNING -- WinXP has a rather poor priority system, it's basicly
4195+ * "largely ignore me", "normal", or "interfere with some system processes".
4196+ * At least Win9x/ME had "increased" and "decreased" modes, but now those API
4197+ * functions aren't "supported" in WinNT/2K/XP, and we're stuck with the mess
4198+ * we have now. "Normal" is preempted by so much other unimportant stuff,
4199+ * including the idle process, that ScummVM never gets above 75% CPU usage,
4200+ * even when the filter is overworked and the frame rate is getting jerky.
4201+ * Massively increasing BOTH the process and thread priorities (need to boost
4202+ * the process priority to keep audio in sync with the increased thread
4203+ * priority when the frame rate gets jerky) beats Windows into giving the
4204+ * program the time it needs, however, doing things outside ScummVM may be
4205+ * sluggish. I recommend pausing ScummVM prior to shrinking from full-screen
4206+ * to a window, or before switching from ScummVM to some other task. Other
4207+ * than the above mentioned sluggishness, I have not seen any other sort of
4208+ * system instability while running with increased priorities.
4209+ *
4210+ */
4211+
4212+/* Rather than check for all Win32 compiler flavors, just check for WIN32 and
4213+ * PRIORITY defines.
4214+ */
4215+#if defined WIN32 && defined(HIGH_PRIORITY_CLASS) && defined(THREAD_PRIORITY_TIME_CRITICAL)
4216+
4217+ /* Raise task and thread priority under Win32 */
4218+ SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
4219+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
4220+#endif
4221+#endif
4222+}
4223+
4224+
4225+
4226+/*
4227+ * Resize old src and dst arrays. Also check for problems that require full
4228+ * redraws, rather than using the unchanged pixel buffering. If the ScummVM
4229+ * backend evolves to draw even more things outside the filter than it
4230+ * currently does, some more checks may need to be added, or external flags
4231+ * set in the backend to tell the filter to redraw everything without using
4232+ * the unchanged pixel buffers. The current checks seem to catch everything
4233+ * for now....
4234+ *
4235+ */
4236+void resize_old_arrays(const uint8 *src, uint8 *dst,
4237+ int w, int h, int scale)
4238+{
4239+ int w2, h2;
4240+ int32 size, max_scaled_size;
4241+ const uint16 *sptr16 = (const uint16 *) src;
4242+ int overlay_flag = 0;
4243+ int skip_unchanged_pixels_flag;
4244+
4245+ if (sptr16 < src_addr_min || sptr16 > src_addr_max)
4246+ overlay_flag = 1;
4247+
4248+ if (scale > max_scale) max_scale = scale;
4249+
4250+ /* Deal with overlays */
4251+ if (overlay_flag)
4252+ {
4253+ skip_unchanged_pixels_flag = 1;
4254+
4255+ w2 = w + 2;
4256+ h2 = h + 2;
4257+ size = w2 * h2;
4258+
4259+ if (size > max_overlay_size)
4260+ {
4261+ max_overlay_size = size;
4262+ old_overlay = (uint16 *) realloc(old_overlay,
4263+ size * sizeof(uint16));
4264+
4265+ skip_unchanged_pixels_flag = 0;
4266+ }
4267+
4268+ max_scaled_size = max_scale * max_scale * max_overlay_size;
4269+
4270+ if (max_scaled_size > max_dst_overlay_size)
4271+ {
4272+ max_dst_overlay_size = max_scaled_size;
4273+ old_dst_overlay = (uint16 *) realloc(old_dst_overlay,
4274+ max_scaled_size * sizeof(uint16));
4275+
4276+ skip_unchanged_pixels_flag = 0;
4277+ }
4278+
4279+ cur_overlay_width = w;
4280+ cur_overlay_height = h;
4281+ cur_dst_overlay_width = w * scale;
4282+ cur_dst_overlay_height = h * scale;
4283+ if (cur_overlay_width != old_overlay_width ||
4284+ cur_overlay_height != old_overlay_height ||
4285+ cur_dst_overlay_width != old_dst_overlay_width ||
4286+ cur_dst_overlay_height != old_dst_overlay_height)
4287+ {
4288+ skip_unchanged_pixels_flag = 0;
4289+ }
4290+ old_overlay_width = cur_overlay_width;
4291+ old_overlay_height = cur_overlay_height;
4292+ old_dst_overlay_width = cur_dst_overlay_width;
4293+ old_dst_overlay_height = cur_dst_overlay_height;
4294+
4295+ if (skip_unchanged_pixels_flag == 0)
4296+ {
4297+ memset(old_overlay, 0, max_overlay_size * sizeof(uint16));
4298+ memset(old_dst_overlay, 0, max_dst_overlay_size * sizeof(uint16));
4299+ }
4300+ }
4301+ else
4302+ {
4303+ w2 = cur_screen_width + 2;
4304+ h2 = cur_screen_height + 2;
4305+ size = w2 * h2;
4306+ }
4307+
4308+ skip_unchanged_pixels_flag = 1;
4309+
4310+ if (overlay_flag == 0 && size > max_old_src_size)
4311+ {
4312+ max_old_src_size = size;
4313+ old_src = (uint16 *) realloc(old_src, size * sizeof(uint16));
4314+
4315+ skip_unchanged_pixels_flag = 0;
4316+ }
4317+
4318+ max_scaled_size = max_scale * max_scale * max_old_src_size;
4319+
4320+ if (overlay_flag == 0 && max_scaled_size > max_old_dst_size)
4321+ {
4322+ max_old_dst_size = max_scaled_size;
4323+ old_dst = (uint16 *) realloc(old_dst,
4324+ max_scaled_size * sizeof(uint16));
4325+
4326+ skip_unchanged_pixels_flag = 0;
4327+ }
4328+
4329+ /* screen dimensions have changed */
4330+ if (cur_screen_width != old_screen_width ||
4331+ cur_screen_height != old_screen_height)
4332+ {
4333+ skip_unchanged_pixels_flag = 0;
4334+ }
4335+ old_screen_width = cur_screen_width;
4336+ old_screen_height = cur_screen_height;
4337+
4338+ cur_dst_screen_width = cur_screen_width * scale;
4339+ cur_dst_screen_height = cur_screen_height * scale;
4340+ if (cur_dst_screen_width != old_dst_screen_width ||
4341+ cur_dst_screen_height != old_dst_screen_height)
4342+ {
4343+ skip_unchanged_pixels_flag = 0;
4344+ }
4345+ old_dst_screen_width = cur_dst_screen_width;
4346+ old_dst_screen_height = cur_dst_screen_height;
4347+
4348+ /* set all the buffers to 0, so that everything gets redrawn */
4349+ if (skip_unchanged_pixels_flag == 0)
4350+ {
4351+ memset(old_src, 0, max_old_src_size * sizeof(uint16));
4352+ memset(old_dst, 0, max_old_dst_size * sizeof(uint16));
4353+ memset(old_overlay, 0, max_overlay_size * sizeof(uint16));
4354+ memset(old_dst_overlay, 0, max_dst_overlay_size * sizeof(uint16));
4355+ }
4356+}
4357+
4358+
4359+
4360+/* Fill old src array, which is used in checking for unchanged pixels */
4361+void fill_old_src(const uint8 *src, int srcPitch, int w, int h)
4362+{
4363+ int x, y;
4364+ int x2, y2;
4365+ const uint16 *sptr16 = (const uint16 *) src;
4366+ const uint16 *sptr2;
4367+ uint16 *optr16;
4368+ int32 screen_width2 = cur_screen_width + 2;
4369+ int32 dist = src - (const uint8 *) src_addr_min;
4370+ int32 x_fudge;
4371+ int32 src_fudge;
4372+
4373+ /* Deal with overlays */
4374+ if (sptr16 < src_addr_min || sptr16 > src_addr_max)
4375+ {
4376+ w += 2;
4377+ h += 2;
4378+
4379+ optr16 = old_overlay;
4380+ sptr2 = (const uint16 *) (src - srcPitch) - 1;
4381+
4382+ x_fudge = 0;
4383+ src_fudge = srcPitch - w - w;
4384+ }
4385+ else
4386+ {
4387+ y = dist / srcPitch;
4388+ x = (dist - y * srcPitch) >> 1;
4389+
4390+ optr16 = old_src + (y + 1) * screen_width2 + x + 1;
4391+ sptr2 = (const uint16 *) src;
4392+
4393+ x_fudge = screen_width2 - w;
4394+ src_fudge = srcPitch - w - w;
4395+ }
4396+
4397+ for (y2 = 0; y2 < h; y2++)
4398+ {
4399+ for (x2 = 0; x2 < w; x2++)
4400+ *optr16++ = *sptr2++;
4401+
4402+ optr16 += x_fudge;
4403+ sptr2 = (const uint16 *) ((const uint8 *) sptr2 + src_fudge);
4404+ }
4405+}
4406+
4407+
4408+
4409+/* Fill old dst array, which is used in drawing unchanged pixels */
4410+void fill_old_dst(const uint8 *src, uint8 *dst, int srcPitch, int dstPitch,
4411+ int w, int h, int scale)
4412+{
4413+ int x, y;
4414+ int x2, y2;
4415+
4416+ const uint16 *sptr16 = (const uint16 *) src;
4417+ uint16 *dptr2;
4418+ uint16 *optr16;
4419+ int32 screen_width_scaled = cur_screen_width * scale;
4420+ int32 dist;
4421+ int w_new = w * scale;
4422+ int h_new = h * scale;
4423+ int32 x_fudge;
4424+ int32 dst_fudge;
4425+
4426+ /* Deal with overlays */
4427+ if (sptr16 < src_addr_min || sptr16 > src_addr_max)
4428+ {
4429+ optr16 = old_dst_overlay;
4430+ dptr2 = (uint16 *) dst;
4431+ x_fudge = 0;
4432+ dst_fudge = dstPitch - w_new - w_new;
4433+ }
4434+ else
4435+ {
4436+ dist = src - (const uint8 *) src_addr_min;
4437+ y = dist / srcPitch;
4438+ x = (dist - y * srcPitch) >> 1;
4439+
4440+ optr16 = old_dst + scale * (y * screen_width_scaled + x);
4441+ dptr2 = (uint16 *) dst;
4442+
4443+ x_fudge = screen_width_scaled - w_new;
4444+ dst_fudge = dstPitch - w_new - w_new;
4445+ }
4446+
4447+ for (y2 = 0; y2 < h_new; y2++)
4448+ {
4449+ for (x2 = 0; x2 < w_new; x2++)
4450+ *optr16++ = *dptr2++;
4451+
4452+ optr16 += x_fudge;
4453+ dptr2 = (uint16 *) ((uint8 *) dptr2 + dst_fudge);
4454+ }
4455+}
4456+
4457+
4458+
4459+/* 3x anti-aliased resize filter, nearest-neighbor anti-aliasing */
4460+void Edge3x(const uint8 *srcPtr, uint32 srcPitch,
4461+ uint8 *dstPtr, uint32 dstPitch, int width, int height)
4462+{
4463+ /* Initialize stuff */
4464+ if (!init_flag)
4465+ {
4466+ cur_screen_width = g_system->getWidth();
4467+ cur_screen_height = g_system->getHeight();
4468+
4469+ /* set initial best guess on min/max screen addresses */
4470+ /* indent by 1 in case only the mouse is ever drawn */
4471+ src_addr_min = (const uint16 *) srcPtr + 1;
4472+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) *
4473+ srcPitch)) + (width - 1) - 1;
4474+
4475+ init_tables(srcPtr, srcPitch, width, height);
4476+ init_flag = 1;
4477+ }
4478+
4479+ /* Uh oh, the screen size has changed */
4480+ if (cur_screen_width != g_system->getWidth() ||
4481+ cur_screen_height != g_system->getHeight())
4482+ {
4483+ cur_screen_width = g_system->getWidth();
4484+ cur_screen_height = g_system->getHeight();
4485+ src_addr_min = (const uint16 *) srcPtr;
4486+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4487+ (width - 1);
4488+ }
4489+
4490+ /* Ah ha, we're doing the whole screen, so we can save the bounds of the
4491+ src array for later bounds checking */
4492+ if (width == g_system->getWidth() &&
4493+ height == g_system->getHeight())
4494+ {
4495+ src_addr_min = (const uint16 *) srcPtr;
4496+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4497+ (width - 1);
4498+ }
4499+
4500+ /* resize and/or blank the old src and dst array */
4501+ resize_old_arrays(srcPtr, dstPtr, width, height, 3);
4502+
4503+ /* Hmm, the src address isn't within the proper bounds.
4504+ * We're probably drawing an overlay now.
4505+ */
4506+ if ((const uint16 *) srcPtr < src_addr_min ||
4507+ (const uint16 *) srcPtr > src_addr_max)
4508+ {
4509+ anti_alias_pass_3x(srcPtr, dstPtr, width, height,
4510+ 3*width, 3*height, srcPitch, dstPitch, 1);
4511+ }
4512+ else /* Draw the regular screen, this isn't an overlay. */
4513+ {
4514+ anti_alias_pass_3x(srcPtr, dstPtr, width, height,
4515+ 3*width, 3*height, srcPitch, dstPitch, 0);
4516+ }
4517+
4518+ /* fill old src array */
4519+ fill_old_src(srcPtr, srcPitch, width, height);
4520+ fill_old_dst(srcPtr, dstPtr, srcPitch, dstPitch, width, height, 3);
4521+}
4522+
4523+
4524+
4525+/* 2x anti-aliased resize filter, nearest-neighbor anti-aliasing */
4526+void Edge2x(const uint8 *srcPtr, uint32 srcPitch,
4527+ uint8 *dstPtr, uint32 dstPitch, int width, int height)
4528+{
4529+ /* Initialize stuff */
4530+ if (!init_flag)
4531+ {
4532+ cur_screen_width = g_system->getWidth();
4533+ cur_screen_height = g_system->getHeight();
4534+
4535+ /* set initial best guess on min/max screen addresses */
4536+ /* indent by 1 in case only the mouse is ever drawn */
4537+ src_addr_min = (const uint16 *) srcPtr + 1;
4538+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) *
4539+ srcPitch)) + (width - 1) - 1;
4540+
4541+ init_tables(srcPtr, srcPitch, width, height);
4542+ init_flag = 1;
4543+ }
4544+
4545+ /* Uh oh, the screen size has changed */
4546+ if (cur_screen_width != g_system->getWidth() ||
4547+ cur_screen_height != g_system->getHeight())
4548+ {
4549+ cur_screen_width = g_system->getWidth();
4550+ cur_screen_height = g_system->getHeight();
4551+ src_addr_min = (const uint16 *) srcPtr;
4552+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4553+ (width - 1);
4554+ }
4555+
4556+ /* Ah ha, we're doing the whole screen, so we can save the bounds of the
4557+ src array for later bounds checking */
4558+ if (width == g_system->getWidth() &&
4559+ height == g_system->getHeight())
4560+ {
4561+ src_addr_min = (const uint16 *) srcPtr;
4562+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4563+ (width - 1);
4564+ }
4565+
4566+ /* resize and/or blank the old src and dst array */
4567+ resize_old_arrays(srcPtr, dstPtr, width, height, 2);
4568+
4569+ /* Hmm, the src address isn't within the proper bounds.
4570+ * We're probably drawing an overlay now.
4571+ */
4572+ if ((const uint16 *) srcPtr < src_addr_min ||
4573+ (const uint16 *) srcPtr > src_addr_max)
4574+ {
4575+ anti_alias_pass_2x(srcPtr, dstPtr, width, height,
4576+ 2*width, 2*height, srcPitch, dstPitch, 1, 0);
4577+ }
4578+ else /* Draw the regular screen, this isn't an overlay. */
4579+ {
4580+ anti_alias_pass_2x(srcPtr, dstPtr, width, height,
4581+ 2*width, 2*height, srcPitch, dstPitch, 0, 0);
4582+ }
4583+
4584+ /* fill old src array */
4585+ fill_old_src(srcPtr, srcPitch, width, height);
4586+ fill_old_dst(srcPtr, dstPtr, srcPitch, dstPitch, width, height, 2);
4587+}
4588+
4589+
4590+
4591+/*
4592+ * 2x anti-aliased resize filter, interpolation based anti-aliasing.
4593+ * This is useful prior to upsizing with the 1.5x filter for the menu
4594+ * overlay. Nearest-neighbor looks bad with 1.5x resize. Interpolated gives
4595+ * results that look good, like a somewhat blurry Edge3x.
4596+ *
4597+ */
4598+void Edge2x_Interp(const uint8 *srcPtr, uint32 srcPitch,
4599+ uint8 *dstPtr, uint32 dstPitch, int width, int height)
4600+{
4601+ /* Initialize stuff */
4602+ if (!init_flag)
4603+ {
4604+ cur_screen_width = g_system->getWidth();
4605+ cur_screen_height = g_system->getHeight();
4606+
4607+ /* set initial best guess on min/max screen addresses */
4608+ /* indent by 1 in case only the mouse is ever drawn */
4609+ src_addr_min = (const uint16 *) srcPtr + 1;
4610+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) *
4611+ srcPitch)) + (width - 1) - 1;
4612+
4613+ init_tables(srcPtr, srcPitch, width, height);
4614+ init_flag = 1;
4615+ }
4616+
4617+ /* Uh oh, the screen size has changed */
4618+ if (cur_screen_width != g_system->getWidth() ||
4619+ cur_screen_height != g_system->getHeight())
4620+ {
4621+ cur_screen_width = g_system->getWidth();
4622+ cur_screen_height = g_system->getHeight();
4623+ src_addr_min = (const uint16 *) srcPtr;
4624+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4625+ (width - 1);
4626+ }
4627+
4628+ /* Ah ha, we're doing the whole screen, so we can save the bounds of the
4629+ src array for later bounds checking */
4630+ if (width == g_system->getWidth() &&
4631+ height == g_system->getHeight())
4632+ {
4633+ src_addr_min = (const uint16 *) srcPtr;
4634+ src_addr_max = ((const uint16 *) (srcPtr + (height - 1) * srcPitch)) +
4635+ (width - 1);
4636+ }
4637+
4638+ /* resize and/or blank the old src and dst array */
4639+ resize_old_arrays(srcPtr, dstPtr, width, height, 2);
4640+
4641+ /* Hmm, the src address isn't within the proper bounds.
4642+ * We're probably drawing an overlay now.
4643+ */
4644+ if ((const uint16 *) srcPtr < src_addr_min ||
4645+ (const uint16 *) srcPtr > src_addr_max)
4646+ {
4647+ anti_alias_pass_2x(srcPtr, dstPtr, width, height,
4648+ 2*width, 2*height, srcPitch, dstPitch, 1, 0);
4649+ }
4650+ else /* Draw the regular screen, this isn't an overlay. */
4651+ {
4652+ anti_alias_pass_2x(srcPtr, dstPtr, width, height,
4653+ 2*width, 2*height, srcPitch, dstPitch, 0, 1);
4654+ }
4655+
4656+ /* fill old src array */
4657+ fill_old_src(srcPtr, srcPitch, width, height);
4658+ fill_old_dst(srcPtr, dstPtr, srcPitch, dstPitch, width, height, 2);
4659+}
4660diff -ruN -b backup_version/graphics/scaler.h new_version/graphics/scaler.h
4661--- backup_version/graphics/scaler.h 2006-07-30 00:48:00.000000000 -0500
4662+++ new_version/graphics/scaler.h 2006-07-31 04:29:20.000000000 -0500
4663@@ -46,6 +46,9 @@
4664 DECLARE_SCALER(Normal1o5x);
4665 DECLARE_SCALER(TV2x);
4666 DECLARE_SCALER(DotMatrix);
4667+DECLARE_SCALER(Edge2x);
4668+DECLARE_SCALER(Edge2x_Interp);
4669+DECLARE_SCALER(Edge3x);
4670
4671 #ifndef DISABLE_HQ_SCALERS
4672 DECLARE_SCALER(HQ2x);