1 /* scalers.c: the actual graphics scalers
2  * Copyright (C) 2003-2008 Fredrick Meunier, Philip Kendall, Gergely Szasz
3  *
4  * $Id: scalers.c 4624 2012-01-09 20:59:35Z pak21 $
5  *
6  * Originally taken from ScummVM - Scumm Interpreter
7  * Copyright (C) 2001  Ludvig Strigeus
8  * Copyright (C) 2001-2003 The ScummVM project
9  *
10  * HQ2x and HQ3x scalers taken from HiEnd3D Demos (http://www.hiend3d.com)
11  * Copyright (C) 2003 MaxSt ( maxst@hiend3d.com )
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22 
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
26  *
27  */
28 
29 #include <config.h>
30 
31 #include <string.h>
32 
33 #include <libspectrum.h>
34 
35 #include "scaler.h"
36 #include "scaler_internals.h"
37 #include "settings.h"
38 #include "ui/ui.h"
39 #include "ui/uidisplay.h"
40 
41 #ifndef MIN
42 #define MIN(a,b)    (((a) < (b)) ? (a) : (b))
43 #endif
44 
45 #ifndef ABS
46 #define ABS(x)     ((x)>=0?(x):-(x))
47 #endif
48 
49 /* The actual code for the scalers starts here */
50 
51 #if SCALER_DATA_SIZE == 2
52 
53 typedef libspectrum_word scaler_data_type;
54 #define FUNCTION( name ) name##_16
55 
56 static libspectrum_dword colorMask;
57 static libspectrum_dword lowPixelMask;
58 static libspectrum_dword qcolorMask;
59 static libspectrum_dword qlowpixelMask;
60 static libspectrum_dword redblueMask;
61 static libspectrum_dword redblue8_Mask;
62 static libspectrum_dword redblue16_Mask;
63 static libspectrum_dword redMask;
64 static libspectrum_dword greenMask;
65 static libspectrum_dword green8_Mask;
66 static libspectrum_dword green16_Mask;
67 static libspectrum_dword blueMask;
68 static int green6bit;
69 
70 static const libspectrum_word dotmatrix_565[16] = {
71   0x01E0, 0x0007, 0x3800, 0x0000,
72   0x39E7, 0x0000, 0x39E7, 0x0000,
73   0x3800, 0x0000, 0x01E0, 0x0007,
74   0x39E7, 0x0000, 0x39E7, 0x0000
75 };
76 static const libspectrum_word dotmatrix_555[16] = {
77   0x00E0, 0x0007, 0x1C00, 0x0000,
78   0x1CE7, 0x0000, 0x1CE7, 0x0000,
79   0x1C00, 0x0000, 0x00E0, 0x0007,
80   0x1CE7, 0x0000, 0x1CE7, 0x0000
81 };
82 static const libspectrum_word *dotmatrix;
83 
84 int
scaler_select_bitformat(libspectrum_dword BitFormat)85 scaler_select_bitformat( libspectrum_dword BitFormat )
86 {
87   switch( BitFormat ) {
88 
89     /* FIXME(?): there is an assumption here that our colour fields
90        are (*) xxxx|xyyy|yyyz|zzzz for the 565 mode
91        and (*) xxxx|xyyy|yyzz|zzz0 for the 555 mode, where (*) is the
92        least significant bit on LSB machines and the most significant
93        bit on MSB machines. This is currently (April 2003) OK as the
94        only user interface to use this code is SDL, which hides all
95        variation in SDL_MapRGB(3), but be very careful (especially
96        about endianness) if we ever use the "interpolating" scalers
97        from another user interface */
98 
99   case 565:
100     colorMask = 0x0000F7DE;
101     lowPixelMask = 0x00000821;
102     qcolorMask = 0x0000E79C;
103     qlowpixelMask = 0x00001863;
104     redblueMask = 0x0000F81F;
105     redblue8_Mask = 0x0007C0F8;
106     redblue16_Mask = 0x000F81F0;
107     green6bit = 1;
108     redMask   = 0x0000001F;
109     greenMask = 0x000007E0;
110     green8_Mask = 0x00003F00;
111     green16_Mask = 0x00007E00;
112     blueMask  = 0x0000F800;
113     dotmatrix = dotmatrix_565;
114     break;
115 
116   case 555:
117     colorMask = 0x00007BDE;
118     lowPixelMask = 0x00000421;
119     qcolorMask = 0x0000739C;
120     qlowpixelMask = 0x00000C63;
121     redblueMask = 0x00007C1F;
122     redblue8_Mask = 0x0003E0F8;
123     redblue16_Mask = 0x0007C1F0;
124     green6bit = 0;
125     redMask   = 0x0000001F;
126     greenMask = 0x000003E0;
127     green8_Mask = 0x00001F00;
128     green16_Mask = 0x00003E00;
129     blueMask  = 0x00007C00;
130     dotmatrix = dotmatrix_555;
131     break;
132 
133   default:
134     ui_error( UI_ERROR_ERROR, "unknown bitformat %d", BitFormat );
135     return 1;
136 
137   }
138 
139   return 0;
140 }
141 
142 #elif SCALER_DATA_SIZE == 4	/* #if SCALER_DATA_SIZE == 2 */
143 
144 typedef libspectrum_dword scaler_data_type;
145 #define FUNCTION( name ) name##_32
146 
147 /* The assumption here is that the colour fields are laid out in
148    memory as (LSB) red|green|blue|padding (MSB). We wish to access
149    these as 32-bit entities, so make sure we get our masks the right
150    way round. */
151 
152 #ifdef WORDS_BIGENDIAN
153 
154 static const libspectrum_dword colorMask = 0xFEFEFE00;
155 static const libspectrum_dword lowPixelMask = 0x01010100;
156 static const libspectrum_dword qcolorMask = 0xFCFCFC00;
157 static const libspectrum_dword qlowpixelMask = 0x03030300;
158 static const libspectrum_qword redblueMask = 0xFF00FF00;
159 static const libspectrum_dword redblue8_Mask = 0xF807F807;
160 static const libspectrum_dword redblue16_Mask = 0x0FF00FF0;
161 static const libspectrum_dword redMask =   0xFF000000;
162 static const libspectrum_dword greenMask = 0x00FF0000;
163 static const libspectrum_dword blueMask =  0x0000FF00;
164 static const libspectrum_dword green8_Mask = 0x008F0700;
165 static const libspectrum_dword green16_Mask = 0x000FF000;
166 
167 static const libspectrum_dword dotmatrix[16] = {
168   0x003F0000, 0x00003F00, 0x3F000000, 0x00000000,
169   0x3F3F3F00, 0x00000000, 0x3F3F3F00, 0x00000000,
170   0x3F000000, 0x00000000, 0x003F0000, 0x00003F00,
171   0x3F3F3F00, 0x00000000, 0x3F3F3F00, 0x00000000
172 };
173 
174 #else				/* #ifdef WORDS_BIGENDIAN */
175 
176 static const libspectrum_dword colorMask = 0x00FEFEFE;
177 static const libspectrum_dword lowPixelMask = 0x00010101;
178 static const libspectrum_dword qcolorMask = 0x00FCFCFC;
179 static const libspectrum_dword qlowpixelMask = 0x00030303;
180 static const libspectrum_qword redblueMask = 0x00FF00FF;
181 static const libspectrum_dword redblue8_Mask = 0x07F807F8;
182 static const libspectrum_dword redblue16_Mask = 0x0FF00FF0;
183 static const libspectrum_dword redMask =   0x000000FF;
184 static const libspectrum_dword greenMask = 0x0000FF00;
185 static const libspectrum_dword blueMask =  0x00FF0000;
186 static const libspectrum_dword green8_Mask = 0x0007F800;
187 static const libspectrum_dword green16_Mask = 0x000FF000;
188 
189 static const libspectrum_dword dotmatrix[16] = {
190   0x00003F00, 0x003F0000, 0x0000003F, 0x00000000,
191   0x003F3F3F, 0x00000000, 0x003F3F3F, 0x00000000,
192   0x0000003F, 0x00000000, 0x00003F00, 0x003F0000,
193   0x003F3F3F, 0x00000000, 0x003F3F3F, 0x00000000
194 };
195 
196 #endif				/* #ifdef WORDS_BIGENDIAN */
197 
198 #else				/* #if SCALER_DATA_SIZE == 2 or 4 */
199 #error Unknown SCALER_DATA_SIZE
200 #endif				/* #if SCALER_DATA_SIZE == 2 or 4 */
201 
202 static inline int
GetResult(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C,libspectrum_dword D)203 GetResult( libspectrum_dword A, libspectrum_dword B, libspectrum_dword C,
204 	   libspectrum_dword D )
205 {
206   const int ac = (A==C);
207   const int bc = (B==C);
208   const int x1 = ac;
209   const int y1 = (bc & !ac);
210   const int ad = (A==D);
211   const int bd = (B==D);
212   const int x2 = ad;
213   const int y2 = (bd & !ad);
214   const int x = x1+x2;
215   const int y = y1+y2;
216   static const int rmap[3][3] = {
217       {0, 0, -1},
218       {0, 0, -1},
219       {1, 1,  0}
220     };
221   return rmap[y][x];
222 }
223 
224 static inline libspectrum_dword
INTERPOLATE(libspectrum_dword A,libspectrum_dword B)225 INTERPOLATE( libspectrum_dword A, libspectrum_dword B )
226 {
227   if (A != B) {
228     return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask));
229   } else
230     return A;
231 }
232 
233 static inline libspectrum_dword
Q_INTERPOLATE(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C,libspectrum_dword D)234 Q_INTERPOLATE( libspectrum_dword A, libspectrum_dword B, libspectrum_dword C,
235 	       libspectrum_dword D )
236 {
237   register libspectrum_dword x = ((A & qcolorMask) >> 2) +
238   ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2);
239   register libspectrum_dword y = (A & qlowpixelMask) +
240   (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask);
241 
242   y = (y >> 2) & qlowpixelMask;
243   return x + y;
244 }
245 
246 /* HQ scalers */
247 #define HQ_INTERPOLATE_1(A,B) Q_INTERPOLATE(A,A,A,B)
248 
249 #define HQ_INTERPOLATE_2(A,B,C) Q_INTERPOLATE(A,A,B,C)
250 
251 static inline libspectrum_dword
HQ_INTERPOLATE_3(libspectrum_dword A,libspectrum_dword B)252 HQ_INTERPOLATE_3( libspectrum_dword A, libspectrum_dword B )
253 {
254   return ( ( ( ( A & greenMask ) * 7 + ( B & greenMask) ) & green8_Mask ) +
255          ( ( ( A & redblueMask ) * 7 + ( B & redblueMask ) ) & redblue8_Mask )
256          ) >> 3;
257 }
258 
259 static inline libspectrum_dword
HQ_INTERPOLATE_4(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C)260 HQ_INTERPOLATE_4( libspectrum_dword A, libspectrum_dword B,
261                   libspectrum_dword C )
262 {
263   return ( ( ( ( A & greenMask ) * 2 + ( ( B & greenMask) +
264 		( C & greenMask ) ) * 7 ) & green16_Mask) +
265          ( ( ( A & redblueMask ) * 2 + ( ( B & redblueMask ) +
266 		( C & redblueMask ) ) * 7 ) & redblue16_Mask ) ) >> 4;
267 }
268 
269 #define HQ_INTERPOLATE_5(A,B) INTERPOLATE(A,B)
270 
271 static inline libspectrum_dword
HQ_INTERPOLATE_6(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C)272 HQ_INTERPOLATE_6( libspectrum_dword A, libspectrum_dword B,
273                   libspectrum_dword C )
274 {
275   return ( ( ( ( A & greenMask ) * 5 + ( B & greenMask) * 2 +
276 		( C & greenMask ) ) & green8_Mask) +
277          ( ( ( A & redblueMask ) * 5 + ( B & redblueMask ) * 2 +
278 		( C & redblueMask ) ) & redblue8_Mask ) ) >> 3;
279 }
280 
281 static inline libspectrum_dword
HQ_INTERPOLATE_7(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C)282 HQ_INTERPOLATE_7( libspectrum_dword A, libspectrum_dword B,
283                   libspectrum_dword C )
284 {
285   return ( ( ( ( A & greenMask ) * 6 + ( B & greenMask) +
286 		( C & greenMask ) ) & green8_Mask) +
287          ( ( ( A & redblueMask ) * 6 + ( B & redblueMask ) +
288 		( C & redblueMask ) ) & redblue8_Mask ) ) >> 3;
289 }
290 
291 static inline libspectrum_dword
HQ_INTERPOLATE_9(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C)292 HQ_INTERPOLATE_9( libspectrum_dword A, libspectrum_dword B,
293                   libspectrum_dword C )
294 {
295   return ( ( ( ( A & greenMask ) * 2 + ( ( B & greenMask) +
296 		( C & greenMask ) ) * 3 ) & green8_Mask) +
297          ( ( ( A & redblueMask ) * 2 + ( ( B & redblueMask ) +
298 		( C & redblueMask ) ) * 3 ) & redblue8_Mask ) ) >> 3;
299 }
300 
301 static inline libspectrum_dword
HQ_INTERPOLATE_10(libspectrum_dword A,libspectrum_dword B,libspectrum_dword C)302 HQ_INTERPOLATE_10( libspectrum_dword A, libspectrum_dword B,
303                    libspectrum_dword C )
304 {
305   return ( ( ( ( A & greenMask ) * 14 + ( B & greenMask) +
306 		( C & greenMask ) ) & green16_Mask) +
307          ( ( ( A & redblueMask ) * 14 + ( B & redblueMask ) +
308 		( C & redblueMask ) ) & redblue16_Mask ) ) >> 4;
309 }
310 
311 /* dstPtr */
312 #define HQ_PIXEL00_0     w[5]
313 #define HQ_PIXEL00_10    HQ_INTERPOLATE_1(w[5], w[1])
314 #define HQ_PIXEL00_11    HQ_INTERPOLATE_1(w[5], w[4])
315 #define HQ_PIXEL00_12    HQ_INTERPOLATE_1(w[5], w[2])
316 #define HQ_PIXEL00_20    HQ_INTERPOLATE_2(w[5], w[4], w[2])
317 #define HQ_PIXEL00_21    HQ_INTERPOLATE_2(w[5], w[1], w[2])
318 #define HQ_PIXEL00_22    HQ_INTERPOLATE_2(w[5], w[1], w[4])
319 #define HQ_PIXEL00_60    HQ_INTERPOLATE_6(w[5], w[2], w[4])
320 #define HQ_PIXEL00_61    HQ_INTERPOLATE_6(w[5], w[4], w[2])
321 #define HQ_PIXEL00_70    HQ_INTERPOLATE_7(w[5], w[4], w[2])
322 #define HQ_PIXEL00_90    HQ_INTERPOLATE_9(w[5], w[4], w[2])
323 #define HQ_PIXEL00_100   HQ_INTERPOLATE_10(w[5], w[4], w[2])
324 /* +1 */
325 #define HQ_PIXEL01_0     w[5]
326 #define HQ_PIXEL01_10    HQ_INTERPOLATE_1(w[5], w[3])
327 #define HQ_PIXEL01_11    HQ_INTERPOLATE_1(w[5], w[2])
328 #define HQ_PIXEL01_12    HQ_INTERPOLATE_1(w[5], w[6])
329 #define HQ_PIXEL01_20    HQ_INTERPOLATE_2(w[5], w[2], w[6])
330 #define HQ_PIXEL01_21    HQ_INTERPOLATE_2(w[5], w[3], w[6])
331 #define HQ_PIXEL01_22    HQ_INTERPOLATE_2(w[5], w[3], w[2])
332 #define HQ_PIXEL01_60    HQ_INTERPOLATE_6(w[5], w[6], w[2])
333 #define HQ_PIXEL01_61    HQ_INTERPOLATE_6(w[5], w[2], w[6])
334 #define HQ_PIXEL01_70    HQ_INTERPOLATE_7(w[5], w[2], w[6])
335 #define HQ_PIXEL01_90    HQ_INTERPOLATE_9(w[5], w[2], w[6])
336 #define HQ_PIXEL01_100   HQ_INTERPOLATE_10(w[5], w[2], w[6])
337 /* +dstPitch */
338 #define HQ_PIXEL10_0     w[5]
339 #define HQ_PIXEL10_10    HQ_INTERPOLATE_1(w[5], w[7])
340 #define HQ_PIXEL10_11    HQ_INTERPOLATE_1(w[5], w[8])
341 #define HQ_PIXEL10_12    HQ_INTERPOLATE_1(w[5], w[4])
342 #define HQ_PIXEL10_20    HQ_INTERPOLATE_2(w[5], w[8], w[4])
343 #define HQ_PIXEL10_21    HQ_INTERPOLATE_2(w[5], w[7], w[4])
344 #define HQ_PIXEL10_22    HQ_INTERPOLATE_2(w[5], w[7], w[8])
345 #define HQ_PIXEL10_60    HQ_INTERPOLATE_6(w[5], w[4], w[8])
346 #define HQ_PIXEL10_61    HQ_INTERPOLATE_6(w[5], w[8], w[4])
347 #define HQ_PIXEL10_70    HQ_INTERPOLATE_7(w[5], w[8], w[4])
348 #define HQ_PIXEL10_90    HQ_INTERPOLATE_9(w[5], w[8], w[4])
349 #define HQ_PIXEL10_100   HQ_INTERPOLATE_10(w[5], w[8], w[4])
350 /* +dstPitch+1*/
351 #define HQ_PIXEL11_0     w[5]
352 #define HQ_PIXEL11_10    HQ_INTERPOLATE_1(w[5], w[9])
353 #define HQ_PIXEL11_11    HQ_INTERPOLATE_1(w[5], w[6])
354 #define HQ_PIXEL11_12    HQ_INTERPOLATE_1(w[5], w[8])
355 #define HQ_PIXEL11_20    HQ_INTERPOLATE_2(w[5], w[6], w[8])
356 #define HQ_PIXEL11_21    HQ_INTERPOLATE_2(w[5], w[9], w[8])
357 #define HQ_PIXEL11_22    HQ_INTERPOLATE_2(w[5], w[9], w[6])
358 #define HQ_PIXEL11_60    HQ_INTERPOLATE_6(w[5], w[8], w[6])
359 #define HQ_PIXEL11_61    HQ_INTERPOLATE_6(w[5], w[6], w[8])
360 #define HQ_PIXEL11_70    HQ_INTERPOLATE_7(w[5], w[6], w[8])
361 #define HQ_PIXEL11_90    HQ_INTERPOLATE_9(w[5], w[6], w[8])
362 #define HQ_PIXEL11_100   HQ_INTERPOLATE_10(w[5], w[6], w[8])
363 
364 /* dstPtr */
365 #define HQ_PIXEL00_1M  HQ_INTERPOLATE_1(w[5], w[1])
366 #define HQ_PIXEL00_1U  HQ_INTERPOLATE_1(w[5], w[2])
367 #define HQ_PIXEL00_1L  HQ_INTERPOLATE_1(w[5], w[4])
368 #define HQ_PIXEL00_2   HQ_INTERPOLATE_2(w[5], w[4], w[2])
369 #define HQ_PIXEL00_4   HQ_INTERPOLATE_4(w[5], w[4], w[2])
370 #define HQ_PIXEL00_5   HQ_INTERPOLATE_5(w[4], w[2])
371 #define HQ_PIXEL00_C   w[5]
372 /* dstPtr+1*/
373 #define HQ_PIXEL01_1   HQ_INTERPOLATE_1(w[5], w[2])
374 #define HQ_PIXEL01_3   HQ_INTERPOLATE_3(w[5], w[2])
375 #define HQ_PIXEL01_6   HQ_INTERPOLATE_1(w[2], w[5])
376 #define HQ_PIXEL01_C   w[5]
377 /* dstPtr+2*/
378 #define HQ_PIXEL02_1M  HQ_INTERPOLATE_1(w[5], w[3])
379 #define HQ_PIXEL02_1U  HQ_INTERPOLATE_1(w[5], w[2])
380 #define HQ_PIXEL02_1R  HQ_INTERPOLATE_1(w[5], w[6])
381 #define HQ_PIXEL02_2   HQ_INTERPOLATE_2(w[5], w[2], w[6])
382 #define HQ_PIXEL02_4   HQ_INTERPOLATE_4(w[5], w[2], w[6])
383 #define HQ_PIXEL02_5   HQ_INTERPOLATE_5(w[2], w[6])
384 #define HQ_PIXEL02_C   w[5]
385 /* + dstPitch*/
386 #define HQ_PIXEL10_1   HQ_INTERPOLATE_1(w[5], w[4])
387 #define HQ_PIXEL10_3   HQ_INTERPOLATE_3(w[5], w[4])
388 #define HQ_PIXEL10_6   HQ_INTERPOLATE_1(w[4], w[5])
389 #define HQ_PIXEL10_C   w[5]
390 /* + dstPitch + 1 */
391 #define HQ_PIXEL11     w[5]
392 /* + dstPitch + 2 */
393 #define HQ_PIXEL12_1   HQ_INTERPOLATE_1(w[5], w[6])
394 #define HQ_PIXEL12_3   HQ_INTERPOLATE_3(w[5], w[6])
395 #define HQ_PIXEL12_6   HQ_INTERPOLATE_1(w[6], w[5])
396 #define HQ_PIXEL12_C   w[5]
397 /* + 2*dstPitch */
398 #define HQ_PIXEL20_1M  HQ_INTERPOLATE_1(w[5], w[7])
399 #define HQ_PIXEL20_1D  HQ_INTERPOLATE_1(w[5], w[8])
400 #define HQ_PIXEL20_1L  HQ_INTERPOLATE_1(w[5], w[4])
401 #define HQ_PIXEL20_2   HQ_INTERPOLATE_2(w[5], w[8], w[4])
402 #define HQ_PIXEL20_4   HQ_INTERPOLATE_4(w[5], w[8], w[4])
403 #define HQ_PIXEL20_5   HQ_INTERPOLATE_5(w[8], w[4])
404 #define HQ_PIXEL20_C   w[5]
405 /* + 2*dstPitch + 1 */
406 #define HQ_PIXEL21_1   HQ_INTERPOLATE_1(w[5], w[8])
407 #define HQ_PIXEL21_3   HQ_INTERPOLATE_3(w[5], w[8])
408 #define HQ_PIXEL21_6   HQ_INTERPOLATE_1(w[8], w[5])
409 #define HQ_PIXEL21_C   w[5]
410 /* + 2*dstPitch + 2 */
411 #define HQ_PIXEL22_1M  HQ_INTERPOLATE_1(w[5], w[9])
412 #define HQ_PIXEL22_1D  HQ_INTERPOLATE_1(w[5], w[8])
413 #define HQ_PIXEL22_1R  HQ_INTERPOLATE_1(w[5], w[6])
414 #define HQ_PIXEL22_2   HQ_INTERPOLATE_2(w[5], w[6], w[8])
415 #define HQ_PIXEL22_4   HQ_INTERPOLATE_4(w[5], w[6], w[8])
416 #define HQ_PIXEL22_5   HQ_INTERPOLATE_5(w[6], w[8])
417 #define HQ_PIXEL22_C   w[5]
418 
419 #define HQ_trY 0x00000030
420 #define HQ_trU 0x00000007
421 #define HQ_trV 0x00000006
422 
423 #define HQ_YUVDIFF(y1,u1,v1,y2,u2,v2) \
424   ( ( ABS( y1 - y2 ) > HQ_trY ) || \
425     ( ABS( u1 - u2 ) > HQ_trU ) || \
426     ( ABS( v1 - v2 ) > HQ_trV ) )
427 
428 void
FUNCTION(scaler_Super2xSaI)429 FUNCTION( scaler_Super2xSaI )( const libspectrum_byte *srcPtr,
430 			       libspectrum_dword srcPitch,
431 			       libspectrum_byte *dstPtr,
432 			       libspectrum_dword dstPitch,
433 			       int width, int height )
434 {
435   const scaler_data_type *bP;
436   scaler_data_type *dP;
437 
438   {
439     const libspectrum_dword nextlineSrc = srcPitch / sizeof( scaler_data_type );
440     libspectrum_dword nextDstLine = dstPitch / sizeof( scaler_data_type );
441     size_t i;
442 
443     while (height--) {
444       bP = (const scaler_data_type*)srcPtr;
445       dP = (scaler_data_type*)dstPtr;
446 
447       for( i = 0; i < width; ++i ) {
448 	libspectrum_dword color4, color5, color6;
449 	libspectrum_dword color1, color2, color3;
450 	libspectrum_dword colorA0, colorA1, colorA2, colorA3, colorB0, colorB1, colorB2,
451 	 colorB3, colorS1, colorS2;
452 	libspectrum_dword product1a, product1b, product2a, product2b;
453 
454 /*---------------------------------------    B1 B2
455                                            4  5  6 S2
456                                            1  2  3 S1
457 	                                     A1 A2
458 */
459 
460         colorB0 = *(bP - nextlineSrc - 1);
461 	colorB1 = *(bP - nextlineSrc);
462 	colorB2 = *(bP - nextlineSrc + 1);
463 	colorB3 = *(bP - nextlineSrc + 2);
464 
465 	color4 = *(bP - 1);
466 	color5 = *(bP);
467 	color6 = *(bP + 1);
468 	colorS2 = *(bP + 2);
469 
470 	color1 = *(bP + nextlineSrc - 1);
471 	color2 = *(bP + nextlineSrc);
472 	color3 = *(bP + nextlineSrc + 1);
473 	colorS1 = *(bP + nextlineSrc + 2);
474 
475 	colorA0 = *(bP + 2 * nextlineSrc - 1);
476 	colorA1 = *(bP + 2 * nextlineSrc);
477 	colorA2 = *(bP + 2 * nextlineSrc + 1);
478 	colorA3 = *(bP + 2 * nextlineSrc + 2);
479 
480 /*--------------------------------------*/
481 	if (color2 == color6 && color5 != color3) {
482 	  product2b = product1b = color2;
483 	} else if (color5 == color3 && color2 != color6) {
484 	  product2b = product1b = color5;
485 	} else if (color5 == color3 && color2 == color6) {
486 	  register int r = 0;
487 
488 	  r += GetResult(color6, color5, color1, colorA1);
489 	  r += GetResult(color6, color5, color4, colorB1);
490 	  r += GetResult(color6, color5, colorA2, colorS1);
491 	  r += GetResult(color6, color5, colorB2, colorS2);
492 
493 	  if (r > 0)
494 	    product2b = product1b = color6;
495 	  else if (r < 0)
496 	    product2b = product1b = color5;
497 	  else {
498 	    product2b = product1b = INTERPOLATE(color5, color6);
499 	  }
500 	} else {
501 	  if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0)
502 	    product2b = Q_INTERPOLATE(color3, color3, color3, color2);
503 	  else if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3)
504 	    product2b = Q_INTERPOLATE(color2, color2, color2, color3);
505 	  else
506 	    product2b = INTERPOLATE(color2, color3);
507 
508 	  if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0)
509 	    product1b = Q_INTERPOLATE(color6, color6, color6, color5);
510 	  else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3)
511 	    product1b = Q_INTERPOLATE(color6, color5, color5, color5);
512 	  else
513 	    product1b = INTERPOLATE(color5, color6);
514 	}
515 
516 	if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2)
517 	  product2a = INTERPOLATE(color2, color5);
518 	else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0)
519 	  product2a = INTERPOLATE(color2, color5);
520 	else
521 	  product2a = color2;
522 
523 	if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2)
524 	  product1a = INTERPOLATE(color2, color5);
525 	else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0)
526 	  product1a = INTERPOLATE(color2, color5);
527 	else
528 	  product1a = color5;
529 
530 	*dP = (scaler_data_type)product1a;
531 	*(dP+nextDstLine) = (scaler_data_type)product2a;
532 	dP++;
533 	*dP = (scaler_data_type)product1b;
534 	*(dP+nextDstLine) = (scaler_data_type)product2b;
535 	dP++;
536 
537 	bP++;
538       }
539 
540       srcPtr += srcPitch;
541       dstPtr += dstPitch * 2;
542     }
543   }
544 }
545 
546 void
FUNCTION(scaler_SuperEagle)547 FUNCTION( scaler_SuperEagle )( const libspectrum_byte *srcPtr,
548 			       libspectrum_dword srcPitch,
549 			       libspectrum_byte *dstPtr,
550 			       libspectrum_dword dstPitch,
551 			       int width, int height )
552 {
553   const scaler_data_type *bP;
554   scaler_data_type *dP;
555 
556   {
557     size_t i;
558     const libspectrum_dword nextlineSrc = srcPitch / sizeof( scaler_data_type );
559     libspectrum_dword nextDstLine = dstPitch / sizeof( scaler_data_type );
560 
561     while (height--) {
562       bP = (const scaler_data_type*)srcPtr;
563       dP = (scaler_data_type*)dstPtr;
564       for( i = 0; i < width; ++i ) {
565 	libspectrum_dword color4, color5, color6;
566 	libspectrum_dword color1, color2, color3;
567 	libspectrum_dword colorA1, colorA2, colorB1, colorB2, colorS1, colorS2;
568 	libspectrum_dword product1a, product1b, product2a, product2b;
569 
570 	colorB1 = *(bP - nextlineSrc);
571 	colorB2 = *(bP - nextlineSrc + 1);
572 
573 	color4 = *(bP - 1);
574 	color5 = *(bP);
575 	color6 = *(bP + 1);
576 	colorS2 = *(bP + 2);
577 
578 	color1 = *(bP + nextlineSrc - 1);
579 	color2 = *(bP + nextlineSrc);
580 	color3 = *(bP + nextlineSrc + 1);
581 	colorS1 = *(bP + nextlineSrc + 2);
582 
583 	colorA1 = *(bP + 2 * nextlineSrc);
584 	colorA2 = *(bP + 2 * nextlineSrc + 1);
585 
586 	/* -------------------------------------- */
587         if (color5 != color3 )
588         {
589           if (color2 == color6)
590           {
591             product1b = product2a = color2;
592             if ((color1 == color2) || (color6 == colorB2)) {
593               product1a = INTERPOLATE(color2, color5);
594               product1a = INTERPOLATE(color2, product1a);
595             } else {
596               product1a = INTERPOLATE(color5, color6);
597             }
598 
599             if ((color6 == colorS2) || (color2 == colorA1)) {
600               product2b = INTERPOLATE(color2, color3);
601               product2b = INTERPOLATE(color2, product2b);
602             } else {
603               product2b = INTERPOLATE(color2, color3);
604             }
605           }
606           else
607           {
608             product2b = product1a = INTERPOLATE(color2, color6);
609             product2b = Q_INTERPOLATE(color3, color3, color3, product2b);
610             product1a = Q_INTERPOLATE(color5, color5, color5, product1a);
611 
612             product2a = product1b = INTERPOLATE(color5, color3);
613             product2a = Q_INTERPOLATE(color2, color2, color2, product2a);
614             product1b = Q_INTERPOLATE(color6, color6, color6, product1b);
615           }
616         }
617         else /*if (color5 == color3) */
618         {
619           if (color2 != color6)
620           {
621             product2b = product1a = color5;
622 
623             if ((colorB1 == color5) || (color3 == colorS1)) {
624               product1b = INTERPOLATE(color5, color6);
625               product1b = INTERPOLATE(color5, product1b);
626             } else {
627               product1b = INTERPOLATE(color5, color6);
628             }
629 
630             if ((color3 == colorA2) || (color4 == color5)) {
631               product2a = INTERPOLATE(color5, color2);
632               product2a = INTERPOLATE(color5, product2a);
633             } else {
634               product2a = INTERPOLATE(color2, color3);
635             }
636 
637           }
638           else /* if (color2 != color6) */
639           {
640             register int r = 0;
641 
642             r += GetResult(color6, color5, color1, colorA1);
643             r += GetResult(color6, color5, color4, colorB1);
644             r += GetResult(color6, color5, colorA2, colorS1);
645             r += GetResult(color6, color5, colorB2, colorS2);
646 
647             if (r > 0) {
648               product1b = product2a = color2;
649               product1a = product2b = INTERPOLATE(color5, color6);
650             } else if (r < 0) {
651               product2b = product1a = color5;
652               product1b = product2a = INTERPOLATE(color5, color6);
653             } else {
654               product2b = product1a = color5;
655               product1b = product2a = color2;
656             }
657           }
658 	}
659 
660 	*dP = (scaler_data_type)product1a;
661 	*(dP+nextDstLine) = (scaler_data_type)product2a;
662 	dP++;
663 	*dP = (scaler_data_type)product1b;
664 	*(dP+nextDstLine) = (scaler_data_type)product2b;
665 	dP++;
666 
667 	bP++;
668       }
669 
670       srcPtr += srcPitch;
671       dstPtr += dstPitch * 2;
672     }
673   }
674 }
675 
676 void
FUNCTION(scaler_2xSaI)677 FUNCTION( scaler_2xSaI )( const libspectrum_byte *srcPtr,
678 			  libspectrum_dword srcPitch, libspectrum_byte *dstPtr,
679 			  libspectrum_dword dstPitch,
680 			  int width, int height )
681 {
682   const scaler_data_type *bP;
683   scaler_data_type *dP;
684 
685   {
686     libspectrum_dword nextlineSrc = srcPitch / sizeof( scaler_data_type );
687     libspectrum_dword nextDstLine = dstPitch / sizeof( scaler_data_type );
688 
689     while (height--) {
690       size_t i;
691       bP = (const scaler_data_type*)srcPtr;
692       dP = (scaler_data_type*)dstPtr;
693 
694       for( i = 0; i < width; ++i ) {
695 
696 	register libspectrum_dword colorA, colorB;
697 	libspectrum_dword colorC, colorD, colorE, colorF, colorG, colorH,
698 	  colorI, colorJ, colorK, colorL, colorM, colorN, colorO;
699 	libspectrum_dword product, product1, product2;
700 
701 /*---------------------------------------
702    Map of the pixels:                    I|E F|J
703                                          G|A B|K
704                                          H|C D|L
705                                          M|N O|P
706 
707    Note that P does not contribute to the algorithm
708 */
709 	colorI = *(bP - nextlineSrc - 1);
710 	colorE = *(bP - nextlineSrc);
711 	colorF = *(bP - nextlineSrc + 1);
712 	colorJ = *(bP - nextlineSrc + 2);
713 
714 	colorG = *(bP - 1);
715 	colorA = *(bP);
716 	colorB = *(bP + 1);
717 	colorK = *(bP + 2);
718 
719 	colorH = *(bP + nextlineSrc - 1);
720 	colorC = *(bP + nextlineSrc);
721 	colorD = *(bP + nextlineSrc + 1);
722 	colorL = *(bP + nextlineSrc + 2);
723 
724 	colorM = *(bP + 2 * nextlineSrc - 1);
725 	colorN = *(bP + 2 * nextlineSrc);
726 	colorO = *(bP + 2 * nextlineSrc + 1);
727 
728 	if ((colorA == colorD) && (colorB != colorC)) {
729 	  if (((colorA == colorE) && (colorB == colorL)) ||
730               ((colorA == colorC) && (colorA == colorF) && (colorB != colorE) && (colorB == colorJ))) {
731 	    product = colorA;
732 	  } else {
733 	    product = INTERPOLATE(colorA, colorB);
734 	  }
735 
736 	  if (((colorA == colorG) && (colorC == colorO)) ||
737               ((colorA == colorB) && (colorA == colorH) && (colorG != colorC) && (colorC == colorM))) {
738 	    product1 = colorA;
739 	  } else {
740 	    product1 = INTERPOLATE(colorA, colorC);
741 	  }
742 	  product2 = colorA;
743 	} else if ((colorB == colorC) && (colorA != colorD)) {
744 	  if (((colorB == colorF) && (colorA == colorH)) ||
745               ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI))) {
746 	    product = colorB;
747 	  } else {
748 	    product = INTERPOLATE(colorA, colorB);
749 	  }
750 
751 	  if (((colorC == colorH) && (colorA == colorF)) ||
752               ((colorC == colorG) && (colorC == colorD) && (colorA != colorH) && (colorA == colorI))) {
753 	    product1 = colorC;
754 	  } else {
755 	    product1 = INTERPOLATE(colorA, colorC);
756 	  }
757 	  product2 = colorB;
758 	} else if ((colorA == colorD) && (colorB == colorC)) {
759 	  if (colorA == colorB) {
760 	    product = colorA;
761 	    product1 = colorA;
762 	    product2 = colorA;
763 	  } else {
764 	    register int r = 0;
765 
766 	    product1 = INTERPOLATE(colorA, colorC);
767 	    product = INTERPOLATE(colorA, colorB);
768 
769 	    r += GetResult(colorA, colorB, colorG, colorE);
770 	    r -= GetResult(colorB, colorA, colorK, colorF);
771 	    r -= GetResult(colorB, colorA, colorH, colorN);
772 	    r += GetResult(colorA, colorB, colorL, colorO);
773 
774 	    if (r > 0)
775 	      product2 = colorA;
776 	    else if (r < 0)
777 	      product2 = colorB;
778 	    else {
779 	      product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
780 	    }
781 	  }
782 	} else {
783 	  product2 = Q_INTERPOLATE(colorA, colorB, colorC, colorD);
784 
785 	  if ((colorA == colorC) && (colorA == colorF)
786 	      && (colorB != colorE) && (colorB == colorJ)) {
787 	    product = colorA;
788 	  } else if ((colorB == colorE) && (colorB == colorD)
789 		     && (colorA != colorF) && (colorA == colorI)) {
790 	    product = colorB;
791 	  } else {
792 	    product = INTERPOLATE(colorA, colorB);
793 	  }
794 
795 	  if ((colorA == colorB) && (colorA == colorH)
796 	      && (colorG != colorC) && (colorC == colorM)) {
797 	    product1 = colorA;
798 	  } else if ((colorC == colorG) && (colorC == colorD)
799 		     && (colorA != colorH) && (colorA == colorI)) {
800 	    product1 = colorC;
801 	  } else {
802 	    product1 = INTERPOLATE(colorA, colorC);
803 	  }
804 	}
805 
806 	*dP = (scaler_data_type)colorA;
807 	*(dP+nextDstLine) = (scaler_data_type)product1;
808 	dP++;
809 	*dP = (scaler_data_type)product;
810 	*(dP+nextDstLine) = (scaler_data_type)product2;
811 	dP++;
812 
813 	bP++;
814       }
815 
816       srcPtr += srcPitch;
817       dstPtr += dstPitch * 2;
818     }
819   }
820 }
821 
822 void
FUNCTION(scaler_AdvMame2x)823 FUNCTION( scaler_AdvMame2x )( const libspectrum_byte *srcPtr,
824 			      libspectrum_dword srcPitch,
825 			      libspectrum_byte *dstPtr,
826 			      libspectrum_dword dstPitch,
827 			      int width, int height )
828 {
829   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
830   const scaler_data_type *p = (const scaler_data_type*) srcPtr;
831 
832   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
833   scaler_data_type *q = (scaler_data_type*) dstPtr;
834 
835   scaler_data_type /* A, */ B, C;
836   scaler_data_type D, E, F;
837   scaler_data_type /* G, */ H, I;
838 
839   while (height--) {
840     int i;
841 
842     B = *(p - 1 - nextlineSrc);
843     E = *(p - 1);
844     H = *(p - 1 + nextlineSrc);
845     C = *(p - nextlineSrc);
846     F = *(p);
847     I = *(p + nextlineSrc);
848 
849     for (i = 0; i < width; ++i) {
850       p++;
851       /* A = B; */ B = C; C = *(p - nextlineSrc);
852       D = E; E = F; F = *(p);
853       /* G = H; */ H = I; I = *(p + nextlineSrc);
854 
855       *(q) = D == B && B != F && D != H ? D : E;
856       *(q + 1) = B == F && B != D && F != H ? F : E;
857       *(q + nextlineDst) = D == H && D != B && H != F ? D : E;
858       *(q + nextlineDst + 1) = H == F && D != H && B != F ? F : E;
859       q += 2;
860     }
861     p += nextlineSrc - width;
862     q += (nextlineDst - width) << 1;
863   }
864 }
865 
866 void
FUNCTION(scaler_AdvMame3x)867 FUNCTION( scaler_AdvMame3x )( const libspectrum_byte *srcPtr,
868 			      libspectrum_dword srcPitch,
869 			      libspectrum_byte *dstPtr,
870 			      libspectrum_dword dstPitch,
871 			      int width, int height )
872 {
873   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
874   const scaler_data_type *p = (const scaler_data_type*) srcPtr;
875 
876   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
877   scaler_data_type *q = (scaler_data_type*) dstPtr;
878 
879   scaler_data_type /* A, */ B, C;
880   scaler_data_type D, E, F;
881   scaler_data_type /* G, */ H, I;
882 
883   while (height--) {
884     int i;
885 
886     B = *(p - 1 - nextlineSrc);
887     E = *(p - 1);
888     H = *(p - 1 + nextlineSrc);
889     C = *(p - nextlineSrc);
890     F = *(p);
891     I = *(p + nextlineSrc);
892 
893     for (i = 0; i < width; ++i) {
894       p++;
895       /* A = B; */ B = C; C = *(p - nextlineSrc);
896       D = E; E = F; F = *(p);
897       /* G = H; */ H = I; I = *(p + nextlineSrc);
898 
899       *(q) = D == B && B != F && D != H ? D : E;
900       *(q + 1) = E;
901       *(q + 2) = B == F && B != D && F != H ? F : E;
902       *(q + nextlineDst) = E;
903       *(q + nextlineDst + 1) = E;
904       *(q + nextlineDst + 2) = E;
905       *(q + 2 * nextlineDst) = D == H && D != B && H != F ? D : E;
906       *(q + 2 * nextlineDst + 1) = E;
907       *(q + 2 * nextlineDst + 2) = H == F && D != H && B != F ? F : E;
908       q += 3;
909     }
910     p += nextlineSrc - width;
911     q += (nextlineDst - width) * 3;
912   }
913 }
914 
915 void
FUNCTION(scaler_Half)916 FUNCTION( scaler_Half )( const libspectrum_byte *srcPtr,
917 			 libspectrum_dword srcPitch, libspectrum_byte *dstPtr,
918 			 libspectrum_dword dstPitch,
919 			 int width, int height )
920 {
921   scaler_data_type *r;
922 
923   while (height--) {
924     int i;
925     r = (scaler_data_type*) dstPtr;
926 
927     if( ( height & 1 ) == 0 ) {
928       for (i = 0; i < width; i+=2, ++r) {
929         scaler_data_type color1 = *(((scaler_data_type*) srcPtr) + i);
930         scaler_data_type color2 = *(((scaler_data_type*) srcPtr) + i + 1);
931 
932         *r = INTERPOLATE(color1, color2);
933       }
934       dstPtr += dstPitch;
935     }
936 
937     srcPtr += srcPitch;
938   }
939 }
940 
941 void
FUNCTION(scaler_HalfSkip)942 FUNCTION( scaler_HalfSkip )( const libspectrum_byte *srcPtr,
943 			     libspectrum_dword srcPitch,
944 			     libspectrum_byte *dstPtr,
945 			     libspectrum_dword dstPitch,
946 			     int width, int height )
947 {
948   scaler_data_type *r;
949 
950   while (height--) {
951     int i;
952     r = (scaler_data_type*) dstPtr;
953 
954     if( ( height & 1 ) == 0 ) {
955       for (i = 0; i < width; i+=2, ++r) {
956         *r = *(((const scaler_data_type*) srcPtr) + i + 1);
957       }
958       dstPtr += dstPitch;
959     }
960 
961     srcPtr += srcPitch;
962   }
963 }
964 
965 void
FUNCTION(scaler_Normal1x)966 FUNCTION( scaler_Normal1x )( const libspectrum_byte *srcPtr,
967 			     libspectrum_dword srcPitch,
968 			     libspectrum_byte *dstPtr,
969 			     libspectrum_dword dstPitch,
970 			     int width, int height )
971 {
972   while( height-- ) {
973     memcpy( dstPtr, srcPtr, SCALER_DATA_SIZE * width );
974     srcPtr += srcPitch;
975     dstPtr += dstPitch;
976   }
977 }
978 
979 void
FUNCTION(scaler_Normal2x)980 FUNCTION( scaler_Normal2x )( const libspectrum_byte *srcPtr,
981 			     libspectrum_dword srcPitch,
982 			     libspectrum_byte *dstPtr,
983 			     libspectrum_dword dstPitch,
984 			     int width, int height )
985 {
986   const scaler_data_type *s;
987   scaler_data_type i, *d, *d2;
988 
989   while( height-- ) {
990 
991     for( i = 0, s = (const scaler_data_type*)srcPtr,
992 	   d = (scaler_data_type*)dstPtr,
993 	   d2 = (scaler_data_type*)(dstPtr + dstPitch);
994 	 i < width;
995 	 i++ ) {
996       *d++ = *d2++ = *s; *d++ = *d2++ = *s++;
997     }
998 
999     srcPtr += srcPitch;
1000     dstPtr += dstPitch << 1;
1001   }
1002 }
1003 
1004 void
FUNCTION(scaler_Normal3x)1005 FUNCTION( scaler_Normal3x )( const libspectrum_byte *srcPtr,
1006 			     libspectrum_dword srcPitch,
1007 			     libspectrum_byte *dstPtr,
1008 			     libspectrum_dword dstPitch,
1009 			     int width, int height )
1010 {
1011   libspectrum_byte *r;
1012   libspectrum_dword dstPitch2 = dstPitch * 2;
1013   libspectrum_dword dstPitch3 = dstPitch * 3;
1014 
1015   while (height--) {
1016     int i;
1017     r = dstPtr;
1018     for (i = 0; i < width; ++i, r += 3 * SCALER_DATA_SIZE ) {
1019       scaler_data_type color = *(((const scaler_data_type*) srcPtr) + i);
1020 
1021       *(scaler_data_type*)( r +                    0             ) = color;
1022       *(scaler_data_type*)( r +     SCALER_DATA_SIZE             ) = color;
1023       *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE             ) = color;
1024       *(scaler_data_type*)( r +                    0 + dstPitch  ) = color;
1025       *(scaler_data_type*)( r +     SCALER_DATA_SIZE + dstPitch  ) = color;
1026       *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE + dstPitch  ) = color;
1027       *(scaler_data_type*)( r +                    0 + dstPitch2 ) = color;
1028       *(scaler_data_type*)( r +     SCALER_DATA_SIZE + dstPitch2 ) = color;
1029       *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE + dstPitch2 ) = color;
1030     }
1031     srcPtr += srcPitch;
1032     dstPtr += dstPitch3;
1033   }
1034 }
1035 
1036 void
FUNCTION(scaler_Timex1_5x)1037 FUNCTION( scaler_Timex1_5x )( const libspectrum_byte *srcPtr,
1038            libspectrum_dword srcPitch,
1039            libspectrum_byte *dstPtr,
1040            libspectrum_dword dstPitch,
1041            int width, int height )
1042 {
1043   libspectrum_byte *r;
1044   libspectrum_dword dstPitch2 = dstPitch * 2;
1045   libspectrum_dword dstPitch3 = dstPitch * 3;
1046 
1047   while (height--) {
1048     int i;
1049     r = dstPtr;
1050     if( ( height & 1 ) == 0 ) {
1051       for (i = 0; i < width; i+=2, r += 3 * SCALER_DATA_SIZE ) {
1052         /* Interpolate a new pixel inbetween the source pixels */
1053         scaler_data_type color1 = *(((const scaler_data_type*) srcPtr) + i);
1054         scaler_data_type color2 = *(((const scaler_data_type*) srcPtr) + i + 1);
1055         scaler_data_type color3 = INTERPOLATE(color1, color2);
1056 
1057         *(scaler_data_type*)( r +                    0             ) = color1;
1058         *(scaler_data_type*)( r +     SCALER_DATA_SIZE             ) = color3;
1059         *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE             ) = color2;
1060         *(scaler_data_type*)( r +                    0 + dstPitch  ) = color1;
1061         *(scaler_data_type*)( r +     SCALER_DATA_SIZE + dstPitch  ) = color3;
1062         *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE + dstPitch  ) = color2;
1063         *(scaler_data_type*)( r +                    0 + dstPitch2 ) = color1;
1064         *(scaler_data_type*)( r +     SCALER_DATA_SIZE + dstPitch2 ) = color3;
1065         *(scaler_data_type*)( r + 2 * SCALER_DATA_SIZE + dstPitch2 ) = color2;
1066       }
1067       dstPtr += dstPitch3;
1068     }
1069     srcPtr += srcPitch;
1070   }
1071 }
1072 
1073 void
FUNCTION(scaler_TV2x)1074 FUNCTION( scaler_TV2x )( const libspectrum_byte *srcPtr,
1075 			 libspectrum_dword srcPitch, libspectrum_byte *dstPtr,
1076 			 libspectrum_dword dstPitch,
1077 			 int width, int height )
1078 {
1079   int i, j;
1080   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1081   const scaler_data_type *p = (const scaler_data_type*)srcPtr;
1082 
1083   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1084   scaler_data_type *q = (scaler_data_type*)dstPtr;
1085 
1086   while(height--) {
1087     for (i = 0, j = 0; i < width; ++i, j += 2) {
1088       scaler_data_type p1 = *(p + i);
1089       scaler_data_type pi;
1090 
1091       pi  = (((p1 & redblueMask) * 7) >> 3) & redblueMask;
1092       pi |= (((p1 & greenMask  ) * 7) >> 3) & greenMask;
1093 
1094       *(q + j) = p1;
1095       *(q + j + 1) = p1;
1096       *(q + j + nextlineDst) = pi;
1097       *(q + j + nextlineDst + 1) = pi;
1098     }
1099     p += nextlineSrc;
1100     q += nextlineDst << 1;
1101   }
1102 }
1103 
1104 void
FUNCTION(scaler_TV3x)1105 FUNCTION( scaler_TV3x )( const libspectrum_byte *srcPtr,
1106                          libspectrum_dword srcPitch, libspectrum_byte *dstPtr,
1107                          libspectrum_dword dstPitch,
1108                          int width, int height )
1109 {
1110   int i, j;
1111   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1112   const scaler_data_type *p = (const scaler_data_type*)srcPtr;
1113 
1114   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1115   scaler_data_type *q = (scaler_data_type*)dstPtr;
1116 
1117   while(height--) {
1118     for (i = 0, j = 0; i < width; ++i, j += 3) {
1119       scaler_data_type p1 = *(p + i);
1120       scaler_data_type pi;
1121 
1122       pi  = (((p1 & redblueMask) * 7) >> 3) & redblueMask;
1123       pi |= (((p1 & greenMask  ) * 7) >> 3) & greenMask;
1124 
1125       *(q + j) = p1;
1126       *(q + j + 1) = p1;
1127       *(q + j + 2) = p1;
1128 
1129       *(q + j + nextlineDst) = p1;
1130       *(q + j + nextlineDst + 1) = p1;
1131       *(q + j + nextlineDst + 2) = p1;
1132 
1133       *(q + j + (nextlineDst << 1)) = pi;
1134       *(q + j + (nextlineDst << 1) + 1) = pi;
1135       *(q + j + (nextlineDst << 1) + 2) = pi;
1136     }
1137     p += nextlineSrc;
1138     q += nextlineDst * 3;
1139   }
1140 }
1141 
1142 void
FUNCTION(scaler_TimexTV)1143 FUNCTION( scaler_TimexTV )( const libspectrum_byte *srcPtr,
1144 			    libspectrum_dword srcPitch,
1145 			    libspectrum_byte *dstPtr,
1146 			    libspectrum_dword dstPitch,
1147 			    int width, int height )
1148 {
1149   int i, j;
1150   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1151   const scaler_data_type *p = (const scaler_data_type *)srcPtr;
1152 
1153   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1154   scaler_data_type *q = (scaler_data_type *)dstPtr;
1155 
1156   while(height--) {
1157     if( ( height & 1 ) == 0 ) {
1158       for (i = 0, j = 0; i < width; ++i, j++ ) {
1159         scaler_data_type p1 = *(p + i);
1160         scaler_data_type pi;
1161 
1162 	pi  = (((p1 & redblueMask) * 7) >> 3) & redblueMask;
1163 	pi |= (((p1 & greenMask  ) * 7) >> 3) & greenMask;
1164 
1165         *(q + j) = p1;
1166         *(q + j + nextlineDst) = pi;
1167       }
1168       q += nextlineDst << 1;
1169     }
1170     p += nextlineSrc;
1171   }
1172 }
1173 
DOT_16(scaler_data_type c,int j,int i)1174 static inline scaler_data_type DOT_16(scaler_data_type c, int j, int i) {
1175   return c - ((c >> 2) & *(dotmatrix + ((j & 3) << 2) + (i & 3)));
1176 }
1177 
1178 void
FUNCTION(scaler_DotMatrix)1179 FUNCTION( scaler_DotMatrix )( const libspectrum_byte *srcPtr,
1180 			      libspectrum_dword srcPitch,
1181 			      libspectrum_byte *dstPtr,
1182 			      libspectrum_dword dstPitch,
1183 			      int width, int height )
1184 {
1185   int i, j, ii, jj;
1186   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1187   const scaler_data_type *p = (const scaler_data_type *)srcPtr;
1188 
1189   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1190   scaler_data_type *q = (scaler_data_type *)dstPtr;
1191 
1192   for (j = 0, jj = 0; j < height; ++j, jj += 2) {
1193     for (i = 0, ii = 0; i < width; ++i, ii += 2) {
1194       scaler_data_type c = *(p + i);
1195       *(q + ii) = DOT_16(c, jj, ii);
1196       *(q + ii + 1) = DOT_16(c, jj, ii + 1);
1197       *(q + ii + nextlineDst) = DOT_16(c, jj + 1, ii);
1198       *(q + ii + nextlineDst + 1) = DOT_16(c, jj + 1, ii + 1);
1199     }
1200     p += nextlineSrc;
1201     q += nextlineDst << 1;
1202   }
1203 }
1204 
1205 /*
1206     Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
1207     U  = -0.16874 * R - 0.33126 * G + 0.50000 * B  (+ 128)
1208     V  =  0.50000 * R - 0.41869 * G - 0.08131 * B  (+ 128)
1209 */
1210 
1211 #define RGB_TO_Y(r, g, b) ( ( 2449L * r + 4809L * g + 934L * b + 1024 ) >> 11 )
1212 #define RGB_TO_U(r, g, b) ( ( 4096L * b - 1383L * r - 2713L * g + 1024 ) >> 11 )
1213 #define RGB_TO_V(r, g, b) ( ( 4096L * r - 3430L * g - 666L * b +  1024 ) >> 11 )
1214 
1215 /*
1216     R = Y + 1.402 (V-128)
1217     G = Y - 0.34414 (U-128) - 0.71414 (V-128)
1218     B = Y + 1.772 (U-128)
1219 */
1220 
1221 #define YUV_TO_R(y, u, v) ( MIN( ABS( ( 8192L * y              + 11485L * v + 16384 ) >> 15 ), 255 ) )
1222 #define YUV_TO_G(y, u, v) ( MIN( ABS( ( 8192L * y - 2819L  * u -  5850L * v + 16384 ) >> 15 ), 255 ) )
1223 #define YUV_TO_B(y, u, v) ( MIN( ABS( ( 8192L * y + 14516L * u              + 16384 ) >> 15 ), 255 ) )
1224 
1225 #define RGB_TO_PIXEL_555(r,g,b) \
1226         (((r * 125) >> 10) + (((g * 125) >> 5) & greenMask) + \
1227                 ((b * 125) & blueMask))
1228 
1229 #define RGB_TO_PIXEL_565(r,g,b) \
1230         (((r * 125) >> 10) + (((g * 253) >> 5) & greenMask) + \
1231                 ((b * 249) & blueMask))
1232 
1233 #define R_TO_R(r) \
1234         ( ( ( (r) & redMask ) * 8424 ) >> 10 )
1235 
1236 #define G_TO_G(g) \
1237       ( green6bit ? \
1238         ( ( ( (g) & greenMask ) >> 5 ) * 4145 ) >> 10 : \
1239         ( ( ( (g) & greenMask ) >> 5 ) * 8424 ) >> 10 )
1240 
1241 #define B_TO_B(b) \
1242       ( green6bit ? \
1243         ( ( ( (b) & blueMask ) >> 11 ) * 8424 ) >> 10 : \
1244         ( ( ( (b) & blueMask ) >> 10 ) * 8424 ) >> 10 )
1245 
1246 void
FUNCTION(scaler_PalTV)1247 FUNCTION( scaler_PalTV )( const libspectrum_byte *srcPtr,
1248                               libspectrum_dword srcPitch,
1249                               libspectrum_byte *dstPtr,
1250                               libspectrum_dword dstPitch,
1251                               int width, int height )
1252 {
1253 /*
1254    1.a. RGB => 255,255,255 RGB
1255    1.b. RGB => YUV
1256    2. 422 interstricial color subsampling
1257    3.a. YUV => RGB
1258    3.b  255,255,255 RGB => RGB
1259 */
1260   int i, j;
1261   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1262   const scaler_data_type *p, *p0 = (const scaler_data_type *)srcPtr;
1263 
1264   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1265   scaler_data_type *q, *q0 = (scaler_data_type *)dstPtr;
1266 
1267   libspectrum_byte  r0, g0, b0,
1268                     r1, g1, b1,
1269                     r2, g2, b2,
1270                     r3, g3, b3;
1271   libspectrum_signed_word y1, y2, u1, u2, v1, v2;
1272 
1273 /*
1274  422 cosited
1275     # + # +             + only Y
1276                         # Y and Cb Cr
1277     # + # +
1278 
1279     abcd...    =>  1/2a + a + 1/2b / 2; ...; 1/2a + b + 1/2c; ... ; ...
1280     always 3 sample/proc
1281 
1282 */
1283   for( j = height; j; j-- ) {
1284     p = p0 - 1; q = q0;
1285 #if SCALER_DATA_SIZE == 2
1286     /* 1.a. RGB => RGB */
1287     r2 = R_TO_R( *p );
1288     g2 = G_TO_G( *p );
1289     b2 = B_TO_B( *p );
1290     p++;
1291     r0 = R_TO_R( *p );
1292     g0 = G_TO_G( *p );
1293     b0 = B_TO_B( *p );
1294     p++;
1295     r1 = R_TO_R( *p );
1296     g1 = G_TO_G( *p );
1297     b1 = B_TO_B( *p );
1298     p++;
1299 #else
1300     r2 = (*p & redMask);
1301     g2 = (*p & greenMask) >> 8;
1302     b2 = (*p & blueMask) >> 16;
1303     p++;
1304     r0 = (*p & redMask);
1305     g0 = (*p & greenMask) >> 8;
1306     b0 = (*p & blueMask) >> 16;
1307     p++;
1308     r1 = (*p & redMask);
1309     g1 = (*p & greenMask) >> 8;
1310     b1 = (*p & blueMask) >> 16;
1311     p++;
1312 #endif
1313     u1 = ( RGB_TO_U( r2, g2, b2 ) + 2 * RGB_TO_U( r0, g0, b0 ) +
1314             RGB_TO_U( r1, g1, b1 ) ) >> 2;
1315     v1 = ( RGB_TO_V( r2, g2, b2 ) + 2 * RGB_TO_V( r0, g0, b0 ) +
1316             RGB_TO_V( r1, g1, b1 ) ) >> 2;
1317     for( i = width; i; i -= 2 ) {
1318 #if SCALER_DATA_SIZE == 2
1319       /* 1.a. RGB => RGB */
1320       r2 = R_TO_R( *p );
1321       g2 = G_TO_G( *p );
1322       b2 = B_TO_B( *p );
1323       p++;
1324       r3 = R_TO_R( *p );
1325       g3 = G_TO_G( *p );
1326       b3 = B_TO_B( *p );
1327       p++;
1328 #else
1329       r2 = (*p & redMask);
1330       g2 = (*p & greenMask) >> 8;
1331       b2 = (*p & blueMask) >> 16;
1332       p++;
1333       r3 = (*p & redMask);
1334       g3 = (*p & greenMask) >> 8;
1335       b3 = (*p & blueMask) >> 16;
1336       p++;
1337 #endif
1338 /* 1.b. RGB => YUV && 2. YUV subsampling */
1339       y1 = RGB_TO_Y( r0, g0, b0 );
1340       y2 = RGB_TO_Y( r1, g1, b1 );
1341 
1342       u2 = ( RGB_TO_U( r1, g1, b1 ) + 2 * RGB_TO_U( r2, g2, b2 ) +
1343             RGB_TO_U( r3, g3, b3 ) ) >> 2;
1344       v2 = ( RGB_TO_V( r1, g1, b1 ) + 2 * RGB_TO_V( r2, g2, b2 ) +
1345             RGB_TO_V( r3, g3, b3 ) ) >> 2;
1346 /* 3.a. YUV => RGB  */
1347       r0 = YUV_TO_R(y1, u1, v1);
1348       g0 = YUV_TO_G(y1, u1, v1);
1349       b0 = YUV_TO_B(y1, u1, v1);
1350 
1351       u1 = (u1 + u2) >> 1;
1352       v1 = (v1 + v2) >> 1;
1353 
1354       r1 = YUV_TO_R(y2, u1, v1);
1355       g1 = YUV_TO_G(y2, u1, v1);
1356       b1 = YUV_TO_B(y2, u1, v1);
1357 #if SCALER_DATA_SIZE == 2
1358 /* 3.b. RGB => RGB */
1359       if( green6bit ) {
1360         *q++ = RGB_TO_PIXEL_565( r0, g0, b0 );
1361         *q++ = RGB_TO_PIXEL_565( r1, g1, b1 );
1362       } else {
1363         *q++ = RGB_TO_PIXEL_555( r0, g0, b0 );
1364         *q++ = RGB_TO_PIXEL_555( r1, g1, b1 );
1365       }
1366 #else
1367       *q++ = r0 + (g0 << 8) + (b0 << 16);
1368       *q++ = r1 + (g1 << 8) + (b1 << 16);
1369 #endif
1370       u1 = u2; v1 = v2;
1371       r0 = r2; g0 = g2; b0 = b2;
1372       r1 = r3; g1 = g3; b1 = b3;
1373     }
1374     p0 += nextlineSrc;
1375     q0 += nextlineDst;
1376   }
1377 }
1378 
1379 void
FUNCTION(scaler_PalTV2x)1380 FUNCTION( scaler_PalTV2x )( const libspectrum_byte *srcPtr,
1381                               libspectrum_dword srcPitch,
1382                               libspectrum_byte *dstPtr,
1383                               libspectrum_dword dstPitch,
1384                               int width, int height )
1385 {
1386 /*
1387    1.a. RGB => 255,255,255 RGB
1388    1.b. RGB => YUV
1389    2. 4:2:2 cosited color subsampling
1390    3.a. YUV => RGB
1391    3.b  255,255,255 RGB => RGB
1392 */
1393   int i, j;
1394   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1395   const scaler_data_type *p, *p0 = (const scaler_data_type *)srcPtr;
1396 
1397   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1398   scaler_data_type *q, *q0 = (scaler_data_type *)dstPtr;
1399 
1400   libspectrum_byte  r0, g0, b0,
1401                     r1, g1, b1,
1402                     rx, gx, bx;
1403   libspectrum_signed_dword y1, y2, u1, v1, u2, v2;
1404 
1405 /*
1406  422 cosited
1407     # + # +             + only Y
1408                         # Y and Cb Cr
1409     # + # +
1410 
1411     abcd...    =>  1/2a + a + 1/2b / 2; ...; 1/2a + b + 1/2c; ... ; ...
1412     always 3 sample/proc
1413 
1414 */
1415   for( j = height; j; j-- ) {
1416     p = p0 - 1; q = q0;
1417 #if SCALER_DATA_SIZE == 2
1418     r0 = R_TO_R( *p );
1419     g0 = G_TO_G( *p );
1420     b0 = B_TO_B( *p );
1421     p++;
1422     r1 = R_TO_R( *p );
1423     g1 = G_TO_G( *p );
1424     b1 = B_TO_B( *p );
1425 #else
1426     r0 = *p & redMask;
1427     g0 = (*p & greenMask) >> 8;
1428     b0 = (*p & blueMask) >> 16;
1429     p++;
1430     r1 = *(p) & redMask;
1431     g1 = (*(p) & greenMask) >> 8;
1432     b1 = (*(p) & blueMask) >> 16;
1433 #endif
1434     y1 = RGB_TO_Y( r1, g1, b1 );
1435     u1 = ( RGB_TO_U( r0, g0, b0 ) + 3 * RGB_TO_U( r1, g1, b1 ) ) >> 2;
1436     v1 = ( RGB_TO_V( r0, g0, b0 ) + 3 * RGB_TO_V( r1, g1, b1 ) ) >> 2;
1437     for( i = width; i; i-- ) {
1438       p++;      /* next point */
1439 #if SCALER_DATA_SIZE == 2
1440       /* 1.a. RGB => RGB */
1441       r0 = R_TO_R( *p );
1442       g0 = G_TO_G( *p );
1443       b0 = B_TO_B( *p );
1444 #else
1445       r0 = (*p & redMask);
1446       g0 = (*p & greenMask) >> 8;
1447       b0 = (*p & blueMask) >> 16;
1448 #endif
1449 /* 1.b. RGB => YUV && 2. YUV subsampling */
1450       y2 = RGB_TO_Y( r0, g0, b0 );
1451       u2 = ( RGB_TO_U( r1, g1, b1 ) + 3 * RGB_TO_U( r0, g0, b0 ) ) >> 2;
1452       v2 = ( RGB_TO_V( r1, g1, b1 ) + 3 * RGB_TO_V( r0, g0, b0 ) ) >> 2;
1453 
1454 /* 3.a. YUV => RGB  */
1455       rx = YUV_TO_R( y1, u1, v1 );      /* [x0][  ]*/
1456       gx = YUV_TO_G( y1, u1, v1 );
1457       bx = YUV_TO_B( y1, u1, v1 );
1458 
1459       u1 = ( u1 + u2 ) >> 1;
1460       v1 = ( v1 + v2 ) >> 1;
1461 
1462       r1 = YUV_TO_R( y1, u1, v1 );
1463       g1 = YUV_TO_G( y1, u1, v1 );
1464       b1 = YUV_TO_B( y1, u1, v1 );
1465 
1466 #if SCALER_DATA_SIZE == 2
1467 /* 3.b. RGB => RGB */
1468       if( green6bit ) {
1469         *q = RGB_TO_PIXEL_565( rx, gx, bx );
1470       } else {
1471         *q = RGB_TO_PIXEL_555( rx, gx, bx );
1472       }
1473 #else
1474       *q = rx + ( gx << 8 ) + ( bx << 16 );
1475 #endif
1476 
1477       if( settings_current.pal_tv2x )
1478         *(q + nextlineDst) =
1479             ((((*q & redblueMask) * 7) >> 3) & redblueMask) |
1480                 ((((*q & greenMask  ) * 7) >> 3) & greenMask);
1481       else
1482         *(q + nextlineDst) = *q;
1483 
1484       q++;
1485 #if SCALER_DATA_SIZE == 2
1486 /* 3.b. RGB => RGB */
1487       if( green6bit ) {
1488         *q = RGB_TO_PIXEL_565( r1, g1, b1 );
1489       } else {
1490         *q = RGB_TO_PIXEL_555( r1, g1, b1 );
1491       }
1492 #else
1493       *q = r1 + ( g1 << 8 ) + ( b1 << 16 );
1494 #endif
1495       if( settings_current.pal_tv2x )
1496         *(q + nextlineDst) =
1497             ((((*q & redblueMask) * 7) >> 3) & redblueMask) |
1498                 ((((*q & greenMask  ) * 7) >> 3) & greenMask);
1499       else
1500         *(q + nextlineDst) = *q;
1501 
1502       q++;
1503       y1 = y2; u1 = u2; v1 = v2;        /* save for next point */
1504       r1 = r0; g1 = g0; b1 = b0;
1505     }
1506     p0 += nextlineSrc;
1507     q0 += nextlineDst << 1;
1508   }
1509 }
1510 
1511 void
FUNCTION(scaler_PalTV3x)1512 FUNCTION( scaler_PalTV3x )( const libspectrum_byte *srcPtr,
1513                               libspectrum_dword srcPitch,
1514                               libspectrum_byte *dstPtr,
1515                               libspectrum_dword dstPitch,
1516                               int width, int height )
1517 {
1518 /*
1519    1.a. RGB => 255,255,255 RGB
1520    1.b. RGB => YUV
1521    2. 4:2:2 cosited color subsampling
1522    3.a. YUV => RGB
1523    3.b  255,255,255 RGB => RGB
1524 */
1525   int i, j;
1526   unsigned int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1527   const scaler_data_type *p, *p0 = (const scaler_data_type *)srcPtr;
1528 
1529   unsigned int nextlineDst = dstPitch / sizeof( scaler_data_type );
1530   scaler_data_type *q, *q0 = (scaler_data_type *)dstPtr;
1531 
1532   libspectrum_byte  r0, g0, b0,
1533                     r1, g1, b1,
1534                     r2, g2, b2,
1535                     rx, gx, bx;
1536   libspectrum_signed_dword y1, y2, u1, v1, u2, v2;
1537 
1538 /*
1539  422 cosited
1540     # + # +             + only Y
1541                         # Y and Cb Cr
1542     # + # +
1543 
1544     abcd...    =>  1/2a + a + 1/2b / 2; ...; 1/2a + b + 1/2c; ... ; ...
1545     always 3 sample/proc
1546 
1547 */
1548   for( j = height; j; j-- ) {
1549     p = p0 - 1; q = q0;
1550 #if SCALER_DATA_SIZE == 2
1551     r0 = R_TO_R( *p );
1552     g0 = G_TO_G( *p );
1553     b0 = B_TO_B( *p );
1554     p++;
1555     r1 = R_TO_R( *p );
1556     g1 = G_TO_G( *p );
1557     b1 = B_TO_B( *p );
1558 #else
1559     r0 = *p & redMask;
1560     g0 = (*p & greenMask) >> 8;
1561     b0 = (*p & blueMask) >> 16;
1562     p++;        /* next point */
1563     r1 = *(p) & redMask;
1564     g1 = (*(p) & greenMask) >> 8;
1565     b1 = (*(p) & blueMask) >> 16;
1566 #endif
1567     y1 = RGB_TO_Y( r1, g1, b1 );
1568     u1 = ( RGB_TO_U( r0, g0, b0 ) + 3 * RGB_TO_U( r1, g1, b1 ) ) >> 2;
1569     v1 = ( RGB_TO_V( r0, g0, b0 ) + 3 * RGB_TO_V( r1, g1, b1 ) ) >> 2;
1570     for( i = width; i; i-- ) {
1571       p++;
1572 #if SCALER_DATA_SIZE == 2
1573       /* 1.a. RGB => RGB */
1574       r0 = R_TO_R( *p );
1575       g0 = G_TO_G( *p );
1576       b0 = B_TO_B( *p );
1577 #else
1578       r0 = (*p & redMask);
1579       g0 = (*p & greenMask) >> 8;
1580       b0 = (*p & blueMask) >> 16;
1581 #endif
1582 /* 1.b. RGB => YUV && 2. YUV subsampling */
1583       y2 = RGB_TO_Y( r0, g0, b0 );
1584       u2 = ( RGB_TO_U( r1, g1, b1 ) + 3 * RGB_TO_U( r0, g0, b0 ) ) >> 2;
1585       v2 = ( RGB_TO_V( r1, g1, b1 ) + 3 * RGB_TO_V( r0, g0, b0 ) ) >> 2;
1586 
1587 /* 3.a. YUV => RGB  */
1588       rx = YUV_TO_R( y1, u1, v1 );      /* [x0][  ]*/
1589       gx = YUV_TO_G( y1, u1, v1 );
1590       bx = YUV_TO_B( y1, u1, v1 );
1591 
1592       u1 = ( u1 + u2 ) >> 1;
1593       v1 = ( v1 + v2 ) >> 1;
1594 
1595       r1 = YUV_TO_R( y1, u1, v1 );
1596       g1 = YUV_TO_G( y1, u1, v1 );
1597       b1 = YUV_TO_B( y1, u1, v1 );
1598 
1599 /*
1600     ab  => EFG
1601     ab     EFG
1602            efg
1603 */
1604       r2 = ((int)rx + r1) >> 1;                 /* F */
1605       g2 = ((int)gx + g1) >> 1;
1606       b2 = ((int)bx + b1) >> 1;
1607 
1608 #if SCALER_DATA_SIZE == 2
1609 /* 3.b. RGB => RGB */
1610       if( green6bit ) {
1611         *q = RGB_TO_PIXEL_565( rx, gx, bx);
1612       } else {
1613         *q = RGB_TO_PIXEL_555( rx, gx, bx);
1614       }
1615 #else
1616       *q = rx + ( gx << 8 ) + ( bx << 16 );     /* E, E, e */
1617 #endif
1618       *(q + nextlineDst) = *q;
1619 
1620       if( settings_current.pal_tv2x )
1621         *(q + (nextlineDst << 1)) =
1622             ((((*q & redblueMask) * 7) >> 3) & redblueMask) |
1623                 ((((*q & greenMask  ) * 7) >> 3) & greenMask);
1624       else
1625         *(q + (nextlineDst << 1)) = *q;
1626 
1627       q++;
1628 #if SCALER_DATA_SIZE == 2
1629 /* 3.b. RGB => RGB */
1630       if( green6bit ) {
1631         *q = RGB_TO_PIXEL_565( r2, g2, b2 );
1632       } else {
1633         *q = RGB_TO_PIXEL_555( r2, g2, b2 );
1634       }
1635 #else
1636       *q = r2 + ( g2 << 8 ) + ( b2 << 16 );     /* F, F, f*/
1637 #endif
1638       *(q + nextlineDst) = *q;
1639 
1640       if( settings_current.pal_tv2x )
1641         *(q + (nextlineDst << 1)) =
1642             ((((*q & redblueMask) * 7) >> 3) & redblueMask) |
1643                 ((((*q & greenMask  ) * 7) >> 3) & greenMask);
1644       else
1645         *(q + (nextlineDst << 1)) = *q;
1646 
1647       q++;
1648 #if SCALER_DATA_SIZE == 2
1649 /* 3.b. RGB => RGB */
1650       if( green6bit ) {
1651         *q = RGB_TO_PIXEL_565( r1, g1, b1 );
1652       } else {
1653         *q = RGB_TO_PIXEL_555( r1, g1, b1 );
1654       }
1655 #else
1656       *q = r1 + ( g1 << 8 ) + ( b1 << 16 );     /* G, G, g*/
1657 #endif
1658       *(q + nextlineDst) = *q;
1659       if( settings_current.pal_tv2x )
1660         *(q + (nextlineDst << 1)) =
1661             ((((*q & redblueMask) * 7) >> 3) & redblueMask) |
1662                 ((((*q & greenMask  ) * 7) >> 3) & greenMask);
1663       else
1664         *(q + (nextlineDst << 1)) = *q;
1665 
1666       q++;
1667       y1 = y2; u1 = u2; v1 = v2;        /* save for next point */
1668       r1 = r0; g1 = g0; b1 = b0;
1669     }
1670     p0 += nextlineSrc;
1671     q0 += (nextlineDst << 1) + nextlineDst;
1672   }
1673 }
1674 
1675 #define prevline (-nextlineSrc)
1676 #define nextline nextlineSrc
1677 #define MOVE_B_TO_A(A,B) \
1678 		w[A] = w[B]; y[A] = y[B]; u[A] = u[B]; v[A] = v[B];
1679 #define MOVE_P_RIGHT \
1680 	MOVE_B_TO_A(1,2) \
1681 	MOVE_B_TO_A(4,5) \
1682 	MOVE_B_TO_A(7,8) \
1683 	MOVE_B_TO_A(2,3) \
1684 	MOVE_B_TO_A(5,6) \
1685 	MOVE_B_TO_A(8,9)
1686 
1687 void
FUNCTION(scaler_HQ2x)1688 FUNCTION( scaler_HQ2x ) ( const libspectrum_byte *srcPtr,
1689                           libspectrum_dword srcPitch,
1690                           libspectrum_byte *dstPtr,
1691                           libspectrum_dword dstPitch,
1692                           int width, int height )
1693 {
1694   int i, j, k, pattern;
1695   int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1696   const scaler_data_type *p, *p0 = (const scaler_data_type *)srcPtr;
1697   int nextlineDst = dstPitch / sizeof( scaler_data_type );
1698   scaler_data_type *q, *q1, *qN, *qN1, *q0 = (scaler_data_type *)dstPtr;
1699   libspectrum_qword w[10];
1700 
1701   libspectrum_byte  r, g, b;
1702   libspectrum_signed_dword y[10], u[10], v[10];
1703 
1704   /*   +----+----+----+
1705        |    |    |    |
1706        | w1 | w2 | w3 |
1707        +----+----+----+
1708        |    |    |    |
1709        | w4 | w5 | w6 |
1710        +----+----+----+
1711        |    |    |    |
1712        | w7 | w8 | w9 |
1713        +----+----+----+ */
1714   for( j = 0; j < height; j++ ) {
1715     p = p0;
1716     q = q0; q1 = q + 1;
1717     qN = q + nextlineDst; qN1 = qN + 1;
1718     w[2] = *(p + prevline);
1719     w[5] = *p;
1720     w[8] = *(p + nextline);
1721     w[1] = *(p + prevline - 1);
1722     w[4] = *(p - 1);
1723     w[7] = *(p + nextline - 1);
1724     w[3] = *(p + prevline + 1);
1725     w[6] = *(p + 1);
1726     w[9] = *(p + nextline + 1);
1727     for( k = 1; k <= 9; k++ ) {
1728 #if SCALER_DATA_SIZE == 2
1729       r = R_TO_R( w[k] );
1730       g = G_TO_G( w[k] );
1731       b = B_TO_B( w[k] );
1732 #else
1733       r =  w[k] & redMask;
1734       g = (w[k] & greenMask) >> 8;
1735       b = (w[k] & blueMask) >> 16;
1736 #endif
1737       y[k] = RGB_TO_Y( r, g, b );
1738       u[k] = RGB_TO_U( r, g, b );
1739       v[k] = RGB_TO_V( r, g, b );
1740     }
1741 
1742     for( i = 0; i < width; i++ ) {
1743       pattern = 0;
1744       if( HQ_YUVDIFF( y[5], u[5], v[5], y[1], u[1], v[1] ) ) pattern |= 0x01;
1745       if( HQ_YUVDIFF( y[5], u[5], v[5], y[2], u[2], v[2] ) ) pattern |= 0x02;
1746       if( HQ_YUVDIFF( y[5], u[5], v[5], y[3], u[3], v[3] ) ) pattern |= 0x04;
1747       if( HQ_YUVDIFF( y[5], u[5], v[5], y[4], u[4], v[4] ) ) pattern |= 0x08;
1748       if( HQ_YUVDIFF( y[5], u[5], v[5], y[6], u[6], v[6] ) ) pattern |= 0x10;
1749       if( HQ_YUVDIFF( y[5], u[5], v[5], y[7], u[7], v[7] ) ) pattern |= 0x20;
1750       if( HQ_YUVDIFF( y[5], u[5], v[5], y[8], u[8], v[8] ) ) pattern |= 0x40;
1751       if( HQ_YUVDIFF( y[5], u[5], v[5], y[9], u[9], v[9] ) ) pattern |= 0x80;
1752 
1753 #include "scaler_hq2x.c"
1754 
1755       p++;
1756       q  += 2; q1  += 2;
1757       qN += 2; qN1 += 2;
1758       MOVE_P_RIGHT
1759       w[3] = *(p + prevline + 1);
1760       w[6] = *(p + 1);
1761       w[9] = *(p + nextline + 1);
1762       for( k = 3; k <= 9; k += 3 ) {
1763 #if SCALER_DATA_SIZE == 2
1764         r = R_TO_R( w[k] );
1765         g = G_TO_G( w[k] );
1766         b = B_TO_B( w[k] );
1767 #else
1768         r =   w[k] & redMask;
1769         g = ( w[k] & greenMask ) >> 8;
1770         b = ( w[k] & blueMask  ) >> 16;
1771 #endif
1772         y[k] = RGB_TO_Y( r, g, b );
1773         u[k] = RGB_TO_U( r, g, b );
1774         v[k] = RGB_TO_V( r, g, b );
1775       }
1776     }
1777     p0 += nextlineSrc;
1778     q0 += nextlineDst << 1;
1779   }
1780 }
1781 
1782 void
FUNCTION(scaler_HQ3x)1783 FUNCTION( scaler_HQ3x ) ( const libspectrum_byte *srcPtr,
1784                           libspectrum_dword srcPitch,
1785                           libspectrum_byte *dstPtr,
1786                           libspectrum_dword dstPitch,
1787                           int width, int height )
1788 {
1789   int i, j, k, pattern;
1790   int nextlineSrc = srcPitch / sizeof( scaler_data_type );
1791   const scaler_data_type *p, *p0 = (const scaler_data_type *)srcPtr;
1792   int nextlineDst = dstPitch / sizeof( scaler_data_type );
1793   scaler_data_type *q, *qN, *qNN, *q1, *qN1, *qNN1, *q2, *qN2, *qNN2,
1794 		   *q0 = (scaler_data_type *)dstPtr;
1795   libspectrum_qword w[10];
1796 
1797   libspectrum_byte  r, g, b;
1798   libspectrum_signed_dword y[10], u[10], v[10];
1799 
1800   /*   +----+----+----+
1801        |    |    |    |
1802        | w1 | w2 | w3 |
1803        +----+----+----+
1804        |    |    |    |
1805        | w4 | w5 | w6 |
1806        +----+----+----+
1807        |    |    |    |
1808        | w7 | w8 | w9 |
1809        +----+----+----+ */
1810   for( j = 0; j < height; j++ ) {
1811     if( j == height - 1 ) nextline = 0;
1812 
1813     p = p0;
1814     q = q0;
1815     q1 = q + 1; q2 = q + 2;
1816     qN = q + nextlineDst; qN1 = qN + 1; qN2 = qN + 2;
1817     qNN = qN + nextlineDst;  qNN1 = qNN + 1; qNN2 = qNN + 2;
1818 
1819     w[2] = *(p + prevline);
1820     w[5] = *p;
1821     w[8] = *(p + nextline);
1822     w[1] = *(p + prevline - 1);
1823     w[4] = *(p - 1);
1824     w[7] = *(p + nextline - 1);
1825     w[3] = *(p + prevline + 1);
1826     w[6] = *(p + 1);
1827     w[9] = *(p + nextline + 1);
1828     for( k = 1; k <= 9; k++ ) {
1829 #if SCALER_DATA_SIZE == 2
1830       r = R_TO_R( w[k] );
1831       g = G_TO_G( w[k] );
1832       b = B_TO_B( w[k] );
1833 #else
1834       r =  w[k] & redMask;
1835       g = (w[k] & greenMask) >> 8;
1836       b = (w[k] & blueMask) >> 16;
1837 #endif
1838       y[k] = RGB_TO_Y( r, g, b );
1839       u[k] = RGB_TO_U( r, g, b );
1840       v[k] = RGB_TO_V( r, g, b );
1841     }
1842 
1843     for( i = 0; i < width; i++ ) {
1844       pattern = 0;
1845       if( HQ_YUVDIFF( y[5], u[5], v[5], y[1], u[1], v[1] ) ) pattern |= 0x01;
1846       if( HQ_YUVDIFF( y[5], u[5], v[5], y[2], u[2], v[2] ) ) pattern |= 0x02;
1847       if( HQ_YUVDIFF( y[5], u[5], v[5], y[3], u[3], v[3] ) ) pattern |= 0x04;
1848       if( HQ_YUVDIFF( y[5], u[5], v[5], y[4], u[4], v[4] ) ) pattern |= 0x08;
1849       if( HQ_YUVDIFF( y[5], u[5], v[5], y[6], u[6], v[6] ) ) pattern |= 0x10;
1850       if( HQ_YUVDIFF( y[5], u[5], v[5], y[7], u[7], v[7] ) ) pattern |= 0x20;
1851       if( HQ_YUVDIFF( y[5], u[5], v[5], y[8], u[8], v[8] ) ) pattern |= 0x40;
1852       if( HQ_YUVDIFF( y[5], u[5], v[5], y[9], u[9], v[9] ) ) pattern |= 0x80;
1853 
1854 #include "scaler_hq3x.c"
1855 
1856       p++;
1857       q   += 3; q1   += 3; q2   += 3;
1858       qN  += 3; qN1  += 3; qN2  += 3;
1859       qNN += 3; qNN1 += 3; qNN2 += 3;
1860       MOVE_P_RIGHT
1861       w[3] = *(p + prevline + 1);
1862       w[6] = *(p + 1);
1863       w[9] = *(p + nextline + 1);
1864       for( k = 3; k <= 9; k += 3 ) {
1865 #if SCALER_DATA_SIZE == 2
1866         r = R_TO_R( w[k] );
1867         g = G_TO_G( w[k] );
1868         b = B_TO_B( w[k] );
1869 #else
1870         r =   w[k] & redMask;
1871         g = ( w[k] & greenMask ) >> 8;
1872         b = ( w[k] & blueMask  ) >> 16;
1873 #endif
1874         y[k] = RGB_TO_Y( r, g, b );
1875         u[k] = RGB_TO_U( r, g, b );
1876         v[k] = RGB_TO_V( r, g, b );
1877       }
1878     }
1879     p0 += nextlineSrc;
1880     q0 += ( nextlineDst << 1 ) + nextlineDst;
1881   }
1882 }
1883