1 // epxb, epxc filter, added by regret
2 // source from Snes9X rerecording (http://code.google.com/p/snes9x151-rerecording/)
3
4 typedef unsigned char uint8;
5 typedef unsigned short uint16;
6 typedef signed char int8;
7 typedef short int16;
8 typedef int int32;
9 typedef unsigned int uint32;
10 # ifdef __GNUC__ /* long long is not part of ISO C++ */
11 __extension__
12 # endif
13 typedef long long int64;
14 typedef unsigned long long uint64;
15
16 #define Mask_2 0x07E0 // 00000 111111 00000
17 #define Mask13 0xF81F // 11111 000000 11111
18 #define Mask_1 0x001F // 00000 000000 11111
19 #define Mask_3 0xF800 // 11111 000000 00000
20 #define CONVERT_16_TO_32(pixel) \
21 (((((pixel) >> 11) ) << /*RedShift+3*/ 19) | \
22 ((((pixel) >> 6) & 0x1f) << /*GreenShift+3*/11) | \
23 (((pixel) & 0x1f) << /*BlueShift+3*/ 3))
24
25 #define Interp01(c1, c2) \
26 ((((c1) == (c2)) ? (c1) : \
27 (((((((c1) & Mask_2) * 3) + ((c2) & Mask_2)) >> 2) & Mask_2) + \
28 ((((((c1) & Mask13) * 3) + ((c2) & Mask13)) >> 2) & Mask13))))
29
30 #ifdef LSB_FIRST
31 #define TWO_PIX(left,right) ((left) | ((right) << 16))
32 #define THREE_PIX(left,middle,right) uint48((left) | ((middle) << 16), (right))
33 #define TWO_PIX_32(left,right) (CONVERT_16_TO_32(left) | ((uint64)CONVERT_16_TO_32(right) << 32))
34 #define THREE_PIX_32(left,middle,right) uint96(CONVERT_16_TO_32(left) | ((uint64)CONVERT_16_TO_32(middle) << 32), CONVERT_16_TO_32(right))
35 #else
36 #define TWO_PIX(left,right) ((right) | ((left) << 16))
37 #define THREE_PIX(left,middle,right) uint48((middle) | ((left) << 16), (right)) // is this right?
38 // #define THREE_PIX(left,middle,right) uint48((right) | ((middle) << 16), (left)) // or this?
39 #endif
40
41 // shared EPX-type loop macros
42 // All of these parameters will be constant values,
43 // so I hope the compiler is smart enough to optimize away "if(0) ..."
44
45 #define DrawRows(scale,diags) \
46 { \
47 h = srcHeight - 1; \
48 DoRow(0,1,scale,diags); \
49 for (h = srcHeight - 2; h; h--) \
50 DoRow(1,1,scale,diags); \
51 DoRow(1,0,scale,diags); \
52 }
53
54 #define DoRow(topValid,botValid,scale,diags) \
55 { \
56 w = srcWidth - 1; \
57 InitLine(topValid,botValid,scale,diags); \
58 DrawPix(0,topValid,0,botValid); \
59 for (w = srcWidth - 2; w; w--) \
60 { \
61 NextPixel(topValid,botValid,1,diags); \
62 DrawPix(topValid,topValid,botValid,botValid); \
63 } \
64 NextPixel(topValid,botValid,0,diags); \
65 DrawPix(topValid,0,botValid,0); \
66 srcPtr += srcPitch; \
67 dstPtr += dstPitch * scale; \
68 }
69
70 #define InitLine(topValid, botValid, scale, diags) \
71 { \
72 if(topValid) uP = (uint16 *) (srcPtr - srcPitch); \
73 if(botValid) lP = (uint16 *) (srcPtr + srcPitch); \
74 sP = (uint16 *) srcPtr; \
75 dP1 = (destType *) dstPtr; \
76 dP2 = (destType *) (dstPtr + dstPitch); \
77 if(scale>=3) dP3 = (destType *) (dstPtr + (dstPitch<<1)); \
78 if(topValid) colorD = *uP++; \
79 if(botValid) colorB = *lP++; \
80 colorX = *sP++; \
81 colorC = *sP; \
82 if(diags) if(topValid) colorH = *uP; \
83 if(diags) if(botValid) colorG = *lP; \
84 }
85
86 #define NextPixel(topValid, botValid, rightValid, diags) \
87 { \
88 colorA = colorX; \
89 colorX = colorC; \
90 if(rightValid) colorC = *++sP; \
91 if(diags) { \
92 if(botValid){ \
93 colorF = colorB; \
94 colorB = colorG; \
95 if(rightValid) colorG = *++lP; \
96 } \
97 if(topValid){ \
98 colorE = colorD; \
99 colorD = colorH; \
100 if(rightValid) colorH = *++uP; \
101 } \
102 } else { \
103 if(botValid) colorB = *lP++; \
104 if(topValid) colorD = *uP++; \
105 } \
106 }
107
108 #define DrawInit(scale,uintDest) \
109 uint8 *srcPtr = src, *dstPtr = dst; \
110 const uint32 srcPitch = srcpitch, dstPitch = dstpitch; \
111 const uint32 srcHeight = nHeight; \
112 const uint32 srcWidth = nWidth; \
113 uint16 colorX, colorA, colorB, colorC, colorD, colorE=0, colorF=0, colorG=0, colorH=0; \
114 uint16 *sP, *uP, *lP; \
115 typedef uintDest destType; \
116 destType *dP1, *dP2, *dP3=0; \
117 int w, h;
118
119 // code for improved 2X EPX, which tends to do better with diagonal edges than regular EPX
RenderEPXB(unsigned char * src,unsigned int srcpitch,unsigned char * dst,unsigned int dstpitch,int nWidth,int nHeight,int vidDepth)120 void RenderEPXB(unsigned char *src, unsigned int srcpitch, unsigned char *dst, unsigned int dstpitch, int nWidth, int nHeight, int vidDepth)
121 {
122 // E D H
123 // A X C
124 // F B G
125 #define DrawPix(on00,on01,on10,on11) /* on00 on01 */ \
126 { /* on10 on11 */ \
127 if ((((on00||on10)?colorA:colorX) != ((on01||on11)?colorC:colorX)) \
128 && (((on10||on11)?colorB:colorX) != ((on00||on01)?colorD:colorX)) \
129 && ((!on00||!on01||!on10|!on11) || \
130 ((colorX == colorA) || (colorX == colorB) || (colorX == colorC) || (colorX == colorD) || /* diagonal */ \
131 (((colorE != colorG) || (colorX == colorF) || (colorX == colorH)) && /* edge */ \
132 ((colorF != colorH) || (colorX == colorE) || (colorX == colorG)))))) /* smoothing */ \
133 { \
134 *dP1++ = _TWO_PIX((on00 && colorD == colorA && (colorX != colorE || colorX != colorG || colorD != colorH || colorA != colorF)) ? colorD : colorX, \
135 (on01 && colorC == colorD && (colorX != colorH || colorX != colorF || colorC != colorG || colorD != colorE)) ? colorC : colorX); \
136 *dP2++ = _TWO_PIX((on10 && colorA == colorB && (colorX != colorF || colorX != colorH || colorA != colorE || colorB != colorG)) ? colorA : colorX, \
137 (on11 && colorB == colorC && (colorX != colorG || colorX != colorE || colorB != colorF || colorC != colorH)) ? colorB : colorX); \
138 } else { \
139 *dP1++ = _TWO_PIX(colorX, colorX); \
140 *dP2++ = _TWO_PIX(colorX, colorX); \
141 } \
142 }
143
144 // again, this supports 32-bit or 16-bit rendering
145 if(vidDepth == 32)
146 {
147 #define _TWO_PIX TWO_PIX_32
148 DrawInit(2,uint64);
149 DrawRows(2,1); // 2x scale, and diags is on since we do use all 8 surrounding pixels
150 #undef _TWO_PIX
151 }
152 else
153 {
154 #define _TWO_PIX TWO_PIX
155 DrawInit(2,uint32);
156 DrawRows(2,1); // 2x scale, and diags is on since we do use all 8 surrounding pixels
157 #undef _TWO_PIX
158 }
159
160 #undef DrawPix
161 }
162
163 #define Interp44(c1, c2, c3, c4) \
164 ((((((c1) & Mask_2) * 5 + ((c2) & Mask_2) + ((c3) & Mask_2) + ((c4) & Mask_2)) >> 3) & Mask_2) + \
165 (((((c1) & Mask13) * 5 + ((c2) & Mask13) + ((c3) & Mask13) + ((c4) & Mask13)) >> 3) & Mask13))
166
167 // EPX3 scaled down to 2X
RenderEPXC(unsigned char * src,unsigned int srcpitch,unsigned char * dst,unsigned int dstpitch,int nWidth,int nHeight,int vidDepth)168 void RenderEPXC(unsigned char *src, unsigned int srcpitch, unsigned char *dst, unsigned int dstpitch, int nWidth, int nHeight, int vidDepth)
169 {
170 // E D H
171 // A X C
172 // F B G
173 #define DrawPix(on00,on01,on10,on11) /* on00 on01 */ \
174 { /* on10 on11 */ \
175 if ((((on00||on10)?colorA:colorX) != ((on01||on11)?colorC:colorX)) \
176 && (((on10||on11)?colorB:colorX) != ((on00||on01)?colorD:colorX))) \
177 { \
178 const bool XnE = colorX != colorE; \
179 const bool XnF = colorX != colorF; \
180 const bool XnG = colorX != colorG; \
181 const bool XnH = colorX != colorH; \
182 const bool DA = on00 && colorD == colorA && (XnE || XnG || colorD != colorH || colorA != colorF); \
183 const bool AB = on10 && colorA == colorB && (XnF || XnH || colorA != colorE || colorB != colorG); \
184 const bool BC = on11 && colorB == colorC && (XnG || XnE || colorB != colorF || colorC != colorH); \
185 const bool CD = on01 && colorC == colorD && (XnH || XnF || colorC != colorG || colorD != colorE); \
186 if (!on00||!on01||!on10||!on11 || ((colorA != colorC) && (colorB != colorD) && \
187 ((colorX == colorA) || (colorX==colorB) || (colorX==colorC) || (colorX==colorD) || (colorX==colorE) || (colorX==colorF) || (colorX==colorG) || (colorX==colorH)))) \
188 { \
189 const uint16 colorAA = on00&&on10 && ((DA && XnF) || (AB && XnE)) ? colorA : colorX; \
190 const uint16 colorBB = on10&&on11 && ((AB && XnG) || (BC && XnF)) ? colorB : colorX; \
191 const uint16 colorCC = on01&&on11 && ((BC && XnH) || (CD && XnG)) ? colorC : colorX; \
192 const uint16 colorDD = on00&&on01 && ((CD && XnE) || (DA && XnH)) ? colorD : colorX; \
193 *dP1++ = _TWO_PIX(Interp44(on00 && DA ? colorA : colorX, colorDD, colorAA, colorX), Interp44(on01 && CD ? colorC : colorX, colorBB, colorCC, colorX)); \
194 *dP2++ = _TWO_PIX(Interp44(on10 && AB ? colorA : colorX, colorAA, colorBB, colorX), Interp44(on11 && BC ? colorC : colorX, colorCC, colorDD, colorX)); \
195 } else { \
196 *dP1++ = _TWO_PIX(Interp01(colorX, on00 && DA && (colorX!=colorB&&colorX!=colorC) ? colorA : colorX), Interp01(colorX, on01 && CD && (colorX!=colorA&&colorX!=colorB) ? colorC : colorX)); \
197 *dP2++ = _TWO_PIX(Interp01(colorX, on10 && AB && (colorX!=colorC&&colorX!=colorD) ? colorA : colorX), Interp01(colorX, on11 && BC && (colorX!=colorD&&colorX!=colorA) ? colorC : colorX)); \
198 } \
199 } else { \
200 *dP1++ = _TWO_PIX(colorX, colorX); \
201 *dP2++ = _TWO_PIX(colorX, colorX); \
202 } \
203 }
204
205 if(vidDepth == 32)
206 {
207 #define _TWO_PIX TWO_PIX_32
208 DrawInit(2,uint64);
209 DrawRows(2,1); // 2x scale, and diags is on since we do use all 8 surrounding pixels
210 #undef _TWO_PIX
211 }
212 else
213 {
214 #define _TWO_PIX TWO_PIX
215 DrawInit(2,uint32);
216 DrawRows(2,1); // 2x scale, and diags is on since we do use all 8 surrounding pixels
217 #undef _TWO_PIX
218 }
219
220 #undef DrawPix
221 }
222