1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Zakk Roberts
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "lib/helper.h"
23 #include "lib/playback_control.h"
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
39 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
40 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
41 #define BTN_MENU BUTTON_MENU
42 #define BTN_FIRE BUTTON_SELECT
44 #elif (CONFIG_KEYPAD == RECORDER_PAD)
45 #define BTN_MENU BUTTON_OFF
46 #define BTN_FIRE BUTTON_PLAY
48 #elif (CONFIG_KEYPAD == ARCHOS_AV300_PAD)
49 #define BTN_MENU BUTTON_OFF
50 #define BTN_FIRE BUTTON_SELECT
52 #elif (CONFIG_KEYPAD == ONDIO_PAD)
53 #define BTN_MENU BUTTON_MENU
54 #define BTN_FIRE BUTTON_UP
56 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
57 #define BTN_MENU BUTTON_POWER
58 #define BTN_FIRE BUTTON_SELECT
60 #elif (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
61 #define BTN_MENU BUTTON_MODE
62 #define BTN_FIRE BUTTON_SELECT
64 #elif (CONFIG_KEYPAD == GIGABEAT_PAD) || \
65 (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
66 (CONFIG_KEYPAD == MROBE100_PAD)
67 #define BTN_MENU BUTTON_MENU
68 #define BTN_FIRE BUTTON_SELECT
70 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
71 (CONFIG_KEYPAD == SANSA_C200_PAD)
72 #define BTN_MENU BUTTON_POWER
73 #define BTN_FIRE BUTTON_SELECT
75 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
76 #define BTN_MENU (BUTTON_HOME|BUTTON_REPEAT)
77 #define BTN_FIRE BUTTON_SELECT
79 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
80 #define BTN_MENU BUTTON_POWER
81 #define BTN_FIRE BUTTON_PLAY
83 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
84 #define BTN_MENU BUTTON_RC_REC
85 #define BTN_FIRE BUTTON_RC_PLAY
87 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
88 #define BTN_MENU (BUTTON_MENU|BUTTON_REL)
90 #elif CONFIG_KEYPAD == IAUDIO67_PAD
91 #define BTN_MENU BUTTON_MENU
92 #define BTN_FIRE BUTTON_PLAY
94 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
95 #define BTN_MENU BUTTON_MENU
96 #define BTN_FIRE BUTTON_SELECT
98 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
99 #define BTN_MENU BUTTON_MENU
100 #define BTN_FIRE BUTTON_SELECT
102 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
103 #define BTN_MENU BUTTON_MENU
104 #define BTN_FIRE BUTTON_PLAY
106 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
107 #define BTN_MENU BUTTON_MENU
108 #define BTN_FIRE BUTTON_PLAY
110 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
111 #define BTN_MENU (BUTTON_MENU|BUTTON_REL)
113 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
114 #define BTN_MENU BUTTON_LEFT
115 #define BTN_FIRE BUTTON_PLAY
117 #elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
118 #define BTN_MENU BUTTON_MENU
119 #define BTN_FIRE BUTTON_OK
121 #elif (CONFIG_KEYPAD == MPIO_HD200_PAD)
122 #define BTN_MENU BUTTON_REC
123 #define BTN_FIRE BUTTON_PLAY
125 #elif (CONFIG_KEYPAD == MPIO_HD300_PAD)
126 #define BTN_MENU BUTTON_MENU
127 #define BTN_FIRE BUTTON_PLAY
129 #elif defined(HAVE_TOUCHSCREEN)
130 /* This is a touchscreen target */
132 #error No keymap defined!
135 #ifdef HAVE_TOUCHSCREEN
137 #define BTN_MENU (BUTTON_TOPLEFT|BUTTON_REL)
140 #define BTN_FIRE BUTTON_CENTER
144 /* The lowdown on source terminology:
145 * a ROCKET is launched from the LCD bottom.
146 * FIREWORKs are ejected from the rocket when it explodes. */
148 #define MAX_ROCKETS 40
149 #define ROCKET_LIFE (LCD_HEIGHT/2)
150 #define ROCKET_LIFE_VAR (LCD_HEIGHT/4)
151 #define ROCKET_SIZE 2
152 #define ROCKET_MOVEMENT_RANGE 4
153 #define ROCKET_TRAIL_PARTICLES 50
155 #define MAX_FIREWORKS 40
156 #define FIREWORK_MOVEMENT_RANGE 6
157 #define FIREWORK_SIZE 2
159 /* position, speed, "phase" (age), color of all fireworks */
160 int firework_xpoints
[MAX_ROCKETS
][MAX_FIREWORKS
];
161 int firework_ypoints
[MAX_ROCKETS
][MAX_FIREWORKS
];
162 int firework_xspeed
[MAX_ROCKETS
][MAX_FIREWORKS
];
163 int firework_yspeed
[MAX_ROCKETS
][MAX_FIREWORKS
];
164 int firework_phase
[MAX_ROCKETS
];
165 #ifdef HAVE_LCD_COLOR
166 int firework_color
[MAX_ROCKETS
][MAX_FIREWORKS
];
169 /* position, speed, "phase" (age) of all rockets */
170 int rocket_xpos
[MAX_ROCKETS
];
171 int rocket_ypos
[MAX_ROCKETS
];
172 int rocket_xspeed
[MAX_ROCKETS
];
173 int rocket_yspeed
[MAX_ROCKETS
];
174 int rocket_phase
[MAX_ROCKETS
];
175 int rocket_targetphase
[MAX_ROCKETS
];
177 /* settings values. these should eventually be saved to
178 * disk. maybe a preset loading/saving system? */
179 int autofire_delay
= 0;
180 int particles_per_firework
= 2;
181 int particle_life
= 1;
183 int show_rockets
= 1;
184 int frames_per_second
= 4;
185 bool quit_plugin
= false;
188 * firework_colors = brightest firework color, used most of the time.
189 * DARK colors = fireworks are nearly burnt out.
190 * DARKER colors = fireworks are several frames away from burning out.
191 * DARKEST colors = fireworks are a couple frames from burning out. */
192 #ifdef HAVE_LCD_COLOR
193 static const unsigned firework_colors
[] = {
194 LCD_RGBPACK(0,255,64), LCD_RGBPACK(61,255,249), LCD_RGBPACK(255,200,61),
195 LCD_RGBPACK(217,22,217), LCD_RGBPACK(22,217,132), LCD_RGBPACK(67,95,254),
196 LCD_RGBPACK(151,84,213) };
198 static const unsigned firework_dark_colors
[] = {
199 LCD_RGBPACK(0,128,32), LCD_RGBPACK(30,128,128), LCD_RGBPACK(128,100,30),
200 LCD_RGBPACK(109,11,109), LCD_RGBPACK(11,109,66), LCD_RGBPACK(33,47,128),
201 LCD_RGBPACK(75,42,105) };
203 static const unsigned firework_darker_colors
[] = {
204 LCD_RGBPACK(0,64,16), LCD_RGBPACK(15,64,64), LCD_RGBPACK(64,50,15),
205 LCD_RGBPACK(55,5,55), LCD_RGBPACK(5,55,33), LCD_RGBPACK(16,24,64),
206 LCD_RGBPACK(38,21,52) };
208 static const unsigned firework_darkest_colors
[] = {
209 LCD_RGBPACK(0,32,8), LCD_RGBPACK(7,32,32), LCD_RGBPACK(32,25,7),
210 LCD_RGBPACK(27,2,27), LCD_RGBPACK(2,27,16), LCD_RGBPACK(8,12,32),
211 LCD_RGBPACK(19,10,26) };
213 #define EXPLOSION_COLOR LCD_RGBPACK(255,240,0)
217 static const struct opt_items autofire_delay_settings
[15] = {
235 int autofire_delay_values
[15] = {
236 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400 };
238 static const struct opt_items particle_settings
[8] = {
249 int particle_values
[8] = {
250 5, 10, 15, 20, 25, 30, 35, 40 };
252 static const struct opt_items particle_life_settings
[9] = {
264 int particle_life_values
[9] = {
265 20, 30, 40, 50, 60, 70, 80, 90, 100 };
267 static const struct opt_items gravity_settings
[4] = {
274 int gravity_values
[4] = {
277 #ifdef HAVE_LCD_COLOR
279 static const struct opt_items rocket_settings
[3] = {
281 { "Yes (no trails)", -1 },
282 { "Yes (with trails)", -1 },
284 int rocket_values
[4] = {
289 static const struct opt_items rocket_settings
[2] = {
293 int rocket_values
[4] = {
298 static const struct opt_items fps_settings
[9] = {
310 int fps_values
[9] = {
311 20, 25, 30, 35, 40, 45, 50, 55, 60 };
313 MENUITEM_STRINGLIST(menu
, "Fireworks Menu", NULL
,
314 "Start Demo", "Auto-Fire", "Particles Per Firework",
315 "Particle Life", "Gravity", "Show Rockets",
316 "FPS (Speed)", "Playback Control", "Quit");
318 /* called on startup. initializes all variables, etc */
323 for(j
=0; j
<MAX_ROCKETS
; j
++)
325 rocket_phase
[j
] = -1;
326 firework_phase
[j
] = -1;
330 /* called when a rocket hits its destination height.
331 * prepares all associated fireworks to be expelled. */
332 void init_explode(int x
, int y
, int firework
, int points
)
336 for(i
=0; i
<points
; i
++)
338 rb
->srand(*rb
->current_tick
* i
);
340 firework_xpoints
[firework
][i
] = x
;
341 firework_ypoints
[firework
][i
] = y
;
343 firework_xspeed
[firework
][i
] = (rb
->rand() % FIREWORK_MOVEMENT_RANGE
)
344 - FIREWORK_MOVEMENT_RANGE
/2;
345 firework_yspeed
[firework
][i
] = (rb
->rand() % FIREWORK_MOVEMENT_RANGE
)
346 - FIREWORK_MOVEMENT_RANGE
/2;
348 #ifdef HAVE_LCD_COLOR
349 firework_color
[firework
][i
] = rb
->rand() % 7;
354 /* called when a rocket is launched.
355 * prepares said rocket to start moving towards its destination. */
356 void init_rocket(int rocket
)
358 rb
->srand(*rb
->current_tick
);
360 rocket_xpos
[rocket
] = rb
->rand() % LCD_WIDTH
;
361 rocket_ypos
[rocket
] = LCD_HEIGHT
;
363 rocket_xspeed
[rocket
] = (rb
->rand() % ROCKET_MOVEMENT_RANGE
)
364 - ROCKET_MOVEMENT_RANGE
/2;
365 rocket_yspeed
[rocket
] = 3;
367 rocket_phase
[rocket
] = 0;
368 rocket_targetphase
[rocket
] = (ROCKET_LIFE
+ (rb
->rand() % ROCKET_LIFE_VAR
))
369 / rocket_yspeed
[rocket
];
372 /* startup/configuration menu. */
373 void fireworks_menu(void)
375 int selected
= 0, result
;
376 bool menu_quit
= false;
378 rb
->lcd_setfont(FONT_UI
);
379 #ifdef HAVE_LCD_COLOR
380 rb
->lcd_set_background(LCD_BLACK
);
381 rb
->lcd_set_foreground(LCD_WHITE
);
383 rb
->lcd_clear_display();
386 rb
->button_clear_queue();
390 result
= rb
->do_menu(&menu
, &selected
, NULL
, false);
395 rb
->lcd_setfont(FONT_SYSFIXED
);
397 #ifdef HAVE_LCD_COLOR
398 rb
->lcd_set_background(LCD_BLACK
);
399 rb
->lcd_set_foreground(LCD_WHITE
);
402 rb
->lcd_clear_display();
410 rb
->set_option("Auto-Fire", &autofire_delay
, INT
,
411 autofire_delay_settings
, 15, NULL
);
415 rb
->set_option("Particles Per Firework", &particles_per_firework
,
416 INT
, particle_settings
, 8, NULL
);
420 rb
->set_option("Particle Life", &particle_life
, INT
,
421 particle_life_settings
, 9, NULL
);
425 rb
->set_option("Gravity", &gravity
, INT
,
426 gravity_settings
, 4, NULL
);
430 rb
->set_option("Show Rockets", &show_rockets
, INT
,
431 rocket_settings
, 3, NULL
);
435 rb
->set_option("FPS (Speed)", &frames_per_second
, INT
,
436 fps_settings
, 9, NULL
);
440 playback_control(NULL
);
451 /* this is the plugin entry point */
452 enum plugin_status
plugin_start(const void* parameter
)
458 int start_tick
, elapsed_tick
;
461 /* set everything up.. no BL timeout, no backdrop,
462 white-text-on-black-background. */
463 backlight_force_on(); /* backlight control in lib/helper.c */
465 rb
->lcd_set_backdrop(NULL
);
466 rb
->lcd_set_background(LCD_BLACK
);
467 rb
->lcd_set_foreground(LCD_WHITE
);
470 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
476 start_tick
= *rb
->current_tick
;
480 rb
->lcd_clear_display();
482 /* loop through every possible rocket */
483 for(j
=0; j
<MAX_ROCKETS
; j
++)
485 /* if the current rocket is actually moving/"alive" then go on and
486 * move/update/explode it */
487 if(rocket_phase
[j
] > -1)
489 #ifdef HAVE_LCD_COLOR /* draw trail, if requested */
492 rb
->lcd_set_foreground(LCD_RGBPACK(128,128,128));
493 rb
->lcd_fillrect(rocket_xpos
[j
], rocket_ypos
[j
],
494 ROCKET_SIZE
, ROCKET_SIZE
);
495 rb
->lcd_set_foreground(LCD_RGBPACK(64,64,64));
496 rb
->lcd_fillrect(rocket_xpos
[j
]-rocket_xspeed
[j
],
497 rocket_ypos
[j
]+rocket_yspeed
[j
],
498 ROCKET_SIZE
, ROCKET_SIZE
);
503 rocket_xpos
[j
] += rocket_xspeed
[j
];
504 rocket_ypos
[j
] -= rocket_yspeed
[j
];
506 #ifdef HAVE_LCD_COLOR
507 rb
->lcd_set_foreground(LCD_WHITE
);
509 if(show_rockets
==2 || show_rockets
==1)
510 rb
->lcd_fillrect(rocket_xpos
[j
], rocket_ypos
[j
],
511 ROCKET_SIZE
, ROCKET_SIZE
);
513 /* if(rocket isn't "there" yet) keep moving
514 * if(rocket IS there) explode it. */
515 if(rocket_phase
[j
] < rocket_targetphase
[j
])
519 rocket_phase
[j
] = -1;
521 firework_phase
[j
] = 0;
522 init_explode(rocket_xpos
[j
], rocket_ypos
[j
], j
,
523 particle_values
[particles_per_firework
]);
527 /* and now onto the fireworks for this particular rocket... */
528 if(firework_phase
[j
] > -1)
530 for(i
=0; i
<particle_values
[particles_per_firework
]; i
++)
532 firework_xpoints
[j
][i
] += firework_xspeed
[j
][i
];
533 firework_ypoints
[j
][i
] += firework_yspeed
[j
][i
];
536 firework_ypoints
[j
][i
] += firework_phase
[j
]
537 /gravity_values
[gravity
];
539 #ifdef HAVE_LCD_COLOR
540 rb
->lcd_set_foreground(
541 firework_darkest_colors
[firework_color
[j
][i
]]);
542 rb
->lcd_fillrect(firework_xpoints
[j
][i
]-1,
543 firework_ypoints
[j
][i
]-1,
544 FIREWORK_SIZE
+2, FIREWORK_SIZE
+2);
546 int phase_left
= particle_life_values
[particle_life
]
549 rb
->lcd_set_foreground(
550 firework_colors
[firework_color
[j
][i
]]);
551 else if(phase_left
> 7)
552 rb
->lcd_set_foreground(
553 firework_dark_colors
[firework_color
[j
][i
]]);
554 else if(phase_left
> 3)
555 rb
->lcd_set_foreground(
556 firework_darker_colors
[firework_color
[j
][i
]]);
558 rb
->lcd_set_foreground(
559 firework_darkest_colors
[firework_color
[j
][i
]]);
561 rb
->lcd_fillrect(firework_xpoints
[j
][i
],
562 firework_ypoints
[j
][i
],
563 FIREWORK_SIZE
, FIREWORK_SIZE
);
564 /* WIP - currently ugly explosion effect
565 #ifdef HAVE_LCD_COLOR
566 if(firework_phase[j] < 10)
568 rb->lcd_set_foreground(EXPLOSION_COLOR);
569 rb->lcd_fillrect(rocket_xpos[j]-firework_phase[j],
570 rocket_ypos[j]-firework_phase[j],
571 firework_phase[j]*2, firework_phase[j]*2);
576 #ifdef HAVE_LCD_COLOR
577 rb
->lcd_set_foreground(LCD_WHITE
);
580 /* firework at its destination age?
581 * no = keep aging; yes = delete it. */
582 if(firework_phase
[j
] < particle_life_values
[particle_life
])
585 firework_phase
[j
] = -1;
589 /* is autofire on? */
590 if(autofire_delay
!= 0)
592 elapsed_tick
= *rb
->current_tick
- start_tick
;
594 if(elapsed_tick
> autofire_delay_values
[autofire_delay
])
596 init_rocket(thisrocket
);
597 if(++thisrocket
== MAX_ROCKETS
)
600 start_tick
= *rb
->current_tick
;
606 button
= rb
->button_get_w_tmo(HZ
/fps_values
[frames_per_second
]);
609 case BTN_MENU
: /* back to config menu */
613 case BTN_FIRE
: /* fire off rockets manually */
614 case BTN_FIRE
|BUTTON_REPEAT
:
615 init_rocket(thisrocket
);
616 if(++thisrocket
== MAX_ROCKETS
)
621 /* Turn on backlight timeout (revert to settings) */
622 backlight_use_settings(); /* backlight control in lib/helper.c */
624 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
625 rb
->cpu_boost(false);