1 /*
2  * This file is part of the Scale2x project.
3  *
4  * Copyright (C) 2003, 2013 Andrea Mazzoleni
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 /*
22  * This is the source of a simple command line tool which uses the reference
23  * implementation of the Scale effects.
24  *
25  * You can find an high level description of the effects at :
26  *
27  * http://scale2x.sourceforge.net/
28  */
29 
30 #include "file.h"
31 #include "pixel.h"
32 #include "portable.h"
33 
34 #include <zlib.h>
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 
scalex(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,unsigned mx,unsigned my)40 void scalex(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, unsigned mx, unsigned my)
41 {
42 	int x;
43 	int y;
44 
45 	for(y=0;y<height;++y) {
46 		for(x=0;x<width;++x) {
47 			pixel_t E;
48 			unsigned i,j;
49 
50 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, 0);
51 
52 			for(i=0;i<mx;++i)
53 				for(j=0;j<my;++j)
54 					pixel_put(x*mx+i, y*my+j, dst_ptr, dst_slice, pixel, width*mx, height*my, E);
55 		}
56 	}
57 }
58 
59 #define SCALE2X_REVISION_MAX 5
60 
lerp(pixel_t v0,pixel_t v1,double f)61 pixel_t lerp(pixel_t v0, pixel_t v1, double f)
62 {
63 	unsigned r0, g0, b0;
64 	unsigned r1, g1, b1;
65 
66 	r0 = v0 & 0xFF;
67 	g0 = (v0 >> 8) & 0xFF;
68 	b0 = (v0 >> 16) & 0xFF;
69 
70 	r1 = v1 & 0xFF;
71 	g1 = (v1 >> 8) & 0xFF;
72 	b1 = (v1 >> 16) & 0xFF;
73 
74 	r0 = r0 * f + r1 * (1.0-f);
75 	g0 = g0 * f + g1 * (1.0-f);
76 	b0 = b0 * f + b1 * (1.0-f);
77 
78 	if (r0 > 255) r0 = 255;
79 	if (g0 > 255) g0 = 255;
80 	if (b0 > 255) b0 = 255;
81 
82 	v0 = r0 + (g0 << 8) + (b0 << 16);
83 
84 	return v0 | 0xFF000000;
85 }
86 
dist(pixel_t v0,pixel_t v1)87 unsigned dist(pixel_t v0, pixel_t v1)
88 {
89 	int r0, g0, b0;
90 	int r1, g1, b1;
91 
92 	r0 = v0 & 0xFF;
93 	g0 = (v0 >> 8) & 0xFF;
94 	b0 = (v0 >> 16) & 0xFF;
95 
96 	r1 = v1 & 0xFF;
97 	g1 = (v1 >> 8) & 0xFF;
98 	b1 = (v1 >> 16) & 0xFF;
99 
100 	r0 -= r1;
101 	g0 -= g1;
102 	b0 -= b1;
103 
104 	if (r0 < 0) r0 = -r0;
105 	if (g0 < 0) g0 = -g0;
106 	if (b0 < 0) b0 = -b0;
107 
108 	return 3 * r0 + 6 * g0 + b0;
109 }
110 
scale2x(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,int opt_tes,int opt_ver)111 void scale2x(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, int opt_tes, int opt_ver)
112 {
113 	int x;
114 	int y;
115 
116 	for(y=0;y<height;++y) {
117 		for(x=0;x<width;++x) {
118 			pixel_t E0, E1, E2, E3;
119 			pixel_t A, B, C, D, E, F, G, H, I;
120 
121 			A = pixel_get(x-1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
122 			B = pixel_get(x, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
123 			C = pixel_get(x+1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
124 			D = pixel_get(x-1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
125 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, opt_tes);
126 			F = pixel_get(x+1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
127 			G = pixel_get(x-1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
128 			H = pixel_get(x, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
129 			I = pixel_get(x+1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
130 
131 			/*
132 				ABC
133 				DEF
134 				GHI
135 
136 				E0E1
137 				E2E3
138 			*/
139 			switch (opt_ver) {
140 			default:
141 			case 0 :
142 				/* version 0, normal scaling */
143 				E0 = E;
144 				E1 = E;
145 				E2 = E;
146 				E3 = E;
147 				break;
148 			case 1 :
149 				/* default */
150 				E0 = D == B && B != F && D != H ? D : E;
151 				E1 = B == F && B != D && F != H ? F : E;
152 				E2 = D == H && D != B && H != F ? D : E;
153 				E3 = H == F && D != H && B != F ? F : E;
154 				break;
155 
156 			case 2 :
157 				/* scalek */
158 
159 #define SCALE2K_BASE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3) \
160 	if (D == B && B != E && D != E) { \
161 		/* diagonal */ \
162 		if (B == C && D == G) { \
163 			/* square block */ \
164 		} else if (B == C) { \
165 			/* horizontal slope */ \
166 			E0 = lerp(D, E0, 0.75); \
167 			E1 = lerp(D, E1, 0.25); \
168 		} else if (D == G) { \
169 			/* vertical slope */ \
170 			E0 = lerp(D, E0, 0.75); \
171 			E2 = lerp(D, E2, 0.25); \
172 		} else { \
173 			/* pure diagonal */ \
174 			E0 = lerp(E0,D,0.5); \
175 		} \
176 	}
177 
178 /* Used by AdvanceMAME */
179 #define SCALE2K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3) \
180 	if (D == B && B != E && D != E) { \
181 		/* diagonal */ \
182 		if (B == C && D == G) { \
183 			/* square block */ \
184 			if (A != E) { \
185 				/* no star */ \
186 				E0 = lerp(D, E0, 0.75); \
187 				E1 = lerp(D, E1, 0.25); \
188 				E2 = lerp(D, E2, 0.25); \
189 			} \
190 		} else if (B == C && C != F) { \
191 			/* horizontal slope */ \
192 			E0 = lerp(D, E0, 0.75); \
193 			E1 = lerp(D, E1, 0.25); \
194 		} else if (D == G && G != H) { \
195 			/* vertical slope */ \
196 			E0 = lerp(D, E0, 0.75); \
197 			E2 = lerp(D, E2, 0.25); \
198 		} else { \
199 			/* pure diagonal */ \
200 			E0 = lerp(E0,D,0.5); \
201 		} \
202 	}
203 
204 #define SCALE2K_SPIKE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3) \
205 	if (B != E && D != E) { \
206 		if (D == B) { \
207 			/* diagonal */ \
208 			if (B == C && D == G) { \
209 				/* square block */ \
210 			} else if (B == C) { \
211 				/* horizontal slope */ \
212 				E0 = lerp(D, E0, 0.75); \
213 				E1 = lerp(D, E1, 0.25); \
214 			} else if (D == G) { \
215 				/* vertical slope */ \
216 				E0 = lerp(D, E0, 0.75); \
217 				E2 = lerp(D, E2, 0.25); \
218 			} else { \
219 				/* pure diagonal */ \
220 				E0 = lerp(E0,D,0.5); \
221 			} \
222 		} else if (A == B && G == E) { \
223 			/* horizontal spike */ \
224 			E0 = lerp(D, E0, 0.5); \
225 		} else if (A == D && C == E) { \
226 			/* vertical spike */ \
227 			E0 = lerp(B, E0, 0.5); \
228 		} \
229 	}
230 
231 #define SCALE2K_ALTERNATE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3) \
232 	if (D == B && B != F && D != H) { \
233 		/* diagonal */ \
234 		if (B == C && D == G) { \
235 			/* square block */ \
236 			if (A != E) { \
237 				E0 = lerp(D, E0, 0.75); \
238 				E1 = lerp(D, E1, 0.25); \
239 				E2 = lerp(D, E2, 0.25); \
240 			} \
241 		} else if (B == C && C != F) { \
242 			/* horizontal slope */ \
243 			E0 = lerp(D, E0, 0.75); \
244 			E1 = lerp(D, E1, 0.25); \
245 		} else if (D == G && G != H) { \
246 			/* vertical slope */ \
247 			E0 = lerp(D, E0, 0.75); \
248 			E2 = lerp(D, E2, 0.25); \
249 		} else { \
250 			/* pure diagonal */ \
251 			E0 = lerp(E0,D,0.5); \
252 		} \
253 	}
254 
255 				E0 = E1 = E2 = E3 = E;
256 
257 				SCALE2K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3);
258 				SCALE2K(G,D,A,H,E,B,I,F,C,E2,E0,E3,E1);
259 				SCALE2K(I,H,G,F,E,D,C,B,A,E3,E2,E1,E0);
260 				SCALE2K(C,F,I,B,E,H,A,D,G,E1,E3,E0,E2);
261 
262 				break;
263 
264 			case 3 :
265 				/* rejected */
266 				E0 = D == B && ((B != F && D != H) || D == A) ? D : E;
267 				E1 = B == F && ((B != D && F != H) || B == C) ? F : E;
268 				E2 = D == H && ((D != B && H != F) || D == G) ? D : E;
269 				E3 = H == F && ((D != H && B != F) || H == I) ? F : E;
270 				break;
271 			case 4 :
272 				/* rejected, loses isolated pixels */
273 				E0 = D == B && A != E ? D : E;
274 				E1 = B == F && C != E ? F : E;
275 				E2 = D == H && G != E ? D : E;
276 				E3 = H == F && I != E ? F : E;
277 				break;
278 			}
279 
280 			pixel_put(x*2, y*2, dst_ptr, dst_slice, pixel, width*2, height*2, E0);
281 			pixel_put(x*2+1, y*2, dst_ptr, dst_slice, pixel, width*2, height*2, E1);
282 			pixel_put(x*2, y*2+1, dst_ptr, dst_slice, pixel, width*2, height*2, E2);
283 			pixel_put(x*2+1, y*2+1, dst_ptr, dst_slice, pixel, width*2, height*2, E3);
284 		}
285 	}
286 }
287 
288 #define SCALE3X_REVISION_MAX 7
289 
scale3x(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,int opt_tes,int opt_ver)290 void scale3x(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, int opt_tes, int opt_ver)
291 {
292 	int x;
293 	int y;
294 
295 	for(y=0;y<height;++y) {
296 		for(x=0;x<width;++x) {
297 			pixel_t E0, E1, E2, E3, E4, E5, E6, E7, E8;
298 			pixel_t A, B, C, D, E, F, G, H, I;
299 			int k0, k1, k2, k3;
300 			int c0, c1, c2, c3;
301 
302 			A = pixel_get(x-1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
303 			B = pixel_get(x, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
304 			C = pixel_get(x+1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
305 			D = pixel_get(x-1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
306 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, opt_tes);
307 			F = pixel_get(x+1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
308 			G = pixel_get(x-1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
309 			H = pixel_get(x, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
310 			I = pixel_get(x+1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
311 
312 			/*
313 				ABC
314 				DEF
315 				GHI
316 
317 				k0k1
318 				k2k3
319 
320 				E0E1E2
321 				E3E4E5
322 				E6E7E8
323 			*/
324 			switch (opt_ver) {
325 			default:
326 			case 0 :
327 				/* version 0, normal scaling */
328 				E0 = E;
329 				E1 = E;
330 				E2 = E;
331 				E3 = E;
332 				E4 = E;
333 				E5 = E;
334 				E6 = E;
335 				E7 = E;
336 				E8 = E;
337 				break;
338 			case 1 :
339 				/* default */
340 				k0 = D == B && B != F && D != H;
341 				k1 = B == F && B != D && F != H;
342 				k2 = D == H && D != B && H != F;
343 				k3 = H == F && D != H && B != F;
344 				E0 = k0 ? D : E;
345 				E1 = (k0 && E != C) || (k1 && E != A) ? B : E;
346 				E2 = k1 ? F : E;
347 				E3 = (k0 && E != G) || (k2 && E != A) ? D : E;
348 				E4 = E;
349 				E5 = (k1 && E != I) || (k3 && E != C) ? F : E;
350 				E6 = k2 ? D : E;
351 				E7 = (k2 && E != I) || (k3 && E != G) ? H : E;
352 				E8 = k3 ? F : E;
353 				break;
354 
355 			case 2:
356 				/* scalek */
357 
358 			/*
359 				ABC
360 				DEF
361 				GHI
362 
363 				E0E1E2
364 				E3E4E5
365 				E6E7E8
366 			*/
367 
368 #define SCALE3K_BASE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8) \
369 	if (D == B && B != E && D != E) { \
370 		/* diagonal */ \
371 		if (B == C && D == G) { \
372 			/* square block */ \
373 		} else if (B == C) { \
374 			/* horizontal slope */ \
375 			E0 = D; \
376 			E1 = lerp(D, E1, 0.75); \
377 			E2 = lerp(D, E2, 0.25); \
378 			E3 = lerp(D, E3, 0.25); \
379 		} else if (D == G) { \
380 			/* vertical slope */ \
381 			E0 = D; \
382 			E3 = lerp(D, E3, 0.75); \
383 			E6 = lerp(D, E6, 0.25); \
384 			E1 = lerp(D, E1, 0.25); \
385 		} else { \
386 			/* pure diagonal */ \
387 			E0 = lerp(D, E0, 0.875); \
388 			E1 = lerp(D, E1, 0.125); \
389 			E3 = lerp(D, E3, 0.125); \
390 		} \
391 	}
392 
393 /* Used by AdvanceMAME */
394 #define SCALE3K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8) \
395 	if (D == B && B != E && D != E) { \
396 		/* diagonal */ \
397 		if (B == C && D == G) { \
398 			/* square block */ \
399 			if (A != E) { \
400 				E0 = D; \
401 				E1 = lerp(D, E1, 0.75); \
402 				E2 = lerp(D, E2, 0.25); \
403 				E3 = lerp(D, E3, 0.75); \
404 				E6 = lerp(D, E6, 0.25); \
405 			} \
406 		} else if (B == C && C != F) { \
407 			/* horizontal slope */ \
408 			E0 = D; \
409 			E1 = lerp(D, E1, 0.75); \
410 			E2 = lerp(D, E2, 0.25); \
411 			E3 = lerp(D, E3, 0.25); \
412 		} else if (D == G && G != H) { \
413 			/* vertical slope */ \
414 			E0 = D; \
415 			E3 = lerp(D, E3, 0.75); \
416 			E6 = lerp(D, E6, 0.25); \
417 			E1 = lerp(D, E1, 0.25); \
418 		} else { \
419 			/* pure diagonal */ \
420 			E0 = lerp(D, E0, 0.875); \
421 			E1 = lerp(D, E1, 0.125); \
422 			E3 = lerp(D, E3, 0.125); \
423 		} \
424 	}
425 
426 #define SCALE3K_SPIKE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8) \
427 	if (B != E && D != E) { \
428 		if (D == B) { \
429 			/* diagonal */ \
430 			if (B == C && D == G) { \
431 				/* square block */ \
432 			} else if (B == C) { \
433 				/* horizontal slope */ \
434 				E0 = D; \
435 				E1 = lerp(D, E1, 0.75); \
436 				E2 = lerp(D, E2, 0.25); \
437 				E3 = lerp(D, E3, 0.25); \
438 			} else if (D == G) { \
439 				/* vertical slope */ \
440 				E0 = D; \
441 				E3 = lerp(D, E3, 0.75); \
442 				E6 = lerp(D, E6, 0.25); \
443 				E1 = lerp(D, E1, 0.25); \
444 			} else { \
445 				/* pure diagonal */ \
446 				E0 = lerp(D, E0, 0.875); \
447 				E1 = lerp(D, E1, 0.125); \
448 				E3 = lerp(D, E3, 0.125); \
449 			} \
450 		} else if (A == B && G == E) { \
451 			/* horizontal spike */ \
452 			E0 = lerp(D, E0, 0.875); \
453 			E1 = lerp(D, E1, 0.125); \
454 			E3 = lerp(D, E3, 0.125); \
455 		} else if (A == D && C == E) { \
456 			/* vertical spike */ \
457 			E0 = lerp(B, E0, 0.875); \
458 			E1 = lerp(B, E1, 0.125); \
459 			E3 = lerp(B, E3, 0.125); \
460 		} \
461 	}
462 
463 #define SCALE3K_ALTERNATE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8) \
464 	if (D == B && B != F && D != H) { \
465 		/* diagonal */ \
466 		if (B == C && D == G) { \
467 			/* square block */ \
468 			if (A != E) { \
469 				E0 = D; \
470 				E1 = lerp(D, E1, 0.75); \
471 				E2 = lerp(D, E2, 0.25); \
472 				E3 = lerp(D, E3, 0.75); \
473 				E6 = lerp(D, E6, 0.25); \
474 			} \
475 		} else if (B == C && C != F) { \
476 			/* horizontal slope */ \
477 			E0 = D; \
478 			E1 = lerp(D, E1, 0.75); \
479 			E2 = lerp(D, E2, 0.25); \
480 			E3 = lerp(D, E3, 0.25); \
481 		} else if (D == G && G != H) { \
482 			/* vertical slope */ \
483 			E0 = D; \
484 			E3 = lerp(D, E3, 0.75); \
485 			E6 = lerp(D, E6, 0.25); \
486 			E1 = lerp(D, E1, 0.25); \
487 		} else { \
488 			/* pure diagonal */ \
489 			E0 = lerp(D, E0, 0.875); \
490 			E1 = lerp(D, E1, 0.125); \
491 			E3 = lerp(D, E3, 0.125); \
492 		} \
493 	}
494 
495 				E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E;
496 
497 				SCALE3K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8);
498 				SCALE3K(G,D,A,H,E,B,I,F,C,E6,E3,E0,E7,E4,E1,E8,E5,E2);
499 				SCALE3K(I,H,G,F,E,D,C,B,A,E8,E7,E6,E5,E4,E3,E2,E1,E0);
500 				SCALE3K(C,F,I,B,E,H,A,D,G,E2,E5,E8,E1,E4,E7,E0,E3,E6);
501 				break;
502 
503 			case 3 :
504 				/* rejected */
505 				E0 = D == B && B != F && D != H ? D : E;
506 				E1 = E;
507 				E2 = B == F && B != D && F != H ? F : E;
508 				E3 = E;
509 				E4 = E;
510 				E5 = E;
511 				E6 = D == H && D != B && H != F ? D : E;
512 				E7 = E;
513 				E8 = H == F && D != H && B != F ? F : E;
514 				break;
515 			case 4 :
516 				/* rejected */
517 				E0 = D == B && ((B != F && D != H) || D == A) ? D : E;
518 				E1 = E;
519 				E2 = B == F && ((B != D && F != H) || B == C) ? F : E;
520 				E3 = E;
521 				E4 = E;
522 				E5 = E;
523 				E6 = D == H && ((D != B && H != F) || D == G) ? D : E;
524 				E7 = E;
525 				E8 = H == F && ((D != H && B != F) || H == I) ? F : E;
526 				break;
527 			case 5 :
528 				/* rejected */
529 				E0 = D == B && A != E ? D : E;
530 				E1 = E;
531 				E2 = B == F && C != E ? F : E;
532 				E3 = E;
533 				E4 = E;
534 				E5 = E;
535 				E6 = D == H && G != E ? D : E;
536 				E7 = E;
537 				E8 = H == F && I != E ? F : E;
538 				break;
539 			case 6 :
540 				/* rejected */
541 				k0 = D == B && B != F && D != H;
542 				k1 = B == F && B != D && F != H;
543 				k2 = D == H && D != B && H != F;
544 				k3 = H == F && D != H && B != F;
545 				c0 = k0 && E != C;
546 				c1 = k1 && E != B;
547 				c2 = k2 && E != H;
548 				c3 = k3 && E != H;
549 				E0 = k0 ? D : E;
550 				E1 = c0 || c1 ? B : E;
551 				E2 = k1 ? F : E;
552 				E3 = c0 || c2 ? D : E;
553 				E4 = E;
554 				E5 = c1 || c3 ? F : E;
555 				E6 = k2 ? D : E;
556 				E7 = c2 || c3 ? H : E;
557 				E8 = k3 ? F : E;
558 				break;
559 			case 7 :
560 				/* rejected */
561 				k0 = D == B && B != F && D != H;
562 				k1 = B == F && B != D && F != H;
563 				k2 = D == H && D != B && H != F;
564 				k3 = H == F && D != H && B != F;
565 				E0 = k0 ? D : E;
566 				E1 = k0 != k1 ? B : E;
567 				E2 = k1 ? F : E;
568 				E3 = k0 != k2 ? D : E;
569 				E4 = E;
570 				E5 = k1 != k3 ? F : E;
571 				E6 = k2 ? D : E;
572 				E7 = k2 != k3 ? H : E;
573 				E8 = k3 ? F : E;
574 				break;
575 			case 8 :
576 				/* rejected */
577 				k0 = D == B && B != F && D != H;
578 				k1 = B == F && B != D && F != H;
579 				k2 = D == H && D != B && H != F;
580 				k3 = H == F && D != H && B != F;
581 				E0 = k0 ? D : E;
582 				E1 = k0 || k1 ? B : E;
583 				E2 = k1 ? F : E;
584 				E3 = k0 || k2 ? D : E;
585 				E4 = E;
586 				E5 = k1 || k3 ? F : E;
587 				E6 = k2 ? D : E;
588 				E7 = k2 || k3 ? H : E;
589 				E8 = k3 ? F : E;
590 				break;
591 			}
592 
593 			pixel_put(x*3, y*3, dst_ptr, dst_slice, pixel, width*3, height*3, E0);
594 			pixel_put(x*3+1, y*3, dst_ptr, dst_slice, pixel, width*3, height*3, E1);
595 			pixel_put(x*3+2, y*3, dst_ptr, dst_slice, pixel, width*3, height*3, E2);
596 			pixel_put(x*3, y*3+1, dst_ptr, dst_slice, pixel, width*3, height*3, E3);
597 			pixel_put(x*3+1, y*3+1, dst_ptr, dst_slice, pixel, width*3, height*3, E4);
598 			pixel_put(x*3+2, y*3+1, dst_ptr, dst_slice, pixel, width*3, height*3, E5);
599 			pixel_put(x*3, y*3+2, dst_ptr, dst_slice, pixel, width*3, height*3, E6);
600 			pixel_put(x*3+1, y*3+2, dst_ptr, dst_slice, pixel, width*3, height*3, E7);
601 			pixel_put(x*3+2, y*3+2, dst_ptr, dst_slice, pixel, width*3, height*3, E8);
602 		}
603 	}
604 }
605 
606 #define SCALE4X_REVISION_MAX SCALE2X_REVISION_MAX
607 
scale4x(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,int opt_tes,int opt_ver)608 int scale4x(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, int opt_tes, int opt_ver)
609 {
610 	int x;
611 	int y;
612 
613 	if (opt_ver != 0 && opt_ver != 2 && opt_ver != 3) {
614 		unsigned char* mid_ptr;
615 		unsigned mid_slice;
616 
617 		mid_slice = width * pixel * 2;
618 		mid_ptr = malloc(mid_slice * height * 2);
619 		if (!mid_ptr) {
620 			fprintf(stderr, "Low memory.\n");
621 			return -1;
622 		}
623 
624 		scale2x(mid_ptr, mid_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver);
625 		scale2x(dst_ptr, dst_slice, mid_ptr, mid_slice, pixel, width * 2, height * 2, opt_tes, opt_ver);
626 
627 		free(mid_ptr);
628 
629 		return 0;
630 	}
631 
632 	for(y=0;y<height;++y) {
633 		for(x=0;x<width;++x) {
634 			pixel_t E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, EA, EB, EC, ED, EE, EF;
635 			pixel_t EV[16];
636 			pixel_t A, B, C, D, E, F, G, H, I;
637 			pixel_t A1, B1, C1, G5, H5, I5, A0, D0, G0, C4, F4, I4;
638 
639 			/* scalex */
640 			A = pixel_get(x-1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
641 			B = pixel_get(x, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
642 			C = pixel_get(x+1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
643 			D = pixel_get(x-1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
644 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, opt_tes);
645 			F = pixel_get(x+1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
646 			G = pixel_get(x-1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
647 			H = pixel_get(x, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
648 			I = pixel_get(x+1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
649 
650 /*
651      0  1  2  3  4
652 
653 0       A1 B1 C1
654 1    A0 PA PB PC C4
655 2    D0 PD PE PF F4
656 3    G0 PG PH PI I4
657 4       G5 H5 I5
658 */
659 
660 			/* xbr */
661 			A1 = pixel_get(x-1, y-2, src_ptr, src_slice, pixel, width, height, opt_tes);
662 			B1 = pixel_get(x, y-2, src_ptr, src_slice, pixel, width, height, opt_tes);
663 			C1 = pixel_get(x+1, y-2, src_ptr, src_slice, pixel, width, height, opt_tes);
664 			G5 = pixel_get(x-1, y+2, src_ptr, src_slice, pixel, width, height, opt_tes);
665 			H5 = pixel_get(x, y+2, src_ptr, src_slice, pixel, width, height, opt_tes);
666 			I5 = pixel_get(x+1, y+2, src_ptr, src_slice, pixel, width, height, opt_tes);
667 			A0 = pixel_get(x-2, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
668 			D0 = pixel_get(x-2, y, src_ptr, src_slice, pixel, width, height, opt_tes);
669 			G0 = pixel_get(x-2, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
670 			C4 = pixel_get(x+2, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
671 			F4 = pixel_get(x+2, y, src_ptr, src_slice, pixel, width, height, opt_tes);
672 			I4 = pixel_get(x+2, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
673 
674 
675 			/*
676 				ABC
677 				DEF
678 				GHI
679 
680 				E0E1E2E3
681 				E4E5E6E7
682 				E8E9EAEB
683 				ECEDEEEF
684 			*/
685 			switch (opt_ver) {
686 			default:
687 			case 0 :
688 				/* version 0, normal scaling */
689 				E0 = E;
690 				E1 = E;
691 				E2 = E;
692 				E3 = E;
693 				E4 = E;
694 				E5 = E;
695 				E6 = E;
696 				E7 = E;
697 				E8 = E;
698 				E9 = E;
699 				EA = E;
700 				EB = E;
701 				EC = E;
702 				ED = E;
703 				EE = E;
704 				EF = E;
705 				break;
706 
707 			case 2:
708 				/* scalek */
709 
710 			/*
711 				ABC
712 				DEF
713 				GHI
714 
715 				E0E1E2E3
716 				E4E5E6E7
717 				E8E9EAEB
718 				ECEDEEEF
719 			*/
720 
721 
722 #define SCALE4K_BASE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF) \
723 	if (D == B && B != E && D != E) { \
724 		/* diagonal */ \
725 		if (B == C && D == G) { \
726 			/* square block */ \
727 		} else if (B == C && C != F) { \
728 			/* horizontal slope */ \
729 			E0 = D; \
730 			E1 = D; \
731 			E2 = lerp(D, E2, 0.75); \
732 			E3 = lerp(D, E3, 0.25); \
733 			E4 = lerp(D, E4, 0.75); \
734 			E5 = lerp(D, E5, 0.25); \
735 		} else if (D == G && G != H) { \
736 			/* vertical slope */ \
737 			E0 = D; \
738 			E4 = D; \
739 			E8 = lerp(D, E8, 0.75); \
740 			EC = lerp(D, EC, 0.25); \
741 			E1 = lerp(D, E1, 0.75); \
742 			E5 = lerp(D, E5, 0.25); \
743 		} else { \
744 			/* pure diagonal */ \
745 			E0 = D; \
746 			E1 = lerp(D, E1, 0.5); \
747 			E4 = lerp(D, E4, 0.5); \
748 		} \
749 	}
750 
751 /* Used by AdvanceMAME */
752 #define SCALE4K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF) \
753 	if (D == B && B != E && D != E) { \
754 		/* diagonal */ \
755 		if (B == C && D == G) { \
756 			if (A != E) { \
757 				/* no star */ \
758 				E0 = D; \
759 				E1 = D; \
760 				E2 = lerp(D, E2, 0.75); \
761 				E3 = lerp(D, E3, 0.25); \
762 				E4 = D; \
763 				E8 = lerp(D, E8, 0.75); \
764 				EC = lerp(D, EC, 0.25); \
765 				E5 = lerp(D, E5, 0.50); \
766 			} \
767 		} else if (B == C && C != F) { \
768 			/* horizontal slope */ \
769 			E0 = D; \
770 			E1 = D; \
771 			E2 = lerp(D, E2, 0.75); \
772 			E3 = lerp(D, E3, 0.25); \
773 			E4 = lerp(D, E4, 0.75); \
774 			E5 = lerp(D, E5, 0.25); \
775 		} else if (D == G && G != H) { \
776 			/* vertical slope */ \
777 			E0 = D; \
778 			E4 = D; \
779 			E8 = lerp(D, E8, 0.75); \
780 			EC = lerp(D, EC, 0.25); \
781 			E1 = lerp(D, E1, 0.75); \
782 			E5 = lerp(D, E5, 0.25); \
783 		} else { \
784 			/* pure diagonal */ \
785 			E0 = D; \
786 			E1 = lerp(D, E1, 0.5); \
787 			E4 = lerp(D, E4, 0.5); \
788 		} \
789 	}
790 
791 #define SCALE4K_ALTERNATE(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF) \
792 	if (D == B && B != F && D != H) { \
793 		/* diagonal */ \
794 		if (B == C && D == G) { \
795 			/* avoid starts */ \
796 			if (A != E) { \
797 				E0 = D; \
798 				E1 = D; \
799 				E2 = lerp(D, E2, 0.75); \
800 				E3 = lerp(D, E3, 0.25); \
801 				E4 = D; \
802 				E8 = lerp(D, E8, 0.75); \
803 				EC = lerp(D, EC, 0.25); \
804 				E5 = lerp(D, E5, 0.50); \
805 			} \
806 		} else if (B == C && C != F) { \
807 			/* horizontal slope */ \
808 			E0 = D; \
809 			E1 = D; \
810 			E2 = lerp(D, E2, 0.75); \
811 			E3 = lerp(D, E3, 0.25); \
812 			E4 = lerp(D, E4, 0.75); \
813 			E5 = lerp(D, E5, 0.25); \
814 		} else if (D == G && G != H) { \
815 			/* vertical slope */ \
816 			E0 = D; \
817 			E4 = D; \
818 			E8 = lerp(D, E8, 0.75); \
819 			EC = lerp(D, EC, 0.25); \
820 			E1 = lerp(D, E1, 0.75); \
821 			E5 = lerp(D, E5, 0.25); \
822 		} else { \
823 			/* pure diagonal */ \
824 			E0 = D; \
825 			E1 = lerp(D, E1, 0.5); \
826 			E4 = lerp(D, E4, 0.5); \
827 		} \
828 	}
829 
830 				E0 = E1 = E2 = E3 = E4 = E5 = E6 = E7 = E8 = E9 = EA = EB = EC = ED = EE = EF = E;
831 
832 				SCALE4K(A,B,C,D,E,F,G,H,I,E0,E1,E2,E3,E4,E5,E6,E7,E8,E9,EA,EB,EC,ED,EE,EF);
833 				SCALE4K(G,D,A,H,E,B,I,F,C,EC,E8,E4,E0,ED,E9,E5,E1,EE,EA,E6,E2,EF,EB,E7,E3);
834 				SCALE4K(I,H,G,F,E,D,C,B,A,EF,EE,ED,EC,EB,EA,E9,E8,E7,E6,E5,E4,E3,E2,E1,E0);
835 				SCALE4K(C,F,I,B,E,H,A,D,G,E3,E7,EB,EF,E2,E6,EA,EE,E1,E5,E9,ED,E0,E4,E8,EC);
836 				break;
837 
838 			case 3:
839 				/* xbr */
840 
841 /*
842      0  1  2  3  4
843 
844 0       A1 B1 C1
845 1    A0 PA PB PC C4
846 2    D0 PD PE PF F4
847 3    G0 PG PH PI I4
848 4       G5 H5 I5
849 */
850 
851 #define XBR(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N11, N12, N13, N14, N15) \
852 	if (PE!=PH && PE!=PF) {\
853 		unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + 4*df(PH,PF); \
854 		unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + 4*df(PE,PI); \
855 		if (e<i) { \
856 			int ex2 = PE!=PC && PB!=PC; \
857 			int ex3 = PE!=PG && PD!=PG; \
858 			unsigned ke = df(PF,PG); \
859 			unsigned ki = df(PH,PC); \
860 			pixel_t px = df(PE,PF) <= df(PE,PH) ? PF : PH; \
861 			if (ke == 0 && ki == 0 && ex3 && ex2) { \
862 				LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, px); \
863 			} else if (2*ke <= ki && ex3) { \
864 				LEFT_2(N15, N14, N11, N13, N12, N10, px); \
865 			} else if (ke >= 2*ki && ex2)  { \
866 				UP_2(N15, N14, N11, N3, N7, N10, px); \
867 			} else { \
868 				DIA_2(N15, N14, N11, px); \
869 			} \
870 		} \
871 	}
872 
873 #define LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, PIXEL) \
874 	EV[N7] = EV[N13] = lerp(PIXEL, EV[N13], 0.75); \
875 	EV[N3] = EV[N10] = EV[N12] = lerp(EV[N12], PIXEL, 0.75); \
876 	EV[N11] = EV[N14] = EV[N15] = PIXEL;
877 
878 #define LEFT_2(N15, N14, N11, N13, N12, N10, PIXEL)\
879 	EV[N11] = lerp(PIXEL, EV[N11], 0.75); \
880 	EV[N13] = lerp(PIXEL, EV[N13], 0.75); \
881 	EV[N10] = lerp(EV[N10], PIXEL, 0.75); \
882 	EV[N12] = lerp(EV[N12], PIXEL, 0.75); \
883 	EV[N14] = EV[N15] = PIXEL;
884 
885 #define UP_2(N15, N14, N11, N3, N7, N10, PIXEL)\
886 	EV[N14] = lerp(PIXEL, EV[N14], 0.75); \
887 	EV[N7] = lerp(PIXEL, EV[N7], 0.75); \
888 	EV[N10] = lerp(EV[N10], PIXEL, 0.75); \
889 	EV[N3] = lerp(EV[N3], PIXEL, 0.75); \
890 	EV[N11] = EV[N15] = PIXEL;
891 
892 #define DIA_2(N15, N14, N11, PIXEL)\
893 	EV[N11] = lerp(EV[N11], PIXEL, 0.5); \
894 	EV[N14] = lerp(EV[N14], PIXEL, 0.5); \
895 	EV[N15] = PIXEL;
896 
897 #define df(A, B) dist(A, B)
898 
899 				EV[0] = EV[1] = EV[2] = EV[3] = EV[4] = EV[5] = EV[6] = EV[7] = EV[8] = EV[9] = EV[10] = EV[11] = EV[12] = EV[13] = EV[14] = EV[15] = E;
900 
901 				XBR(E, I, H, F, G, C, D, B, A, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15);
902 				XBR(E, C, F, B, I, A, H, D, G, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, 12,  8,  4,  0, 13,  9,  5,  1, 14, 10,  6,  2, 15, 11,  7,  3);
903 				XBR(E, A, B, D, C, G, F, H, I, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0);
904 				XBR(E, G, D, H, A, I, B, F, C, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4,  3,  7, 11, 15,  2,  6, 10, 14,  1,  5,  9, 13,  0,  4,  8, 12);
905 
906 				E0 = EV[0];
907 				E1 = EV[1];
908 				E2 = EV[2];
909 				E3 = EV[3];
910 				E4 = EV[4];
911 				E5 = EV[5];
912 				E6 = EV[6];
913 				E7 = EV[7];
914 				E8 = EV[8];
915 				E9 = EV[9];
916 				EA = EV[10];
917 				EB = EV[11];
918 				EC = EV[12];
919 				ED = EV[13];
920 				EE = EV[14];
921 				EF = EV[15];
922 				break;
923 			}
924 
925 			pixel_put(x*4, y*4, dst_ptr, dst_slice, pixel, width*4, height*4, E0);
926 			pixel_put(x*4+1, y*4, dst_ptr, dst_slice, pixel, width*4, height*4, E1);
927 			pixel_put(x*4+2, y*4, dst_ptr, dst_slice, pixel, width*4, height*4, E2);
928 			pixel_put(x*4+3, y*4, dst_ptr, dst_slice, pixel, width*4, height*4, E3);
929 			pixel_put(x*4, y*4+1, dst_ptr, dst_slice, pixel, width*4, height*4, E4);
930 			pixel_put(x*4+1, y*4+1, dst_ptr, dst_slice, pixel, width*4, height*4, E5);
931 			pixel_put(x*4+2, y*4+1, dst_ptr, dst_slice, pixel, width*4, height*4, E6);
932 			pixel_put(x*4+3, y*4+1, dst_ptr, dst_slice, pixel, width*4, height*4, E7);
933 			pixel_put(x*4, y*4+2, dst_ptr, dst_slice, pixel, width*4, height*4, E8);
934 			pixel_put(x*4+1, y*4+2, dst_ptr, dst_slice, pixel, width*4, height*4, E9);
935 			pixel_put(x*4+2, y*4+2, dst_ptr, dst_slice, pixel, width*4, height*4, EA);
936 			pixel_put(x*4+3, y*4+2, dst_ptr, dst_slice, pixel, width*4, height*4, EB);
937 			pixel_put(x*4, y*4+3, dst_ptr, dst_slice, pixel, width*4, height*4, EC);
938 			pixel_put(x*4+1, y*4+3, dst_ptr, dst_slice, pixel, width*4, height*4, ED);
939 			pixel_put(x*4+2, y*4+3, dst_ptr, dst_slice, pixel, width*4, height*4, EE);
940 			pixel_put(x*4+3, y*4+3, dst_ptr, dst_slice, pixel, width*4, height*4, EF);
941 		}
942 	}
943 
944 	return 0;
945 }
946 
947 #define SCALE2X3_REVISION_MAX 1
948 
scale2x3(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,int opt_tes,int opt_ver)949 void scale2x3(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, int opt_tes, int opt_ver)
950 {
951 	int x;
952 	int y;
953 
954 	for(y=0;y<height;++y) {
955 		for(x=0;x<width;++x) {
956 			pixel_t E0, E1, E2, E3, E4, E5;
957 			pixel_t A, B, C, D, E, F, G, H, I;
958 			int k0, k1, k2, k3;
959 
960 			A = pixel_get(x-1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
961 			B = pixel_get(x, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
962 			C = pixel_get(x+1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
963 			D = pixel_get(x-1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
964 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, opt_tes);
965 			F = pixel_get(x+1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
966 			G = pixel_get(x-1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
967 			H = pixel_get(x, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
968 			I = pixel_get(x+1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
969 
970 			/*
971 				ABC
972 				DEF
973 				GHI
974 
975 				E0E1
976 				E2E3
977 				E4E5
978 			*/
979 			switch (opt_ver) {
980 			default:
981 			case 0 :
982 				/* version 0, normal scaling */
983 				E0 = E;
984 				E1 = E;
985 				E2 = E;
986 				E3 = E;
987 				E4 = E;
988 				E5 = E;
989 				break;
990 			case 1 :
991 				/* default */
992 				k0 = D == B && B != F && D != H;
993 				k1 = B == F && B != D && F != H;
994 				k2 = D == H && D != B && H != F;
995 				k3 = H == F && D != H && B != F;
996 				E0 = k0 ? D : E;
997 				E1 = k1 ? F : E;
998 				E2 = (k0 && E != G) || (k2 && E != A) ? D : E;
999 				E3 = (k1 && E != I) || (k3 && E != C) ? F : E;
1000 				E4 = k2 ? D : E;
1001 				E5 = k3 ? F : E;
1002 				break;
1003 			}
1004 
1005 			pixel_put(x*2, y*3, dst_ptr, dst_slice, pixel, width*2, height*3, E0);
1006 			pixel_put(x*2+1, y*3, dst_ptr, dst_slice, pixel, width*2, height*3, E1);
1007 			pixel_put(x*2, y*3+1, dst_ptr, dst_slice, pixel, width*2, height*3, E2);
1008 			pixel_put(x*2+1, y*3+1, dst_ptr, dst_slice, pixel, width*2, height*3, E3);
1009 			pixel_put(x*2, y*3+2, dst_ptr, dst_slice, pixel, width*2, height*3, E4);
1010 			pixel_put(x*2+1, y*3+2, dst_ptr, dst_slice, pixel, width*2, height*3, E5);
1011 		}
1012 	}
1013 }
1014 
1015 #define SCALE2X4_REVISION_MAX 2
1016 
scale2x4(unsigned char * dst_ptr,unsigned dst_slice,const unsigned char * src_ptr,unsigned src_slice,unsigned pixel,int width,int height,int opt_tes,int opt_ver)1017 void scale2x4(unsigned char* dst_ptr, unsigned dst_slice, const unsigned char* src_ptr, unsigned src_slice, unsigned pixel, int width, int height, int opt_tes, int opt_ver)
1018 {
1019 	int x;
1020 	int y;
1021 
1022 	for(y=0;y<height;++y) {
1023 		for(x=0;x<width;++x) {
1024 			pixel_t E0, E1, E2, E3, E4, E5, E6, E7;
1025 			pixel_t A, B, C, D, E, F, G, H, I;
1026 			int k0, k1, k2, k3;
1027 
1028 			A = pixel_get(x-1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
1029 			B = pixel_get(x, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
1030 			C = pixel_get(x+1, y-1, src_ptr, src_slice, pixel, width, height, opt_tes);
1031 			D = pixel_get(x-1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
1032 			E = pixel_get(x, y, src_ptr, src_slice, pixel, width, height, opt_tes);
1033 			F = pixel_get(x+1, y, src_ptr, src_slice, pixel, width, height, opt_tes);
1034 			G = pixel_get(x-1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
1035 			H = pixel_get(x, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
1036 			I = pixel_get(x+1, y+1, src_ptr, src_slice, pixel, width, height, opt_tes);
1037 
1038 			/*
1039 				ABC
1040 				DEF
1041 				GHI
1042 
1043 				E0E1
1044 				E2E3
1045 				E4E5
1046 				E6E7
1047 			*/
1048 			switch (opt_ver) {
1049 			default:
1050 			case 0 :
1051 				/* version 0, normal scaling */
1052 				E0 = E;
1053 				E1 = E;
1054 				E2 = E;
1055 				E3 = E;
1056 				E4 = E;
1057 				E5 = E;
1058 				E6 = E;
1059 				E7 = E;
1060 				break;
1061 			case 1 :
1062 				/* default */
1063 				k0 = D == B && B != F && D != H;
1064 				k1 = B == F && B != D && F != H;
1065 				k2 = D == H && D != B && H != F;
1066 				k3 = H == F && D != H && B != F;
1067 				E0 = k0 ? D : E;
1068 				E1 = k1 ? F : E;
1069 				E2 = (k0 && E != G) || (k2 && E != A) ? D : E;
1070 				E3 = (k1 && E != I) || (k3 && E != C) ? F : E;
1071 				E4 = (k0 && E != G) || (k2 && E != A) ? D : E;
1072 				E5 = (k1 && E != I) || (k3 && E != C) ? F : E;
1073 				E6 = k2 ? D : E;
1074 				E7 = k3 ? F : E;
1075 				break;
1076 			case 2 :
1077 				/* Hans de Goede variation, rejected */
1078 				k0 = D == B && B != F && D != H;
1079 				k1 = B == F && B != D && F != H;
1080 				k2 = D == H && D != B && H != F;
1081 				k3 = H == F && D != H && B != F;
1082 				E0 = k0 ? D : E;
1083 				E1 = k1 ? F : E;
1084 				E2 = k0 ? D : E;
1085 				E3 = k1 ? F : E;
1086 				E4 = k2 ? D : E;
1087 				E5 = k3 ? F : E;
1088 				E6 = k2 ? D : E;
1089 				E7 = k3 ? F : E;
1090 				break;
1091 			}
1092 
1093 			pixel_put(x*2, y*4, dst_ptr, dst_slice, pixel, width*2, height*4, E0);
1094 			pixel_put(x*2+1, y*4, dst_ptr, dst_slice, pixel, width*2, height*4, E1);
1095 			pixel_put(x*2, y*4+1, dst_ptr, dst_slice, pixel, width*2, height*4, E2);
1096 			pixel_put(x*2+1, y*4+1, dst_ptr, dst_slice, pixel, width*2, height*4, E3);
1097 			pixel_put(x*2, y*4+2, dst_ptr, dst_slice, pixel, width*2, height*4, E4);
1098 			pixel_put(x*2+1, y*4+2, dst_ptr, dst_slice, pixel, width*2, height*4, E5);
1099 			pixel_put(x*2, y*4+3, dst_ptr, dst_slice, pixel, width*2, height*4, E6);
1100 			pixel_put(x*2+1, y*4+3, dst_ptr, dst_slice, pixel, width*2, height*4, E7);
1101 		}
1102 	}
1103 }
1104 
file_process(const char * file0,const char * file1,int opt_scale_x,int opt_scale_y,int opt_tes,int opt_ver,int opt_crc,int opt_only124)1105 int file_process(const char* file0, const char* file1, int opt_scale_x, int opt_scale_y, int opt_tes, int opt_ver, int opt_crc, int opt_only124)
1106 {
1107 	unsigned pixel;
1108 	unsigned width;
1109 	unsigned height;
1110 	unsigned char* src_ptr;
1111 	unsigned src_slice;
1112 	unsigned char* dst_ptr;
1113 	unsigned dst_slice;
1114 	int type;
1115 	int channel;
1116 	png_color* palette;
1117 	unsigned palette_size;
1118 
1119 	if (file_read(file0, &src_ptr, &src_slice, &pixel, &width, &height, &type, &channel, &palette, &palette_size, opt_only124 ? 1 : 0) != 0) {
1120 		goto err;
1121 	}
1122 
1123 	dst_slice = width * pixel * opt_scale_x;
1124 	dst_ptr = malloc(dst_slice * height * opt_scale_y);
1125 	if (!dst_ptr) {
1126 		fprintf(stderr, "Low memory.\n");
1127 		goto err_src;
1128 	}
1129 
1130 	switch (opt_scale_x * 100 + opt_scale_y) {
1131 	case 202 :
1132 		scale2x(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver);
1133 		break;
1134 	case 203 :
1135 		scale2x3(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver);
1136 		break;
1137 	case 204 :
1138 		scale2x4(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver);
1139 		break;
1140 	case 303 :
1141 		scale3x(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver);
1142 		break;
1143 	case 404 :
1144 		if (scale4x(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_tes, opt_ver) != 0)
1145 			goto err_dst;
1146 		break;
1147 	default:
1148 		scalex(dst_ptr, dst_slice, src_ptr, src_slice, pixel, width, height, opt_scale_x, opt_scale_y);
1149 		break;
1150 	}
1151 
1152 	if (file_write(file1, dst_ptr, dst_slice, pixel, width * opt_scale_x, height * opt_scale_y, type, channel, palette, palette_size) != 0) {
1153 		goto err_dst;
1154 	}
1155 
1156 	if (opt_crc) {
1157 		unsigned crc = crc32(0, dst_ptr, dst_slice * height * opt_scale_y);
1158 		printf("%08x\n", crc);
1159 	}
1160 
1161 	free(dst_ptr);
1162 	free(src_ptr);
1163 	free(palette);
1164 
1165 	return 0;
1166 
1167 err_dst:
1168 	free(dst_ptr);
1169 err_src:
1170 	free(src_ptr);
1171 	free(palette);
1172 err:
1173 	return -1;
1174 }
1175 
file_gen(void)1176 int file_gen(void)
1177 {
1178 	unsigned width;
1179 	unsigned height;
1180 	unsigned slice;
1181 	unsigned pixel;
1182 	unsigned type;
1183 	unsigned channel;
1184 	unsigned char* ptr;
1185 	unsigned x,y,i,j;
1186 	unsigned delta = 5;
1187 
1188 	pixel = 3;
1189 	width = 32 * delta + delta/2;
1190 	height = 16 * delta + delta/2;
1191 	type = PNG_COLOR_TYPE_RGB;
1192 	channel = 3;
1193 
1194 	slice = width * pixel;
1195 	ptr = malloc(slice * height);
1196 	if (!ptr) {
1197 		fprintf(stderr, "Low memory.\n");
1198 		goto err;
1199 	}
1200 
1201 	/* red background */
1202 	for(y=0;y<height;++y) {
1203 		for(x=0;x<width;++x) {
1204 			pixel_put(x, y, ptr, slice, pixel, width, height, 0x0000FF);
1205 		}
1206 	}
1207 
1208 	for(y=0;y<16;++y) {
1209 		for(x=0;x<32;++x) {
1210 			unsigned mask = (y << 5) | x;
1211 			for(j=0;j<3;++j) {
1212 				for(i=0;i<3;++i) {
1213 					unsigned index = j*3+i;
1214 					unsigned color;
1215 					if ((mask & (1 << index)) != 0) {
1216 						color = 0xFFFFFF;
1217 					} else {
1218 						color = 0x000000;
1219 					}
1220 					pixel_put(x*delta+delta/2+i, y*delta+delta/2+j, ptr, slice, pixel, width, height, color);
1221 				}
1222 			}
1223 		}
1224 	}
1225 
1226 	if (file_write("template.png", ptr, slice, pixel, width, height, type, channel, 0, 0) != 0) {
1227 		goto err_ptr;
1228 	}
1229 
1230 	return 0;
1231 
1232 err_ptr:
1233 	free(ptr);
1234 err:
1235 	return -1;
1236 }
1237 
version(void)1238 void version(void) {
1239 	printf(PACKAGE " v" VERSION " by Andrea Mazzoleni\n");
1240 }
1241 
usage(void)1242 void usage(void) {
1243 	version();
1244 	printf("Reference implementation of the Scale2/3/4x effect\n");
1245 	printf("\nSyntax: scalerx [-k N] [-w] [-r N] FROM.png TO.png\n");
1246 	printf("\nOptions:\n");
1247 	printf("\t-k N\tSelect the scale factor. 2, 2x3, 2x4, 3, 4 (default 2).\n");
1248 	printf("\t-w\tWrap around on the borders.\n");
1249 	printf("\t-r N\tSelect the revision of the algorithm 0-N (default 1).\n");
1250 	printf("\nMore info at http://scale2x.sourceforge.net/\n");
1251 	exit(EXIT_FAILURE);
1252 }
1253 
1254 #ifdef HAVE_GETOPT_LONG
1255 struct option long_options[] = {
1256 	{"scale", 1, 0, 'k'},
1257 	{"crc", 0, 0, 'c'},
1258 	{"only124", 0, 0, 'o'},
1259 	{"wrap", 0, 0, 'w'},
1260 	{"revision", 1, 0, 'r'},
1261 	{"help", 0, 0, 'h'},
1262 	{"version", 0, 0, 'v'},
1263 	{0, 0, 0, 0}
1264 };
1265 #endif
1266 
1267 #define OPTIONS "k:cowr:ghv"
1268 
main(int argc,char * argv[])1269 int main(int argc, char* argv[]) {
1270 	int opt_scale_x = 2;
1271 	int opt_scale_y = 2;
1272 	int opt_crc = 0;
1273 	int opt_tes = 0;
1274 	int opt_ver = 1;
1275 	int opt_gen = 0;
1276 	int opt_only124 = 0;
1277 	int max_ver;
1278 	int c;
1279 
1280 	opterr = 0;
1281 
1282 	while ((c =
1283 #ifdef HAVE_GETOPT_LONG
1284 		getopt_long(argc, argv, OPTIONS, long_options, 0))
1285 #else
1286 		getopt(argc, argv, OPTIONS))
1287 #endif
1288 	!= EOF) {
1289 		switch (c) {
1290 			case 'h' :
1291 				usage();
1292 				exit(EXIT_SUCCESS);
1293 			case 'v' :
1294 				version();
1295 				exit(EXIT_SUCCESS);
1296 			case 'k' :
1297 				if (strcmp(optarg, "2") == 0) {
1298 					opt_scale_x = 2;
1299 					opt_scale_y = 2;
1300 				} else if (strcmp(optarg, "3") == 0) {
1301 					opt_scale_x = 3;
1302 					opt_scale_y = 3;
1303 				} else if (strcmp(optarg, "4") == 0) {
1304 					opt_scale_x = 4;
1305 					opt_scale_y = 4;
1306 				} else {
1307 					if (sscanf(optarg, "%dx%d", &opt_scale_x, &opt_scale_y) != 2
1308 						|| opt_scale_x < 1
1309 						|| opt_scale_y < 1
1310 					) {
1311 						printf("Invalid -k option. Valid values are 2, 2x3, 2x4, 3 and 4.\n");
1312 						exit(EXIT_FAILURE);
1313 					}
1314 				}
1315 				break;
1316 			case 'c' :
1317 				opt_crc = 1;
1318 				break;
1319 			case 'o' :
1320 				opt_only124 = 1;
1321 				break;
1322 			case 'w' :
1323 				opt_tes = 1;
1324 				break;
1325 			case 'r' :
1326 				if (strcmp(optarg, "x") == 0)
1327 					opt_ver = 1;
1328 				else if (strcmp(optarg, "k") == 0)
1329 					opt_ver = 2;
1330 				else
1331 					opt_ver = atoi(optarg);
1332 				break;
1333 			case 'g' :
1334 				opt_gen = 1;
1335 				break;
1336 			default:
1337 				printf("Unknown option `%c'.\n", (char)optopt);
1338 				exit(EXIT_FAILURE);
1339 		}
1340 	}
1341 
1342 	switch (opt_scale_x * 100 + opt_scale_y) {
1343 	case 202 : max_ver = SCALE2X_REVISION_MAX; break;
1344 	case 203 : max_ver = SCALE2X3_REVISION_MAX; break;
1345 	case 204 : max_ver = SCALE2X4_REVISION_MAX; break;
1346 	case 303 : max_ver = SCALE3X_REVISION_MAX; break;
1347 	case 404 : max_ver = SCALE4X_REVISION_MAX; break;
1348 	default : max_ver = 0; break;
1349 	}
1350 
1351 	if (opt_ver < 0 || opt_ver > max_ver) {
1352 		printf("Invalid -r option. Valid values are 0 - %d.\n", max_ver);
1353 		exit(EXIT_FAILURE);
1354 	}
1355 
1356 	if (opt_gen) {
1357 		if (optind != argc) {
1358 			usage();
1359 			exit(EXIT_FAILURE);
1360 		}
1361 
1362 		file_gen();
1363 	} else {
1364 		if (optind + 2 != argc) {
1365 			usage();
1366 			exit(EXIT_FAILURE);
1367 		}
1368 
1369 		if (file_process(argv[optind], argv[optind+1], opt_scale_x, opt_scale_y, opt_tes, opt_ver, opt_crc, opt_only124) != 0) {
1370 			exit(EXIT_FAILURE);
1371 		}
1372 	}
1373 
1374 	return EXIT_SUCCESS;
1375 }
1376 
1377