Part of Slepp's ProjectsPastebinTURLImagebinFilebin
Feedback -- English French German Japanese
Create Upload Newest Tools Donate
Sign In | Create Account

pictureflow.patch
Friday, December 7th, 2007 at 10:36:14pm UTC 

  1. diff --git a/apps/plugin.c b/apps/plugin.c
  2. index 9067097..9b3e679 100644
  3. --- a/apps/plugin.c
  4. +++ b/apps/plugin.c
  5. @@ -532,6 +532,24 @@ static const struct plugin_api rockbox_api = {
  6.      remote_backlight_set_timeout_plugged,
  7.  #endif
  8.  #endif /* HAVE_REMOTE_LCD */
  9. +
  10. +#if (CONFIG_CODEC == SWCODEC)
  11. +    bufopen,
  12. +    bufalloc,
  13. +    bufclose,
  14. +    bufseek,
  15. +    bufadvance,
  16. +    bufread,
  17. +    bufgetdata,
  18. +    bufgettail,
  19. +    bufcuttail,
  20. +
  21. +    buf_get_offset,
  22. +    buf_handle_offset,
  23. +    buf_request_buffer_handle,
  24. +    buf_set_base_handle,
  25. +    buf_used,
  26. +#endif
  27.  };
  28.  
  29.  int plugin_load(const char* plugin, void* parameter)
  30. diff --git a/apps/plugin.h b/apps/plugin.h
  31. index 9105932..825b0a0 100644
  32. --- a/apps/plugin.h
  33. +++ b/apps/plugin.h
  34. @@ -78,6 +78,7 @@
  35.  #include "list.h"
  36.  #include "tree.h"
  37.  #include "color_picker.h"
  38. +#include "buffering.h"
  39.  
  40.  #ifdef HAVE_REMOTE_LCD
  41.  #include "lcd-remote.h"
  42. @@ -655,6 +656,24 @@ struct plugin_api {
  43.      void (*remote_backlight_set_timeout_plugged)(int index);
  44.  #endif
  45.  #endif /* HAVE_REMOTE_LCD */
  46. +
  47. +#if (CONFIG_CODEC == SWCODEC)
  48. +    int (*bufopen)(const char *file, size_t offset, enum data_type type);
  49. +    int (*bufalloc)(const void *src, size_t size, enum data_type type);
  50. +    bool (*bufclose)(int handle_id);
  51. +    int (*bufseek)(int handle_id, size_t newpos);
  52. +    int (*bufadvance)(int handle_id, off_t offset);
  53. +    ssize_t (*bufread)(int handle_id, size_t size, void *dest);
  54. +    ssize_t (*bufgetdata)(int handle_id, size_t size, void **data);
  55. +    ssize_t (*bufgettail)(int handle_id, size_t size, void **data);
  56. +    ssize_t (*bufcuttail)(int handle_id, size_t size);
  57. +
  58. +    ssize_t (*buf_get_offset)(int handle_id, void *ptr);
  59. +    ssize_t (*buf_handle_offset)(int handle_id);
  60. +    void (*buf_request_buffer_handle)(int handle_id);
  61. +    void (*buf_set_base_handle)(int handle_id);
  62. +    size_t (*buf_used)(void);
  63. +#endif
  64.  };
  65.  
  66.  /* plugin header */
  67. diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
  68. index 709c5be..57cab53 100644
  69. --- a/apps/plugins/CATEGORIES
  70. +++ b/apps/plugins/CATEGORIES
  71. @@ -47,6 +47,7 @@ mpegplayer,viewers
  72.  nim,games
  73.  oscilloscope,demos
  74.  pacbox,games
  75. +pictureflow,demos
  76.  plasma,demos
  77.  pong,games
  78.  properties,viewers
  79. diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
  80. index 727e5a8..b24fef1 100644
  81. --- a/apps/plugins/SOURCES
  82. +++ b/apps/plugins/SOURCES
  83. @@ -20,6 +20,8 @@ stopwatch.c
  84.  vbrfix.c
  85.  viewer.c
  86.  
  87. +pictureflow.c
  88. +
  89.  #ifdef OLYMPUS_MROBE_500
  90.  /* remove these once the plugins before it are compileable */
  91.  jpeg.c
  92. diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
  93. new file mode 100644
  94. index 0000000..aeb34bd
  95. --- /dev/null
  96. +++ b/apps/plugins/pictureflow.c
  97. @@ -0,0 +1,1215 @@
  98. +
  99. +/***************************************************************************
  100. +*             __________               __   ___.
  101. +*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
  102. +*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
  103. +*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
  104. +*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
  105. +*                     \/            \/     \/    \/            \/
  106. +*
  107. +* Copyright (C) 2007 Jonas Hurrelmann ([email protected])
  108. +* Copyright (C) 2007 Ariya Hidayat ([email protected]) (original Qt Version)
  109. +*
  110. +* PictureFlow Demo
  111. +*
  112. +* All files in this archive are subject to the GNU General Public License.
  113. +* See the file COPYING in the source tree root for full license agreement.
  114. +*
  115. +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  116. +* KIND, either express or implied.
  117. +*
  118. +****************************************************************************/
  119. +
  120. +#include "plugin.h"
  121. +#include "helper.h"
  122. +#include "lib/bmp.h"
  123. +
  124. +
  125. +#ifdef HAVE_LCD_BITMAP          /* and also not for the Player */
  126. +
  127. +PLUGIN_HEADER
  128. +/******************************* Globals ***********************************/
  129. +static struct plugin_api *rb;   /* global api struct pointer */
  130. +
  131. +/* Key assignement */
  132. +
  133. +#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
  134. +      (CONFIG_KEYPAD == IPOD_1G2G_PAD)
  135. +#define PICTUREFLOW_QUIT BUTTON_MENU
  136. +#define PICTUREFLOW_SELECT_ALBUM BUTTON_SELECT
  137. +#define PICTUREFLOW_NEXT_ALBUM BUTTON_SCROLL_FWD
  138. +#define PICTUREFLOW_PREV_ALBUM BUTTON_SCROLL_BACK
  139. +#endif
  140. +
  141. +
  142. +#if CONFIG_KEYPAD == GIGABEAT_PAD
  143. +#define PICTUREFLOW_QUIT BUTTON_MENU
  144. +#define PICTUREFLOW_SELECT_ALBUM BUTTON_SELECT
  145. +#define PICTUREFLOW_NEXT_ALBUM BUTTON_RIGHT
  146. +#define PICTUREFLOW_PREV_ALBUM BUTTON_LEFT
  147. +#endif
  148. +
  149. +
  150. +
  151. +
  152. +// for fixed-point arithmetic, we need minimum 32-bit long
  153. +// long long (64-bit) might be useful for multiplication and division
  154. +#define PFreal long
  155. +#define PFREAL_SHIFT 10
  156. +#define PFREAL_FACTOR (1 << PFREAL_SHIFT)
  157. +#define PFREAL_ONE (1 << PFREAL_SHIFT)
  158. +#define PFREAL_HALF (PFREAL_ONE >> 1)
  159. +
  160. +
  161. +#define fmin(a,b) (((a) < (b)) ? (a) : (b))
  162. +#define fmax(a,b) (((a) > (b)) ? (a) : (b))
  163. +#define fbound(min,val,max) (fmax((min),fmin((max),(val))))
  164. +
  165. +// There are some precision issues when not using (long long) which in turn takes very long to compute...
  166. +// I guess the best solution would be to optimize the computations so it only requires a single long
  167. +
  168. +static inline PFreal fmul(PFreal a, PFreal b)
  169. +{
  170. +    return ((long long) (a)) * ((long long) (b)) >> PFREAL_SHIFT;
  171. +}
  172. +
  173. +static inline PFreal fdiv(PFreal num, PFreal den)
  174. +{
  175. +    long long p = (long long) (num) << (PFREAL_SHIFT * 2);
  176. +    long long q = p / (long long) den;
  177. +    long long r = q >> PFREAL_SHIFT;
  178. +
  179. +    return r;
  180. +}
  181. +
  182. +/*
  183. +#define fmul(a,b) ( ((a)*(b)) >> PFREAL_SHIFT )
  184. +#define fdiv(n,m) ( ((n)<< PFREAL_SHIFT ) / m )
  185. +
  186. +#define fconv(a, q1, q2) (((q2)>(q1)) ? (a)<<((q2)-(q1)) : (a)>>((q1)-(q2)))
  187. +#define tofloat(a, q) ( (float)(a) / (float)(1<<(q)) )
  188. +*/
  189. +
  190. +/*
  191. +static inline PFreal fmul(PFreal a, PFreal b)
  192. +{
  193. +    return (a*b) >> PFREAL_SHIFT;
  194. +}
  195. +
  196. +static inline PFreal fdiv(PFreal n, PFreal m)
  197. +{
  198. +    return (n<<(PFREAL_SHIFT))/m;
  199. +}
  200. +*/
  201. +
  202. +
  203. +#define IANGLE_MAX 1024
  204. +#define IANGLE_MASK 1023
  205. +
  206. +/**
  207. + Precomupted sin-table
  208. +*/
  209. +static const PFreal sinTable[IANGLE_MAX] = {    // 10
  210. +    3, 9, 15, 21, 28, 34, 40, 47,
  211. +    53, 59, 65, 72, 78, 84, 90, 97,
  212. +    103, 109, 115, 122, 128, 134, 140, 147,
  213. +    153, 159, 165, 171, 178, 184, 190, 196,
  214. +    202, 209, 215, 221, 227, 233, 239, 245,
  215. +    251, 257, 264, 270, 276, 282, 288, 294,
  216. +    300, 306, 312, 318, 324, 330, 336, 342,
  217. +    347, 353, 359, 365, 371, 377, 383, 388,
  218. +    394, 400, 406, 412, 417, 423, 429, 434,
  219. +    440, 446, 451, 457, 463, 468, 474, 479,
  220. +    485, 491, 496, 501, 507, 512, 518, 523,
  221. +    529, 534, 539, 545, 550, 555, 561, 566,
  222. +    571, 576, 581, 587, 592, 597, 602, 607,
  223. +    612, 617, 622, 627, 632, 637, 642, 647,
  224. +    652, 656, 661, 666, 671, 675, 680, 685,
  225. +    690, 694, 699, 703, 708, 712, 717, 721,
  226. +    726, 730, 735, 739, 743, 748, 752, 756,
  227. +    760, 765, 769, 773, 777, 781, 785, 789,
  228. +    793, 797, 801, 805, 809, 813, 816, 820,
  229. +    824, 828, 831, 835, 839, 842, 846, 849,
  230. +    853, 856, 860, 863, 866, 870, 873, 876,
  231. +    879, 883, 886, 889, 892, 895, 898, 901,
  232. +    904, 907, 910, 913, 916, 918, 921, 924,
  233. +    927, 929, 932, 934, 937, 939, 942, 944,
  234. +    947, 949, 951, 954, 956, 958, 960, 963,
  235. +    965, 967, 969, 971, 973, 975, 977, 978,
  236. +    980, 982, 984, 986, 987, 989, 990, 992,
  237. +    994, 995, 997, 998, 999, 1001, 1002, 1003,
  238. +    1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
  239. +    1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018,
  240. +    1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
  241. +    1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
  242. +    1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022,
  243. +    1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019,
  244. +    1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013,
  245. +    1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004,
  246. +    1003, 1002, 1001, 999, 998, 997, 995, 994,
  247. +    992, 990, 989, 987, 986, 984, 982, 980,
  248. +    978, 977, 975, 973, 971, 969, 967, 965,
  249. +    963, 960, 958, 956, 954, 951, 949, 947,
  250. +    944, 942, 939, 937, 934, 932, 929, 927,
  251. +    924, 921, 918, 916, 913, 910, 907, 904,
  252. +    901, 898, 895, 892, 889, 886, 883, 879,
  253. +    876, 873, 870, 866, 863, 860, 856, 853,
  254. +    849, 846, 842, 839, 835, 831, 828, 824,
  255. +    820, 816, 813, 809, 805, 801, 797, 793,
  256. +    789, 785, 781, 777, 773, 769, 765, 760,
  257. +    756, 752, 748, 743, 739, 735, 730, 726,
  258. +    721, 717, 712, 708, 703, 699, 694, 690,
  259. +    685, 680, 675, 671, 666, 661, 656, 652,
  260. +    647, 642, 637, 632, 627, 622, 617, 612,
  261. +    607, 602, 597, 592, 587, 581, 576, 571,
  262. +    566, 561, 555, 550, 545, 539, 534, 529,
  263. +    523, 518, 512, 507, 501, 496, 491, 485,
  264. +    479, 474, 468, 463, 457, 451, 446, 440,
  265. +    434, 429, 423, 417, 412, 406, 400, 394,
  266. +    388, 383, 377, 371, 365, 359, 353, 347,
  267. +    342, 336, 330, 324, 318, 312, 306, 300,
  268. +    294, 288, 282, 276, 270, 264, 257, 251,
  269. +    245, 239, 233, 227, 221, 215, 209, 202,
  270. +    196, 190, 184, 178, 171, 165, 159, 153,
  271. +    147, 140, 134, 128, 122, 115, 109, 103,
  272. +    97, 90, 84, 78, 72, 65, 59, 53,
  273. +    47, 40, 34, 28, 21, 15, 9, 3,
  274. +    -4, -10, -16, -22, -29, -35, -41, -48,
  275. +    -54, -60, -66, -73, -79, -85, -91, -98,
  276. +    -104, -110, -116, -123, -129, -135, -141, -148,
  277. +    -154, -160, -166, -172, -179, -185, -191, -197,
  278. +    -203, -210, -216, -222, -228, -234, -240, -246,
  279. +    -252, -258, -265, -271, -277, -283, -289, -295,
  280. +    -301, -307, -313, -319, -325, -331, -337, -343,
  281. +    -348, -354, -360, -366, -372, -378, -384, -389,
  282. +    -395, -401, -407, -413, -418, -424, -430, -435,
  283. +    -441, -447, -452, -458, -464, -469, -475, -480,
  284. +    -486, -492, -497, -502, -508, -513, -519, -524,
  285. +    -530, -535, -540, -546, -551, -556, -562, -567,
  286. +    -572, -577, -582, -588, -593, -598, -603, -608,
  287. +    -613, -618, -623, -628, -633, -638, -643, -648,
  288. +    -653, -657, -662, -667, -672, -676, -681, -686,
  289. +    -691, -695, -700, -704, -709, -713, -718, -722,
  290. +    -727, -731, -736, -740, -744, -749, -753, -757,
  291. +    -761, -766, -770, -774, -778, -782, -786, -790,
  292. +    -794, -798, -802, -806, -810, -814, -817, -821,
  293. +    -825, -829, -832, -836, -840, -843, -847, -850,
  294. +    -854, -857, -861, -864, -867, -871, -874, -877,
  295. +    -880, -884, -887, -890, -893, -896, -899, -902,
  296. +    -905, -908, -911, -914, -917, -919, -922, -925,
  297. +    -928, -930, -933, -935, -938, -940, -943, -945,
  298. +    -948, -950, -952, -955, -957, -959, -961, -964,
  299. +    -966, -968, -970, -972, -974, -976, -978, -979,
  300. +    -981, -983, -985, -987, -988, -990, -991, -993,
  301. +    -995, -996, -998, -999, -1000, -1002, -1003, -1004,
  302. +    -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013,
  303. +    -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019,
  304. +    -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023,
  305. +    -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024,
  306. +    -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023,
  307. +    -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020,
  308. +    -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014,
  309. +    -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005,
  310. +    -1004, -1003, -1002, -1000, -999, -998, -996, -995,
  311. +    -993, -991, -990, -988, -987, -985, -983, -981,
  312. +    -979, -978, -976, -974, -972, -970, -968, -966,
  313. +    -964, -961, -959, -957, -955, -952, -950, -948,
  314. +    -945, -943, -940, -938, -935, -933, -930, -928,
  315. +    -925, -922, -919, -917, -914, -911, -908, -905,
  316. +    -902, -899, -896, -893, -890, -887, -884, -880,
  317. +    -877, -874, -871, -867, -864, -861, -857, -854,
  318. +    -850, -847, -843, -840, -836, -832, -829, -825,
  319. +    -821, -817, -814, -810, -806, -802, -798, -794,
  320. +    -790, -786, -782, -778, -774, -770, -766, -761,
  321. +    -757, -753, -749, -744, -740, -736, -731, -727,
  322. +    -722, -718, -713, -709, -704, -700, -695, -691,
  323. +    -686, -681, -676, -672, -667, -662, -657, -653,
  324. +    -648, -643, -638, -633, -628, -623, -618, -613,
  325. +    -608, -603, -598, -593, -588, -582, -577, -572,
  326. +    -567, -562, -556, -551, -546, -540, -535, -530,
  327. +    -524, -519, -513, -508, -502, -497, -492, -486,
  328. +    -480, -475, -469, -464, -458, -452, -447, -441,
  329. +    -435, -430, -424, -418, -413, -407, -401, -395,
  330. +    -389, -384, -378, -372, -366, -360, -354, -348,
  331. +    -343, -337, -331, -325, -319, -313, -307, -301,
  332. +    -295, -289, -283, -277, -271, -265, -258, -252,
  333. +    -246, -240, -234, -228, -222, -216, -210, -203,
  334. +    -197, -191, -185, -179, -172, -166, -160, -154,
  335. +    -148, -141, -135, -129, -123, -116, -110, -104,
  336. +    -98, -91, -85, -79, -73, -66, -60, -54,
  337. +    -48, -41, -35, -29, -22, -16, -10, -4
  338. +};
  339. +
  340. +inline PFreal fsin(int iangle)
  341. +{
  342. +    while (iangle < 0)
  343. +        iangle += IANGLE_MAX;
  344. +    return sinTable[iangle & IANGLE_MASK];
  345. +}
  346. +
  347. +inline PFreal fcos(int iangle)
  348. +{
  349. +    // quarter phase shift
  350. +    return fsin(iangle + (IANGLE_MAX >> 2));
  351. +}
  352. +
  353. +
  354. +#define IMG_WIDTH 100
  355. +#define IMG_HEIGHT 100
  356. +#define SLIDE_WIDTH 100
  357. +#define SLIDE_HEIGHT 100
  358. +#define BUFFER_WIDTH LCD_WIDTH
  359. +#define BUFFER_HEIGHT LCD_HEIGHT
  360. +
  361. +// TODO: it would be nice if we could actually make use of much more memory
  362. +// this would speed up the whole process but we hit the PLUGIN_RAM (512k) at about
  363. +// 11 (where one slide is 100*200*2 ~ 40kb).
  364. +// It seems we need to do our own malloc and grab memory from the audio buffer.
  365. +// Given the 40kb per slide, we would get 500 slides into 20MB.
  366. +// The question is, how much audio buffer we can allocate until we have a noticable
  367. +// negative effect.
  368. +#define SLIDE_CACHE_SIZE 11
  369. +#define LEFT_SLIDES_COUNT 3
  370. +#define RIGHT_SLIDES_COUNT 3
  371. +
  372. +
  373. +#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
  374. +
  375. +
  376. +
  377. +struct slide_data {
  378. +    int slide_index;
  379. +    int angle;
  380. +    PFreal cx;
  381. +    PFreal cy;
  382. +};
  383. +
  384. +
  385. +struct rect {
  386. +    int left;
  387. +    int right;
  388. +    int top;
  389. +    int bottom;
  390. +};
  391. +
  392. +struct load_slide_event_data {
  393. +    int slide_index;
  394. +    int cache_index;
  395. +};
  396. +
  397. +/** below we allocate the memory we want to use **/
  398. +
  399. +static fb_data *buffer;
  400. +static PFreal rays[BUFFER_WIDTH];
  401. +static bool animation_is_active; // an animation is currently running
  402. +static struct slide_data center_slide;
  403. +static struct slide_data left_slides[LEFT_SLIDES_COUNT];
  404. +static struct slide_data right_slides[RIGHT_SLIDES_COUNT];
  405. +static int slide_frame;
  406. +static int step;
  407. +static int target;
  408. +static int fade;
  409. +static int center_index; // index of the slide that is in the center
  410. +static int itilt;
  411. +static int spacing; // spacing between slides
  412. +static int zoom;
  413. +static PFreal offsetX;
  414. +static PFreal offsetY;
  415. +static bool show_fps; // show fps in the main screen
  416. +static int number_of_slides;
  417. +
  418. +
  419. +static int slide_cache_map[SLIDE_CACHE_SIZE+1]; // map cached slides to an index
  420. +static int slide_cache_hid[SLIDE_CACHE_SIZE+1]; // map cached slides to a handle ID
  421. +static long slide_cache_touched[SLIDE_CACHE_SIZE+1]; // map cached slides to an index
  422. +static int  slide_cache_in_use;
  423. +
  424. +/* use long for aligning */
  425. +unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
  426. +static int slide_cache_stack[SLIDE_CACHE_SIZE]; // queue (as array) for scheduling load_surface
  427. +static int slide_cache_stack_index;
  428. +struct mutex slide_cache_stack_lock;
  429. +
  430. +struct thread_entry *thread_id;
  431. +struct event_queue thread_q;
  432. +
  433. +#define EV_EXIT 9999
  434. +#define EV_WAKEUP 1337
  435. +
  436. +int load_surface(int);
  437. +
  438. +/**
  439. +   Return the index on the stack of slide_index.
  440. +   Return -1 if slide_index is not on the stack.
  441. + */
  442. +int slide_stack_get_index(int slide_index)
  443. +{
  444. +    int i = slide_cache_stack_index + 1;
  445. +    while (i--) {
  446. +        if ( slide_cache_stack[i] == slide_index ) return i;
  447. +    };
  448. +    return -1;
  449. +}
  450. +
  451. +/**
  452. +   Push the slide_index on the stack so the image will be loaded.
  453. +   The algorithm tries to keep the center_index on top and the
  454. +   slide_index as high as possible (so second if center_index is
  455. +   on the stack).
  456. + */
  457. +void slide_stack_push(int slide_index)
  458. +{
  459. +    rb->mutex_lock(&slide_cache_stack_lock);
  460. +
  461. +    if ( slide_cache_stack_index == -1 ) {
  462. +        // empty stack, no checks at all
  463. +        slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
  464. +        rb->mutex_unlock(&slide_cache_stack_lock);
  465. +        return;
  466. +    }
  467. +   
  468. +    int i = slide_stack_get_index( slide_index );
  469. +
  470. +    if ( i == slide_cache_stack_index ) { 
  471. +        // slide_index is on top, so we do not change anything
  472. +        rb->mutex_unlock(&slide_cache_stack_lock);
  473. +        return;
  474. +    }
  475. +   
  476. +    if ( i >= 0 ) {
  477. +        // slide_index is already on the stack, but not on top
  478. +        int tmp = slide_cache_stack[ slide_cache_stack_index  ];
  479. +        if ( tmp == center_index ) {
  480. +            // the center_index is on top of the stack so do not touch that
  481. +            if ( slide_cache_stack_index  > 0 ) {
  482. +                // but maybe it is possible to swap the given slide_index to the second place
  483. +                tmp = slide_cache_stack[ slide_cache_stack_index -1 ];
  484. +                slide_cache_stack[ slide_cache_stack_index - 1  ] = slide_cache_stack[];
  485. +                slide_cache_stack[ i ] = tmp;
  486. +            }
  487. +        }
  488. +        else {
  489. +            // if the center_index is not on top (i.e. already loaded) bring the slide_index to the top
  490. +            slide_cache_stack[ slide_cache_stack_index  ] = slide_cache_stack[];
  491. +            slide_cache_stack[ i ] = tmp;
  492. +        }
  493. +    }
  494. +    else {
  495. +        // slide_index is not on the stack
  496. +        if ( slide_cache_stack_index >= SLIDE_CACHE_SIZE-1 ) {
  497. +            // if we exceeded the stack size, clear the first half of the stack
  498. +            slide_cache_stack_index = SLIDE_CACHE_SIZE/2;
  499. +            for (i = 0; i <= slide_cache_stack_index ; i++)
  500. +                slide_cache_stack[ i ] = slide_cache_stack[ i + slide_cache_stack_index  ];
  501. +        }
  502. +        if ( slide_cache_stack[ slide_cache_stack_index ] == center_index ) {
  503. +            // if the center_index is on top leave it there
  504. +            slide_cache_stack[ slide_cache_stack_index ] = slide_index;
  505. +            slide_cache_stack[ ++slide_cache_stack_index ] = center_index;
  506. +        }
  507. +        else {
  508. +            // usual stack case: push the slide_index on top
  509. +            slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
  510. +        }
  511. +    }
  512. +    rb->mutex_unlock(&slide_cache_stack_lock);
  513. +}
  514. +
  515. +/**
  516. +  Pop the topmost item from the stack and decrease the stack size
  517. + */
  518. +inline int slide_stack_pop(void)
  519. +{
  520. +    rb->mutex_lock(&slide_cache_stack_lock);
  521. +    int result;
  522. +    if ( slide_cache_stack_index >= 0 )
  523. +        result = slide_cache_stack[ slide_cache_stack_index-- ];
  524. +    else
  525. +        result = -1;
  526. +    rb->mutex_unlock(&slide_cache_stack_lock);
  527. +    return result;
  528. +}
  529. +
  530. +/**
  531. +  Load the slide into the cache.
  532. +  Thus we have to queue the loading request in our thread while discarding the oldest slide.
  533. + */
  534. +void request_surface(int slide_index)
  535. +{
  536. +    slide_stack_push(slide_index);
  537. +    rb->queue_post(&thread_q, EV_WAKEUP, 0);
  538. +}
  539. +
  540. +
  541. +/**
  542. + Thread used for loading and preparing bitmaps in the background
  543. + */
  544. +void thread(void)
  545. +{
  546. +    long sleep_time = 5 * HZ;
  547. +    struct queue_event ev;
  548. +    while (1) {
  549. +        rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
  550. +        switch (ev.id) {
  551. +            case EV_EXIT:
  552. +                return;
  553. +            case EV_WAKEUP:
  554. +            // we just woke up
  555. +                break;
  556. +        }
  557. +        int slide_index;
  558. +        while ( (slide_index = slide_stack_pop()) != -1 ) {
  559. +            load_surface( slide_index );
  560. +            rb->sleep( HZ ); // FIXME: optimize if we are satisified :)
  561. +        }
  562. +    }
  563. +}
  564. +
  565. +
  566. +/**
  567. + End the thread by posting the EV_EXIT event
  568. + */
  569. +void end_pf_thread(void)
  570. +{
  571. +    rb->queue_post(&thread_q, EV_EXIT, 0);
  572. +    rb->thread_wait(thread_id);
  573. +    /* remove the thread's queue from the broadcast list */
  574. +    rb->queue_delete(&thread_q);
  575. +}
  576. +
  577. +
  578. +/**
  579. + Create the thread an setup the event queue
  580. + */
  581. +bool create_pf_thread(void)
  582. +{
  583. +    rb->queue_init(&thread_q, true);    /* put the thread's queue in the bcast list */
  584. +    if ((thread_id = rb->create_thread(
  585. +                           thread,
  586. +                           thread_stack,
  587. +                           sizeof(thread_stack),
  588. +                            0,
  589. +                           "Picture load thread"
  590. +                               IF_PRIO(, PRIORITY_BACKGROUND)
  591. +                               IF_COP(, CPU)
  592. +                                      )
  593. +        ) == NULL) {
  594. +        return false;
  595. +    }
  596. +    return true;
  597. +}
  598. +
  599. +
  600. +static fb_data tmp_bmp_buffer[IMG_WIDTH * IMG_HEIGHT]; // static buffer for reading the bitmaps
  601. +
  602. +/**
  603. +  Read the slide at the given index into the cache
  604. +  TODO: This could be *much* more efficient
  605. +  It probably would make sense to store the files in raw format
  606. +  We would save the expensive 24->16bpp conversion and the computation of the
  607. +  reflection.
  608. + */
  609. +static bool read_bmp(int slide_index, int cache_index)
  610. +{
  611. +    struct bitmap tmp_bmp;
  612. +    int ret;
  613. +    tmp_bmp.data = (char *) &tmp_bmp_buffer;
  614. +    char path[MAX_PATH];
  615. +    // TODO: map slide_index to the actual album filename
  616. +    rb->snprintf(path, sizeof(path), "/pics/cover%d.bmp", slide_index+1);
  617. +    ret = rb->read_bmp_file(path, &tmp_bmp, sizeof(tmp_bmp_buffer), FORMAT_NATIVE);
  618. +
  619. +    int hid = rb->bufalloc(NULL, sizeof(struct bitmap) + (tmp_bmp.width+1) * tmp_bmp.height*2 * sizeof(fb_data), TYPE_BITMAP);
  620. +    if (hid < 0)
  621. +        return false;
  622. +
  623. +    struct bitmap *bmp;
  624. +    rb->bufgetdata(hid, 0, (void *)&bmp);
  625. +    bmp->width = tmp_bmp.width;
  626. +    bmp->height = tmp_bmp.height;
  627. +    bmp->format = tmp_bmp.format;
  628. +    bmp->data = (char *)(bmp + sizeof(struct bitmap));
  629. +    slide_cache_hid[cache_index] = hid;
  630. +
  631. +    if (ret > 0) {
  632. +        int h = bmp->height;
  633. +        int w = bmp->width;
  634. +        fb_data *result = (fb_data *)bmp->data;
  635. +        // slightly larger, to accomodate for the reflection
  636. +        int hs = h * 2;
  637. +        int hofs = w / 3;
  638. +        rb->memset(result, 0, sizeof(fb_data) * w * hs);
  639. +        int x, y;
  640. +        // transpose the image, this is to speed-up the rendering
  641. +        // because we process one column at a time
  642. +        // (and much better and faster to work row-wise, i.e in one scanline)
  643. +        for (x = 0; x < w; x++)
  644. +            for (y = 0; y < h; y++)
  645. +                result[bmp->width * 2 * x + (hofs + y)] =
  646. +                        tmp_bmp_buffer[y * bmp->width + x];
  647. +
  648. +        // create the reflection
  649. +        int ht = hs - h - hofs;
  650. +        int hte = ht;
  651. +        for (x = 0; x < w; x++) {
  652. +            for (y = 0; y < ht; y++) {
  653. +            fb_data color = tmp_bmp_buffer[x + bmp->width * (bmp->height - y - 1)];
  654. +            int r = RGB_UNPACK_RED(color) * (hte - y) / hte * 3 / 5;
  655. +            int g = RGB_UNPACK_GREEN(color) * (hte - y) / hte * 3 / 5;
  656. +            int b = RGB_UNPACK_BLUE(color) * (hte - y) / hte * 3 / 5;
  657. +            result[h + hofs + y + bmp->width * x * 2] =
  658. +                    LCD_RGBPACK(r, g, b);
  659. +            }
  660. +        }
  661. +        if ( cache_index < SLIDE_CACHE_SIZE ) {
  662. +            slide_cache_map[cache_index] = slide_index;
  663. +            slide_cache_touched[cache_index] = *rb->current_tick;
  664. +        }
  665. +        return true;
  666. +    }
  667. +    return false;
  668. +}
  669. +
  670. +
  671. +
  672. +/**
  673. + Load the surface from a bmp and store overwrite the oldest slide in the cache
  674. + */
  675. +int load_surface(int slide_index)
  676. +{
  677. +    long oldest_tick = *rb->current_tick;
  678. +    int oldest_slide = 0;
  679. +    int i;
  680. +    if ( slide_cache_in_use < SLIDE_CACHE_SIZE ) { // initial fill
  681. +        oldest_slide = slide_cache_in_use;
  682. +        read_bmp(slide_index, slide_cache_in_use++);
  683. +    }
  684. +    else {
  685. +        for (i = 0; i < SLIDE_CACHE_SIZE; i++) { // look for oldest slide
  686. +            if (slide_cache_touched[i] < oldest_tick) {
  687. +                oldest_slide = i;
  688. +                oldest_tick = slide_cache_touched[i];
  689. +            }
  690. +        }
  691. +        slide_cache_hid[oldest_slide] = -1;
  692. +        rb->bufclose(slide_cache_hid[oldest_slide]);
  693. +        read_bmp(slide_index, oldest_slide);
  694. +    }
  695. +    return oldest_slide;
  696. +}
  697. +
  698. +
  699. +/**
  700. +  Get a slide from the buffer
  701. + */
  702. +struct bitmap *get_slide(int hid)
  703. +{
  704. +    if (hid < 0)
  705. +        return NULL;
  706. +
  707. +    struct bitmap *bmp;
  708. +
  709. +    ssize_t ret = rb->bufgetdata(hid, 0, (void *)&bmp);
  710. +    if (ret < 0)
  711. +        return NULL;
  712. +
  713. +    return bmp;
  714. +}
  715. +
  716. +
  717. +/**
  718. + Return the requested surface
  719. +*/
  720. +struct bitmap *surface(int slide_index)
  721. +{
  722. +    if (slide_index < 0)
  723. +        return 0;
  724. +    if (slide_index >= number_of_slides)
  725. +        return 0;
  726. +
  727. +    int i;
  728. +    for (i = 0; i < slide_cache_in_use; i++) { // maybe do the inverse mapping => implies dynamic allocation?
  729. +        if ( slide_cache_map[i] == slide_index ) {
  730. +            // We have already loaded our slide, so touch it and return it.
  731. +            slide_cache_touched[i] = *rb->current_tick;
  732. +            return get_slide(slide_cache_hid[i]);
  733. +        }
  734. +    }
  735. +    request_surface(slide_index);
  736. +    return get_slide(slide_cache_hid[SLIDE_CACHE_SIZE]);
  737. +}
  738. +
  739. +/**
  740. + adjust slides so that they are in "steady state" position
  741. + */
  742. +void reset_slides(void)
  743. +{
  744. +    center_slide.angle = 0;
  745. +    center_slide.cx = 0;
  746. +    center_slide.cy = 0;
  747. +    center_slide.slide_index = center_index;
  748. +
  749. +    int i;
  750. +    for (i = 0; i < LEFT_SLIDES_COUNT; i++) {
  751. +        struct slide_data *si = &left_slides[i];
  752. +        si->angle = itilt;
  753. +        si->cx = -(offsetX + spacing * i * PFREAL_ONE);
  754. +        si->cy = offsetY;
  755. +        si->slide_index = center_index - 1 - i;
  756. +    }
  757. +
  758. +    for (i = 0; i < RIGHT_SLIDES_COUNT; i++) {
  759. +        struct slide_data *si = &right_slides[i];
  760. +        si->angle = -itilt;
  761. +        si->cx = offsetX + spacing * i * PFREAL_ONE;
  762. +        si->cy = offsetY;
  763. +        si->slide_index = center_index + 1 + i;
  764. +    }
  765. +}
  766. +
  767. +
  768. +/**
  769. + Updates look-up table and other stuff necessary for the rendering.
  770. + Call this when the viewport size or slide dimension is changed.
  771. + */
  772. +void recalc_table(void)
  773. +{
  774. +    int w = (BUFFER_WIDTH + 1) / 2;
  775. +    int h = (BUFFER_HEIGHT + 1) / 2;
  776. +    int i;
  777. +    for (i = 0; i < w; i++) {
  778. +        PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2 * h);
  779. +        rays[w - i - 1] = -gg;
  780. +        rays[w + i] = gg;
  781. +    }
  782. +
  783. +
  784. +    itilt = 70 * IANGLE_MAX / 360;      // approx. 70 degrees tilted
  785. +
  786. +    offsetX = SLIDE_WIDTH / 2 * (PFREAL_ONE - fcos(itilt));
  787. +    offsetY = SLIDE_WIDTH / 2 * fsin(itilt);
  788. +    offsetX += SLIDE_WIDTH * PFREAL_ONE;
  789. +    offsetY += SLIDE_WIDTH * PFREAL_ONE / 4;
  790. +    spacing = 40;
  791. +}
  792. +
  793. +
  794. +
  795. +/**
  796. + render a single slide
  797. +*/
  798. +void render_slide(struct slide_data *slide, struct rect *result_rect,
  799. +                  int alpha, int col1, int col2)
  800. +{
  801. +    rb->memset(result_rect, 0, sizeof(struct rect));
  802. +    struct bitmap *bmp = surface(slide->slide_index);
  803. +    if (!bmp) {
  804. +        return;
  805. +    }
  806. +    fb_data *src = (fb_data *)bmp->data;
  807. +
  808. +    int sw = bmp->height;
  809. +    int sh = bmp->width * 2;
  810. +
  811. +    int h = LCD_HEIGHT;
  812. +    int w = LCD_WIDTH;
  813. +
  814. +    if (col1 > col2) {
  815. +        int c = col2;
  816. +        col2 = col1;
  817. +        col1 = c;
  818. +    }
  819. +
  820. +    col1 = (col1 >= 0) ? col1 : 0;
  821. +    col2 = (col2 >= 0) ? col2 : w - 1;
  822. +    col1 = fmin(col1, w - 1);
  823. +    col2 = fmin(col2, w - 1);
  824. +
  825. +    int distance = h * 100 / zoom;
  826. +    PFreal sdx = fcos(slide->angle);
  827. +    PFreal sdy = fsin(slide->angle);
  828. +    PFreal xs = slide->cx - bmp->width * sdx / 2;
  829. +    PFreal ys = slide->cy - bmp->width * sdy / 2;
  830. +    PFreal dist = distance * PFREAL_ONE;
  831. +
  832. +
  833. +    int xi = fmax((PFreal) 0,
  834. +                  ((w * PFREAL_ONE / 2) +
  835. +                   fdiv(xs * h, dist + ys)) >> PFREAL_SHIFT);
  836. +    if (xi >= w) {
  837. +        return;
  838. +    }
  839. +
  840. +    bool flag = false;
  841. +    result_rect->left = xi;
  842. +    int x;
  843. +    for (x = fmax(xi, col1); x <= col2; x++) {
  844. +        PFreal hity = 0;
  845. +        PFreal fk = rays[x];
  846. +        if (sdy) {
  847. +            fk = fk - fdiv(sdx, sdy);
  848. +            hity = -fdiv(( rays[x] * distance
  849. +                         - slide->cx
  850. +                         + slide->cy * sdx / sdy), fk);
  851. +        }
  852. +
  853. +        dist = distance * PFREAL_ONE + hity;
  854. +        if (dist < 0)
  855. +            continue;
  856. +
  857. +        PFreal hitx = fmul(dist, rays[x]);
  858. +
  859. +        PFreal hitdist = fdiv(hitx - slide->cx, sdx);
  860. +
  861. +        int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
  862. +        if (column >= sw)
  863. +            break;
  864. +
  865. +        if (column < 0)
  866. +            continue;
  867. +
  868. +        result_rect->right = x;
  869. +        if (!flag)
  870. +            result_rect->left = x;
  871. +        flag = true;
  872. +
  873. +        int y1 = h / 2;
  874. +        int y2 = y1 + 1;
  875. +        fb_data *pixel1 = &buffer[y1 * BUFFER_WIDTH + x];
  876. +        fb_data *pixel2 = &buffer[y2 * BUFFER_WIDTH + x];
  877. +        int pixelstep = pixel2 - pixel1;
  878. +
  879. +        int center = (sh / 2);
  880. +        int dy = dist / h;
  881. +        int p1 = center * PFREAL_ONE - dy / 2;
  882. +        int p2 = center * PFREAL_ONE + dy / 2;
  883. +
  884. +
  885. +        const fb_data *ptr = &src[column * bmp->width * 2];
  886. +        if (alpha == 256)
  887. +            while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
  888. +                *pixel1 = ptr[p1 >> PFREAL_SHIFT];
  889. +                *pixel2 = ptr[p2 >> PFREAL_SHIFT];
  890. +                p1 -= dy;
  891. +                p2 += dy;
  892. +                y1--;
  893. +                y2++;
  894. +                pixel1 -= pixelstep;
  895. +                pixel2 += pixelstep;
  896. +        } else
  897. +            while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
  898. +                fb_data c1 = ptr[p1 >> PFREAL_SHIFT];
  899. +                fb_data c2 = ptr[p2 >> PFREAL_SHIFT];
  900. +
  901. +                int r1 = RGB_UNPACK_RED(c1) * alpha / 256;
  902. +                int g1 = RGB_UNPACK_GREEN(c1) * alpha / 256;
  903. +                int b1 = RGB_UNPACK_BLUE(c1) * alpha / 256;
  904. +                int r2 = RGB_UNPACK_RED(c2) * alpha / 256;
  905. +                int g2 = RGB_UNPACK_GREEN(c2) * alpha / 256;
  906. +                int b2 = RGB_UNPACK_BLUE(c2) * alpha / 256;
  907. +
  908. +                *pixel1 = LCD_RGBPACK(r1, g1, b1);
  909. +                *pixel2 = LCD_RGBPACK(r2, g2, b2);
  910. +                p1 -= dy;
  911. +                p2 += dy;
  912. +                y1--;
  913. +                y2++;
  914. +                pixel1 -= pixelstep;
  915. +                pixel2 += pixelstep;
  916. +            }
  917. +    }
  918. +    // let the music play...
  919. +    rb->yield();
  920. +
  921. +    result_rect->top = 0;
  922. +    result_rect->bottom = h - 1;
  923. +    return;
  924. +}
  925. +
  926. +
  927. +static inline void set_current_slide(int index)
  928. +{
  929. +    step = 0;
  930. +    center_index = fbound(index, 0, number_of_slides - 1);
  931. +    target = center_index;
  932. +    slide_frame = index << 16;
  933. +    reset_slides();
  934. +}
  935. +
  936. +void start_animation(void)
  937. +{
  938. +    if (!animation_is_active) {
  939. +        step = (target < center_slide.slide_index) ? -1 : 1;
  940. +        animation_is_active = true;
  941. +    }
  942. +}
  943. +
  944. +void show_previous_slide(void)
  945. +{
  946. +    if (step >= 0) {
  947. +        if (center_index > 0) {
  948. +            target = center_index - 1;
  949. +            start_animation();
  950. +        }
  951. +    } else {
  952. +        target = fmax(0, center_index - 2);
  953. +    }
  954. +}
  955. +
  956. +void show_next_slide(void)
  957. +{
  958. +    if (step <= 0) {
  959. +        if (center_index < number_of_slides - 1) {
  960. +            target = center_index + 1;
  961. +            start_animation();
  962. +        }
  963. +    } else {
  964. +        target = fmin(center_index + 2, number_of_slides - 1);
  965. +    }
  966. +}
  967. +
  968. +
  969. +
  970. +/**
  971. +  Return true if the rect has size 0
  972. +*/
  973. +bool is_empty_rect(struct rect *r)
  974. +{
  975. +    return ((r->left == 0) && (r->right == 0) && (r->top == 0)
  976. +            && (r->bottom == 0));
  977. +}
  978. +
  979. +
  980. +/**
  981. +  Render the slides. Updates only the offscreen buffer.
  982. +*/
  983. +void render(void)
  984. +{
  985. +    rb->lcd_set_background(LCD_RGBPACK(0,0,0));
  986. +    rb->lcd_clear_display(); // TODO: Optimizes this by e.g. invalidating rects
  987. +
  988. +    int nleft = LEFT_SLIDES_COUNT;
  989. +    int nright = RIGHT_SLIDES_COUNT;
  990. +
  991. +    struct rect r;
  992. +    render_slide(&center_slide, &r, 256, -1, -1);
  993. +#ifdef DEBUG_DRAW
  994. +    rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
  995. +#endif
  996. +    int c1 = r.left;
  997. +    int c2 = r.right;
  998. +    int index;
  999. +    if (step == 0) {
  1000. +        // no animation, boring plain rendering
  1001. +        for (index = 0; index < nleft - 1; index++) {
  1002. +            int alpha = (index < nleft - 2) ? 256 : 128;
  1003. +            render_slide(&left_slides[index], &r, alpha, 0, c1 - 1);
  1004. +            if (!is_empty_rect(&r)) {
  1005. +#ifdef DEBUG_DRAW
  1006. +                rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
  1007. +#endif
  1008. +                c1 = r.left;
  1009. +            }
  1010. +        }
  1011. +        for (index = 0; index < nright - 1; index++) {
  1012. +            int alpha = (index < nright - 2) ? 256 : 128;
  1013. +            render_slide(&right_slides[index], &r, alpha, c2 + 1,
  1014. +                         BUFFER_WIDTH);
  1015. +            if (!is_empty_rect(&r)) {
  1016. +#ifdef DEBUG_DRAW
  1017. +                rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
  1018. +#endif
  1019. +                c2 = r.right;
  1020. +            }
  1021. +        }
  1022. +    } else {
  1023. +        // the first and last slide must fade in/fade out
  1024. +        for (index = 0; index < nleft; index++) {
  1025. +            int alpha = 256;
  1026. +            if (index == nleft - 1)
  1027. +                alpha = (step > 0) ? 0 : 128 - fade / 2;
  1028. +            if (index == nleft - 2)
  1029. +                alpha = (step > 0) ? 128 - fade / 2 : 256 - fade / 2;
  1030. +            if (index == nleft - 3)
  1031. +                alpha = (step > 0) ? 256 - fade / 2 : 256;
  1032. +            render_slide(&left_slides[index], &r, alpha, 0, c1 - 1);
  1033. +           
  1034. +            if (!is_empty_rect(&r)) {
  1035. +#ifdef DEBUG_DRAW
  1036. +                rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
  1037. +#endif
  1038. +                c1 = r.left;
  1039. +            }
  1040. +        }
  1041. +        for (index = 0; index < nright; index++) {
  1042. +            int alpha = (index < nright - 2) ? 256 : 128;
  1043. +            if (index == nright - 1)
  1044. +                alpha = (step > 0) ? fade / 2 : 0;
  1045. +            if (index == nright - 2)
  1046. +                alpha = (step > 0) ? 128 + fade / 2 : fade / 2;
  1047. +            if (index == nright - 3)
  1048. +                alpha = (step > 0) ? 256 : 128 + fade / 2;
  1049. +            render_slide(&right_slides[index], &r, alpha, c2 + 1,
  1050. +                         BUFFER_WIDTH);
  1051. +            if (!is_empty_rect(&r)) {
  1052. +#ifdef DEBUG_DRAW
  1053. +                rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
  1054. +#endif
  1055. +                c2 = r.right;
  1056. +            }
  1057. +        }
  1058. +    }
  1059. +}
  1060. +
  1061. +
  1062. +/**
  1063. +  Updates the animation effect. Call this periodically from a timer.
  1064. +*/
  1065. +void update_animation(void)
  1066. +{
  1067. +    if (!animation_is_active)
  1068. +        return;
  1069. +    if (step == 0)
  1070. +        return;
  1071. +
  1072. +    int speed = 16384;
  1073. +    int i;
  1074. +
  1075. +    // deaccelerate when approaching the target
  1076. +    if (true) {
  1077. +        const int max = 2 * 65536;
  1078. +
  1079. +        int fi = slide_frame;
  1080. +        fi -= (target << 16);
  1081. +        if (fi < 0)
  1082. +            fi = -fi;
  1083. +        fi = fmin(fi, max);
  1084. +
  1085. +        int ia = IANGLE_MAX * (fi - max / 2) / (max * 2);
  1086. +        speed = 512 + 16384 * (PFREAL_ONE + fsin(ia)) / PFREAL_ONE;
  1087. +    }
  1088. +
  1089. +    slide_frame += speed * step;
  1090. +
  1091. +    int index = slide_frame >> 16;
  1092. +    int pos = slide_frame & 0xffff;
  1093. +    int neg = 65536 - pos;
  1094. +    int tick = (step < 0) ? neg : pos;
  1095. +    PFreal ftick = (tick * PFREAL_ONE) >> 16;
  1096. +
  1097. +    // the leftmost and rightmost slide must fade away
  1098. +    fade = pos / 256;
  1099. +
  1100. +    if (step < 0)
  1101. +        index++;
  1102. +    if (center_index != index) {
  1103. +        center_index = index;
  1104. +        slide_frame = index << 16;
  1105. +        center_slide.slide_index = center_index;
  1106. +        for (i = 0; i < LEFT_SLIDES_COUNT; i++)
  1107. +            left_slides[i].slide_index = center_index - 1 - i;
  1108. +        for (i = 0; i < RIGHT_SLIDES_COUNT; i++)
  1109. +            right_slides[i].slide_index = center_index + 1 + i;
  1110. +    }
  1111. +
  1112. +    center_slide.angle = (step * tick * itilt) >> 16;
  1113. +    center_slide.cx = -step * fmul(offsetX, ftick);
  1114. +    center_slide.cy = fmul(offsetY, ftick);
  1115. +
  1116. +    if (center_index == target) {
  1117. +        reset_slides();
  1118. +        animation_is_active = false;
  1119. +        step = 0;
  1120. +        fade = 256;
  1121. +        return;
  1122. +    }
  1123. +
  1124. +    for (i = 0; i < LEFT_SLIDES_COUNT; i++) {
  1125. +        struct slide_data *si = &left_slides[i];
  1126. +        si->angle = itilt;
  1127. +        si->cx =
  1128. +            -(offsetX + spacing * i * PFREAL_ONE + step * spacing * ftick);
  1129. +        si->cy = offsetY;
  1130. +    }
  1131. +
  1132. +    for (i = 0; i < RIGHT_SLIDES_COUNT; i++) {
  1133. +        struct slide_data *si = &right_slides[i];
  1134. +        si->angle = -itilt;
  1135. +        si->cx =
  1136. +            offsetX + spacing * i * PFREAL_ONE - step * spacing * ftick;
  1137. +        si->cy = offsetY;
  1138. +    }
  1139. +
  1140. +    if (step > 0) {
  1141. +        PFreal ftick = (neg * PFREAL_ONE) >> 16;
  1142. +        right_slides[0].angle = -(neg * itilt) >> 16;
  1143. +        right_slides[0].cx = fmul(offsetX, ftick);
  1144. +        right_slides[0].cy = fmul(offsetY, ftick);
  1145. +    } else {
  1146. +        PFreal ftick = (pos * PFREAL_ONE) >> 16;
  1147. +        left_slides[0].angle = (pos * itilt) >> 16;
  1148. +        left_slides[0].cx = -fmul(offsetX, ftick);
  1149. +        left_slides[0].cy = fmul(offsetY, ftick);
  1150. +    }
  1151. +
  1152. +    // must change direction ?
  1153. +    if (target < index)
  1154. +        if (step > 0)
  1155. +            step = -1;
  1156. +    if (target > index)
  1157. +        if (step < 0)
  1158. +            step = 1;
  1159. +}
  1160. +
  1161. +
  1162. +/**
  1163. +  Cleanup the plugin
  1164. +*/
  1165. +void cleanup(void *parameter)
  1166. +{
  1167. +    (void) parameter;
  1168. +#ifdef HAVE_ADJUSTABLE_CPU_FREQ
  1169. +    rb->cpu_boost(false);
  1170. +#endif
  1171. +    /* Turn on backlight timeout (revert to settings) */
  1172. +    backlight_use_settings(rb); /* backlight control in lib/helper.c */
  1173. +
  1174. +    int i;
  1175. +    for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
  1176. +        rb->bufclose(slide_cache_hid[i]);
  1177. +    }
  1178. +}
  1179. +
  1180. +
  1181. +
  1182. +/**
  1183. +  Main function that also contain the main plasma
  1184. +  algorithm.
  1185. + */
  1186. +int main(void)
  1187. +{
  1188. +    if (!create_pf_thread()) {
  1189. +        rb->splash(HZ, "Cannot create thread!");
  1190. +        return PLUGIN_ERROR;
  1191. +    }
  1192. +
  1193. +    int i;
  1194. +
  1195. +    // initialize
  1196. +    for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
  1197. +        slide_cache_hid[i] = -1;
  1198. +        slide_cache_touched[i] = 0;
  1199. +    }
  1200. +    slide_cache_in_use = 0;
  1201. +    buffer = rb->lcd_framebuffer;
  1202. +    animation_is_active = false;
  1203. +    zoom = 100;
  1204. +    center_index = 0;
  1205. +    slide_frame = 0;
  1206. +    step = 0;
  1207. +    target = 0;
  1208. +    fade = 256;
  1209. +    show_fps = true;
  1210. +    number_of_slides = 100; // this is the album count
  1211. +/*
  1212. +    for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
  1213. +        if (!read_bmp(i,i)) {
  1214. +            rb->splash(HZ, "error reading bmp");
  1215. +            return PLUGIN_ERROR;
  1216. +        }
  1217. +    }
  1218. +    */
  1219. +    read_bmp(-1,SLIDE_CACHE_SIZE); // empty slide hack... FIXME: make this prettier
  1220. +   
  1221. +    recalc_table();
  1222. +    reset_slides();
  1223. +
  1224. +    char fpstxt[10];
  1225. +    char albumtxt[30];
  1226. +    int button;
  1227. +
  1228. +#ifdef HAVE_ADJUSTABLE_CPU_FREQ
  1229. +    rb->cpu_boost(true);
  1230. +#endif
  1231. +    int frames = 0;
  1232. +    long last_update = *rb->current_tick;
  1233. +    long current_update;
  1234. +    long update_interval = 100;
  1235. +    int fps = 0;
  1236. +    int albumtxt_w, albumtxt_h;
  1237. +    while (true) {
  1238. +        current_update = *rb->current_tick;
  1239. +        frames++;
  1240. +        update_animation();
  1241. +        render();
  1242. +
  1243. +        if (current_update - last_update > update_interval) {
  1244. +            fps = frames * HZ / (current_update - last_update);
  1245. +            last_update = current_update;
  1246. +            frames = 0;
  1247. +        }
  1248. +
  1249. +        if (show_fps) {
  1250. +            rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
  1251. +            rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
  1252. +            rb->lcd_putsxy(0, 0, fpstxt);
  1253. +        }
  1254. +
  1255. +        rb->snprintf(albumtxt, sizeof(albumtxt), "Index is %d", center_index); // replace with album title
  1256. +        rb->lcd_set_foreground(LCD_RGBPACK(255, 255, 255));
  1257. +        rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
  1258. +        rb->lcd_putsxy((LCD_WIDTH - albumtxt_w) /2, LCD_HEIGHT-albumtxt_h-10, albumtxt);
  1259. +
  1260. +
  1261. +
  1262. +        rb->lcd_update();
  1263. +        rb->yield();
  1264. +
  1265. +        button = rb->button_get(false); //always paint -> sucks our battery
  1266. +        //button = rb->button_get(!animation_is_active); // we need to wake up here if our thread yells
  1267. +        switch (button) {
  1268. +        case PICTUREFLOW_QUIT:
  1269. +            cleanup(NULL);
  1270. +            return PLUGIN_OK;
  1271. +            break;
  1272. +
  1273. +        case PICTUREFLOW_NEXT_ALBUM:
  1274. +        case (PICTUREFLOW_NEXT_ALBUM | BUTTON_REPEAT):
  1275. +            show_next_slide();
  1276. +            break;
  1277. +
  1278. +        case PICTUREFLOW_PREV_ALBUM:
  1279. +        case (PICTUREFLOW_PREV_ALBUM | BUTTON_REPEAT):
  1280. +            show_previous_slide();
  1281. +            break;
  1282. +
  1283. +        default:
  1284. +            if (rb->default_event_handler_ex(button, cleanup, NULL)
  1285. +                == SYS_USB_CONNECTED)
  1286. +                return PLUGIN_USB_CONNECTED;
  1287. +            break;
  1288. +        }
  1289. +        //rb->sleep(HZ/100);
  1290. +    }
  1291. +}
  1292. +
  1293. +/*************************** Plugin entry point ****************************/
  1294. +
  1295. +enum plugin_status plugin_start(struct plugin_api *api, void *parameter)
  1296. +{
  1297. +    int ret;
  1298. +
  1299. +    rb = api;                   // copy to global api pointer
  1300. +    (void) parameter;
  1301. +#if LCD_DEPTH > 1
  1302. +    rb->lcd_set_backdrop(NULL);
  1303. +#endif
  1304. +    /* Turn off backlight timeout */
  1305. +    backlight_force_on(rb);     /* backlight control in lib/helper.c */
  1306. +
  1307. +    ret = main();
  1308. +    end_pf_thread();
  1309. +    return ret;
  1310. +}
  1311. +
  1312. +#endif                          /* #ifdef HAVE_LCD_BITMAP */

Update the Post

Either update this post and resubmit it with changes, or make a new post.

You may also comment on this post.

update paste below
details of the post (optional)

Note: Only the paste content is required, though the following information can be useful to others.

Save name / title?

(space separated, optional)



Please note that information posted here will expire by default in one month. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.

comments powered by Disqus
worth-right
worth-right