Glide Plugin GLES2 port from mupen64plus-ae, but with special FrameSkip code
[mupen64plus-pandora.git] / source / gles2glide64 / src / GlideHQ / TextureFilters.cpp
1 /*
2 Copyright (C) 2003 Rice1964
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17
18 */
19
20 /* Copyright (C) 2007 Hiroshi Morii <koolsmoky(at)users.sourceforge.net>
21  * Modified for the Texture Filtering library
22  */
23
24 #include <string.h>
25 #include "TextureFilters.h"
26
27 /************************************************************************/
28 /* 2X filters                                                           */
29 /************************************************************************/
30
31 #define DWORD_MAKE(r, g, b, a)   ((uint32) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)))
32 #define WORD_MAKE(r, g, b, a)   ((uint16) (((a) << 12) | ((r) << 8) | ((g) << 4) | (b)))
33
34 // Basic 2x R8G8B8A8 filter with interpolation
35
36 void Texture2x_32(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
37 {
38   uint32 *pDst1, *pDst2;
39   uint32 *pSrc, *pSrc2;
40   uint32 nWidth = width;
41   uint32 nHeight = height;
42
43   uint32 b1;
44   uint32 g1;
45   uint32 r1;
46   uint32 a1;
47   uint32 b2;
48   uint32 g2;
49   uint32 r2;
50   uint32 a2;
51   uint32 b3;
52   uint32 g3;
53   uint32 r3;
54   uint32 a3;
55   uint32 b4;
56   uint32 g4;
57   uint32 r4;
58   uint32 a4;
59
60   uint32 xSrc;
61   uint32 ySrc;
62
63   for (ySrc = 0; ySrc < nHeight; ySrc++)
64   {
65     pSrc = (uint32*)(((uint8*)srcPtr)+ySrc*srcPitch);
66     pSrc2 = (uint32*)(((uint8*)srcPtr)+(ySrc+1)*srcPitch);
67     pDst1 = (uint32*)(((uint8*)dstPtr)+(ySrc*2)*dstPitch);
68     pDst2 = (uint32*)(((uint8*)dstPtr)+(ySrc*2+1)*dstPitch);
69
70     for (xSrc = 0; xSrc < nWidth; xSrc++)
71     {
72       b1 = (pSrc[xSrc]>>0)&0xFF;
73       g1 = (pSrc[xSrc]>>8)&0xFF;
74       r1 = (pSrc[xSrc]>>16)&0xFF;
75       a1 = (pSrc[xSrc]>>24)&0xFF;
76
77       // Pixel 1
78       pDst1[xSrc*2] = pSrc[xSrc];
79
80       // Pixel 2
81       if( xSrc<nWidth-1 )
82       {
83         b2 = (pSrc[xSrc+1]>>0)&0xFF;
84         g2 = (pSrc[xSrc+1]>>8)&0xFF;
85         r2 = (pSrc[xSrc+1]>>16)&0xFF;
86         a2 = (pSrc[xSrc+1]>>24)&0xFF;
87         pDst1[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
88       }
89       else
90         pDst1[xSrc*2+1] = pSrc[xSrc];
91
92       // Pixel 3
93       if( ySrc<nHeight-1 )
94       {
95         b3 = (pSrc2[xSrc]>>0)&0xFF;
96         g3 = (pSrc2[xSrc]>>8)&0xFF;
97         r3 = (pSrc2[xSrc]>>16)&0xFF;
98         a3 = (pSrc2[xSrc]>>24)&0xFF;
99         pDst2[xSrc*2] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
100         if( xSrc<nWidth-1 )
101         {
102           b4 = (pSrc2[xSrc+1]>>0)&0xFF;
103           g4 = (pSrc2[xSrc+1]>>8)&0xFF;
104           r4 = (pSrc2[xSrc+1]>>16)&0xFF;
105           a4 = (pSrc2[xSrc+1]>>24)&0xFF;
106           // Pixel 4
107           pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
108         }
109         else
110         {
111           // Pixel 4
112           pDst2[xSrc*2+1] = DWORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
113         }
114       }
115       else
116       {
117         // Pixel 3
118         pDst2[xSrc*2] = pSrc[xSrc];
119         // Pixel 4
120         if( xSrc<nWidth-1 )
121         {
122           pDst2[xSrc*2+1] = DWORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
123         }
124         else
125         {
126           pDst2[xSrc*2+1] = pSrc[xSrc];
127         }
128       }
129     }
130   }
131 }
132
133 #if !_16BPP_HACK
134 // Basic 2x R4G4B4A4 filter with interpolation
135 void Texture2x_16(uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height)
136 {
137   uint16 *pDst1, *pDst2;
138   uint16 *pSrc, *pSrc2;
139   uint32 nWidth = width;
140   uint32 nHeight = height;
141
142   uint16 b1;
143   uint16 g1;
144   uint16 r1;
145   uint16 a1;
146   uint16 b2;
147   uint16 g2;
148   uint16 r2;
149   uint16 a2;
150   uint16 b3;
151   uint16 g3;
152   uint16 r3;
153   uint16 a3;
154   uint16 b4;
155   uint16 g4;
156   uint16 r4;
157   uint16 a4;
158
159   uint16 xSrc;
160   uint16 ySrc;
161
162   for (ySrc = 0; ySrc < nHeight; ySrc++)
163   {
164     pSrc = (uint16*)(((uint8*)srcPtr)+ySrc*srcPitch);
165     pSrc2 = (uint16*)(((uint8*)srcPtr)+(ySrc+1)*srcPitch);
166     pDst1 = (uint16*)(((uint8*)dstPtr)+(ySrc*2)*dstPitch);
167     pDst2 = (uint16*)(((uint8*)dstPtr)+(ySrc*2+1)*dstPitch);
168
169     for (xSrc = 0; xSrc < nWidth; xSrc++)
170     {
171       b1 = (pSrc[xSrc]>> 0)&0xF;
172       g1 = (pSrc[xSrc]>> 4)&0xF;
173       r1 = (pSrc[xSrc]>> 8)&0xF;
174       a1 = (pSrc[xSrc]>>12)&0xF;
175
176       if( xSrc<nWidth-1 )
177       {
178         b2 = (pSrc[xSrc+1]>> 0)&0xF;
179         g2 = (pSrc[xSrc+1]>> 4)&0xF;
180         r2 = (pSrc[xSrc+1]>> 8)&0xF;
181         a2 = (pSrc[xSrc+1]>>12)&0xF;
182       }
183
184       if( ySrc<nHeight-1 )
185       {
186         b3 = (pSrc2[xSrc]>> 0)&0xF;
187         g3 = (pSrc2[xSrc]>> 4)&0xF;
188         r3 = (pSrc2[xSrc]>> 8)&0xF;
189         a3 = (pSrc2[xSrc]>>12)&0xF;
190         if( xSrc<nWidth-1 )
191         {
192           b4 = (pSrc2[xSrc+1]>> 0)&0xF;
193           g4 = (pSrc2[xSrc+1]>> 4)&0xF;
194           r4 = (pSrc2[xSrc+1]>> 8)&0xF;
195           a4 = (pSrc2[xSrc+1]>>12)&0xF;
196         }
197       }
198
199       // Pixel 1
200       pDst1[xSrc*2] = pSrc[xSrc];
201
202       // Pixel 2
203       if( xSrc<nWidth-1 )
204       {
205         pDst1[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
206       }
207       else
208         pDst1[xSrc*2+1] = pSrc[xSrc];
209
210
211       // Pixel 3
212       if( ySrc<nHeight-1 )
213       {
214         pDst2[xSrc*2] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
215       }
216       else
217         pDst2[xSrc*2] = pSrc[xSrc];
218
219       // Pixel 4
220       if( xSrc<nWidth-1 )
221       {
222         if( ySrc<nHeight-1 )
223         {
224           pDst2[xSrc*2+1] = WORD_MAKE((r1+r2+r3+r4)/4, (g1+g2+g3+g4)/4, (b1+b2+b3+b4)/4, (a1+a2+a3+a4)/4);
225         }
226         else
227         {
228           pDst2[xSrc*2+1] = WORD_MAKE((r1+r2)/2, (g1+g2)/2, (b1+b2)/2, (a1+a2)/2);
229         }
230       }
231       else
232       {
233         if( ySrc<nHeight-1 )
234         {
235           pDst2[xSrc*2+1] = WORD_MAKE((r1+r3)/2, (g1+g3)/2, (b1+b3)/2, (a1+a3)/2);
236         }
237         else
238           pDst2[xSrc*2+1] = pSrc[xSrc];
239       }
240     }
241   }
242 }
243 #endif /* !_16BPP_HACK */
244
245 /*
246  * Sharp filters
247  * Hiroshi Morii <koolsmoky@users.sourceforge.net>
248  */
249 void SharpFilter_8888(uint32 *src, uint32 srcwidth, uint32 srcheight, uint32 *dest, uint32 filter)
250 {
251   // NOTE: for now we get away with copying the boundaries
252   //       filter the boundaries if we face problems
253
254   uint32 mul1, mul2, mul3, shift4;
255
256   uint32 x,y,z;
257   uint32 *_src1, *_src2, *_src3, *_dest;
258   uint32 val[4];
259   uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
260
261   switch( filter )
262   {
263   case SHARP_FILTER_2:
264     mul1=1;
265     mul2=8;
266     mul3=12;
267     shift4=2;
268     break;
269   case SHARP_FILTER_1:
270   default:
271     mul1=1;
272     mul2=8;
273     mul3=16;
274     shift4=3;
275     break;
276   }
277
278   // setup rows
279   _src1 = src;
280   _src2 = _src1 + srcwidth;
281   _src3 = _src2 + srcwidth;
282   _dest = dest;
283
284   // copy the first row
285   memcpy(_dest, _src1, (srcwidth << 2));
286   _dest += srcwidth;
287   // filter 2nd row to 1 row before the last
288   for (y = 1; y < srcheight-1; y++) {
289     // copy the first pixel
290     _dest[0] = *_src2;
291     // filter 2nd pixel to 1 pixel before last
292     for (x = 1; x < srcwidth-1; x++) {
293       for (z=0; z<4; z++) {
294         t1 = *((uint8*)(_src1+x-1)+z);
295         t2 = *((uint8*)(_src1+x  )+z);
296         t3 = *((uint8*)(_src1+x+1)+z);
297         t4 = *((uint8*)(_src2+x-1)+z);
298         t5 = *((uint8*)(_src2+x  )+z);
299         t6 = *((uint8*)(_src2+x+1)+z);
300         t7 = *((uint8*)(_src3+x-1)+z);
301         t8 = *((uint8*)(_src3+x  )+z);
302         t9 = *((uint8*)(_src3+x+1)+z);
303         
304         if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) {
305           val[z]= ((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4;
306           if (val[z] > 0xFF) val[z] = 0xFF;
307         } else {
308           val[z] = t5;
309         }
310       }
311       _dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
312     }
313     // copy the ending pixel
314     _dest[srcwidth-1] = *(_src3 - 1);
315     // next row
316     _src1 += srcwidth;
317     _src2 += srcwidth;
318     _src3 += srcwidth;
319     _dest += srcwidth;
320   }
321   // copy the last row
322   memcpy(_dest, _src2, (srcwidth << 2));
323 }
324
325 #if !_16BPP_HACK
326 void SharpFilter_4444(uint16 *src, uint32 srcwidth, uint32 srcheight, uint16 *dest, uint32 filter)
327 {
328   // NOTE: for now we get away with copying the boundaries
329   //       filter the boundaries if we face problems
330
331   uint16 mul1, mul2, mul3, shift4;
332
333   uint32 x,y,z;
334   uint16 *_src1, *_src2, *_src3, *_dest;
335   uint16 val[4];
336   uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
337
338   switch( filter ) {
339   case SHARP_FILTER_2:
340     mul1=1;
341     mul2=8;
342     mul3=12;
343     shift4=2;
344     break;
345   case SHARP_FILTER_1:
346   default:
347     mul1=1;
348     mul2=8;
349     mul3=16;
350     shift4=3;
351     break;
352   }
353
354   // setup rows
355   _src1 = src;
356   _src2 = _src1 + srcwidth;
357   _src3 = _src2 + srcwidth;
358   _dest = dest;
359
360   // copy the first row
361   memcpy(_dest, _src1, (srcwidth << 1));
362   _dest += srcwidth;
363   // filter 2nd row to 1 row before the last
364   for( y = 1; y < srcheight - 1; y++) {
365     // copy the first pixel
366     _dest[0] = *_src2;
367     // filter 2nd pixel to 1 pixel before last
368     for( x = 1; x < srcwidth - 1; x++) {
369       for( z = 0; z < 4; z++ ) {
370         /* Hiroshi Morii <koolsmoky@users.sourceforge.net>
371          * Read the entire 16bit pixel and then extract the A,R,G,B components.
372          */
373         uint32 shift = z << 2;
374         t1 = ((*((uint16*)(_src1+x-1))) >> shift) & 0xF;
375         t2 = ((*((uint16*)(_src1+x  ))) >> shift) & 0xF;
376         t3 = ((*((uint16*)(_src1+x+1))) >> shift) & 0xF;
377         t4 = ((*((uint16*)(_src2+x-1))) >> shift) & 0xF;
378         t5 = ((*((uint16*)(_src2+x  ))) >> shift) & 0xF;
379         t6 = ((*((uint16*)(_src2+x+1))) >> shift) & 0xF;
380         t7 = ((*((uint16*)(_src3+x-1))) >> shift) & 0xF;
381         t8 = ((*((uint16*)(_src3+x  ))) >> shift) & 0xF;
382         t9 = ((*((uint16*)(_src3+x+1))) >> shift) & 0xF;
383         
384         if( (t5*mul2) > (t1+t3+t7+t9+t2+t4+t6+t8)*mul1 ) {
385           val[z] = ((t5*mul3) - (t1+t3+t7+t9+t2+t4+t6+t8)*mul1)>>shift4;
386           if (val[z] > 0xF) val[z] = 0xF;
387         } else {
388           val[z] = t5;
389         }
390       }
391       _dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
392     }
393     // copy the ending pixel
394     _dest[srcwidth-1] = *(_src3 - 1);
395     // next row
396     _src1 += srcwidth;
397     _src2 += srcwidth;
398     _src3 += srcwidth;
399     _dest += srcwidth;
400   }
401   // copy the last row
402   memcpy(_dest, _src2, (srcwidth << 1));
403 }
404 #endif /* !_16BPP_HACK */
405
406 /*
407  * Smooth filters
408  * Hiroshi Morii <koolsmoky@users.sourceforge.net>
409  */
410 void SmoothFilter_8888(uint32 *src, uint32 srcwidth, uint32 srcheight, uint32 *dest, uint32 filter)
411 {
412   // NOTE: for now we get away with copying the boundaries
413   //       filter the boundaries if we face problems
414
415   uint32 mul1, mul2, mul3, shift4;
416
417   uint32 x,y,z;
418   uint32 *_src1, *_src2, *_src3, *_dest;
419   uint32 val[4];
420   uint32 t1,t2,t3,t4,t5,t6,t7,t8,t9;
421
422   switch( filter ) {
423   case SMOOTH_FILTER_4:
424     mul1=1;
425     mul2=2;
426     mul3=4;
427     shift4=4;
428     break;
429   case SMOOTH_FILTER_3:
430     mul1=1;
431     mul2=1;
432     mul3=8;
433     shift4=4;
434     break;
435   case SMOOTH_FILTER_2:
436     mul1=1;
437     mul2=1;
438     mul3=2;
439     shift4=2;
440     break;
441   case SMOOTH_FILTER_1:
442   default:
443     mul1=1;
444     mul2=1;
445     mul3=6;
446     shift4=3;
447     break;
448   }
449
450   switch (filter) {
451   case SMOOTH_FILTER_3:
452   case SMOOTH_FILTER_4:
453     // setup rows
454     _src1 = src;
455     _src2 = _src1 + srcwidth;
456     _src3 = _src2 + srcwidth;
457     _dest = dest;
458     // copy the first row
459     memcpy(_dest, _src1, (srcwidth << 2));
460     _dest += srcwidth;
461     // filter 2nd row to 1 row before the last
462     for (y = 1; y < srcheight - 1; y++){
463       // copy the first pixel
464       _dest[0] = _src2[0];
465       // filter 2nd pixel to 1 pixel before last
466       for (x = 1; x < srcwidth - 1; x++) {
467         for (z = 0; z < 4; z++ ) {
468           t1 = *((uint8*)(_src1+x-1)+z);
469           t2 = *((uint8*)(_src1+x  )+z);
470           t3 = *((uint8*)(_src1+x+1)+z);
471           t4 = *((uint8*)(_src2+x-1)+z);
472           t5 = *((uint8*)(_src2+x  )+z);
473           t6 = *((uint8*)(_src2+x+1)+z);
474           t7 = *((uint8*)(_src3+x-1)+z);
475           t8 = *((uint8*)(_src3+x  )+z);
476           t9 = *((uint8*)(_src3+x+1)+z);
477           /* the component value must not overflow 0xFF */
478           val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
479           if (val[z] > 0xFF) val[z] = 0xFF;
480         }
481         _dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
482       }
483       // copy the ending pixel
484       _dest[srcwidth-1] = *(_src3 - 1);
485       // next row
486       _src1 += srcwidth;
487       _src2 += srcwidth;
488       _src3 += srcwidth;
489       _dest += srcwidth;
490     }
491     // copy the last row
492     memcpy(_dest, _src2, (srcwidth << 2));
493     break;
494   case SMOOTH_FILTER_1:
495   case SMOOTH_FILTER_2:
496   default:
497     // setup rows
498     _src1 = src;
499     _src2 = _src1 + srcwidth;
500     _src3 = _src2 + srcwidth;
501     _dest = dest;
502     // copy the first row
503     memcpy(_dest, _src1, (srcwidth << 2));
504     _dest += srcwidth;
505     // filter 2nd row to 1 row before the last
506     for (y = 1; y < srcheight - 1; y++) {
507       // filter 1st pixel to the last
508       if (y & 1) {
509         for( x = 0; x < srcwidth; x++) {
510           for( z = 0; z < 4; z++ ) {
511             t2 = *((uint8*)(_src1+x  )+z);
512             t5 = *((uint8*)(_src2+x  )+z);
513             t8 = *((uint8*)(_src3+x  )+z);
514             /* the component value must not overflow 0xFF */
515             val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
516             if (val[z] > 0xFF) val[z] = 0xFF;
517           }
518           _dest[x] = val[0]|(val[1]<<8)|(val[2]<<16)|(val[3]<<24);
519         }
520       } else {
521          memcpy(_dest, _src2, (srcwidth << 2));
522       }
523       // next row
524       _src1 += srcwidth;
525       _src2 += srcwidth;
526       _src3 += srcwidth;
527       _dest += srcwidth;
528     }
529     // copy the last row
530     memcpy(_dest, _src2, (srcwidth << 2));
531     break;
532   }
533 }
534
535 #if !_16BPP_HACK
536 void SmoothFilter_4444(uint16 *src, uint32 srcwidth, uint32 srcheight, uint16 *dest, uint32 filter)
537 {
538   // NOTE: for now we get away with copying the boundaries
539   //       filter the boundaries if we face problems
540
541   uint16 mul1, mul2, mul3, shift4;
542
543   uint32 x,y,z;
544   uint16 *_src1, *_src2, *_src3, *_dest;
545   uint16 val[4];
546   uint16 t1,t2,t3,t4,t5,t6,t7,t8,t9;
547
548   switch( filter ) {
549   case SMOOTH_FILTER_4:
550     mul1=1;
551     mul2=2;
552     mul3=4;
553     shift4=4;
554     break;
555   case SMOOTH_FILTER_3:
556     mul1=1;
557     mul2=1;
558     mul3=8;
559     shift4=4;
560     break;
561   case SMOOTH_FILTER_2:
562     mul1=1;
563     mul2=1;
564     mul3=2;
565     shift4=2;
566     break;
567   case SMOOTH_FILTER_1:
568   default:
569     mul1=1;
570     mul2=1;
571     mul3=6;
572     shift4=3;
573     break;
574   }
575
576   switch (filter) {
577   case SMOOTH_FILTER_3:
578   case SMOOTH_FILTER_4:
579     // setup rows
580     _src1 = src;
581     _src2 = _src1 + srcwidth;
582     _src3 = _src2 + srcwidth;
583     _dest = dest;
584     // copy the first row
585     memcpy(_dest, _src1, (srcwidth << 1));
586     _dest += srcwidth;
587     // filter 2nd row to 1 row before the last
588     for (y = 1; y < srcheight - 1; y++) {
589       // copy the first pixel
590       _dest[0] = *_src2;
591       // filter 2nd pixel to 1 pixel before last
592       for (x = 1; x < srcwidth - 1; x++) {
593         for (z = 0; z < 4; z++ ) {
594           /* Read the entire 16bit pixel and then extract the A,R,G,B components. */
595           uint32 shift = z << 2;
596           t1 = ((*(uint16*)(_src1+x-1)) >> shift) & 0xF;
597           t2 = ((*(uint16*)(_src1+x  )) >> shift) & 0xF;
598           t3 = ((*(uint16*)(_src1+x+1)) >> shift) & 0xF;
599           t4 = ((*(uint16*)(_src2+x-1)) >> shift) & 0xF;
600           t5 = ((*(uint16*)(_src2+x  )) >> shift) & 0xF;
601           t6 = ((*(uint16*)(_src2+x+1)) >> shift) & 0xF;
602           t7 = ((*(uint16*)(_src3+x-1)) >> shift) & 0xF;
603           t8 = ((*(uint16*)(_src3+x  )) >> shift) & 0xF;
604           t9 = ((*(uint16*)(_src3+x+1)) >> shift) & 0xF;
605           /* the component value must not overflow 0xF */
606           val[z] = ((t1+t3+t7+t9)*mul1+((t2+t4+t6+t8)*mul2)+(t5*mul3))>>shift4;
607           if (val[z] > 0xF) val[z] = 0xF;
608         }
609         _dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
610       }
611       // copy the ending pixel
612       _dest[srcwidth-1] = *(_src3 - 1);
613       // next row
614       _src1 += srcwidth;
615       _src2 += srcwidth;
616       _src3 += srcwidth;
617       _dest += srcwidth;
618     }
619     // copy the last row
620     memcpy(_dest, _src2, (srcwidth << 1));
621     break;
622   case SMOOTH_FILTER_1:
623   case SMOOTH_FILTER_2:
624   default:
625     // setup rows
626     _src1 = src;
627     _src2 = _src1 + srcwidth;
628     _src3 = _src2 + srcwidth;
629     _dest = dest;
630     // copy the first row
631     memcpy(_dest, _src1, (srcwidth << 1));
632     _dest += srcwidth;
633     // filter 2nd row to 1 row before the last
634     for( y = 1; y < srcheight - 1; y++) {
635       if (y & 1) {
636         for( x = 0; x < srcwidth; x++) {
637           for( z = 0; z < 4; z++ ) {
638             /* Read the entire 16bit pixel and then extract the A,R,G,B components. */
639             uint32 shift = z << 2;
640             t2 = ((*(uint16*)(_src1+x)) >> shift) & 0xF;
641             t5 = ((*(uint16*)(_src2+x)) >> shift) & 0xF;
642             t8 = ((*(uint16*)(_src3+x)) >> shift) & 0xF;
643             /* the component value must not overflow 0xF */
644             val[z] = ((t2+t8)*mul2+(t5*mul3))>>shift4;
645             if (val[z] > 0xF) val[z] = 0xF;
646           }
647           _dest[x] = val[0]|(val[1]<<4)|(val[2]<<8)|(val[3]<<12);
648         }
649       } else {
650          memcpy(_dest, _src2, (srcwidth << 1));
651       }
652       // next row
653       _src1 += srcwidth;
654       _src2 += srcwidth;
655       _src3 += srcwidth;
656       _dest += srcwidth;
657     }
658     // copy the last row
659     memcpy(_dest, _src2, (srcwidth << 1));
660     break;
661   }
662 }
663 #endif /* !_16BPP_HACK */
664
665 void filter_8888(uint32 *src, uint32 srcwidth, uint32 srcheight, uint32 *dest, uint32 filter) {
666   switch (filter & ENHANCEMENT_MASK) {
667   case HQ4X_ENHANCEMENT:
668     hq4x_8888((uint8*)src, (uint8*)dest, srcwidth, srcheight, srcwidth, (srcwidth << 4));
669     return;
670   case HQ2X_ENHANCEMENT:
671     hq2x_32((uint8*)src, (srcwidth << 2), (uint8*)dest, (srcwidth << 3), srcwidth, srcheight);
672     return;
673   case HQ2XS_ENHANCEMENT:
674     hq2xS_32((uint8*)src, (srcwidth << 2), (uint8*)dest, (srcwidth << 3), srcwidth, srcheight);
675     return;
676   case LQ2X_ENHANCEMENT:
677     lq2x_32((uint8*)src, (srcwidth << 2), (uint8*)dest, (srcwidth << 3), srcwidth, srcheight);
678     return;
679   case LQ2XS_ENHANCEMENT:
680     lq2xS_32((uint8*)src, (srcwidth << 2), (uint8*)dest, (srcwidth << 3), srcwidth, srcheight);
681     return;
682   case X2SAI_ENHANCEMENT:
683     Super2xSaI_8888((uint32*)src, (uint32*)dest, srcwidth, srcheight, srcwidth);
684     return;
685   case X2_ENHANCEMENT:
686     Texture2x_32((uint8*)src, (srcwidth << 2), (uint8*)dest, (srcwidth << 3), srcwidth, srcheight);
687     return;
688   }
689
690   switch (filter & (SMOOTH_FILTER_MASK|SHARP_FILTER_MASK)) {
691   case SMOOTH_FILTER_1:
692   case SMOOTH_FILTER_2:
693   case SMOOTH_FILTER_3:
694   case SMOOTH_FILTER_4:
695     SmoothFilter_8888((uint32*)src, srcwidth, srcheight, (uint32*)dest, (filter & SMOOTH_FILTER_MASK));
696     return;
697   case SHARP_FILTER_1:
698   case SHARP_FILTER_2:
699     SharpFilter_8888((uint32*)src, srcwidth, srcheight, (uint32*)dest, (filter & SHARP_FILTER_MASK));
700     return;
701   }
702 }