1 /*
2 * This file is part of the Scale2x project.
3 *
4 * Copyright (C) 2003, 2004 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
17 /*
18 * This file contains an example implementation of the Scale effect
19 * applyed to a generic bitmap.
20 *
21 * You can find an high level description of the effect at :
22 *
23 * http://www.scale2x.it/
24 */
25
26 #include "../stdafx.h"
27
28 #if HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include "scale2x.h"
33 #include "scale3x.h"
34
35 #if HAVE_ALLOCA_H
36 #include <alloca.h>
37 #endif
38
39 #include <assert.h>
40 #include <stdlib.h>
41
42 #if !(defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__))
43 #include <malloc.h>
44 #endif
45
46 #define SSDST(bits, num) (scale2x_uint##bits *)dst##num
47 #define SSSRC(bits, num) (const scale2x_uint##bits *)src##num
48
49 /**
50 * Apply the Scale2x effect on a group of rows. Used internally.
51 */
stage_scale2x(void * dst0,void * dst1,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)52 static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
53 {
54 switch (pixel) {
55 case 1 : scale2x_8_def(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
56 case 2 : scale2x_16_def(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
57 case 4 : scale2x_32_def(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
58 }
59 }
60
61 /**
62 * Apply the Scale2x3 effect on a group of rows. Used internally.
63 */
stage_scale2x3(void * dst0,void * dst1,void * dst2,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)64 static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
65 {
66 switch (pixel) {
67 case 1 : scale2x3_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
68 case 2 : scale2x3_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
69 case 4 : scale2x3_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
70 }
71 }
72
73 /**
74 * Apply the Scale2x4 effect on a group of rows. Used internally.
75 */
stage_scale2x4(void * dst0,void * dst1,void * dst2,void * dst3,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)76 static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
77 {
78 switch (pixel) {
79 case 1 : scale2x4_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
80 case 2 : scale2x4_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
81 case 4 : scale2x4_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
82 }
83 }
84
85 /**
86 * Apply the Scale3x effect on a group of rows. Used internally.
87 */
stage_scale3x(void * dst0,void * dst1,void * dst2,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)88 static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
89 {
90 switch (pixel) {
91 case 1 : scale3x_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
92 case 2 : scale3x_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
93 case 4 : scale3x_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
94 }
95 }
96
97 /**
98 * Apply the Scale4x effect on a group of rows. Used internally.
99 */
stage_scale4x(void * dst0,void * dst1,void * dst2,void * dst3,const void * src0,const void * src1,const void * src2,const void * src3,unsigned pixel,unsigned pixel_per_row)100 static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row)
101 {
102 stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
103 stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
104 }
105
106 #define SCDST(i) (dst+(i)*dst_slice)
107 #define SCSRC(i) (src+(i)*src_slice)
108 #define SCMID(i) (mid[(i)])
109
110 /**
111 * Apply the Scale2x effect on a bitmap.
112 * The destination bitmap is filled with the scaled version of the source bitmap.
113 * The source bitmap isn't modified.
114 * The destination bitmap must be manually allocated before calling the function,
115 * note that the resulting size is exactly 2x2 times the size of the source bitmap.
116 * \param void_dst Pointer at the first pixel of the destination bitmap.
117 * \param dst_slice Size in bytes of a destination bitmap row.
118 * \param void_src Pointer at the first pixel of the source bitmap.
119 * \param src_slice Size in bytes of a source bitmap row.
120 * \param pixel Bytes per pixel of the source and destination bitmap.
121 * \param width Horizontal size in pixels of the source bitmap.
122 * \param height Vertical size in pixels of the source bitmap.
123 */
scale2x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)124 static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
125 {
126 unsigned char* dst = (unsigned char*)void_dst;
127 const unsigned char* src = (const unsigned char*)void_src;
128 unsigned count;
129
130 assert(height >= 2);
131
132 count = height;
133
134 stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
135
136 dst = SCDST(2);
137
138 count -= 2;
139 while (count) {
140 stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
141
142 dst = SCDST(2);
143 src = SCSRC(1);
144
145 --count;
146 }
147
148 stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
149 }
150
151 /**
152 * Apply the Scale2x3 effect on a bitmap.
153 * The destination bitmap is filled with the scaled version of the source bitmap.
154 * The source bitmap isn't modified.
155 * The destination bitmap must be manually allocated before calling the function,
156 * note that the resulting size is exactly 2x3 times the size of the source bitmap.
157 * \param void_dst Pointer at the first pixel of the destination bitmap.
158 * \param dst_slice Size in bytes of a destination bitmap row.
159 * \param void_src Pointer at the first pixel of the source bitmap.
160 * \param src_slice Size in bytes of a source bitmap row.
161 * \param pixel Bytes per pixel of the source and destination bitmap.
162 * \param width Horizontal size in pixels of the source bitmap.
163 * \param height Vertical size in pixels of the source bitmap.
164 */
scale2x3(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)165 static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
166 {
167 unsigned char* dst = (unsigned char*)void_dst;
168 const unsigned char* src = (const unsigned char*)void_src;
169 unsigned count;
170
171 assert(height >= 2);
172
173 count = height;
174
175 stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
176
177 dst = SCDST(3);
178
179 count -= 2;
180 while (count) {
181 stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
182
183 dst = SCDST(3);
184 src = SCSRC(1);
185
186 --count;
187 }
188
189 stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
190 }
191
192 /**
193 * Apply the Scale2x4 effect on a bitmap.
194 * The destination bitmap is filled with the scaled version of the source bitmap.
195 * The source bitmap isn't modified.
196 * The destination bitmap must be manually allocated before calling the function,
197 * note that the resulting size is exactly 2x4 times the size of the source bitmap.
198 * \param void_dst Pointer at the first pixel of the destination bitmap.
199 * \param dst_slice Size in bytes of a destination bitmap row.
200 * \param void_src Pointer at the first pixel of the source bitmap.
201 * \param src_slice Size in bytes of a source bitmap row.
202 * \param pixel Bytes per pixel of the source and destination bitmap.
203 * \param width Horizontal size in pixels of the source bitmap.
204 * \param height Vertical size in pixels of the source bitmap.
205 */
scale2x4(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)206 static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
207 {
208 unsigned char* dst = (unsigned char*)void_dst;
209 const unsigned char* src = (const unsigned char*)void_src;
210 unsigned count;
211
212 assert(height >= 2);
213
214 count = height;
215
216 stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
217
218 dst = SCDST(4);
219
220 count -= 2;
221 while (count) {
222 stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
223
224 dst = SCDST(4);
225 src = SCSRC(1);
226
227 --count;
228 }
229
230 stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
231 }
232
233 /**
234 * Apply the Scale3x effect on a bitmap.
235 * The destination bitmap is filled with the scaled version of the source bitmap.
236 * The source bitmap isn't modified.
237 * The destination bitmap must be manually allocated before calling the function,
238 * note that the resulting size is exactly 3x3 times the size of the source bitmap.
239 * \param void_dst Pointer at the first pixel of the destination bitmap.
240 * \param dst_slice Size in bytes of a destination bitmap row.
241 * \param void_src Pointer at the first pixel of the source bitmap.
242 * \param src_slice Size in bytes of a source bitmap row.
243 * \param pixel Bytes per pixel of the source and destination bitmap.
244 * \param width Horizontal size in pixels of the source bitmap.
245 * \param height Vertical size in pixels of the source bitmap.
246 */
scale3x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)247 static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
248 {
249 unsigned char* dst = (unsigned char*)void_dst;
250 const unsigned char* src = (const unsigned char*)void_src;
251 unsigned count;
252
253 assert(height >= 2);
254
255 count = height;
256
257 stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
258
259 dst = SCDST(3);
260
261 count -= 2;
262 while (count) {
263 stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
264
265 dst = SCDST(3);
266 src = SCSRC(1);
267
268 --count;
269 }
270
271 stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
272 }
273
274 /**
275 * Apply the Scale4x effect on a bitmap.
276 * The destination bitmap is filled with the scaled version of the source bitmap.
277 * The source bitmap isn't modified.
278 * The destination bitmap must be manually allocated before calling the function,
279 * note that the resulting size is exactly 4x4 times the size of the source bitmap.
280 * \note This function requires also a small buffer bitmap used internally to store
281 * intermediate results. This bitmap must have at least an horizontal size in bytes of 2*width*pixel,
282 * and a vertical size of 6 rows. The memory of this buffer must not be allocated
283 * in video memory because it's also read and not only written. Generally
284 * a heap (malloc) or a stack (alloca) buffer is the best choice.
285 * \param void_dst Pointer at the first pixel of the destination bitmap.
286 * \param dst_slice Size in bytes of a destination bitmap row.
287 * \param void_mid Pointer at the first pixel of the buffer bitmap.
288 * \param mid_slice Size in bytes of a buffer bitmap row.
289 * \param void_src Pointer at the first pixel of the source bitmap.
290 * \param src_slice Size in bytes of a source bitmap row.
291 * \param pixel Bytes per pixel of the source and destination bitmap.
292 * \param width Horizontal size in pixels of the source bitmap.
293 * \param height Vertical size in pixels of the source bitmap.
294 */
scale4x_buf(void * void_dst,unsigned dst_slice,void * void_mid,unsigned mid_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)295 static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
296 {
297 unsigned char* dst = (unsigned char*)void_dst;
298 const unsigned char* src = (const unsigned char*)void_src;
299 unsigned count;
300 unsigned char* mid[6];
301
302 assert(height >= 4);
303
304 count = height;
305
306 /* set the 6 buffer pointers */
307 mid[0] = (unsigned char*)void_mid;
308 mid[1] = mid[0] + mid_slice;
309 mid[2] = mid[1] + mid_slice;
310 mid[3] = mid[2] + mid_slice;
311 mid[4] = mid[3] + mid_slice;
312 mid[5] = mid[4] + mid_slice;
313
314 stage_scale2x(SCMID(-2+6), SCMID(-1+6), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
315 stage_scale2x(SCMID(0), SCMID(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
316 stage_scale2x(SCMID(2), SCMID(3), SCSRC(1), SCSRC(2), SCSRC(3), pixel, width);
317 stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-2+6), SCMID(-2+6), SCMID(-1+6), SCMID(0), pixel, width);
318
319 dst = SCDST(4);
320
321 stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-1+6), SCMID(0), SCMID(1), SCMID(2), pixel, width);
322
323 dst = SCDST(4);
324
325 count -= 4;
326 while (count) {
327 unsigned char* tmp;
328
329 stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
330 stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
331
332 dst = SCDST(4);
333 src = SCSRC(1);
334
335 tmp = SCMID(0); /* shift by 2 position */
336 SCMID(0) = SCMID(2);
337 SCMID(2) = SCMID(4);
338 SCMID(4) = tmp;
339 tmp = SCMID(1);
340 SCMID(1) = SCMID(3);
341 SCMID(3) = SCMID(5);
342 SCMID(5) = tmp;
343
344 --count;
345 }
346
347 stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(3), pixel, width);
348 stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
349
350 dst = SCDST(4);
351
352 stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(3), SCMID(4), SCMID(5), SCMID(5), pixel, width);
353 }
354
355 /**
356 * Apply the Scale4x effect on a bitmap.
357 * The destination bitmap is filled with the scaled version of the source bitmap.
358 * The source bitmap isn't modified.
359 * The destination bitmap must be manually allocated before calling the function,
360 * note that the resulting size is exactly 4x4 times the size of the source bitmap.
361 * \note This function operates like ::scale4x_buf() but the intermediate buffer is
362 * automatically allocated in the stack.
363 * \param void_dst Pointer at the first pixel of the destination bitmap.
364 * \param dst_slice Size in bytes of a destination bitmap row.
365 * \param void_src Pointer at the first pixel of the source bitmap.
366 * \param src_slice Size in bytes of a source bitmap row.
367 * \param pixel Bytes per pixel of the source and destination bitmap.
368 * \param width Horizontal size in pixels of the source bitmap.
369 * \param height Vertical size in pixels of the source bitmap.
370 */
scale4x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)371 static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
372 {
373 unsigned mid_slice;
374 void* mid;
375
376 mid_slice = 2 * pixel * width; /* required space for 1 row buffer */
377
378 mid_slice = (mid_slice + 0x7) & ~0x7; /* align to 8 bytes */
379
380 #if HAVE_ALLOCA
381 mid = alloca(6 * mid_slice); /* allocate space for 6 row buffers */
382
383 assert(mid != 0); /* alloca should never fails */
384 #else
385 mid = malloc(6 * mid_slice); /* allocate space for 6 row buffers */
386
387 if (!mid)
388 return;
389 #endif
390
391 scale4x_buf(void_dst, dst_slice, mid, mid_slice, void_src, src_slice, pixel, width, height);
392
393 #if !HAVE_ALLOCA
394 free(mid);
395 #endif
396 }
397
398 /**
399 * Check if the scale implementation is applicable at the given arguments.
400 * \param scale Scale factor. 2, 203 (fox 2x3), 204 (for 2x4), 3 or 4.
401 * \param pixel Bytes per pixel of the source and destination bitmap.
402 * \param width Horizontal size in pixels of the source bitmap.
403 * \param height Vertical size in pixels of the source bitmap.
404 * \return
405 * - -1 on precondition violated.
406 * - 0 on success.
407 */
scale_precondition(unsigned scale,unsigned pixel,unsigned width,unsigned height)408 int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height)
409 {
410 if (pixel != 1 && pixel != 2 && pixel != 4)
411 return -1;
412
413 switch (scale) {
414 case 202 :
415 case 203 :
416 case 204 :
417 case 2 :
418 case 303 :
419 case 3 :
420 if (height < 2)
421 return -1;
422 break;
423 case 404 :
424 case 4 :
425 if (height < 4)
426 return -1;
427 break;
428 default:
429 return -1;
430 }
431
432 if (width < 2)
433 return -1;
434
435 return 0;
436 }
437
438 /**
439 * Apply the Scale effect on a bitmap.
440 * This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
441 * \param scale Scale factor. 2, 203 (fox 2x3), 204 (for 2x4), 3 or 4.
442 * \param void_dst Pointer at the first pixel of the destination bitmap.
443 * \param dst_slice Size in bytes of a destination bitmap row.
444 * \param void_src Pointer at the first pixel of the source bitmap.
445 * \param src_slice Size in bytes of a source bitmap row.
446 * \param pixel Bytes per pixel of the source and destination bitmap.
447 * \param width Horizontal size in pixels of the source bitmap.
448 * \param height Vertical size in pixels of the source bitmap.
449 */
scale(unsigned scale,void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)450 void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
451 {
452 switch (scale) {
453 case 202 :
454 case 2 :
455 scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
456 break;
457 case 203 :
458 scale2x3(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
459 break;
460 case 204 :
461 scale2x4(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
462 break;
463 case 303 :
464 case 3 :
465 scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
466 break;
467 case 404 :
468 case 4 :
469 scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
470 break;
471 }
472 }
473
474