summaryrefslogtreecommitdiff
path: root/apps/plugins/pictureflow.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/pictureflow.c')
-rw-r--r--apps/plugins/pictureflow.c806
1 files changed, 562 insertions, 244 deletions
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index 977b18c1fb..8f34ca5b8b 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -46,6 +46,10 @@ const struct button_mapping *plugin_contexts[]
46 || (CONFIG_KEYPAD == IPOD_3G_PAD) \ 46 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
47 || (CONFIG_KEYPAD == IPOD_4G_PAD) \ 47 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
48 || (CONFIG_KEYPAD == SANSA_E200_PAD) 48 || (CONFIG_KEYPAD == SANSA_E200_PAD)
49#define SCROLLWHEEL
50#endif
51
52#ifdef SCROLLWHEEL
49#define PICTUREFLOW_NEXT_ALBUM PLA_UP 53#define PICTUREFLOW_NEXT_ALBUM PLA_UP
50#define PICTUREFLOW_NEXT_ALBUM_REPEAT PLA_UP_REPEAT 54#define PICTUREFLOW_NEXT_ALBUM_REPEAT PLA_UP_REPEAT
51#define PICTUREFLOW_PREV_ALBUM PLA_DOWN 55#define PICTUREFLOW_PREV_ALBUM PLA_DOWN
@@ -55,6 +59,10 @@ const struct button_mapping *plugin_contexts[]
55#define PICTUREFLOW_NEXT_ALBUM_REPEAT PLA_RIGHT_REPEAT 59#define PICTUREFLOW_NEXT_ALBUM_REPEAT PLA_RIGHT_REPEAT
56#define PICTUREFLOW_PREV_ALBUM PLA_LEFT 60#define PICTUREFLOW_PREV_ALBUM PLA_LEFT
57#define PICTUREFLOW_PREV_ALBUM_REPEAT PLA_LEFT_REPEAT 61#define PICTUREFLOW_PREV_ALBUM_REPEAT PLA_LEFT_REPEAT
62#define PICTUREFLOW_NEXT_TRACK PLA_DOWN
63#define PICTUREFLOW_NEXT_TRACK_REPEAT PLA_DOWN_REPEAT
64#define PICTUREFLOW_PREV_TRACK PLA_UP
65#define PICTUREFLOW_PREV_TRACK_REPEAT PLA_UP_REPEAT
58#endif 66#endif
59#define PICTUREFLOW_MENU PLA_MENU 67#define PICTUREFLOW_MENU PLA_MENU
60#define PICTUREFLOW_QUIT PLA_QUIT 68#define PICTUREFLOW_QUIT PLA_QUIT
@@ -105,6 +113,10 @@ const struct button_mapping *plugin_contexts[]
105#define MAX_ALBUMS 1024 113#define MAX_ALBUMS 1024
106#define AVG_ALBUM_NAME_LENGTH 20 114#define AVG_ALBUM_NAME_LENGTH 20
107 115
116#define MAX_TRACKS 50
117#define AVG_TRACK_NAME_LENGTH 20
118
119
108#define UNIQBUF_SIZE (64*1024) 120#define UNIQBUF_SIZE (64*1024)
109 121
110#define EMPTY_SLIDE CACHE_PREFIX "/emptyslide.pfraw" 122#define EMPTY_SLIDE CACHE_PREFIX "/emptyslide.pfraw"
@@ -122,6 +134,7 @@ struct slide_data {
122 int angle; 134 int angle;
123 PFreal cx; 135 PFreal cx;
124 PFreal cy; 136 PFreal cy;
137 PFreal distance;
125}; 138};
126 139
127struct slide_cache { 140struct slide_cache {
@@ -135,6 +148,11 @@ struct album_data {
135 long seek; 148 long seek;
136}; 149};
137 150
151struct track_data {
152 int name_idx;
153 long seek;
154};
155
138struct rect { 156struct rect {
139 int left; 157 int left;
140 int right; 158 int right;
@@ -162,13 +180,13 @@ struct config_data {
162 int spacing_between_slides; 180 int spacing_between_slides;
163 int extra_spacing_for_center_slide; 181 int extra_spacing_for_center_slide;
164 int show_slides; 182 int show_slides;
183 int zoom;
165}; 184};
166 185
167/** below we allocate the memory we want to use **/ 186/** below we allocate the memory we want to use **/
168 187
169static fb_data *buffer; /* for now it always points to the lcd framebuffer */ 188static fb_data *buffer; /* for now it always points to the lcd framebuffer */
170static PFreal rays[BUFFER_WIDTH]; 189static PFreal rays[BUFFER_WIDTH];
171static bool animation_is_active; /* an animation is currently running */
172static struct slide_data center_slide; 190static struct slide_data center_slide;
173static struct slide_data left_slides[MAX_SLIDES_COUNT]; 191static struct slide_data left_slides[MAX_SLIDES_COUNT];
174static struct slide_data right_slides[MAX_SLIDES_COUNT]; 192static struct slide_data right_slides[MAX_SLIDES_COUNT];
@@ -178,7 +196,6 @@ static int target;
178static int fade; 196static int fade;
179static int center_index; /* index of the slide that is in the center */ 197static int center_index; /* index of the slide that is in the center */
180static int itilt; 198static int itilt;
181static int zoom;
182static PFreal offsetX; 199static PFreal offsetX;
183static PFreal offsetY; 200static PFreal offsetY;
184static bool show_fps; /* show fps in the main screen */ 201static bool show_fps; /* show fps in the main screen */
@@ -207,161 +224,74 @@ static struct album_data album[MAX_ALBUMS];
207static char album_names[MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH]; 224static char album_names[MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH];
208static int album_count; 225static int album_count;
209 226
227static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH];
228static struct track_data tracks[MAX_TRACKS];
229static int track_count;
230static int track_index;
231static int selected_track;
232static int selected_track_pulse;
233
210static fb_data *input_bmp_buffer; 234static fb_data *input_bmp_buffer;
211static fb_data *output_bmp_buffer; 235static fb_data *output_bmp_buffer;
212static int input_hid; 236static int input_hid;
213static int output_hid; 237static int output_hid;
214static struct config_data config; 238static struct config_data config;
215 239
240static int old_drawmode;
241
216static bool thread_is_running; 242static bool thread_is_running;
217 243
244static int cover_animation_keyframe;
245static int extra_fade;
246
247static int albumtxt_x = 0;
248static int albumtxt_dir = -1;
249static int prev_center_index = -1;
250
251static int start_index_track_list = 0;
252static int track_list_visible_entries = 0;
253static int track_scroll_index = 0;
254static int track_scroll_dir = 1;
255
256/*
257 Proposals for transitions:
258
259 pf_idle -> pf_scrolling : NEXT_ALBUM/PREV_ALBUM pressed
260 -> pf_cover_in -> pf_show_tracks : SELECT_ALBUM clicked
218 261
219PFreal sinTable[] = { /* 10 */ 262 pf_scrolling -> pf_idle : NEXT_ALBUM/PREV_ALBUM released
220 3, 9, 15, 21, 28, 34, 40, 47, 263
221 53, 59, 65, 72, 78, 84, 90, 97, 264 pf_show_tracks -> pf_cover_out -> pf_idle : SELECT_ALBUM pressed
222 103, 109, 115, 122, 128, 134, 140, 147, 265
223 153, 159, 165, 171, 178, 184, 190, 196, 266 TODO:
224 202, 209, 215, 221, 227, 233, 239, 245, 267 pf_show_tracks -> pf_cover_out -> pf_idle : MENU_PRESSED pressed
225 251, 257, 264, 270, 276, 282, 288, 294, 268 pf_show_tracks -> play_track() -> exit() : SELECT_ALBUM pressed
226 300, 306, 312, 318, 324, 330, 336, 342, 269
227 347, 353, 359, 365, 371, 377, 383, 388, 270 pf_idle, pf_scrolling -> show_menu(): MENU_PRESSED
228 394, 400, 406, 412, 417, 423, 429, 434, 271*/
229 440, 446, 451, 457, 463, 468, 474, 479, 272enum pf_states {
230 485, 491, 496, 501, 507, 512, 518, 523, 273 pf_idle = 0,
231 529, 534, 539, 545, 550, 555, 561, 566, 274 pf_scrolling,
232 571, 576, 581, 587, 592, 597, 602, 607, 275 pf_cover_in,
233 612, 617, 622, 627, 632, 637, 642, 647, 276 pf_show_tracks,
234 652, 656, 661, 666, 671, 675, 680, 685, 277 pf_cover_out
235 690, 694, 699, 703, 708, 712, 717, 721,
236 726, 730, 735, 739, 743, 748, 752, 756,
237 760, 765, 769, 773, 777, 781, 785, 789,
238 793, 797, 801, 805, 809, 813, 816, 820,
239 824, 828, 831, 835, 839, 842, 846, 849,
240 853, 856, 860, 863, 866, 870, 873, 876,
241 879, 883, 886, 889, 892, 895, 898, 901,
242 904, 907, 910, 913, 916, 918, 921, 924,
243 927, 929, 932, 934, 937, 939, 942, 944,
244 947, 949, 951, 954, 956, 958, 960, 963,
245 965, 967, 969, 971, 973, 975, 977, 978,
246 980, 982, 984, 986, 987, 989, 990, 992,
247 994, 995, 997, 998, 999, 1001, 1002, 1003,
248 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
249 1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018,
250 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
251 1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
252 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022,
253 1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019,
254 1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013,
255 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004,
256 1003, 1002, 1001, 999, 998, 997, 995, 994,
257 992, 990, 989, 987, 986, 984, 982, 980,
258 978, 977, 975, 973, 971, 969, 967, 965,
259 963, 960, 958, 956, 954, 951, 949, 947,
260 944, 942, 939, 937, 934, 932, 929, 927,
261 924, 921, 918, 916, 913, 910, 907, 904,
262 901, 898, 895, 892, 889, 886, 883, 879,
263 876, 873, 870, 866, 863, 860, 856, 853,
264 849, 846, 842, 839, 835, 831, 828, 824,
265 820, 816, 813, 809, 805, 801, 797, 793,
266 789, 785, 781, 777, 773, 769, 765, 760,
267 756, 752, 748, 743, 739, 735, 730, 726,
268 721, 717, 712, 708, 703, 699, 694, 690,
269 685, 680, 675, 671, 666, 661, 656, 652,
270 647, 642, 637, 632, 627, 622, 617, 612,
271 607, 602, 597, 592, 587, 581, 576, 571,
272 566, 561, 555, 550, 545, 539, 534, 529,
273 523, 518, 512, 507, 501, 496, 491, 485,
274 479, 474, 468, 463, 457, 451, 446, 440,
275 434, 429, 423, 417, 412, 406, 400, 394,
276 388, 383, 377, 371, 365, 359, 353, 347,
277 342, 336, 330, 324, 318, 312, 306, 300,
278 294, 288, 282, 276, 270, 264, 257, 251,
279 245, 239, 233, 227, 221, 215, 209, 202,
280 196, 190, 184, 178, 171, 165, 159, 153,
281 147, 140, 134, 128, 122, 115, 109, 103,
282 97, 90, 84, 78, 72, 65, 59, 53,
283 47, 40, 34, 28, 21, 15, 9, 3,
284 -4, -10, -16, -22, -29, -35, -41, -48,
285 -54, -60, -66, -73, -79, -85, -91, -98,
286 -104, -110, -116, -123, -129, -135, -141, -148,
287 -154, -160, -166, -172, -179, -185, -191, -197,
288 -203, -210, -216, -222, -228, -234, -240, -246,
289 -252, -258, -265, -271, -277, -283, -289, -295,
290 -301, -307, -313, -319, -325, -331, -337, -343,
291 -348, -354, -360, -366, -372, -378, -384, -389,
292 -395, -401, -407, -413, -418, -424, -430, -435,
293 -441, -447, -452, -458, -464, -469, -475, -480,
294 -486, -492, -497, -502, -508, -513, -519, -524,
295 -530, -535, -540, -546, -551, -556, -562, -567,
296 -572, -577, -582, -588, -593, -598, -603, -608,
297 -613, -618, -623, -628, -633, -638, -643, -648,
298 -653, -657, -662, -667, -672, -676, -681, -686,
299 -691, -695, -700, -704, -709, -713, -718, -722,
300 -727, -731, -736, -740, -744, -749, -753, -757,
301 -761, -766, -770, -774, -778, -782, -786, -790,
302 -794, -798, -802, -806, -810, -814, -817, -821,
303 -825, -829, -832, -836, -840, -843, -847, -850,
304 -854, -857, -861, -864, -867, -871, -874, -877,
305 -880, -884, -887, -890, -893, -896, -899, -902,
306 -905, -908, -911, -914, -917, -919, -922, -925,
307 -928, -930, -933, -935, -938, -940, -943, -945,
308 -948, -950, -952, -955, -957, -959, -961, -964,
309 -966, -968, -970, -972, -974, -976, -978, -979,
310 -981, -983, -985, -987, -988, -990, -991, -993,
311 -995, -996, -998, -999, -1000, -1002, -1003, -1004,
312 -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013,
313 -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019,
314 -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023,
315 -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024,
316 -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023,
317 -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020,
318 -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014,
319 -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005,
320 -1004, -1003, -1002, -1000, -999, -998, -996, -995,
321 -993, -991, -990, -988, -987, -985, -983, -981,
322 -979, -978, -976, -974, -972, -970, -968, -966,
323 -964, -961, -959, -957, -955, -952, -950, -948,
324 -945, -943, -940, -938, -935, -933, -930, -928,
325 -925, -922, -919, -917, -914, -911, -908, -905,
326 -902, -899, -896, -893, -890, -887, -884, -880,
327 -877, -874, -871, -867, -864, -861, -857, -854,
328 -850, -847, -843, -840, -836, -832, -829, -825,
329 -821, -817, -814, -810, -806, -802, -798, -794,
330 -790, -786, -782, -778, -774, -770, -766, -761,
331 -757, -753, -749, -744, -740, -736, -731, -727,
332 -722, -718, -713, -709, -704, -700, -695, -691,
333 -686, -681, -676, -672, -667, -662, -657, -653,
334 -648, -643, -638, -633, -628, -623, -618, -613,
335 -608, -603, -598, -593, -588, -582, -577, -572,
336 -567, -562, -556, -551, -546, -540, -535, -530,
337 -524, -519, -513, -508, -502, -497, -492, -486,
338 -480, -475, -469, -464, -458, -452, -447, -441,
339 -435, -430, -424, -418, -413, -407, -401, -395,
340 -389, -384, -378, -372, -366, -360, -354, -348,
341 -343, -337, -331, -325, -319, -313, -307, -301,
342 -295, -289, -283, -277, -271, -265, -258, -252,
343 -246, -240, -234, -228, -222, -216, -210, -203,
344 -197, -191, -185, -179, -172, -166, -160, -154,
345 -148, -141, -135, -129, -123, -116, -110, -104,
346 -98, -91, -85, -79, -73, -66, -60, -54,
347 -48, -41, -35, -29, -22, -16, -10, -4,
348}; 278};
349 279
280static int pf_state;
350 281
351/** code */ 282/** code */
352 283
353
354bool create_bmp(struct bitmap* input_bmp, char *target_path, bool resize); 284bool create_bmp(struct bitmap* input_bmp, char *target_path, bool resize);
355int load_surface(int); 285int load_surface(int);
356 286
357/* There are some precision issues when not using (long long) which in turn
358 takes very long to compute... I guess the best solution would be to optimize
359 the computations so it only requires a single long */
360static inline PFreal fmul(PFreal a, PFreal b) 287static inline PFreal fmul(PFreal a, PFreal b)
361{ 288{
362 return ((long long) (a)) * ((long long) (b)) >> PFREAL_SHIFT; 289 return (a*b) >> PFREAL_SHIFT;
363} 290}
364 291
292/* There are some precision issues when not using (long long) which in turn
293 takes very long to compute... I guess the best solution would be to optimize
294 the computations so it only requires a single long */
365static inline PFreal fdiv(PFreal num, PFreal den) 295static inline PFreal fdiv(PFreal num, PFreal den)
366{ 296{
367 long long p = (long long) (num) << (PFREAL_SHIFT * 2); 297 long long p = (long long) (num) << (PFREAL_SHIFT * 2);
@@ -394,21 +324,37 @@ static inline PFreal fdiv(PFreal n, PFreal m)
394} 324}
395#endif 325#endif
396 326
327/* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */
328static const PFreal sin_tab[] = {
329 3, 103, 202, 300, 394, 485, 571, 652,
330 726, 793, 853, 904, 947, 980, 1004, 1019,
331 1023, 1018, 1003, 978, 944, 901, 849, 789,
332 721, 647, 566, 479, 388, 294, 196, 97,
333 -4, -104, -203, -301, -395, -486, -572, -653,
334 -727, -794, -854, -905, -948, -981, -1005, -1020,
335 -1024, -1019, -1004, -979, -945, -902, -850, -790,
336 -722, -648, -567, -480, -389, -295, -197, -98,
337 3
338};
397 339
398inline PFreal fsin(int iangle) 340static inline PFreal fsin(int iangle)
399{ 341{
400 while (iangle < 0) 342 while(iangle < 0)
401 iangle += IANGLE_MAX; 343 iangle += IANGLE_MAX;
402 return sinTable[iangle & IANGLE_MASK]; 344 iangle &= IANGLE_MASK;
345
346 int i = (iangle >> 4);
347 PFreal p = sin_tab[i];
348 PFreal q = sin_tab[(i+1)];
349 PFreal g = (q - p);
350 return p + g * (iangle-i*16)/16;
403} 351}
404 352
405inline PFreal fcos(int iangle) 353static inline PFreal fcos(int iangle)
406{ 354{
407 /* quarter phase shift */
408 return fsin(iangle + (IANGLE_MAX >> 2)); 355 return fsin(iangle + (IANGLE_MAX >> 2));
409} 356}
410 357
411
412/** 358/**
413 Create an index of all albums from the database. 359 Create an index of all albums from the database.
414 Also store the album names so we can access them later. 360 Also store the album names so we can access them later.
@@ -444,11 +390,68 @@ int create_album_index(void)
444/** 390/**
445 Return a pointer to the album name of the given slide_index 391 Return a pointer to the album name of the given slide_index
446 */ 392 */
447char* get_album_name(int slide_index) 393char* get_album_name(const int slide_index)
448{ 394{
449 return album_names + album[slide_index].name_idx; 395 return album_names + album[slide_index].name_idx;
450} 396}
451 397
398/**
399 Return a pointer to the track name of the active album
400 create_track_index has to be called first.
401 */
402char* get_track_name(const int track_index)
403{
404 if ( track_index < track_count )
405 return track_names + tracks[track_index].name_idx;
406 return 0;
407}
408
409/**
410 Create the track index of the given slide_index.
411 */
412int create_track_index(const int slide_index)
413{
414 if ( slide_index == track_index ) {
415 return -1;
416 }
417
418 if (!rb->tagcache_search(&tcs, tag_title))
419 return -1;
420
421 int ret = 0;
422
423 rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek);
424 track_count=0;
425 int l, old_l = 0;
426 tracks[0].name_idx = 0;
427
428 while (rb->tagcache_get_next(&tcs) && track_count < MAX_TRACKS)
429 {
430 l = rb->strlen(tcs.result) + 1;
431 if ( track_count > 0 )
432 tracks[track_count].name_idx = tracks[track_count-1].name_idx + old_l;
433
434 if ( (tracks[track_count].name_idx + l) > MAX_TRACKS * AVG_TRACK_NAME_LENGTH )
435 {
436 /* not enough memory */
437 ret = ERROR_BUFFER_FULL;
438 break;
439 }
440 rb->strcpy(track_names + tracks[track_count].name_idx, tcs.result);
441 tracks[track_count].seek = tcs.result_seek;
442 old_l = l;
443 track_count++;
444 }
445
446 rb->tagcache_search_finish(&tcs);
447 track_index = slide_index;
448
449 if (ret != 0)
450 return ret;
451 else
452 return (track_count > 0) ? 0 : -1;
453}
454
452 455
453/** 456/**
454 Determine filename of the album art for the given slide_index and 457 Determine filename of the album art for the given slide_index and
@@ -456,7 +459,7 @@ char* get_album_name(int slide_index)
456 The algorithm looks for the first track of the given album uses 459 The algorithm looks for the first track of the given album uses
457 find_albumart to find the filename. 460 find_albumart to find the filename.
458 */ 461 */
459bool get_albumart_for_index_from_db(int slide_index, char *buf, int buflen) 462bool get_albumart_for_index_from_db(const int slide_index, char *buf, int buflen)
460{ 463{
461 if ( slide_index == -1 ) 464 if ( slide_index == -1 )
462 { 465 {
@@ -473,7 +476,8 @@ bool get_albumart_for_index_from_db(int slide_index, char *buf, int buflen)
473 if ( rb->tagcache_get_next(&tcs) ) { 476 if ( rb->tagcache_get_next(&tcs) ) {
474 struct mp3entry id3; 477 struct mp3entry id3;
475 char size[9]; 478 char size[9];
476 rb->snprintf(size, sizeof(size), ".%dx%d", PREFERRED_IMG_WIDTH, PREFERRED_IMG_HEIGHT); 479 rb->snprintf(size, sizeof(size), ".%dx%d", PREFERRED_IMG_WIDTH,
480 PREFERRED_IMG_HEIGHT);
477 rb->strncpy( (char*)&id3.path, tcs.result, MAX_PATH ); 481 rb->strncpy( (char*)&id3.path, tcs.result, MAX_PATH );
478 id3.album = get_album_name(slide_index); 482 id3.album = get_album_name(slide_index);
479 if ( rb->search_albumart_files(&id3, size, buf, buflen) ) 483 if ( rb->search_albumart_files(&id3, size, buf, buflen) )
@@ -536,6 +540,9 @@ void draw_progressbar(int step)
536 rb->yield(); 540 rb->yield();
537} 541}
538 542
543/**
544 Allocate temporary buffers
545 */
539bool allocate_buffers(void) 546bool allocate_buffers(void)
540{ 547{
541 int input_size = MAX_IMG_WIDTH * MAX_IMG_HEIGHT * sizeof( fb_data ); 548 int input_size = MAX_IMG_WIDTH * MAX_IMG_HEIGHT * sizeof( fb_data );
@@ -566,6 +573,9 @@ bool allocate_buffers(void)
566} 573}
567 574
568 575
576/**
577 Free the temporary buffers
578 */
569bool free_buffers(void) 579bool free_buffers(void)
570{ 580{
571 rb->bufclose(input_hid); 581 rb->bufclose(input_hid);
@@ -586,6 +596,7 @@ bool create_albumart_cache(bool force)
586 int i, slides = 0; 596 int i, slides = 0;
587 struct bitmap input_bmp; 597 struct bitmap input_bmp;
588 598
599 config.avg_album_width = 0;
589 for (i=0; i < album_count; i++) 600 for (i=0; i < album_count; i++)
590 { 601 {
591 draw_progressbar(i); 602 draw_progressbar(i);
@@ -597,19 +608,23 @@ bool create_albumart_cache(bool force)
597 sizeof(fb_data)*MAX_IMG_WIDTH*MAX_IMG_HEIGHT, 608 sizeof(fb_data)*MAX_IMG_WIDTH*MAX_IMG_HEIGHT,
598 FORMAT_NATIVE); 609 FORMAT_NATIVE);
599 if (ret <= 0) { 610 if (ret <= 0) {
600 rb->splash(HZ, "couldn't read bmp"); 611 rb->splash(HZ, "Could not read bmp");
601 continue; /* skip missing/broken files */ 612 continue; /* skip missing/broken files */
602 } 613 }
603 614
604 615
605 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", i); 616 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", i);
606 if (!create_bmp(&input_bmp, tmp_path_name, false)) { 617 if (!create_bmp(&input_bmp, tmp_path_name, false)) {
607 rb->splash(HZ, "couldn't write bmp"); 618 rb->splash(HZ, "Could not write bmp");
608 } 619 }
609 config.avg_album_width += input_bmp.width; 620 config.avg_album_width += input_bmp.width;
610 slides++; 621 slides++;
611 if ( rb->button_get(false) == PICTUREFLOW_MENU ) return false; 622 if ( rb->button_get(false) == PICTUREFLOW_MENU ) return false;
612 } 623 }
624 if ( slides == 0 ) {
625 rb->splash(2*HZ, "No albums found");
626 return false;
627 }
613 config.avg_album_width /= slides; 628 config.avg_album_width /= slides;
614 if ( config.avg_album_width == 0 ) { 629 if ( config.avg_album_width == 0 ) {
615 rb->splash(HZ, "album size is 0"); 630 rb->splash(HZ, "album size is 0");
@@ -624,7 +639,7 @@ bool create_albumart_cache(bool force)
624 Return the index on the stack of slide_index. 639 Return the index on the stack of slide_index.
625 Return -1 if slide_index is not on the stack. 640 Return -1 if slide_index is not on the stack.
626 */ 641 */
627int slide_stack_get_index(int slide_index) 642static inline int slide_stack_get_index(const int slide_index)
628{ 643{
629 int i = slide_cache_stack_index + 1; 644 int i = slide_cache_stack_index + 1;
630 while (i--) { 645 while (i--) {
@@ -639,7 +654,7 @@ int slide_stack_get_index(int slide_index)
639 slide_index as high as possible (so second if center_index is 654 slide_index as high as possible (so second if center_index is
640 on the stack). 655 on the stack).
641 */ 656 */
642void slide_stack_push(int slide_index) 657void slide_stack_push(const int slide_index)
643{ 658{
644 rb->mutex_lock(&slide_cache_stack_lock); 659 rb->mutex_lock(&slide_cache_stack_lock);
645 660
@@ -701,7 +716,7 @@ void slide_stack_push(int slide_index)
701/** 716/**
702 Pop the topmost item from the stack and decrease the stack size 717 Pop the topmost item from the stack and decrease the stack size
703 */ 718 */
704inline int slide_stack_pop(void) 719static inline int slide_stack_pop(void)
705{ 720{
706 rb->mutex_lock(&slide_cache_stack_lock); 721 rb->mutex_lock(&slide_cache_stack_lock);
707 int result; 722 int result;
@@ -716,9 +731,10 @@ inline int slide_stack_pop(void)
716 731
717/** 732/**
718 Load the slide into the cache. 733 Load the slide into the cache.
719 Thus we have to queue the loading request in our thread while discarding the oldest slide. 734 Thus we have to queue the loading request in our thread while discarding the
735 oldest slide.
720 */ 736 */
721void request_surface(int slide_index) 737static inline void request_surface(const int slide_index)
722{ 738{
723 slide_stack_push(slide_index); 739 slide_stack_push(slide_index);
724 rb->queue_post(&thread_q, EV_WAKEUP, 0); 740 rb->queue_post(&thread_q, EV_WAKEUP, 0);
@@ -919,9 +935,11 @@ bool create_bmp(struct bitmap *input_bmp, char *target_path, bool resize)
919/** 935/**
920 Load the surface for the given slide_index into the cache at cache_index. 936 Load the surface for the given slide_index into the cache at cache_index.
921 */ 937 */
922static bool load_and_prepare_surface(int slide_index, int cache_index) 938static inline bool load_and_prepare_surface(const int slide_index,
939 const int cache_index)
923{ 940{
924 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", slide_index); 941 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw",
942 slide_index);
925 943
926 int hid = read_pfraw(tmp_path_name); 944 int hid = read_pfraw(tmp_path_name);
927 if (hid < 0) 945 if (hid < 0)
@@ -942,7 +960,7 @@ static bool load_and_prepare_surface(int slide_index, int cache_index)
942 Load the surface from a bmp and overwrite the oldest slide in the cache 960 Load the surface from a bmp and overwrite the oldest slide in the cache
943 if necessary. 961 if necessary.
944 */ 962 */
945int load_surface(int slide_index) 963int load_surface(const int slide_index)
946{ 964{
947 long oldest_tick = *rb->current_tick; 965 long oldest_tick = *rb->current_tick;
948 int oldest_slide = 0; 966 int oldest_slide = 0;
@@ -971,7 +989,7 @@ int load_surface(int slide_index)
971/** 989/**
972 Get a slide from the buffer 990 Get a slide from the buffer
973 */ 991 */
974struct bitmap *get_slide(int hid) 992static inline struct bitmap *get_slide(const int hid)
975{ 993{
976 if (hid < 0) 994 if (hid < 0)
977 return NULL; 995 return NULL;
@@ -989,7 +1007,7 @@ struct bitmap *get_slide(int hid)
989/** 1007/**
990 Return the requested surface 1008 Return the requested surface
991*/ 1009*/
992struct bitmap *surface(int slide_index) 1010static inline struct bitmap *surface(const int slide_index)
993{ 1011{
994 if (slide_index < 0) 1012 if (slide_index < 0)
995 return 0; 1013 return 0;
@@ -1016,6 +1034,7 @@ void reset_slides(void)
1016 center_slide.angle = 0; 1034 center_slide.angle = 0;
1017 center_slide.cx = 0; 1035 center_slide.cx = 0;
1018 center_slide.cy = 0; 1036 center_slide.cy = 0;
1037 center_slide.distance = 0;
1019 center_slide.slide_index = center_index; 1038 center_slide.slide_index = center_index;
1020 1039
1021 int i; 1040 int i;
@@ -1025,6 +1044,7 @@ void reset_slides(void)
1025 si->cx = -(offsetX + config.spacing_between_slides * i * PFREAL_ONE); 1044 si->cx = -(offsetX + config.spacing_between_slides * i * PFREAL_ONE);
1026 si->cy = offsetY; 1045 si->cy = offsetY;
1027 si->slide_index = center_index - 1 - i; 1046 si->slide_index = center_index - 1 - i;
1047 si->distance = 0;
1028 } 1048 }
1029 1049
1030 for (i = 0; i < config.show_slides; i++) { 1050 for (i = 0; i < config.show_slides; i++) {
@@ -1033,6 +1053,7 @@ void reset_slides(void)
1033 si->cx = offsetX + config.spacing_between_slides * i * PFREAL_ONE; 1053 si->cx = offsetX + config.spacing_between_slides * i * PFREAL_ONE;
1034 si->cy = offsetY; 1054 si->cy = offsetY;
1035 si->slide_index = center_index + 1 + i; 1055 si->slide_index = center_index + 1 + i;
1056 si->distance = 0;
1036 } 1057 }
1037} 1058}
1038 1059
@@ -1063,10 +1084,32 @@ void recalc_table(void)
1063 1084
1064 1085
1065/** 1086/**
1087 Fade the given color by spreading the fb_data (ushort)
1088 to an uint, multiply and compress the result back to a ushort.
1089 */
1090#if (LCD_PIXELFORMAT == RGB565SWAPPED)
1091static inline fb_data fade_color(fb_data c, unsigned int a)
1092{
1093 c = swap16(c);
1094 unsigned int p = ((((c|(c<<16)) & 0x07e0f81f) * a) >> 5) & 0x07e0f81f;
1095 return swap16( (fb_data) (p | ( p >> 16 )) );
1096}
1097#else
1098static inline fb_data fade_color(fb_data c, unsigned int a)
1099{
1100 unsigned int p = ((((c|(c<<16)) & 0x07e0f81f) * a) >> 5) & 0x07e0f81f;
1101 return (p | ( p >> 16 ));
1102}
1103#endif
1104
1105
1106
1107
1108/**
1066 Render a single slide 1109 Render a single slide
1067*/ 1110*/
1068void render_slide(struct slide_data *slide, struct rect *result_rect, 1111void render_slide(struct slide_data *slide, struct rect *result_rect,
1069 int alpha, int col1, int col2) 1112 const int alpha, int col1, int col2)
1070{ 1113{
1071 rb->memset(result_rect, 0, sizeof(struct rect)); 1114 rb->memset(result_rect, 0, sizeof(struct rect));
1072 struct bitmap *bmp = surface(slide->slide_index); 1115 struct bitmap *bmp = surface(slide->slide_index);
@@ -1075,11 +1118,11 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1075 } 1118 }
1076 fb_data *src = (fb_data *)bmp->data; 1119 fb_data *src = (fb_data *)bmp->data;
1077 1120
1078 int sw = bmp->height; 1121 const int sw = bmp->height;
1079 int sh = bmp->width; 1122 const int sh = bmp->width;
1080 1123
1081 int h = LCD_HEIGHT; 1124 const int h = LCD_HEIGHT;
1082 int w = LCD_WIDTH; 1125 const int w = LCD_WIDTH;
1083 1126
1084 if (col1 > col2) { 1127 if (col1 > col2) {
1085 int c = col2; 1128 int c = col2;
@@ -1092,13 +1135,15 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1092 col1 = fmin(col1, w - 1); 1135 col1 = fmin(col1, w - 1);
1093 col2 = fmin(col2, w - 1); 1136 col2 = fmin(col2, w - 1);
1094 1137
1095 int distance = h * 100 / zoom; 1138 int distance = (h + slide->distance) * 100 / config.zoom;
1139 if (distance < 100 ) distance = 100; /* clamp distances */
1096 PFreal sdx = fcos(slide->angle); 1140 PFreal sdx = fcos(slide->angle);
1097 PFreal sdy = fsin(slide->angle); 1141 PFreal sdy = fsin(slide->angle);
1098 PFreal xs = slide->cx - bmp->width * sdx / 4; 1142 PFreal xs = slide->cx - bmp->width * sdx / 4;
1099 PFreal ys = slide->cy - bmp->width * sdy / 4; 1143 PFreal ys = slide->cy - bmp->width * sdy / 4;
1100 PFreal dist = distance * PFREAL_ONE; 1144 PFreal dist = distance * PFREAL_ONE;
1101 1145
1146 const int alpha4 = alpha >> 3;
1102 1147
1103 int xi = fmax((PFreal) 0, 1148 int xi = fmax((PFreal) 0,
1104 ((w * PFREAL_ONE / 2) + 1149 ((w * PFREAL_ONE / 2) +
@@ -1128,7 +1173,7 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1128 1173
1129 PFreal hitdist = fdiv(hitx - slide->cx, sdx); 1174 PFreal hitdist = fdiv(hitx - slide->cx, sdx);
1130 1175
1131 int column = sw / 2 + (hitdist >> PFREAL_SHIFT); 1176 const int column = (sw >> 1) + (hitdist >> PFREAL_SHIFT);
1132 if (column >= sw) 1177 if (column >= sw)
1133 break; 1178 break;
1134 1179
@@ -1140,19 +1185,19 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1140 result_rect->left = x; 1185 result_rect->left = x;
1141 flag = true; 1186 flag = true;
1142 1187
1143 int y1 = h / 2; 1188 int y1 = (h >> 1);
1144 int y2 = y1 + 1; 1189 int y2 = y1 + 1;
1145 fb_data *pixel1 = &buffer[y1 * BUFFER_WIDTH + x]; 1190 fb_data *pixel1 = &buffer[y1 * BUFFER_WIDTH + x];
1146 fb_data *pixel2 = &buffer[y2 * BUFFER_WIDTH + x]; 1191 fb_data *pixel2 = &buffer[y2 * BUFFER_WIDTH + x];
1147 int pixelstep = pixel2 - pixel1; 1192 const int pixelstep = pixel2 - pixel1;
1148 1193
1149 int center = (sh / 2); 1194 int center = (sh >> 1);
1150 int dy = dist / h; 1195 int dy = dist / h;
1151 int p1 = center * PFREAL_ONE - dy / 2; 1196 int p1 = center * PFREAL_ONE - (dy >> 2);
1152 int p2 = center * PFREAL_ONE + dy / 2; 1197 int p2 = center * PFREAL_ONE + (dy >> 2);
1153
1154 1198
1155 const fb_data *ptr = &src[column * bmp->width]; 1199 const fb_data *ptr = &src[column * bmp->width];
1200
1156 if (alpha == 256) 1201 if (alpha == 256)
1157 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) { 1202 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
1158 *pixel1 = ptr[p1 >> PFREAL_SHIFT]; 1203 *pixel1 = ptr[p1 >> PFREAL_SHIFT];
@@ -1165,18 +1210,8 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1165 pixel2 += pixelstep; 1210 pixel2 += pixelstep;
1166 } else 1211 } else
1167 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) { 1212 while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
1168 fb_data c1 = ptr[p1 >> PFREAL_SHIFT]; 1213 *pixel1 = fade_color(ptr[p1 >> PFREAL_SHIFT], alpha4);
1169 fb_data c2 = ptr[p2 >> PFREAL_SHIFT]; 1214 *pixel2 = fade_color(ptr[p2 >> PFREAL_SHIFT], alpha4);
1170
1171 int r1 = RGB_UNPACK_RED(c1) * alpha / 256;
1172 int g1 = RGB_UNPACK_GREEN(c1) * alpha / 256;
1173 int b1 = RGB_UNPACK_BLUE(c1) * alpha / 256;
1174 int r2 = RGB_UNPACK_RED(c2) * alpha / 256;
1175 int g2 = RGB_UNPACK_GREEN(c2) * alpha / 256;
1176 int b2 = RGB_UNPACK_BLUE(c2) * alpha / 256;
1177
1178 *pixel1 = LCD_RGBPACK(r1, g1, b1);
1179 *pixel2 = LCD_RGBPACK(r2, g2, b2);
1180 p1 -= dy; 1215 p1 -= dy;
1181 p2 += dy; 1216 p2 += dy;
1182 y1--; 1217 y1--;
@@ -1197,7 +1232,7 @@ void render_slide(struct slide_data *slide, struct rect *result_rect,
1197/** 1232/**
1198 Jump the the given slide_index 1233 Jump the the given slide_index
1199 */ 1234 */
1200static inline void set_current_slide(int slide_index) 1235static inline void set_current_slide(const int slide_index)
1201{ 1236{
1202 step = 0; 1237 step = 0;
1203 center_index = fbound(slide_index, 0, number_of_slides - 1); 1238 center_index = fbound(slide_index, 0, number_of_slides - 1);
@@ -1211,10 +1246,8 @@ static inline void set_current_slide(int slide_index)
1211 */ 1246 */
1212void start_animation(void) 1247void start_animation(void)
1213{ 1248{
1214 if (!animation_is_active) { 1249 step = (target < center_slide.slide_index) ? -1 : 1;
1215 step = (target < center_slide.slide_index) ? -1 : 1; 1250 pf_state = pf_scrolling;
1216 animation_is_active = true;
1217 }
1218} 1251}
1219 1252
1220/** 1253/**
@@ -1222,11 +1255,14 @@ void start_animation(void)
1222 */ 1255 */
1223void show_previous_slide(void) 1256void show_previous_slide(void)
1224{ 1257{
1225 if (step >= 0) { 1258 if (step == 0) {
1226 if (center_index > 0) { 1259 if (center_index > 0) {
1227 target = center_index - 1; 1260 target = center_index - 1;
1228 start_animation(); 1261 start_animation();
1229 } 1262 }
1263 } else if ( step > 0 ) {
1264 target = center_index;
1265 start_animation();
1230 } else { 1266 } else {
1231 target = fmax(0, center_index - 2); 1267 target = fmax(0, center_index - 2);
1232 } 1268 }
@@ -1238,11 +1274,14 @@ void show_previous_slide(void)
1238 */ 1274 */
1239void show_next_slide(void) 1275void show_next_slide(void)
1240{ 1276{
1241 if (step <= 0) { 1277 if (step == 0) {
1242 if (center_index < number_of_slides - 1) { 1278 if (center_index < number_of_slides - 1) {
1243 target = center_index + 1; 1279 target = center_index + 1;
1244 start_animation(); 1280 start_animation();
1245 } 1281 }
1282 } else if ( step < 0 ) {
1283 target = center_index;
1284 start_animation();
1246 } else { 1285 } else {
1247 target = fmin(center_index + 2, number_of_slides - 1); 1286 target = fmin(center_index + 2, number_of_slides - 1);
1248 } 1287 }
@@ -1252,7 +1291,7 @@ void show_next_slide(void)
1252/** 1291/**
1253 Return true if the rect has size 0 1292 Return true if the rect has size 0
1254*/ 1293*/
1255bool is_empty_rect(struct rect *r) 1294static inline bool is_empty_rect(struct rect *r)
1256{ 1295{
1257 return ((r->left == 0) && (r->right == 0) && (r->top == 0) 1296 return ((r->left == 0) && (r->right == 0) && (r->top == 0)
1258 && (r->bottom == 0)); 1297 && (r->bottom == 0));
@@ -1262,7 +1301,7 @@ bool is_empty_rect(struct rect *r)
1262/** 1301/**
1263 Render the slides. Updates only the offscreen buffer. 1302 Render the slides. Updates only the offscreen buffer.
1264*/ 1303*/
1265void render(void) 1304void render_all_slides(void)
1266{ 1305{
1267 rb->lcd_set_background(LCD_RGBPACK(0,0,0)); 1306 rb->lcd_set_background(LCD_RGBPACK(0,0,0));
1268 rb->lcd_clear_display(); /* TODO: Optimizes this by e.g. invalidating rects */ 1307 rb->lcd_clear_display(); /* TODO: Optimizes this by e.g. invalidating rects */
@@ -1271,6 +1310,7 @@ void render(void)
1271 int nright = config.show_slides; 1310 int nright = config.show_slides;
1272 1311
1273 struct rect r; 1312 struct rect r;
1313 r.left = LCD_WIDTH; r.top = 0; r.bottom = 0; r.right = 0;
1274 render_slide(&center_slide, &r, 256, -1, -1); 1314 render_slide(&center_slide, &r, 256, -1, -1);
1275#ifdef DEBUG_DRAW 1315#ifdef DEBUG_DRAW
1276 rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top); 1316 rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
@@ -1282,6 +1322,8 @@ void render(void)
1282 /* no animation, boring plain rendering */ 1322 /* no animation, boring plain rendering */
1283 for (index = 0; index < nleft - 1; index++) { 1323 for (index = 0; index < nleft - 1; index++) {
1284 int alpha = (index < nleft - 2) ? 256 : 128; 1324 int alpha = (index < nleft - 2) ? 256 : 128;
1325 alpha -= extra_fade;
1326 if (alpha < 0 ) alpha = 0;
1285 render_slide(&left_slides[index], &r, alpha, 0, c1 - 1); 1327 render_slide(&left_slides[index], &r, alpha, 0, c1 - 1);
1286 if (!is_empty_rect(&r)) { 1328 if (!is_empty_rect(&r)) {
1287#ifdef DEBUG_DRAW 1329#ifdef DEBUG_DRAW
@@ -1292,6 +1334,8 @@ void render(void)
1292 } 1334 }
1293 for (index = 0; index < nright - 1; index++) { 1335 for (index = 0; index < nright - 1; index++) {
1294 int alpha = (index < nright - 2) ? 256 : 128; 1336 int alpha = (index < nright - 2) ? 256 : 128;
1337 alpha -= extra_fade;
1338 if (alpha < 0 ) alpha = 0;
1295 render_slide(&right_slides[index], &r, alpha, c2 + 1, 1339 render_slide(&right_slides[index], &r, alpha, c2 + 1,
1296 BUFFER_WIDTH); 1340 BUFFER_WIDTH);
1297 if (!is_empty_rect(&r)) { 1341 if (!is_empty_rect(&r)) {
@@ -1346,10 +1390,8 @@ void render(void)
1346/** 1390/**
1347 Updates the animation effect. Call this periodically from a timer. 1391 Updates the animation effect. Call this periodically from a timer.
1348*/ 1392*/
1349void update_animation(void) 1393void update_scroll_animation(void)
1350{ 1394{
1351 if (!animation_is_active)
1352 return;
1353 if (step == 0) 1395 if (step == 0)
1354 return; 1396 return;
1355 1397
@@ -1399,7 +1441,7 @@ void update_animation(void)
1399 1441
1400 if (center_index == target) { 1442 if (center_index == target) {
1401 reset_slides(); 1443 reset_slides();
1402 animation_is_active = false; 1444 pf_state = pf_idle;
1403 step = 0; 1445 step = 0;
1404 fade = 256; 1446 fade = 256;
1405 return; 1447 return;
@@ -1409,7 +1451,8 @@ void update_animation(void)
1409 struct slide_data *si = &left_slides[i]; 1451 struct slide_data *si = &left_slides[i];
1410 si->angle = itilt; 1452 si->angle = itilt;
1411 si->cx = 1453 si->cx =
1412 -(offsetX + config.spacing_between_slides * i * PFREAL_ONE + step * config.spacing_between_slides * ftick); 1454 -(offsetX + config.spacing_between_slides * i * PFREAL_ONE + step
1455 * config.spacing_between_slides * ftick);
1413 si->cy = offsetY; 1456 si->cy = offsetY;
1414 } 1457 }
1415 1458
@@ -1417,7 +1460,8 @@ void update_animation(void)
1417 struct slide_data *si = &right_slides[i]; 1460 struct slide_data *si = &right_slides[i];
1418 si->angle = -itilt; 1461 si->angle = -itilt;
1419 si->cx = 1462 si->cx =
1420 offsetX + config.spacing_between_slides * i * PFREAL_ONE - step * config.spacing_between_slides * ftick; 1463 offsetX + config.spacing_between_slides * i * PFREAL_ONE - step
1464 * config.spacing_between_slides * ftick;
1421 si->cy = offsetY; 1465 si->cy = offsetY;
1422 } 1466 }
1423 1467
@@ -1461,9 +1505,13 @@ void cleanup(void *parameter)
1461 } 1505 }
1462 if ( empty_slide_hid != - 1) 1506 if ( empty_slide_hid != - 1)
1463 rb->bufclose(empty_slide_hid); 1507 rb->bufclose(empty_slide_hid);
1508 rb->lcd_set_drawmode(old_drawmode);
1464} 1509}
1465 1510
1466 1511/**
1512 Create the "?" slide, that is shown while loading
1513 or when no cover was found.
1514 */
1467int create_empty_slide(bool force) 1515int create_empty_slide(bool force)
1468{ 1516{
1469 if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) { 1517 if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) {
@@ -1488,7 +1536,9 @@ int create_empty_slide(bool force)
1488int settings_menu(void) { 1536int settings_menu(void) {
1489 int selection = 0; 1537 int selection = 0;
1490 1538
1491 MENUITEM_STRINGLIST(settings_menu,"PictureFlow Settings",NULL,"Show FPS", "Spacing", "Center margin", "Number of slides", "Rebuild cache"); 1539 MENUITEM_STRINGLIST(settings_menu, "PictureFlow Settings", NULL, "Show FPS",
1540 "Spacing", "Center margin", "Number of slides", "Zoom",
1541 "Rebuild cache");
1492 1542
1493 do { 1543 do {
1494 selection=rb->do_menu(&settings_menu,&selection); 1544 selection=rb->do_menu(&settings_menu,&selection);
@@ -1498,14 +1548,16 @@ int settings_menu(void) {
1498 break; 1548 break;
1499 1549
1500 case 1: 1550 case 1:
1501 rb->set_int("Spacing between slides", "", 1, &(config.spacing_between_slides), 1551 rb->set_int("Spacing between slides", "", 1,
1552 &(config.spacing_between_slides),
1502 NULL, 1, 0, 100, NULL ); 1553 NULL, 1, 0, 100, NULL );
1503 recalc_table(); 1554 recalc_table();
1504 reset_slides(); 1555 reset_slides();
1505 break; 1556 break;
1506 1557
1507 case 2: 1558 case 2:
1508 rb->set_int("Center margin", "", 1, &(config.extra_spacing_for_center_slide), 1559 rb->set_int("Center margin", "", 1,
1560 &(config.extra_spacing_for_center_slide),
1509 NULL, 1, -50, 50, NULL ); 1561 NULL, 1, -50, 50, NULL );
1510 recalc_table(); 1562 recalc_table();
1511 reset_slides(); 1563 reset_slides();
@@ -1519,6 +1571,13 @@ int settings_menu(void) {
1519 break; 1571 break;
1520 1572
1521 case 4: 1573 case 4:
1574 rb->set_int("Number of slides", "", 1, &(config.zoom),
1575 NULL, 1, 10, 300, NULL );
1576 recalc_table();
1577 reset_slides();
1578 break;
1579
1580 case 5:
1522 rb->remove(CACHE_PREFIX "/ready"); 1581 rb->remove(CACHE_PREFIX "/ready");
1523 rb->remove(EMPTY_SLIDE); 1582 rb->remove(EMPTY_SLIDE);
1524 rb->splash(HZ, "Cache will be rebuilt on next restart"); 1583 rb->splash(HZ, "Cache will be rebuilt on next restart");
@@ -1566,21 +1625,43 @@ int main_menu(void)
1566 } 1625 }
1567} 1626}
1568 1627
1569bool read_pfconfig(void) 1628/**
1629 Fill the config struct with some defaults
1630 */
1631void set_default_config(void)
1570{ 1632{
1571 /* defaults */
1572 config.spacing_between_slides = 40; 1633 config.spacing_between_slides = 40;
1573 config.extra_spacing_for_center_slide = 0; 1634 config.extra_spacing_for_center_slide = 0;
1574 config.show_slides = 3; 1635 config.show_slides = 3;
1636 config.avg_album_width = 0;
1637 config.zoom = 100;
1638}
1639
1640/**
1641 Read the config file.
1642 For now, the size has to match.
1643 Later a version number might be appropiate.
1644 */
1645bool read_pfconfig(void)
1646{
1647 set_default_config();
1648 /* defaults */
1575 int fh = rb->open( CONFIG_FILE, O_RDONLY ); 1649 int fh = rb->open( CONFIG_FILE, O_RDONLY );
1576 if ( fh < 0 ) { /* no config yet */ 1650 if ( fh < 0 ) { /* no config yet */
1577 return true; 1651 return true;
1578 } 1652 }
1579 int ret = rb->read(fh, &config, sizeof(struct config_data)); 1653 int ret = rb->read(fh, &config, sizeof(struct config_data));
1580 rb->close(fh); 1654 rb->close(fh);
1581 return ( ret == sizeof(struct config_data) ); 1655 if ( ret != sizeof(struct config_data) ) {
1656 set_default_config();
1657 rb->splash(2*HZ, "Config invalid. Using defaults");
1658 }
1659 return true;
1582} 1660}
1583 1661
1662/**
1663 Write the config file
1664 */
1584bool write_pfconfig(void) 1665bool write_pfconfig(void)
1585{ 1666{
1586 int fh = rb->creat( CONFIG_FILE ); 1667 int fh = rb->creat( CONFIG_FILE );
@@ -1591,6 +1672,197 @@ bool write_pfconfig(void)
1591} 1672}
1592 1673
1593/** 1674/**
1675 Animation step for zooming into the current cover
1676 */
1677void update_cover_in_animation(void)
1678{
1679 cover_animation_keyframe++;
1680 if( cover_animation_keyframe < 20 ) {
1681 center_slide.distance-=5;
1682 center_slide.angle+=1;
1683 extra_fade += 13;
1684 }
1685 else if( cover_animation_keyframe < 35 ) {
1686 center_slide.angle+=16;
1687 }
1688 else {
1689 cover_animation_keyframe = 0;
1690 selected_track = 0;
1691 pf_state = pf_show_tracks;
1692 }
1693}
1694
1695/**
1696 Animation step for zooming out the current cover
1697 */
1698void update_cover_out_animation(void)
1699{
1700 cover_animation_keyframe++;
1701 if( cover_animation_keyframe <= 15 ) {
1702 center_slide.angle-=16;
1703 }
1704 else if( cover_animation_keyframe < 35 ) {
1705 center_slide.distance+=5;
1706 center_slide.angle-=1;
1707 extra_fade -= 13;
1708 }
1709 else {
1710 cover_animation_keyframe = 0;
1711 pf_state = pf_idle;
1712 }
1713}
1714
1715/**
1716 Draw a blue gradient at y with height h
1717 */
1718static inline void draw_gradient(int y, int h)
1719{
1720 static int r, inc, c;
1721 inc = (100 << 8) / h;
1722 c = 0;
1723 selected_track_pulse = (selected_track_pulse+1) % 10;
1724 int c2 = selected_track_pulse - 5;
1725 for (r=0; r<h; r++) {
1726 rb->lcd_set_foreground(LCD_RGBPACK(c2+80-(c >> 9), c2+100-(c >> 9),
1727 c2+250-(c >> 8)));
1728 rb->lcd_hline(0, LCD_WIDTH, r+y);
1729 if ( r > h/2 )
1730 c-=inc;
1731 else
1732 c+=inc;
1733 }
1734}
1735
1736
1737/**
1738 Reset the track list after a album change
1739 */
1740void reset_track_list(void)
1741{
1742 int albumtxt_w, albumtxt_h;
1743 const char* albumtxt = get_album_name(center_index);
1744 rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
1745 const int height = LCD_HEIGHT-albumtxt_h-10;
1746 track_list_visible_entries = fmin( height/albumtxt_h , track_count );
1747 start_index_track_list = 0;
1748 track_scroll_index = 0;
1749 track_scroll_dir = 1;
1750 selected_track = 0;
1751}
1752
1753/**
1754 Display the list of tracks
1755 */
1756void show_track_list(void)
1757{
1758 rb->lcd_clear_display();
1759 if ( center_slide.slide_index != track_index ) {
1760 create_track_index(center_slide.slide_index);
1761 reset_track_list();
1762 }
1763 static int titletxt_w, titletxt_h, titletxt_y, titletxt_x, i, color;
1764 titletxt_y = 0;
1765 int track_i;
1766 for (i=0; i < track_list_visible_entries; i++) {
1767 track_i = i+start_index_track_list;
1768 rb->lcd_getstringsize(get_track_name(track_i), &titletxt_w, &titletxt_h);
1769 titletxt_x = (LCD_WIDTH-titletxt_w)/2;
1770 if ( track_i == selected_track ) {
1771 draw_gradient(titletxt_y, titletxt_h);
1772 rb->lcd_set_foreground(LCD_RGBPACK(255,255,255));
1773 if (titletxt_w > LCD_WIDTH ) {
1774 if ( titletxt_w + track_scroll_index <= LCD_WIDTH )
1775 track_scroll_dir = 1;
1776 else if ( track_scroll_index >= 0 ) track_scroll_dir = -1;
1777 track_scroll_index += track_scroll_dir*2;
1778 titletxt_x = track_scroll_index;
1779 }
1780 rb->lcd_putsxy(titletxt_x,titletxt_y,get_track_name(track_i));
1781 }
1782 else {
1783 color = 250 - (abs(selected_track - track_i) * 200 / track_count);
1784 rb->lcd_set_foreground(LCD_RGBPACK(color,color,color));
1785 rb->lcd_putsxy(titletxt_x,titletxt_y,get_track_name(track_i));
1786 }
1787 titletxt_y += titletxt_h;
1788 }
1789}
1790
1791void select_next_track(void)
1792{
1793 if ( selected_track < track_count - 1 ) {
1794 selected_track++;
1795 track_scroll_index = 0;
1796 track_scroll_dir = 1;
1797 if (selected_track==(track_list_visible_entries+start_index_track_list))
1798 start_index_track_list++;
1799 }
1800}
1801
1802void select_prev_track(void)
1803{
1804 if (selected_track > 0 ) {
1805 if (selected_track==start_index_track_list) start_index_track_list--;
1806 track_scroll_index = 0;
1807 track_scroll_dir = 1;
1808 selected_track--;
1809 }
1810}
1811
1812/**
1813 Draw the current album name
1814 */
1815void draw_album_text(void)
1816{
1817 int albumtxt_w, albumtxt_h;
1818 int albumtxt_y = 0;
1819
1820 char *albumtxt;
1821 int c;
1822 /* Draw album text */
1823 if ( pf_state == pf_scrolling ) {
1824 c = ((slide_frame & 0xffff )/ 255);
1825 if (step < 0) c = 255-c;
1826 if (c > 128 ) { /* half way to next slide .. still not perfect! */
1827 albumtxt = get_album_name(center_index+step);
1828 c = (c-128)*2;
1829 }
1830 else {
1831 albumtxt = get_album_name(center_index);
1832 c = (128-c)*2;
1833 }
1834 }
1835 else {
1836 c= 255;
1837 albumtxt = get_album_name(center_index);
1838 }
1839
1840 rb->lcd_set_foreground(LCD_RGBPACK(c,c,c));
1841 rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
1842 if (center_index != prev_center_index) {
1843 albumtxt_x = 0;
1844 albumtxt_dir = -1;
1845 prev_center_index = center_index;
1846 }
1847 albumtxt_y = LCD_HEIGHT-albumtxt_h-10;
1848
1849 if (albumtxt_w > LCD_WIDTH ) {
1850 rb->lcd_putsxy(albumtxt_x, albumtxt_y , albumtxt);
1851 if ( pf_state == pf_idle || pf_state == pf_show_tracks ) {
1852 if ( albumtxt_w + albumtxt_x <= LCD_WIDTH ) albumtxt_dir = 1;
1853 else if ( albumtxt_x >= 0 ) albumtxt_dir = -1;
1854 albumtxt_x += albumtxt_dir;
1855 }
1856 }
1857 else {
1858 rb->lcd_putsxy((LCD_WIDTH - albumtxt_w) /2, albumtxt_y , albumtxt);
1859 }
1860
1861
1862}
1863
1864
1865/**
1594 Main function that also contain the main plasma 1866 Main function that also contain the main plasma
1595 algorithm. 1867 algorithm.
1596 */ 1868 */
@@ -1601,7 +1873,7 @@ int main(void)
1601 1873
1602 if ( ! rb->dir_exists( CACHE_PREFIX ) ) { 1874 if ( ! rb->dir_exists( CACHE_PREFIX ) ) {
1603 if ( rb->mkdir( CACHE_PREFIX ) < 0 ) { 1875 if ( rb->mkdir( CACHE_PREFIX ) < 0 ) {
1604 rb->splash(HZ, "Could not create directory"); 1876 rb->splash(HZ, "Could not create directory " CACHE_PREFIX );
1605 return PLUGIN_ERROR; 1877 return PLUGIN_ERROR;
1606 } 1878 }
1607 } 1879 }
@@ -1657,8 +1929,11 @@ int main(void)
1657 slide_cache_stack_index = min_slide_cache-1; 1929 slide_cache_stack_index = min_slide_cache-1;
1658 slide_cache_in_use = 0; 1930 slide_cache_in_use = 0;
1659 buffer = rb->lcd_framebuffer; 1931 buffer = rb->lcd_framebuffer;
1660 animation_is_active = false; 1932
1661 zoom = 100; 1933 pf_state = pf_idle;
1934
1935 track_index = -1;
1936 extra_fade = 0;
1662 center_index = 0; 1937 center_index = 0;
1663 slide_frame = 0; 1938 slide_frame = 0;
1664 step = 0; 1939 step = 0;
@@ -1670,7 +1945,6 @@ int main(void)
1670 reset_slides(); 1945 reset_slides();
1671 1946
1672 char fpstxt[10]; 1947 char fpstxt[10];
1673 char *albumtxt;
1674 int button; 1948 int button;
1675 1949
1676#ifdef HAVE_ADJUSTABLE_CPU_FREQ 1950#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -1681,58 +1955,65 @@ int main(void)
1681 long current_update; 1955 long current_update;
1682 long update_interval = 100; 1956 long update_interval = 100;
1683 int fps = 0; 1957 int fps = 0;
1684 int albumtxt_w, albumtxt_h;
1685 int albumtxt_x = 0, albumtxt_y = 0;
1686 int albumtxt_dir = -1;
1687 int c;
1688 int prev_center_index = -1;
1689 1958
1959 bool instant_update;
1960 old_drawmode = rb->lcd_get_drawmode();
1961 rb->lcd_set_drawmode(DRMODE_FG);
1690 while (true) { 1962 while (true) {
1691 current_update = *rb->current_tick; 1963 current_update = *rb->current_tick;
1692 frames++; 1964 frames++;
1693 update_animation();
1694 render();
1695 1965
1966 /* Initial rendering */
1967 instant_update = false;
1968
1969 /* Handle states */
1970 switch ( pf_state ) {
1971 case pf_scrolling:
1972 update_scroll_animation();
1973 render_all_slides();
1974 instant_update = true;
1975 break;
1976 case pf_cover_in:
1977 update_cover_in_animation();
1978 render_all_slides();
1979 instant_update = true;
1980 break;
1981 case pf_cover_out:
1982 update_cover_out_animation();
1983 render_all_slides();
1984 instant_update = true;
1985 break;
1986 case pf_show_tracks:
1987 show_track_list();
1988 break;
1989 case pf_idle:
1990 render_all_slides();
1991 break;
1992 }
1993
1994 /* Calculate FPS */
1696 if (current_update - last_update > update_interval) { 1995 if (current_update - last_update > update_interval) {
1697 fps = frames * HZ / (current_update - last_update); 1996 fps = frames * HZ / (current_update - last_update);
1698 last_update = current_update; 1997 last_update = current_update;
1699 frames = 0; 1998 frames = 0;
1700 } 1999 }
1701 2000
2001 /* Draw FPS */
1702 if (show_fps) { 2002 if (show_fps) {
1703 rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0)); 2003 rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
1704 rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps); 2004 rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
1705 rb->lcd_putsxy(0, 0, fpstxt); 2005 rb->lcd_putsxy(0, 0, fpstxt);
1706 } 2006 }
1707 2007
1708 albumtxt = get_album_name(center_index); 2008 draw_album_text();
1709 if ( animation_is_active ) { 2009
1710 c = ((slide_frame & 0xffff )/ 256);
1711 if (step > 0) c = 255-c;
1712 }
1713 else c= 255;
1714 rb->lcd_set_foreground(LCD_RGBPACK(c,c,c));
1715 rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
1716 if (center_index != prev_center_index) {
1717 albumtxt_x = 0;
1718 albumtxt_dir = -1;
1719 albumtxt_y = LCD_HEIGHT-albumtxt_h-10;
1720 prev_center_index = center_index;
1721 }
1722 if (albumtxt_w > LCD_WIDTH && ! animation_is_active ) {
1723 rb->lcd_putsxy(albumtxt_x, albumtxt_y , albumtxt);
1724 if ( albumtxt_w + albumtxt_x <= LCD_WIDTH ) albumtxt_dir = 1;
1725 else if ( albumtxt_x >= 0 ) albumtxt_dir = -1;
1726 albumtxt_x += albumtxt_dir;
1727 }
1728 else {
1729 rb->lcd_putsxy((LCD_WIDTH - albumtxt_w) /2, albumtxt_y , albumtxt);
1730 }
1731 2010
2011 /* Copy offscreen buffer to LCD and give time to other threads */
1732 rb->lcd_update(); 2012 rb->lcd_update();
1733 rb->yield(); 2013 rb->yield();
1734 2014
1735 button = pluginlib_getaction(rb, animation_is_active ? 0 : HZ/16, 2015 /*/ Handle buttons */
2016 button = pluginlib_getaction(rb, instant_update ? 0 : HZ/16,
1736 plugin_contexts, NB_ACTION_CONTEXTS); 2017 plugin_contexts, NB_ACTION_CONTEXTS);
1737 2018
1738 switch (button) { 2019 switch (button) {
@@ -1740,19 +2021,56 @@ int main(void)
1740 return PLUGIN_OK; 2021 return PLUGIN_OK;
1741 2022
1742 case PICTUREFLOW_MENU: 2023 case PICTUREFLOW_MENU:
1743 ret = main_menu(); 2024 if ( pf_state == pf_idle || pf_state == pf_scrolling ) {
1744 if ( ret == -1 ) return PLUGIN_OK; 2025 ret = main_menu();
1745 if ( ret != 0 ) return i; 2026 if ( ret == -1 ) return PLUGIN_OK;
2027 if ( ret != 0 ) return i;
2028 rb->lcd_set_drawmode(DRMODE_FG);
2029 }
2030 else {
2031 pf_state = pf_cover_out;
2032 }
1746 break; 2033 break;
1747 2034
1748 case PICTUREFLOW_NEXT_ALBUM: 2035 case PICTUREFLOW_NEXT_ALBUM:
1749 case PICTUREFLOW_NEXT_ALBUM_REPEAT: 2036 case PICTUREFLOW_NEXT_ALBUM_REPEAT:
1750 show_next_slide(); 2037#ifdef SCROLLWHEEL
2038 if ( pf_state == pf_show_tracks )
2039 select_next_track();
2040#endif
2041 if ( pf_state == pf_idle || pf_state == pf_scrolling )
2042 show_next_slide();
1751 break; 2043 break;
1752 2044
1753 case PICTUREFLOW_PREV_ALBUM: 2045 case PICTUREFLOW_PREV_ALBUM:
1754 case PICTUREFLOW_PREV_ALBUM_REPEAT: 2046 case PICTUREFLOW_PREV_ALBUM_REPEAT:
1755 show_previous_slide(); 2047#ifdef SCROLLWHEEL
2048 if ( pf_state == pf_show_tracks )
2049 select_prev_track();
2050#endif
2051 if ( pf_state == pf_idle || pf_state == pf_scrolling )
2052 show_previous_slide();
2053 break;
2054
2055#ifndef SCROLLWHEEL
2056 case PICTUREFLOW_NEXT_TRACK:
2057 case PICTUREFLOW_NEXT_TRACK_REPEAT:
2058 if ( pf_state == pf_show_tracks )
2059 select_next_track();
2060 break;
2061
2062 case PICTUREFLOW_PREV_TRACK:
2063 case PICTUREFLOW_PREV_TRACK_REPEAT:
2064 if ( pf_state == pf_show_tracks )
2065 select_prev_track();
2066 break;
2067#endif
2068
2069 case PICTUREFLOW_SELECT_ALBUM:
2070 if ( pf_state == pf_idle )
2071 pf_state = pf_cover_in;
2072 if ( pf_state == pf_show_tracks )
2073 pf_state = pf_cover_out;
1756 break; 2074 break;
1757 2075
1758 default: 2076 default: