Prepare new maemo release
[maemo-rb.git] / apps / plugins / matrix.c
blob087a501474dacd36281cc7aef0e4b9b078615310
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 #include "lib/pluginlib_actions.h"
39 /* Images */
40 #include "pluginbitmaps/matrix_bold.h"
41 #include "pluginbitmaps/matrix_normal.h"
42 #define MAXCHARS 27 - 1
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 /* this set the context to use with PLA */
53 static const struct button_mapping *plugin_contexts[] = { pla_main_ctx };
55 #ifdef HAVE_SCROLLWHEEL
56 #define MATRIX_SLEEP_MORE PLA_SCROLL_BACK
57 #define MATRIX_SLEEP_MORE_REPEAT PLA_SCROLL_BACK_REPEAT
58 #define MATRIX_SLEEP_LESS PLA_SCROLL_FWD
59 #define MATRIX_SLEEP_LESS_REPEAT PLA_SCROLL_FWD_REPEAT
60 #else
61 #define MATRIX_SLEEP_MORE PLA_UP
62 #define MATRIX_SLEEP_MORE_REPEAT PLA_UP_REPEAT
63 #define MATRIX_SLEEP_LESS PLA_DOWN
64 #define MATRIX_SLEEP_LESS_REPEAT PLA_DOWN_REPEAT
65 #endif /* HAVE_SCROLLWHEEL */
66 #define MATRIX_PAUSE PLA_SELECT
67 #define MATRIX_EXIT PLA_EXIT
68 #define MATRIX_EXIT2 PLA_CANCEL
70 #define SLEEP HZ/50
72 /* Each position is of this type */
73 typedef struct cmatrix {
74 int val;
75 int bold;
76 } cmatrix;
78 /* The matrix - who'd have guessed it was just a few hundred bytes? */
79 static cmatrix matrix[ROWS][COLS];
80 static int length[COLS];
81 static int spaces[COLS];
82 static int updates[COLS];
84 static void matrix_init(void) {
85 int i,j;
87 /* Seed rand */
88 rb->srand(*rb->current_tick);
90 /* Make the matrix */
91 for (i = 0; i < ROWS; i++) {
92 for (j = 0; j < COLS; j++) {
93 matrix[i][j].val = -1;
94 matrix[i][j].bold = 0;
98 for (j = 0; j < COLS; j++) {
99 /* Set up spaces[] array of how many spaces to skip */
100 spaces[j] = rb->rand() % ROWS + 1;
102 /* And length of the stream */
103 length[j] = rb->rand() % (ROWS - 3) + 3;
105 /* Sentinel value for creation of new objects */
106 matrix[1][j].val = 129;
108 /* And set updates[] array for update speed. */
109 updates[j] = rb->rand() % 3 + 1;
113 static void matrix_blit_char(const int row, const int col, int cha)
115 if (cha == 129 || cha == 2 || cha > MAXCHARS)
116 cha = 0;
118 if (matrix[row][col].bold == 1) {
119 rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0,
120 STRIDE( SCREEN_MAIN,
121 BMPWIDTH_matrix_bold, BMPHEIGHT_matrix_bold),
122 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
124 else {
125 rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0,
126 STRIDE( SCREEN_MAIN,
127 BMPWIDTH_matrix_normal, BMPHEIGHT_matrix_normal),
128 col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
132 static void matrix_loop(void)
134 int i, j = 0, y, z, firstcoldone = 0;
135 static int count = 0;
136 int randomness = 6;
138 count++;
139 if (count > 4)
140 count = 1;
142 for (j = 0; j < COLS; j++) {
143 if (count > updates[j]) {
144 /* New style scrolling */
145 if (matrix[0][j].val == -1 && matrix[1][j].val == 129
146 && spaces[j] > 0) {
147 matrix[0][j].val = -1;
148 spaces[j]--;
149 } else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
150 length[j] = rb->rand() % (ROWS - 3) + 3;
151 matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
152 if (rb->rand() % 2 == 1)
153 matrix[0][j].bold = 2;
154 spaces[j] = rb->rand() % ROWS + 1;
156 i = 0;
157 y = 0;
158 firstcoldone = 0;
159 while (i <= ROWS) {
160 /* Skip over spaces */
161 /* this is whear the characters were disappearing */
163 while (i <= ROWS && (matrix[i][j].val == 129 ||
164 matrix[i][j].val == -1))
165 i++;
167 /* A little more random now for spaces */
168 if (rb->rand() % randomness == 1){
169 while (i <= ROWS && (matrix[i][j].val == 129 ||
170 matrix[i][j].val == -1)){
171 i++;
172 randomness--;
173 if(randomness <=1)
174 randomness = 6;}
175 }else{
176 randomness++;
177 if(randomness >6)
178 randomness = 6;
182 if (i > ROWS)
183 break;
185 /* Go to the head of this collumn */
186 z = i;
187 y = 0;
188 while (i <= ROWS && (matrix[i][j].val != 129 &&
189 matrix[i][j].val != -1)) {
190 i++;
191 y++;
194 if (i > ROWS) {
195 matrix[z][j].val = 129;
196 matrix[ROWS - 1][j].bold = 1;
197 matrix_blit_char(z - 1, j, matrix[z][j].val);
198 continue;
201 matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
203 if (matrix[i - 1][j].bold == 2) {
204 matrix[i - 1][j].bold = 1;
205 matrix[i][j].bold = 2;
208 /* If we're at the top of the collumn and it's reached its
209 * full length (about to start moving down), we do this
210 * to get it moving. This is also how we keep segments
211 * not already growing from growing accidentally =>
213 if (y > length[j] || firstcoldone) {
214 matrix[z][j].val = 129;
215 matrix[0][j].val = -1;
217 firstcoldone = 1;
218 i++;
220 for (i = 1; i < ROWS; i++) {
221 if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
222 if (matrix[i][j].val == 0)
223 matrix_blit_char(i - 1, j, 20);
224 else
225 matrix_blit_char(i - 1, j, matrix[i][j].val);
226 } else {
227 if (matrix[i][j].val == 1)
228 matrix_blit_char(i - 1, j, 2);
229 else if (matrix[i][j].val == -1)
230 matrix_blit_char(i - 1, j, 129);
231 else
232 matrix_blit_char(i - 1, j, matrix[i][j].val);
239 enum plugin_status plugin_start(const void* parameter) {
240 int button;
241 int sleep = SLEEP;
242 bool frozen = false;
244 (void)parameter;
246 rb->lcd_set_background(LCD_BLACK);
247 rb->lcd_set_backdrop(NULL);
248 rb->lcd_clear_display();
249 matrix_init();
251 while (1) {
252 if (!frozen) {
253 matrix_loop();
254 rb->lcd_update();
255 rb->sleep(sleep);
258 button = pluginlib_getaction(frozen ? TIMEOUT_BLOCK : TIMEOUT_NOBLOCK,
259 plugin_contexts, ARRAYLEN(plugin_contexts));
261 switch(button) {
262 case MATRIX_PAUSE:
263 frozen = !frozen;
264 break;
265 case MATRIX_EXIT:
266 case MATRIX_EXIT2:
267 return PLUGIN_OK;
268 break;
269 case MATRIX_SLEEP_MORE:
270 case MATRIX_SLEEP_MORE_REPEAT:
271 /* Sleep longer */
272 sleep += SLEEP;
273 break;
274 case MATRIX_SLEEP_LESS:
275 case MATRIX_SLEEP_LESS_REPEAT:
276 /* Sleep less */
277 sleep -= SLEEP;
278 if (sleep < 0) sleep = 0;
279 break;
280 default:
281 if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
282 return PLUGIN_USB_CONNECTED;
284 break;
287 return PLUGIN_OK;