summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2008-12-26 07:03:22 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2008-12-26 07:03:22 +0000
commitf7fa7e5ad537415f1f75b3a9c1a58eb925e10d04 (patch)
treeea469e428a756e4f4979be1b6f5a84179a2cc80f
parent7428c7cc5b8462ed95683f707fe78609ce8208bf (diff)
downloadrockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.tar.gz
rockbox-f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04.zip
Latest work on the bmp on-load scaler:
Macros for calculating size needed for bitmap load and scaling, so that these can be compile-time constant when their inputs are. Reduce size of bayer dither by chopping all but first row of dither matrix, and replacing 2D lookup with 1D lookup and small calculation. Move some functions not related to actual bmp file loading out of bmp.c. A smaller brightness() for mono targets, and a higher-quality one for greyscale targets, both replacing the division by 10 with a shift. Port of the linear and area scalers to greyscale targets, this costs some binsize but produces better output even when dithered to 2bpp. Move duplicated row output code from inside vertical scalers to a separate row output function. Move some multiplies out of the line scaler, for a small speedup and code size reduction, as well as a small improvement in accuracy for the upscaling case. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19592 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.h1
-rw-r--r--apps/plugins/sliding_puzzle.c32
-rw-r--r--apps/recorder/bmp.c323
-rw-r--r--apps/recorder/bmp.h221
-rw-r--r--apps/recorder/resize.c920
-rw-r--r--apps/recorder/resize.h25
-rw-r--r--firmware/export/lcd-remote.h4
-rw-r--r--firmware/export/lcd.h4
8 files changed, 736 insertions, 794 deletions
diff --git a/apps/plugin.h b/apps/plugin.h
index e16d9ebaec..20e3a71595 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -78,6 +78,7 @@ void* plugin_get_buffer(size_t *buffer_size);
78#include "playlist.h" 78#include "playlist.h"
79#ifdef HAVE_LCD_BITMAP 79#ifdef HAVE_LCD_BITMAP
80#include "scrollbar.h" 80#include "scrollbar.h"
81#include "../recorder/bmp.h"
81#endif 82#endif
82#include "statusbar.h" 83#include "statusbar.h"
83#include "menu.h" 84#include "menu.h"
diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c
index 85f4d32f68..fa9e093c3c 100644
--- a/apps/plugins/sliding_puzzle.c
+++ b/apps/plugins/sliding_puzzle.c
@@ -19,7 +19,6 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "plugin.h" 21#include "plugin.h"
22#include "lib/bmp.h"
23 22
24#ifdef HAVE_LCD_BITMAP 23#ifdef HAVE_LCD_BITMAP
25PLUGIN_HEADER 24PLUGIN_HEADER
@@ -258,13 +257,9 @@ static int num_font = FONT_UI;
258static int moves_font = FONT_UI; 257static int moves_font = FONT_UI;
259static int moves_y = 0; 258static int moves_y = 0;
260 259
261#ifdef HAVE_LCD_COLOR 260static unsigned char img_buf
262static unsigned char *img_buf; 261 [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)]
263static size_t buf_len; 262 __attribute__ ((aligned(16)));
264#else
265static unsigned char img_buf[IMAGE_WIDTH*IMAGE_HEIGHT*sizeof(fb_data)]
266__attribute__ ((aligned(16)));
267#endif
268#ifdef HAVE_ALBUMART 263#ifdef HAVE_ALBUMART
269static char albumart_path[MAX_PATH+1]; 264static char albumart_path[MAX_PATH+1];
270#endif 265#endif
@@ -343,13 +338,9 @@ static bool load_resize_bitmap(void)
343 main_bitmap.width = IMAGE_WIDTH; 338 main_bitmap.width = IMAGE_WIDTH;
344 main_bitmap.height = IMAGE_HEIGHT; 339 main_bitmap.height = IMAGE_HEIGHT;
345 340
346#ifndef HAVE_LCD_COLOR
347 size_t buf_len = sizeof(img_buf);
348#endif
349
350 rc = rb->read_bmp_file( filename, &main_bitmap, 341 rc = rb->read_bmp_file( filename, &main_bitmap,
351 buf_len, 342 sizeof(img_buf),
352 FORMAT_NATIVE|FORMAT_RESIZE ); 343 FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_DITHER);
353 if( rc > 0 ) 344 if( rc > 0 )
354 { 345 {
355 puzzle_bmp_ptr = (const fb_data *)img_buf; 346 puzzle_bmp_ptr = (const fb_data *)img_buf;
@@ -574,7 +565,8 @@ static int puzzle_loop(void)
574 /* change picture */ 565 /* change picture */
575 picmode = (picmode+1)%PICMODE_LAST_XXX; 566 picmode = (picmode+1)%PICMODE_LAST_XXX;
576 567
577 /* if load_resize_bitmap fails to load bitmap, try next picmode */ 568 /* if load_resize_bitmap fails to load bitmap, try next picmode
569 */
578 do 570 do
579 { 571 {
580 load_success = load_resize_bitmap(); 572 load_success = load_resize_bitmap();
@@ -618,7 +610,8 @@ static int puzzle_loop(void)
618 } 610 }
619} 611}
620 612
621enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) 613enum plugin_status plugin_start(const struct plugin_api* api,
614 const void* parameter)
622{ 615{
623 int i, w, h; 616 int i, w, h;
624 617
@@ -627,13 +620,6 @@ enum plugin_status plugin_start(const struct plugin_api* api, const void* parame
627 initial_bmp_path=(const char *)parameter; 620 initial_bmp_path=(const char *)parameter;
628 picmode = PICMODE_INITIAL_PICTURE; 621 picmode = PICMODE_INITIAL_PICTURE;
629 img_buf_path[0] = '\0'; 622 img_buf_path[0] = '\0';
630#ifdef HAVE_LCD_COLOR
631 unsigned char *img_buf_end;
632 img_buf = (unsigned char *)(rb->plugin_get_buffer(&buf_len));
633 img_buf_end = img_buf + buf_len;
634 rb->align_buffer(PUN_PTR(void **,&img_buf), buf_len, 16);
635 buf_len = img_buf_end - img_buf;
636#endif
637 623
638 /* If launched as a viewer, just go straight to the game without 624 /* If launched as a viewer, just go straight to the game without
639 bothering with the splash or instructions page */ 625 bothering with the splash or instructions page */
diff --git a/apps/recorder/bmp.c b/apps/recorder/bmp.c
index cdff8ccb07..cc574649d8 100644
--- a/apps/recorder/bmp.c
+++ b/apps/recorder/bmp.c
@@ -124,25 +124,10 @@ static const struct uint8_rgb bitfields[3][3] = {
124}; 124};
125 125
126#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 126#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
127/* canonical ordered dither matrix */ 127/* the full 16x16 Bayer dither matrix may be calculated quickly with this table
128const unsigned char dither_matrix[16][16] = { 128*/
129 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, 129const unsigned char dither_table[16] =
130 { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, 130 { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 };
131 { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
132 { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
133 { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
134 { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
135 { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
136 { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
137 { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
138 { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
139 { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
140 { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
141 { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
142 { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
143 { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
144 { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
145};
146#endif 131#endif
147 132
148#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ 133#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
@@ -194,7 +179,7 @@ struct bmp_args {
194 short read_width; 179 short read_width;
195 short width; 180 short width;
196 short depth; 181 short depth;
197 unsigned char buf[MAX_WIDTH * 4]; 182 unsigned char buf[BM_MAX_WIDTH * 4];
198 struct uint8_rgb *palette; 183 struct uint8_rgb *palette;
199#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) 184#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
200 int cur_row; 185 int cur_row;
@@ -222,13 +207,14 @@ static unsigned int read_part_line(struct bmp_args *ba)
222 int i, cols, len; 207 int i, cols, len;
223 208
224#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 209#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
225 cols = MIN(width - cur_col,(int)MAX_WIDTH); 210 cols = MIN(width - cur_col,(int)BM_MAX_WIDTH);
211 BDEBUGF("reading %d cols (width: %d, max: %d)\n",cols,width,BM_MAX_WIDTH);
226 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3; 212 len = (cols * (depth == 15 ? 16 : depth) + 7) >> 3;
227#else 213#else
228 cols = width; 214 cols = width;
229 len = read_width; 215 len = read_width;
230#endif 216#endif
231 ibuf = ((unsigned char *)buf) + (MAX_WIDTH << 2) - len; 217 ibuf = ((unsigned char *)buf) + (BM_MAX_WIDTH << 2) - len;
232 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len); 218 BDEBUGF("read_part_line: cols=%d len=%d\n",cols,len);
233 ret = read(fd, ibuf, len); 219 ret = read(fd, ibuf, len);
234 if (ret != len) 220 if (ret != len)
@@ -239,25 +225,25 @@ static unsigned int read_part_line(struct bmp_args *ba)
239 cols, len); 225 cols, len);
240 return 0; 226 return 0;
241 } 227 }
242 for (i = 0; i < cols; i++) 228 while (ibuf < ba->buf + (BM_MAX_WIDTH << 2))
243 { 229 {
244 switch (depth) 230 switch (depth)
245 { 231 {
246 case 1: 232 case 1:
247 if ((i & 7) == 0) 233 data = *ibuf++;
248 data = *ibuf++; 234 for (i = 0; i < 8; i++)
249 *buf = palette[(data >> 7) & 1]; 235 {
250 data <<= 1; 236 *buf++ = palette[data & 0x80 ? 1 : 0];
237 data <<= 1;
238 }
251 break; 239 break;
252 case 4: 240 case 4:
253 *buf = palette[*ibuf >> 4]; 241 data = *ibuf++;
254 if (i & 1) 242 *buf++ = palette[data >> 4];
255 ibuf++; 243 *buf++ = palette[data & 0xf];
256 else
257 *ibuf <<= 4;
258 break; 244 break;
259 case 8: 245 case 8:
260 *buf = palette[*ibuf++]; 246 *buf++ = palette[*ibuf++];
261 break; 247 break;
262 case 15: 248 case 15:
263 case 16: 249 case 16:
@@ -280,6 +266,7 @@ static unsigned int read_part_line(struct bmp_args *ba)
280 component = data & 0xf8; 266 component = data & 0xf8;
281 component |= component >> 5; 267 component |= component >> 5;
282 buf->red = component; 268 buf->red = component;
269 buf++;
283 ibuf += 2; 270 ibuf += 2;
284 break; 271 break;
285 case 32: 272 case 32:
@@ -289,11 +276,19 @@ static unsigned int read_part_line(struct bmp_args *ba)
289 buf->red = *ibuf++; 276 buf->red = *ibuf++;
290 if (depth == 32) 277 if (depth == 32)
291 ibuf++; 278 ibuf++;
279 buf++;
292 break; 280 break;
293 } 281 }
294 buf++;
295 } 282 }
296 283
284#if !defined(HAVE_LCD_COLOR) && \
285 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
286 ibuf = ba->buf;
287 buf = (struct uint8_rgb*)ba->buf;
288 while (ibuf < ba->buf + cols)
289 *ibuf++ = brightness(*buf++);
290#endif
291
297#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) 292#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
298 cur_col += cols; 293 cur_col += cols;
299 if (cur_col == width) 294 if (cur_col == width)
@@ -323,58 +318,16 @@ static struct img_part *store_part_bmp(void *args)
323 struct bmp_args *ba = (struct bmp_args *)args; 318 struct bmp_args *ba = (struct bmp_args *)args;
324 319
325 ba->part.len = read_part_line(ba); 320 ba->part.len = read_part_line(ba);
321#ifdef HAVE_LCD_COLOR
326 ba->part.buf = (struct uint8_rgb *)ba->buf; 322 ba->part.buf = (struct uint8_rgb *)ba->buf;
323#else
324 ba->part.buf = (uint8_t *)ba->buf;
325#endif
327 if (ba->part.len) 326 if (ba->part.len)
328 return &(ba->part); 327 return &(ba->part);
329 else 328 else
330 return NULL; 329 return NULL;
331} 330}
332
333static bool skip_lines_bmp(void *args, unsigned int lines)
334{
335 struct bmp_args * ba = (struct bmp_args *)args;
336
337 int pad = lines * ba->padded_width +
338 (ba->cur_col
339 ? ((ba->cur_col * ba->depth + 7) >> 3) - ba->padded_width
340 : 0);
341 if (pad)
342 {
343 if(lseek(ba->fd, pad, SEEK_CUR) < 0)
344
345 return false;
346 }
347 ba->cur_row += lines + (ba->cur_col ? 1 : 0);
348 ba->cur_col = 0;
349 return true;
350}
351#endif
352
353#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
354static inline int recalc_dimension(struct dim *dst, struct dim *src)
355{
356 int tmp;
357 if (dst->width <= 0)
358 dst->width = LCD_WIDTH;
359 if (dst->height <= 0)
360 dst->height = LCD_HEIGHT;
361#ifndef HAVE_UPSCALER
362 if (dst->width > src->width || dst->height > src->height)
363 {
364 dst->width = src->width;
365 dst->height = src->height;
366 }
367 if (src->width == dst->width && src->height == dst->height)
368 return 1;
369#endif
370 tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
371 if (tmp > dst->width)
372 dst->height = (src->height * dst->width + (src->width >> 1))
373 / src->width;
374 else
375 dst->width = tmp;
376 return src->width == dst->width && src->height == dst->height;
377}
378#endif 331#endif
379 332
380static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) 333static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2)
@@ -406,37 +359,32 @@ int read_bmp_fd(int fd,
406 359
407 unsigned char *bitmap = bm->data; 360 unsigned char *bitmap = bm->data;
408 struct uint8_rgb palette[256]; 361 struct uint8_rgb palette[256];
409 bool remote = false;
410 struct rowset rset; 362 struct rowset rset;
411 struct dim src_dim; 363 struct dim src_dim;
412#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 364#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
365 bool remote = false;
413 unsigned int resize = IMG_NORESIZE; 366 unsigned int resize = IMG_NORESIZE;
414 bool dither = false; 367 bool dither = false;
415 bool transparent = false; 368 bool transparent = false;
416 369
417#ifdef HAVE_REMOTE_LCD 370#ifdef HAVE_REMOTE_LCD
418 if (format & FORMAT_REMOTE) { 371 if (format & FORMAT_REMOTE) {
419 remote = true; 372 remote = true;
420#if LCD_REMOTE_DEPTH == 1 373#if LCD_REMOTE_DEPTH == 1
421 format = FORMAT_MONO; 374 format = FORMAT_MONO;
422#else
423 format &= ~FORMAT_REMOTE;
424#endif 375#endif
425 } 376 }
426#endif /* HAVE_REMOTE_LCD */ 377#endif /* HAVE_REMOTE_LCD */
427 378
428 if (format & FORMAT_RESIZE) { 379 if (format & FORMAT_RESIZE) {
429 resize = IMG_RESIZE; 380 resize = IMG_RESIZE;
430 format &= ~FORMAT_RESIZE;
431 } 381 }
432 382
433 if (format & FORMAT_TRANSPARENT) { 383 if (format & FORMAT_TRANSPARENT) {
434 transparent = true; 384 transparent = true;
435 format &= ~FORMAT_TRANSPARENT;
436 } 385 }
437 if (format & FORMAT_DITHER) { 386 if (format & FORMAT_DITHER) {
438 dither = true; 387 dither = true;
439 format &= ~FORMAT_DITHER;
440 } 388 }
441#else 389#else
442 390
@@ -470,23 +418,23 @@ int read_bmp_fd(int fd,
470 418
471 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width, 419 BDEBUGF("width: %d height: %d depth: %d padded_width: %d\n", src_dim.width,
472 src_dim.height, depth, padded_width); 420 src_dim.height, depth, padded_width);
473 421
474#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 422#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
475 if ((format & 3) == FORMAT_ANY) { 423 if ((format & 3) == FORMAT_ANY) {
476 if (depth == 1) 424 if (depth == 1)
477 format = (format & ~3); 425 format = (format & ~3);
478 else 426 else
479 format = (format & ~3) | FORMAT_NATIVE; 427 format = (format & ~3) | FORMAT_NATIVE;
480 } 428 }
481 bm->format = format & 3; 429 bm->format = format & 1;
482 if ((format & 3) == FORMAT_MONO) 430 if ((format & 1) == FORMAT_MONO)
483 { 431 {
484 resize &= ~IMG_RESIZE; 432 resize &= ~IMG_RESIZE;
485 resize |= IMG_NORESIZE; 433 resize |= IMG_NORESIZE;
486 remote = 0; 434 remote = 0;
487 } 435 }
488#else 436#else
489 if (src_dim.width > MAX_WIDTH) 437 if (src_dim.width > BM_MAX_WIDTH)
490 return -6; 438 return -6;
491#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/ 439#endif /*(LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)*/
492 440
@@ -494,7 +442,6 @@ int read_bmp_fd(int fd,
494 if (resize & IMG_RESIZE) { 442 if (resize & IMG_RESIZE) {
495 if(format & FORMAT_KEEP_ASPECT) { 443 if(format & FORMAT_KEEP_ASPECT) {
496 /* keep aspect ratio.. */ 444 /* keep aspect ratio.. */
497 format &= ~FORMAT_KEEP_ASPECT;
498 struct dim resize_dim = { 445 struct dim resize_dim = {
499 .width = bm->width, 446 .width = bm->width,
500 .height = bm->height, 447 .height = bm->height,
@@ -506,6 +453,8 @@ int read_bmp_fd(int fd,
506 } 453 }
507 } 454 }
508 455
456 format &= 1;
457
509 if (!(resize & IMG_RESIZE)) { 458 if (!(resize & IMG_RESIZE)) {
510#endif 459#endif
511 /* returning image size */ 460 /* returning image size */
@@ -524,7 +473,7 @@ int read_bmp_fd(int fd,
524 rset.rowstop = -1; 473 rset.rowstop = -1;
525 } 474 }
526 475
527 totalsize = get_totalsize(bm, remote); 476 totalsize = BM_SIZE(bm->width,bm->height,format,remote);
528 477
529 /* Check if this fits the buffer */ 478 /* Check if this fits the buffer */
530 if (totalsize > maxsize) { 479 if (totalsize > maxsize) {
@@ -616,90 +565,146 @@ int read_bmp_fd(int fd,
616 }; 565 };
617 566
618#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) 567#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
619#if LCD_DEPTH == 16 568 if (resize)
620#ifdef HAVE_REMOTE_LCD 569 return resize_on_load(bm, dither, &src_dim, &rset,
621 if (resize & IMG_RESIZE || remote)
622#else
623 if (resize & IMG_RESIZE)
624#endif
625#else
626 if (format == FORMAT_NATIVE)
627#endif
628 return resize_on_load(bm, dither, &src_dim, &rset, remote,
629#ifdef HAVE_LCD_COLOR
630 bitmap + totalsize, maxsize - totalsize, 570 bitmap + totalsize, maxsize - totalsize,
631#endif 571 store_part_bmp, &ba);
632 store_part_bmp, skip_lines_bmp, &ba); 572
573 int fb_width = BM_WIDTH(bm->width,bm->format,remote);
633#endif /* LCD_DEPTH */ 574#endif /* LCD_DEPTH */
634 575
635 int fb_width = get_fb_width(bm, remote);
636 int col, row; 576 int col, row;
637 577
638 /* loop to read rows and put them to buffer */ 578 /* loop to read rows and put them to buffer */
639 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) { 579 for (row = rset.rowstart; row != rset.rowstop; row += rset.rowstep) {
640 struct uint8_rgb *qp; 580#if !defined(HAVE_LCD_COLOR) && \
581 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
582 uint8_t* qp = ba.buf;
583#else
584 struct uint8_rgb *qp = (struct uint8_rgb *)ba.buf;
585#endif
641 unsigned mask; 586 unsigned mask;
642 unsigned char *p; 587 unsigned char *p;
643#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
644 unsigned int len;
645
646 if (!(len = read_part_line(&ba)))
647 return -9;
648#else
649 if (!read_part_line(&ba)) 588 if (!read_part_line(&ba))
650 return -9; 589 return -9;
651#endif
652 590
653 /* Convert to destination format */ 591 /* Convert to destination format */
654 qp = (struct uint8_rgb *) ba.buf; 592#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
655#if LCD_DEPTH == 16 593 unsigned char dy = DITHERY(row);
656 if (format == FORMAT_NATIVE) 594 if (format == FORMAT_NATIVE) {
657 { 595#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
658 /* iriver h300, colour iPods, X5 */ 596 if (remote) {
659 fb_data *dest = (fb_data *)bitmap + fb_width * row; 597#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
660 int delta = 127; 598 /* iAudio X5/M5 remote */
661 unsigned r, g, b; 599 fb_remote_data *dest = (fb_remote_data *)bitmap
662 struct uint8_rgb q0; 600 + bm->width * (row >> 3);
663 601 int shift = row & 7;
664 for (col = 0; col < src_dim.width; col++) { 602 int delta = 127;
665 if (dither) 603 unsigned bright;
666 delta = dither_mat(row & 0xf, col & 0xf); 604
667 if (!len) 605 for (col = 0; col < bm->width; col++) {
668 { 606 if (dither)
669 if(!(len = read_part_line(&ba))) 607 delta = DITHERXDY(col,dy);
670 return -9; 608#if !defined(HAVE_LCD_COLOR) && \
671 else 609 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
672 qp = (struct uint8_rgb *)ba.buf; 610 bright = *qp++;
611#else
612 bright = brightness(*qp++);
613#endif
614 bright = (3 * bright + (bright >> 6) + delta) >> 8;
615 *dest++ |= vi_pattern[bright] << shift;
673 } 616 }
674 q0 = *qp++; 617#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
675 len--; 618 } else
676 r = (31 * q0.red + (q0.red >> 3) + delta) >> 8; 619#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
677 g = (63 * q0.green + (q0.green >> 2) + delta) >> 8; 620 {
678 b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8; 621#if LCD_DEPTH == 2
679 *dest++ = LCD_RGBPACK_LCD(r, g, b); 622#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
623 /* greyscale iPods */
624 fb_data *dest = (fb_data *)bitmap + fb_width * row;
625 int shift = 6;
626 int delta = 127;
627 unsigned bright;
628 unsigned data = 0;
629
630 for (col = 0; col < bm->width; col++) {
631 if (dither)
632 delta = DITHERXDY(col,dy);
633 bright = *qp++;
634 bright = (3 * bright + (bright >> 6) + delta) >> 8;
635 data |= (~bright & 3) << shift;
636 shift -= 2;
637 if (shift < 0) {
638 *dest++ = data;
639 data = 0;
640 shift = 6;
641 }
642 }
643 if (shift < 6)
644 *dest++ = data;
645#elif LCD_PIXELFORMAT == VERTICAL_PACKING
646 /* iriver H1x0 */
647 fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 2);
648 int shift = 2 * (row & 3);
649 int delta = 127;
650 unsigned bright;
651
652 for (col = 0; col < bm->width; col++) {
653 if (dither)
654 delta = DITHERXDY(col,dy);
655 bright = *qp++;
656 bright = (3 * bright + (bright >> 6) + delta) >> 8;
657 *dest++ |= (~bright & 3) << shift;
658 }
659#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
660 /* iAudio M3 */
661 fb_data *dest = (fb_data *)bitmap + fb_width * (row >> 3);
662 int shift = row & 7;
663 int delta = 127;
664 unsigned bright;
665
666 for (col = 0; col < bm->width; col++) {
667 if (dither)
668 delta = DITHERXDY(col,dy);
669 bright = *qp++;
670 bright = (3 * bright + (bright >> 6) + delta) >> 8;
671 *dest++ |= vi_pattern[bright] << shift;
672 }
673#endif /* LCD_PIXELFORMAT */
674#elif LCD_DEPTH == 16
675 /* iriver h300, colour iPods, X5 */
676 fb_data *dest = (fb_data *)bitmap + fb_width * row;
677 int delta = 127;
678 unsigned r, g, b;
679 struct uint8_rgb q0;
680
681 for (col = 0; col < bm->width; col++) {
682 if (dither)
683 delta = DITHERXDY(col,dy);
684 q0 = *qp++;
685 r = (31 * q0.red + (q0.red >> 3) + delta) >> 8;
686 g = (63 * q0.green + (q0.green >> 2) + delta) >> 8;
687 b = (31 * q0.blue + (q0.blue >> 3) + delta) >> 8;
688 *dest++ = LCD_RGBPACK_LCD(r, g, b);
689 }
690#endif /* LCD_DEPTH */
680 } 691 }
681 } 692 } else
682 else 693#endif /* (LCD_DEPTH > 1) ||
683#endif 694 defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
684 { 695 {
685 p = bitmap + fb_width * (row >> 3); 696 p = bitmap + bm->width * (row >> 3);
686 mask = 1 << (row & 7); 697 mask = 1 << (row & 7);
687 for (col = 0; col < src_dim.width; col++) 698
688 { 699 for (col = 0; col < bm->width; col++, p++)
689#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) 700#if !defined(HAVE_LCD_COLOR) && \
690 if (!len) 701 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
691 { 702 if (*qp++ < 128)
692 if(!(len = read_part_line(&ba))) 703 *p |= mask;
693 return -9; 704#else
694 else
695 qp = (struct uint8_rgb *)ba.buf;
696 }
697 len--;
698#endif
699 if (brightness(*qp++) < 128) 705 if (brightness(*qp++) < 128)
700 *p |= mask; 706 *p |= mask;
701 p++; 707#endif
702 }
703 } 708 }
704 } 709 }
705 return totalsize; /* return the used buffer size. */ 710 return totalsize; /* return the used buffer size. */
diff --git a/apps/recorder/bmp.h b/apps/recorder/bmp.h
index d1b1d7f3ed..273e178bc9 100644
--- a/apps/recorder/bmp.h
+++ b/apps/recorder/bmp.h
@@ -32,11 +32,7 @@
32 32
33#define IMG_NORESIZE 0 33#define IMG_NORESIZE 0
34#define IMG_RESIZE 1 34#define IMG_RESIZE 1
35#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1) 35#define BM_MAX_WIDTH (((LCD_WIDTH) + 7) & ~7)
36#define MAX_WIDTH 8
37#else
38#define MAX_WIDTH LCD_WIDTH
39#endif
40 36
41struct uint8_rgb { 37struct uint8_rgb {
42 uint8_t blue; 38 uint8_t blue;
@@ -56,129 +52,144 @@ struct rowset {
56}; 52};
57 53
58#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 54#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
59extern const unsigned char dither_matrix[16][16]; 55extern const unsigned char dither_table[16];
60static inline unsigned char dither_mat(unsigned int x, unsigned int y) 56#define DITHERY(y) (dither_table[(y) & 15] & 0xAA)
61{ 57#define DITHERX(x) (dither_table[(x) & 15])
62 return dither_matrix[y][x]; 58#define DITHERXDY(x,dy) (DITHERX(x) ^ dy)
63} 59#define DITHERDXY(dx,y) (dx ^ DITHERY(y))
60#define DITHERXY(x,y) (DITHERX(x) ^ DITHERY(y))
64#endif 61#endif
65 62
63/* The /256 version has a mean squared variance from YUV luma of <1 grey level.
64 The /8 version is a good deal less accurate, but sufficient on mono as we
65 don't support HQ output or dithering there, yet.
66*/
66static inline unsigned brightness(struct uint8_rgb color) 67static inline unsigned brightness(struct uint8_rgb color)
67{ 68{
68 return (3 * (unsigned)color.red + 6 * (unsigned)color.green 69#if LCD_DEPTH > 1
69 + (unsigned)color.blue) / 10; 70 return (77 * (unsigned)color.red + 150 * (unsigned)color.green
71 + 29 * (unsigned)color.blue) / 256;
72#else
73 return (2 * (unsigned)color.red + 5 * (unsigned)color.green
74 + (unsigned)color.blue) / 8;
75#endif
70} 76}
71 77
72#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \ 78#if ((LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)) \
73 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \ 79 || (defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH == 2) \
74 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)) 80 && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED))
75extern const unsigned short vi_pattern[4]; 81extern const unsigned short vi_pattern[4];
76static inline unsigned short vi_pat(unsigned int bright)
77{
78 return vi_pattern[bright];
79}
80#endif 82#endif
81 83
82static inline int get_fb_height(struct bitmap *bm, bool remote) 84/* Number of rows of data in a mono bitmap height pixels tall */
83{ 85#define MONO_BM_HEIGHT(height) (((height) + 7) >> 3)
84 const int height = bm->height; 86
85#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 87/* Number of rows of datain a LCD native bitmap height pixels tall */
86 const int format = bm->format; 88#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
89#if LCD_DEPTH == 1 || \
90 (LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
91#define LCD_BM_HEIGHT(height) (((height) + 7) >> 3)
92#elif LCD_DEPTH == 2 && LCD_PIXELFORMAT == VERTICAL_PACKING
93#define LCD_BM_HEIGHT(height) (((height) + 3) >> 2)
94#else
95#define LCD_BM_HEIGHT(height) (height)
87#endif 96#endif
88 int dst_height;
89 97
90#if !defined(HAVE_REMOTE_LCD) || \ 98/* Number of rows of data in a remote native bitmap height pixels tall. */
91 (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) 99#ifdef HAVE_REMOTE_LCD
92 (void) remote; 100#if LCD_REMOTE_DEPTH == 1 || \
101 (LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED)
102#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 7) >> 3)
103#elif LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING
104#define LCD_REMOTE_BM_HEIGHT(height) (((height) + 3) >> 2)
105#else
106#define LCD_REMOTE_BM_HEIGHT(height) (height)
107#endif
108#define NATIVE_BM_HEIGHT(height,remote) ((remote) ? \
109 LCD_REMOTE_BM_HEIGHT(height) : LCD_BM_HEIGHT(height))
110#else
111#define NATIVE_BM_HEIGHT(height,remote) LCD_BM_HEIGHT(height)
93#endif 112#endif
94 113
95#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 114/* Convenience macro to calculate rows based on height, remote vs main LCD,
96 if (format == FORMAT_NATIVE) { 115 and format
97#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 116*/
98 if (remote) { 117#define BM_HEIGHT(height,format,remote) ((format) == FORMAT_MONO ? \
99#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) 118 MONO_BM_HEIGHT(height) : NATIVE_BM_HEIGHT(height,remote))
100 dst_height = (height + 7) >> 3; 119#else
101#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ 120#define BM_HEIGHT(height,format,remote) MONO_BM_HEIGHT(height)
102 } else 121#endif
103#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
104 {
105#if LCD_DEPTH == 2
106#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
107 dst_height = height;
108#elif LCD_PIXELFORMAT == VERTICAL_PACKING
109 dst_height = (height + 3) >> 2;
110#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
111 dst_height = (height + 7) >> 3;
112#endif /* LCD_PIXELFORMAT */
113#elif LCD_DEPTH == 16
114 dst_height = height;
115#endif /* LCD_DEPTH */
116 }
117 } else
118#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
119 {
120 dst_height = (height + 7) >> 3;
121 }
122
123 return dst_height;
124}
125 122
126static inline int get_fb_width(struct bitmap *bm, bool remote) 123/* Number of data elements in a mono bitmap width pixels wide */
127{ 124#define MONO_BM_WIDTH(width) (width)
128 const int width = bm->width; 125
129#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 126/* Number of data elements in a LCD native bitmap width pixels wide */
130 const int format = bm->format; 127#if LCD_DEPTH > 1
128#if LCD_DEPTH == 2 && LCD_PIXELFORMAT == HORIZONTAL_PACKING
129#define LCD_BM_WIDTH(width) (((width) + 3) >> 2)
130#else
131#define LCD_BM_WIDTH(width) (width)
131#endif 132#endif
132 int dst_width;
133 133
134#if !defined(HAVE_REMOTE_LCD) || \ 134/* Number of data elements in a remote native bitmap width pixels wide */
135 (defined(HAVE_REMOTE_LCD) &&(LCD_REMOTE_DEPTH == 1)) 135#ifdef HAVE_LCD_REMOTE
136 (void) remote; 136#if LCD_REMOTE_DEPTH == 2 && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING
137#define LCD_REMOTE_BM_WIDTH(width) (((width) + 3) >> 2)
138#else
139#define LCD_REMOTE_BM_WIDTH(width) (width)
140#endif
141#define NATIVE_BM_WIDTH(width,remote) ((remote) ? \
142 LCD_REMOTE_BM_WIDTH(width) : LCD_BM_WIDTH(width))
143#else
144#define NATIVE_BM_WIDTH(width,remote) LCD_BM_WIDTH(width)
137#endif 145#endif
138 146
139#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) 147/* Convenience macro to calculate elements based on height, remote vs native
140 if (format == FORMAT_NATIVE) { 148 main LCD, and format
141#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 149*/
142 if (remote) { 150#define BM_WIDTH(width,format,remote) ((format) == FORMAT_MONO ? \
143#if (LCD_REMOTE_DEPTH == 2) && (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) 151 MONO_BM_WIDTH(width) : NATIVE_BM_WIDTH(width,remote))
144 dst_width = width; 152#else
145#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */ 153#define BM_WIDTH(width,format,remote) MONO_BM_WIDTH(width)
146 } else 154#endif
147#endif /* defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1 */
148 {
149#if LCD_DEPTH == 2
150#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
151 dst_width = (width + 3) >> 2;
152#elif LCD_PIXELFORMAT == VERTICAL_PACKING
153 dst_width = width;
154#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
155 dst_width = width;
156#endif /* LCD_PIXELFORMAT */
157#elif LCD_DEPTH == 16
158 dst_width = width;
159#endif /* LCD_DEPTH */
160 }
161 } else
162#endif /* (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) */
163 {
164 dst_width = width;
165 }
166
167 return dst_width;
168}
169 155
170static inline int get_totalsize(struct bitmap *bm, bool remote) 156/* Size in bytes of a mono bitmap of dimensions width*height */
171{ 157#define MONO_BM_SIZE(width,height) (MONO_BM_WIDTH(width) * \
172 int sz; 158 MONO_BM_HEIGHT(height) * FB_DATA_SZ)
173#ifdef HAVE_REMOTE_LCD
174 if (remote && sizeof(fb_data) != sizeof(fb_remote_data))
175 sz = sizeof(fb_remote_data);
176 else
177#endif /* LCD_REMOTE_DEPTH / LCD_REMOTE_PIXELFORMAT */
178 sz = sizeof(fb_data);
179 159
180 return get_fb_width(bm, remote) * get_fb_height(bm, remote) * sz; 160/* Size in bytes of a native bitmap of dimensions width*height */
181} 161#if LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
162#if defined(HAVE_REMOTE_LCD) && FB_DATA_SZ != FB_RDATA_SZ
163#define NATIVE_BM_SIZE(width,height,format,remote) \
164 (((remote) ? FB_RDATA_SZ : FB_DATA_SZ) * BM_WIDTH(width,format,remote) \
165 * BM_HEIGHT(height,format,remote))
166#else
167#define NATIVE_BM_SIZE(width,height,format,remote) \
168 (FB_DATA_SZ * BM_WIDTH(width,format,remote) * \
169 BM_HEIGHT(height,format,remote))
170#endif
171
172/* Convenience macro to calculate size in bytes based on height, remote vs
173 main LCD, and format
174*/
175#define BM_SIZE(width,height,format,remote) (((format) == FORMAT_MONO) ? \
176 MONO_BM_SIZE(width,height) : NATIVE_BM_SIZE(width,height,format,remote))
177#else
178#define BM_SIZE(width,height,format,remote) MONO_BM_SIZE(width,height)
179#endif
180
181/* Size in bytes needed to load and scale a bitmap with target size up to
182 width*height, including overhead to allow for buffer alignment.
183*/
184#ifdef HAVE_LCD_COLOR
185#define BM_SCALED_SIZE(width,height,format,remote) \
186 (BM_SIZE(width,height,format,remote) + \
187 (remote ? 0 : BM_WIDTH(width,format,remote) * sizeof(uint32_t) * 9 + 3))
188#else
189#define BM_SCALED_SIZE(width,height,format,remote) \
190 (BM_SIZE(width,height,format,remote) + \
191 (width * sizeof(uint32_t) * 3 + 3))
192#endif
182 193
183/********************************************************************* 194/*********************************************************************
184 * read_bmp_file() 195 * read_bmp_file()
diff --git a/apps/recorder/resize.c b/apps/recorder/resize.c
index e41501032a..3c1d34f046 100644
--- a/apps/recorder/resize.c
+++ b/apps/recorder/resize.c
@@ -59,15 +59,45 @@
59#define DEBUGF(...) 59#define DEBUGF(...)
60#endif 60#endif
61 61
62/* calculate the maximum dimensions which will preserve the aspect ration of
63 src while fitting in the constraints passed in dst, and store result in dst,
64 returning 0 if rounding and 1 if not rounding.
65*/
66int recalc_dimension(struct dim *dst, struct dim *src)
67{
68 int tmp;
69 if (dst->width <= 0)
70 dst->width = LCD_WIDTH;
71 if (dst->height <= 0)
72 dst->height = LCD_HEIGHT;
73#ifndef HAVE_UPSCALER
74 if (dst->width > src->width || dst->height > src->height)
75 {
76 dst->width = src->width;
77 dst->height = src->height;
78 }
79 if (src->width == dst->width && src->height == dst->height)
80 return 1;
81#endif
82 tmp = (src->width * dst->height + (src->height >> 1)) / src->height;
83 if (tmp > dst->width)
84 dst->height = (src->height * dst->width + (src->width >> 1))
85 / src->width;
86 else
87 dst->width = tmp;
88 return src->width == dst->width && src->height == dst->height;
89}
90
62/* All of these scalers use variations of Bresenham's algorithm to convert from 91/* All of these scalers use variations of Bresenham's algorithm to convert from
63 their input to output coordinates. The color scalers have the error value 92 their input to output coordinates. The error value is shifted from the
64 shifted so that it is a useful input to the scaling algorithm. 93 "classic" version such that it is a useful input to the scaling calculation.
65*/ 94*/
66 95
67#ifdef HAVE_LCD_COLOR 96#ifdef HAVE_LCD_COLOR
68/* dither + pack on channel of RGB565, R an B share a packing macro */ 97/* dither + pack on channel of RGB565, R an B share a packing macro */
69#define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8) 98#define PACKRB(v, delta) ((31 * v + (v >> 3) + delta) >> 8)
70#define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8) 99#define PACKG(g, delta) ((63 * g + (g >> 2) + delta) >> 8)
100#endif
71 101
72/* read new img_part unconditionally, return false on failure */ 102/* read new img_part unconditionally, return false on failure */
73#define FILL_BUF_INIT(img_part, store_part, args) { \ 103#define FILL_BUF_INIT(img_part, store_part, args) { \
@@ -84,183 +114,204 @@
84 return false; \ 114 return false; \
85} 115}
86 116
87struct uint32_rgb { 117/* struct which containers various parameters shared between vertical scaler,
88 uint32_t r; 118 horizontal scaler, and row output
89 uint32_t g; 119*/
90 uint32_t b;
91};
92
93struct scaler_context { 120struct scaler_context {
94 uint32_t divmul; 121 uint32_t divisor;
95 uint32_t round; 122 uint32_t round;
96 struct img_part* (*store_part)(void *); 123 struct bitmap *bm;
97 long last_tick; 124 struct dim *src;
98 unsigned char *buf; 125 unsigned char *buf;
126 bool dither;
99 int len; 127 int len;
100 void *args; 128 void *args;
129 struct img_part* (*store_part)(void *);
130 void (*output_row)(uint32_t,void*,struct scaler_context*);
131 bool (*h_scaler)(void*,struct scaler_context*, bool);
101}; 132};
102 133
103/* Set up rounding and scale factors for horizontal area scaler */ 134/* Set up rounding and scale factors for horizontal area scaler */
104static void scale_h_area_setup(struct bitmap *bm, struct dim *src, 135static inline void scale_h_area_setup(struct scaler_context *ctx)
105 struct scaler_context *ctx)
106{ 136{
107 (void) bm;
108/* sum is output value * src->width */ 137/* sum is output value * src->width */
109 ctx->divmul = ((src->width - 1 + 0x80000000U) / src->width) << 1; 138 SDEBUGF("scale_h_area_setup\n");
110 ctx->round = (src->width + 1) >> 1; 139 ctx->divisor = ctx->src->width;
111} 140}
112 141
113/* horizontal area average scaler */ 142/* horizontal area average scaler */
114static bool scale_h_area(struct bitmap *bm, struct dim *src, 143static bool scale_h_area(void *out_line_ptr,
115 struct uint32_rgb *out_line,
116 struct scaler_context *ctx, bool accum) 144 struct scaler_context *ctx, bool accum)
117{ 145{
118 SDEBUGF("scale_h_area\n"); 146 SDEBUGF("scale_h_area\n");
119 unsigned int ix, ox, oxe, mul; 147 unsigned int ix, ox, oxe, mul;
120 struct uint32_rgb rgbvalacc = { 0, 0, 0 }, 148#ifdef HAVE_LCD_COLOR
121 rgbvaltmp = { 0, 0, 0 }; 149 struct uint32_rgb rgbvalacc = { 0, 0, 0 },
150 rgbvaltmp = { 0, 0, 0 },
151 *out_line = (struct uint32_rgb *)out_line_ptr;
152#else
153 uint32_t acc = 0, tmp = 0, *out_line = (uint32_t*)out_line_ptr;
154#endif
122 struct img_part *part; 155 struct img_part *part;
123 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 156 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
124 ox = 0; 157 ox = 0;
125 oxe = 0; 158 oxe = 0;
126 mul = 0; 159 mul = 0;
127 for (ix = 0; ix < (unsigned int)src->width; ix++) 160 /* give other tasks a chance to run */
161 yield();
162 for (ix = 0; ix < (unsigned int)ctx->src->width; ix++)
128 { 163 {
129 oxe += bm->width; 164 oxe += ctx->bm->width;
130 /* end of current area has been reached */ 165 /* end of current area has been reached */
131 if (oxe >= (unsigned int)src->width) 166 /* fill buffer if needed */
167 FILL_BUF(part,ctx->store_part,ctx->args);
168#ifdef HAVE_LCD_COLOR
169 if (oxe >= (unsigned int)ctx->src->width)
132 { 170 {
133 /* yield if we haven't since last tick */
134 if (ctx->last_tick != current_tick)
135 {
136 yield();
137 ctx->last_tick = current_tick;
138 }
139 /* "reset" error, which now represents partial coverage of next 171 /* "reset" error, which now represents partial coverage of next
140 pixel by the next area 172 pixel by the next area
141 */ 173 */
142 oxe -= src->width; 174 oxe -= ctx->src->width;
175
143 /* add saved partial pixel from start of area */ 176 /* add saved partial pixel from start of area */
144 rgbvalacc.r = rgbvalacc.r * bm->width + rgbvaltmp.r * mul; 177 rgbvalacc.r = rgbvalacc.r * ctx->bm->width + rgbvaltmp.r * mul;
145 rgbvalacc.g = rgbvalacc.g * bm->width + rgbvaltmp.g * mul; 178 rgbvalacc.g = rgbvalacc.g * ctx->bm->width + rgbvaltmp.g * mul;
146 rgbvalacc.b = rgbvalacc.b * bm->width + rgbvaltmp.b * mul; 179 rgbvalacc.b = rgbvalacc.b * ctx->bm->width + rgbvaltmp.b * mul;
147 /* fill buffer if needed */ 180
148 FILL_BUF(part,ctx->store_part,ctx->args);
149 /* get new pixel , then add its partial coverage to this area */ 181 /* get new pixel , then add its partial coverage to this area */
150 rgbvaltmp.r = part->buf->red; 182 rgbvaltmp.r = part->buf->red;
151 rgbvaltmp.g = part->buf->green; 183 rgbvaltmp.g = part->buf->green;
152 rgbvaltmp.b = part->buf->blue; 184 rgbvaltmp.b = part->buf->blue;
153 part->buf++; 185 mul = ctx->bm->width - oxe;
154 part->len--;
155 mul = bm->width - oxe;
156 rgbvalacc.r += rgbvaltmp.r * mul; 186 rgbvalacc.r += rgbvaltmp.r * mul;
157 rgbvalacc.g += rgbvaltmp.g * mul; 187 rgbvalacc.g += rgbvaltmp.g * mul;
158 rgbvalacc.b += rgbvaltmp.b * mul; 188 rgbvalacc.b += rgbvaltmp.b * mul;
159 /* round, divide, and either store or accumulate to output row */ 189 /* store or accumulate to output row */
160 out_line[ox].r = (accum ? out_line[ox].r : 0) + 190 if (accum)
161 ((rgbvalacc.r + ctx->round) * 191 {
162 (uint64_t)ctx->divmul >> 32); 192 rgbvalacc.r += out_line[ox].r;
163 out_line[ox].g = (accum ? out_line[ox].g : 0) + 193 rgbvalacc.g += out_line[ox].g;
164 ((rgbvalacc.g + ctx->round) * 194 rgbvalacc.b += out_line[ox].b;
165 (uint64_t)ctx->divmul >> 32); 195 }
166 out_line[ox].b = (accum ? out_line[ox].b : 0) + 196 out_line[ox].r = rgbvalacc.r;
167 ((rgbvalacc.b + ctx->round) * 197 out_line[ox].g = rgbvalacc.g;
168 (uint64_t)ctx->divmul >> 32); 198 out_line[ox].b = rgbvalacc.b;
169 /* reset accumulator */ 199 /* reset accumulator */
170 rgbvalacc.r = 0; 200 rgbvalacc.r = 0;
171 rgbvalacc.g = 0; 201 rgbvalacc.g = 0;
172 rgbvalacc.b = 0; 202 rgbvalacc.b = 0;
173 mul = bm->width - mul; 203 mul = ctx->bm->width - mul;
174 ox += 1; 204 ox += 1;
175 /* inside an area */ 205 /* inside an area */
176 } else { 206 } else {
177 /* fill buffer if needed */
178 FILL_BUF(part,ctx->store_part,ctx->args);
179 /* add pixel value to accumulator */ 207 /* add pixel value to accumulator */
180 rgbvalacc.r += part->buf->red; 208 rgbvalacc.r += part->buf->red;
181 rgbvalacc.g += part->buf->green; 209 rgbvalacc.g += part->buf->green;
182 rgbvalacc.b += part->buf->blue; 210 rgbvalacc.b += part->buf->blue;
183 part->buf++;
184 part->len--;
185 } 211 }
212#else
213 if (oxe >= (unsigned int)ctx->src->width)
214 {
215 /* "reset" error, which now represents partial coverage of next
216 pixel by the next area
217 */
218 oxe -= ctx->src->width;
219
220 /* add saved partial pixel from start of area */
221 acc = acc * ctx->bm->width + tmp * mul;
222
223 /* get new pixel , then add its partial coverage to this area */
224 tmp = *(part->buf);
225 mul = ctx->bm->width - oxe;
226 acc += tmp * mul;
227 /* round, divide, and either store or accumulate to output row */
228 if (accum)
229 {
230 acc += out_line[ox];
231 }
232 out_line[ox] = acc;
233 /* reset accumulator */
234 acc = 0;
235 mul = ctx->bm->width - mul;
236 ox += 1;
237 /* inside an area */
238 } else {
239 /* add pixel value to accumulator */
240 acc += *(part->buf);
241 }
242#endif
243 part->buf++;
244 part->len--;
186 } 245 }
187 return true; 246 return true;
188} 247}
189 248
190/* vertical area average scaler */ 249/* vertical area average scaler */
191static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, 250static inline bool scale_v_area(struct rowset *rset, struct scaler_context *ctx)
192 struct rowset *rset,
193 bool (*h_scaler)(struct bitmap*, struct dim*,
194 struct uint32_rgb*,
195 struct scaler_context*, bool),
196 struct scaler_context *ctx)
197{ 251{
198 uint32_t mul, divmul, x, oy, iy, oye, round; 252 uint32_t mul, x, oy, iy, oye;
199 int delta = 127, r, g, b;
200 fb_data *row, *pix;
201 253
202 /* Set up rounding and scale factors */ 254 /* Set up rounding and scale factors */
203 divmul = ((src->height - 1 + 0x80000000U) / src->height) << 1; 255 ctx->divisor *= ctx->src->height;
204 round = (src->height + 1) >> 1; 256 ctx->round = ctx->divisor >> 1;
257 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
205 mul = 0; 258 mul = 0;
206 oy = 0; 259 oy = rset->rowstart;
207 oye = 0; 260 oye = 0;
208 struct uint32_rgb *rowacc = (struct uint32_rgb *)(ctx->buf), 261#ifdef HAVE_LCD_COLOR
209 *rowtmp = rowacc + bm->width; 262 uint32_t *rowacc = (uint32_t *) ctx->buf,
210 263 *rowtmp = rowacc + 3 * ctx->bm->width;
264 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(struct uint32_rgb));
265#else
266 uint32_t *rowacc = (uint32_t *) ctx->buf,
267 *rowtmp = rowacc + ctx->bm->width;
268 memset((void *)ctx->buf, 0, ctx->bm->width * 2 * sizeof(uint32_t));
269#endif
211 SDEBUGF("scale_v_area\n"); 270 SDEBUGF("scale_v_area\n");
212 /* zero the accumulator and temp rows */ 271 /* zero the accumulator and temp rows */
213 memset((void *)ctx->buf, 0, bm->width * 2 * sizeof(struct uint32_rgb)); 272 for (iy = 0; iy < (unsigned int)ctx->src->height; iy++)
214 row = (fb_data *)(bm->data) + bm->width * rset->rowstart;
215 for (iy = 0; iy < (unsigned int)src->height; iy++)
216 { 273 {
217 oye += bm->height; 274 oye += ctx->bm->height;
218 /* end of current area has been reached */ 275 /* end of current area has been reached */
219 if (oye >= (unsigned int)src->height) 276 if (oye >= (unsigned int)ctx->src->height)
220 { 277 {
221 /* "reset" error, which now represents partial coverage of the next 278 /* "reset" error, which now represents partial coverage of the next
222 row by the next area 279 row by the next area
223 */ 280 */
224 oye -= src->height; 281 oye -= ctx->src->height;
225 /* add stored partial row to accumulator */ 282 /* add stored partial row to accumulator */
226 for (x = 0; x < 3 *(unsigned int)bm->width; x++) 283#ifdef HAVE_LCD_COLOR
227 ((uint32_t*)rowacc)[x] = ((uint32_t*)rowacc)[x] * 284 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
228 bm->height + mul * 285#else
229 ((uint32_t*)rowtmp)[x]; 286 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
287#endif
288 rowacc[x] = rowacc[x] * ctx->bm->height + mul * rowtmp[x];
230 /* store new scaled row in temp row */ 289 /* store new scaled row in temp row */
231 if(!h_scaler(bm, src, rowtmp, ctx, false)) 290 if(!ctx->h_scaler(rowtmp, ctx, false))
232 return false; 291 return false;
233 /* add partial coverage by new row to this area, then round and 292 /* add partial coverage by new row to this area, then round and
234 scale to final value 293 scale to final value
235 */ 294 */
236 mul = bm->height - oye; 295 mul = ctx->bm->height - oye;
237 for (x = 0; x < 3 *(unsigned int)bm->width; x++) 296#ifdef HAVE_LCD_COLOR
238 { 297 for (x = 0; x < 3 * (unsigned int)ctx->bm->width; x++)
239 ((uint32_t*)rowacc)[x] += mul * ((uint32_t*)rowtmp)[x]; 298#else
240 ((uint32_t*)rowacc)[x] = (round + 299 for (x = 0; x < (unsigned int)ctx->bm->width; x++)
241 ((uint32_t*)rowacc)[x]) * 300#endif
242 (uint64_t)divmul >> 32; 301 rowacc[x] += mul * rowtmp[x];
243 } 302 ctx->output_row(oy, (void*)rowacc, ctx);
244 /* convert to RGB565 in output bitmap */
245 pix = row;
246 for (x = 0; x < (unsigned int)bm->width; x++)
247 {
248 if (dither)
249 delta = dither_mat(x & 0xf, oy & 0xf);
250 r = PACKRB(rowacc[x].r,delta);
251 g = PACKG(rowacc[x].g,delta);
252 b = PACKRB(rowacc[x].b,delta);
253 *pix++ = LCD_RGBPACK_LCD(r, g, b);
254 }
255 /* clear accumulator row, store partial coverage for next row */ 303 /* clear accumulator row, store partial coverage for next row */
256 memset((void *)rowacc, 0, bm->width * sizeof(struct uint32_rgb)); 304#ifdef HAVE_LCD_COLOR
305 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t) * 3);
306#else
307 memset((void *)rowacc, 0, ctx->bm->width * sizeof(uint32_t));
308#endif
257 mul = oye; 309 mul = oye;
258 row += bm->width * rset->rowstep; 310 oy += rset->rowstep;
259 oy += 1;
260 /* inside an area */ 311 /* inside an area */
261 } else { 312 } else {
262 /* accumulate new scaled row to rowacc */ 313 /* accumulate new scaled row to rowacc */
263 if (!h_scaler(bm, src, rowacc, ctx, true)) 314 if (!ctx->h_scaler(rowacc, ctx, true))
264 return false; 315 return false;
265 } 316 }
266 } 317 }
@@ -272,53 +323,52 @@ static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src,
272 is bm->width - 1, so that the first and last pixels in the row align 323 is bm->width - 1, so that the first and last pixels in the row align
273 exactly between input and output 324 exactly between input and output
274*/ 325*/
275static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, 326static inline void scale_h_linear_setup(struct scaler_context *ctx)
276 struct scaler_context *ctx)
277{ 327{
278 (void) src; 328 ctx->divisor = ctx->bm->width - 1;
279 ctx->divmul = ((bm->width - 2 + 0x80000000U) / (bm->width - 1)) << 1;
280 ctx->round = bm->width >> 1;
281} 329}
282 330
283/* horizontal linear scaler */ 331/* horizontal linear scaler */
284static bool scale_h_linear(struct bitmap *bm, struct dim *src, 332static bool scale_h_linear(void *out_line_ptr, struct scaler_context *ctx,
285 struct uint32_rgb *out_line, 333 bool accum)
286 struct scaler_context *ctx, bool accum)
287{ 334{
288 unsigned int ix, ox, ixe; 335 unsigned int ix, ox, ixe;
289 /* type x = x is an ugly hack for hiding an unitialized data warning. The 336 /* type x = x is an ugly hack for hiding an unitialized data warning. The
290 values are conditionally initialized before use, but other values are 337 values are conditionally initialized before use, but other values are
291 set such that this will occur before these are used. 338 set such that this will occur before these are used.
292 */ 339 */
293 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc; 340#ifdef HAVE_LCD_COLOR
341 struct uint32_rgb rgbval=rgbval, rgbinc=rgbinc,
342 *out_line = (struct uint32_rgb*)out_line_ptr;
343#else
344 uint32_t val=val, inc=inc, *out_line = (uint32_t*)out_line_ptr;
345#endif
294 struct img_part *part; 346 struct img_part *part;
295 SDEBUGF("scale_h_linear\n"); 347 SDEBUGF("scale_h_linear\n");
296 FILL_BUF_INIT(part,ctx->store_part,ctx->args); 348 FILL_BUF_INIT(part,ctx->store_part,ctx->args);
297 ix = 0; 349 ix = 0;
298 /* The error is set so that values are initialized on the first pass. */ 350 /* The error is set so that values are initialized on the first pass. */
299 ixe = bm->width - 1; 351 ixe = ctx->bm->width - 1;
300 for (ox = 0; ox < (uint32_t)bm->width; ox++) { 352 /* give other tasks a chance to run */
301 if (ixe >= ((uint32_t)bm->width - 1)) 353 yield();
354 for (ox = 0; ox < (uint32_t)ctx->bm->width; ox++)
355 {
356#ifdef HAVE_LCD_COLOR
357 if (ixe >= ((uint32_t)ctx->bm->width - 1))
302 { 358 {
303 /* yield once each tick */ 359 /* Store the new "current" pixel value in rgbval, and the color
304 if (ctx->last_tick != current_tick)
305 {
306 yield();
307 ctx->last_tick = current_tick;
308 }
309 /* Store the new "current" pixel value in rgbval, and the color
310 step value in rgbinc. 360 step value in rgbinc.
311 */ 361 */
312 ixe -= (bm->width - 1); 362 ixe -= (ctx->bm->width - 1);
313 rgbinc.r = -(part->buf->red); 363 rgbinc.r = -(part->buf->red);
314 rgbinc.g = -(part->buf->green); 364 rgbinc.g = -(part->buf->green);
315 rgbinc.b = -(part->buf->blue); 365 rgbinc.b = -(part->buf->blue);
316 rgbval.r = (part->buf->red) * (bm->width - 1); 366 rgbval.r = (part->buf->red) * (ctx->bm->width - 1);
317 rgbval.g = (part->buf->green) * (bm->width - 1); 367 rgbval.g = (part->buf->green) * (ctx->bm->width - 1);
318 rgbval.b = (part->buf->blue) * (bm->width - 1); 368 rgbval.b = (part->buf->blue) * (ctx->bm->width - 1);
319 ix += 1; 369 ix += 1;
320 /* If this wasn't the last pixel, add the next one to rgbinc. */ 370 /* If this wasn't the last pixel, add the next one to rgbinc. */
321 if (ix < (uint32_t)src->width) { 371 if (ix < (uint32_t)ctx->src->width) {
322 part->buf++; 372 part->buf++;
323 part->len--; 373 part->len--;
324 /* Fetch new pixels if needed */ 374 /* Fetch new pixels if needed */
@@ -334,448 +384,314 @@ static bool scale_h_linear(struct bitmap *bm, struct dim *src,
334 rgbval.b += rgbinc.b * ixe; 384 rgbval.b += rgbinc.b * ixe;
335 } 385 }
336 /* Now multiple the color increment to its proper value */ 386 /* Now multiple the color increment to its proper value */
337 rgbinc.r *= src->width - 1; 387 rgbinc.r *= ctx->src->width - 1;
338 rgbinc.g *= src->width - 1; 388 rgbinc.g *= ctx->src->width - 1;
339 rgbinc.b *= src->width - 1; 389 rgbinc.b *= ctx->src->width - 1;
390 } else {
391 rgbval.r += rgbinc.r;
392 rgbval.g += rgbinc.g;
393 rgbval.b += rgbinc.b;
340 } 394 }
341 /* round and scale values, and accumulate or store to output */ 395 /* round and scale values, and accumulate or store to output */
342 out_line[ox].r = (accum ? out_line[ox].r : 0) + 396 if (accum)
343 ((rgbval.r + ctx->round) * 397 {
344 (uint64_t)ctx->divmul >> 32); 398 out_line[ox].r += rgbval.r;
345 out_line[ox].g = (accum ? out_line[ox].g : 0) + 399 out_line[ox].g += rgbval.g;
346 ((rgbval.g + ctx->round) * 400 out_line[ox].b += rgbval.b;
347 (uint64_t)ctx->divmul >> 32); 401 } else {
348 out_line[ox].b = (accum ? out_line[ox].b : 0) + 402 out_line[ox].r = rgbval.r;
349 ((rgbval.b + ctx->round) * 403 out_line[ox].g = rgbval.g;
350 (uint64_t)ctx->divmul >> 32); 404 out_line[ox].b = rgbval.b;
351 rgbval.r += rgbinc.r; 405 }
352 rgbval.g += rgbinc.g; 406#else
353 rgbval.b += rgbinc.b; 407 if (ixe >= ((uint32_t)ctx->bm->width - 1))
354 ixe += src->width - 1; 408 {
409 /* Store the new "current" pixel value in rgbval, and the color
410 step value in rgbinc.
411 */
412 ixe -= (ctx->bm->width - 1);
413 val = *(part->buf);
414 inc = -val;
415 val *= (ctx->bm->width - 1);
416 ix += 1;
417 /* If this wasn't the last pixel, add the next one to rgbinc. */
418 if (ix < (uint32_t)ctx->src->width) {
419 part->buf++;
420 part->len--;
421 /* Fetch new pixels if needed */
422 FILL_BUF(part,ctx->store_part,ctx->args);
423 inc += *(part->buf);
424 /* Add a partial step to rgbval, in this pixel isn't precisely
425 aligned with the new source pixel
426 */
427 val += inc * ixe;
428 }
429 /* Now multiply the color increment to its proper value */
430 inc *= ctx->src->width - 1;
431 } else
432 val += inc;
433 /* round and scale values, and accumulate or store to output */
434 if (accum)
435 {
436 out_line[ox] += val;
437 } else {
438 out_line[ox] = val;
439 }
440#endif
441 ixe += ctx->src->width - 1;
355 } 442 }
356 return true; 443 return true;
357} 444}
358 445
359/* vertical linear scaler */ 446/* vertical linear scaler */
360static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, 447static inline bool scale_v_linear(struct rowset *rset,
361 struct rowset *rset, 448 struct scaler_context *ctx)
362 bool (*h_scaler)(struct bitmap*, struct dim*,
363 struct uint32_rgb*,
364 struct scaler_context*, bool),
365 struct scaler_context *ctx)
366{ 449{
367 uint32_t mul, divmul, x, oy, iy, iye, round; 450 uint32_t mul, x, iy, iye;
368 int delta = 127; 451 int32_t oy;
369 struct uint32_rgb p;
370 fb_data *row, *pix;
371 /* Set up scale and rounding factors, the divisor is bm->height - 1 */ 452 /* Set up scale and rounding factors, the divisor is bm->height - 1 */
372 divmul = ((bm->height - 2 + 0x80000000U) / (bm->height - 1)) << 1; 453 ctx->divisor *= (ctx->bm->height - 1);
373 round = bm->height >> 1; 454 ctx->round = ctx->divisor >> 1;
374 mul = 0; 455 ctx->divisor = ((ctx->divisor - 1 + 0x80000000U) / ctx->divisor) << 1;
375 iy = 0;
376 iye = bm->height - 1;
377 /* Set up our two temp buffers. The names are generic because they'll be 456 /* Set up our two temp buffers. The names are generic because they'll be
378 swapped each time a new input row is read 457 swapped each time a new input row is read
379 */ 458 */
380 struct uint32_rgb *crow1 = (struct uint32_rgb *)(ctx->buf), 459#ifdef HAVE_LCD_COLOR
381 *crow2 = crow1 + bm->width, 460 uint32_t *rowinc = (uint32_t *)(ctx->buf),
382 *t; 461 *rowval = rowinc + 3 * ctx->bm->width,
462 *rowtmp = rowval + 3 * ctx->bm->width;
463#else
464 uint32_t *rowinc = (uint32_t *)(ctx->buf),
465 *rowval = rowinc + ctx->bm->width,
466 *rowtmp = rowval + ctx->bm->width;
467#endif
383 468
384 SDEBUGF("scale_v_linear\n"); 469 SDEBUGF("scale_v_linear\n");
385 row = (fb_data *)(bm->data) + bm->width * rset->rowstart; 470 mul = 0;
386 /* get first scaled row in crow2 */ 471 iy = 0;
387 if(!h_scaler(bm, src, crow2, ctx, false)) 472 iye = ctx->bm->height - 1;
473 /* get first scaled row in rowtmp */
474 if(!ctx->h_scaler((void*)rowtmp, ctx, false))
388 return false; 475 return false;
389 for (oy = 0; oy < (uint32_t)bm->height; oy++) 476 for (oy = rset->rowstart; oy != rset->rowstop; oy += rset->rowstep)
390 { 477 {
391 if (iye >= (uint32_t)bm->height - 1) 478 if (iye >= (uint32_t)ctx->bm->height - 1)
392 { 479 {
393 /* swap temp rows, then read another row into crow2 */ 480 iye -= ctx->bm->height - 1;
394 t = crow2;
395 crow2 = crow1;
396 crow1 = t;
397 iye -= bm->height - 1;
398 iy += 1; 481 iy += 1;
399 if (iy < (uint32_t)src->height) 482#ifdef HAVE_LCD_COLOR
483 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
484#else
485 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
486#endif
400 { 487 {
401 if (!h_scaler(bm, src, crow2, ctx, false)) 488 rowinc[x] = -rowtmp[x];
489 rowval[x] = rowtmp[x] * (ctx->bm->height - 1);
490 }
491 if (iy < (uint32_t)ctx->src->height)
492 {
493 if (!ctx->h_scaler((void*)rowtmp, ctx, false))
402 return false; 494 return false;
495#ifdef HAVE_LCD_COLOR
496 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
497#else
498 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
499#endif
500 {
501 rowinc[x] += rowtmp[x];
502 rowval[x] += rowinc[x] * iye;
503 rowinc[x] *= ctx->src->height - 1;
504 }
403 } 505 }
404 } 506 } else
405 pix = row; 507#ifdef HAVE_LCD_COLOR
406 for (x = 0; x < (uint32_t)bm->width; x++) 508 for (x = 0; x < 3 * (uint32_t)ctx->bm->width; x++)
407 { 509#else
408 /* iye and bm-height - 1 - iye represent the contribution of each 510 for (x = 0; x < (uint32_t)ctx->bm->width; x++)
409 row to the output. Calculate their weighted sum, then round and 511#endif
410 scale it. 512 rowval[x] += rowinc[x];
411 */ 513 ctx->output_row(oy, (void*)rowval, ctx);
412 p.r = (crow1[x].r * (bm->height - 1 - iye) + 514 iye += ctx->src->height - 1;
413 crow2[x].r * iye + round) * (uint64_t)divmul >> 32;
414 p.g = (crow1[x].g * (bm->height - 1 - iye) +
415 crow2[x].g * iye + round) * (uint64_t)divmul >> 32;
416 p.b = (crow1[x].b * (bm->height - 1 - iye) +
417 crow2[x].b * iye + round) * (uint64_t)divmul >> 32;
418 /* dither and pack pixels to output */
419 if (dither)
420 delta = dither_mat(x & 0xf, oy & 0xf);
421 p.r = PACKRB(p.r,delta);
422 p.g = PACKG(p.g,delta);
423 p.b = PACKRB(p.b,delta);
424 *pix++ = LCD_RGBPACK_LCD(p.r, p.g, p.b);
425 }
426 row += bm->width * rset->rowstep;
427 iye += src->height - 1;
428 } 515 }
429 return true; 516 return true;
430} 517}
431#endif /* HAVE_UPSCALER */ 518#endif /* HAVE_UPSCALER */
432#endif /* HAVE_LCD_COLOR */
433 519
434/* docs for this are still TODO, but it's Bresenham's again, used to skip or 520void output_row_native(uint32_t row, void * row_in, struct scaler_context *ctx)
435 repeat input pixels, and with the *ls values being used for "long steps"
436 that skip all the way, or nearly all the way, to the next transition of
437 the associated value.
438*/
439#if LCD_DEPTH < 8 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH < 8)
440/* nearest-neighbor up/down/non-scaler */
441static inline bool scale_nearest(struct bitmap *bm,
442 struct dim *src,
443 struct rowset *rset,
444 bool remote, bool dither,
445 struct img_part* (*store_part)(void *args),
446 bool (*skip_lines)(void *args, unsigned int),
447 void *args)
448{ 521{
449 const int sw = src->width; 522 int col;
450 const int sh = src->height; 523 int fb_width = BM_WIDTH(ctx->bm->width,FORMAT_NATIVE,0);
451 const int dw = bm->width; 524 uint8_t dy = DITHERY(row);
452 const int dh = bm->height; 525#ifdef HAVE_LCD_COLOR
453 unsigned char *bitmap = bm->data; 526 struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
454 const int rowstep = rset->rowstep;
455 const int rowstart = rset->rowstart;
456 const int rowstop = rset->rowstop;
457 const int fb_width = get_fb_width(bm, false);
458 long last_tick = current_tick;
459 /* yet/oyt will always be initialized before use, since they are set in the
460 inside loop, and not used elsewhere until the end of the outside loop.
461 */
462 int ix, ox, lx, xe, iy, oy, ly, ye, yet = yet, oyt = oyt;
463 int xelim, ixls, xels, yelim, iyls, yels, p;
464 struct img_part *cur_part;
465#ifndef HAVE_LCD_COLOR
466 fb_data *dest = dest, *dest_t;
467#endif
468#ifdef HAVE_REMOTE_LCD
469 fb_remote_data *rdest = rdest, *rdest_t;
470#endif
471
472 SDEBUGF("scale_nearest sw=%d sh=%d dw=%d dh=%d remote=%d\n", sw, sh, dw,
473 dh, remote);
474 ly = 0;
475 iy = 0;
476 ye = 0;
477 xelim = sw == dw - 1 ? dw : dw - 1;
478 ixls = xelim ? sw / xelim : 1;
479 xels = sw - ixls * (xelim ? xelim : 1);
480 yelim = sh == dh - 1 ? dh : dh - 1;
481 iyls = yelim ? sh / yelim : 1;
482 yels = iyls * (yelim ? yelim : 1);
483 int delta = 127;
484#if LCD_PIXELFORMAT == HORIZONTAL_PACKING || \
485 (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_PIXELFORMAT == HORIZONTAL_PACKING)
486 uint8_t buf[4];
487 int data, oxt;
488#endif
489#if LCD_PIXELFORMAT == VERTICAL_PACKING || \
490 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED || \
491 (defined(HAVE_REMOTE_LCD) && \
492 (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED || \
493 LCD_REMOTE_PIXELFORMAT == VERTICAL_PACKING))
494 int bright, shift;
495#endif
496 for (oy = rowstart; oy != rowstop;) {
497 SDEBUGF("oy=%d iy=%d\n", oy, iy);
498 if (last_tick != current_tick)
499 {
500 yield();
501 last_tick = current_tick;
502 }
503 if (iy > ly && !skip_lines(args, iy - ly - 1))
504 return false;
505 ly = iy;
506
507 cur_part = store_part(args);
508 if (cur_part == NULL)
509 return false;
510
511 lx = 0;
512 ix = 0;
513 xe = 0;
514#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
515 if(!remote)
516#else 527#else
517 (void)remote; 528 uint32_t *qp = (uint32_t*)row_in;
518#endif
519#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
520 dest = (fb_data *)bitmap + fb_width * oy;
521#elif LCD_PIXELFORMAT == VERTICAL_PACKING
522 dest = (fb_data *)bitmap + fb_width * (oy >> 2);
523#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
524 dest = (fb_data *)bitmap + fb_width * (oy >> 3);
525#endif
526#ifdef HAVE_REMOTE_LCD
527#ifndef HAVE_LCD_COLOR
528 else
529#endif
530 rdest = (fb_remote_data *)bitmap + fb_width * (oy >> 3);
531#endif
532 for (ox = 0; ox < dw; ox++) {
533 while (cur_part->len <= ix - lx)
534 {
535 lx += cur_part->len;
536 cur_part = store_part(args);
537 if (cur_part == NULL)
538 return false;
539 }
540 cur_part->len -= ix - lx;
541 cur_part->buf += ix - lx;
542 lx = ix;
543#if defined(HAVE_REMOTE_LCD) && !defined(HAVE_LCD_COLOR)
544 if(!remote)
545 {
546#endif 529#endif
530 SDEBUGF("output_row: y: %d in: %p\n",row, row_in);
531#if LCD_DEPTH == 2
547#if LCD_PIXELFORMAT == HORIZONTAL_PACKING 532#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
548 /* greyscale iPods */ 533 /* greyscale iPods */
549 buf[ox & 3] = brightness(*(cur_part->buf)); 534 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
550 if ((ox & 3) == 3 || ox == dw - 1) 535 int shift = 6;
551 { 536 int delta = 127;
552 dest_t = dest++; 537 unsigned bright;
553 oyt = oy; 538 unsigned data = 0;
554 yet = ye; 539
555 int xo = ox & ~3; 540 for (col = 0; col < ctx->bm->width; col++) {
556 while(yet < dh) 541 if (ctx->dither)
557 { 542 delta = DITHERXDY(col,dy);
543 bright = ((*qp++) + ctx->round) *
544 (uint64_t)ctx->divisor >> 32;
545 bright = (3 * bright + (bright >> 6) + delta) >> 8;
546 data |= (~bright & 3) << shift;
547 shift -= 2;
548 if (shift < 0) {
549 *dest++ = data;
558 data = 0; 550 data = 0;
559 for (oxt = 0; oxt < (ox & 3) + 1; oxt++) 551 shift = 6;
560 {
561 if (dither)
562 delta = dither_mat(oyt & 0xf, (xo + oxt) & 0xf);
563 p = (3 * buf[oxt] + (buf[oxt] >> 6) + delta) >> 8;
564 data |= (~p & 3) << ((3 - oxt) << 1);
565 }
566 *dest_t = data;
567 dest_t += rowstep * fb_width;
568 yet += sh;
569 oyt += rowstep;
570 } 552 }
571 } 553 }
554 if (shift < 6)
555 *dest++ = data;
572#elif LCD_PIXELFORMAT == VERTICAL_PACKING 556#elif LCD_PIXELFORMAT == VERTICAL_PACKING
573 /* iriver H1x0 */ 557 /* iriver H1x0 */
574 bright = brightness(*(cur_part->buf)); 558 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
575 dest_t = dest++; 559 (row >> 2);
576 oyt = oy; 560 int shift = 2 * (row & 3);
577 yet = ye; 561 int delta = 127;
578 while(yet < dh) 562 unsigned bright;
579 {
580 shift = (oyt & 3) << 1;
581 if (dither)
582 delta = dither_mat(oyt & 0xf, ox & 0xf);
583 563
584 p = (3 * bright + (bright >> 6) + delta) >> 8; 564 for (col = 0; col < ctx->bm->width; col++) {
585 *dest_t |= (~p & 3) << shift; 565 if (ctx->dither)
586 if ((rowstep > 0 && shift == 6) || shift == 0) 566 delta = DITHERXDY(col,dy);
587 dest_t += rowstep * fb_width; 567 bright = ((*qp++) + ctx->round) *
588 yet += sh; 568 (uint64_t)ctx->divisor >> 32;
589 oyt += rowstep; 569 bright = (3 * bright + (bright >> 6) + delta) >> 8;
570 *dest++ |= (~bright & 3) << shift;
590 } 571 }
591#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED 572#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
592 bright = brightness(*(cur_part->buf)); 573 /* iAudio M3 */
593 dest_t = dest++; 574 fb_data *dest = (fb_data *)ctx->bm->data + fb_width *
594 oyt = oy; 575 (row >> 3);
595 yet = ye; 576 int shift = row & 7;
596 while(yet < dh) 577 int delta = 127;
597 { 578 unsigned bright;
598 shift = oyt & 7;
599 if (dither)
600 delta = dither_mat(oyt & 0xf, ox & 0xf);
601 579
602 p = (3 * bright + (bright >> 6) + delta) >> 8; 580 for (col = 0; col < ctx->bm->width; col++) {
603 *dest_t |= vi_pat(p) << shift; 581 if (ctx->dither)
604 if ((rowstep > 0 && shift == 7) || shift == 0) 582 delta = DITHERXDY(col,dy);
605 dest_t += rowstep * fb_width; 583 bright = ((*qp++) + ctx->round) *
606 yet += sh; 584 (uint64_t)ctx->divisor >> 32;
607 oyt += rowstep; 585 bright = (3 * bright + (bright >> 6) + delta) >> 8;
586 *dest++ |= vi_pattern[bright] << shift;
608 } 587 }
609#endif /* LCD_PIXELFORMAT */ 588#endif /* LCD_PIXELFORMAT */
610#ifdef HAVE_REMOTE_LCD 589#elif LCD_DEPTH == 16
611#ifndef HAVE_LCD_COLOR 590 /* iriver h300, colour iPods, X5 */
612 } else 591 fb_data *dest = (fb_data *)ctx->bm->data + fb_width * row;
613#endif 592 int delta = 127;
614 { 593 unsigned r, g, b;
615#if LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED 594 struct uint32_rgb q0;
616 bright = brightness(*(cur_part->buf));
617 rdest_t = rdest++;
618 oyt = oy;
619 yet = ye;
620 while(yet < dh)
621 {
622 shift = oyt & 7;
623 if (dither)
624 delta = dither_mat(oyt & 0xf, ox & 0xf);
625 595
626 p = (3 * bright + (bright >> 6) + delta) >> 8; 596 for (col = 0; col < ctx->bm->width; col++) {
627 *rdest_t |= vi_pat(p) << shift; 597 if (ctx->dither)
628 if ((rowstep > 0 && shift == 7) || shift == 0) 598 delta = DITHERXDY(col,dy);
629 rdest_t += rowstep * fb_width; 599 q0 = *qp++;
630 yet += sh; 600 r = (q0.r + ctx->round) * (uint64_t)ctx->divisor >> 32;
631 oyt += rowstep; 601 g = (q0.g + ctx->round) * (uint64_t)ctx->divisor >> 32;
632 } 602 b = (q0.b + ctx->round) * (uint64_t)ctx->divisor >> 32;
633#else 603 r = (31 * r + (r >> 3) + delta) >> 8;
634 bright = brightness(*(cur_part->buf)); 604 g = (63 * g + (g >> 2) + delta) >> 8;
635 rdest_t = rdest++; 605 b = (31 * b + (b >> 3) + delta) >> 8;
636 oyt = oy; 606 *dest++ = LCD_RGBPACK_LCD(r, g, b);
637 yet = ye;
638 while(yet < dh)
639 {
640 shift = oyt & 7;
641 if (dither)
642 delta = dither_mat(oyt & 0xf, ox & 0xf);
643 p = (bright + delta) >> 8;
644 *rdest_t |= (~p & 1) << shift;
645 if ((rowstep > 0 && shift == 7) || shift == 0)
646 rdest_t += rowstep * fb_width;
647 yet += sh;
648 oyt += rowstep;
649 } 607 }
650#endif 608#endif /* LCD_DEPTH */
651 }
652#endif
653 xe += xels;
654 ix += ixls;
655 while (xe > xelim)
656 {
657 xe -= xelim;
658 ix += 1;
659 }
660 }
661 oy = oyt;
662 ye = yet - yels;
663 iy += iyls;
664 while (ye > yelim)
665 {
666 ye -= yelim;
667 iy += 1;
668 }
669 }
670 return true;
671} 609}
672#endif
673 610
674int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, 611int resize_on_load(struct bitmap *bm, bool dither, struct dim *src,
675 struct rowset *rset, bool remote, 612 struct rowset *rset, unsigned char *buf, unsigned int len,
676#ifdef HAVE_LCD_COLOR
677 unsigned char *buf, unsigned int len,
678#endif
679 struct img_part* (*store_part)(void *args), 613 struct img_part* (*store_part)(void *args),
680 bool (*skip_lines)(void *args, unsigned int lines),
681 void *args) 614 void *args)
682{ 615{
683 616
684#if defined(HAVE_LCD_COLOR) && !defined(HAVE_REMOTE_LCD) 617#ifdef HAVE_UPSCALER
685 (void)skip_lines; 618 const int sw = src->width;
619 const int sh = src->height;
620 const int dw = bm->width;
621 const int dh = bm->height;
686#endif 622#endif
623 int ret;
687#ifdef HAVE_LCD_COLOR 624#ifdef HAVE_LCD_COLOR
688#ifdef HAVE_REMOTE_LCD 625 unsigned int needed = sizeof(struct uint32_rgb) * 3 * bm->width;
689 if (!remote) 626#else
690#endif 627 unsigned int needed = sizeof(uint32_t) * 3 * bm->width;
691 {
692#ifdef HAVE_UPSCALER
693 const int sw = src->width;
694 const int sh = src->height;
695 const int dw = bm->width;
696 const int dh = bm->height;
697#endif 628#endif
698 int ret;
699 unsigned int needed = sizeof(struct uint32_rgb) * 2 * bm->width;
700#if MAX_SC_STACK_ALLOC 629#if MAX_SC_STACK_ALLOC
701 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ? 630 uint8_t sc_buf[(needed <= len || needed > MAX_SC_STACK_ALLOC) ?
702 0 : needed]; 631 0 : needed];
703 if (len && buf)
704#endif 632#endif
705 len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len, 633 len = (unsigned int)align_buffer(PUN_PTR(void**, &buf), len,
706 sizeof(uint32_t)); 634 sizeof(uint32_t));
707 if (needed > len) 635 if (needed > len)
708 { 636 {
709#if MAX_SC_STACK_ALLOC 637#if MAX_SC_STACK_ALLOC
710 if (needed > MAX_SC_STACK_ALLOC) 638 if (needed > MAX_SC_STACK_ALLOC)
711 { 639 {
712 DEBUGF("unable to allocate required buffer: %d needed, " 640 DEBUGF("unable to allocate required buffer: %d needed, "
713 "%d available, %d permitted from stack\n", 641 "%d available, %d permitted from stack\n",
714 needed, len, MAX_SC_STACK_ALLOC); 642 needed, len, MAX_SC_STACK_ALLOC);
715 return 0; 643 return 0;
716 } 644 }
717 if (sizeof(sc_buf) < needed) 645 if (sizeof(sc_buf) < needed)
718 { 646 {
719 DEBUGF("failed to allocate large enough buffer on stack: " 647 DEBUGF("failed to allocate large enough buffer on stack: "
720 "%d needed, only got %d", 648 "%d needed, only got %d",
721 needed, MAX_SC_STACK_ALLOC); 649 needed, MAX_SC_STACK_ALLOC);
722 return 0; 650 return 0;
723 } 651 }
724#else 652#else
725 DEBUGF("unable to allocate required buffer: %d needed, " 653 DEBUGF("unable to allocate required buffer: %d needed, "
726 "%d available\n", needed, len); 654 "%d available\n", needed, len);
727 return 0; 655 return 0;
728#endif 656#endif
729 } 657 }
730 658
731 bool (*h_scaler)(struct bitmap*, struct dim*, 659 struct scaler_context ctx;
732 struct uint32_rgb*, 660 cpu_boost(true);
733 struct scaler_context*, bool); 661 ctx.store_part = store_part;
734 struct scaler_context ctx; 662 ctx.args = args;
735 ctx.last_tick = current_tick;
736 cpu_boost(true);
737#ifdef HAVE_UPSCALER
738 if (sw > dw)
739 {
740#endif
741 h_scaler = scale_h_area;
742 scale_h_area_setup(bm, src, &ctx);
743#ifdef HAVE_UPSCALER
744 } else {
745 h_scaler = scale_h_linear;
746 scale_h_linear_setup(bm, src, &ctx);
747 }
748#endif
749 ctx.store_part = store_part;
750 ctx.args = args;
751#if MAX_SC_STACK_ALLOC 663#if MAX_SC_STACK_ALLOC
752 ctx.buf = needed > len ? sc_buf : buf; 664 ctx.buf = needed > len ? sc_buf : buf;
753#else 665#else
754 ctx.buf = buf; 666 ctx.buf = buf;
755#endif 667#endif
756 ctx.len = len; 668 ctx.len = len;
669 ctx.bm = bm;
670 ctx.src = src;
671 ctx.dither = dither;
672 ctx.output_row = output_row_native;
757#ifdef HAVE_UPSCALER 673#ifdef HAVE_UPSCALER
758 if (sh > dh) 674 if (sw > dw)
675 {
759#endif 676#endif
760 ret = scale_v_area(bm, dither, src, rset, h_scaler, &ctx); 677 ctx.h_scaler = scale_h_area;
678 scale_h_area_setup(&ctx);
761#ifdef HAVE_UPSCALER 679#ifdef HAVE_UPSCALER
762 else 680 } else {
763 ret = scale_v_linear(bm, dither, src, rset, h_scaler, &ctx); 681 ctx.h_scaler = scale_h_linear;
682 scale_h_linear_setup(&ctx);
683 }
764#endif 684#endif
765 cpu_boost(false); 685#ifdef HAVE_UPSCALER
766 if (!ret) 686 if (sh > dh)
767 return 0;
768 }
769#ifdef HAVE_REMOTE_LCD
770 else
771#endif 687#endif
772#endif /* HAVE_LCD_COLOR */ 688 ret = scale_v_area(rset, &ctx);
773#if !defined(HAVE_LCD_COLOR) || defined(HAVE_REMOTE_LCD) 689#ifdef HAVE_UPSCALER
774 { 690 else
775 if (!scale_nearest(bm, src, rset, remote, dither, store_part, 691 ret = scale_v_linear(rset, &ctx);
776 skip_lines, args)) 692#endif
777 return 0; 693 cpu_boost(false);
778 } 694 if (!ret)
779#endif /* !HAVE_LCD_COLOR || HAVE_REMOTE_LCD*/ 695 return 0;
780 return get_totalsize(bm, remote); 696 return BM_SIZE(bm->width,bm->height,bm->format,0);
781} 697}
diff --git a/apps/recorder/resize.h b/apps/recorder/resize.h
index 8a39db503a..451830742e 100644
--- a/apps/recorder/resize.h
+++ b/apps/recorder/resize.h
@@ -23,6 +23,7 @@
23 23
24#include "config.h" 24#include "config.h"
25#include "lcd.h" 25#include "lcd.h"
26#include "inttypes.h"
26 27
27/**************************************************************** 28/****************************************************************
28 * resize_on_load() 29 * resize_on_load()
@@ -45,16 +46,30 @@
45 46
46struct img_part { 47struct img_part {
47 int len; 48 int len;
49#if !defined(HAVE_LCD_COLOR) && \
50 (LCD_DEPTH > 1 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1))
51 uint8_t *buf;
52#else
48 struct uint8_rgb* buf; 53 struct uint8_rgb* buf;
54#endif
49}; 55};
50 56
51int resize_on_load(struct bitmap *bm, bool dither,
52 struct dim *src,
53 struct rowset *tmp_row, bool remote,
54#ifdef HAVE_LCD_COLOR 57#ifdef HAVE_LCD_COLOR
55 unsigned char *buf, unsigned int len, 58/* intermediate type used by the scaler for color output. greyscale version
59 uses uint32_t
60*/
61struct uint32_rgb {
62 uint32_t r;
63 uint32_t g;
64 uint32_t b;
65};
56#endif 66#endif
67
68int recalc_dimension(struct dim *dst, struct dim *src);
69
70int resize_on_load(struct bitmap *bm, bool dither,
71 struct dim *src, struct rowset *tmp_row,
72 unsigned char *buf, unsigned int len,
57 struct img_part* (*store_part)(void *args), 73 struct img_part* (*store_part)(void *args),
58 bool (*skip_lines)(void *args, unsigned int lines),
59 void *args); 74 void *args);
60#endif /* _RESIZE_H_ */ 75#endif /* _RESIZE_H_ */
diff --git a/firmware/export/lcd-remote.h b/firmware/export/lcd-remote.h
index 3c013d657a..01df5a7eab 100644
--- a/firmware/export/lcd-remote.h
+++ b/firmware/export/lcd-remote.h
@@ -48,13 +48,17 @@ int remote_type(void);
48#if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \ 48#if (LCD_REMOTE_PIXELFORMAT == VERTICAL_INTERLEAVED) \
49 || (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED) 49 || (LCD_REMOTE_PIXELFORMAT == HORIZONTAL_INTERLEAVED)
50typedef unsigned short fb_remote_data; 50typedef unsigned short fb_remote_data;
51#define FB_RDATA_SZ 2
51#else 52#else
52typedef unsigned char fb_remote_data; 53typedef unsigned char fb_remote_data;
54#define FB_RDATA_SZ 1
53#endif 55#endif
54#elif LCD_DEPTH <= 16 56#elif LCD_DEPTH <= 16
55typedef unsigned short fb_remote_data; 57typedef unsigned short fb_remote_data;
58#define FB_RDATA_SZ 2
56#else 59#else
57typedef unsigned long fb_remote_data; 60typedef unsigned long fb_remote_data;
61#define FB_RDATA_SZ 4
58#endif 62#endif
59 63
60/* common functions */ 64/* common functions */
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index ea5851e736..e435d174f2 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -75,13 +75,17 @@ struct viewport {
75#if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \ 75#if (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) \
76 || (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED) 76 || (LCD_PIXELFORMAT == HORIZONTAL_INTERLEAVED)
77typedef unsigned short fb_data; 77typedef unsigned short fb_data;
78#define FB_DATA_SZ 2
78#else 79#else
79typedef unsigned char fb_data; 80typedef unsigned char fb_data;
81#define FB_DATA_SZ 1
80#endif 82#endif
81#elif LCD_DEPTH <= 16 83#elif LCD_DEPTH <= 16
82typedef unsigned short fb_data; 84typedef unsigned short fb_data;
85#define FB_DATA_SZ 2
83#else /* LCD_DEPTH > 16 */ 86#else /* LCD_DEPTH > 16 */
84typedef unsigned long fb_data; 87typedef unsigned long fb_data;
88#define FB_DATA_SZ 4
85#endif /* LCD_DEPTH */ 89#endif /* LCD_DEPTH */
86 90
87#else /* LCD_CHARCELLS */ 91#else /* LCD_CHARCELLS */