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* Additional LCD routines not present in the rockbox core
11* Drawing functions
12*
13* Copyright (C) 2005 Jens Arnold
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 "plugin.h"
26
27#include "xlcd.h"
28
29/* sort the given coordinates by increasing x value */
30static void sort_points_by_increasing_x(int* x1, int* y1,
31 int* x2, int* y2,
32 int* x3, int* y3)
33{
34 int x, y;
35 if (*x1 > *x3)
36 {
37 if (*x2 < *x3) /* x2 < x3 < x1 */
38 {
39 x = *x1; *x1 = *x2; *x2 = *x3; *x3 = x;
40 y = *y1; *y1 = *y2; *y2 = *y3; *y3 = y;
41 }
42 else if (*x2 > *x1) /* x3 < x1 < x2 */
43 {
44 x = *x1; *x1 = *x3; *x3 = *x2; *x2 = x;
45 y = *y1; *y1 = *y3; *y3 = *y2; *y2 = y;
46 }
47 else /* x3 <= x2 <= x1 */
48 {
49 x = *x1; *x1 = *x3; *x3 = x;
50 y = *y1; *y1 = *y3; *y3 = y;
51 }
52 }
53 else
54 {
55 if (*x2 < *x1) /* x2 < x1 <= x3 */
56 {
57 x = *x1; *x1 = *x2; *x2 = x;
58 y = *y1; *y1 = *y2; *y2 = y;
59 }
60 else if (*x2 > *x3) /* x1 <= x3 < x2 */
61 {
62 x = *x2; *x2 = *x3; *x3 = x;
63 y = *y2; *y2 = *y3; *y3 = y;
64 }
65 /* else already sorted */
66 }
67}
68
69#define sort_points_by_increasing_y(x1, y1, x2, y2, x3, y3) \
70 sort_points_by_increasing_x(y1, x1, y2, x2, y3, x3)
71
72/* draw a filled triangle, using horizontal lines for speed */
73static void xlcd_filltriangle_horizontal(struct screen* display,
74 int x1, int y1,
75 int x2, int y2,
76 int x3, int y3)
77{
78 long fp_x1, fp_x2, fp_dx1, fp_dx2;
79 int y;
80 sort_points_by_increasing_y(&x1, &y1, &x2, &y2, &x3, &y3);
81
82 if (y1 < y3) /* draw */
83 {
84 fp_dx1 = ((x3 - x1) << 16) / (y3 - y1);
85 fp_x1 = (x1 << 16) + (1<<15) + (fp_dx1 >> 1);
86
87 if (y1 < y2) /* first part */
88 {
89 fp_dx2 = ((x2 - x1) << 16) / (y2 - y1);
90 fp_x2 = (x1 << 16) + (1<<15) + (fp_dx2 >> 1);
91 for (y = y1; y < y2; y++)
92 {
93 display->hline(fp_x1 >> 16, fp_x2 >> 16, y);
94 fp_x1 += fp_dx1;
95 fp_x2 += fp_dx2;
96 }
97 }
98 if (y2 < y3) /* second part */
99 {
100 fp_dx2 = ((x3 - x2) << 16) / (y3 - y2);
101 fp_x2 = (x2 << 16) + (1<<15) + (fp_dx2 >> 1);
102 for (y = y2; y < y3; y++)
103 {
104 display->hline(fp_x1 >> 16, fp_x2 >> 16, y);
105 fp_x1 += fp_dx1;
106 fp_x2 += fp_dx2;
107 }
108 }
109 }
110}
111
112/* draw a filled triangle, using vertical lines for speed */
113static void xlcd_filltriangle_vertical(struct screen* display,
114 int x1, int y1,
115 int x2, int y2,
116 int x3, int y3)
117{
118 long fp_y1, fp_y2, fp_dy1, fp_dy2;
119 int x;
120 sort_points_by_increasing_x(&x1, &y1, &x2, &y2, &x3, &y3);
121
122 if (x1 < x3) /* draw */
123 {
124 fp_dy1 = ((y3 - y1) << 16) / (x3 - x1);
125 fp_y1 = (y1 << 16) + (1<<15) + (fp_dy1 >> 1);
126
127 if (x1 < x2) /* first part */
128 {
129 fp_dy2 = ((y2 - y1) << 16) / (x2 - x1);
130 fp_y2 = (y1 << 16) + (1<<15) + (fp_dy2 >> 1);
131 for (x = x1; x < x2; x++)
132 {
133 display->vline(x, fp_y1 >> 16, fp_y2 >> 16);
134 fp_y1 += fp_dy1;
135 fp_y2 += fp_dy2;
136 }
137 }
138 if (x2 < x3) /* second part */
139 {
140 fp_dy2 = ((y3 - y2) << 16) / (x3 - x2);
141 fp_y2 = (y2 << 16) + (1<<15) + (fp_dy2 >> 1);
142 for (x = x2; x < x3; x++)
143 {
144 display->vline(x, fp_y1 >> 16, fp_y2 >> 16);
145 fp_y1 += fp_dy1;
146 fp_y2 += fp_dy2;
147 }
148 }
149 }
150}
151
152void xlcd_filltriangle(int x1, int y1,
153 int x2, int y2,
154 int x3, int y3)
155{
156 /* default is main screen */
157 xlcd_filltriangle_screen(rb->screens[SCREEN_MAIN],
158 x1, y1, x2, y2, x3, y3);
159}
160
161void xlcd_filltriangle_screen(struct screen* display,
162 int x1, int y1,
163 int x2, int y2,
164 int x3, int y3)
165{
166 if(display->pixel_format==HORIZONTAL_PACKING || display->depth>=8)
167 xlcd_filltriangle_horizontal(display, x1, y1, x2, y2, x3, y3);
168 else
169 xlcd_filltriangle_vertical(display, x1, y1, x2, y2, x3, y3);
170}
171
172static void xlcd_fillcircle_horizontal(struct screen* display,
173 int cx, int cy, int radius)
174{
175 int d = 3 - (radius * 2);
176 int x = 0;
177 int y = radius;
178 while(x <= y)
179 {
180 display->hline(cx - x, cx + x, cy + y);
181 display->hline(cx - x, cx + x, cy - y);
182 display->hline(cx - y, cx + y, cy + x);
183 display->hline(cx - y, cx + y, cy - x);
184 if(d < 0)
185 {
186 d += (x * 4) + 6;
187 }
188 else
189 {
190 d += ((x - y) * 4) + 10;
191 --y;
192 }
193 ++x;
194 }
195}
196
197static void xlcd_fillcircle_vertical(struct screen* display,
198 int cx, int cy, int radius)
199{
200 int d = 3 - (radius * 2);
201 int x = 0;
202 int y = radius;
203 while(x <= y)
204 {
205 display->vline(cx + x, cy + y, cy - y);
206 display->vline(cx - x, cy + y, cy - y);
207 display->vline(cy + x, cx + y, cx - y);
208 display->vline(cy - x, cx + y, cx - y);
209 if(d < 0)
210 {
211 d += (x * 4) + 6;
212 }
213 else
214 {
215 d += ((x - y) * 4) + 10;
216 --y;
217 }
218 ++x;
219 }
220}
221
222void xlcd_fillcircle_screen(struct screen* display,
223 int cx, int cy, int radius)
224{
225 if(display->pixel_format == HORIZONTAL_PACKING || display->depth >= 8)
226 xlcd_fillcircle_horizontal(display, cx, cy, radius);
227 else
228 xlcd_fillcircle_vertical(display, cx, cy, radius);
229}
230
231void xlcd_fillcircle(int cx, int cy, int radius)
232{
233 xlcd_fillcircle_screen(rb->screens[SCREEN_MAIN], cx, cy, radius);
234}
235
236void xlcd_drawcircle_screen(struct screen* display,
237 int cx, int cy, int radius)
238{
239 int d = 3 - (radius * 2);
240 int x = 0;
241 int y = radius;
242 while(x <= y)
243 {
244 display->drawpixel(cx + x, cy + y);
245 display->drawpixel(cx - x, cy + y);
246 display->drawpixel(cx + x, cy - y);
247 display->drawpixel(cx - x, cy - y);
248 display->drawpixel(cx + y, cy + x);
249 display->drawpixel(cx - y, cy + x);
250 display->drawpixel(cx + y, cy - x);
251 display->drawpixel(cx - y, cy - x);
252 if(d < 0)
253 {
254 d += (x * 4) + 6;
255 }
256 else
257 {
258 d += ((x - y) * 4) + 10;
259 --y;
260 }
261 ++x;
262 }
263}
264
265void xlcd_drawcircle(int cx, int cy, int radius)
266{
267 /* default is main screen */
268 xlcd_drawcircle_screen(rb->screens[SCREEN_MAIN], cx, cy, radius);
269}
270
271
272#if LCD_DEPTH >= 8 && LCD_DEPTH <= 16
273#if 0 /* unused functions, enable when needed */
274#if defined(HAVE_LCD_COLOR) && (LCD_DEPTH == 16)
275static const fb_data graylut[256] = {
276#if LCD_PIXELFORMAT == RGB565
277 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0821, 0x0821, 0x0841,
278 0x0841, 0x0841, 0x0841, 0x0861, 0x0861, 0x1062, 0x1062, 0x1082,
279 0x1082, 0x1082, 0x1082, 0x10a2, 0x10a2, 0x18a3, 0x18a3, 0x18c3,
280 0x18c3, 0x18c3, 0x18c3, 0x18e3, 0x18e3, 0x20e4, 0x20e4, 0x2104,
281 0x2104, 0x2104, 0x2104, 0x2124, 0x2124, 0x2124, 0x2925, 0x2945,
282 0x2945, 0x2945, 0x2945, 0x2965, 0x2965, 0x2965, 0x3166, 0x3186,
283 0x3186, 0x3186, 0x3186, 0x31a6, 0x31a6, 0x31a6, 0x39a7, 0x39c7,
284 0x39c7, 0x39c7, 0x39c7, 0x39e7, 0x39e7, 0x39e7, 0x41e8, 0x4208,
285 0x4208, 0x4208, 0x4208, 0x4228, 0x4228, 0x4228, 0x4a29, 0x4a49,
286 0x4a49, 0x4a49, 0x4a49, 0x4a69, 0x4a69, 0x4a69, 0x4a69, 0x528a,
287 0x528a, 0x528a, 0x528a, 0x52aa, 0x52aa, 0x52aa, 0x52aa, 0x5aab,
288 0x5acb, 0x5acb, 0x5acb, 0x5acb, 0x5aeb, 0x5aeb, 0x5aeb, 0x62ec,
289 0x630c, 0x630c, 0x630c, 0x630c, 0x632c, 0x632c, 0x632c, 0x6b2d,
290 0x6b4d, 0x6b4d, 0x6b4d, 0x6b4d, 0x6b6d, 0x6b6d, 0x6b6d, 0x6b6d,
291 0x738e, 0x738e, 0x738e, 0x738e, 0x73ae, 0x73ae, 0x73ae, 0x73ae,
292 0x7bcf, 0x7bcf, 0x7bcf, 0x7bcf, 0x7bef, 0x7bef, 0x7bef, 0x7bef,
293 0x8410, 0x8410, 0x8410, 0x8410, 0x8430, 0x8430, 0x8430, 0x8430,
294 0x8c51, 0x8c51, 0x8c51, 0x8c51, 0x8c71, 0x8c71, 0x8c71, 0x8c71,
295 0x9492, 0x9492, 0x9492, 0x9492, 0x94b2, 0x94b2, 0x94b2, 0x94b2,
296 0x94d2, 0x9cd3, 0x9cd3, 0x9cd3, 0x9cf3, 0x9cf3, 0x9cf3, 0x9cf3,
297 0x9d13, 0xa514, 0xa514, 0xa514, 0xa534, 0xa534, 0xa534, 0xa534,
298 0xa554, 0xad55, 0xad55, 0xad55, 0xad55, 0xad75, 0xad75, 0xad75,
299 0xad75, 0xb596, 0xb596, 0xb596, 0xb596, 0xb5b6, 0xb5b6, 0xb5b6,
300 0xb5b6, 0xb5d6, 0xbdd7, 0xbdd7, 0xbdd7, 0xbdf7, 0xbdf7, 0xbdf7,
301 0xbdf7, 0xbe17, 0xc618, 0xc618, 0xc618, 0xc638, 0xc638, 0xc638,
302 0xc638, 0xc658, 0xce59, 0xce59, 0xce59, 0xce79, 0xce79, 0xce79,
303 0xce79, 0xce99, 0xd69a, 0xd69a, 0xd69a, 0xd6ba, 0xd6ba, 0xd6ba,
304 0xd6ba, 0xd6da, 0xd6da, 0xdedb, 0xdedb, 0xdefb, 0xdefb, 0xdefb,
305 0xdefb, 0xdf1b, 0xdf1b, 0xe71c, 0xe71c, 0xe73c, 0xe73c, 0xe73c,
306 0xe73c, 0xe75c, 0xe75c, 0xef5d, 0xef5d, 0xef7d, 0xef7d, 0xef7d,
307 0xef7d, 0xef9d, 0xef9d, 0xf79e, 0xf79e, 0xf7be, 0xf7be, 0xf7be,
308 0xf7be, 0xf7de, 0xf7de, 0xffdf, 0xffdf, 0xffff, 0xffff, 0xffff
309#elif LCD_PIXELFORMAT == RGB565SWAPPED
310 0x0000, 0x0000, 0x0000, 0x2000, 0x2000, 0x2108, 0x2108, 0x4108,
311 0x4108, 0x4108, 0x4108, 0x6108, 0x6108, 0x6210, 0x6210, 0x8210,
312 0x8210, 0x8210, 0x8210, 0xa210, 0xa210, 0xa318, 0xa318, 0xc318,
313 0xc318, 0xc318, 0xc318, 0xe318, 0xe318, 0xe420, 0xe420, 0x0421,
314 0x0421, 0x0421, 0x0421, 0x2421, 0x2421, 0x2421, 0x2529, 0x4529,
315 0x4529, 0x4529, 0x4529, 0x6529, 0x6529, 0x6529, 0x6631, 0x8631,
316 0x8631, 0x8631, 0x8631, 0xa631, 0xa631, 0xa631, 0xa739, 0xc739,
317 0xc739, 0xc739, 0xc739, 0xe739, 0xe739, 0xe739, 0xe841, 0x0842,
318 0x0842, 0x0842, 0x0842, 0x2842, 0x2842, 0x2842, 0x294a, 0x494a,
319 0x494a, 0x494a, 0x494a, 0x694a, 0x694a, 0x694a, 0x694a, 0x8a52,
320 0x8a52, 0x8a52, 0x8a52, 0xaa52, 0xaa52, 0xaa52, 0xaa52, 0xab5a,
321 0xcb5a, 0xcb5a, 0xcb5a, 0xcb5a, 0xeb5a, 0xeb5a, 0xeb5a, 0xec62,
322 0x0c63, 0x0c63, 0x0c63, 0x0c63, 0x2c63, 0x2c63, 0x2c63, 0x2d6b,
323 0x4d6b, 0x4d6b, 0x4d6b, 0x4d6b, 0x6d6b, 0x6d6b, 0x6d6b, 0x6d6b,
324 0x8e73, 0x8e73, 0x8e73, 0x8e73, 0xae73, 0xae73, 0xae73, 0xae73,
325 0xcf7b, 0xcf7b, 0xcf7b, 0xcf7b, 0xef7b, 0xef7b, 0xef7b, 0xef7b,
326 0x1084, 0x1084, 0x1084, 0x1084, 0x3084, 0x3084, 0x3084, 0x3084,
327 0x518c, 0x518c, 0x518c, 0x518c, 0x718c, 0x718c, 0x718c, 0x718c,
328 0x9294, 0x9294, 0x9294, 0x9294, 0xb294, 0xb294, 0xb294, 0xb294,
329 0xd294, 0xd39c, 0xd39c, 0xd39c, 0xf39c, 0xf39c, 0xf39c, 0xf39c,
330 0x139d, 0x14a5, 0x14a5, 0x14a5, 0x34a5, 0x34a5, 0x34a5, 0x34a5,
331 0x54a5, 0x55ad, 0x55ad, 0x55ad, 0x55ad, 0x75ad, 0x75ad, 0x75ad,
332 0x75ad, 0x96b5, 0x96b5, 0x96b5, 0x96b5, 0xb6b5, 0xb6b5, 0xb6b5,
333 0xb6b5, 0xd6b5, 0xd7bd, 0xd7bd, 0xd7bd, 0xf7bd, 0xf7bd, 0xf7bd,
334 0xf7bd, 0x17be, 0x18c6, 0x18c6, 0x18c6, 0x38c6, 0x38c6, 0x38c6,
335 0x38c6, 0x58c6, 0x59ce, 0x59ce, 0x59ce, 0x79ce, 0x79ce, 0x79ce,
336 0x79ce, 0x99ce, 0x9ad6, 0x9ad6, 0x9ad6, 0xbad6, 0xbad6, 0xbad6,
337 0xbad6, 0xdad6, 0xdad6, 0xdbde, 0xdbde, 0xfbde, 0xfbde, 0xfbde,
338 0xfbde, 0x1bdf, 0x1bdf, 0x1ce7, 0x1ce7, 0x3ce7, 0x3ce7, 0x3ce7,
339 0x3ce7, 0x5ce7, 0x5ce7, 0x5def, 0x5def, 0x7def, 0x7def, 0x7def,
340 0x7def, 0x9def, 0x9def, 0x9ef7, 0x9ef7, 0xbef7, 0xbef7, 0xbef7,
341 0xbef7, 0xdef7, 0xdef7, 0xdfff, 0xdfff, 0xffff, 0xffff, 0xffff
342#endif /* LCD_PIXELFORMAT */
343};
344#endif /* HAVE_LCD_COLOR && LCD_DEPTH == 16 */
345
346/* Draw a partial greyscale bitmap, canonical 8 bit format */
347void xlcd_gray_bitmap_part(const unsigned char *src, int src_x, int src_y,
348 int stride, int x, int y, int width, int height)
349{
350 size_t dst_stride;
351 fb_data *lcd_fb = get_framebuffer(NULL, &dst_stride);
352
353 const unsigned char *src_end;
354 fb_data *dst;
355
356 /* nothing to draw? */
357 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
358 || (x + width <= 0) || (y + height <= 0))
359 return;
360
361 /* clipping */
362 if (x < 0)
363 {
364 width += x;
365 src_x -= x;
366 x = 0;
367 }
368 if (y < 0)
369 {
370 height += y;
371 src_y -= y;
372 y = 0;
373 }
374 if (x + width > LCD_WIDTH)
375 width = LCD_WIDTH - x;
376 if (y + height > LCD_HEIGHT)
377 height = LCD_HEIGHT - y;
378
379 src += stride * src_y + src_x; /* move starting point */
380 src_end = src + stride * height;
381 dst = lcd_fb + dst_stride * y + x;
382
383 do
384 {
385 const unsigned char *src_row = src;
386 const unsigned char *row_end = src_row + width;
387 fb_data *dst_row = dst;
388
389#ifdef HAVE_LCD_COLOR
390 do
391#if LCD_DEPTH == 16
392 *dst_row++ = graylut[*src_row++];
393#else
394 /* untested change because this function is completely unused */
395 *dst_row->r = *dst_row->g = *dst_row->b = *src_row++;
396 dst_row++;
397#endif
398 while (src_row < row_end);
399#endif
400
401 src += stride;
402 dst += dst_stride;
403 }
404 while (src < src_end);
405}
406
407/* Draw a full greyscale bitmap, canonical 8 bit format */
408void xlcd_gray_bitmap(const unsigned char *src, int x, int y, int width,
409 int height)
410{
411 xlcd_gray_bitmap_part(src, 0, 0, width, x, y, width, height);
412}
413#endif // unused functions
414
415#ifdef HAVE_LCD_COLOR
416/* Draw a partial colour bitmap, canonical 24 bit RGB format */
417void xlcd_color_bitmap_part(const unsigned char *src, int src_x, int src_y,
418 int stride, int x, int y, int width, int height)
419{
420 size_t dst_stride;
421 fb_data *lcd_fb = get_framebuffer(NULL, &dst_stride);
422
423 const unsigned char *src_end;
424 fb_data *dst;
425
426 /* nothing to draw? */
427 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
428 || (x + width <= 0) || (y + height <= 0))
429 return;
430
431 /* clipping */
432 if (x < 0)
433 {
434 width += x;
435 src_x -= x;
436 x = 0;
437 }
438 if (y < 0)
439 {
440 height += y;
441 src_y -= y;
442 y = 0;
443 }
444 if (x + width > LCD_WIDTH)
445 width = LCD_WIDTH - x;
446 if (y + height > LCD_HEIGHT)
447 height = LCD_HEIGHT - y;
448
449 src += 3 * (stride * src_y + src_x); /* move starting point */
450 src_end = src + 3 * stride * height;
451 dst = lcd_fb + dst_stride * y + x;
452
453 do
454 {
455 const unsigned char *src_row = src;
456 const unsigned char *row_end = src_row + 3 * width;
457 fb_data *dst_row = dst;
458
459 do
460 { /* only RGB565 and RGB565SWAPPED so far */
461 unsigned red = 31 * (*src_row++) + 127;
462 unsigned green = 63 * (*src_row++) + 127;
463 unsigned blue = 31 * (*src_row++) + 127;
464
465 red = (red + (red >> 8)) >> 8; /* approx red /= 255: */
466 green = (green + (green >> 8)) >> 8; /* approx green /= 255: */
467 blue = (blue + (blue >> 8)) >> 8; /* approx blue /= 255: */
468
469#if LCD_PIXELFORMAT == RGB565
470 *dst_row++ = (red << 11) | (green << 5) | blue;
471#elif LCD_PIXELFORMAT == RGB565SWAPPED
472 *dst_row++ = swap16((red << 11) | (green << 5) | blue);
473#endif
474 }
475 while (src_row < row_end);
476
477 src += 3 * stride;
478 dst += dst_stride;
479 }
480 while (src < src_end);
481}
482
483/* Draw a full colour bitmap, canonical 24 bit RGB format */
484void xlcd_color_bitmap(const unsigned char *src, int x, int y, int width,
485 int height)
486{
487 xlcd_color_bitmap_part(src, 0, 0, width, x, y, width, height);
488}
489#endif /* HAVE_LCD_COLOR */
490
491#endif /* LCD_DEPTH >= 8 */