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 Kevin Ferrare
11*
12* Fire demo plugin
13*
14* This program is free software; you can redistribute it and/or
15* modify it under the terms of the GNU General Public License
16* as published by the Free Software Foundation; either version 2
17* of the License, or (at your option) any later version.
18*
19* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20* KIND, either express or implied.
21*
22****************************************************************************/
23
24#include "plugin.h"
25#include "fixedpoint.h"
26#include "lib/helper.h"
27
28#include "lib/pluginlib_actions.h"
29
30#ifndef HAVE_LCD_COLOR
31#include "lib/grey.h"
32#endif
33static fb_data *lcd_fb = NULL;
34
35#if (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
36/* Archos has not enough plugin RAM for full-width fire :( */
37#define FIRE_WIDTH 106
38#define FIRE_XPOS 3
39#else
40#define FIRE_WIDTH LCD_WIDTH
41#define FIRE_XPOS 0
42#endif
43
44#ifndef HAVE_LCD_COLOR
45GREY_INFO_STRUCT
46 static unsigned char draw_buffer[FIRE_WIDTH];
47
48#endif
49
50/* Key assignement */
51const struct button_mapping* plugin_contexts[]= {
52 pla_main_ctx,
53#if defined(HAVE_REMOTE_LCD)
54 pla_remote_ctx,
55#endif
56};
57
58#define FIRE_QUIT PLA_CANCEL
59#define FIRE_SWITCH_FLAMES_TYPE PLA_LEFT
60#define FIRE_SWITCH_FLAMES_MOVING PLA_RIGHT
61
62#if (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
63 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
64 || (CONFIG_KEYPAD == IPOD_4G_PAD)
65#define FIRE_QUIT2 PLA_UP
66#else
67#define FIRE_QUIT2 PLA_EXIT
68#endif
69
70#ifdef HAVE_SCROLLWHEEL
71#define FIRE_INCREASE_MULT PLA_SCROLL_FWD
72#define FIRE_INCREASE_MULT_REP PLA_SCROLL_FWD_REPEAT
73#define FIRE_DECREASE_MULT PLA_SCROLL_BACK
74#define FIRE_DECREASE_MULT_REP PLA_SCROLL_BACK_REPEAT
75#else
76#define FIRE_INCREASE_MULT PLA_UP
77#define FIRE_INCREASE_MULT_REP PLA_UP_REPEAT
78#define FIRE_DECREASE_MULT PLA_DOWN
79#define FIRE_DECREASE_MULT_REP PLA_DOWN_REPEAT
80#endif
81
82#define MIN_FLAME_VALUE 0
83#define COOL_MAX (440/LCD_HEIGHT+2)
84
85#ifndef HAVE_LCD_COLOR
86static unsigned char palette[256];
87
88static void color_palette_init(unsigned char* palette)
89{
90 int i;
91 for(i=0;i<=160;i++)//palette[i]=(3/2)*i
92 palette[i]=(i*3)/2;
93
94 /* 'regular' fire doesn't exceed this value */
95 for(;i<=255;i++)//palette[i]=(3/20)*i+216
96 palette[i]=(i*3+20*217)/20;
97}
98#else
99
100static fb_data palette[256];
101
102/*
103 * Color palette generation algorithm taken from
104 * the "The Demo Effects Collection" GPL project
105 * Copyright (C) 2002 W.P. van Paassen
106 */
107static void color_palette_init(fb_data* palette)
108{
109 int i;
110 for (i = 0; i < 32; i++){
111 /* black to blue, 32 values*/
112 palette[i]=FB_RGBPACK(0, 0, 2*i);
113
114 /* blue to red, 32 values*/
115 palette[i + 32]=FB_RGBPACK(8*i, 0, 64 - 2*i);
116
117 /* red to yellow, 32 values*/
118 palette[i + 64]=FB_RGBPACK(255, 8*i, 0);
119
120 /* yellow to white, 162 values */
121 palette[i + 96]=FB_RGBPACK(255, 255, 0 + 4*i);
122 palette[i + 128]=FB_RGBPACK(255, 255, 64 + 4*i);
123 palette[i + 160]=FB_RGBPACK(255, 255, 128 + 4*i);
124 palette[i + 192]=FB_RGBPACK(255, 255, 192 + i);
125 palette[i + 224]=FB_RGBPACK(255, 255, 224 + i);
126 }
127#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
128 rb->lcd_pal256_update_pal(palette);
129#endif
130}
131
132#endif
133
134static void tab_init_rand(unsigned char *tab, unsigned int tab_size,
135 int rand_max)
136{
137 unsigned char *end = tab + tab_size;
138
139 while(tab < end)
140 *tab++ = (unsigned char)rb->rand() % rand_max;
141}
142
143struct fire {
144 unsigned char fire[LCD_HEIGHT+3][FIRE_WIDTH];
145 unsigned char cooling_map[LCD_HEIGHT][FIRE_WIDTH];
146 int flames_type;
147 bool moving;
148 unsigned int mult;
149};
150/* makes the instance a global variable since it's too big to fit on the target's stack */
151static struct fire fire;
152
153static inline void fire_convolve(struct fire* fire)
154{
155 unsigned int pixel_value;
156 unsigned int cooling_value;
157 unsigned char *ptr, *end, *cool;
158 unsigned int mult=fire->mult;
159
160 rb->yield();
161 /* Convolve the pixels and handle cooling (to add nice shapes effects later) */
162 cool = &fire->cooling_map[0][0];
163 ptr = &fire->fire[0][0];
164 end = ptr + LCD_HEIGHT*FIRE_WIDTH;
165
166 switch (fire->flames_type){
167 case 0:
168 do{
169 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
170 + ptr[2*FIRE_WIDTH] /* fire[y+2][x] */
171 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
172 + ptr[3*FIRE_WIDTH]; /* fire[y+3][x] */
173 pixel_value = FMULU(pixel_value, mult) >> 10;
174
175 cooling_value = *cool++;
176 if (cooling_value <= pixel_value)
177 pixel_value -= cooling_value;
178 /* else it's too cold, don't frost the pixels !!! */
179
180 if (pixel_value > 255)
181 pixel_value = 255;
182
183 *ptr++ = pixel_value;
184 }while (ptr < end);
185 break;
186
187 case 1:
188 mult -= 2;
189 do{
190 pixel_value = ptr[FIRE_WIDTH-1] /* fire[y+1][x-1] */
191 + ptr[FIRE_WIDTH] /* fire[y+1][x] */
192 + ptr[FIRE_WIDTH+1] /* fire[y+1][x+1] */
193 + ptr[2*FIRE_WIDTH]; /* fire[y+2][x] */
194 pixel_value = FMULU(pixel_value, mult) >> 10;
195
196 cooling_value = *cool++;
197 if (cooling_value <= pixel_value)
198 pixel_value -= cooling_value;
199 /* else it's too cold, don't frost the pixels !!! */
200
201 if (pixel_value > 255)
202 pixel_value = 255;
203
204 *ptr++ = pixel_value;
205 }while (ptr < end);
206 break;
207
208 default: /* We should never reach this */
209 break;
210 }
211 rb->yield();
212}
213
214static void fire_generate_bottom_seed(struct fire* fire)
215{
216 unsigned char *ptr, *end;
217 ptr = &fire->fire[LCD_HEIGHT][0];
218 end = ptr + FIRE_WIDTH;
219 do{
220 *ptr++ = (MIN_FLAME_VALUE + rb->rand() % (256-MIN_FLAME_VALUE));
221 }while (ptr < end);
222}
223
224static inline void fire_step(struct fire* fire)
225{
226 if(fire->moving){
227 /* Randomize the bottom line */
228 fire_generate_bottom_seed(fire);
229 /* Add here further effects like fire letters, ball ... */
230 }
231 fire_convolve(fire);
232}
233
234static void fire_init(struct fire* fire)
235{
236 fire->mult = 261;
237 fire->flames_type=0;
238 fire->moving=true;
239 rb->memset(&fire->fire[0][0], 0, sizeof(fire->fire));
240 tab_init_rand(&fire->cooling_map[0][0], LCD_HEIGHT*FIRE_WIDTH, COOL_MAX);
241 fire_generate_bottom_seed(fire);
242}
243
244static inline void fire_draw(struct fire* fire)
245{
246#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
247 rb->lcd_blit_pal256((unsigned char*)&fire->fire[0][0],0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
248#else
249 int y;
250 unsigned char *src = &fire->fire[0][0];
251
252#ifndef HAVE_LCD_COLOR
253 unsigned char *dest, *end;
254#else
255 fb_data *dest, *end;
256#endif
257
258 for (y = 0; y < LCD_HEIGHT; y++){
259#ifndef HAVE_LCD_COLOR
260 dest = draw_buffer;
261#else
262 dest = lcd_fb + LCD_WIDTH * y + FIRE_XPOS;
263#endif
264 end = dest + FIRE_WIDTH;
265
266 do
267 *dest++ = palette[*src++];
268 while (dest < end);
269#ifndef HAVE_LCD_COLOR
270 grey_ub_gray_bitmap(draw_buffer, 0, y, FIRE_WIDTH, 1);
271#endif
272 }
273#ifdef HAVE_LCD_COLOR
274 rb->lcd_update();
275#endif
276
277#endif
278}
279
280static void cleanup(void *parameter)
281{
282 (void)parameter;
283#ifdef HAVE_ADJUSTABLE_CPU_FREQ
284 rb->cpu_boost(false);
285#endif
286#ifndef HAVE_LCD_COLOR
287 grey_release();
288#endif
289
290 /* Turn on backlight timeout (revert to settings) */
291 backlight_use_settings();
292}
293
294
295#ifndef HAVE_LCD_COLOR
296static int init_grey(void)
297{
298 unsigned char *gbuf;
299 size_t gbuf_size = 0;
300
301 /* get the remainder of the plugin buffer */
302 gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
303
304 if (!grey_init(gbuf, gbuf_size, GREY_ON_COP,
305 FIRE_WIDTH, LCD_HEIGHT, NULL)){
306 rb->splash(HZ, "not enough memory");
307 return PLUGIN_ERROR;
308 }
309 /* switch on greyscale overlay */
310 grey_set_position(FIRE_XPOS, 0);
311 grey_show(true);
312 return PLUGIN_OK;
313}
314#endif
315
316int main(void)
317{
318 int action;
319
320#ifndef HAVE_LCD_COLOR
321 if(init_grey()!=PLUGIN_OK)
322 return(PLUGIN_ERROR);
323#endif
324 color_palette_init(palette);
325
326#ifdef HAVE_ADJUSTABLE_CPU_FREQ
327 rb->cpu_boost(true);
328#endif
329
330 fire_init(&fire);
331 while (true){
332 fire_step(&fire);
333 fire_draw(&fire);
334 rb->yield();
335
336 action = pluginlib_getaction(0, plugin_contexts,
337 ARRAYLEN(plugin_contexts));
338
339 switch(action){
340 case FIRE_QUIT:
341 case FIRE_QUIT2:
342 cleanup(NULL);
343 return PLUGIN_OK;
344
345 case FIRE_INCREASE_MULT:
346 ++fire.mult;
347 break;
348
349 case FIRE_DECREASE_MULT:
350 if (fire.mult > 0)
351 --fire.mult;
352 break;
353
354 case FIRE_SWITCH_FLAMES_TYPE:
355 fire.flames_type = (fire.flames_type + 1) % 2;
356 break;
357
358 case FIRE_SWITCH_FLAMES_MOVING:
359 fire.moving = !fire.moving;
360 break;
361
362 default:
363 if (rb->default_event_handler_ex(action, cleanup, NULL)
364 == SYS_USB_CONNECTED)
365 return PLUGIN_USB_CONNECTED;
366 }
367 }
368}
369
370/*************************** Plugin entry point ****************************/
371
372enum plugin_status plugin_start(const void* parameter)
373{
374 int ret;
375
376 (void)parameter;
377#if LCD_DEPTH > 1
378 rb->lcd_set_backdrop(NULL);
379#endif
380
381 /* Turn off backlight timeout */
382 backlight_ignore_timeout();
383
384#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
385 rb->lcd_set_mode(LCD_MODE_PAL256);
386#endif
387
388 struct viewport *vp_main = rb->lcd_set_viewport(NULL);
389 lcd_fb = vp_main->buffer->fb_ptr;
390 ret = main();
391
392#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
393 rb->lcd_set_mode(LCD_MODE_RGB565);
394#endif
395
396 return ret;
397}