1 /*
2  * 2xSaI engine. This file was obtained from:
3  * http://bob.allegronetwork.com/projects.html
4  * Authors: Derek Liauw Kie Fa/Kreed, Robert J Ohannessian, Peter Wang
5  */
6 
7 /*
8 2xSaI
9 ~~~~~
10 
11 Copyright (c) Derek Liauw Kie Fa, 1999
12 Modifications for Allegro 3.9+ comptibility by Robert J Ohannessian.
13 
14 Comments, Suggestions, Questions, Bugs etc.:
15     derek-liauw@usa.net
16     void_star_@excite.com
17 
18 Original web site: http://members.xoom.com/derek_liauw/
19 
20 This program is free for non-commercial use.
21 
22 
23 Disclaimer
24 ----------
25 #include <std_disclaimer.h>
26 Use this program at your own risk. This program was not intended to do
27 anything malicious, but we are not responsible for any damage or loss
28 that may arise by the use of this program.
29 */
30 
31 #include <string.h>
32 #include <allegro.h>
33 #include <allegro/internal/aintern.h>
34 #include "2xsai.h"
35 
36 
37 
38 static __UInt32 colorMask = 0xF7DEF7DE;
39 static __UInt32 lowPixelMask = 0x08210821;
40 static __UInt32 qcolorMask = 0xE79CE79C;
41 static __UInt32 qlowpixelMask = 0x18631863;
42 static __UInt32 redblueMask = 0xF81F;
43 static __UInt32 greenMask = 0x7E0;
44 static int PixelsPerMask = 2;
45 static int xsai_depth = 0;
46 
47 
48 
Init_2xSaI(int d)49 int Init_2xSaI(int d)
50 {
51 
52     int minr = 0, ming = 0, minb = 0;
53     int i;
54 
55     if (d != 15 && d != 16 && d != 24 && d != 32)
56         return -1;
57 
58     /* Get lowest color bit */
59     for (i = 0; i < 255; i++) {
60         if (!minr)
61             minr = makecol(i, 0, 0);
62         if (!ming)
63             ming = makecol(0, i, 0);
64         if (!minb)
65             minb = makecol(0, 0, i);
66     }
67 
68     colorMask = (makecol_depth(d, 255, 0, 0) - minr) | (makecol_depth(d, 0, 255, 0) - ming) | (makecol_depth(d, 0, 0, 255) - minb);
69     lowPixelMask = minr | ming | minb;
70     qcolorMask = (makecol_depth(d, 255, 0, 0) - 3 * minr) | (makecol_depth(d, 0, 255, 0) - 3 * ming) | (makecol_depth(d, 0, 0, 255) - 3 * minb);
71     qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3);
72     redblueMask = makecol_depth(d, 255, 0, 255);
73     greenMask = makecol_depth(d, 0, 255, 0);
74 
75     PixelsPerMask = (d <= 16) ? 2 : 1;
76 
77     if (PixelsPerMask == 2) {
78         colorMask |= (colorMask << 16);
79         qcolorMask |= (qcolorMask << 16);
80         lowPixelMask |= (lowPixelMask << 16);
81         qlowpixelMask |= (qlowpixelMask << 16);
82     }
83 
84     /*TRACE("Color Mask:       0x%lX\n", colorMask);
85     TRACE("Low Pixel Mask:   0x%lX\n", lowPixelMask);
86     TRACE("QColor Mask:      0x%lX\n", qcolorMask);
87     TRACE("QLow Pixel Mask:  0x%lX\n", qlowpixelMask);*/
88 
89     xsai_depth = d;
90 
91     return 0;
92 }
93 
94 
95 /*static int GetResult1(__UInt32 A, __UInt32 B, __UInt32 C, __UInt32 D)
96 {
97     int x = 0;
98     int y = 0;
99     int r = 0;
100     if (A == C)
101         x += 1;
102     else if (B == C)
103         y += 1;
104     if (A == D)
105         x += 1;
106     else if (B == D)
107         y += 1;
108     if (x <= 1)
109         r += 1;
110     if (y <= 1)
111         r -= 1;
112     return r;
113 }
114 
115 static int GetResult2(__UInt32 A, __UInt32 B, __UInt32 C, __UInt32 D, __UInt32 E)
116 {
117     int x = 0;
118     int y = 0;
119     int r = 0;
120     if (A == C)
121         x += 1;
122     else if (B == C)
123         y += 1;
124     if (A == D)
125         x += 1;
126     else if (B == D)
127         y += 1;
128     if (x <= 1)
129         r -= 1;
130     if (y <= 1)
131         r += 1;
132     return r;
133 }*/
134 
135 
136 #define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D))
137 
138 #define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask))
139 
140 #define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) \
141     + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask)
142 
143 
144 /* Clipping Macro, stolen from Allegro, modified to work with 2xSaI */
145 #define BLIT_CLIP2(src, dest, s_x, s_y, d_x, d_y, w, h, xscale, yscale)      \
146    /* check for ridiculous cases */                                          \
147    if ((s_x >= src->cr) || (s_y >= src->cb) ||                               \
148        (d_x >= dest->cr) || (d_y >= dest->cb))                               \
149       return;                                                                \
150                                                                              \
151    if ((s_x + w < src->cl) || (s_y + h < src->ct) ||                         \
152        (d_x + w * xscale < dest->cl) || (d_y + h * yscale < dest->ct))       \
153       return;                                                                \
154                                                                              \
155    if (xscale < 1 || yscale < 1)                                             \
156       return;                                                                \
157                                                                              \
158    /* clip src left */                                                       \
159    if (s_x < src->cl) {                                                      \
160       w += s_x;                                                              \
161       d_x -= s_x * xscale;                                                   \
162       s_x = src->cl;                                                         \
163    }                                                                         \
164                                                                              \
165    /* clip src top */                                                        \
166    if (s_y < src->ct) {                                                      \
167       h += s_y;                                                              \
168       d_y -= s_y * yscale;                                                   \
169       s_y = src->ct;                                                         \
170    }                                                                         \
171                                                                              \
172    /* clip src right */                                                      \
173    if (s_x + w > src->cr)                                                    \
174       w = src->cr - s_x;                                                     \
175                                                                              \
176    /* clip src bottom */                                                     \
177    if (s_y + h > src->cb)                                                    \
178       h = src->cb - s_y;                                                     \
179                                                                              \
180    /* clip dest left */                                                      \
181    if (d_x < dest->cl) {                                                     \
182       d_x -= dest->cl;                                                       \
183       w += d_x / xscale;                                                     \
184       s_x -= d_x / xscale;                                                   \
185       d_x = dest->cl;                                                        \
186    }                                                                         \
187                                                                              \
188    /* clip dest top */                                                       \
189    if (d_y < dest->ct) {                                                     \
190       d_y -= dest->ct;                                                       \
191       h += d_y / yscale;                                                     \
192       s_y -= d_y / yscale;                                                   \
193       d_y = dest->ct;                                                        \
194    }                                                                         \
195                                                                              \
196    /* clip dest right */                                                     \
197    if (d_x + w * xscale > dest->cr)                                          \
198       w = (dest->cr - d_x) / xscale;                                         \
199                                                                              \
200    /* clip dest bottom */                                                    \
201    if (d_y + h * yscale > dest->cb)                                          \
202       h = (dest->cb - d_y) / yscale;                                         \
203                                                                              \
204    /* bottle out if zero size */                                             \
205    if ((w <= 0) || (h <= 0))                                                 \
206       return;
207 
208 
209 static unsigned char *src_line[4];
210 static unsigned char *dst_line[2];
211 
212 
Super2xSaI(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)213 void Super2xSaI(BITMAP * src, BITMAP * dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
214 {
215     int sbpp, dbpp;
216 
217     BITMAP *dst2 = NULL;
218 
219     if (!src || !dest)
220         return;
221 
222     sbpp = bitmap_color_depth(src);
223     dbpp = bitmap_color_depth(dest);
224 
225     if ((sbpp != xsai_depth) || (sbpp != dbpp))    /* Must be same color depth */
226         return;
227 
228     BLIT_CLIP2(src, dest, s_x, s_y, d_x, d_y, w, h, 2, 2);
229 
230     if (w < 4 || h < 4) {  /* Image is too small to be 2xSaI'ed. */
231         stretch_blit(src, dest, s_x, s_y, w, h, d_x, d_y, w * 2, h * 2);
232         return;
233     }
234 
235     sbpp = BYTES_PER_PIXEL(sbpp);
236     if (d_x || d_y)
237         dst2 = create_sub_bitmap(dest, d_x, d_y, w * 2, h * 2);
238 
239     Super2xSaI_ex(src->line[s_y] + s_x * sbpp, (unsigned int)(src->line[1] - src->line[0]), NULL, dst2 ? dst2 : dest, w, h);
240 
241     if (dst2)
242         destroy_bitmap(dst2);
243 
244     return;
245 }
246 
Super2xSaI_ex(__UInt8 * src,__UInt32 src_pitch,__UInt8 * unused,BITMAP * dest,__UInt32 width,__UInt32 height)247 void Super2xSaI_ex(__UInt8 *src, __UInt32 src_pitch, __UInt8 *unused, BITMAP *dest, __UInt32 width, __UInt32 height) {
248 
249     int j, v;
250     unsigned int x, y;
251     int sbpp = BYTES_PER_PIXEL(bitmap_color_depth(dest));
252     unsigned long color[16];
253 
254     /* Point to the first 3 lines. */
255     src_line[0] = src;
256     src_line[1] = src;
257     src_line[2] = src + src_pitch;
258     src_line[3] = src + src_pitch * 2;
259 
260     /* Can we write the results directly? */
261     if (is_video_bitmap(dest) || is_planar_bitmap(dest)) {
262         dst_line[0] = malloc(sizeof(char) * sbpp * width);
263         dst_line[1] = malloc(sizeof(char) * sbpp * width);
264         v = 1;
265     }
266     else {
267         dst_line[0] = dest->line[0];
268         dst_line[1] = dest->line[1];
269         v = 0;
270     }
271 
272     /* Set destination */
273     bmp_select(dest);
274 
275     x = 0, y = 0;
276 
277     if (PixelsPerMask == 2) {
278         unsigned short *sbp;
279         sbp = (unsigned short*)src_line[0];
280         color[0] = *sbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
281         color[4] = color[0];   color[5] = color[0];   color[6] = *(sbp + 1);  color[7] = *(sbp + 2);
282         sbp = (unsigned short*)src_line[2];
283         color[8] = *sbp;     color[9] = color[8];     color[10] = *(sbp + 1); color[11] = *(sbp + 2);
284         sbp = (unsigned short*)src_line[3];
285         color[12] = *sbp;    color[13] = color[12];   color[14] = *(sbp + 1); color[15] = *(sbp + 2);
286     }
287     else {
288         unsigned long *lbp;
289         lbp = (unsigned long*)src_line[0];
290         color[0] = *lbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
291         color[4] = color[0];   color[5] = color[0];   color[6] = *(lbp + 1);  color[7] = *(lbp + 2);
292         lbp = (unsigned long*)src_line[2];
293         color[8] = *lbp;     color[9] = color[8];     color[10] = *(lbp + 1); color[11] = *(lbp + 2);
294         lbp = (unsigned long*)src_line[3];
295         color[12] = *lbp;    color[13] = color[12];   color[14] = *(lbp + 1); color[15] = *(lbp + 2);
296     }
297 
298     for (y = 0; y < height; y++) {
299 
300         /* Todo: x = width - 2, x = width - 1 */
301 
302         for (x = 0; x < width; x++) {
303             unsigned long product1a, product1b, product2a, product2b;
304 
305 /*
306 ---------------------------------------  B0 B1 B2 B3    0  1  2  3
307                                          4  5* 6  S2 -> 4  5* 6  7
308                                          1  2  3  S1    8  9 10 11
309                                          A0 A1 A2 A3   12 13 14 15
310 --------------------------------------
311 */
312             if (color[9] == color[6] && color[5] != color[10]) {
313                 product2b = color[9];
314                 product1b = product2b;
315             }
316             else if (color[5] == color[10] && color[9] != color[6]) {
317                 product2b = color[5];
318                 product1b = product2b;
319             }
320             else if (color[5] == color[10] && color[9] == color[6]) {
321                 int r = 0;
322 
323                 r += GET_RESULT(color[6], color[5], color[8], color[13]);
324                 r += GET_RESULT(color[6], color[5], color[4], color[1]);
325                 r += GET_RESULT(color[6], color[5], color[14], color[11]);
326                 r += GET_RESULT(color[6], color[5], color[2], color[7]);
327 
328                 if (r > 0)
329                     product1b = color[6];
330                 else if (r < 0)
331                     product1b = color[5];
332                 else
333                     product1b = INTERPOLATE(color[5], color[6]);
334 
335                 product2b = product1b;
336 
337             }
338             else {
339                 if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12])
340                     product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]);
341                 else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15])
342                     product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]);
343                 else
344                     product2b = INTERPOLATE(color[9], color[10]);
345 
346                 if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0])
347                     product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]);
348                 else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3])
349                     product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]);
350                 else
351                     product1b = INTERPOLATE(color[5], color[6]);
352             }
353 
354             if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14])
355                 product2a = INTERPOLATE(color[9], color[5]);
356             else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12])
357                 product2a = INTERPOLATE(color[9], color[5]);
358             else
359                 product2a = color[9];
360 
361             if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2])
362                 product1a = INTERPOLATE(color[9], color[5]);
363             else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0])
364                 product1a = INTERPOLATE(color[9], color[5]);
365             else
366                 product1a = color[5];
367 
368             if (PixelsPerMask == 2) {
369                 *((unsigned long *) (&dst_line[0][x * 4])) = product1a | (product1b << 16);
370                 *((unsigned long *) (&dst_line[1][x * 4])) = product2a | (product2b << 16);
371             }
372             else {
373                 *((unsigned long *) (&dst_line[0][x * 8])) = product1a;
374                 *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b;
375                 *((unsigned long *) (&dst_line[1][x * 8])) = product2a;
376                 *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b;
377             }
378 
379             /* Move color matrix forward */
380             color[0] = color[1]; color[4] = color[5]; color[8] = color[9];   color[12] = color[13];
381             color[1] = color[2]; color[5] = color[6]; color[9] = color[10];  color[13] = color[14];
382             color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15];
383 
384             if (x < width - 3) {
385                 x += 3;
386                 if (PixelsPerMask == 2) {
387                     color[3] = *(((unsigned short*)src_line[0]) + x);
388                     color[7] = *(((unsigned short*)src_line[1]) + x);
389                     color[11] = *(((unsigned short*)src_line[2]) + x);
390                     color[15] = *(((unsigned short*)src_line[3]) + x);
391                 }
392                 else {
393                     color[3] = *(((unsigned long*)src_line[0]) + x);
394                     color[7] = *(((unsigned long*)src_line[1]) + x);
395                     color[11] = *(((unsigned long*)src_line[2]) + x);
396                     color[15] = *(((unsigned long*)src_line[3]) + x);
397                 }
398                 x -= 3;
399             }
400         }
401 
402         /* We're done with one line, so we shift the source lines up */
403         src_line[0] = src_line[1];
404         src_line[1] = src_line[2];
405         src_line[2] = src_line[3];
406 
407         /* Read next line */
408         if (y + 3 >= height)
409             src_line[3] = src_line[2];
410         else
411             src_line[3] = src_line[2] + src_pitch;
412 
413         /* Then shift the color matrix up */
414         if (PixelsPerMask == 2) {
415             unsigned short *sbp;
416             sbp = (unsigned short*)src_line[0];
417             color[0] = *sbp;     color[1] = color[0];    color[2] = *(sbp + 1);  color[3] = *(sbp + 2);
418             sbp = (unsigned short*)src_line[1];
419             color[4] = *sbp;     color[5] = color[4];    color[6] = *(sbp + 1);  color[7] = *(sbp + 2);
420             sbp = (unsigned short*)src_line[2];
421             color[8] = *sbp;     color[9] = color[9];    color[10] = *(sbp + 1); color[11] = *(sbp + 2);
422             sbp = (unsigned short*)src_line[3];
423             color[12] = *sbp;    color[13] = color[12];  color[14] = *(sbp + 1); color[15] = *(sbp + 2);
424         }
425         else {
426             unsigned long *lbp;
427             lbp = (unsigned long*)src_line[0];
428             color[0] = *lbp;     color[1] = color[0];    color[2] = *(lbp + 1);  color[3] = *(lbp + 2);
429             lbp = (unsigned long*)src_line[1];
430             color[4] = *lbp;     color[5] = color[4];    color[6] = *(lbp + 1);  color[7] = *(lbp + 2);
431             lbp = (unsigned long*)src_line[2];
432             color[8] = *lbp;     color[9] = color[9];    color[10] = *(lbp + 1); color[11] = *(lbp + 2);
433             lbp = (unsigned long*)src_line[3];
434             color[12] = *lbp;    color[13] = color[12];  color[14] = *(lbp + 1); color[15] = *(lbp + 2);
435         }
436 
437 
438         /* Write the 2 lines, if not already done so */
439         if (v) {
440             unsigned long dst_addr;
441 
442             dst_addr = bmp_write_line(dest, y * 2);
443             for (j = 0; j < dest->w * sbpp; j += sizeof(long))
444                 bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[0] + j)));
445 
446             dst_addr = bmp_write_line(dest, y * 2 + 1);
447             for (j = 0; j < dest->w * sbpp; j += sizeof(long))
448                 bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[1] + j)));
449         }
450         else {
451             if (y < height - 1) {
452                 dst_line[0] = dest->line[y * 2 + 2];
453                 dst_line[1] = dest->line[y * 2 + 3];
454             }
455         }
456     }
457     bmp_unwrite_line(dest);
458 
459     if (v) {
460         free(dst_line[0]);
461         free(dst_line[1]);
462     }
463 }
464 
465 
466 
SuperEagle(BITMAP * src,BITMAP * dest,int s_x,int s_y,int d_x,int d_y,int w,int h)467 void SuperEagle(BITMAP * src, BITMAP * dest, int s_x, int s_y, int d_x, int d_y, int w, int h)
468 {
469     int sbpp, dbpp;
470 
471     BITMAP *dst2 = NULL;
472 
473     if (!src || !dest)
474         return;
475 
476     sbpp = bitmap_color_depth(src);
477     dbpp = bitmap_color_depth(dest);
478 
479     if ((sbpp != xsai_depth) || (sbpp != dbpp))    /* Must be same color depth */
480         return;
481 
482     BLIT_CLIP2(src, dest, s_x, s_y, d_x, d_y, w, h, 2, 2);
483 
484     if (w < 4 || h < 4) {  /* Image is too small to be 2xSaI'ed. */
485         stretch_blit(src, dest, s_x, s_y, w, h, d_x, d_y, w * 2, h * 2);
486         return;
487     }
488 
489     sbpp = BYTES_PER_PIXEL(sbpp);
490     if (d_x || d_y)
491         dst2 = create_sub_bitmap(dest, d_x, d_y, w * 2, h * 2);
492 
493     SuperEagle_ex(src->line[s_y] + s_x * sbpp, (unsigned int)(src->line[1] - src->line[0]), NULL, dst2 ? dst2 : dest, w, h);
494 
495     if (dst2)
496         destroy_bitmap(dst2);
497 
498     return;
499 }
500 
SuperEagle_ex(__UInt8 * src,__UInt32 src_pitch,__UInt8 * unused,BITMAP * dest,__UInt32 width,__UInt32 height)501 void SuperEagle_ex(__UInt8 *src, __UInt32 src_pitch, __UInt8 *unused, BITMAP *dest, __UInt32 width, __UInt32 height) {
502 
503     int j, v;
504     unsigned int x, y;
505     int sbpp = BYTES_PER_PIXEL(bitmap_color_depth(dest));
506     unsigned long color[12];
507 
508     /* Point to the first 3 lines. */
509     src_line[0] = src;
510     src_line[1] = src;
511     src_line[2] = src + src_pitch;
512     src_line[3] = src + src_pitch * 2;
513 
514     /* Can we write the results directly? */
515     if (is_video_bitmap(dest) || is_planar_bitmap(dest)) {
516         dst_line[0] = malloc(sizeof(char) * sbpp * width);
517         dst_line[1] = malloc(sizeof(char) * sbpp * width);
518         v = 1;
519     }
520     else {
521         dst_line[0] = dest->line[0];
522         dst_line[1] = dest->line[1];
523         v = 0;
524     }
525 
526     /* Set destination */
527     bmp_select(dest);
528 
529     x = 0, y = 0;
530 
531     if (PixelsPerMask == 2) {
532         unsigned short *sbp;
533         sbp = (unsigned short*)src_line[0];
534         color[0] = *sbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
535         color[4] = *(sbp + 1); color[5] = *(sbp + 2);
536         sbp = (unsigned short*)src_line[2];
537         color[6] = *sbp;     color[7] = color[6];     color[8] = *(sbp + 1); color[9] = *(sbp + 2);
538         sbp = (unsigned short*)src_line[3];
539         color[10] = *sbp;    color[11] = *(sbp + 1);
540     }
541     else {
542         unsigned long *lbp;
543         lbp = (unsigned long*)src_line[0];
544         color[0] = *lbp;       color[1] = color[0];   color[2] = color[0];    color[3] = color[0];
545         color[4] = *(lbp + 1); color[5] = *(lbp + 2);
546         lbp = (unsigned long*)src_line[2];
547         color[6] = *lbp;     color[7] = color[6];     color[8] = *(lbp + 1); color[9] = *(lbp + 2);
548         lbp = (unsigned long*)src_line[3];
549         color[10] = *lbp;    color[11] = *(lbp + 1);
550     }
551 
552     for (y = 0; y < height; y++) {
553 
554         /* Todo: x = width - 2, x = width - 1 */
555 
556         for (x = 0; x < width; x++) {
557             unsigned long product1a, product1b, product2a, product2b;
558 
559 /*
560 ---------------------------------------     B1 B2           0  1
561                                          4  5  6  S2 ->  2  3  4  5
562                                          1  2  3  S1     6  7  8  9
563                                             A1 A2          10 11
564 */
565 
566             if (color[7] == color[4] && color[3] != color[8]) {
567                 product1b = product2a = color[7];
568 
569                 if ((color[6] == color[7]) || (color[4] == color[1]))
570                     product1a = INTERPOLATE(color[7], INTERPOLATE(color[7], color[3]));
571                 else
572                     product1a = INTERPOLATE(color[3], color[4]);
573 
574                 if ((color[4] == color[5]) || (color[7] == color[10]))
575                     product2b = INTERPOLATE(color[7], INTERPOLATE(color[7], color[8]));
576                 else
577                     product2b = INTERPOLATE(color[7], color[8]);
578             }
579             else if (color[3] == color[8] && color[7] != color[4]) {
580                 product2b = product1a = color[3];
581 
582                 if ((color[0] == color[3]) || (color[5] == color[9]))
583                     product1b = INTERPOLATE(color[3], INTERPOLATE(color[3], color[4]));
584                 else
585                     product1b = INTERPOLATE(color[3], color[1]);
586 
587                 if ((color[8] == color[11]) || (color[2] == color[3]))
588                     product2a = INTERPOLATE(color[3], INTERPOLATE(color[3], color[2]));
589                 else
590                     product2a = INTERPOLATE(color[7], color[8]);
591 
592             }
593             else if (color[3] == color[8] && color[7] == color[4]) {
594                 register int r = 0;
595 
596                 r += GET_RESULT(color[4], color[3], color[6], color[10]);
597                 r += GET_RESULT(color[4], color[3], color[2], color[0]);
598                 r += GET_RESULT(color[4], color[3], color[11], color[9]);
599                 r += GET_RESULT(color[4], color[3], color[1], color[5]);
600 
601                 if (r > 0) {
602                     product1b = product2a = color[7];
603                     product1a = product2b = INTERPOLATE(color[3], color[4]);
604                 }
605                 else if (r < 0) {
606                     product2b = product1a = color[3];
607                     product1b = product2a = INTERPOLATE(color[3], color[4]);
608                 }
609                 else {
610                     product2b = product1a = color[3];
611                     product1b = product2a = color[7];
612                 }
613             }
614             else {
615                 product2b = product1a = INTERPOLATE(color[7], color[4]);
616                 product2b = Q_INTERPOLATE(color[8], color[8], color[8], product2b);
617                 product1a = Q_INTERPOLATE(color[3], color[3], color[3], product1a);
618 
619                 product2a = product1b = INTERPOLATE(color[3], color[8]);
620                 product2a = Q_INTERPOLATE(color[7], color[7], color[7], product2a);
621                 product1b = Q_INTERPOLATE(color[4], color[4], color[4], product1b);
622             }
623 
624             if (PixelsPerMask == 2) {
625                 *((unsigned long *) (&dst_line[0][x * 4])) = product1a | (product1b << 16);
626                 *((unsigned long *) (&dst_line[1][x * 4])) = product2a | (product2b << 16);
627             }
628             else {
629                 *((unsigned long *) (&dst_line[0][x * 8])) = product1a;
630                 *((unsigned long *) (&dst_line[0][x * 8 + 4])) = product1b;
631                 *((unsigned long *) (&dst_line[1][x * 8])) = product2a;
632                 *((unsigned long *) (&dst_line[1][x * 8 + 4])) = product2b;
633             }
634 
635             /* Move color matrix forward */
636             color[0] = color[1];
637             color[2] = color[3]; color[3] = color[4]; color[4] = color[5];
638             color[6] = color[7]; color[7] = color[8]; color[8] = color[9];
639             color[10] = color[11];
640 
641             if (x < width - 2) {
642                 x += 2;
643                 if (PixelsPerMask == 2) {
644                     color[1] = *(((unsigned short*)src_line[0]) + x);
645                     if (x < width) {
646                         color[5] = *(((unsigned short*)src_line[1]) + x + 1);
647                         color[9] = *(((unsigned short*)src_line[2]) + x + 1);
648                     }
649                     color[11] = *(((unsigned short*)src_line[3]) + x);
650                 }
651                 else {
652                     color[1] = *(((unsigned long*)src_line[0]) + x);
653                     if (x < width) {
654                         color[5] = *(((unsigned long*)src_line[1]) + x + 1);
655                         color[9] = *(((unsigned long*)src_line[2]) + x + 1);
656                     }
657                     color[11] = *(((unsigned long*)src_line[3]) + x);
658                 }
659                 x -= 2;
660             }
661         }
662 
663         /* We're done with one line, so we shift the source lines up */
664         src_line[0] = src_line[1];
665         src_line[1] = src_line[2];
666         src_line[2] = src_line[3];
667 
668         /* Read next line */
669         if (y + 3 >= height)
670             src_line[3] = src_line[2];
671         else
672             src_line[3] = src_line[2] + src_pitch;
673 
674         /* Then shift the color matrix up */
675         if (PixelsPerMask == 2) {
676             unsigned short *sbp;
677             sbp = (unsigned short*)src_line[0];
678             color[0] = *sbp;     color[1] = *(sbp + 1);
679             sbp = (unsigned short*)src_line[1];
680             color[2] = *sbp;     color[3] = color[2];    color[4] = *(sbp + 1);  color[5] = *(sbp + 2);
681             sbp = (unsigned short*)src_line[2];
682             color[6] = *sbp;     color[7] = color[6];    color[8] = *(sbp + 1);  color[9] = *(sbp + 2);
683             sbp = (unsigned short*)src_line[3];
684             color[10] = *sbp;    color[11] = *(sbp + 1);
685         }
686         else {
687             unsigned long *lbp;
688             lbp = (unsigned long*)src_line[0];
689             color[0] = *lbp;     color[1] = *(lbp + 1);
690             lbp = (unsigned long*)src_line[1];
691             color[2] = *lbp;     color[3] = color[2];    color[4] = *(lbp + 1);  color[5] = *(lbp + 2);
692             lbp = (unsigned long*)src_line[2];
693             color[6] = *lbp;     color[7] = color[6];    color[8] = *(lbp + 1);  color[9] = *(lbp + 2);
694             lbp = (unsigned long*)src_line[3];
695             color[10] = *lbp;    color[11] = *(lbp + 1);
696         }
697 
698 
699         /* Write the 2 lines, if not already done so */
700         if (v) {
701             unsigned long dst_addr;
702 
703             dst_addr = bmp_write_line(dest, y * 2);
704             for (j = 0; j < dest->w * sbpp; j += sizeof(long))
705                 bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[0] + j)));
706 
707             dst_addr = bmp_write_line(dest, y * 2 + 1);
708             for (j = 0; j < dest->w * sbpp; j += sizeof(long))
709                 bmp_write32(dst_addr + j, *((unsigned long *) (dst_line[1] + j)));
710         }
711         else {
712             if (y < height - 1) {
713                 dst_line[0] = dest->line[y * 2 + 2];
714                 dst_line[1] = dest->line[y * 2 + 3];
715             }
716         }
717     }
718     bmp_unwrite_line(dest);
719 
720     if (v) {
721         free(dst_line[0]);
722         free(dst_line[1]);
723     }
724 }
725