fix red.
[kugel-rb.git] / apps / plugins / lib / bmp_smooth_scale.c
blob4d5eab00a0a61857af3a6a094a9e4d9e7be1fa94
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 const int sw = src_bmp->width;
82 const int sh = src_bmp->height;
83 const int dw = dest_bmp->width;
84 const int dh = dest_bmp->height;
85 const int inc_x = (sw << 16) / dw;
86 const int inc_y = (sh << 16) / dh;
87 const int Cp_x = ((dw << 14) / sw) + 1;
88 const int Cp_y = ((dh << 14) / sh) + 1;
89 const int xup_yup = (dw >= sw) + ((dh >= sh) << 1);
90 const int dow = dw;
91 const int sow = sw;
92 fb_data *src = (fb_data*)src_bmp->data;
93 fb_data *dest = (fb_data*)dest_bmp->data;
94 int XAP, YAP, INV_YAP, INV_XAP;
95 int xpoint;
96 fb_data *ypoint;
98 end = dw;
99 /* scaling up both ways */
100 if (xup_yup == 3) {
101 /* go through every scanline in the output buffer */
102 for (y = 0; y < dh; y++) {
103 /* calculate the source line we'll scan from */
104 ypoint = src + ((val_y >> 16) * sw);
105 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
106 INV_YAP = 256 - YAP;
108 val_y += inc_y;
109 val_x = 0;
111 dptr = dest + (y * dow);
112 sptr = ypoint;
113 if (YAP > 0) {
114 for (x = 0; x < end; x++) {
115 int r = 0, g = 0, b = 0;
116 int rr = 0, gg = 0, bb = 0;
117 fb_data *pix;
119 xpoint = (val_x >> 16);
120 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
121 INV_XAP = 256 - XAP;
122 val_x += inc_x;
124 if (XAP > 0) {
125 pix = ypoint + xpoint;
126 r = RGB_UNPACK_RED(*pix) * INV_XAP;
127 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
128 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
129 pix++;
130 r += RGB_UNPACK_RED(*pix) * XAP;
131 g += RGB_UNPACK_GREEN(*pix) * XAP;
132 b += RGB_UNPACK_BLUE(*pix) * XAP;
133 pix += sow;
134 rr = RGB_UNPACK_RED(*pix) * XAP;
135 gg = RGB_UNPACK_GREEN(*pix) * XAP;
136 bb = RGB_UNPACK_BLUE(*pix) * XAP;
137 pix--;
138 rr += RGB_UNPACK_RED(*pix) * INV_XAP;
139 gg += RGB_UNPACK_GREEN(*pix) * INV_XAP;
140 bb += RGB_UNPACK_BLUE(*pix) * INV_XAP;
141 r = ((rr * YAP) + (r * INV_YAP)) >> 16;
142 g = ((gg * YAP) + (g * INV_YAP)) >> 16;
143 b = ((bb * YAP) + (b * INV_YAP)) >> 16;
144 *dptr++ = LCD_RGBPACK(r, g, b);
145 } else {
146 pix = ypoint + xpoint;
147 r = RGB_UNPACK_RED(*pix) * INV_YAP;
148 g = RGB_UNPACK_GREEN(*pix) * INV_YAP;
149 b = RGB_UNPACK_BLUE(*pix) * INV_YAP;
150 pix += sow;
151 r += RGB_UNPACK_RED(*pix) * YAP;
152 g += RGB_UNPACK_GREEN(*pix) * YAP;
153 b += RGB_UNPACK_BLUE(*pix) * YAP;
154 r >>= 8;
155 g >>= 8;
156 b >>= 8;
157 *dptr++ = LCD_RGBPACK(r, g, b);
160 } else {
161 for (x = 0; x < end; x++) {
162 int r = 0, g = 0, b = 0;
163 fb_data *pix;
165 xpoint = (val_x >> 16);
166 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
167 INV_XAP = 256 - XAP;
168 val_x += inc_x;
170 if (XAP > 0) {
171 pix = ypoint + xpoint;
172 r = RGB_UNPACK_RED(*pix) * INV_XAP;
173 g = RGB_UNPACK_GREEN(*pix) * INV_XAP;
174 b = RGB_UNPACK_BLUE(*pix) * INV_XAP;
175 pix++;
176 r += RGB_UNPACK_RED(*pix) * XAP;
177 g += RGB_UNPACK_GREEN(*pix) * XAP;
178 b += RGB_UNPACK_BLUE(*pix) * XAP;
179 r >>= 8;
180 g >>= 8;
181 b >>= 8;
182 *dptr++ = LCD_RGBPACK(r, g, b);
183 } else
184 *dptr++ = sptr[xpoint];
189 /* if we're scaling down vertically */
190 else if (xup_yup == 1) {
191 /*\ 'Correct' version, with math units prepared for MMXification \ */
192 int Cy, j;
193 fb_data *pix;
194 int r, g, b, rr, gg, bb;
195 int yap;
197 /* go through every scanline in the output buffer */
198 for (y = 0; y < dh; y++) {
199 ypoint = src + ((val_y >> 16) * sw);
200 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
201 INV_YAP = 256 - YAP;
202 val_y += inc_y;
203 val_x = 0;
205 Cy = YAP >> 16;
206 yap = YAP & 0xffff;
209 dptr = dest + (y * dow);
210 for (x = 0; x < end; x++) {
211 xpoint = (val_x >> 16);
212 XAP = ((val_x >> 16) >= (sw - 1)) ? 0 : (val_x >> 8) - ((val_x >> 8) & 0xffffff00);
213 INV_XAP = 256 - XAP;
214 val_x += inc_x;
216 pix = ypoint + xpoint;
217 r = (RGB_UNPACK_RED(*pix) * yap) >> 10;
218 g = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
219 b = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
220 pix += sow;
221 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
222 r += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
223 g += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
224 b += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
225 pix += sow;
227 if (j > 0) {
228 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
229 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
230 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
232 if (XAP > 0) {
233 pix = ypoint + xpoint + 1;
234 rr = (RGB_UNPACK_RED(*pix) * yap) >> 10;
235 gg = (RGB_UNPACK_GREEN(*pix) * yap) >> 10;
236 bb = (RGB_UNPACK_BLUE(*pix) * yap) >> 10;
237 pix += sow;
238 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
239 rr += (RGB_UNPACK_RED(*pix) * Cy) >> 10;
240 gg += (RGB_UNPACK_GREEN(*pix) * Cy) >> 10;
241 bb += (RGB_UNPACK_BLUE(*pix) * Cy) >> 10;
242 pix += sow;
244 if (j > 0) {
245 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
246 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
247 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
249 r = r * INV_XAP;
250 g = g * INV_XAP;
251 b = b * INV_XAP;
252 r = (r + ((rr * XAP))) >> 12;
253 g = (g + ((gg * XAP))) >> 12;
254 b = (b + ((bb * XAP))) >> 12;
255 } else {
256 r >>= 4;
257 g >>= 4;
258 b >>= 4;
260 *dptr = LCD_RGBPACK(r, g, b);
261 dptr++;
265 /* if we're scaling down horizontally */
266 else if (xup_yup == 2) {
267 /*\ 'Correct' version, with math units prepared for MMXification \ */
268 int Cx, j;
269 fb_data *pix;
270 int r, g, b, rr, gg, bb;
271 int xap;
273 /* go through every scanline in the output buffer */
274 for (y = 0; y < dh; y++) {
275 ypoint = src + ((val_y >> 16) * sw);
276 YAP = ((val_y >> 16) >= (sh - 1)) ? 0 : (val_y >> 8) - ((val_y >> 8) & 0xffffff00);
277 INV_YAP = 256 - YAP;
278 val_y += inc_y;
279 val_x = 0;
281 dptr = dest + (y * dow);
282 for (x = 0; x < end; x++) {
283 xpoint = (val_x >> 16);
284 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
285 INV_XAP = 256 - XAP;
287 val_x += inc_x;
289 Cx = XAP >> 16;
290 xap = XAP & 0xffff;
292 pix = ypoint + xpoint;
293 r = (RGB_UNPACK_RED(*pix) * xap) >> 10;
294 g = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
295 b = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
296 pix++;
297 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
298 r += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
299 g += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
300 b += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
301 pix++;
303 if (j > 0) {
304 r += (RGB_UNPACK_RED(*pix) * j) >> 10;
305 g += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
306 b += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
308 if (YAP > 0) {
309 pix = ypoint + xpoint + sow;
310 rr = (RGB_UNPACK_RED(*pix) * xap) >> 10;
311 gg = (RGB_UNPACK_GREEN(*pix) * xap) >> 10;
312 bb = (RGB_UNPACK_BLUE(*pix) * xap) >> 10;
313 pix++;
314 for (j = (1 << 14) - xap; j > Cx; j -= Cx) {
315 rr += (RGB_UNPACK_RED(*pix) * Cx) >> 10;
316 gg += (RGB_UNPACK_GREEN(*pix) * Cx) >> 10;
317 bb += (RGB_UNPACK_BLUE(*pix) * Cx) >> 10;
318 pix++;
320 if (j > 0) {
321 rr += (RGB_UNPACK_RED(*pix) * j) >> 10;
322 gg += (RGB_UNPACK_GREEN(*pix) * j) >> 10;
323 bb += (RGB_UNPACK_BLUE(*pix) * j) >> 10;
325 r = r * INV_YAP;
326 g = g * INV_YAP;
327 b = b * INV_YAP;
328 r = (r + ((rr * YAP))) >> 12;
329 g = (g + ((gg * YAP))) >> 12;
330 b = (b + ((bb * YAP))) >> 12;
331 } else {
332 r >>= 4;
333 g >>= 4;
334 b >>= 4;
336 *dptr = LCD_RGBPACK(r, g, b);
337 dptr++;
341 /* fully optimized (i think) - only change of algorithm can help */
342 /* if we're scaling down horizontally & vertically */
343 else {
344 /*\ 'Correct' version, with math units prepared for MMXification \ */
345 int Cx, Cy, i, j;
346 fb_data *pix;
347 int r, g, b, rx, gx, bx;
348 int xap, yap;
350 for (y = 0; y < dh; y++) {
351 ypoint = src + ((val_y >> 16) * sw);
352 YAP = (((0x100 - ((val_y >> 8) & 0xff)) * Cp_y) >> 8) | (Cp_y << 16);
353 INV_YAP = 256 - YAP;
354 val_y += inc_y;
355 val_x = 0;
357 Cy = YAP >> 16;
358 yap = YAP & 0xffff;
360 dptr = dest + (y * dow);
361 for (x = 0; x < end; x++) {
362 xpoint = (val_x >> 16);
363 XAP = (((0x100 - ((val_x >> 8) & 0xff)) * Cp_x) >> 8) | (Cp_x << 16);
364 INV_XAP = 256 - XAP;
365 val_x += inc_x;
367 Cx = XAP >> 16;
368 xap = XAP & 0xffff;
370 sptr = ypoint + xpoint;
372 pix = sptr;
373 sptr += sow;
374 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
375 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
376 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
377 pix++;
378 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
379 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
380 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
381 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
382 pix++;
384 if (i > 0) {
385 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
386 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
387 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
390 r = (rx * yap) >> 14;
391 g = (gx * yap) >> 14;
392 b = (bx * yap) >> 14;
394 for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
395 pix = sptr;
396 sptr += sow;
397 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
398 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
399 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
400 pix++;
401 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
402 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
403 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
404 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
405 pix++;
407 if (i > 0) {
408 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
409 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
410 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
413 r += (rx * Cy) >> 14;
414 g += (gx * Cy) >> 14;
415 b += (bx * Cy) >> 14;
417 if (j > 0) {
418 pix = sptr;
419 sptr += sow;
420 rx = (RGB_UNPACK_RED(*pix) * xap) >> 9;
421 gx = (RGB_UNPACK_GREEN(*pix) * xap) >> 9;
422 bx = (RGB_UNPACK_BLUE(*pix) * xap) >> 9;
423 pix++;
424 for (i = (1 << 14) - xap; i > Cx; i -= Cx) {
425 rx += (RGB_UNPACK_RED(*pix) * Cx) >> 9;
426 gx += (RGB_UNPACK_GREEN(*pix) * Cx) >> 9;
427 bx += (RGB_UNPACK_BLUE(*pix) * Cx) >> 9;
428 pix++;
430 if (i > 0) {
431 rx += (RGB_UNPACK_RED(*pix) * i) >> 9;
432 gx += (RGB_UNPACK_GREEN(*pix) * i) >> 9;
433 bx += (RGB_UNPACK_BLUE(*pix) * i) >> 9;
436 r += (rx * j) >> 14;
437 g += (gx * j) >> 14;
438 b += (bx * j) >> 14;
441 *dptr = LCD_RGBPACK(r >> 5, g >> 5, b >> 5);
442 dptr++;