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