New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / matrix.c
blob93565596dd0f9eb4b345d6a48f7f24b9bbc97c1f
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 1999 Chris Allegretta
11 * Copyright (C) 2005 Alastair S - ported to podzilla
12 * Copyright (C) 2005 Jonas Häggqvist - ported to rockbox
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.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
26 * TODO:
27 * - The font is a bit large, create smaller one
28 * - For colour/greyscale displays, the font from the xscreensaver xmatrix
29 * should be converted and used
30 * BUGS:
31 * - The animation "dies" after a few seconds, not sure why. Works in sim.
32 * Symtom Fixed Oct 2007 GRaTT (Gerritt Gonzales)
36 #include "plugin.h"
37 PLUGIN_HEADER
39 /* Images */
40 #define MAXCHARS 27 - 1
41 extern const fb_data matrix_bold[];
42 extern const fb_data matrix_normal[];
43 #define COL_W 14
44 #define COL_H 15
46 #define COLS LCD_WIDTH/COL_W
47 #define ROWS LCD_HEIGHT/COL_H
49 #define LEFTMARGIN (LCD_WIDTH-(COLS*COL_W))/2
50 #define TOPMARGIN (LCD_HEIGHT-(ROWS*COL_H))/2
52 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
53 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
54 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
55 #define MATRIX_EXIT BUTTON_MENU
56 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
57 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
58 #define MATRIX_PAUSE BUTTON_PLAY
59 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
60 (CONFIG_KEYPAD == IRIVER_H300_PAD)
61 #define MATRIX_EXIT BUTTON_OFF
62 #define MATRIX_SLEEP_MORE BUTTON_UP
63 #define MATRIX_SLEEP_LESS BUTTON_DOWN
64 #define MATRIX_PAUSE BUTTON_SELECT
65 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
66 #define MATRIX_EXIT BUTTON_POWER
67 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_UP|BUTTON_REPEAT
68 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_DOWN|BUTTON_REPEAT
69 #define MATRIX_PAUSE BUTTON_PLAY
70 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
71 #define MATRIX_EXIT BUTTON_POWER
72 #define MATRIX_SLEEP_MORE BUTTON_UP
73 #define MATRIX_SLEEP_LESS BUTTON_DOWN
74 #define MATRIX_PAUSE BUTTON_PLAY
75 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
76 #define MATRIX_EXIT BUTTON_POWER
77 #define MATRIX_SLEEP_MORE BUTTON_UP
78 #define MATRIX_SLEEP_LESS BUTTON_DOWN
79 #define MATRIX_PAUSE BUTTON_SELECT
80 #elif CONFIG_KEYPAD == SANSA_E200_PAD
81 #define MATRIX_EXIT BUTTON_POWER
82 #define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
83 #define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
84 #define MATRIX_PAUSE BUTTON_SELECT
85 #elif CONFIG_KEYPAD == SANSA_C200_PAD
86 #define MATRIX_EXIT BUTTON_POWER
87 #define MATRIX_SLEEP_MORE BUTTON_UP
88 #define MATRIX_SLEEP_LESS BUTTON_DOWN
89 #define MATRIX_PAUSE BUTTON_SELECT
90 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
91 #define MATRIX_EXIT BUTTON_BACK
92 #define MATRIX_SLEEP_MORE BUTTON_UP
93 #define MATRIX_SLEEP_LESS BUTTON_DOWN
94 #define MATRIX_PAUSE BUTTON_SELECT
95 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
96 #define MATRIX_EXIT BUTTON_RC_REC
97 #define MATRIX_SLEEP_MORE BUTTON_RC_VOL_UP
98 #define MATRIX_SLEEP_LESS BUTTON_RC_VOL_DOWN
99 #define MATRIX_PAUSE BUTTON_RC_PLAY
100 #elif (CONFIG_KEYPAD == COWOND2_PAD)
101 #define MATRIX_EXIT BUTTON_POWER
102 #elif CONFIG_KEYPAD == IAUDIO67_PAD
103 #define MATRIX_EXIT BUTTON_POWER
104 #define MATRIX_SLEEP_MORE BUTTON_VOLUP
105 #define MATRIX_SLEEP_LESS BUTTON_VOLDOWN
106 #define MATRIX_PAUSE BUTTON_PLAY
107 #else
108 #error Unsupported keypad
109 #endif
111 #ifdef HAVE_TOUCHSCREEN
112 #ifndef MATRIX_EXIT
113 #define MATRIX_EXIT BUTTON_TOPLEFT
114 #endif
115 #ifndef MATRIX_SLEEP_MORE
116 #define MATRIX_SLEEP_MORE BUTTON_MIDRIGHT
117 #endif
118 #ifndef MATRIX_SLEEP_LESS
119 #define MATRIX_SLEEP_LESS BUTTON_MIDLEFT
120 #endif
121 #ifndef MATRIX_PAUSE
122 #define MATRIX_PAUSE BUTTON_CENTER
123 #endif
124 #endif
126 #define SLEEP HZ/50
128 /* Codec api pointer */
129 static const struct plugin_api* rb;
131 /* Each position is of this type */
132 typedef struct cmatrix {
133 int val;
134 int bold;
135 } cmatrix;
137 /* The matrix - who'd have guessed it was just a few hundred bytes? */
138 static cmatrix matrix[ROWS][COLS];
139 static int length[COLS];
140 static int spaces[COLS];
141 static int updates[COLS];
143 static void matrix_init(void) {
144 int i,j;
146 /* Seed rand */
147 rb->srand(*rb->current_tick);
149 /* Make the matrix */
150 for (i = 0; i <= ROWS; i++) {
151 for (j = 0; j <= COLS - 1; j++ ) {
152 matrix[i][j].val = -1;
153 matrix[i][j].bold = 0;
157 for (j = 0; j <= COLS - 1; j++) {
158 /* Set up spaces[] array of how many spaces to skip */
159 spaces[j] = rb->rand() % ROWS + 1;
161 /* And length of the stream */
162 length[j] = rb->rand() % (ROWS - 3) + 3;
164 /* Sentinel value for creation of new objects */
165 matrix[1][j].val = 129;
167 /* And set updates[] array for update speed. */
168 updates[j] = rb->rand() % 3 + 1;
172 static void matrix_blit_char(const int row, const int col, int cha)
174 if (cha == 129 || cha == 2 || cha > MAXCHARS)
175 cha = 0;
177 if (matrix[row][col].bold == 1) {
178 rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0, 392,
179 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
181 else {
182 rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0, 392,
183 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
187 static void matrix_loop(void)
189 int i, j = 0, y, z, firstcoldone = 0;
190 static int count = 0;
191 int randomness = 6;
193 count++;
194 if (count > 4)
195 count = 1;
197 for (j = 0; j <= COLS - 1; j++) {
198 if (count > updates[j]) {
199 /* New style scrolling */
200 if (matrix[0][j].val == -1 && matrix[1][j].val == 129
201 && spaces[j] > 0) {
202 matrix[0][j].val = -1;
203 spaces[j]--;
204 } else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
205 length[j] = rb->rand() % (ROWS - 3) + 3;
206 matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
207 if (rb->rand() % 2 == 1)
208 matrix[0][j].bold = 2;
209 spaces[j] = rb->rand() % ROWS + 1;
211 i = 0;
212 y = 0;
213 firstcoldone = 0;
214 while (i <= ROWS) {
215 /* Skip over spaces */
216 /* this is whear the characters were disappearing */
218 while (i <= ROWS && (matrix[i][j].val == 129 ||
219 matrix[i][j].val == -1))
220 i++;
222 /* A little more random now for spaces */
223 if (rb->rand() % randomness == 1){
224 while (i <= ROWS && (matrix[i][j].val == 129 ||
225 matrix[i][j].val == -1)){
226 i++;
227 randomness--;
228 if(randomness <=1)
229 randomness = 6;}
230 }else{
231 randomness++;
232 if(randomness >6)
233 randomness = 6;
237 if (i > ROWS)
238 break;
240 /* Go to the head of this collumn */
241 z = i;
242 y = 0;
243 while (i <= ROWS && (matrix[i][j].val != 129 &&
244 matrix[i][j].val != -1)) {
245 i++;
246 y++;
249 if (i > ROWS) {
250 matrix[z][j].val = 129;
251 matrix[ROWS][j].bold = 1;
252 matrix_blit_char(z - 1, j, matrix[z][j].val);
253 continue;
256 matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
258 if (matrix[i - 1][j].bold == 2) {
259 matrix[i - 1][j].bold = 1;
260 matrix[i][j].bold = 2;
263 /* If we're at the top of the collumn and it's reached its
264 * full length (about to start moving down), we do this
265 * to get it moving. This is also how we keep segments
266 * not already growing from growing accidentally =>
268 if (y > length[j] || firstcoldone) {
269 matrix[z][j].val = 129;
270 matrix[0][j].val = -1;
272 firstcoldone = 1;
273 i++;
275 for (i = 1; i <= ROWS; i++) {
276 if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
277 if (matrix[i][j].val == 0)
278 matrix_blit_char(i - 1, j, 20);
279 else
280 matrix_blit_char(i - 1, j, matrix[i][j].val);
281 } else {
282 if (matrix[i][j].val == 1)
283 matrix_blit_char(i - 1, j, 2);
284 else if (matrix[i][j].val == -1)
285 matrix_blit_char(i - 1, j, 129);
286 else
287 matrix_blit_char(i - 1, j, matrix[i][j].val);
294 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) {
295 int button;
296 int sleep = SLEEP;
297 bool frozen = false;
299 (void)parameter;
300 rb = api;
302 rb->lcd_set_background(LCD_BLACK);
303 rb->lcd_set_backdrop(NULL);
304 rb->lcd_clear_display();
305 matrix_init();
307 while (1) {
308 if (!frozen) {
309 matrix_loop();
310 rb->lcd_update();
311 rb->sleep(sleep);
313 button = rb->button_get(false);
314 switch(button) {
315 case MATRIX_PAUSE:
316 frozen = !frozen;
317 break;
318 case MATRIX_EXIT:
319 return PLUGIN_OK;
320 break;
321 case MATRIX_SLEEP_MORE:
322 /* Sleep longer */
323 sleep += SLEEP;
324 break;
325 case MATRIX_SLEEP_LESS:
326 /* Sleep less */
327 sleep -= SLEEP;
328 if (sleep < 0) sleep = 0;
329 break;
330 default:
331 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
332 return PLUGIN_USB_CONNECTED;
334 break;
337 return PLUGIN_OK;