1 /*
2  * This file is part of the Scale2x project.
3  *
4  * Copyright (C) 2003 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 file contains an example implementation of the Scale effect
23  * applyed to a generic bitmap.
24  *
25  * You can find an high level description of the effect at :
26  *
27  * http://scale2x.sourceforge.net/
28  *
29  * Alternatively at the previous license terms, you are allowed to use this
30  * code in your program with these conditions:
31  * - the program is not used in commercial activities.
32  * - the whole source code of the program is released with the binary.
33  * - derivative works of the program are allowed.
34  */
35 
36 #include "common/scummsys.h"
37 
38 #include "graphics/scaler/scale2x.h"
39 #include "graphics/scaler/scale3x.h"
40 
41 #define DST(bits, num)	(scale2x_uint ## bits *)dst ## num
42 #define SRC(bits, num)	(const scale2x_uint ## bits *)src ## num
43 
44 /**
45  * Apply the Scale2x effect on a group of rows. Used internally.
46  */
stage_scale2x(void * dst0,void * dst1,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)47 static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row) {
48 	switch (pixel) {
49 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
50 	case 1: scale2x_8_mmx( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
51 	case 2: scale2x_16_mmx(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
52 	case 4: scale2x_32_mmx(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
53 #elif defined(USE_ARM_SCALER_ASM)
54 	case 1: scale2x_8_arm( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
55 	case 2: scale2x_16_arm(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
56 	case 4: scale2x_32_arm(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
57 #else
58 	case 1: scale2x_8_def( DST( 8,0), DST( 8,1), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
59 	case 2: scale2x_16_def(DST(16,0), DST(16,1), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
60 	case 4: scale2x_32_def(DST(32,0), DST(32,1), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
61 #endif
62 	}
63 }
64 
65 /**
66  * Apply the Scale3x effect on a group of rows. Used internally.
67  */
stage_scale3x(void * dst0,void * dst1,void * dst2,const void * src0,const void * src1,const void * src2,unsigned pixel,unsigned pixel_per_row)68 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) {
69 	switch (pixel) {
70 	case 1: scale3x_8_def( DST( 8,0), DST( 8,1), DST( 8,2), SRC( 8,0), SRC( 8,1), SRC( 8,2), pixel_per_row); break;
71 	case 2: scale3x_16_def(DST(16,0), DST(16,1), DST(16,2), SRC(16,0), SRC(16,1), SRC(16,2), pixel_per_row); break;
72 	case 4: scale3x_32_def(DST(32,0), DST(32,1), DST(32,2), SRC(32,0), SRC(32,1), SRC(32,2), pixel_per_row); break;
73 	}
74 }
75 
76 /**
77  * Apply the Scale4x effect on a group of rows. Used internally.
78  */
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)79 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) {
80 	stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
81 	stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
82 }
83 
84 #define SCDST(i) (dst+(i)*dst_slice)
85 #define SCSRC(i) (src+(i)*src_slice)
86 #define SCMID(i) (mid[(i)])
87 
88 /**
89  * Apply the Scale2x effect on a bitmap.
90  * The destination bitmap is filled with the scaled version of the source bitmap.
91  * The source bitmap isn't modified.
92  * The destination bitmap must be manually allocated before calling the function,
93  * note that the resulting size is exactly 2x2 times the size of the source bitmap.
94  * @param void_dst Pointer at the first pixel of the destination bitmap.
95  * @param dst_slice Size in bytes of a destination bitmap row.
96  * @param void_src Pointer at the first pixel of the source bitmap.
97  * @param src_slice Size in bytes of a source bitmap row.
98  * @param pixel Bytes per pixel of the source and destination bitmap.
99  * @param width Horizontal size in pixels of the source bitmap.
100  * @param height Vertical size in pixels of the source bitmap.
101  */
scale2x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)102 static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
103 	unsigned char* dst = (unsigned char*)void_dst;
104 	const unsigned char* src = (const unsigned char*)void_src;
105 	unsigned count;
106 
107 	assert(height >= 2);
108 
109 	count = height;
110 
111 	while (count) {
112 		stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
113 
114 		dst = SCDST(2);
115 		src = SCSRC(1);
116 
117 		--count;
118 	}
119 
120 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
121 	scale2x_mmx_emms();
122 #endif
123 }
124 
125 /**
126  * Apply the Scale3x effect on a bitmap.
127  * The destination bitmap is filled with the scaled version of the source bitmap.
128  * The source bitmap isn't modified.
129  * The destination bitmap must be manually allocated before calling the function,
130  * note that the resulting size is exactly 3x3 times the size of the source bitmap.
131  * @param void_dst Pointer at the first pixel of the destination bitmap.
132  * @param dst_slice Size in bytes of a destination bitmap row.
133  * @param void_src Pointer at the first pixel of the source bitmap.
134  * @param src_slice Size in bytes of a source bitmap row.
135  * @param pixel Bytes per pixel of the source and destination bitmap.
136  * @param width Horizontal size in pixels of the source bitmap.
137  * @param height Vertical size in pixels of the source bitmap.
138  */
scale3x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)139 static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
140 	unsigned char* dst = (unsigned char*)void_dst;
141 	const unsigned char* src = (const unsigned char*)void_src;
142 	unsigned count;
143 
144 	assert(height >= 2);
145 
146 	count = height;
147 
148 	while (count) {
149 		stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
150 
151 		dst = SCDST(3);
152 		src = SCSRC(1);
153 
154 		--count;
155 	}
156 }
157 
158 /**
159  * Apply the Scale4x effect on a bitmap.
160  * The destination bitmap is filled with the scaled version of the source bitmap.
161  * The source bitmap isn't modified.
162  * The destination bitmap must be manually allocated before calling the function,
163  * note that the resulting size is exactly 4x4 times the size of the source bitmap.
164  * \note This function requires also a small buffer bitmap used internally to store
165  * intermediate results. This bitmap must have at least an horizontal size in bytes of 2*width*pixel,
166  * and a vertical size of 6 rows. The memory of this buffer must not be allocated
167  * in video memory because it's also read and not only written. Generally
168  * a heap (malloc) or a stack (alloca) buffer is the best choices.
169  * @param void_dst Pointer at the first pixel of the destination bitmap.
170  * @param dst_slice Size in bytes of a destination bitmap row.
171  * @param void_mid Pointer at the first pixel of the buffer bitmap.
172  * @param mid_slice Size in bytes of a buffer bitmap row.
173  * @param void_src Pointer at the first pixel of the source bitmap.
174  * @param src_slice Size in bytes of a source bitmap row.
175  * @param pixel Bytes per pixel of the source and destination bitmap.
176  * @param width Horizontal size in pixels of the source bitmap.
177  * @param height Vertical size in pixels of the source bitmap.
178  */
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)179 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) {
180 	unsigned char* dst = (unsigned char*)void_dst;
181 	const unsigned char* src = (const unsigned char*)void_src;
182 	unsigned count;
183 	unsigned char* mid[6];
184 
185 	assert(height >= 4);
186 
187 	count = height;
188 
189 	/* set the 6 buffer pointers */
190 	mid[0] = (unsigned char*)void_mid;
191 	mid[1] = mid[0] + mid_slice;
192 	mid[2] = mid[1] + mid_slice;
193 	mid[3] = mid[2] + mid_slice;
194 	mid[4] = mid[3] + mid_slice;
195 	mid[5] = mid[4] + mid_slice;
196 
197 	while (count) {
198 		unsigned char* tmp;
199 
200 		stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
201 		stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
202 
203 		dst = SCDST(4);
204 		src = SCSRC(1);
205 
206 		tmp = SCMID(0); /* shift by 2 position */
207 		SCMID(0) = SCMID(2);
208 		SCMID(2) = SCMID(4);
209 		SCMID(4) = tmp;
210 		tmp = SCMID(1);
211 		SCMID(1) = SCMID(3);
212 		SCMID(3) = SCMID(5);
213 		SCMID(5) = tmp;
214 
215 		--count;
216 	}
217 
218 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
219 	scale2x_mmx_emms();
220 #endif
221 }
222 
223 /**
224  * Apply the Scale4x effect on a bitmap.
225  * The destination bitmap is filled with the scaled version of the source bitmap.
226  * The source bitmap isn't modified.
227  * The destination bitmap must be manually allocated before calling the function,
228  * note that the resulting size is exactly 4x4 times the size of the source bitmap.
229  * \note This function operates like ::scale4x_buf() but the intermediate buffer is
230  * automatically allocated in the stack.
231  * @param void_dst Pointer at the first pixel of the destination bitmap.
232  * @param dst_slice Size in bytes of a destination bitmap row.
233  * @param void_src Pointer at the first pixel of the source bitmap.
234  * @param src_slice Size in bytes of a source bitmap row.
235  * @param pixel Bytes per pixel of the source and destination bitmap.
236  * @param width Horizontal size in pixels of the source bitmap.
237  * @param height Vertical size in pixels of the source bitmap.
238  */
scale4x(void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)239 static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height) {
240 	unsigned mid_slice;
241 	void* mid;
242 
243 	mid_slice = 2 * pixel * width; /* required space for 1 row buffer */
244 
245 	mid_slice = (mid_slice + 0x7) & ~0x7; /* align to 8 bytes */
246 
247 #if defined(HAVE_ALLOCA)
248 	mid = alloca(6 * mid_slice); /* allocate space for 6 row buffers */
249 
250 	assert(mid != 0); /* alloca should never fails */
251 #else
252 	mid = malloc(6 * mid_slice); /* allocate space for 6 row buffers */
253 
254 	if (!mid)
255 		return;
256 #endif
257 
258 	scale4x_buf(void_dst, dst_slice, mid, mid_slice, void_src, src_slice, pixel, width, height);
259 
260 #if !defined(HAVE_ALLOCA)
261 	free(mid);
262 #endif
263 }
264 
265 /**
266  * Check if the scale implementation is applicable at the given arguments.
267  * @param scale Scale factor. 2, 3 or 4.
268  * @param pixel Bytes per pixel of the source and destination bitmap.
269  * @param width Horizontal size in pixels of the source bitmap.
270  * @param height Vertical size in pixels of the source bitmap.
271  * \return
272  *   - -1 on precondition violated.
273  *   - 0 on success.
274  */
scale_precondition(unsigned scale,unsigned pixel,unsigned width,unsigned height)275 int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height)
276 {
277 	if (scale != 2 && scale != 3 && scale != 4)
278 		return -1;
279 
280 	if (pixel != 1 && pixel != 2 && pixel != 4)
281 		return -1;
282 
283 	switch (scale) {
284 	case 2:
285 	case 3:
286 		if (height < 2)
287 			return -1;
288 		break;
289 	case 4:
290 		if (height < 4)
291 			return -1;
292 		break;
293 	}
294 
295 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
296 	switch (scale) {
297 	case 2:
298 	case 4:
299 		if (width < (16 / pixel))
300 			return -1;
301 		if (width % (8 / pixel) != 0)
302 			return -1;
303 		break;
304 	case 3:
305 		if (width < 2)
306 			return -1;
307 		break;
308 	}
309 #else
310 	if (width < 2)
311 		return -1;
312 #endif
313 
314 	return 0;
315 }
316 
317 /**
318  * Apply the Scale effect on a bitmap.
319  * This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
320  * @param scale Scale factor. 2, 3 or 4.
321  * @param void_dst Pointer at the first pixel of the destination bitmap.
322  * @param dst_slice Size in bytes of a destination bitmap row.
323  * @param void_src Pointer at the first pixel of the source bitmap.
324  * @param src_slice Size in bytes of a source bitmap row.
325  * @param pixel Bytes per pixel of the source and destination bitmap.
326  * @param width Horizontal size in pixels of the source bitmap.
327  * @param height Vertical size in pixels of the source bitmap.
328  */
scale(unsigned scale,void * void_dst,unsigned dst_slice,const void * void_src,unsigned src_slice,unsigned pixel,unsigned width,unsigned height)329 void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
330 {
331 	switch (scale) {
332 	case 2:
333 		scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
334 		break;
335 	case 3:
336 		scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
337 		break;
338 	case 4:
339 		scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
340 		break;
341 	}
342 }
343