We have a 3.9 release, update builds.pm
[maemo-rb.git] / apps / plugins / lib / bmp_smooth_scale.c
blobe99ff33d71610edcfb60fc2c3488e57a305f73d5
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 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
26 ****************************************************************************/
29 * Copyright (C) 2004, 2005 Daniel M. Duley
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
50 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 /* OTHER CREDITS:
56 * This is the normal smoothscale method, based on Imlib2's smoothscale.
58 * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
59 * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
60 * C algorithm and it ran at about the same speed as my MMX optimized one...
61 * Finally I ported Imlib's MMX version and it ran in less than half the
62 * time as my MMX algorithm, (taking only a quarter of the time Qt does).
63 * After further optimization it seems to run at around 1/6th.
65 * Changes include formatting, namespaces and other C++'ings, removal of old
66 * #ifdef'ed code, and removal of unneeded border calculation code.
68 * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
69 * is by Willem Monsuwe <willem@stack.nl>. All other modifications are
70 * (C) Daniel M. Duley.
73 #include "pluginlib_bmp.h"
74 #include "lcd.h"
76 void smooth_resize_bitmap(struct bitmap *src_bmp, struct bitmap *dest_bmp)
78 fb_data *sptr, *dptr;
79 int x, y, end;
80 int val_y = 0, val_x;
81 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
82 const int sw = src_bmp->height;
83 const int sh = src_bmp->width;
84 const int dw = dest_bmp->height;
85 const int dh = dest_bmp->width;
86 #else
87 const int sw = src_bmp->width;
88 const int sh = src_bmp->height;
89 const int dw = dest_bmp->width;
90 const int dh = dest_bmp->height;
91 #endif
92 const int inc_x = (sw << 16) / dw;
93 const int inc_y = (sh << 16) / dh;
94 const int Cp_x = ((dw << 14) / sw) + 1;
95 const int Cp_y = ((dh << 14) / sh) + 1;
96 const int xup_yup = (dw >= sw) + ((dh >= sh) << 1);
97 const int dow = dw;
98 const int sow = sw;
99 fb_data *src = (fb_data*)src_bmp->data;
100 fb_data *dest = (fb_data*)dest_bmp->data;
101 int XAP, YAP, INV_YAP, INV_XAP;
102 int xpoint;
103 fb_data *ypoint;
105 end = dw;
106 /* scaling up both ways */
107 if (xup_yup == 3) {
108 /* go through every scanline in the output buffer */
109 for (y = 0; y < dh; y++) {
110 /* calculate the source line we'll scan from */
111 ypoint = src + ((val_y >> 16) * sw);
112 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
113 INV_YAP = 256 - YAP;
115 val_y += inc_y;
116 val_x = 0;
118 dptr = dest + (y * dow);
119 sptr = ypoint;
120 if (YAP > 0) {
121 for (x = 0; x < end; x++) {
122 int r = 0, g = 0, b = 0;
123 int rr = 0, gg = 0, bb = 0;
124 fb_data *pix;
126 xpoint = (val_x >> 16);
127 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
128 INV_XAP = 256 - XAP;
129 val_x += inc_x;
131 if (XAP > 0) {
132 pix = ypoint + xpoint;
133 r = RGB_UNPACK_RED(*pix) * INV_XAP;
134 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
135 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
136 pix++;
137 r += RGB_UNPACK_RED(*pix) * XAP;
138 g += RGB_UNPACK_GREEN(*pix) * XAP;
139 b += RGB_UNPACK_BLUE(*pix) * XAP;
140 pix += sow;
141 rr = RGB_UNPACK_RED(*pix) * XAP;
142 gg = RGB_UNPACK_GREEN(*pix) * XAP;
143 bb = RGB_UNPACK_BLUE(*pix) * XAP;
144 pix--;
145 rr += RGB_UNPACK_RED(*pix) * INV_XAP;
146 gg += RGB_UNPACK_GREEN(*pix) * INV_XAP;
147 bb += RGB_UNPACK_BLUE(*pix) * INV_XAP;
148 r = ((rr * YAP) + (r * INV_YAP)) >> 16;
149 g = ((gg * YAP) + (g * INV_YAP)) >> 16;
150 b = ((bb * YAP) + (b * INV_YAP)) >> 16;
151 *dptr++ = LCD_RGBPACK(r, g, b);
152 } else {
153 pix = ypoint + xpoint;
154 r = RGB_UNPACK_RED(*pix) * INV_YAP;
155 g = RGB_UNPACK_GREEN(*pix) * INV_YAP;
156 b = RGB_UNPACK_BLUE(*pix) * INV_YAP;
157 pix += sow;
158 r += RGB_UNPACK_RED(*pix) * YAP;
159 g += RGB_UNPACK_GREEN(*pix) * YAP;
160 b += RGB_UNPACK_BLUE(*pix) * YAP;
161 r >>= 8;
162 g >>= 8;
163 b >>= 8;
164 *dptr++ = LCD_RGBPACK(r, g, b);
167 } else {
168 for (x = 0; x < end; x++) {
169 int r = 0, g = 0, b = 0;
170 fb_data *pix;
172 xpoint = (val_x >> 16);
173 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
174 INV_XAP = 256 - XAP;
175 val_x += inc_x;
177 if (XAP > 0) {
178 pix = ypoint + xpoint;
179 r = RGB_UNPACK_RED(*pix) * INV_XAP;
180 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
181 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
182 pix++;
183 r += RGB_UNPACK_RED(*pix) * XAP;
184 g += RGB_UNPACK_GREEN(*pix) * XAP;
185 b += RGB_UNPACK_BLUE(*pix) * XAP;
186 r >>= 8;
187 g >>= 8;
188 b >>= 8;
189 *dptr++ = LCD_RGBPACK(r, g, b);
190 } else
191 *dptr++ = sptr[xpoint];
196 /* if we're scaling down vertically */
197 else if (xup_yup == 1) {
198 /*\ 'Correct' version, with math units prepared for MMXification \ */
199 int Cy, j;
200 fb_data *pix;
201 int r, g, b, rr, gg, bb;
202 int yap;
204 /* go through every scanline in the output buffer */
205 for (y = 0; y < dh; y++) {
206 ypoint = src + ((val_y >> 16) * sw);
207 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
208 INV_YAP = 256 - YAP;
209 val_y += inc_y;
210 val_x = 0;
212 Cy = YAP >> 16;
213 yap = YAP & 0xffff;
216 dptr = dest + (y * dow);
217 for (x = 0; x < end; x++) {
218 xpoint = (val_x >> 16);
219 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
220 INV_XAP = 256 - XAP;
221 val_x += inc_x;
223 pix = ypoint + xpoint;
224 r = (RGB_UNPACK_RED(*pix) * yap) >> 10;
225 g = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
226 b = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
227 pix += sow;
228 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
229 r += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
230 g += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
231 b += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
232 pix += sow;
234 if (j > 0) {
235 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
236 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
237 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
239 if (XAP > 0) {
240 pix = ypoint + xpoint + 1;
241 rr = (RGB_UNPACK_RED(*pix) * yap) >> 10;
242 gg = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
243 bb = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
244 pix += sow;
245 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
246 rr += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
247 gg += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
248 bb += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
249 pix += sow;
251 if (j > 0) {
252 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
253 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
254 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
256 r = r * INV_XAP;
257 g = g * INV_XAP;
258 b = b * INV_XAP;
259 r = (r + ((rr * XAP))) >> 12;
260 g = (g + ((gg * XAP))) >> 12;
261 b = (b + ((bb * XAP))) >> 12;
262 } else {
263 r >>= 4;
264 g >>= 4;
265 b >>= 4;
267 *dptr = LCD_RGBPACK(r, g, b);
268 dptr++;
272 /* if we're scaling down horizontally */
273 else if (xup_yup == 2) {
274 /*\ 'Correct' version, with math units prepared for MMXification \ */
275 int Cx, j;
276 fb_data *pix;
277 int r, g, b, rr, gg, bb;
278 int xap;
280 /* go through every scanline in the output buffer */
281 for (y = 0; y < dh; y++) {
282 ypoint = src + ((val_y >> 16) * sw);
283 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
284 INV_YAP = 256 - YAP;
285 val_y += inc_y;
286 val_x = 0;
288 dptr = dest + (y * dow);
289 for (x = 0; x < end; x++) {
290 xpoint = (val_x >> 16);
291 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
292 INV_XAP = 256 - XAP;
294 val_x += inc_x;
296 Cx = XAP >> 16;
297 xap = XAP & 0xffff;
299 pix = ypoint + xpoint;
300 r = (RGB_UNPACK_RED(*pix) * xap) >> 10;
301 g = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
302 b = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
303 pix++;
304 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
305 r += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
306 g += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
307 b += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
308 pix++;
310 if (j > 0) {
311 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
312 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
313 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
315 if (YAP > 0) {
316 pix = ypoint + xpoint + sow;
317 rr = (RGB_UNPACK_RED(*pix) * xap) >> 10;
318 gg = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
319 bb = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
320 pix++;
321 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
322 rr += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
323 gg += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
324 bb += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
325 pix++;
327 if (j > 0) {
328 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
329 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
330 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
332 r = r * INV_YAP;
333 g = g * INV_YAP;
334 b = b * INV_YAP;
335 r = (r + ((rr * YAP))) >> 12;
336 g = (g + ((gg * YAP))) >> 12;
337 b = (b + ((bb * YAP))) >> 12;
338 } else {
339 r >>= 4;
340 g >>= 4;
341 b >>= 4;
343 *dptr = LCD_RGBPACK(r, g, b);
344 dptr++;
348 /* fully optimized (i think) - only change of algorithm can help */
349 /* if we're scaling down horizontally & vertically */
350 else {
351 /*\ 'Correct' version, with math units prepared for MMXification \ */
352 int Cx, Cy, i, j;
353 fb_data *pix;
354 int r, g, b, rx, gx, bx;
355 int xap, yap;
357 for (y = 0; y < dh; y++) {
358 ypoint = src + ((val_y >> 16) * sw);
359 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
360 INV_YAP = 256 - YAP;
361 val_y += inc_y;
362 val_x = 0;
364 Cy = YAP >> 16;
365 yap = YAP & 0xffff;
367 dptr = dest + (y * dow);
368 for (x = 0; x < end; x++) {
369 xpoint = (val_x >> 16);
370 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
371 INV_XAP = 256 - XAP;
372 val_x += inc_x;
374 Cx = XAP >> 16;
375 xap = XAP & 0xffff;
377 sptr = ypoint + xpoint;
379 pix = sptr;
380 sptr += sow;
381 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
382 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
383 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
384 pix++;
385 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
386 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
387 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
388 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
389 pix++;
391 if (i > 0) {
392 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
393 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
394 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
397 r = (rx * yap) >> 14;
398 g = (gx * yap) >> 14;
399 b = (bx * yap) >> 14;
401 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
402 pix = sptr;
403 sptr += sow;
404 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
405 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
406 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
407 pix++;
408 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
409 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
410 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
411 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
412 pix++;
414 if (i > 0) {
415 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
416 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
417 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
420 r += (rx * Cy) >> 14;
421 g += (gx * Cy) >> 14;
422 b += (bx * Cy) >> 14;
424 if (j > 0) {
425 pix = sptr;
426 sptr += sow;
427 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
428 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
429 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
430 pix++;
431 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
432 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
433 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
434 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
435 pix++;
437 if (i > 0) {
438 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
439 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
440 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
443 r += (rx * j) >> 14;
444 g += (gx * j) >> 14;
445 b += (bx * j) >> 14;
448 *dptr = LCD_RGBPACK(r >> 5, g >> 5, b >> 5);
449 dptr++;