A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 799 lines 25 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 by Dave Chapman 11 * Copyright (C) 2009 by Karl Kurbjun 12 * 13 * Rockbox driver for 16-bit colour LCDs 14 * 15 * This program is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU General Public License 17 * as published by the Free Software Foundation; either version 2 18 * of the License, or (at your option) any later version. 19 * 20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 * KIND, either express or implied. 22 * 23 ****************************************************************************/ 24 25#include <stdio.h> 26#include "config.h" 27 28#include "cpu.h" 29#include "lcd.h" 30#include "kernel.h" 31#include "thread.h" 32#include <stdlib.h> 33#include "string-extra.h" /* mem*() */ 34#include "file.h" 35#include "debug.h" 36#include "system.h" 37#include "font.h" 38#include "rbunicode.h" 39#include "bidi.h" 40#include "scroll_engine.h" 41 42/*#define LOGF_ENABLE*/ 43#include "logf.h" 44 45#define ROW_INC lcd_current_viewport->buffer->stride 46#define COL_INC 1 47 48extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[]; 49extern lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[]; 50#ifndef DISABLE_ALPHA_BITMAP 51static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, 52 const unsigned char *src, int src_x, 53 int src_y, int x, int y, 54 int width, int height, 55 int stride_image, int stride_src); 56#endif /* !DISABLE_ALPHA_BITMAP */ 57#include "lcd-color-common.c" 58#include "lcd-bitmap-common.c" 59 60 61/* Clear the current viewport */ 62void lcd_clear_viewport(void) 63{ 64 struct viewport *vp = lcd_current_viewport; 65 fb_data *dst, *dst_end; 66 int x, y, width, height; 67 int len, step; 68 69 x = vp->x; 70 y = vp->y; 71 width = vp->width; 72 height = vp->height; 73 74 len = STRIDE_MAIN(width, height); 75 step = STRIDE_MAIN(ROW_INC, COL_INC); 76 77 dst = FBADDR(x, y); 78 dst_end = FBADDR(x + width - 1 , y + height - 1); 79 80 if (vp->drawmode & DRMODE_INVERSEVID) 81 { 82 fb_data px = FB_SCALARPACK(vp->fg_pattern); 83 do 84 { 85 fb_data *end = dst + len; 86 do { 87 *dst++ = px; 88 } while (dst < end); 89 dst += step - len; 90 } 91 while (dst <= dst_end); 92 } 93 else 94 { 95 if (!lcd_backdrop) 96 { 97 fb_data px = FB_SCALARPACK(vp->bg_pattern); 98 do 99 { 100 fb_data *end = dst + len; 101 do { 102 *dst++ = px; 103 } while (dst < end); 104 dst += step - len; 105 } 106 while (dst <= dst_end); 107 } 108 else 109 { 110 do 111 { 112 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), 113 len * sizeof(fb_data)); 114 dst += step; 115 } 116 while (dst <= dst_end); 117 } 118 } 119 120 if (vp == &default_vp) 121 lcd_scroll_stop(); 122 else 123 lcd_scroll_stop_viewport(vp); 124 125 vp->flags &= ~(VP_FLAG_VP_SET_CLEAN); 126} 127 128/*** low-level drawing functions ***/ 129 130static void ICODE_ATTR setpixel(fb_data *address) 131{ 132 *address = FB_SCALARPACK(lcd_current_viewport->fg_pattern); 133} 134 135static void ICODE_ATTR clearpixel(fb_data *address) 136{ 137 *address = FB_SCALARPACK(lcd_current_viewport->bg_pattern); 138} 139 140static void ICODE_ATTR clearimgpixel(fb_data *address) 141{ 142 *address = *(fb_data *)((long)address + lcd_backdrop_offset); 143} 144 145static void ICODE_ATTR flippixel(fb_data *address) 146{ 147 unsigned px = FB_UNPACK_SCALAR_LCD(*address); 148 *address = FB_SCALARPACK(~px); 149} 150 151static void ICODE_ATTR nopixel(fb_data *address) 152{ 153 (void)address; 154} 155 156lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_bgcolor[8] = { 157 flippixel, nopixel, setpixel, setpixel, 158 nopixel, clearpixel, nopixel, clearpixel 159}; 160 161lcd_fastpixelfunc_type* const lcd_fastpixelfuncs_backdrop[8] = { 162 flippixel, nopixel, setpixel, setpixel, 163 nopixel, clearimgpixel, nopixel, clearimgpixel 164}; 165 166lcd_fastpixelfunc_type* const * lcd_fastpixelfuncs = lcd_fastpixelfuncs_bgcolor; 167 168/* Fill a rectangular area */ 169void lcd_fillrect(int x, int y, int width, int height) 170{ 171 struct viewport *vp = lcd_current_viewport; 172 enum fill_opt fillopt = OPT_NONE; 173 fb_data *dst, *dst_end; 174 int len, step; 175 fb_data bits; 176 memset(&bits, 0, sizeof(fb_data)); 177 178 if (!clip_viewport_rect(vp, &x, &y, &width, &height, NULL, NULL)) 179 return; 180 181 /* drawmode and optimisation */ 182 if (vp->drawmode & DRMODE_INVERSEVID) 183 { 184 if (vp->drawmode & DRMODE_BG) 185 { 186 if (!lcd_backdrop) 187 { 188 fillopt = OPT_SET; 189 bits = FB_SCALARPACK(vp->bg_pattern); 190 } 191 else 192 fillopt = OPT_COPY; 193 } 194 } 195 else 196 { 197 if (vp->drawmode & DRMODE_FG) 198 { 199 fillopt = OPT_SET; 200 bits = FB_SCALARPACK(vp->fg_pattern); 201 } 202 } 203 if (fillopt == OPT_NONE && vp->drawmode != DRMODE_COMPLEMENT) 204 return; 205 206 dst = FBADDR(x, y); 207 dst_end = FBADDR(x + width - 1, y + height - 1); 208 209 len = STRIDE_MAIN(width, height); 210 step = STRIDE_MAIN(ROW_INC, COL_INC); 211 212 do 213 { 214 switch (fillopt) 215 { 216 case OPT_SET: 217 { 218 fb_data *start = dst; 219 fb_data *end = start + len; 220 do { 221 *start = bits; 222 } while (++start < end); 223 break; 224 } 225 226 case OPT_COPY: 227 memcpy(dst, (void *)((long)dst + lcd_backdrop_offset), 228 len * sizeof(fb_data)); 229 break; 230 231 case OPT_NONE: /* DRMODE_COMPLEMENT */ 232 { 233 fb_data *start = dst; 234 fb_data *end = start + len; 235 do { 236 flippixel(start); 237 } while (++start < end); 238 break; 239 } 240 } 241 dst += step; 242 } 243 while (dst <= dst_end); 244} 245 246/* About Rockbox' internal monochrome bitmap format: 247 * 248 * A bitmap contains one bit for every pixel that defines if that pixel is 249 * black (1) or white (0). Bits within a byte are arranged vertically, LSB 250 * at top. 251 * The bytes are stored in row-major order, with byte 0 being top left, 252 * byte 1 2nd from left etc. The first row of bytes defines pixel rows 253 * 0..7, the second row defines pixel row 8..15 etc. 254 * 255 * This is the mono bitmap format used on all other targets so far; the 256 * pixel packing doesn't really matter on a 8bit+ target. */ 257 258/* Draw a partial monochrome bitmap */ 259 260void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x, 261 int src_y, int stride, int x, int y, 262 int width, int height) 263{ 264 struct viewport *vp = lcd_current_viewport; 265 const unsigned char *src_end; 266 fb_data *dst, *dst_col; 267 unsigned dmask = 0x100; /* bit 8 == sentinel */ 268 int drmode = vp->drawmode; 269 int row; 270 271 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 272 return; 273 274 src += stride * (src_y >> 3) + src_x; /* move starting point */ 275 src_y &= 7; 276 src_end = src + width; 277 dst_col = FBADDR(x, y); 278 279 280 if (drmode & DRMODE_INVERSEVID) 281 { 282 dmask = 0x1ff; /* bit 8 == sentinel */ 283 drmode &= DRMODE_SOLID; /* mask out inversevid */ 284 } 285 286 /* Use extra bit to avoid if () in the switch-cases below */ 287 if ((drmode & DRMODE_BG) && lcd_backdrop) 288 drmode |= DRMODE_INT_BD; 289 290 /* go through each column and update each pixel */ 291 do 292 { 293 const unsigned char *src_col = src++; 294 unsigned data = (*src_col ^ dmask) >> src_y; 295 fb_data fg, bg; 296 uintptr_t bo; 297 298 dst = dst_col; 299 dst_col += COL_INC; 300 row = height; 301 302#define UPDATE_SRC do { \ 303 data >>= 1; \ 304 if (data == 0x001) { \ 305 src_col += stride; \ 306 data = *src_col ^ dmask; \ 307 } \ 308 } while (0) 309 310 switch (drmode) 311 { 312 case DRMODE_COMPLEMENT: 313 do 314 { 315 if (data & 0x01) 316 flippixel(dst); 317 318 dst += ROW_INC; 319 UPDATE_SRC; 320 } 321 while (--row); 322 break; 323 324 case DRMODE_BG|DRMODE_INT_BD: 325 bo = lcd_backdrop_offset; 326 do 327 { 328 if (!(data & 0x01)) 329 *dst = *(fb_data *)((long)dst + bo); 330 331 dst += ROW_INC; 332 UPDATE_SRC; 333 } 334 while (--row); 335 break; 336 337 case DRMODE_BG: 338 bg = FB_SCALARPACK(vp->bg_pattern); 339 do 340 { 341 if (!(data & 0x01)) 342 *dst = bg; 343 344 dst += ROW_INC; 345 UPDATE_SRC; 346 } 347 while (--row); 348 break; 349 350 case DRMODE_FG: 351 fg = FB_SCALARPACK(vp->fg_pattern); 352 do 353 { 354 if (data & 0x01) 355 *dst = fg; 356 357 dst += ROW_INC; 358 UPDATE_SRC; 359 } 360 while (--row); 361 break; 362 363 case DRMODE_SOLID|DRMODE_INT_BD: 364 fg = FB_SCALARPACK(vp->fg_pattern); 365 bo = lcd_backdrop_offset; 366 do 367 { 368 *dst = (data & 0x01) ? fg 369 : *(fb_data *)((long)dst + bo); 370 dst += ROW_INC; 371 UPDATE_SRC; 372 } 373 while (--row); 374 break; 375 376 case DRMODE_SOLID: 377 fg = FB_SCALARPACK(vp->fg_pattern); 378 bg = FB_SCALARPACK(vp->bg_pattern); 379 do 380 { 381 *dst = (data & 0x01) ? fg : bg; 382 dst += ROW_INC; 383 UPDATE_SRC; 384 } 385 while (--row); 386 break; 387 } 388 } 389 while (src < src_end); 390} 391/* Draw a full monochrome bitmap */ 392void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) 393{ 394 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); 395} 396 397 398/* About Rockbox' internal alpha channel format (for ALPHA_COLOR_FONT_DEPTH == 2) 399 * 400 * For each pixel, 4bit of alpha information is stored in a byte-stream, 401 * so two pixels are packed into one byte. 402 * The lower nibble is the first pixel, the upper one the second. The stride is 403 * horizontal. E.g row0: pixel0: byte0[0:3], pixel1: byte0[4:7], pixel2: byte1[0:3],... 404 * The format is independant of the internal display orientation and color 405 * representation, as to support the same font files on all displays. 406 * The values go linear from 0 (fully opaque) to 15 (fully transparent) 407 * (note how this is the opposite of the alpha channel in the ARGB format). 408 * 409 * This might suggest that rows need to have an even number of pixels. 410 * However this is generally not the case. lcd_alpha_bitmap_part_mix() can deal 411 * with uneven colums (i.e. two rows can share one byte). And font files do 412 * exploit this. 413 * However, this is difficult to do for image files, especially bottom-up bitmaps, 414 * so lcd_bmp() do expect even rows. 415 */ 416 417#define ALPHA_COLOR_FONT_DEPTH 2 418#define ALPHA_COLOR_LOOKUP_SHIFT (1 << ALPHA_COLOR_FONT_DEPTH) 419#define ALPHA_COLOR_LOOKUP_SIZE ((1 << ALPHA_COLOR_LOOKUP_SHIFT) - 1) 420#define ALPHA_COLOR_PIXEL_PER_BYTE (8 >> ALPHA_COLOR_FONT_DEPTH) 421#define ALPHA_COLOR_PIXEL_PER_WORD (32 >> ALPHA_COLOR_FONT_DEPTH) 422 423/* This is based on SDL (src/video/SDL_RLEaccel.c) ALPHA_BLIT32_888() macro */ 424static inline fb_data blend_two_colors(unsigned c1, unsigned c2, unsigned a) 425{ 426 unsigned s = c1; 427 unsigned d = c2; 428 unsigned s1 = s & 0xff00ff; 429 unsigned d1 = d & 0xff00ff; 430 a += a >> (ALPHA_COLOR_LOOKUP_SHIFT - 1); 431 d1 = (d1 + ((s1 - d1) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00ff; 432 s &= 0xff00; 433 d &= 0xff00; 434 d = (d + ((s - d) * a >> ALPHA_COLOR_LOOKUP_SHIFT)) & 0xff00; 435 436 return FB_SCALARPACK(d1 | d); 437} 438 439/* Blend an image with an alpha channel 440 * if image is NULL, drawing will happen according to the drawmode 441 * src is the alpha channel (4bit per pixel) */ 442static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image, 443 const unsigned char *src, int src_x, 444 int src_y, int x, int y, 445 int width, int height, 446 int stride_image, int stride_src) 447{ 448 struct viewport *vp = lcd_current_viewport; 449 fb_data *dst, *dst_row; 450 unsigned dmask = 0x00000000; 451 int drmode = vp->drawmode; 452 453 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 454 return; 455 456 /* the following drawmode combinations are possible: 457 * 1) COMPLEMENT: just negates the framebuffer contents 458 * 2) BG and BG+backdrop: draws _only_ background pixels with either 459 * the background color or the backdrop (if any). The backdrop 460 * is an image in native lcd format 461 * 3) FG and FG+image: draws _only_ foreground pixels with either 462 * the foreground color or an image buffer. The image is in 463 * native lcd format 464 * 4) SOLID, SOLID+backdrop, SOLID+image, SOLID+backdrop+image, i.e. all 465 * possible combinations of 2) and 3). Draws both, fore- and background, 466 * pixels. The rules of 2) and 3) apply. 467 * 468 * INVERSEVID swaps fore- and background pixels, i.e. background pixels 469 * become foreground ones and vice versa. 470 */ 471 if (drmode & DRMODE_INVERSEVID) 472 { 473 dmask = 0xffffffff; 474 drmode &= DRMODE_SOLID; /* mask out inversevid */ 475 } 476 477 /* Use extra bits to avoid if () in the switch-cases below */ 478 if (image != NULL) 479 drmode |= DRMODE_INT_IMG; 480 481 if ((drmode & DRMODE_BG) && lcd_backdrop) 482 drmode |= DRMODE_INT_BD; 483 484 dst_row = FBADDR(x, y); 485 486 int col, row = height; 487 unsigned data, pixels; 488 unsigned skip_end = (stride_src - width); 489 unsigned skip_start = src_y * stride_src + src_x; 490 unsigned skip_start_image = STRIDE_MAIN(src_y * stride_image + src_x, 491 src_x * stride_image + src_y); 492 493#ifdef ALPHA_BITMAP_READ_WORDS 494 uint32_t *src_w = (uint32_t *)((uintptr_t)src & ~3); 495 skip_start += ALPHA_COLOR_PIXEL_PER_BYTE * ((uintptr_t)src & 3); 496 src_w += skip_start / ALPHA_COLOR_PIXEL_PER_WORD; 497 data = letoh32(*src_w++) ^ dmask; 498 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_WORD; 499#else 500 src += skip_start / ALPHA_COLOR_PIXEL_PER_BYTE; 501 data = *src ^ dmask; 502 pixels = skip_start % ALPHA_COLOR_PIXEL_PER_BYTE; 503#endif 504 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; 505#ifdef ALPHA_BITMAP_READ_WORDS 506 pixels = 8 - pixels; 507#endif 508 509 /* image is only accessed in DRMODE_INT_IMG cases, i.e. when non-NULL. 510 * Therefore NULL accesses are impossible and we can increment 511 * unconditionally (applies for stride at the end of the loop as well) */ 512 image += skip_start_image; 513 /* go through the rows and update each pixel */ 514 do 515 { 516 /* saving lcd_current_viewport->fg/bg_pattern and lcd_backdrop_offset into these 517 * temp vars just before the loop helps gcc to opimize the loop better 518 * (testing showed ~15% speedup) */ 519 unsigned fg, bg; 520 ptrdiff_t bo, img_offset; 521 col = width; 522 dst = dst_row; 523 dst_row += ROW_INC; 524#ifdef ALPHA_BITMAP_READ_WORDS 525#define UPDATE_SRC_ALPHA do { \ 526 if (--pixels) \ 527 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ 528 else \ 529 { \ 530 data = letoh32(*src_w++) ^ dmask; \ 531 pixels = ALPHA_COLOR_PIXEL_PER_WORD; \ 532 } \ 533 } while (0) 534#elif ALPHA_COLOR_PIXEL_PER_BYTE == 2 535#define UPDATE_SRC_ALPHA do { \ 536 if (pixels ^= 1) \ 537 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ 538 else \ 539 data = *(++src) ^ dmask; \ 540 } while (0) 541#else 542#define UPDATE_SRC_ALPHA do { \ 543 if (pixels = (++pixels % ALPHA_COLOR_PIXEL_PER_BYTE)) \ 544 data >>= ALPHA_COLOR_LOOKUP_SHIFT; \ 545 else \ 546 data = *(++src) ^ dmask; \ 547 } while (0) 548#endif 549 550 switch (drmode) 551 { 552 case DRMODE_COMPLEMENT: 553 do 554 { 555 unsigned px = FB_UNPACK_SCALAR_LCD(*dst); 556 *dst = blend_two_colors(px, ~px, 557 data & ALPHA_COLOR_LOOKUP_SIZE ); 558 dst += COL_INC; 559 UPDATE_SRC_ALPHA; 560 } 561 while (--col); 562 break; 563 case DRMODE_BG|DRMODE_INT_BD: 564 bo = lcd_backdrop_offset; 565 do 566 { 567 unsigned px = FB_UNPACK_SCALAR_LCD(*dst); 568 unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); 569 *dst = blend_two_colors(c, px, data & ALPHA_COLOR_LOOKUP_SIZE ); 570 dst += COL_INC; 571 image += STRIDE_MAIN(1, stride_image); 572 UPDATE_SRC_ALPHA; 573 } 574 while (--col); 575 break; 576 case DRMODE_BG: 577 bg = vp->bg_pattern; 578 do 579 { 580 unsigned px = FB_UNPACK_SCALAR_LCD(*dst); 581 *dst = blend_two_colors(bg, px, data & ALPHA_COLOR_LOOKUP_SIZE ); 582 dst += COL_INC; 583 UPDATE_SRC_ALPHA; 584 } 585 while (--col); 586 break; 587 case DRMODE_FG|DRMODE_INT_IMG: 588 img_offset = image - dst; 589 do 590 { 591 unsigned px1 = FB_UNPACK_SCALAR_LCD(*dst); 592 unsigned px2 = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); 593 *dst = blend_two_colors(px1, px2, data & ALPHA_COLOR_LOOKUP_SIZE ); 594 dst += COL_INC; 595 UPDATE_SRC_ALPHA; 596 } 597 while (--col); 598 break; 599 case DRMODE_FG: 600 fg = vp->fg_pattern; 601 do 602 { 603 unsigned px = FB_UNPACK_SCALAR_LCD(*dst); 604 *dst = blend_two_colors(px, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); 605 dst += COL_INC; 606 UPDATE_SRC_ALPHA; 607 } 608 while (--col); 609 break; 610 case DRMODE_SOLID|DRMODE_INT_BD: 611 bo = lcd_backdrop_offset; 612 fg = vp->fg_pattern; 613 do 614 { 615 unsigned c = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); 616 *dst = blend_two_colors(c, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); 617 dst += COL_INC; 618 UPDATE_SRC_ALPHA; 619 } 620 while (--col); 621 break; 622 case DRMODE_SOLID|DRMODE_INT_IMG: 623 bg = vp->bg_pattern; 624 img_offset = image - dst; 625 do 626 { 627 unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); 628 *dst = blend_two_colors(bg, c, data & ALPHA_COLOR_LOOKUP_SIZE ); 629 dst += COL_INC; 630 UPDATE_SRC_ALPHA; 631 } 632 while (--col); 633 break; 634 case DRMODE_SOLID|DRMODE_INT_BD|DRMODE_INT_IMG: 635 bo = lcd_backdrop_offset; 636 img_offset = image - dst; 637 do 638 { 639 unsigned px = FB_UNPACK_SCALAR_LCD(*(fb_data *)((uintptr_t)dst + bo)); 640 unsigned c = FB_UNPACK_SCALAR_LCD(*(dst + img_offset)); 641 *dst = blend_two_colors(px, c, data & ALPHA_COLOR_LOOKUP_SIZE ); 642 dst += COL_INC; 643 UPDATE_SRC_ALPHA; 644 } 645 while (--col); 646 break; 647 case DRMODE_SOLID: 648 bg = vp->bg_pattern; 649 fg = vp->fg_pattern; 650 do 651 { 652 *dst = blend_two_colors(bg, fg, data & ALPHA_COLOR_LOOKUP_SIZE ); 653 dst += COL_INC; 654 UPDATE_SRC_ALPHA; 655 } 656 while (--col); 657 break; 658 } 659#ifdef ALPHA_BITMAP_READ_WORDS 660 if (skip_end < pixels) 661 { 662 pixels -= skip_end; 663 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; 664 } else { 665 pixels = skip_end - pixels; 666 src_w += pixels / ALPHA_COLOR_PIXEL_PER_WORD; 667 pixels %= ALPHA_COLOR_PIXEL_PER_WORD; 668 data = letoh32(*src_w++) ^ dmask; 669 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; 670 pixels = 8 - pixels; 671 } 672#else 673 if (skip_end) 674 { 675 pixels += skip_end; 676 if (pixels >= ALPHA_COLOR_PIXEL_PER_BYTE) 677 { 678 src += pixels / ALPHA_COLOR_PIXEL_PER_BYTE; 679 pixels %= ALPHA_COLOR_PIXEL_PER_BYTE; 680 data = *src ^ dmask; 681 data >>= pixels * ALPHA_COLOR_LOOKUP_SHIFT; 682 } else 683 data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; 684 } 685#endif 686 687 image += STRIDE_MAIN(stride_image,1); 688 } while (--row); 689} 690 691/*** drawing functions ***/ 692 693/* Draw a horizontal line (optimised) */ 694void lcd_hline(int x1, int x2, int y) 695{ 696 struct viewport *vp = lcd_current_viewport; 697 int width; 698 fb_data *dst, *dst_end; 699 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[vp->drawmode]; 700 701 if (!clip_viewport_hline(vp, &x1, &x2, &y)) 702 return; 703 704 width = x2 - x1 + 1; 705 706 dst = FBADDR(x1, y); 707 dst_end = dst + width; 708 do 709 { 710 pfunc(dst); 711 } 712 while (++dst < dst_end); 713} 714 715/* Draw a vertical line (optimised) */ 716void lcd_vline(int x, int y1, int y2) 717{ 718 struct viewport *vp = lcd_current_viewport; 719 fb_data *dst, *dst_end; 720 lcd_fastpixelfunc_type *pfunc = lcd_fastpixelfuncs[vp->drawmode]; 721 722 if (!clip_viewport_vline(vp, &x, &y1, &y2)) 723 return; 724 725 dst = FBADDR(x, y1); 726 dst_end = dst + (y2 - y1) * LCD_WIDTH; 727 728 do 729 { 730 pfunc(dst); 731 dst += LCD_WIDTH; 732 } 733 while (dst <= dst_end); 734} 735 736/* Draw a partial native bitmap */ 737void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y, 738 int stride, int x, int y, int width, 739 int height) 740{ 741 struct viewport *vp = lcd_current_viewport; 742 fb_data *dst; 743 744 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 745 return; 746 747 src += stride * src_y + src_x; /* move starting point */ 748 dst = FBADDR(x, y); 749 750 do 751 { 752 memcpy(dst, src, width * sizeof(fb_data)); 753 src += stride; 754 dst += LCD_WIDTH; 755 } 756 while (--height > 0); 757} 758 759/* Draw a partial native bitmap with transparency and foreground colors */ 760void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x, 761 int src_y, int stride, int x, 762 int y, int width, int height) 763{ 764 struct viewport *vp = lcd_current_viewport; 765 fb_data *dst; 766 fb_data fg, transparent, replacewithfg; 767 768 if (!clip_viewport_rect(vp, &x, &y, &width, &height, &src_x, &src_y)) 769 return; 770 771 src += stride * src_y + src_x; /* move starting point */ 772 dst = FBADDR(x, y); 773 774 transparent = FB_SCALARPACK(TRANSPARENT_COLOR); 775 replacewithfg = FB_SCALARPACK(REPLACEWITHFG_COLOR); 776 fg = FB_SCALARPACK(vp->fg_pattern); 777#define CMP(c1, c2) (c1.r == c2.r && c1.g == c2.g && c1.b == c2.b) 778 779 do 780 { 781 const fb_data *src_row = src; 782 fb_data *dst_row = dst; 783 fb_data *row_end = dst_row + width; 784 do 785 { 786 fb_data data = *src_row++; 787 if (!CMP(data, transparent)) 788 { 789 if (CMP(data, replacewithfg)) 790 data = fg; 791 *dst_row = data; 792 } 793 } 794 while (++dst_row < row_end); 795 src += stride; 796 dst += LCD_WIDTH; 797 } 798 while (--height > 0); 799}