summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/pictureflow.c622
1 files changed, 383 insertions, 239 deletions
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index 5613ce82bd..cead25c959 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -32,6 +32,7 @@
32#include "pluginbitmaps/pictureflow_logo.h" 32#include "pluginbitmaps/pictureflow_logo.h"
33#include "lib/grey.h" 33#include "lib/grey.h"
34#include "lib/feature_wrappers.h" 34#include "lib/feature_wrappers.h"
35#include "lib/buflib.h"
35 36
36PLUGIN_HEADER 37PLUGIN_HEADER
37 38
@@ -116,7 +117,7 @@ typedef fb_data pix_t;
116#define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF) 117#define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF)
117#define MAXSLIDE_LEFT_R (PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF) 118#define MAXSLIDE_LEFT_R (PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF)
118 119
119#define SLIDE_CACHE_SIZE 100 120#define SLIDE_CACHE_SIZE 64 /* probably more than can be loaded */
120 121
121#define MAX_SLIDES_COUNT 10 122#define MAX_SLIDES_COUNT 10
122 123
@@ -127,8 +128,6 @@ typedef fb_data pix_t;
127#define EV_WAKEUP 1337 128#define EV_WAKEUP 1337
128 129
129/* maximum number of albums */ 130/* maximum number of albums */
130#define MAX_ALBUMS 1024
131#define AVG_ALBUM_NAME_LENGTH 20
132 131
133#define MAX_TRACKS 50 132#define MAX_TRACKS 50
134#define AVG_TRACK_NAME_LENGTH 20 133#define AVG_TRACK_NAME_LENGTH 20
@@ -161,7 +160,8 @@ struct slide_data {
161struct slide_cache { 160struct slide_cache {
162 int index; /* index of the cached slide */ 161 int index; /* index of the cached slide */
163 int hid; /* handle ID of the cached slide */ 162 int hid; /* handle ID of the cached slide */
164 long touched; /* last time the slide was touched */ 163 short next; /* "next" slide, with LRU last */
164 short prev; /* "previous" slide */
165}; 165};
166 166
167struct album_data { 167struct album_data {
@@ -196,7 +196,7 @@ const struct picture logos[]={
196 {pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo}, 196 {pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo},
197}; 197};
198 198
199enum show_album_name_values { album_name_hide = 0, album_name_bottom , 199enum show_album_name_values { album_name_hide = 0, album_name_bottom,
200 album_name_top }; 200 album_name_top };
201static char* show_album_name_conf[] = 201static char* show_album_name_conf[] =
202{ 202{
@@ -216,7 +216,8 @@ static int zoom = 100;
216static bool show_fps = false; 216static bool show_fps = false;
217static bool resize = true; 217static bool resize = true;
218static int cache_version = 0; 218static int cache_version = 0;
219static int show_album_name = (LCD_HEIGHT > 100) ? album_name_top : album_name_bottom; 219static int show_album_name = (LCD_HEIGHT > 100)
220 ? album_name_top : album_name_bottom;
220 221
221static struct configdata config[] = 222static struct configdata config[] =
222{ 223{
@@ -239,7 +240,7 @@ static struct configdata config[] =
239/** below we allocate the memory we want to use **/ 240/** below we allocate the memory we want to use **/
240 241
241static pix_t *buffer; /* for now it always points to the lcd framebuffer */ 242static pix_t *buffer; /* for now it always points to the lcd framebuffer */
242static uint16_t reflect_table[REFLECT_HEIGHT]; 243static uint8_t reflect_table[REFLECT_HEIGHT];
243static struct slide_data center_slide; 244static struct slide_data center_slide;
244static struct slide_data left_slides[MAX_SLIDES_COUNT]; 245static struct slide_data left_slides[MAX_SLIDES_COUNT];
245static struct slide_data right_slides[MAX_SLIDES_COUNT]; 246static struct slide_data right_slides[MAX_SLIDES_COUNT];
@@ -247,32 +248,34 @@ static int slide_frame;
247static int step; 248static int step;
248static int target; 249static int target;
249static int fade; 250static int fade;
250static int center_index; /* index of the slide that is in the center */ 251static int center_index = 0; /* index of the slide that is in the center */
251static int itilt; 252static int itilt;
252static PFreal offsetX; 253static PFreal offsetX;
253static PFreal offsetY; 254static PFreal offsetY;
254static int number_of_slides; 255static int number_of_slides;
255 256
256static struct slide_cache cache[SLIDE_CACHE_SIZE]; 257static struct slide_cache cache[SLIDE_CACHE_SIZE];
257static int slide_cache_in_use; 258static int cache_free;
259static int cache_used = -1;
260static int cache_left_index = -1;
261static int cache_right_index = -1;
262static int cache_center_index = -1;
258 263
259/* use long for aligning */ 264/* use long for aligning */
260unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; 265unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
261/* queue (as array) for scheduling load_surface */ 266/* queue (as array) for scheduling load_surface */
262static int slide_cache_stack[SLIDE_CACHE_SIZE];
263static int slide_cache_stack_index;
264struct mutex slide_cache_stack_lock;
265 267
266static int empty_slide_hid; 268static int empty_slide_hid;
267 269
268unsigned int thread_id; 270unsigned int thread_id;
269struct event_queue thread_q; 271struct event_queue thread_q;
270 272
271static long uniqbuf[UNIQBUF_SIZE];
272static struct tagcache_search tcs; 273static struct tagcache_search tcs;
273 274
274static struct album_data album[MAX_ALBUMS]; 275static struct buflib_context buf_ctx;
275static char album_names[MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH]; 276
277static struct album_data *album;
278static char *album_names;
276static int album_count; 279static int album_count;
277 280
278static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH]; 281static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH];
@@ -333,6 +336,7 @@ static int pf_state;
333/** code */ 336/** code */
334static inline pix_t fade_color(pix_t c, unsigned int a); 337static inline pix_t fade_color(pix_t c, unsigned int a);
335bool save_pfraw(char* filename, struct bitmap *bm); 338bool save_pfraw(char* filename, struct bitmap *bm);
339bool load_new_slide(void);
336int load_surface(int); 340int load_surface(int);
337 341
338static inline PFreal fmul(PFreal a, PFreal b) 342static inline PFreal fmul(PFreal a, PFreal b)
@@ -398,7 +402,7 @@ static inline int clz(uint32_t v)
398} 402}
399#else 403#else
400static const char clz_lut[16] = { 4, 3, 2, 2, 1, 1, 1, 1, 404static const char clz_lut[16] = { 4, 3, 2, 2, 1, 1, 1, 1,
401 0, 0, 0, 0, 0, 0, 0, 0 }; 405 0, 0, 0, 0, 0, 0, 0, 0 };
402/* This clz is based on the log2(n) implementation at 406/* This clz is based on the log2(n) implementation at
403 * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup 407 * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
404 * It is not any faster than the one above, but trades 16B in the lookup table 408 * It is not any faster than the one above, but trades 16B in the lookup table
@@ -472,7 +476,7 @@ static inline PFreal fdiv(PFreal n, PFreal m)
472#endif 476#endif
473 477
474/* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */ 478/* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */
475static const PFreal sin_tab[] = { 479static const short sin_tab[] = {
476 0, 100, 200, 297, 392, 483, 569, 650, 480 0, 100, 200, 297, 392, 483, 569, 650,
477 724, 792, 851, 903, 946, 980, 1004, 1019, 481 724, 792, 851, 903, 946, 980, 1004, 1019,
478 1024, 1019, 1004, 980, 946, 903, 851, 792, 482 1024, 1019, 1004, 980, 946, 903, 851, 792,
@@ -562,30 +566,43 @@ void init_reflect_table(void)
562 */ 566 */
563int create_album_index(void) 567int create_album_index(void)
564{ 568{
569 plugin_buf_size -= UNIQBUF_SIZE * sizeof(long);
570 long *uniqbuf = (long *)(plugin_buf_size + (char *)plugin_buf);
571 album = ((struct album_data *)uniqbuf) - 1;
565 rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); 572 rb->memset(&tcs, 0, sizeof(struct tagcache_search) );
566 album_count = 0; 573 album_count = 0;
567 rb->tagcache_search(&tcs, tag_album); 574 rb->tagcache_search(&tcs, tag_album);
568 rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE); 575 rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE);
569 int l, old_l = 0; 576 unsigned int l, old_l = 0;
577 album_names = plugin_buf;
570 album[0].name_idx = 0; 578 album[0].name_idx = 0;
571 while (rb->tagcache_get_next(&tcs) && album_count < MAX_ALBUMS) 579 while (rb->tagcache_get_next(&tcs))
572 { 580 {
581 plugin_buf_size -= sizeof(struct album_data);
573 l = rb->strlen(tcs.result) + 1; 582 l = rb->strlen(tcs.result) + 1;
574 if ( album_count > 0 ) 583 if ( album_count > 0 )
575 album[album_count].name_idx = album[album_count-1].name_idx + old_l; 584 album[-album_count].name_idx = album[1-album_count].name_idx + old_l;
576 585
577 if ( (album[album_count].name_idx + l) > 586 if ( l > plugin_buf_size )
578 MAX_ALBUMS*AVG_ALBUM_NAME_LENGTH )
579 /* not enough memory */ 587 /* not enough memory */
580 return ERROR_BUFFER_FULL; 588 return ERROR_BUFFER_FULL;
581 589
582 rb->strcpy(album_names + album[album_count].name_idx, tcs.result); 590 rb->strcpy(plugin_buf, tcs.result);
583 album[album_count].seek = tcs.result_seek; 591 plugin_buf_size -= l;
592 plugin_buf = l + (char *)plugin_buf;
593 album[-album_count].seek = tcs.result_seek;
584 old_l = l; 594 old_l = l;
585 album_count++; 595 album_count++;
586 } 596 }
587 rb->tagcache_search_finish(&tcs); 597 rb->tagcache_search_finish(&tcs);
588 598 ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
599 int i;
600 struct album_data* tmp_album = (struct album_data*)plugin_buf;
601 for (i = album_count - 1; i >= 0; i--)
602 tmp_album[i] = album[-i];
603 album = tmp_album;
604 plugin_buf = album + album_count;
605 plugin_buf_size += UNIQBUF_SIZE * sizeof(long);
589 return (album_count > 0) ? 0 : ERROR_NO_ALBUMS; 606 return (album_count > 0) ? 0 : ERROR_NO_ALBUMS;
590} 607}
591 608
@@ -825,123 +842,6 @@ bool create_albumart_cache(void)
825} 842}
826 843
827/** 844/**
828 Return the index on the stack of slide_index.
829 Return -1 if slide_index is not on the stack.
830 */
831static inline int slide_stack_get_index(const int slide_index)
832{
833 int i = slide_cache_stack_index + 1;
834 while (i--) {
835 if ( slide_cache_stack[i] == slide_index ) return i;
836 };
837 return -1;
838}
839
840/**
841 Push the slide_index on the stack so the image will be loaded.
842 The algorithm tries to keep the center_index on top and the
843 slide_index as high as possible (so second if center_index is
844 on the stack).
845 */
846void slide_stack_push(const int slide_index)
847{
848 rb->mutex_lock(&slide_cache_stack_lock);
849
850 if ( slide_cache_stack_index == -1 ) {
851 /* empty stack, no checks at all */
852 slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
853 rb->mutex_unlock(&slide_cache_stack_lock);
854 return;
855 }
856
857 int i = slide_stack_get_index( slide_index );
858
859 if ( i == slide_cache_stack_index ) {
860 /* slide_index is on top, so we do not change anything */
861 rb->mutex_unlock(&slide_cache_stack_lock);
862 return;
863 }
864
865 if ( i >= 0 ) {
866 /* slide_index is already on the stack, but not on top */
867 int tmp = slide_cache_stack[ slide_cache_stack_index ];
868 if ( tmp == center_index ) {
869 /* the center_index is on top of the stack so do not touch that */
870 if ( slide_cache_stack_index > 0 ) {
871 /*
872 but maybe it is possible to swap the given slide_index to
873 the second place
874 */
875 tmp = slide_cache_stack[slide_cache_stack_index - 1];
876 slide_cache_stack[slide_cache_stack_index - 1] =
877 slide_cache_stack[i];
878 slide_cache_stack[i] = tmp;
879 }
880 }
881 else {
882 /*
883 if the center_index is not on top (i.e. already loaded) bring
884 the slide_index to the top
885 */
886 slide_cache_stack[slide_cache_stack_index] = slide_cache_stack[i];
887 slide_cache_stack[i] = tmp;
888 }
889 }
890 else {
891 /* slide_index is not on the stack */
892 if ( slide_cache_stack_index >= SLIDE_CACHE_SIZE-1 ) {
893 /*
894 if we exceeded the stack size, clear the first half of the
895 stack
896 */
897 slide_cache_stack_index = SLIDE_CACHE_SIZE/2;
898 for (i = 0; i <= slide_cache_stack_index ; i++)
899 slide_cache_stack[i] = slide_cache_stack[i +
900 slide_cache_stack_index];
901 }
902 if ( slide_cache_stack[ slide_cache_stack_index ] == center_index ) {
903 /* if the center_index is on top leave it there */
904 slide_cache_stack[ slide_cache_stack_index ] = slide_index;
905 slide_cache_stack[ ++slide_cache_stack_index ] = center_index;
906 }
907 else {
908 /* usual stack case: push the slide_index on top */
909 slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
910 }
911 }
912 rb->mutex_unlock(&slide_cache_stack_lock);
913}
914
915
916/**
917 Pop the topmost item from the stack and decrease the stack size
918 */
919static inline int slide_stack_pop(void)
920{
921 rb->mutex_lock(&slide_cache_stack_lock);
922 int result;
923 if ( slide_cache_stack_index >= 0 )
924 result = slide_cache_stack[ slide_cache_stack_index-- ];
925 else
926 result = -1;
927 rb->mutex_unlock(&slide_cache_stack_lock);
928 return result;
929}
930
931
932/**
933 Load the slide into the cache.
934 Thus we have to queue the loading request in our thread while discarding the
935 oldest slide.
936 */
937static inline void request_surface(const int slide_index)
938{
939 slide_stack_push(slide_index);
940 rb->queue_post(&thread_q, EV_WAKEUP, 0);
941}
942
943
944/**
945 Thread used for loading and preparing bitmaps in the background 845 Thread used for loading and preparing bitmaps in the background
946 */ 846 */
947void thread(void) 847void thread(void)
@@ -957,10 +857,8 @@ void thread(void)
957 /* we just woke up */ 857 /* we just woke up */
958 break; 858 break;
959 } 859 }
960 int slide_index; 860 while ( load_new_slide() ) {
961 while ( (slide_index = slide_stack_pop()) != -1 ) { 861 rb->yield();
962 load_surface( slide_index );
963 rb->queue_wait_w_tmo(&thread_q, &ev, HZ/10);
964 switch (ev.id) { 862 switch (ev.id) {
965 case EV_EXIT: 863 case EV_EXIT:
966 return; 864 return;
@@ -999,13 +897,15 @@ bool create_pf_thread(void)
999 sizeof(thread_stack), 897 sizeof(thread_stack),
1000 0, 898 0,
1001 "Picture load thread" 899 "Picture load thread"
1002 IF_PRIO(, PRIORITY_BACKGROUND) 900 IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2,
901 PRIORITY_REALTIME + 1))
1003 IF_COP(, CPU) 902 IF_COP(, CPU)
1004 ) 903 )
1005 ) == 0) { 904 ) == 0) {
1006 return false; 905 return false;
1007 } 906 }
1008 thread_is_running = true; 907 thread_is_running = true;
908 rb->queue_post(&thread_q, EV_WAKEUP, 0);
1009 return true; 909 return true;
1010} 910}
1011 911
@@ -1031,45 +931,201 @@ bool save_pfraw(char* filename, struct bitmap *bm)
1031} 931}
1032 932
1033 933
934/*
935 * The following functions implement the linked-list-in-array used to manage
936 * the LRU cache of slides, and the list of free cache slots.
937 */
938
939#define seek_right_while(start, cond) \
940({ \
941 int ind_, next_ = (start); \
942 do { \
943 ind_ = next_; \
944 next_ = cache[ind_].next; \
945 } while (next_ != cache_used && (cond)); \
946 ind_; \
947})
948
949#define seek_left_while(start, cond) \
950({ \
951 int ind_, next_ = (start); \
952 do { \
953 ind_ = next_; \
954 next_ = cache[ind_].prev; \
955 } while (ind_ != cache_used && (cond)); \
956 ind_; \
957})
958
959/**
960 Pop the given item from the linked list starting at *head, returning the next
961 item, or -1 if the list is now empty.
962*/
963static inline int lla_pop_item (int *head, int i)
964{
965 int prev = cache[i].prev;
966 int next = cache[i].next;
967 if (i == next)
968 {
969 *head = -1;
970 return -1;
971 }
972 else if (i == *head)
973 *head = next;
974 cache[next].prev = prev;
975 cache[prev].next = next;
976 return next;
977}
978
979
980/**
981 Pop the head item from the list starting at *head, returning the index of the
982 item, or -1 if the list is already empty.
983*/
984static inline int lla_pop_head (int *head)
985{
986 int i = *head;
987 if (i != -1)
988 lla_pop_item(head, i);
989 return i;
990}
991
992/**
993 Insert the item at index i before the one at index p.
994*/
995static inline void lla_insert (int i, int p)
996{
997 int next = p;
998 int prev = cache[next].prev;
999 cache[next].prev = i;
1000 cache[prev].next = i;
1001 cache[i].next = next;
1002 cache[i].prev = prev;
1003}
1004
1005
1006/**
1007 Insert the item at index i at the end of the list starting at *head.
1008*/
1009static inline void lla_insert_tail (int *head, int i)
1010{
1011 if (*head == -1)
1012 {
1013 *head = i;
1014 cache[i].next = i;
1015 cache[i].prev = i;
1016 } else
1017 lla_insert(i, *head);
1018}
1019
1020/**
1021 Insert the item at index i before the one at index p.
1022*/
1023static inline void lla_insert_after(int i, int p)
1024{
1025 p = cache[p].next;
1026 lla_insert(i, p);
1027}
1028
1029
1030/**
1031 Insert the item at index i before the one at index p in the list starting at
1032 *head
1033*/
1034static inline void lla_insert_before(int *head, int i, int p)
1035{
1036 lla_insert(i, p);
1037 if (*head == p)
1038 *head = i;
1039}
1040
1041
1042/**
1043 Free the used slide at index i, and its buffer, and move it to the free
1044 slides list.
1045*/
1046static inline void free_slide(int i)
1047{
1048 if (cache[i].hid != empty_slide_hid)
1049 buflib_free(&buf_ctx, cache[i].hid);
1050 cache[i].index = -1;
1051 lla_pop_item(&cache_used, i);
1052 lla_insert_tail(&cache_free, i);
1053 if (cache_used == -1)
1054 {
1055 cache_right_index = -1;
1056 cache_left_index = -1;
1057 cache_center_index = -1;
1058 }
1059}
1060
1061
1062/**
1063 Free one slide ranked above the given priority. If no such slide can be found,
1064 return false.
1065*/
1066static inline int free_slide_prio(int prio)
1067{
1068 if (cache_used == -1)
1069 return false;
1070 int i, l = cache_used, r = cache[cache_used].prev, prio_max;
1071 int prio_l = cache[l].index < center_index ?
1072 center_index - cache[l].index : 0;
1073 int prio_r = cache[r].index > center_index ?
1074 cache[r].index - center_index : 0;
1075 if (prio_l > prio_r)
1076 {
1077 i = l;
1078 prio_max = prio_l;
1079 } else {
1080 i = r;
1081 prio_max = prio_r;
1082 }
1083 if (prio_max > prio)
1084 {
1085 if (i == cache_left_index)
1086 cache_left_index = cache[i].next;
1087 if (i == cache_right_index)
1088 cache_right_index = cache[i].prev;
1089 free_slide(i);
1090 return true;
1091 } else
1092 return false;
1093}
1094
1034/** 1095/**
1035 Read the pfraw image given as filename and return the hid of the buffer 1096 Read the pfraw image given as filename and return the hid of the buffer
1036 */ 1097 */
1037int read_pfraw(char* filename) 1098int read_pfraw(char* filename, int prio)
1038{ 1099{
1039 struct pfraw_header bmph; 1100 struct pfraw_header bmph;
1040 int fh = rb->open(filename, O_RDONLY); 1101 int fh = rb->open(filename, O_RDONLY);
1041 rb->read(fh, &bmph, sizeof(struct pfraw_header)); 1102 if( fh < 0 )
1042 if( fh < 0 ) {
1043 return empty_slide_hid; 1103 return empty_slide_hid;
1044 } 1104 else
1105 rb->read(fh, &bmph, sizeof(struct pfraw_header));
1045 1106
1046 int size = sizeof(struct bitmap) + sizeof( pix_t ) * 1107 int size = sizeof(struct bitmap) + sizeof( pix_t ) *
1047 bmph.width * bmph.height; 1108 bmph.width * bmph.height;
1048 1109
1049 int hid = rb->bufalloc(NULL, size, TYPE_BITMAP); 1110 int hid;
1050 if (hid < 0) { 1111 while (!(hid = buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio));
1051 rb->close( fh );
1052 return -1;
1053 }
1054 1112
1055 struct bitmap *bm; 1113 if (!hid) {
1056 if (rb->bufgetdata(hid, 0, (void *)&bm) < size) {
1057 rb->close( fh ); 1114 rb->close( fh );
1058 return -1; 1115 return 0;
1059 } 1116 }
1060 1117
1118 struct dim *bm = buflib_get_data(&buf_ctx, hid);
1119
1061 bm->width = bmph.width; 1120 bm->width = bmph.width;
1062 bm->height = bmph.height; 1121 bm->height = bmph.height;
1063#if LCD_DEPTH > 1 1122 pix_t *data = (pix_t*)(sizeof(struct dim) + (char *)bm);
1064 bm->format = FORMAT_NATIVE;
1065#endif
1066 bm->data = ((unsigned char *)bm + sizeof(struct bitmap));
1067 1123
1068 int y; 1124 int y;
1069 for( y = 0; y < bm->height; y++ ) 1125 for( y = 0; y < bm->height; y++ )
1070 { 1126 {
1071 pix_t *d = (pix_t*)( bm->data ) + (y*bm->width); 1127 rb->read( fh, data , sizeof( pix_t ) * bm->width );
1072 rb->read( fh, d , sizeof( pix_t ) * bm->width ); 1128 data += bm->width;
1073 } 1129 }
1074 rb->close( fh ); 1130 rb->close( fh );
1075 return hid; 1131 return hid;
@@ -1080,21 +1136,21 @@ int read_pfraw(char* filename)
1080 Load the surface for the given slide_index into the cache at cache_index. 1136 Load the surface for the given slide_index into the cache at cache_index.
1081 */ 1137 */
1082static inline bool load_and_prepare_surface(const int slide_index, 1138static inline bool load_and_prepare_surface(const int slide_index,
1083 const int cache_index) 1139 const int cache_index,
1140 const int prio)
1084{ 1141{
1085 char tmp_path_name[MAX_PATH+1]; 1142 char tmp_path_name[MAX_PATH+1];
1086 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw", 1143 rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw",
1087 slide_index); 1144 slide_index);
1088 1145
1089 int hid = read_pfraw(tmp_path_name); 1146 int hid = read_pfraw(tmp_path_name, prio);
1090 if (hid < 0) 1147 if (!hid)
1091 return false; 1148 return false;
1092 1149
1093 cache[cache_index].hid = hid; 1150 cache[cache_index].hid = hid;
1094 1151
1095 if ( cache_index < SLIDE_CACHE_SIZE ) { 1152 if ( cache_index < SLIDE_CACHE_SIZE ) {
1096 cache[cache_index].index = slide_index; 1153 cache[cache_index].index = slide_index;
1097 cache[cache_index].touched = *rb->current_tick;
1098 } 1154 }
1099 1155
1100 return true; 1156 return true;
@@ -1102,48 +1158,129 @@ static inline bool load_and_prepare_surface(const int slide_index,
1102 1158
1103 1159
1104/** 1160/**
1105 Load the surface from a bmp and overwrite the oldest slide in the cache 1161 Load the "next" slide that we can load, freeing old slides if needed, provided
1106 if necessary. 1162 that they are further from center_index than the current slide
1107 */ 1163*/
1108int load_surface(const int slide_index) 1164bool load_new_slide(void)
1109{ 1165{
1110 long oldest_tick = *rb->current_tick; 1166 int i = -1;
1111 int oldest_slide = 0; 1167 if (cache_center_index != -1)
1112 int i; 1168 {
1113 if ( slide_cache_in_use < SLIDE_CACHE_SIZE ) { /* initial fill */ 1169 int next, prev;
1114 oldest_slide = slide_cache_in_use; 1170 if (cache[cache_center_index].index != center_index)
1115 load_and_prepare_surface(slide_index, slide_cache_in_use++); 1171 {
1116 } 1172 if (cache[cache_center_index].index < center_index)
1117 else { 1173 {
1118 for (i = 0; i < SLIDE_CACHE_SIZE; i++) { /* look for oldest slide */ 1174 cache_center_index = seek_right_while(cache_center_index,
1119 if (cache[i].touched < oldest_tick) { 1175 cache[next_].index <= center_index);
1120 oldest_slide = i; 1176 prev = cache_center_index;
1121 oldest_tick = cache[i].touched; 1177 next = cache[cache_center_index].next;
1178 }
1179 else
1180 {
1181 cache_center_index = seek_left_while(cache_center_index,
1182 cache[next_].index >= center_index);
1183 next = cache_center_index;
1184 prev = cache[cache_center_index].prev;
1185 }
1186 if (cache[cache_center_index].index != center_index)
1187 {
1188 if (cache_free == -1)
1189 free_slide_prio(0);
1190 i = lla_pop_head(&cache_free);
1191 if (!load_and_prepare_surface(center_index, i, 0))
1192 goto fail_and_refree;
1193 if (cache[next].index == -1)
1194 {
1195 if (cache[prev].index == -1)
1196 goto insert_first_slide;
1197 else
1198 next = cache[prev].next;
1199 }
1200 lla_insert(i, next);
1201 if (cache[i].index < cache[cache_used].index)
1202 cache_used = i;
1203 cache_center_index = i;
1204 cache_left_index = i;
1205 cache_right_index = i;
1206 return true;
1207 }
1208 }
1209 if (cache[cache_left_index].index >
1210 cache[cache_center_index].index)
1211 cache_left_index = cache_center_index;
1212 if (cache[cache_right_index].index <
1213 cache[cache_center_index].index)
1214 cache_right_index = cache_center_index;
1215 cache_left_index = seek_left_while(cache_left_index,
1216 cache[ind_].index - 1 == cache[next_].index);
1217 cache_right_index = seek_right_while(cache_right_index,
1218 cache[ind_].index - 1 == cache[next_].index);
1219 int prio_l = cache[cache_center_index].index -
1220 cache[cache_left_index].index + 1;
1221 int prio_r = cache[cache_right_index].index -
1222 cache[cache_center_index].index + 1;
1223 if ((prio_l < prio_r ||
1224 cache[cache_right_index].index >= number_of_slides) &&
1225 cache[cache_left_index].index > 0)
1226 {
1227 if (cache_free == -1)
1228 free_slide_prio(prio_l);
1229 i = lla_pop_head(&cache_free);
1230 if (load_and_prepare_surface(cache[cache_left_index].index
1231 - 1, i, prio_l))
1232 {
1233 lla_insert_before(&cache_used, i, cache_left_index);
1234 cache_left_index = i;
1235 return true;
1236 }
1237 } else if(cache[cache_right_index].index < number_of_slides - 1)
1238 {
1239 if (cache_free == -1)
1240 free_slide_prio(prio_l);
1241 i = lla_pop_head(&cache_free);
1242 if (load_and_prepare_surface(cache[cache_right_index].index
1243 + 1, i, prio_r))
1244 {
1245 lla_insert_after(i, cache_right_index);
1246 cache_right_index = i;
1247 return true;
1122 } 1248 }
1123 } 1249 }
1124 if (cache[oldest_slide].hid != empty_slide_hid) { 1250 } else {
1125 rb->bufclose(cache[oldest_slide].hid); 1251 i = lla_pop_head(&cache_free);
1126 cache[oldest_slide].hid = -1; 1252 if (load_and_prepare_surface(center_index, i, 0))
1253 {
1254insert_first_slide:
1255 cache[i].next = i;
1256 cache[i].prev = i;
1257 cache_center_index = i;
1258 cache_left_index = i;
1259 cache_right_index = i;
1260 cache_used = i;
1261 return true;
1127 } 1262 }
1128 load_and_prepare_surface(slide_index, oldest_slide);
1129 } 1263 }
1130 return oldest_slide; 1264fail_and_refree:
1265 if (i != -1)
1266 {
1267 lla_insert_tail(&cache_free, i);
1268 }
1269 return false;
1131} 1270}
1132 1271
1133 1272
1134/** 1273/**
1135 Get a slide from the buffer 1274 Get a slide from the buffer
1136 */ 1275 */
1137static inline struct bitmap *get_slide(const int hid) 1276static inline struct dim *get_slide(const int hid)
1138{ 1277{
1139 if (hid < 0) 1278 if (!hid)
1140 return NULL; 1279 return NULL;
1141 1280
1142 struct bitmap *bmp; 1281 struct dim *bmp;
1143 1282
1144 ssize_t ret = rb->bufgetdata(hid, 0, (void *)&bmp); 1283 bmp = buflib_get_data(&buf_ctx, hid);
1145 if (ret < 0)
1146 return NULL;
1147 1284
1148 return bmp; 1285 return bmp;
1149} 1286}
@@ -1152,23 +1289,21 @@ static inline struct bitmap *get_slide(const int hid)
1152/** 1289/**
1153 Return the requested surface 1290 Return the requested surface
1154*/ 1291*/
1155static inline struct bitmap *surface(const int slide_index) 1292static inline struct dim *surface(const int slide_index)
1156{ 1293{
1157 if (slide_index < 0) 1294 if (slide_index < 0)
1158 return 0; 1295 return 0;
1159 if (slide_index >= number_of_slides) 1296 if (slide_index >= number_of_slides)
1160 return 0; 1297 return 0;
1161
1162 int i; 1298 int i;
1163 for (i = 0; i < slide_cache_in_use; i++) { 1299 if ((i = cache_used ) != -1)
1164 /* maybe do the inverse mapping => implies dynamic allocation? */ 1300 {
1165 if ( cache[i].index == slide_index ) { 1301 do {
1166 /* We have already loaded our slide, so touch it and return it. */ 1302 if (cache[i].index == slide_index)
1167 cache[i].touched = *rb->current_tick; 1303 return get_slide(cache[i].hid);
1168 return get_slide(cache[i].hid); 1304 i = cache[i].next;
1169 } 1305 } while (i != cache_used);
1170 } 1306 }
1171 request_surface(slide_index);
1172 return get_slide(empty_slide_hid); 1307 return get_slide(empty_slide_hid);
1173} 1308}
1174 1309
@@ -1293,13 +1428,13 @@ static inline pix_t fade_color(pix_t c, unsigned int a)
1293 */ 1428 */
1294void render_slide(struct slide_data *slide, const int alpha) 1429void render_slide(struct slide_data *slide, const int alpha)
1295{ 1430{
1296 struct bitmap *bmp = surface(slide->slide_index); 1431 struct dim *bmp = surface(slide->slide_index);
1297 if (!bmp) { 1432 if (!bmp) {
1298 return; 1433 return;
1299 } 1434 }
1300 if (slide->angle > 255 || slide->angle < -255) 1435 if (slide->angle > 255 || slide->angle < -255)
1301 return; 1436 return;
1302 pix_t *src = (pix_t *)bmp->data; 1437 pix_t *src = (pix_t*)(sizeof(struct dim) + (char *)bmp);
1303 1438
1304 const int sw = bmp->width; 1439 const int sw = bmp->width;
1305 const int sh = bmp->height; 1440 const int sh = bmp->height;
@@ -1329,7 +1464,7 @@ void render_slide(struct slide_data *slide, const int alpha)
1329 xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0); 1464 xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0);
1330 xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr; 1465 xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr;
1331 xs = fdiv(xsnum, xsden); 1466 xs = fdiv(xsnum, xsden);
1332 1467
1333 xsnumi = -CAM_DIST_R - zo; 1468 xsnumi = -CAM_DIST_R - zo;
1334 xsdeni = sinr; 1469 xsdeni = sinr;
1335 int x; 1470 int x;
@@ -1411,11 +1546,10 @@ void render_slide(struct slide_data *slide, const int alpha)
1411 xs = fdiv(xsnum, xsden); 1546 xs = fdiv(xsnum, xsden);
1412 } else 1547 } else
1413 xs += PFREAL_ONE; 1548 xs += PFREAL_ONE;
1414 1549
1415 } 1550 }
1416 /* let the music play... */ 1551 /* let the music play... */
1417 rb->yield(); 1552 rb->yield();
1418
1419 return; 1553 return;
1420} 1554}
1421 1555
@@ -1425,8 +1559,11 @@ void render_slide(struct slide_data *slide, const int alpha)
1425 */ 1559 */
1426static inline void set_current_slide(const int slide_index) 1560static inline void set_current_slide(const int slide_index)
1427{ 1561{
1562 int old_center_index = center_index;
1428 step = 0; 1563 step = 0;
1429 center_index = fbound(slide_index, 0, number_of_slides - 1); 1564 center_index = fbound(slide_index, 0, number_of_slides - 1);
1565 if (old_center_index != center_index)
1566 rb->queue_post(&thread_q, EV_WAKEUP, 0);
1430 target = center_index; 1567 target = center_index;
1431 slide_frame = slide_index << 16; 1568 slide_frame = slide_index << 16;
1432 reset_slides(); 1569 reset_slides();
@@ -1583,6 +1720,7 @@ void update_scroll_animation(void)
1583 index++; 1720 index++;
1584 if (center_index != index) { 1721 if (center_index != index) {
1585 center_index = index; 1722 center_index = index;
1723 rb->queue_post(&thread_q, EV_WAKEUP, 0);
1586 slide_frame = index << 16; 1724 slide_frame = index << 16;
1587 center_slide.slide_index = center_index; 1725 center_slide.slide_index = center_index;
1588 for (i = 0; i < num_slides; i++) 1726 for (i = 0; i < num_slides; i++)
@@ -1652,12 +1790,6 @@ void cleanup(void *parameter)
1652 /* Turn on backlight timeout (revert to settings) */ 1790 /* Turn on backlight timeout (revert to settings) */
1653 backlight_use_settings(); /* backlight control in lib/helper.c */ 1791 backlight_use_settings(); /* backlight control in lib/helper.c */
1654 1792
1655 int i;
1656 for (i = 0; i < slide_cache_in_use; i++) {
1657 rb->bufclose(cache[i].hid);
1658 }
1659 if ( empty_slide_hid != - 1)
1660 rb->bufclose(empty_slide_hid);
1661#ifdef USEGSLIB 1793#ifdef USEGSLIB
1662 grey_release(); 1794 grey_release();
1663#endif 1795#endif
@@ -1687,9 +1819,6 @@ int create_empty_slide(bool force)
1687 return false; 1819 return false;
1688 } 1820 }
1689 1821
1690 empty_slide_hid = read_pfraw( EMPTY_SLIDE );
1691 if (empty_slide_hid == -1 ) return false;
1692
1693 return true; 1822 return true;
1694} 1823}
1695 1824
@@ -2053,7 +2182,7 @@ void draw_album_text(void)
2053int main(void) 2182int main(void)
2054{ 2183{
2055 int ret; 2184 int ret;
2056 2185
2057 rb->lcd_setfont(FONT_UI); 2186 rb->lcd_setfont(FONT_UI);
2058 draw_splashscreen(); 2187 draw_splashscreen();
2059 2188
@@ -2068,6 +2197,7 @@ int main(void)
2068 2197
2069 init_reflect_table(); 2198 init_reflect_table();
2070 2199
2200 ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
2071 ret = create_album_index(); 2201 ret = create_album_index();
2072 if (ret == ERROR_BUFFER_FULL) { 2202 if (ret == ERROR_BUFFER_FULL) {
2073 rb->splash(HZ, "Not enough memory for album names"); 2203 rb->splash(HZ, "Not enough memory for album names");
@@ -2076,7 +2206,8 @@ int main(void)
2076 rb->splash(HZ, "No albums found. Please enable database"); 2206 rb->splash(HZ, "No albums found. Please enable database");
2077 return PLUGIN_ERROR; 2207 return PLUGIN_ERROR;
2078 } 2208 }
2079 2209
2210 ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
2080 number_of_slides = album_count; 2211 number_of_slides = album_count;
2081 if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { 2212 if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) {
2082 rb->splash(HZ, "Could not create album art cache"); 2213 rb->splash(HZ, "Could not create album art cache");
@@ -2090,6 +2221,27 @@ int main(void)
2090 cache_version = CACHE_VERSION; 2221 cache_version = CACHE_VERSION;
2091 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); 2222 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
2092 2223
2224
2225#ifdef USEGSLIB
2226 long grey_buf_used;
2227 if (!grey_init(plugin_buf, plugin_buf_size, GREY_BUFFERED|GREY_ON_COP,
2228 LCD_WIDTH, LCD_HEIGHT, &grey_buf_used))
2229 {
2230 rb->splash(HZ, "Greylib init failed!");
2231 return PLUGIN_ERROR;
2232 }
2233 grey_setfont(FONT_UI);
2234 plugin_buf_size -= grey_buf_used;
2235 plugin_buf = (void*)(grey_buf_used + (char*)plugin_buf);
2236#endif
2237 buflib_init(&buf_ctx, (void *)plugin_buf, plugin_buf_size);
2238
2239 if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0)))
2240 {
2241 rb->splash(HZ, "Unable to load empty slide image");
2242 return PLUGIN_ERROR;
2243 }
2244
2093 if (!create_pf_thread()) { 2245 if (!create_pf_thread()) {
2094 rb->splash(HZ, "Cannot create thread!"); 2246 rb->splash(HZ, "Cannot create thread!");
2095 return PLUGIN_ERROR; 2247 return PLUGIN_ERROR;
@@ -2098,27 +2250,21 @@ int main(void)
2098 int i; 2250 int i;
2099 2251
2100 /* initialize */ 2252 /* initialize */
2101 int min_slide_cache = fmin(number_of_slides, SLIDE_CACHE_SIZE); 2253 for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
2102 for (i = 0; i < min_slide_cache; i++) { 2254 cache[i].hid = 0;
2103 cache[i].hid = -1; 2255 cache[i].index = 0;
2104 cache[i].touched = 0; 2256 cache[i].next = i + 1;
2105 slide_cache_stack[i] = SLIDE_CACHE_SIZE-i-1; 2257 cache[i].prev = i - 1;
2106 } 2258 }
2107 slide_cache_stack_index = min_slide_cache-1; 2259 cache[0].prev = i - 1;
2108 slide_cache_in_use = 0; 2260 cache[i - 1].next = 0;
2109#ifdef USEGSLIB 2261 cache_free = 0;
2110 if (!grey_init(plugin_buf, plugin_buf_size, GREY_BUFFERED|GREY_ON_COP,
2111 LCD_WIDTH, LCD_HEIGHT, NULL))
2112 rb->splash(HZ, "Greylib init failed!");
2113 grey_setfont(FONT_UI);
2114#endif
2115 buffer = LCD_BUF; 2262 buffer = LCD_BUF;
2116 2263
2117 pf_state = pf_idle; 2264 pf_state = pf_idle;
2118 2265
2119 track_index = -1; 2266 track_index = -1;
2120 extra_fade = 0; 2267 extra_fade = 0;
2121 center_index = 0;
2122 slide_frame = 0; 2268 slide_frame = 0;
2123 step = 0; 2269 step = 0;
2124 target = 0; 2270 target = 0;
@@ -2289,7 +2435,6 @@ int main(void)
2289enum plugin_status plugin_start(const void *parameter) 2435enum plugin_status plugin_start(const void *parameter)
2290{ 2436{
2291 int ret; 2437 int ret;
2292
2293 (void) parameter; 2438 (void) parameter;
2294#if LCD_DEPTH > 1 2439#if LCD_DEPTH > 1
2295 rb->lcd_set_backdrop(NULL); 2440 rb->lcd_set_backdrop(NULL);
@@ -2300,7 +2445,6 @@ enum plugin_status plugin_start(const void *parameter)
2300 rb->cpu_boost(true); 2445 rb->cpu_boost(true);
2301#endif 2446#endif
2302 plugin_buf = rb->plugin_get_buffer(&plugin_buf_size); 2447 plugin_buf = rb->plugin_get_buffer(&plugin_buf_size);
2303 ALIGN_BUFFER(plugin_buf, plugin_buf_size, 4);
2304 ret = main(); 2448 ret = main();
2305#ifdef HAVE_ADJUSTABLE_CPU_FREQ 2449#ifdef HAVE_ADJUSTABLE_CPU_FREQ
2306 rb->cpu_boost(false); 2450 rb->cpu_boost(false);