diff options
author | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
---|---|---|
committer | Andrew Mahone <andrew.mahone@gmail.com> | 2008-12-26 07:03:22 +0000 |
commit | f7fa7e5ad537415f1f75b3a9c1a58eb925e10d04 (patch) | |
tree | ea469e428a756e4f4979be1b6f5a84179a2cc80f /apps/recorder | |
parent | 7428c7cc5b8462ed95683f707fe78609ce8208bf (diff) | |
download | rockbox-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
Diffstat (limited to 'apps/recorder')
-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 |
4 files changed, 718 insertions, 771 deletions
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_ */ |