diff options
-rw-r--r-- | apps/plugin.h | 1 | ||||
-rw-r--r-- | apps/plugins/sliding_puzzle.c | 32 | ||||
-rw-r--r-- | apps/recorder/bmp.c | 323 | ||||
-rw-r--r-- | apps/recorder/bmp.h | 221 | ||||
-rw-r--r-- | apps/recorder/resize.c | 920 | ||||
-rw-r--r-- | apps/recorder/resize.h | 25 | ||||
-rw-r--r-- | firmware/export/lcd-remote.h | 4 | ||||
-rw-r--r-- | firmware/export/lcd.h | 4 |
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 |
25 | PLUGIN_HEADER | 24 | PLUGIN_HEADER |
@@ -258,13 +257,9 @@ static int num_font = FONT_UI; | |||
258 | static int moves_font = FONT_UI; | 257 | static int moves_font = FONT_UI; |
259 | static int moves_y = 0; | 258 | static int moves_y = 0; |
260 | 259 | ||
261 | #ifdef HAVE_LCD_COLOR | 260 | static unsigned char img_buf |
262 | static unsigned char *img_buf; | 261 | [BM_SCALED_SIZE(IMAGE_WIDTH,IMAGE_HEIGHT,FORMAT_NATIVE,0)] |
263 | static size_t buf_len; | 262 | __attribute__ ((aligned(16))); |
264 | #else | ||
265 | static 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 |
269 | static char albumart_path[MAX_PATH+1]; | 264 | static 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 | ||
621 | enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) | 613 | enum 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 |
128 | const unsigned char dither_matrix[16][16] = { | 128 | */ |
129 | { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 }, | 129 | const 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 | |||
333 | static 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) | ||
354 | static 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 | ||
380 | static inline int rgbcmp(struct uint8_rgb rgb1, struct uint8_rgb rgb2) | 333 | static 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 | ||
41 | struct uint8_rgb { | 37 | struct 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) |
59 | extern const unsigned char dither_matrix[16][16]; | 55 | extern const unsigned char dither_table[16]; |
60 | static 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 | */ | ||
66 | static inline unsigned brightness(struct uint8_rgb color) | 67 | static 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)) |
75 | extern const unsigned short vi_pattern[4]; | 81 | extern const unsigned short vi_pattern[4]; |
76 | static inline unsigned short vi_pat(unsigned int bright) | ||
77 | { | ||
78 | return vi_pattern[bright]; | ||
79 | } | ||
80 | #endif | 82 | #endif |
81 | 83 | ||
82 | static 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 | ||
126 | static 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 | ||
170 | static 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 | */ | ||
66 | int 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 | ||
87 | struct 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 | |||
93 | struct scaler_context { | 120 | struct 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 */ |
104 | static void scale_h_area_setup(struct bitmap *bm, struct dim *src, | 135 | static 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 */ |
114 | static bool scale_h_area(struct bitmap *bm, struct dim *src, | 143 | static 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 */ |
191 | static bool scale_v_area(struct bitmap *bm, bool dither, struct dim *src, | 250 | static 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 | */ |
275 | static void scale_h_linear_setup(struct bitmap *bm, struct dim *src, | 326 | static 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 */ |
284 | static bool scale_h_linear(struct bitmap *bm, struct dim *src, | 332 | static 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 */ |
360 | static bool scale_v_linear(struct bitmap *bm, bool dither, struct dim *src, | 447 | static 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 | 520 | void 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 */ | ||
441 | static 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 | ||
674 | int resize_on_load(struct bitmap *bm, bool dither, struct dim *src, | 611 | int 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 | ||
46 | struct img_part { | 47 | struct 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 | ||
51 | int 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 | */ | ||
61 | struct uint32_rgb { | ||
62 | uint32_t r; | ||
63 | uint32_t g; | ||
64 | uint32_t b; | ||
65 | }; | ||
56 | #endif | 66 | #endif |
67 | |||
68 | int recalc_dimension(struct dim *dst, struct dim *src); | ||
69 | |||
70 | int 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) |
50 | typedef unsigned short fb_remote_data; | 50 | typedef unsigned short fb_remote_data; |
51 | #define FB_RDATA_SZ 2 | ||
51 | #else | 52 | #else |
52 | typedef unsigned char fb_remote_data; | 53 | typedef 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 |
55 | typedef unsigned short fb_remote_data; | 57 | typedef unsigned short fb_remote_data; |
58 | #define FB_RDATA_SZ 2 | ||
56 | #else | 59 | #else |
57 | typedef unsigned long fb_remote_data; | 60 | typedef 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) |
77 | typedef unsigned short fb_data; | 77 | typedef unsigned short fb_data; |
78 | #define FB_DATA_SZ 2 | ||
78 | #else | 79 | #else |
79 | typedef unsigned char fb_data; | 80 | typedef unsigned char fb_data; |
81 | #define FB_DATA_SZ 1 | ||
80 | #endif | 82 | #endif |
81 | #elif LCD_DEPTH <= 16 | 83 | #elif LCD_DEPTH <= 16 |
82 | typedef unsigned short fb_data; | 84 | typedef unsigned short fb_data; |
85 | #define FB_DATA_SZ 2 | ||
83 | #else /* LCD_DEPTH > 16 */ | 86 | #else /* LCD_DEPTH > 16 */ |
84 | typedef unsigned long fb_data; | 87 | typedef 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 */ |