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