1 /*
2 * This file is part of the Scale2x project.
3 *
4 * Copyright (C) 2001, 2002, 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 * 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 a C and MMX implementation of the Scale2x effect.
23 *
24 * You can find an high level description of the effect at :
25 *
26 * http://scale2x.sourceforge.net/
27 *
28 * Alternatively at the previous license terms, you are allowed to use this
29 * code in your program with these conditions:
30 * - the program is not used in commercial activities.
31 * - the whole source code of the program is released with the binary.
32 * - derivative works of the program are allowed.
33 */
34
35 #include "scale3x.h"
36
37 #include <assert.h>
38
39 /***************************************************************************/
40 /* Scale3x C implementation */
41
42 /**
43 * Define the macro USE_SCALE_RANDOMWRITE to enable
44 * an optimized version which writes memory in random order.
45 * This version is a little faster if you write in system memory.
46 * But it's a lot slower if you write in video memory.
47 * So, enable it only if you are sure to never write directly in video memory.
48 */
49 /* #define USE_SCALE_RANDOMWRITE */
50
51 #ifdef USE_SCALE_RANDOMWRITE
52
scale3x_8_def_whole(scale3x_uint8 * restrict dst0,scale3x_uint8 * restrict dst1,scale3x_uint8 * restrict dst2,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)53 static inline void scale3x_8_def_whole(scale3x_uint8* restrict dst0, scale3x_uint8* restrict dst1, scale3x_uint8* restrict dst2, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
54 {
55 assert(count >= 2);
56
57 /* first pixel */
58 if (src0[0] != src2[0] && src1[0] != src1[1]) {
59 dst0[0] = src1[0];
60 dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
61 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
62 dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
63 dst1[1] = src1[0];
64 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
65 dst2[0] = src1[0];
66 dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
67 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
68 } else {
69 dst0[0] = src1[0];
70 dst0[1] = src1[0];
71 dst0[2] = src1[0];
72 dst1[0] = src1[0];
73 dst1[1] = src1[0];
74 dst1[2] = src1[0];
75 dst2[0] = src1[0];
76 dst2[1] = src1[0];
77 dst2[2] = src1[0];
78 }
79 ++src0;
80 ++src1;
81 ++src2;
82 dst0 += 3;
83 dst1 += 3;
84 dst2 += 3;
85
86 /* central pixels */
87 count -= 2;
88 while (count) {
89 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
90 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
91 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
92 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
93 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
94 dst1[1] = src1[0];
95 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
96 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
97 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
98 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
99 } else {
100 dst0[0] = src1[0];
101 dst0[1] = src1[0];
102 dst0[2] = src1[0];
103 dst1[0] = src1[0];
104 dst1[1] = src1[0];
105 dst1[2] = src1[0];
106 dst2[0] = src1[0];
107 dst2[1] = src1[0];
108 dst2[2] = src1[0];
109 }
110
111 ++src0;
112 ++src1;
113 ++src2;
114 dst0 += 3;
115 dst1 += 3;
116 dst2 += 3;
117 --count;
118 }
119
120 /* last pixel */
121 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
122 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
123 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
124 dst0[2] = src1[0];
125 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
126 dst1[1] = src1[0];
127 dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
128 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
129 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
130 dst2[2] = src1[0];
131 } else {
132 dst0[0] = src1[0];
133 dst0[1] = src1[0];
134 dst0[2] = src1[0];
135 dst1[0] = src1[0];
136 dst1[1] = src1[0];
137 dst1[2] = src1[0];
138 dst2[0] = src1[0];
139 dst2[1] = src1[0];
140 dst2[2] = src1[0];
141 }
142 }
143
144 #endif
145
scale3x_8_def_border(scale3x_uint8 * restrict dst,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)146 static inline void scale3x_8_def_border(scale3x_uint8* restrict dst, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
147 {
148 assert(count >= 2);
149
150 /* first pixel */
151 if (src0[0] != src2[0] && src1[0] != src1[1]) {
152 dst[0] = src1[0];
153 dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
154 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
155 } else {
156 dst[0] = src1[0];
157 dst[1] = src1[0];
158 dst[2] = src1[0];
159 }
160 ++src0;
161 ++src1;
162 ++src2;
163 dst += 3;
164
165 /* central pixels */
166 count -= 2;
167 while (count) {
168 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
169 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
170 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
171 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
172 } else {
173 dst[0] = src1[0];
174 dst[1] = src1[0];
175 dst[2] = src1[0];
176 }
177
178 ++src0;
179 ++src1;
180 ++src2;
181 dst += 3;
182 --count;
183 }
184
185 /* last pixel */
186 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
187 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
188 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
189 dst[2] = src1[0];
190 } else {
191 dst[0] = src1[0];
192 dst[1] = src1[0];
193 dst[2] = src1[0];
194 }
195 }
196
scale3x_8_def_center(scale3x_uint8 * restrict dst,const scale3x_uint8 * restrict src0,const scale3x_uint8 * restrict src1,const scale3x_uint8 * restrict src2,unsigned count)197 static inline void scale3x_8_def_center(scale3x_uint8* restrict dst, const scale3x_uint8* restrict src0, const scale3x_uint8* restrict src1, const scale3x_uint8* restrict src2, unsigned count)
198 {
199 assert(count >= 2);
200
201 /* first pixel */
202 if (src0[0] != src2[0] && src1[0] != src1[1]) {
203 dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
204 dst[1] = src1[0];
205 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
206 } else {
207 dst[0] = src1[0];
208 dst[1] = src1[0];
209 dst[2] = src1[0];
210 }
211 ++src0;
212 ++src1;
213 ++src2;
214 dst += 3;
215
216 /* central pixels */
217 count -= 2;
218 while (count) {
219 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
220 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
221 dst[1] = src1[0];
222 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
223 } else {
224 dst[0] = src1[0];
225 dst[1] = src1[0];
226 dst[2] = src1[0];
227 }
228
229 ++src0;
230 ++src1;
231 ++src2;
232 dst += 3;
233 --count;
234 }
235
236 /* last pixel */
237 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
238 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
239 dst[1] = src1[0];
240 dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
241 } else {
242 dst[0] = src1[0];
243 dst[1] = src1[0];
244 dst[2] = src1[0];
245 }
246 }
247
248 #ifdef USE_SCALE_RANDOMWRITE
249
scale3x_16_def_whole(scale3x_uint16 * restrict dst0,scale3x_uint16 * restrict dst1,scale3x_uint16 * restrict dst2,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)250 static inline void scale3x_16_def_whole(scale3x_uint16* restrict dst0, scale3x_uint16* restrict dst1, scale3x_uint16* restrict dst2, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
251 {
252 assert(count >= 2);
253
254 /* first pixel */
255 if (src0[0] != src2[0] && src1[0] != src1[1]) {
256 dst0[0] = src1[0];
257 dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
258 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
259 dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
260 dst1[1] = src1[0];
261 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
262 dst2[0] = src1[0];
263 dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
264 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
265 } else {
266 dst0[0] = src1[0];
267 dst0[1] = src1[0];
268 dst0[2] = src1[0];
269 dst1[0] = src1[0];
270 dst1[1] = src1[0];
271 dst1[2] = src1[0];
272 dst2[0] = src1[0];
273 dst2[1] = src1[0];
274 dst2[2] = src1[0];
275 }
276 ++src0;
277 ++src1;
278 ++src2;
279 dst0 += 3;
280 dst1 += 3;
281 dst2 += 3;
282
283 /* central pixels */
284 count -= 2;
285 while (count) {
286 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
287 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
288 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
289 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
290 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
291 dst1[1] = src1[0];
292 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
293 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
294 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
295 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
296 } else {
297 dst0[0] = src1[0];
298 dst0[1] = src1[0];
299 dst0[2] = src1[0];
300 dst1[0] = src1[0];
301 dst1[1] = src1[0];
302 dst1[2] = src1[0];
303 dst2[0] = src1[0];
304 dst2[1] = src1[0];
305 dst2[2] = src1[0];
306 }
307
308 ++src0;
309 ++src1;
310 ++src2;
311 dst0 += 3;
312 dst1 += 3;
313 dst2 += 3;
314 --count;
315 }
316
317 /* last pixel */
318 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
319 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
320 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
321 dst0[2] = src1[0];
322 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
323 dst1[1] = src1[0];
324 dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
325 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
326 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
327 dst2[2] = src1[0];
328 } else {
329 dst0[0] = src1[0];
330 dst0[1] = src1[0];
331 dst0[2] = src1[0];
332 dst1[0] = src1[0];
333 dst1[1] = src1[0];
334 dst1[2] = src1[0];
335 dst2[0] = src1[0];
336 dst2[1] = src1[0];
337 dst2[2] = src1[0];
338 }
339 }
340
341 #endif
342
scale3x_16_def_border(scale3x_uint16 * restrict dst,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)343 static inline void scale3x_16_def_border(scale3x_uint16* restrict dst, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
344 {
345 assert(count >= 2);
346
347 /* first pixel */
348 if (src0[0] != src2[0] && src1[0] != src1[1]) {
349 dst[0] = src1[0];
350 dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
351 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
352 } else {
353 dst[0] = src1[0];
354 dst[1] = src1[0];
355 dst[2] = src1[0];
356 }
357 ++src0;
358 ++src1;
359 ++src2;
360 dst += 3;
361
362 /* central pixels */
363 count -= 2;
364 while (count) {
365 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
366 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
367 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
368 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
369 } else {
370 dst[0] = src1[0];
371 dst[1] = src1[0];
372 dst[2] = src1[0];
373 }
374
375 ++src0;
376 ++src1;
377 ++src2;
378 dst += 3;
379 --count;
380 }
381
382 /* last pixel */
383 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
384 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
385 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
386 dst[2] = src1[0];
387 } else {
388 dst[0] = src1[0];
389 dst[1] = src1[0];
390 dst[2] = src1[0];
391 }
392 }
393
scale3x_16_def_center(scale3x_uint16 * restrict dst,const scale3x_uint16 * restrict src0,const scale3x_uint16 * restrict src1,const scale3x_uint16 * restrict src2,unsigned count)394 static inline void scale3x_16_def_center(scale3x_uint16* restrict dst, const scale3x_uint16* restrict src0, const scale3x_uint16* restrict src1, const scale3x_uint16* restrict src2, unsigned count)
395 {
396 assert(count >= 2);
397
398 /* first pixel */
399 if (src0[0] != src2[0] && src1[0] != src1[1]) {
400 dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
401 dst[1] = src1[0];
402 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
403 } else {
404 dst[0] = src1[0];
405 dst[1] = src1[0];
406 dst[2] = src1[0];
407 }
408 ++src0;
409 ++src1;
410 ++src2;
411 dst += 3;
412
413 /* central pixels */
414 count -= 2;
415 while (count) {
416 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
417 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
418 dst[1] = src1[0];
419 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
420 } else {
421 dst[0] = src1[0];
422 dst[1] = src1[0];
423 dst[2] = src1[0];
424 }
425
426 ++src0;
427 ++src1;
428 ++src2;
429 dst += 3;
430 --count;
431 }
432
433 /* last pixel */
434 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
435 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
436 dst[1] = src1[0];
437 dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
438 } else {
439 dst[0] = src1[0];
440 dst[1] = src1[0];
441 dst[2] = src1[0];
442 }
443 }
444
445 #ifdef USE_SCALE_RANDOMWRITE
446
scale3x_32_def_whole(scale3x_uint32 * restrict dst0,scale3x_uint32 * restrict dst1,scale3x_uint32 * restrict dst2,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)447 static inline void scale3x_32_def_whole(scale3x_uint32* restrict dst0, scale3x_uint32* restrict dst1, scale3x_uint32* restrict dst2, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
448 {
449 assert(count >= 2);
450
451 /* first pixel */
452 if (src0[0] != src2[0] && src1[0] != src1[1]) {
453 dst0[0] = src1[0];
454 dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
455 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
456 dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
457 dst1[1] = src1[0];
458 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
459 dst2[0] = src1[0];
460 dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0];
461 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
462 } else {
463 dst0[0] = src1[0];
464 dst0[1] = src1[0];
465 dst0[2] = src1[0];
466 dst1[0] = src1[0];
467 dst1[1] = src1[0];
468 dst1[2] = src1[0];
469 dst2[0] = src1[0];
470 dst2[1] = src1[0];
471 dst2[2] = src1[0];
472 }
473 ++src0;
474 ++src1;
475 ++src2;
476 dst0 += 3;
477 dst1 += 3;
478 dst2 += 3;
479
480 /* central pixels */
481 count -= 2;
482 while (count) {
483 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
484 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
485 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
486 dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0];
487 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
488 dst1[1] = src1[0];
489 dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
490 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
491 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
492 dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0];
493 } else {
494 dst0[0] = src1[0];
495 dst0[1] = src1[0];
496 dst0[2] = src1[0];
497 dst1[0] = src1[0];
498 dst1[1] = src1[0];
499 dst1[2] = src1[0];
500 dst2[0] = src1[0];
501 dst2[1] = src1[0];
502 dst2[2] = src1[0];
503 }
504
505 ++src0;
506 ++src1;
507 ++src2;
508 dst0 += 3;
509 dst1 += 3;
510 dst2 += 3;
511 --count;
512 }
513
514 /* last pixel */
515 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
516 dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
517 dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
518 dst0[2] = src1[0];
519 dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
520 dst1[1] = src1[0];
521 dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
522 dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0];
523 dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0];
524 dst2[2] = src1[0];
525 } else {
526 dst0[0] = src1[0];
527 dst0[1] = src1[0];
528 dst0[2] = src1[0];
529 dst1[0] = src1[0];
530 dst1[1] = src1[0];
531 dst1[2] = src1[0];
532 dst2[0] = src1[0];
533 dst2[1] = src1[0];
534 dst2[2] = src1[0];
535 }
536 }
537
538 #endif
539
scale3x_32_def_border(scale3x_uint32 * restrict dst,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)540 static inline void scale3x_32_def_border(scale3x_uint32* restrict dst, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
541 {
542 assert(count >= 2);
543
544 /* first pixel */
545 if (src0[0] != src2[0] && src1[0] != src1[1]) {
546 dst[0] = src1[0];
547 dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
548 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
549 } else {
550 dst[0] = src1[0];
551 dst[1] = src1[0];
552 dst[2] = src1[0];
553 }
554 ++src0;
555 ++src1;
556 ++src2;
557 dst += 3;
558
559 /* central pixels */
560 count -= 2;
561 while (count) {
562 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
563 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
564 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
565 dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
566 } else {
567 dst[0] = src1[0];
568 dst[1] = src1[0];
569 dst[2] = src1[0];
570 }
571
572 ++src0;
573 ++src1;
574 ++src2;
575 dst += 3;
576 --count;
577 }
578
579 /* last pixel */
580 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
581 dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
582 dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
583 dst[2] = src1[0];
584 } else {
585 dst[0] = src1[0];
586 dst[1] = src1[0];
587 dst[2] = src1[0];
588 }
589 }
590
scale3x_32_def_center(scale3x_uint32 * restrict dst,const scale3x_uint32 * restrict src0,const scale3x_uint32 * restrict src1,const scale3x_uint32 * restrict src2,unsigned count)591 static inline void scale3x_32_def_center(scale3x_uint32* restrict dst, const scale3x_uint32* restrict src0, const scale3x_uint32* restrict src1, const scale3x_uint32* restrict src2, unsigned count)
592 {
593 assert(count >= 2);
594
595 /* first pixel */
596 if (src0[0] != src2[0] && src1[0] != src1[1]) {
597 dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
598 dst[1] = src1[0];
599 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
600 } else {
601 dst[0] = src1[0];
602 dst[1] = src1[0];
603 dst[2] = src1[0];
604 }
605 ++src0;
606 ++src1;
607 ++src2;
608 dst += 3;
609
610 /* central pixels */
611 count -= 2;
612 while (count) {
613 if (src0[0] != src2[0] && src1[-1] != src1[1]) {
614 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
615 dst[1] = src1[0];
616 dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
617 } else {
618 dst[0] = src1[0];
619 dst[1] = src1[0];
620 dst[2] = src1[0];
621 }
622
623 ++src0;
624 ++src1;
625 ++src2;
626 dst += 3;
627 --count;
628 }
629
630 /* last pixel */
631 if (src0[0] != src2[0] && src1[-1] != src1[0]) {
632 dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
633 dst[1] = src1[0];
634 dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
635 } else {
636 dst[0] = src1[0];
637 dst[1] = src1[0];
638 dst[2] = src1[0];
639 }
640 }
641
642 /**
643 * Scale by a factor of 3 a row of pixels of 8 bits.
644 * The function is implemented in C.
645 * The pixels over the left and right borders are assumed of the same color of
646 * the pixels on the border.
647 * \param src0 Pointer at the first pixel of the previous row.
648 * \param src1 Pointer at the first pixel of the current row.
649 * \param src2 Pointer at the first pixel of the next row.
650 * \param count Length in pixels of the src0, src1 and src2 rows.
651 * It must be at least 2.
652 * \param dst0 First destination row, triple length in pixels.
653 * \param dst1 Second destination row, triple length in pixels.
654 * \param dst2 Third destination row, triple length in pixels.
655 */
scale3x_8_def(scale3x_uint8 * dst0,scale3x_uint8 * dst1,scale3x_uint8 * dst2,const scale3x_uint8 * src0,const scale3x_uint8 * src1,const scale3x_uint8 * src2,unsigned count)656 void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
657 {
658 #ifdef USE_SCALE_RANDOMWRITE
659 scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
660 #else
661 scale3x_8_def_border(dst0, src0, src1, src2, count);
662 scale3x_8_def_center(dst1, src0, src1, src2, count);
663 scale3x_8_def_border(dst2, src2, src1, src0, count);
664 #endif
665 }
666
667 /**
668 * Scale by a factor of 3 a row of pixels of 16 bits.
669 * This function operates like scale3x_8_def() but for 16 bits pixels.
670 * \param src0 Pointer at the first pixel of the previous row.
671 * \param src1 Pointer at the first pixel of the current row.
672 * \param src2 Pointer at the first pixel of the next row.
673 * \param count Length in pixels of the src0, src1 and src2 rows.
674 * It must be at least 2.
675 * \param dst0 First destination row, triple length in pixels.
676 * \param dst1 Second destination row, triple length in pixels.
677 * \param dst2 Third destination row, triple length in pixels.
678 */
scale3x_16_def(scale3x_uint16 * dst0,scale3x_uint16 * dst1,scale3x_uint16 * dst2,const scale3x_uint16 * src0,const scale3x_uint16 * src1,const scale3x_uint16 * src2,unsigned count)679 void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
680 {
681 #ifdef USE_SCALE_RANDOMWRITE
682 scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
683 #else
684 scale3x_16_def_border(dst0, src0, src1, src2, count);
685 scale3x_16_def_center(dst1, src0, src1, src2, count);
686 scale3x_16_def_border(dst2, src2, src1, src0, count);
687 #endif
688 }
689
690 /**
691 * Scale by a factor of 3 a row of pixels of 32 bits.
692 * This function operates like scale3x_8_def() but for 32 bits pixels.
693 * \param src0 Pointer at the first pixel of the previous row.
694 * \param src1 Pointer at the first pixel of the current row.
695 * \param src2 Pointer at the first pixel of the next row.
696 * \param count Length in pixels of the src0, src1 and src2 rows.
697 * It must be at least 2.
698 * \param dst0 First destination row, triple length in pixels.
699 * \param dst1 Second destination row, triple length in pixels.
700 * \param dst2 Third destination row, triple length in pixels.
701 */
scale3x_32_def(scale3x_uint32 * dst0,scale3x_uint32 * dst1,scale3x_uint32 * dst2,const scale3x_uint32 * src0,const scale3x_uint32 * src1,const scale3x_uint32 * src2,unsigned count)702 void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
703 {
704 #ifdef USE_SCALE_RANDOMWRITE
705 scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
706 #else
707 scale3x_32_def_border(dst0, src0, src1, src2, count);
708 scale3x_32_def_center(dst1, src0, src1, src2, count);
709 scale3x_32_def_border(dst2, src2, src1, src0, count);
710 #endif
711 }
712
713