A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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}