1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Zakk Roberts
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include "oldmenuapi.h"
25 static struct plugin_api
* rb
;
28 * FIREWORKS.C by ZAKK ROBERTS
29 * Rockbox plugin simulating a fireworks display.
30 * Supports all bitmap LCDs, fully scalable.
31 * Currently disabled for Archos Recorder - runs too slow.
34 /* All sorts of keymappings.. */
35 #if (CONFIG_KEYPAD == IRIVER_H300_PAD) || (CONFIG_KEYPAD == IRIVER_H100_PAD)
36 #define BTN_MENU BUTTON_OFF
37 #define BTN_FIRE BUTTON_SELECT
38 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
39 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
40 #define BTN_MENU BUTTON_MENU
41 #define BTN_FIRE BUTTON_SELECT
42 #elif (CONFIG_KEYPAD == RECORDER_PAD)
43 #define BTN_MENU BUTTON_OFF
44 #define BTN_FIRE BUTTON_PLAY
45 #elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
46 #define BTN_MENU BUTTON_OFF
47 #define BTN_FIRE BUTTON_SELECT
48 #elif (CONFIG_KEYPAD == ONDIO_PAD)
49 #define BTN_MENU BUTTON_MENU
50 #define BTN_FIRE BUTTON_UP
51 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
52 #define BTN_MENU BUTTON_POWER
53 #define BTN_FIRE BUTTON_SELECT
54 #elif (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
55 #define BTN_MENU BUTTON_MODE
56 #define BTN_FIRE BUTTON_SELECT
57 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
58 #define BTN_MENU BUTTON_MENU
59 #define BTN_FIRE BUTTON_SELECT
60 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
61 (CONFIG_KEYPAD == SANSA_C200_PAD)
62 #define BTN_MENU BUTTON_POWER
63 #define BTN_FIRE BUTTON_SELECT
64 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
65 #define BTN_MENU BUTTON_POWER
66 #define BTN_FIRE BUTTON_PLAY
69 /* The lowdown on source terminology:
70 * a ROCKET is launched from the LCD bottom.
71 * FIREWORKs are ejected from the rocket when it explodes. */
73 #define MAX_ROCKETS 40
74 #define ROCKET_LIFE (LCD_HEIGHT/2)
75 #define ROCKET_LIFE_VAR (LCD_HEIGHT/4)
77 #define ROCKET_MOVEMENT_RANGE 4
78 #define ROCKET_TRAIL_PARTICLES 50
80 #define MAX_FIREWORKS 40
81 #define FIREWORK_MOVEMENT_RANGE 6
82 #define FIREWORK_SIZE 2
84 /* position, speed, "phase" (age), color of all fireworks */
85 int firework_xpoints
[MAX_ROCKETS
+1][MAX_FIREWORKS
];
86 int firework_ypoints
[MAX_ROCKETS
+1][MAX_FIREWORKS
];
87 int firework_xspeed
[MAX_ROCKETS
+1][MAX_FIREWORKS
];
88 int firework_yspeed
[MAX_ROCKETS
+1][MAX_FIREWORKS
];
89 int firework_phase
[MAX_ROCKETS
+1];
91 int firework_color
[MAX_ROCKETS
+1][MAX_FIREWORKS
];
94 /* position, speed, "phase" (age) of all rockets */
95 int rocket_xpos
[MAX_ROCKETS
+1];
96 int rocket_ypos
[MAX_ROCKETS
+1];
97 int rocket_xspeed
[MAX_ROCKETS
+1];
98 int rocket_yspeed
[MAX_ROCKETS
+1];
99 int rocket_phase
[MAX_ROCKETS
+1];
100 int rocket_targetphase
[MAX_ROCKETS
+1];
102 /* settings values. these should eventually be saved to
103 * disk. maybe a preset loading/saving system? */
104 int autofire_delay
= 0;
105 int particles_per_firework
= 2;
106 int particle_life
= 1;
108 int show_rockets
= 1;
109 int frames_per_second
= 4;
110 bool quit_plugin
= false;
113 * firework_colors = brightest firework color, used most of the time.
114 * DARK colors = fireworks are nearly burnt out.
115 * DARKER colors = fireworks are several frames away from burning out.
116 * DARKEST colors = fireworks are a couple frames from burning out. */
117 #ifdef HAVE_LCD_COLOR
118 static const unsigned firework_colors
[] = {
119 LCD_RGBPACK(0,255,64), LCD_RGBPACK(61,255,249), LCD_RGBPACK(255,200,61),
120 LCD_RGBPACK(217,22,217), LCD_RGBPACK(22,217,132), LCD_RGBPACK(67,95,254),
121 LCD_RGBPACK(151,84,213) };
123 static const unsigned firework_dark_colors
[] = {
124 LCD_RGBPACK(0,128,32), LCD_RGBPACK(30,128,128), LCD_RGBPACK(128,100,30),
125 LCD_RGBPACK(109,11,109), LCD_RGBPACK(11,109,66), LCD_RGBPACK(33,47,128),
126 LCD_RGBPACK(75,42,105) };
128 static const unsigned firework_darker_colors
[] = {
129 LCD_RGBPACK(0,64,16), LCD_RGBPACK(15,64,64), LCD_RGBPACK(64,50,15),
130 LCD_RGBPACK(55,5,55), LCD_RGBPACK(5,55,33), LCD_RGBPACK(16,24,64),
131 LCD_RGBPACK(38,21,52) };
133 static const unsigned firework_darkest_colors
[] = {
134 LCD_RGBPACK(0,32,8), LCD_RGBPACK(7,32,32), LCD_RGBPACK(32,25,7),
135 LCD_RGBPACK(27,2,27), LCD_RGBPACK(2,27,16), LCD_RGBPACK(8,12,32),
136 LCD_RGBPACK(19,10,26) };
138 #define EXPLOSION_COLOR LCD_RGBPACK(255,240,0)
142 static const struct opt_items autofire_delay_settings
[15] = {
160 int autofire_delay_values
[15] = {
161 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400 };
163 static const struct opt_items particle_settings
[8] = {
174 int particle_values
[8] = {
175 5, 10, 15, 20, 25, 30, 35, 40 };
177 static const struct opt_items particle_life_settings
[9] = {
178 { "20 cycles", NULL
},
179 { "30 cycles", NULL
},
180 { "40 cycles", NULL
},
181 { "50 cycles", NULL
},
182 { "60 cycles", NULL
},
183 { "70 cycles", NULL
},
184 { "80 cycles", NULL
},
185 { "90 cycles", NULL
},
186 { "100 cycles", NULL
}
189 int particle_life_values
[9] = {
190 20, 30, 40, 50, 60, 70, 80, 90, 100 };
192 static const struct opt_items gravity_settings
[4] = {
195 { "Moderate", NULL
},
199 int gravity_values
[4] = {
202 #ifdef HAVE_LCD_COLOR
204 static const struct opt_items rocket_settings
[3] = {
206 { "Yes (no trails)", NULL
},
207 { "Yes (with trails)", NULL
},
209 int rocket_values
[4] = {
214 static const struct opt_items rocket_settings
[2] = {
218 int rocket_values
[4] = {
223 static const struct opt_items fps_settings
[9] = {
235 int fps_values
[9] = {
236 20, 25, 30, 35, 40, 45, 50, 55, 60 };
238 static const struct menu_item items
[] = {
239 { "Start Demo", NULL
},
240 { "Auto-Fire", NULL
},
241 { "Particles Per Firework", NULL
},
242 { "Particle Life", NULL
},
244 { "Show Rockets", NULL
},
245 { "FPS (Speed)", NULL
},
249 /* called on startup. initializes all variables, etc */
254 for(j
=0; j
<MAX_ROCKETS
; j
++)
255 firework_phase
[j
] = -1;
258 /* called when a rocket hits its destination height.
259 * prepares all associated fireworks to be expelled. */
260 void init_explode(int x
, int y
, int firework
, int points
)
264 for(i
=0; i
<points
; i
++)
266 rb
->srand(*rb
->current_tick
* i
);
268 firework_xpoints
[firework
][i
] = x
;
269 firework_ypoints
[firework
][i
] = y
;
271 firework_xspeed
[firework
][i
] = (rb
->rand() % FIREWORK_MOVEMENT_RANGE
) - FIREWORK_MOVEMENT_RANGE
/2;
272 firework_yspeed
[firework
][i
] = (rb
->rand() % FIREWORK_MOVEMENT_RANGE
) - FIREWORK_MOVEMENT_RANGE
/2;
274 #ifdef HAVE_LCD_COLOR
275 firework_color
[firework
][i
] = rb
->rand() % 7;
280 /* called when a rocket is launched.
281 * prepares said rocket to start moving towards its destination. */
282 void init_rocket(int rocket
)
284 rb
->srand(*rb
->current_tick
);
286 rocket_xpos
[rocket
] = rb
->rand() % LCD_WIDTH
;
287 rocket_ypos
[rocket
] = LCD_HEIGHT
;
289 rocket_xspeed
[rocket
] = (rb
->rand() % ROCKET_MOVEMENT_RANGE
) - ROCKET_MOVEMENT_RANGE
/2;
290 rocket_yspeed
[rocket
] = 3;
292 rocket_targetphase
[rocket
] = (ROCKET_LIFE
+ (rb
->rand() % ROCKET_LIFE_VAR
)) / rocket_yspeed
[rocket
];
295 /* startup/configuration menu. */
296 void fireworks_menu(void)
299 bool menu_quit
= false;
301 rb
->lcd_setfont(FONT_UI
);
302 #ifdef HAVE_LCD_COLOR
303 rb
->lcd_set_background(LCD_BLACK
);
304 rb
->lcd_set_foreground(LCD_WHITE
);
306 rb
->lcd_clear_display();
309 m
= menu_init(rb
, items
, sizeof(items
) / sizeof(*items
),
310 NULL
, NULL
, NULL
, NULL
);
312 rb
->button_clear_queue();
316 result
= menu_show(m
);
321 rb
->lcd_setfont(FONT_SYSFIXED
);
323 #ifdef HAVE_LCD_COLOR
324 rb
->lcd_set_background(LCD_BLACK
);
325 rb
->lcd_set_foreground(LCD_WHITE
);
328 rb
->lcd_clear_display();
336 rb
->set_option("Auto-Fire", &autofire_delay
, INT
, autofire_delay_settings
, 15, NULL
);
340 rb
->set_option("Particles Per Firework", &particles_per_firework
, INT
, particle_settings
, 8, NULL
);
344 rb
->set_option("Particle Life", &particle_life
, INT
, particle_life_settings
, 9, NULL
);
348 rb
->set_option("Gravity", &gravity
, INT
, gravity_settings
, 4, NULL
);
352 rb
->set_option("Show Rockets", &show_rockets
, INT
, rocket_settings
, 3, NULL
);
356 rb
->set_option("FPS (Speed)", &frames_per_second
, INT
, fps_settings
, 9, NULL
);
369 /* this is the plugin entry point */
370 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
376 int j
, i
, autofire
=0;
378 int start_tick
, elapsed_tick
;
381 /* set everything up.. no BL timeout, no backdrop,
382 white-text-on-black-background. */
383 backlight_force_on(rb
); /* backlight control in lib/helper.c */
385 rb
->lcd_set_backdrop(NULL
);
386 rb
->lcd_set_background(LCD_BLACK
);
387 rb
->lcd_set_foreground(LCD_WHITE
);
390 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
396 start_tick
= *rb
->current_tick
;
400 rb
->lcd_clear_display();
402 /* loop through every possible rocket */
403 for(j
=0; j
<MAX_ROCKETS
; j
++)
405 /* if the current rocket is actually moving/"alive" then go on and
406 * move/update/explode it */
407 if(rocket_phase
[j
] > -1)
409 #ifdef HAVE_LCD_COLOR /* draw trail, if requested */
412 rb
->lcd_set_foreground(LCD_RGBPACK(128,128,128));
413 rb
->lcd_fillrect(rocket_xpos
[j
], rocket_ypos
[j
],
414 ROCKET_SIZE
, ROCKET_SIZE
);
415 rb
->lcd_set_foreground(LCD_RGBPACK(64,64,64));
416 rb
->lcd_fillrect(rocket_xpos
[j
]-rocket_xspeed
[j
], rocket_ypos
[j
]+rocket_yspeed
[j
],
417 ROCKET_SIZE
, ROCKET_SIZE
);
422 rocket_xpos
[j
] += rocket_xspeed
[j
];
423 rocket_ypos
[j
] -= rocket_yspeed
[j
];
425 #ifdef HAVE_LCD_COLOR
426 rb
->lcd_set_foreground(LCD_WHITE
);
428 if(show_rockets
==2 || show_rockets
==1)
429 rb
->lcd_fillrect(rocket_xpos
[j
], rocket_ypos
[j
],
430 ROCKET_SIZE
, ROCKET_SIZE
);
432 /* if(rocket isn't "there" yet) keep moving
433 * if(rocket IS there) explode it. */
434 if(rocket_phase
[j
] < rocket_targetphase
[j
])
438 rocket_phase
[j
] = -1;
440 firework_phase
[j
] = 0;
441 init_explode(rocket_xpos
[j
], rocket_ypos
[j
], j
, particle_values
[particles_per_firework
]);
445 /* and now onto the fireworks for this particular rocket... */
446 if(firework_phase
[j
] > -1)
448 for(i
=0; i
<particle_values
[particles_per_firework
]; i
++)
450 firework_xpoints
[j
][i
] += firework_xspeed
[j
][i
];
451 firework_ypoints
[j
][i
] += firework_yspeed
[j
][i
];
454 firework_ypoints
[j
][i
] += firework_phase
[j
]/gravity_values
[gravity
];
456 #ifdef HAVE_LCD_COLOR
457 rb
->lcd_set_foreground(firework_darkest_colors
[firework_color
[j
][i
]]);
458 rb
->lcd_fillrect(firework_xpoints
[j
][i
]-1,
459 firework_ypoints
[j
][i
]-1,
460 FIREWORK_SIZE
+2, FIREWORK_SIZE
+2);
462 if(firework_phase
[j
] < particle_life_values
[particle_life
]-10)
463 rb
->lcd_set_foreground(firework_colors
[firework_color
[j
][i
]]);
464 else if(firework_phase
[j
] < particle_life_values
[particle_life
]-7)
465 rb
->lcd_set_foreground(firework_dark_colors
[firework_color
[j
][i
]]);
466 else if(firework_phase
[j
] < particle_life_values
[particle_life
]-3)
467 rb
->lcd_set_foreground(firework_darker_colors
[firework_color
[j
][i
]]);
469 rb
->lcd_set_foreground(firework_darkest_colors
[firework_color
[j
][i
]]);
471 rb
->lcd_fillrect(firework_xpoints
[j
][i
],
472 firework_ypoints
[j
][i
],
473 FIREWORK_SIZE
, FIREWORK_SIZE
);
474 /* WIP - currently ugly explosion effect
475 #ifdef HAVE_LCD_COLOR
476 if(firework_phase[j] < 10)
478 rb->lcd_set_foreground(EXPLOSION_COLOR);
479 rb->lcd_fillrect(rocket_xpos[j]-firework_phase[j],
480 rocket_ypos[j]-firework_phase[j],
481 firework_phase[j]*2, firework_phase[j]*2);
486 #ifdef HAVE_LCD_COLOR
487 rb
->lcd_set_foreground(LCD_WHITE
);
490 /* firework at its destination age?
491 * no = keep aging; yes = delete it. */
492 if(firework_phase
[j
] < particle_life_values
[particle_life
])
495 firework_phase
[j
] = -1;
499 /* is autofire on? */
500 if(autofire_delay
!= 0)
502 elapsed_tick
= *rb
->current_tick
- start_tick
;
504 if(elapsed_tick
> autofire_delay_values
[autofire_delay
])
506 rocket_phase
[autofire
] = 0;
507 init_rocket(autofire
);
509 start_tick
= *rb
->current_tick
;
511 if(autofire
< MAX_ROCKETS
)
520 button
= rb
->button_get_w_tmo(HZ
/fps_values
[frames_per_second
]);
523 case BTN_MENU
: /* back to config menu */
527 case BTN_FIRE
: /* fire off rockets manually */
528 case BTN_FIRE
|BUTTON_REPEAT
:
529 if(thisrocket
< MAX_ROCKETS
)
534 rocket_phase
[thisrocket
] = 0;
535 init_rocket(thisrocket
);
539 /* Turn on backlight timeout (revert to settings) */
540 backlight_use_settings(rb
); /* backlight control in lib/helper.c */
542 #ifdef HAVE_ADJUSTABLE_CPU_FREQ