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