Merge branch 'feature/handle-quit-event'
[jumpnbump.git] / filter.c
blob988788c28e61e41b15f2e56cb5624bebae053989
1 /*
2 * filter.c
3 * Copyright (C) 2003 Florian Schulze <crow@icculus.org>
5 * This file is part of Jump'n'Bump.
7 * Jump'n'Bump is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * Jump'n'Bump is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 The following scaling filter is called advancedmame2x.
24 The implementation found here was possible because of the great ideas of
25 Lucas Pope.
28 typedef unsigned char byte;
29 static int scale2x_inited = 0;
30 static byte lookup_map[4*16];
32 void init_scale2x(void)
34 int i;
36 if (scale2x_inited)
37 return;
39 //-------------------------------------------------------------------------
40 // scale2x takes the following source:
41 // A B C
42 // D E F
43 // G H I
45 // and doubles the size of E to produce:
46 // E0 E1
47 // E2 E3
49 // E0 = D == B && B != F && D != H ? D : E;
50 // E1 = B == F && B != D && F != H ? F : E;
51 // E2 = D == H && D != B && H != F ? D : E;
52 // E3 = H == F && D != H && B != F ? F : E;
54 // to make this comparison regimen faster, we encode source color
55 // equivalency into a single byte with the getCode() macro
57 // #define getCode(b,f,h,d) ( (b == f)<<0 | (f == h)<<1 | (h == d)<<2 | (d == b)<<3 )
59 // encode the scale2x conditionals into a lookup code
60 for (i=0; i<16; i++) {
61 // E0 = D == B && B != F && D != H ? D : E; // 10-0 => 1000 or 1010 => 8 or A
62 lookup_map[0*16+i] = (i == 0x8 || i == 0xA) ? 0 : 1;
63 // E1 = B == F && B != D && F != H ? F : E; // 0-01 => 0101 or 0001 => 5 or 1
64 lookup_map[1*16+i] = (i == 0x5 || i == 0x1) ? 2 : 1;
65 // E2 = D == H && D != B && H != F ? D : E; // 010- => 0101 or 0100 => 5 or 4
66 lookup_map[2*16+i] = (i == 0x4 || i == 0x5) ? 0 : 1;
67 // E3 = H == F && D != H && B != F ? F : E; // -010 => 1010 or 0010 => A or 2
68 lookup_map[3*16+i] = (i == 0xA || i == 0x2) ? 2 : 1;
72 void do_scale2x(unsigned char *src,
73 int src_width,
74 int src_height,
75 unsigned char *dst)
77 int x;
78 int y;
79 int dst_width = src_width * 2;
80 int dst_height = src_height * 2;
81 int code;
82 byte rowColors[3];
83 byte *e0;
84 byte *e1;
85 byte *e2;
86 byte *e3;
88 if (!scale2x_inited)
89 init_scale2x();
91 // special top case - b is always unknown
93 byte *d;
94 byte *e;
95 byte *f;
96 byte *h;
98 e0 = &dst[0];
99 e1 = &dst[1];
100 e2 = &dst[dst_width];
101 e3 = &dst[dst_width + 1];
102 e = &src[0];
103 f = &src[1];
104 h = &src[src_width];
106 // special left case - d is unknown
107 rowColors[0] = *e;
108 rowColors[1] = *e;
109 rowColors[2] = *f;
110 code = ( (*f == *h)<<1 );
111 *e0 = rowColors[lookup_map[0*16+code]];
112 *e1 = rowColors[lookup_map[1*16+code]];
113 *e2 = rowColors[lookup_map[2*16+code]];
114 *e3 = rowColors[lookup_map[3*16+code]];
115 e++; f++; h++;
116 d = &src[src_width]; // (src_width - 1) + 1
117 e0+=2; e1+=2; e2+=2; e3+=2;
119 // normal case
120 for (x=1; x<(src_width-1); x++) {
121 rowColors[0] = *d;
122 rowColors[1] = *e;
123 rowColors[2] = *f;
124 code = ( (*f == *h)<<1 | (*h == *d)<<2 );
125 *e0 = rowColors[lookup_map[0*16+code]];
126 *e1 = rowColors[lookup_map[1*16+code]];
127 *e2 = rowColors[lookup_map[2*16+code]];
128 *e3 = rowColors[lookup_map[3*16+code]];
129 d++; e++; f++; h++;
130 e0+=2; e1+=2; e2+=2; e3+=2;
133 // special right case - f is unknown
134 rowColors[0] = *d;
135 rowColors[1] = *e;
136 rowColors[2] = *e;
137 code = ( (*h == *d)<<2 );
138 *e0 = rowColors[lookup_map[0*16+code]];
139 *e1 = rowColors[lookup_map[1*16+code]];
140 *e2 = rowColors[lookup_map[2*16+code]];
141 *e3 = rowColors[lookup_map[3*16+code]];
144 // top and bottom always known
145 for (y=1; y<(src_height-1); y++) {
146 byte *b;
147 byte *d;
148 byte *e;
149 byte *f;
150 byte *h;
152 e0 = &dst[y*dst_width*2];
153 e1 = &dst[y*dst_width*2 + 1];
154 e2 = &dst[y*dst_width*2 + dst_width];
155 e3 = &dst[y*dst_width*2 + dst_width + 1];
156 b = &src[y * src_width - src_width];
157 e = &src[y * src_width];
158 f = &src[y * src_width + 1];
159 h = &src[y * src_width + src_width];
161 // special left case - d is unknown
162 rowColors[0] = *e;
163 rowColors[1] = *e;
164 rowColors[2] = *f;
165 code = ( (*b == *f)<<0 | (*f == *h)<<1 );
166 *e0 = rowColors[lookup_map[0*16+code]];
167 *e1 = rowColors[lookup_map[1*16+code]];
168 *e2 = rowColors[lookup_map[2*16+code]];
169 *e3 = rowColors[lookup_map[3*16+code]];
170 b++; e++; f++; h++;
171 d = &src[y * src_width]; // (y * src_width - 1) + 1
172 e0+=2; e1+=2; e2+=2; e3+=2;
174 // normal case
175 for (x=1; x<(src_width-1); x++) {
176 rowColors[0] = *d;
177 rowColors[1] = *e;
178 rowColors[2] = *f;
179 code = ( (*b == *f)<<0 | (*f == *h)<<1 | (*h == *d)<<2 | (*d == *b)<<3 );
180 *e0 = rowColors[lookup_map[0*16+code]];
181 *e1 = rowColors[lookup_map[1*16+code]];
182 *e2 = rowColors[lookup_map[2*16+code]];
183 *e3 = rowColors[lookup_map[3*16+code]];
184 b++; d++; e++; f++; h++;
185 e0+=2; e1+=2; e2+=2; e3+=2;
188 // special right case - f is unknown
189 rowColors[0] = *d;
190 rowColors[1] = *e;
191 rowColors[2] = *e;
192 code = ( (*h == *d)<<2 | (*d == *b)<<3 );
193 *e0 = rowColors[lookup_map[0*16+code]];
194 *e1 = rowColors[lookup_map[1*16+code]];
195 *e2 = rowColors[lookup_map[2*16+code]];
196 *e3 = rowColors[lookup_map[3*16+code]];
199 // special bottom case - h is always unknown
201 byte *b;
202 byte *d;
203 byte *e;
204 byte *f;
206 e0 = &dst[y*dst_width*2];
207 e1 = &dst[y*dst_width*2 + 1];
208 e2 = &dst[y*dst_width*2 + dst_width];
209 e3 = &dst[y*dst_width*2 + dst_width + 1];
210 b = &src[y * src_width - src_width];
211 e = &src[y * src_width];
212 f = &src[y * src_width + 1];
214 // special left case - d is unknown
215 rowColors[0] = *e;
216 rowColors[1] = *e;
217 rowColors[2] = *f;
218 code = ( (*b == *f)<<0 );
219 *e0 = rowColors[lookup_map[0*16+code]];
220 *e1 = rowColors[lookup_map[1*16+code]];
221 *e2 = rowColors[lookup_map[2*16+code]];
222 *e3 = rowColors[lookup_map[3*16+code]];
223 b++; e++; f++;
224 d = &src[y * src_width]; // (y * src_width - 1) + 1
225 e0+=2; e1+=2; e2+=2; e3+=2;
227 // normal case
228 for (x=1; x<(src_width-1); x++) {
229 rowColors[0] = *d;
230 rowColors[1] = *e;
231 rowColors[2] = *f;
232 code = ( (*b == *f)<<0 | (*d == *b)<<3 );
233 *e0 = rowColors[lookup_map[0*16+code]];
234 *e1 = rowColors[lookup_map[1*16+code]];
235 *e2 = rowColors[lookup_map[2*16+code]];
236 *e3 = rowColors[lookup_map[3*16+code]];
237 b++; d++; e++; f++;
238 e0+=2; e1+=2; e2+=2; e3+=2;
241 // special right case - f is unknown
242 rowColors[0] = *d;
243 rowColors[1] = *e;
244 rowColors[2] = *e;
245 code = ( (*d == *b)<<3 );
246 *e0 = rowColors[lookup_map[0*16+code]];
247 *e1 = rowColors[lookup_map[1*16+code]];
248 *e2 = rowColors[lookup_map[2*16+code]];
249 *e3 = rowColors[lookup_map[3*16+code]];