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* New greyscale framework
11* Drawing functions
12*
13* This is a generic framework to display 129 shades of grey on low-depth
14* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
15*
16* Copyright (C) 2008 Jens Arnold
17*
18* This program is free software; you can redistribute it and/or
19* modify it under the terms of the GNU General Public License
20* as published by the Free Software Foundation; either version 2
21* of the License, or (at your option) any later version.
22*
23* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24* KIND, either express or implied.
25*
26****************************************************************************/
27
28#include "plugin.h"
29#include "grey.h"
30
31extern struct viewport _grey_default_vp;
32
33/*** low-level drawing functions ***/
34
35static void setpixel(unsigned char *address)
36{
37 *address = _grey_info.vp->fg_pattern;
38}
39
40static void clearpixel(unsigned char *address)
41{
42 *address = _grey_info.vp->bg_pattern;
43}
44
45static void flippixel(unsigned char *address)
46{
47 *address = ~(*address);
48}
49
50static void nopixel(unsigned char *address)
51{
52 (void)address;
53}
54
55void (* const _grey_pixelfuncs[8])(unsigned char *address) = {
56 flippixel, nopixel, setpixel, setpixel,
57 nopixel, clearpixel, nopixel, clearpixel
58};
59
60/*** Drawing functions ***/
61
62/* Clear the current viewport */
63void grey_clear_viewport(void)
64{
65 struct viewport *vp = _grey_info.vp;
66 int drawmode = vp->drawmode;
67 vp->drawmode = DRMODE_SOLID | DRMODE_INVERSEVID;
68 grey_fillrect(0, 0, vp->width, vp->height);
69 vp->drawmode = drawmode;
70}
71
72/* Clear the whole display */
73void grey_clear_display(void)
74{
75 struct viewport *vp = &_grey_default_vp;
76
77 int value = (vp->drawmode & DRMODE_INVERSEVID) ?
78 vp->fg_pattern : vp->bg_pattern;
79
80 rb->memset(_grey_info.curbuffer, value,
81 _GREY_MULUQ(_grey_info.cb_width, _grey_info.cb_height));
82}
83
84/* Set a single pixel */
85void grey_drawpixel(int x, int y)
86{
87 if (x >= _grey_info.clip_l && x < _grey_info.clip_r &&
88 y >= _grey_info.clip_t && y < _grey_info.clip_b)
89 {
90 int dst_stride = _grey_info.cb_width;
91 struct viewport *vp = _grey_info.vp;
92 _grey_pixelfuncs[vp->drawmode](
93 &_grey_info.curbuffer[
94 _GREY_MULUQ(dst_stride, vp->y - _grey_info.cb_y + y) +
95 vp->x - _grey_info.cb_x + x]);
96 }
97}
98
99/* Draw a line */
100void grey_drawline(int x1, int y1, int x2, int y2)
101{
102 struct viewport *vp = _grey_info.vp;
103 int numpixels;
104 int i;
105 int deltax, deltay;
106 int d, dinc1, dinc2;
107 int x, xinc1, xinc2;
108 int y, yinc1, yinc2;
109 void (*pfunc)(unsigned char *address) = _grey_pixelfuncs[vp->drawmode];
110 int dwidth;
111 int xoffs, yoffs;
112
113 deltax = abs(x2 - x1);
114 deltay = abs(y2 - y1);
115 xinc2 = 1;
116 yinc2 = 1;
117
118 if (deltax >= deltay)
119 {
120 numpixels = deltax;
121 d = 2 * deltay - deltax;
122 dinc1 = deltay * 2;
123 dinc2 = (deltay - deltax) * 2;
124 xinc1 = 1;
125 yinc1 = 0;
126 }
127 else
128 {
129 numpixels = deltay;
130 d = 2 * deltax - deltay;
131 dinc1 = deltax * 2;
132 dinc2 = (deltax - deltay) * 2;
133 xinc1 = 0;
134 yinc1 = 1;
135 }
136 numpixels++; /* include endpoints */
137
138 if (x1 > x2)
139 {
140 xinc1 = -xinc1;
141 xinc2 = -xinc2;
142 }
143
144 if (y1 > y2)
145 {
146 yinc1 = -yinc1;
147 yinc2 = -yinc2;
148 }
149
150 x = x1;
151 y = y1;
152
153 dwidth = _grey_info.cb_width;
154 xoffs = vp->x - _grey_info.cb_x;
155 yoffs = vp->y - _grey_info.cb_y;
156
157 for (i = 0; i < numpixels; i++)
158 {
159 if (x >= _grey_info.clip_l && x < _grey_info.clip_r &&
160 y >= _grey_info.clip_t && y < _grey_info.clip_b)
161 {
162 pfunc(&_grey_info.curbuffer[_GREY_MULUQ(dwidth, yoffs + y) +
163 xoffs + x]);
164 }
165
166 if (d < 0)
167 {
168 d += dinc1;
169 x += xinc1;
170 y += yinc1;
171 }
172 else
173 {
174 d += dinc2;
175 x += xinc2;
176 y += yinc2;
177 }
178 }
179}
180
181/* Draw a horizontal line (optimised) */
182void grey_hline(int x1, int x2, int y)
183{
184 struct viewport *vp = _grey_info.vp;
185 int x;
186 int value = 0;
187 unsigned char *dst;
188 bool fillopt = false;
189 int dwidth;
190
191 /* direction flip */
192 if (x2 < x1)
193 {
194 x = x1;
195 x1 = x2;
196 x2 = x;
197 }
198
199 /* nothing to draw? */
200 if (y < _grey_info.clip_t || y >= _grey_info.clip_b ||
201 x1 >= _grey_info.clip_r || x2 < _grey_info.clip_l)
202 return;
203
204 /* drawmode and optimisation */
205 if (vp->drawmode & DRMODE_INVERSEVID)
206 {
207 if (vp->drawmode & DRMODE_BG)
208 {
209 fillopt = true;
210 value = vp->bg_pattern;
211 }
212 }
213 else
214 {
215 if (vp->drawmode & DRMODE_FG)
216 {
217 fillopt = true;
218 value = vp->fg_pattern;
219 }
220 }
221 if (!fillopt && vp->drawmode != DRMODE_COMPLEMENT)
222 return;
223
224 /* clipping */
225 if (x1 < _grey_info.clip_l)
226 x1 = _grey_info.clip_l;
227 if (x2 >= _grey_info.clip_r)
228 x2 = _grey_info.clip_r - 1;
229
230 dwidth = _grey_info.cb_width;
231 dst = &_grey_info.curbuffer[
232 _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y) +
233 vp->x - _grey_info.cb_x + x1];
234
235 if (fillopt)
236 rb->memset(dst, value, x2 - x1 + 1);
237 else /* DRMODE_COMPLEMENT */
238 {
239 unsigned char *dst_end = dst + x2 - x1;
240 do
241 *dst = ~(*dst);
242 while (++dst <= dst_end);
243 }
244}
245
246/* Draw a vertical line (optimised) */
247void grey_vline(int x, int y1, int y2)
248{
249 struct viewport *vp = _grey_info.vp;
250 int y;
251 unsigned char *dst, *dst_end;
252 void (*pfunc)(unsigned char *address);
253 int dwidth;
254
255 /* direction flip */
256 if (y2 < y1)
257 {
258 y = y1;
259 y1 = y2;
260 y2 = y;
261 }
262
263 /* nothing to draw? */
264 if (x < _grey_info.clip_l || x >= _grey_info.clip_r ||
265 y1 >= _grey_info.clip_b || y2 < _grey_info.clip_t)
266 return;
267
268 /* clipping */
269 if (y1 < _grey_info.clip_t)
270 y1 = _grey_info.clip_t;
271 if (y2 >= _grey_info.clip_b)
272 y2 = _grey_info.clip_b - 1;
273
274 dwidth = _grey_info.cb_width;
275 pfunc = _grey_pixelfuncs[vp->drawmode];
276 dst = &_grey_info.curbuffer[
277 _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y1) +
278 vp->x - _grey_info.cb_x + x];
279
280 dst_end = dst + _GREY_MULUQ(dwidth, y2 - y1);
281 do
282 {
283 pfunc(dst);
284 dst += dwidth;
285 }
286 while (dst <= dst_end);
287}
288
289/* Draw a filled triangle */
290void grey_filltriangle(int x1, int y1, int x2, int y2, int x3, int y3)
291{
292 int x, y;
293 long fp_x1, fp_x2, fp_dx1, fp_dx2;
294
295 /* sort vertices by increasing y value */
296 if (y1 > y3)
297 {
298 if (y2 < y3) /* y2 < y3 < y1 */
299 {
300 x = x1; x1 = x2; x2 = x3; x3 = x;
301 y = y1; y1 = y2; y2 = y3; y3 = y;
302 }
303 else if (y2 > y1) /* y3 < y1 < y2 */
304 {
305 x = x1; x1 = x3; x3 = x2; x2 = x;
306 y = y1; y1 = y3; y3 = y2; y2 = y;
307 }
308 else /* y3 <= y2 <= y1 */
309 {
310 x = x1; x1 = x3; x3 = x;
311 y = y1; y1 = y3; y3 = y;
312 }
313 }
314 else
315 {
316 if (y2 < y1) /* y2 < y1 <= y3 */
317 {
318 x = x1; x1 = x2; x2 = x;
319 y = y1; y1 = y2; y2 = y;
320 }
321 else if (y2 > y3) /* y1 <= y3 < y2 */
322 {
323 x = x2; x2 = x3; x3 = x;
324 y = y2; y2 = y3; y3 = y;
325 }
326 /* else already sorted */
327 }
328
329 if (y1 < y3) /* draw */
330 {
331 fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
332 fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
333
334 if (y1 < y2) /* first part */
335 {
336 fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
337 fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
338 for (y = y1; y < y2; y++)
339 {
340 grey_hline(fp_x1 >> 16, fp_x2 >> 16, y);
341 fp_x1 += fp_dx1;
342 fp_x2 += fp_dx2;
343 }
344 }
345 if (y2 < y3) /* second part */
346 {
347 fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
348 fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
349 for (y = y2; y < y3; y++)
350 {
351 grey_hline(fp_x1 >> 16, fp_x2 >> 16, y);
352 fp_x1 += fp_dx1;
353 fp_x2 += fp_dx2;
354 }
355 }
356 }
357}
358
359/* Draw a rectangular box */
360void grey_drawrect(int x, int y, int width, int height)
361{
362 if ((width <= 0) || (height <= 0))
363 return;
364
365 int x2 = x + width - 1;
366 int y2 = y + height - 1;
367
368 grey_vline(x, y, y2);
369 grey_vline(x2, y, y2);
370 grey_hline(x, x2, y);
371 grey_hline(x, x2, y2);
372}
373
374/* Fill a rectangular area */
375void grey_fillrect(int x, int y, int width, int height)
376{
377 struct viewport *vp = _grey_info.vp;
378 int value = 0;
379 unsigned char *dst, *dst_end;
380 bool fillopt = false;
381 int dwidth;
382
383 /* drawmode and optimisation */
384 if (vp->drawmode & DRMODE_INVERSEVID)
385 {
386 if (vp->drawmode & DRMODE_BG)
387 {
388 fillopt = true;
389 value = vp->bg_pattern;
390 }
391 }
392 else
393 {
394 if (vp->drawmode & DRMODE_FG)
395 {
396 fillopt = true;
397 value = vp->fg_pattern;
398
399 }
400 }
401 if (!fillopt && vp->drawmode != DRMODE_COMPLEMENT)
402 return;
403
404 /* clipping */
405 if (x < _grey_info.clip_l)
406 {
407 width += x - _grey_info.clip_l;
408 x = _grey_info.clip_l;
409 }
410
411 if (x + width > _grey_info.clip_r)
412 width = _grey_info.clip_r - x;
413
414 if (width <= 0)
415 return;
416
417 if (y < _grey_info.clip_t)
418 {
419 height += y - _grey_info.clip_t;
420 y = _grey_info.clip_t;
421 }
422
423 if (y + height > _grey_info.clip_b)
424 height = _grey_info.clip_b - y;
425
426 if (height <= 0)
427 return;
428
429 dwidth = _grey_info.cb_width;
430 dst = &_grey_info.curbuffer[
431 _GREY_MULUQ(dwidth, _grey_info.vp->y - _grey_info.cb_y + y) +
432 _grey_info.vp->x - _grey_info.cb_x + x];
433 dst_end = dst + _GREY_MULUQ(dwidth, height);
434
435 do
436 {
437 if (fillopt)
438 rb->memset(dst, value, width);
439 else /* DRMODE_COMPLEMENT */
440 {
441 unsigned char *dst_row = dst;
442 unsigned char *row_end = dst_row + width;
443
444 do
445 *dst_row = ~(*dst_row);
446 while (++dst_row < row_end);
447 }
448 dst += dwidth;
449 }
450 while (dst < dst_end);
451}
452
453/* About Rockbox' internal monochrome bitmap format:
454 *
455 * A bitmap contains one bit for every pixel that defines if that pixel is
456 * foreground (1) or background (0). Bits within a byte are arranged
457 * vertically, LSB at top.
458 * The bytes are stored in row-major order, with byte 0 being top left,
459 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
460 * 0..7, the second row defines pixel row 8..15 etc. */
461
462/* Draw a partial monochrome bitmap */
463void grey_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
464 int stride, int x, int y, int width, int height)
465{
466 struct viewport *vp = _grey_info.vp;
467 const unsigned char *src_end;
468 unsigned char *dst, *dst_end;
469 unsigned dmask = 0x100; /* bit 8 == sentinel */
470 int drmode = vp->drawmode;
471 int dwidth;
472
473 /* clipping */
474 if (x < _grey_info.clip_l)
475 {
476 int dx = x - _grey_info.clip_l;
477 width += dx;
478 src_x -= dx;
479 x = _grey_info.clip_l;
480 }
481
482 if (x + width > _grey_info.clip_r)
483 width = _grey_info.clip_r - x;
484
485 if (width <= 0)
486 return;
487
488 if (y < _grey_info.clip_t)
489 {
490 int dy = y - _grey_info.clip_t;
491 height += dy;
492 src_y += dy;
493 y = _grey_info.clip_t;
494 }
495
496 if (y + height > _grey_info.clip_b)
497 height = _grey_info.clip_b - y;
498
499 if (height <= 0)
500 return;
501
502 src += _GREY_MULUQ(stride, src_y >> 3) + src_x; /* move starting point */
503 src_y &= 7;
504 src_end = src + width;
505 dwidth = _grey_info.cb_width;
506 dst = &_grey_info.curbuffer[
507 _GREY_MULUQ(dwidth, vp->y - _grey_info.cb_y + y) +
508 vp->x - _grey_info.cb_x + x];
509 dst_end = dst + _GREY_MULUQ(dwidth, height);
510
511 if (drmode & DRMODE_INVERSEVID)
512 {
513 dmask = 0x1ff; /* bit 8 == sentinel */
514 drmode &= DRMODE_SOLID; /* mask out inversevid */
515 }
516
517 do
518 {
519 const unsigned char *src_col = src++;
520 unsigned char *dst_col = dst++;
521 unsigned data = (*src_col ^ dmask) >> src_y;
522 int fg, bg;
523
524#define UPDATE_SRC do { \
525 data >>= 1; \
526 if (data == 0x001) { \
527 src_col += stride; \
528 data = *src_col ^ dmask; \
529 } \
530 } while (0)
531
532 switch (drmode)
533 {
534 case DRMODE_COMPLEMENT:
535 do
536 {
537 if (data & 0x01)
538 *dst_col = ~(*dst_col);
539
540 dst_col += dwidth;
541 UPDATE_SRC;
542 }
543 while (dst_col < dst_end);
544 break;
545
546 case DRMODE_BG:
547 bg = vp->bg_pattern;
548 do
549 {
550 if (!(data & 0x01))
551 *dst_col = bg;
552
553 dst_col += dwidth;
554 UPDATE_SRC;
555 }
556 while (dst_col < dst_end);
557 break;
558
559 case DRMODE_FG:
560 fg = vp->fg_pattern;
561 do
562 {
563 if (data & 0x01)
564 *dst_col = fg;
565
566 dst_col += dwidth;
567 UPDATE_SRC;
568 }
569 while (dst_col < dst_end);
570 break;
571
572 case DRMODE_SOLID:
573 fg = vp->fg_pattern;
574 bg = vp->bg_pattern;
575 do
576 {
577 *dst_col = (data & 0x01) ? fg : bg;
578 dst_col += dwidth;
579 UPDATE_SRC;
580 }
581 while (dst_col < dst_end);
582 break;
583 }
584 }
585 while (src < src_end);
586}
587
588/* Draw a full monochrome bitmap */
589void grey_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
590{
591 grey_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
592}
593
594/* Draw a partial greyscale bitmap, canonical format */
595void grey_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
596 int stride, int x, int y, int width, int height)
597{
598 unsigned char *dst, *dst_end;
599 int dwidth;
600
601 /* clipping */
602 if (x < _grey_info.clip_l)
603 {
604 int dx = x - _grey_info.clip_l;
605 width += dx;
606 src_x -= dx;
607 x = _grey_info.clip_l;
608 }
609
610 if (x + width > _grey_info.clip_r)
611 width = _grey_info.clip_r - x;
612
613 if (width <= 0)
614 return;
615
616 if (y < 0)
617 {
618 int dy = y - _grey_info.clip_t;
619 height += dy;
620 src_y -= dy;
621 y = _grey_info.clip_t;
622 }
623
624 if (y + height > _grey_info.clip_b)
625 height = _grey_info.clip_b - y;
626
627 if (height <= 0)
628 return;
629
630 dwidth = _grey_info.cb_width;
631 src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */
632 dst = &_grey_info.curbuffer[
633 _GREY_MULUQ(dwidth, _grey_info.vp->y - _grey_info.cb_y + y) +
634 _grey_info.vp->x - _grey_info.cb_x + x];
635 dst_end = dst + _GREY_MULUQ(dwidth, height);
636
637 do
638 {
639 rb->memcpy(dst, src, width);
640 dst += dwidth;
641 src += stride;
642 }
643 while (dst < dst_end);
644}
645
646/* Draw a full greyscale bitmap, canonical format */
647void grey_gray_bitmap(const unsigned char *src, int x, int y, int width,
648 int height)
649{
650 grey_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
651}
652
653/* Put a string at a given pixel position, skipping first ofs pixel columns */
654void grey_putsxyofs(int x, int y, int ofs, const unsigned char *str)
655{
656 ucschar_t ch;
657 ucschar_t *ucs;
658 struct font* pf;
659
660 if (_grey_info.clip_b <= _grey_info.clip_t)
661 return;
662
663 pf = rb->font_get(_grey_info.vp->font);
664 ucs = rb->bidi_l2v(str, 1);
665
666 while ((ch = *ucs++) != 0 && x < _grey_info.clip_r)
667 {
668 int width;
669 const unsigned char *bits;
670
671 /* get proportional width and glyph bits */
672 width = rb->font_get_width(pf, ch);
673
674 if (ofs > width)
675 {
676 ofs -= width;
677 continue;
678 }
679
680 bits = rb->font_get_bits(pf, ch);
681
682 grey_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
683
684 x += width - ofs;
685 ofs = 0;
686 }
687}
688
689/* Put a string at a given pixel position */
690void grey_putsxy(int x, int y, const unsigned char *str)
691{
692 grey_putsxyofs(x, y, 0, str);
693}
694
695/*** Unbuffered drawing functions ***/
696
697/* Clear the greyscale display (sets all pixels to white) */
698void grey_ub_clear_display(void)
699{
700 struct viewport *vp = &_grey_default_vp;
701 int value = _grey_info.gvalue[(vp->drawmode & DRMODE_INVERSEVID) ?
702 vp->fg_pattern : vp->bg_pattern];
703
704 rb->memset(_grey_info.values, value,
705 _GREY_MULUQ(_grey_info.width, _grey_info.height));
706#ifdef SIMULATOR
707 rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
708 _grey_info.width, _grey_info.height);
709#endif
710}
711
712/* Assembler optimised helper function for copying a single line to the
713 * greyvalue buffer. */
714void _grey_line1(int width, unsigned char *dst, const unsigned char *src,
715 const unsigned char *lut);
716
717/* Draw a partial greyscale bitmap, canonical format */
718void grey_ub_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
719 int stride, int x, int y, int width, int height)
720{
721 int yc, ye;
722 unsigned char *dst;
723
724 /* nothing to draw? */
725 if ((width <= 0) || (height <= 0) || (x >= _grey_info.width)
726 || (y >= _grey_info.height) || (x + width <= 0) || (y + height <= 0))
727 return;
728
729 /* clipping */
730 if (x < 0)
731 {
732 width += x;
733 src_x -= x;
734 x = 0;
735 }
736 if (y < 0)
737 {
738 height += y;
739 src_y -= y;
740 y = 0;
741 }
742 if (x + width > _grey_info.width)
743 width = _grey_info.width - x;
744 if (y + height > _grey_info.height)
745 height = _grey_info.height - y;
746
747 src += _GREY_MULUQ(stride, src_y) + src_x; /* move starting point */
748 yc = y;
749 ye = y + height;
750 dst = _grey_info.values + (x << _GREY_BSHIFT);
751
752 do
753 {
754#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
755 int idx = _GREY_MULUQ(_grey_info.width, yc);
756#else /* vertical packing or vertical interleaved */
757 int idx = _GREY_MULUQ(_grey_info.width, yc & ~_GREY_BMASK)
758 + (~yc & _GREY_BMASK);
759#endif /* LCD_PIXELFORMAT */
760
761#if ((LCD_PIXELFORMAT == VERTICAL_PACKING) && (LCD_DEPTH == 2) && defined(CPU_COLDFIRE)) \
762 || ((LCD_PIXELFORMAT == VERTICAL_INTERLEAVED) && defined(CPU_COLDFIRE))
763 _grey_line1(width, dst + idx, src, _grey_info.gvalue);
764#else
765 unsigned char *dst_row = dst + idx;
766 const unsigned char *src_row = src;
767 const unsigned char *src_end = src + width;
768
769 do
770 {
771 *dst_row = _grey_info.gvalue[*src_row++];
772 dst_row += _GREY_BSIZE;
773 }
774 while (src_row < src_end);
775#endif
776
777 src += stride;
778 }
779 while (++yc < ye);
780#ifdef SIMULATOR
781 rb->sim_lcd_ex_update_rect(_grey_info.x + x, _grey_info.y + y,
782 width, height);
783#endif
784}
785
786/* Draw a full greyscale bitmap, canonical format */
787void grey_ub_gray_bitmap(const unsigned char *src, int x, int y, int width,
788 int height)
789{
790 grey_ub_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
791}
792
793static void output_row_grey_8(uint32_t row, void * row_in,
794 struct scaler_context *ctx)
795{
796 uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
797 rb->memcpy(dest, row_in, ctx->bm->width);
798}
799
800static void output_row_grey_32(uint32_t row, void * row_in,
801 struct scaler_context *ctx)
802{
803 int col;
804 uint32_t *qp = (uint32_t*)row_in;
805 uint8_t *dest = (uint8_t*)ctx->bm->data + ctx->bm->width * row;
806 for (col = 0; col < ctx->bm->width; col++)
807 *dest++ = SC_OUT(*qp++, ctx);
808}
809
810static unsigned int get_size_grey(struct bitmap *bm)
811{
812 return bm->width * bm->height;
813}
814
815const struct custom_format format_grey = {
816 .output_row_8 = output_row_grey_8,
817 .output_row_32 = output_row_grey_32,
818 .get_size = get_size_grey
819};