Philips GoGear SA9200 port. Working bootloader and normal builds, including sound...
[Rockbox.git] / apps / plugins / lib / bmp_smooth_scale.c
bloba500bfa792721735d3c3b26eb2c2562d089144d4
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Code for the scaling algorithm:
11 * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
12 * is by Willem Monsuwe <willem@stack.nl>. Additional modifications are by
13 * (C) Daniel M. Duley.
15 * Port to Rockbox
16 * Copyright (C) 2007 Jonas Hurrelmann (j@outpo.st)
18 * All files in this archive are subject to the GNU General Public License.
19 * See the file COPYING in the source tree root for full license agreement.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
27 * Copyright (C) 2004, 2005 Daniel M. Duley
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
39 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
40 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
42 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
43 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
48 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 /* OTHER CREDITS:
54 * This is the normal smoothscale method, based on Imlib2's smoothscale.
56 * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
57 * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
58 * C algorithm and it ran at about the same speed as my MMX optimized one...
59 * Finally I ported Imlib's MMX version and it ran in less than half the
60 * time as my MMX algorithm, (taking only a quarter of the time Qt does).
61 * After further optimization it seems to run at around 1/6th.
63 * Changes include formatting, namespaces and other C++'ings, removal of old
64 * #ifdef'ed code, and removal of unneeded border calculation code.
66 * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
67 * is by Willem Monsuwe <willem@stack.nl>. All other modifications are
68 * (C) Daniel M. Duley.
71 #include "bmp.h"
72 #include "lcd.h"
74 void smooth_resize_bitmap(struct bitmap *src_bmp, struct bitmap *dest_bmp)
76 fb_data *sptr, *dptr;
77 int x, y, end;
78 int val_y = 0, val_x;
79 const int sw = src_bmp->width;
80 const int sh = src_bmp->height;
81 const int dw = dest_bmp->width;
82 const int dh = dest_bmp->height;
83 const int inc_x = (sw << 16) / dw;
84 const int inc_y = (sh << 16) / dh;
85 const int Cp_x = ((dw << 14) / sw) + 1;
86 const int Cp_y = ((dh << 14) / sh) + 1;
87 const int xup_yup = (dw >= sw) + ((dh >= sh) << 1);
88 const int dow = dw;
89 const int sow = sw;
90 fb_data *src = (fb_data*)src_bmp->data;
91 fb_data *dest = (fb_data*)dest_bmp->data;
92 int XAP, YAP, INV_YAP, INV_XAP;
93 int xpoint;
94 fb_data *ypoint;
96 end = dw;
97 /* scaling up both ways */
98 if (xup_yup == 3) {
99 /* go through every scanline in the output buffer */
100 for (y = 0; y < dh; y++) {
101 /* calculate the source line we'll scan from */
102 ypoint = src + ((val_y >> 16) * sw);
103 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
104 INV_YAP = 256 - YAP;
106 val_y += inc_y;
107 val_x = 0;
109 dptr = dest + (y * dow);
110 sptr = ypoint;
111 if (YAP > 0) {
112 for (x = 0; x < end; x++) {
113 int r = 0, g = 0, b = 0;
114 int rr = 0, gg = 0, bb = 0;
115 fb_data *pix;
117 xpoint = (val_x >> 16);
118 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
119 INV_XAP = 256 - XAP;
120 val_x += inc_x;
122 if (XAP > 0) {
123 pix = ypoint + xpoint;
124 r = RGB_UNPACK_RED(*pix) * INV_XAP;
125 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
126 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
127 pix++;
128 r += RGB_UNPACK_RED(*pix) * XAP;
129 g += RGB_UNPACK_GREEN(*pix) * XAP;
130 b += RGB_UNPACK_BLUE(*pix) * XAP;
131 pix += sow;
132 rr = RGB_UNPACK_RED(*pix) * XAP;
133 gg = RGB_UNPACK_GREEN(*pix) * XAP;
134 bb = RGB_UNPACK_BLUE(*pix) * XAP;
135 pix--;
136 rr += RGB_UNPACK_RED(*pix) * INV_XAP;
137 gg += RGB_UNPACK_GREEN(*pix) * INV_XAP;
138 bb += RGB_UNPACK_BLUE(*pix) * INV_XAP;
139 r = ((rr * YAP) + (r * INV_YAP)) >> 16;
140 g = ((gg * YAP) + (g * INV_YAP)) >> 16;
141 b = ((bb * YAP) + (b * INV_YAP)) >> 16;
142 *dptr++ = LCD_RGBPACK(r, g, b);
143 } else {
144 pix = ypoint + xpoint;
145 r = RGB_UNPACK_RED(*pix) * INV_YAP;
146 g = RGB_UNPACK_GREEN(*pix) * INV_YAP;
147 b = RGB_UNPACK_BLUE(*pix) * INV_YAP;
148 pix += sow;
149 r += RGB_UNPACK_RED(*pix) * YAP;
150 g += RGB_UNPACK_GREEN(*pix) * YAP;
151 b += RGB_UNPACK_BLUE(*pix) * YAP;
152 r >>= 8;
153 g >>= 8;
154 b >>= 8;
155 *dptr++ = LCD_RGBPACK(r, g, b);
158 } else {
159 for (x = 0; x < end; x++) {
160 int r = 0, g = 0, b = 0;
161 fb_data *pix;
163 xpoint = (val_x >> 16);
164 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
165 INV_XAP = 256 - XAP;
166 val_x += inc_x;
168 if (XAP > 0) {
169 pix = ypoint + xpoint;
170 r = RGB_UNPACK_RED(*pix) * INV_XAP;
171 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
172 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
173 pix++;
174 r += RGB_UNPACK_RED(*pix) * XAP;
175 g += RGB_UNPACK_GREEN(*pix) * XAP;
176 b += RGB_UNPACK_BLUE(*pix) * XAP;
177 r >>= 8;
178 g >>= 8;
179 b >>= 8;
180 *dptr++ = LCD_RGBPACK(r, g, b);
181 } else
182 *dptr++ = sptr[xpoint];
187 /* if we're scaling down vertically */
188 else if (xup_yup == 1) {
189 /*\ 'Correct' version, with math units prepared for MMXification \ */
190 int Cy, j;
191 fb_data *pix;
192 int r, g, b, rr, gg, bb;
193 int yap;
195 /* go through every scanline in the output buffer */
196 for (y = 0; y < dh; y++) {
197 ypoint = src + ((val_y >> 16) * sw);
198 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
199 INV_YAP = 256 - YAP;
200 val_y += inc_y;
201 val_x = 0;
203 Cy = YAP >> 16;
204 yap = YAP & 0xffff;
207 dptr = dest + (y * dow);
208 for (x = 0; x < end; x++) {
209 xpoint = (val_x >> 16);
210 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
211 INV_XAP = 256 - XAP;
212 val_x += inc_x;
214 pix = ypoint + xpoint;
215 r = (RGB_UNPACK_RED(*pix) * yap) >> 10;
216 g = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
217 b = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
218 pix += sow;
219 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
220 r += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
221 g += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
222 b += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
223 pix += sow;
225 if (j > 0) {
226 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
227 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
228 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
230 if (XAP > 0) {
231 pix = ypoint + xpoint + 1;
232 rr = (RGB_UNPACK_RED(*pix) * yap) >> 10;
233 gg = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
234 bb = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
235 pix += sow;
236 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
237 rr += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
238 gg += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
239 bb += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
240 pix += sow;
242 if (j > 0) {
243 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
244 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
245 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
247 r = r * INV_XAP;
248 g = g * INV_XAP;
249 b = b * INV_XAP;
250 r = (r + ((rr * XAP))) >> 12;
251 g = (g + ((gg * XAP))) >> 12;
252 b = (b + ((bb * XAP))) >> 12;
253 } else {
254 r >>= 4;
255 g >>= 4;
256 b >>= 4;
258 *dptr = LCD_RGBPACK(r, g, b);
259 dptr++;
263 /* if we're scaling down horizontally */
264 else if (xup_yup == 2) {
265 /*\ 'Correct' version, with math units prepared for MMXification \ */
266 int Cx, j;
267 fb_data *pix;
268 int r, g, b, rr, gg, bb;
269 int xap;
271 /* go through every scanline in the output buffer */
272 for (y = 0; y < dh; y++) {
273 ypoint = src + ((val_y >> 16) * sw);
274 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
275 INV_YAP = 256 - YAP;
276 val_y += inc_y;
277 val_x = 0;
279 dptr = dest + (y * dow);
280 for (x = 0; x < end; x++) {
281 xpoint = (val_x >> 16);
282 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
283 INV_XAP = 256 - XAP;
285 val_x += inc_x;
287 Cx = XAP >> 16;
288 xap = XAP & 0xffff;
290 pix = ypoint + xpoint;
291 r = (RGB_UNPACK_RED(*pix) * xap) >> 10;
292 g = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
293 b = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
294 pix++;
295 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
296 r += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
297 g += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
298 b += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
299 pix++;
301 if (j > 0) {
302 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
303 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
304 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
306 if (YAP > 0) {
307 pix = ypoint + xpoint + sow;
308 rr = (RGB_UNPACK_RED(*pix) * xap) >> 10;
309 gg = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
310 bb = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
311 pix++;
312 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
313 rr += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
314 gg += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
315 bb += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
316 pix++;
318 if (j > 0) {
319 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
320 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
321 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
323 r = r * INV_YAP;
324 g = g * INV_YAP;
325 b = b * INV_YAP;
326 r = (r + ((rr * YAP))) >> 12;
327 g = (g + ((gg * YAP))) >> 12;
328 b = (b + ((bb * YAP))) >> 12;
329 } else {
330 r >>= 4;
331 g >>= 4;
332 b >>= 4;
334 *dptr = LCD_RGBPACK(r, g, b);
335 dptr++;
339 /* fully optimized (i think) - only change of algorithm can help */
340 /* if we're scaling down horizontally & vertically */
341 else {
342 /*\ 'Correct' version, with math units prepared for MMXification \ */
343 int Cx, Cy, i, j;
344 fb_data *pix;
345 int r, g, b, rx, gx, bx;
346 int xap, yap;
348 for (y = 0; y < dh; y++) {
349 ypoint = src + ((val_y >> 16) * sw);
350 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
351 INV_YAP = 256 - YAP;
352 val_y += inc_y;
353 val_x = 0;
355 Cy = YAP >> 16;
356 yap = YAP & 0xffff;
358 dptr = dest + (y * dow);
359 for (x = 0; x < end; x++) {
360 xpoint = (val_x >> 16);
361 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
362 INV_XAP = 256 - XAP;
363 val_x += inc_x;
365 Cx = XAP >> 16;
366 xap = XAP & 0xffff;
368 sptr = ypoint + xpoint;
370 pix = sptr;
371 sptr += sow;
372 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
373 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
374 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
375 pix++;
376 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
377 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
378 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
379 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
380 pix++;
382 if (i > 0) {
383 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
384 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
385 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
388 r = (rx * yap) >> 14;
389 g = (gx * yap) >> 14;
390 b = (bx * yap) >> 14;
392 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
393 pix = sptr;
394 sptr += sow;
395 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
396 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
397 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
398 pix++;
399 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
400 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
401 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
402 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
403 pix++;
405 if (i > 0) {
406 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
407 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
408 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
411 r += (rx * Cy) >> 14;
412 g += (gx * Cy) >> 14;
413 b += (bx * Cy) >> 14;
415 if (j > 0) {
416 pix = sptr;
417 sptr += sow;
418 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
419 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
420 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
421 pix++;
422 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
423 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
424 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
425 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
426 pix++;
428 if (i > 0) {
429 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
430 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
431 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
434 r += (rx * j) >> 14;
435 g += (gx * j) >> 14;
436 b += (bx * j) >> 14;
439 *dptr = LCD_RGBPACK(r >> 5, g >> 5, b >> 5);
440 dptr++;