Advertising
- pictureflow.patch
- Friday, December 7th, 2007 at 3:36:14pm MST
- diff --git a/apps/plugin.c b/apps/plugin.c
- index 9067097..9b3e679 100644
- --- a/apps/plugin.c
- +++ b/apps/plugin.c
- @@ -532,6 +532,24 @@ static const struct plugin_api rockbox_api = {
- remote_backlight_set_timeout_plugged,
- #endif
- #endif /* HAVE_REMOTE_LCD */
- +
- +#if (CONFIG_CODEC == SWCODEC)
- + bufopen,
- + bufalloc,
- + bufclose,
- + bufseek,
- + bufadvance,
- + bufread,
- + bufgetdata,
- + bufgettail,
- + bufcuttail,
- +
- + buf_get_offset,
- + buf_handle_offset,
- + buf_request_buffer_handle,
- + buf_set_base_handle,
- + buf_used,
- +#endif
- };
- int plugin_load(const char* plugin, void* parameter)
- diff --git a/apps/plugin.h b/apps/plugin.h
- index 9105932..825b0a0 100644
- --- a/apps/plugin.h
- +++ b/apps/plugin.h
- @@ -78,6 +78,7 @@
- #include "list.h"
- #include "tree.h"
- #include "color_picker.h"
- +#include "buffering.h"
- #ifdef HAVE_REMOTE_LCD
- #include "lcd-remote.h"
- @@ -655,6 +656,24 @@ struct plugin_api {
- void (*remote_backlight_set_timeout_plugged)(int index);
- #endif
- #endif /* HAVE_REMOTE_LCD */
- +
- +#if (CONFIG_CODEC == SWCODEC)
- + int (*bufopen)(const char *file, size_t offset, enum data_type type);
- + int (*bufalloc)(const void *src, size_t size, enum data_type type);
- + bool (*bufclose)(int handle_id);
- + int (*bufseek)(int handle_id, size_t newpos);
- + int (*bufadvance)(int handle_id, off_t offset);
- + ssize_t (*bufread)(int handle_id, size_t size, void *dest);
- + ssize_t (*bufgetdata)(int handle_id, size_t size, void **data);
- + ssize_t (*bufgettail)(int handle_id, size_t size, void **data);
- + ssize_t (*bufcuttail)(int handle_id, size_t size);
- +
- + ssize_t (*buf_get_offset)(int handle_id, void *ptr);
- + ssize_t (*buf_handle_offset)(int handle_id);
- + void (*buf_request_buffer_handle)(int handle_id);
- + void (*buf_set_base_handle)(int handle_id);
- + size_t (*buf_used)(void);
- +#endif
- };
- /* plugin header */
- diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
- index 709c5be..57cab53 100644
- --- a/apps/plugins/CATEGORIES
- +++ b/apps/plugins/CATEGORIES
- @@ -47,6 +47,7 @@ mpegplayer,viewers
- nim,games
- oscilloscope,demos
- pacbox,games
- +pictureflow,demos
- plasma,demos
- pong,games
- properties,viewers
- diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
- index 727e5a8..b24fef1 100644
- --- a/apps/plugins/SOURCES
- +++ b/apps/plugins/SOURCES
- @@ -20,6 +20,8 @@ stopwatch.c
- vbrfix.c
- viewer.c
- +pictureflow.c
- +
- #ifdef OLYMPUS_MROBE_500
- /* remove these once the plugins before it are compileable */
- jpeg.c
- diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
- new file mode 100644
- index 0000000..aeb34bd
- --- /dev/null
- +++ b/apps/plugins/pictureflow.c
- @@ -0,0 +1,1215 @@
- +
- +/***************************************************************************
- +* __________ __ ___.
- +* Open \______ \ ____ ____ | | _\_ |__ _______ ___
- +* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
- +* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
- +* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
- +* \/ \/ \/ \/ \/
- +*
- +* Copyright (C) 2007 Jonas Hurrelmann (j@outpo.st)
- +* Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) (original Qt Version)
- +*
- +* PictureFlow Demo
- +*
- +* All files in this archive are subject to the GNU General Public License.
- +* See the file COPYING in the source tree root for full license agreement.
- +*
- +* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- +* KIND, either express or implied.
- +*
- +****************************************************************************/
- +
- +#include "plugin.h"
- +#include "helper.h"
- +#include "lib/bmp.h"
- +
- +
- +#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
- +
- +PLUGIN_HEADER
- +/******************************* Globals ***********************************/
- +static struct plugin_api *rb; /* global api struct pointer */
- +
- +/* Key assignement */
- +
- +#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
- + (CONFIG_KEYPAD == IPOD_1G2G_PAD)
- +#define PICTUREFLOW_QUIT BUTTON_MENU
- +#define PICTUREFLOW_SELECT_ALBUM BUTTON_SELECT
- +#define PICTUREFLOW_NEXT_ALBUM BUTTON_SCROLL_FWD
- +#define PICTUREFLOW_PREV_ALBUM BUTTON_SCROLL_BACK
- +#endif
- +
- +
- +#if CONFIG_KEYPAD == GIGABEAT_PAD
- +#define PICTUREFLOW_QUIT BUTTON_MENU
- +#define PICTUREFLOW_SELECT_ALBUM BUTTON_SELECT
- +#define PICTUREFLOW_NEXT_ALBUM BUTTON_RIGHT
- +#define PICTUREFLOW_PREV_ALBUM BUTTON_LEFT
- +#endif
- +
- +
- +
- +
- +// for fixed-point arithmetic, we need minimum 32-bit long
- +// long long (64-bit) might be useful for multiplication and division
- +#define PFreal long
- +#define PFREAL_SHIFT 10
- +#define PFREAL_FACTOR (1 << PFREAL_SHIFT)
- +#define PFREAL_ONE (1 << PFREAL_SHIFT)
- +#define PFREAL_HALF (PFREAL_ONE >> 1)
- +
- +
- +#define fmin(a,b) (((a) < (b)) ? (a) : (b))
- +#define fmax(a,b) (((a) > (b)) ? (a) : (b))
- +#define fbound(min,val,max) (fmax((min),fmin((max),(val))))
- +
- +// There are some precision issues when not using (long long) which in turn takes very long to compute...
- +// I guess the best solution would be to optimize the computations so it only requires a single long
- +
- +static inline PFreal fmul(PFreal a, PFreal b)
- +{
- + return ((long long) (a)) * ((long long) (b)) >> PFREAL_SHIFT;
- +}
- +
- +static inline PFreal fdiv(PFreal num, PFreal den)
- +{
- + long long p = (long long) (num) << (PFREAL_SHIFT * 2);
- + long long q = p / (long long) den;
- + long long r = q >> PFREAL_SHIFT;
- +
- + return r;
- +}
- +
- +/*
- +#define fmul(a,b) ( ((a)*(b)) >> PFREAL_SHIFT )
- +#define fdiv(n,m) ( ((n)<< PFREAL_SHIFT ) / m )
- +
- +#define fconv(a, q1, q2) (((q2)>(q1)) ? (a)<<((q2)-(q1)) : (a)>>((q1)-(q2)))
- +#define tofloat(a, q) ( (float)(a) / (float)(1<<(q)) )
- +*/
- +
- +/*
- +static inline PFreal fmul(PFreal a, PFreal b)
- +{
- + return (a*b) >> PFREAL_SHIFT;
- +}
- +
- +static inline PFreal fdiv(PFreal n, PFreal m)
- +{
- + return (n<<(PFREAL_SHIFT))/m;
- +}
- +*/
- +
- +
- +#define IANGLE_MAX 1024
- +#define IANGLE_MASK 1023
- +
- +/**
- + Precomupted sin-table
- +*/
- +static const PFreal sinTable[IANGLE_MAX] = { // 10
- + 3, 9, 15, 21, 28, 34, 40, 47,
- + 53, 59, 65, 72, 78, 84, 90, 97,
- + 103, 109, 115, 122, 128, 134, 140, 147,
- + 153, 159, 165, 171, 178, 184, 190, 196,
- + 202, 209, 215, 221, 227, 233, 239, 245,
- + 251, 257, 264, 270, 276, 282, 288, 294,
- + 300, 306, 312, 318, 324, 330, 336, 342,
- + 347, 353, 359, 365, 371, 377, 383, 388,
- + 394, 400, 406, 412, 417, 423, 429, 434,
- + 440, 446, 451, 457, 463, 468, 474, 479,
- + 485, 491, 496, 501, 507, 512, 518, 523,
- + 529, 534, 539, 545, 550, 555, 561, 566,
- + 571, 576, 581, 587, 592, 597, 602, 607,
- + 612, 617, 622, 627, 632, 637, 642, 647,
- + 652, 656, 661, 666, 671, 675, 680, 685,
- + 690, 694, 699, 703, 708, 712, 717, 721,
- + 726, 730, 735, 739, 743, 748, 752, 756,
- + 760, 765, 769, 773, 777, 781, 785, 789,
- + 793, 797, 801, 805, 809, 813, 816, 820,
- + 824, 828, 831, 835, 839, 842, 846, 849,
- + 853, 856, 860, 863, 866, 870, 873, 876,
- + 879, 883, 886, 889, 892, 895, 898, 901,
- + 904, 907, 910, 913, 916, 918, 921, 924,
- + 927, 929, 932, 934, 937, 939, 942, 944,
- + 947, 949, 951, 954, 956, 958, 960, 963,
- + 965, 967, 969, 971, 973, 975, 977, 978,
- + 980, 982, 984, 986, 987, 989, 990, 992,
- + 994, 995, 997, 998, 999, 1001, 1002, 1003,
- + 1004, 1006, 1007, 1008, 1009, 1010, 1011, 1012,
- + 1013, 1014, 1015, 1015, 1016, 1017, 1018, 1018,
- + 1019, 1019, 1020, 1020, 1021, 1021, 1022, 1022,
- + 1022, 1023, 1023, 1023, 1023, 1023, 1023, 1023,
- + 1023, 1023, 1023, 1023, 1023, 1023, 1023, 1022,
- + 1022, 1022, 1021, 1021, 1020, 1020, 1019, 1019,
- + 1018, 1018, 1017, 1016, 1015, 1015, 1014, 1013,
- + 1012, 1011, 1010, 1009, 1008, 1007, 1006, 1004,
- + 1003, 1002, 1001, 999, 998, 997, 995, 994,
- + 992, 990, 989, 987, 986, 984, 982, 980,
- + 978, 977, 975, 973, 971, 969, 967, 965,
- + 963, 960, 958, 956, 954, 951, 949, 947,
- + 944, 942, 939, 937, 934, 932, 929, 927,
- + 924, 921, 918, 916, 913, 910, 907, 904,
- + 901, 898, 895, 892, 889, 886, 883, 879,
- + 876, 873, 870, 866, 863, 860, 856, 853,
- + 849, 846, 842, 839, 835, 831, 828, 824,
- + 820, 816, 813, 809, 805, 801, 797, 793,
- + 789, 785, 781, 777, 773, 769, 765, 760,
- + 756, 752, 748, 743, 739, 735, 730, 726,
- + 721, 717, 712, 708, 703, 699, 694, 690,
- + 685, 680, 675, 671, 666, 661, 656, 652,
- + 647, 642, 637, 632, 627, 622, 617, 612,
- + 607, 602, 597, 592, 587, 581, 576, 571,
- + 566, 561, 555, 550, 545, 539, 534, 529,
- + 523, 518, 512, 507, 501, 496, 491, 485,
- + 479, 474, 468, 463, 457, 451, 446, 440,
- + 434, 429, 423, 417, 412, 406, 400, 394,
- + 388, 383, 377, 371, 365, 359, 353, 347,
- + 342, 336, 330, 324, 318, 312, 306, 300,
- + 294, 288, 282, 276, 270, 264, 257, 251,
- + 245, 239, 233, 227, 221, 215, 209, 202,
- + 196, 190, 184, 178, 171, 165, 159, 153,
- + 147, 140, 134, 128, 122, 115, 109, 103,
- + 97, 90, 84, 78, 72, 65, 59, 53,
- + 47, 40, 34, 28, 21, 15, 9, 3,
- + -4, -10, -16, -22, -29, -35, -41, -48,
- + -54, -60, -66, -73, -79, -85, -91, -98,
- + -104, -110, -116, -123, -129, -135, -141, -148,
- + -154, -160, -166, -172, -179, -185, -191, -197,
- + -203, -210, -216, -222, -228, -234, -240, -246,
- + -252, -258, -265, -271, -277, -283, -289, -295,
- + -301, -307, -313, -319, -325, -331, -337, -343,
- + -348, -354, -360, -366, -372, -378, -384, -389,
- + -395, -401, -407, -413, -418, -424, -430, -435,
- + -441, -447, -452, -458, -464, -469, -475, -480,
- + -486, -492, -497, -502, -508, -513, -519, -524,
- + -530, -535, -540, -546, -551, -556, -562, -567,
- + -572, -577, -582, -588, -593, -598, -603, -608,
- + -613, -618, -623, -628, -633, -638, -643, -648,
- + -653, -657, -662, -667, -672, -676, -681, -686,
- + -691, -695, -700, -704, -709, -713, -718, -722,
- + -727, -731, -736, -740, -744, -749, -753, -757,
- + -761, -766, -770, -774, -778, -782, -786, -790,
- + -794, -798, -802, -806, -810, -814, -817, -821,
- + -825, -829, -832, -836, -840, -843, -847, -850,
- + -854, -857, -861, -864, -867, -871, -874, -877,
- + -880, -884, -887, -890, -893, -896, -899, -902,
- + -905, -908, -911, -914, -917, -919, -922, -925,
- + -928, -930, -933, -935, -938, -940, -943, -945,
- + -948, -950, -952, -955, -957, -959, -961, -964,
- + -966, -968, -970, -972, -974, -976, -978, -979,
- + -981, -983, -985, -987, -988, -990, -991, -993,
- + -995, -996, -998, -999, -1000, -1002, -1003, -1004,
- + -1005, -1007, -1008, -1009, -1010, -1011, -1012, -1013,
- + -1014, -1015, -1016, -1016, -1017, -1018, -1019, -1019,
- + -1020, -1020, -1021, -1021, -1022, -1022, -1023, -1023,
- + -1023, -1024, -1024, -1024, -1024, -1024, -1024, -1024,
- + -1024, -1024, -1024, -1024, -1024, -1024, -1024, -1023,
- + -1023, -1023, -1022, -1022, -1021, -1021, -1020, -1020,
- + -1019, -1019, -1018, -1017, -1016, -1016, -1015, -1014,
- + -1013, -1012, -1011, -1010, -1009, -1008, -1007, -1005,
- + -1004, -1003, -1002, -1000, -999, -998, -996, -995,
- + -993, -991, -990, -988, -987, -985, -983, -981,
- + -979, -978, -976, -974, -972, -970, -968, -966,
- + -964, -961, -959, -957, -955, -952, -950, -948,
- + -945, -943, -940, -938, -935, -933, -930, -928,
- + -925, -922, -919, -917, -914, -911, -908, -905,
- + -902, -899, -896, -893, -890, -887, -884, -880,
- + -877, -874, -871, -867, -864, -861, -857, -854,
- + -850, -847, -843, -840, -836, -832, -829, -825,
- + -821, -817, -814, -810, -806, -802, -798, -794,
- + -790, -786, -782, -778, -774, -770, -766, -761,
- + -757, -753, -749, -744, -740, -736, -731, -727,
- + -722, -718, -713, -709, -704, -700, -695, -691,
- + -686, -681, -676, -672, -667, -662, -657, -653,
- + -648, -643, -638, -633, -628, -623, -618, -613,
- + -608, -603, -598, -593, -588, -582, -577, -572,
- + -567, -562, -556, -551, -546, -540, -535, -530,
- + -524, -519, -513, -508, -502, -497, -492, -486,
- + -480, -475, -469, -464, -458, -452, -447, -441,
- + -435, -430, -424, -418, -413, -407, -401, -395,
- + -389, -384, -378, -372, -366, -360, -354, -348,
- + -343, -337, -331, -325, -319, -313, -307, -301,
- + -295, -289, -283, -277, -271, -265, -258, -252,
- + -246, -240, -234, -228, -222, -216, -210, -203,
- + -197, -191, -185, -179, -172, -166, -160, -154,
- + -148, -141, -135, -129, -123, -116, -110, -104,
- + -98, -91, -85, -79, -73, -66, -60, -54,
- + -48, -41, -35, -29, -22, -16, -10, -4
- +};
- +
- +inline PFreal fsin(int iangle)
- +{
- + while (iangle < 0)
- + iangle += IANGLE_MAX;
- + return sinTable[iangle & IANGLE_MASK];
- +}
- +
- +inline PFreal fcos(int iangle)
- +{
- + // quarter phase shift
- + return fsin(iangle + (IANGLE_MAX >> 2));
- +}
- +
- +
- +#define IMG_WIDTH 100
- +#define IMG_HEIGHT 100
- +#define SLIDE_WIDTH 100
- +#define SLIDE_HEIGHT 100
- +#define BUFFER_WIDTH LCD_WIDTH
- +#define BUFFER_HEIGHT LCD_HEIGHT
- +
- +// TODO: it would be nice if we could actually make use of much more memory
- +// this would speed up the whole process but we hit the PLUGIN_RAM (512k) at about
- +// 11 (where one slide is 100*200*2 ~ 40kb).
- +// It seems we need to do our own malloc and grab memory from the audio buffer.
- +// Given the 40kb per slide, we would get 500 slides into 20MB.
- +// The question is, how much audio buffer we can allocate until we have a noticable
- +// negative effect.
- +#define SLIDE_CACHE_SIZE 11
- +#define LEFT_SLIDES_COUNT 3
- +#define RIGHT_SLIDES_COUNT 3
- +
- +
- +#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
- +
- +
- +
- +struct slide_data {
- + int slide_index;
- + int angle;
- + PFreal cx;
- + PFreal cy;
- +};
- +
- +
- +struct rect {
- + int left;
- + int right;
- + int top;
- + int bottom;
- +};
- +
- +struct load_slide_event_data {
- + int slide_index;
- + int cache_index;
- +};
- +
- +/** below we allocate the memory we want to use **/
- +
- +static fb_data *buffer;
- +static PFreal rays[BUFFER_WIDTH];
- +static bool animation_is_active; // an animation is currently running
- +static struct slide_data center_slide;
- +static struct slide_data left_slides[LEFT_SLIDES_COUNT];
- +static struct slide_data right_slides[RIGHT_SLIDES_COUNT];
- +static int slide_frame;
- +static int step;
- +static int target;
- +static int fade;
- +static int center_index; // index of the slide that is in the center
- +static int itilt;
- +static int spacing; // spacing between slides
- +static int zoom;
- +static PFreal offsetX;
- +static PFreal offsetY;
- +static bool show_fps; // show fps in the main screen
- +static int number_of_slides;
- +
- +
- +static int slide_cache_map[SLIDE_CACHE_SIZE+1]; // map cached slides to an index
- +static int slide_cache_hid[SLIDE_CACHE_SIZE+1]; // map cached slides to a handle ID
- +static long slide_cache_touched[SLIDE_CACHE_SIZE+1]; // map cached slides to an index
- +static int slide_cache_in_use;
- +
- +/* use long for aligning */
- +unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
- +static int slide_cache_stack[SLIDE_CACHE_SIZE]; // queue (as array) for scheduling load_surface
- +static int slide_cache_stack_index;
- +struct mutex slide_cache_stack_lock;
- +
- +struct thread_entry *thread_id;
- +struct event_queue thread_q;
- +
- +#define EV_EXIT 9999
- +#define EV_WAKEUP 1337
- +
- +int load_surface(int);
- +
- +/**
- + Return the index on the stack of slide_index.
- + Return -1 if slide_index is not on the stack.
- + */
- +int slide_stack_get_index(int slide_index)
- +{
- + int i = slide_cache_stack_index + 1;
- + while (i--) {
- + if ( slide_cache_stack[i] == slide_index ) return i;
- + };
- + return -1;
- +}
- +
- +/**
- + Push the slide_index on the stack so the image will be loaded.
- + The algorithm tries to keep the center_index on top and the
- + slide_index as high as possible (so second if center_index is
- + on the stack).
- + */
- +void slide_stack_push(int slide_index)
- +{
- + rb->mutex_lock(&slide_cache_stack_lock);
- +
- + if ( slide_cache_stack_index == -1 ) {
- + // empty stack, no checks at all
- + slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
- + rb->mutex_unlock(&slide_cache_stack_lock);
- + return;
- + }
- +
- + int i = slide_stack_get_index( slide_index );
- +
- + if ( i == slide_cache_stack_index ) {
- + // slide_index is on top, so we do not change anything
- + rb->mutex_unlock(&slide_cache_stack_lock);
- + return;
- + }
- +
- + if ( i >= 0 ) {
- + // slide_index is already on the stack, but not on top
- + int tmp = slide_cache_stack[ slide_cache_stack_index ];
- + if ( tmp == center_index ) {
- + // the center_index is on top of the stack so do not touch that
- + if ( slide_cache_stack_index > 0 ) {
- + // but maybe it is possible to swap the given slide_index to the second place
- + tmp = slide_cache_stack[ slide_cache_stack_index -1 ];
- + slide_cache_stack[ slide_cache_stack_index - 1 ] = slide_cache_stack[ i ];
- + slide_cache_stack[ i ] = tmp;
- + }
- + }
- + else {
- + // if the center_index is not on top (i.e. already loaded) bring the slide_index to the top
- + slide_cache_stack[ slide_cache_stack_index ] = slide_cache_stack[ i ];
- + slide_cache_stack[ i ] = tmp;
- + }
- + }
- + else {
- + // slide_index is not on the stack
- + if ( slide_cache_stack_index >= SLIDE_CACHE_SIZE-1 ) {
- + // if we exceeded the stack size, clear the first half of the stack
- + slide_cache_stack_index = SLIDE_CACHE_SIZE/2;
- + for (i = 0; i <= slide_cache_stack_index ; i++)
- + slide_cache_stack[ i ] = slide_cache_stack[ i + slide_cache_stack_index ];
- + }
- + if ( slide_cache_stack[ slide_cache_stack_index ] == center_index ) {
- + // if the center_index is on top leave it there
- + slide_cache_stack[ slide_cache_stack_index ] = slide_index;
- + slide_cache_stack[ ++slide_cache_stack_index ] = center_index;
- + }
- + else {
- + // usual stack case: push the slide_index on top
- + slide_cache_stack[ ++slide_cache_stack_index ] = slide_index;
- + }
- + }
- + rb->mutex_unlock(&slide_cache_stack_lock);
- +}
- +
- +/**
- + Pop the topmost item from the stack and decrease the stack size
- + */
- +inline int slide_stack_pop(void)
- +{
- + rb->mutex_lock(&slide_cache_stack_lock);
- + int result;
- + if ( slide_cache_stack_index >= 0 )
- + result = slide_cache_stack[ slide_cache_stack_index-- ];
- + else
- + result = -1;
- + rb->mutex_unlock(&slide_cache_stack_lock);
- + return result;
- +}
- +
- +/**
- + Load the slide into the cache.
- + Thus we have to queue the loading request in our thread while discarding the oldest slide.
- + */
- +void request_surface(int slide_index)
- +{
- + slide_stack_push(slide_index);
- + rb->queue_post(&thread_q, EV_WAKEUP, 0);
- +}
- +
- +
- +/**
- + Thread used for loading and preparing bitmaps in the background
- + */
- +void thread(void)
- +{
- + long sleep_time = 5 * HZ;
- + struct queue_event ev;
- + while (1) {
- + rb->queue_wait_w_tmo(&thread_q, &ev, sleep_time);
- + switch (ev.id) {
- + case EV_EXIT:
- + return;
- + case EV_WAKEUP:
- + // we just woke up
- + break;
- + }
- + int slide_index;
- + while ( (slide_index = slide_stack_pop()) != -1 ) {
- + load_surface( slide_index );
- + rb->sleep( HZ ); // FIXME: optimize if we are satisified :)
- + }
- + }
- +}
- +
- +
- +/**
- + End the thread by posting the EV_EXIT event
- + */
- +void end_pf_thread(void)
- +{
- + rb->queue_post(&thread_q, EV_EXIT, 0);
- + rb->thread_wait(thread_id);
- + /* remove the thread's queue from the broadcast list */
- + rb->queue_delete(&thread_q);
- +}
- +
- +
- +/**
- + Create the thread an setup the event queue
- + */
- +bool create_pf_thread(void)
- +{
- + rb->queue_init(&thread_q, true); /* put the thread's queue in the bcast list */
- + if ((thread_id = rb->create_thread(
- + thread,
- + thread_stack,
- + sizeof(thread_stack),
- + 0,
- + "Picture load thread"
- + IF_PRIO(, PRIORITY_BACKGROUND)
- + IF_COP(, CPU)
- + )
- + ) == NULL) {
- + return false;
- + }
- + return true;
- +}
- +
- +
- +static fb_data tmp_bmp_buffer[IMG_WIDTH * IMG_HEIGHT]; // static buffer for reading the bitmaps
- +
- +/**
- + Read the slide at the given index into the cache
- + TODO: This could be *much* more efficient
- + It probably would make sense to store the files in raw format
- + We would save the expensive 24->16bpp conversion and the computation of the
- + reflection.
- + */
- +static bool read_bmp(int slide_index, int cache_index)
- +{
- + struct bitmap tmp_bmp;
- + int ret;
- + tmp_bmp.data = (char *) &tmp_bmp_buffer;
- + char path[MAX_PATH];
- + // TODO: map slide_index to the actual album filename
- + rb->snprintf(path, sizeof(path), "/pics/cover%d.bmp", slide_index+1);
- + ret = rb->read_bmp_file(path, &tmp_bmp, sizeof(tmp_bmp_buffer), FORMAT_NATIVE);
- +
- + int hid = rb->bufalloc(NULL, sizeof(struct bitmap) + (tmp_bmp.width+1) * tmp_bmp.height*2 * sizeof(fb_data), TYPE_BITMAP);
- + if (hid < 0)
- + return false;
- +
- + struct bitmap *bmp;
- + rb->bufgetdata(hid, 0, (void *)&bmp);
- + bmp->width = tmp_bmp.width;
- + bmp->height = tmp_bmp.height;
- + bmp->format = tmp_bmp.format;
- + bmp->data = (char *)(bmp + sizeof(struct bitmap));
- + slide_cache_hid[cache_index] = hid;
- +
- + if (ret > 0) {
- + int h = bmp->height;
- + int w = bmp->width;
- + fb_data *result = (fb_data *)bmp->data;
- + // slightly larger, to accomodate for the reflection
- + int hs = h * 2;
- + int hofs = w / 3;
- + rb->memset(result, 0, sizeof(fb_data) * w * hs);
- + int x, y;
- + // transpose the image, this is to speed-up the rendering
- + // because we process one column at a time
- + // (and much better and faster to work row-wise, i.e in one scanline)
- + for (x = 0; x < w; x++)
- + for (y = 0; y < h; y++)
- + result[bmp->width * 2 * x + (hofs + y)] =
- + tmp_bmp_buffer[y * bmp->width + x];
- +
- + // create the reflection
- + int ht = hs - h - hofs;
- + int hte = ht;
- + for (x = 0; x < w; x++) {
- + for (y = 0; y < ht; y++) {
- + fb_data color = tmp_bmp_buffer[x + bmp->width * (bmp->height - y - 1)];
- + int r = RGB_UNPACK_RED(color) * (hte - y) / hte * 3 / 5;
- + int g = RGB_UNPACK_GREEN(color) * (hte - y) / hte * 3 / 5;
- + int b = RGB_UNPACK_BLUE(color) * (hte - y) / hte * 3 / 5;
- + result[h + hofs + y + bmp->width * x * 2] =
- + LCD_RGBPACK(r, g, b);
- + }
- + }
- + if ( cache_index < SLIDE_CACHE_SIZE ) {
- + slide_cache_map[cache_index] = slide_index;
- + slide_cache_touched[cache_index] = *rb->current_tick;
- + }
- + return true;
- + }
- + return false;
- +}
- +
- +
- +
- +/**
- + Load the surface from a bmp and store overwrite the oldest slide in the cache
- + */
- +int load_surface(int slide_index)
- +{
- + long oldest_tick = *rb->current_tick;
- + int oldest_slide = 0;
- + int i;
- + if ( slide_cache_in_use < SLIDE_CACHE_SIZE ) { // initial fill
- + oldest_slide = slide_cache_in_use;
- + read_bmp(slide_index, slide_cache_in_use++);
- + }
- + else {
- + for (i = 0; i < SLIDE_CACHE_SIZE; i++) { // look for oldest slide
- + if (slide_cache_touched[i] < oldest_tick) {
- + oldest_slide = i;
- + oldest_tick = slide_cache_touched[i];
- + }
- + }
- + slide_cache_hid[oldest_slide] = -1;
- + rb->bufclose(slide_cache_hid[oldest_slide]);
- + read_bmp(slide_index, oldest_slide);
- + }
- + return oldest_slide;
- +}
- +
- +
- +/**
- + Get a slide from the buffer
- + */
- +struct bitmap *get_slide(int hid)
- +{
- + if (hid < 0)
- + return NULL;
- +
- + struct bitmap *bmp;
- +
- + ssize_t ret = rb->bufgetdata(hid, 0, (void *)&bmp);
- + if (ret < 0)
- + return NULL;
- +
- + return bmp;
- +}
- +
- +
- +/**
- + Return the requested surface
- +*/
- +struct bitmap *surface(int slide_index)
- +{
- + if (slide_index < 0)
- + return 0;
- + if (slide_index >= number_of_slides)
- + return 0;
- +
- + int i;
- + for (i = 0; i < slide_cache_in_use; i++) { // maybe do the inverse mapping => implies dynamic allocation?
- + if ( slide_cache_map[i] == slide_index ) {
- + // We have already loaded our slide, so touch it and return it.
- + slide_cache_touched[i] = *rb->current_tick;
- + return get_slide(slide_cache_hid[i]);
- + }
- + }
- + request_surface(slide_index);
- + return get_slide(slide_cache_hid[SLIDE_CACHE_SIZE]);
- +}
- +
- +/**
- + adjust slides so that they are in "steady state" position
- + */
- +void reset_slides(void)
- +{
- + center_slide.angle = 0;
- + center_slide.cx = 0;
- + center_slide.cy = 0;
- + center_slide.slide_index = center_index;
- +
- + int i;
- + for (i = 0; i < LEFT_SLIDES_COUNT; i++) {
- + struct slide_data *si = &left_slides[i];
- + si->angle = itilt;
- + si->cx = -(offsetX + spacing * i * PFREAL_ONE);
- + si->cy = offsetY;
- + si->slide_index = center_index - 1 - i;
- + }
- +
- + for (i = 0; i < RIGHT_SLIDES_COUNT; i++) {
- + struct slide_data *si = &right_slides[i];
- + si->angle = -itilt;
- + si->cx = offsetX + spacing * i * PFREAL_ONE;
- + si->cy = offsetY;
- + si->slide_index = center_index + 1 + i;
- + }
- +}
- +
- +
- +/**
- + Updates look-up table and other stuff necessary for the rendering.
- + Call this when the viewport size or slide dimension is changed.
- + */
- +void recalc_table(void)
- +{
- + int w = (BUFFER_WIDTH + 1) / 2;
- + int h = (BUFFER_HEIGHT + 1) / 2;
- + int i;
- + for (i = 0; i < w; i++) {
- + PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2 * h);
- + rays[w - i - 1] = -gg;
- + rays[w + i] = gg;
- + }
- +
- +
- + itilt = 70 * IANGLE_MAX / 360; // approx. 70 degrees tilted
- +
- + offsetX = SLIDE_WIDTH / 2 * (PFREAL_ONE - fcos(itilt));
- + offsetY = SLIDE_WIDTH / 2 * fsin(itilt);
- + offsetX += SLIDE_WIDTH * PFREAL_ONE;
- + offsetY += SLIDE_WIDTH * PFREAL_ONE / 4;
- + spacing = 40;
- +}
- +
- +
- +
- +/**
- + render a single slide
- +*/
- +void render_slide(struct slide_data *slide, struct rect *result_rect,
- + int alpha, int col1, int col2)
- +{
- + rb->memset(result_rect, 0, sizeof(struct rect));
- + struct bitmap *bmp = surface(slide->slide_index);
- + if (!bmp) {
- + return;
- + }
- + fb_data *src = (fb_data *)bmp->data;
- +
- + int sw = bmp->height;
- + int sh = bmp->width * 2;
- +
- + int h = LCD_HEIGHT;
- + int w = LCD_WIDTH;
- +
- + if (col1 > col2) {
- + int c = col2;
- + col2 = col1;
- + col1 = c;
- + }
- +
- + col1 = (col1 >= 0) ? col1 : 0;
- + col2 = (col2 >= 0) ? col2 : w - 1;
- + col1 = fmin(col1, w - 1);
- + col2 = fmin(col2, w - 1);
- +
- + int distance = h * 100 / zoom;
- + PFreal sdx = fcos(slide->angle);
- + PFreal sdy = fsin(slide->angle);
- + PFreal xs = slide->cx - bmp->width * sdx / 2;
- + PFreal ys = slide->cy - bmp->width * sdy / 2;
- + PFreal dist = distance * PFREAL_ONE;
- +
- +
- + int xi = fmax((PFreal) 0,
- + ((w * PFREAL_ONE / 2) +
- + fdiv(xs * h, dist + ys)) >> PFREAL_SHIFT);
- + if (xi >= w) {
- + return;
- + }
- +
- + bool flag = false;
- + result_rect->left = xi;
- + int x;
- + for (x = fmax(xi, col1); x <= col2; x++) {
- + PFreal hity = 0;
- + PFreal fk = rays[x];
- + if (sdy) {
- + fk = fk - fdiv(sdx, sdy);
- + hity = -fdiv(( rays[x] * distance
- + - slide->cx
- + + slide->cy * sdx / sdy), fk);
- + }
- +
- + dist = distance * PFREAL_ONE + hity;
- + if (dist < 0)
- + continue;
- +
- + PFreal hitx = fmul(dist, rays[x]);
- +
- + PFreal hitdist = fdiv(hitx - slide->cx, sdx);
- +
- + int column = sw / 2 + (hitdist >> PFREAL_SHIFT);
- + if (column >= sw)
- + break;
- +
- + if (column < 0)
- + continue;
- +
- + result_rect->right = x;
- + if (!flag)
- + result_rect->left = x;
- + flag = true;
- +
- + int y1 = h / 2;
- + int y2 = y1 + 1;
- + fb_data *pixel1 = &buffer[y1 * BUFFER_WIDTH + x];
- + fb_data *pixel2 = &buffer[y2 * BUFFER_WIDTH + x];
- + int pixelstep = pixel2 - pixel1;
- +
- + int center = (sh / 2);
- + int dy = dist / h;
- + int p1 = center * PFREAL_ONE - dy / 2;
- + int p2 = center * PFREAL_ONE + dy / 2;
- +
- +
- + const fb_data *ptr = &src[column * bmp->width * 2];
- + if (alpha == 256)
- + while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
- + *pixel1 = ptr[p1 >> PFREAL_SHIFT];
- + *pixel2 = ptr[p2 >> PFREAL_SHIFT];
- + p1 -= dy;
- + p2 += dy;
- + y1--;
- + y2++;
- + pixel1 -= pixelstep;
- + pixel2 += pixelstep;
- + } else
- + while ((y1 >= 0) && (y2 < h) && (p1 >= 0)) {
- + fb_data c1 = ptr[p1 >> PFREAL_SHIFT];
- + fb_data c2 = ptr[p2 >> PFREAL_SHIFT];
- +
- + int r1 = RGB_UNPACK_RED(c1) * alpha / 256;
- + int g1 = RGB_UNPACK_GREEN(c1) * alpha / 256;
- + int b1 = RGB_UNPACK_BLUE(c1) * alpha / 256;
- + int r2 = RGB_UNPACK_RED(c2) * alpha / 256;
- + int g2 = RGB_UNPACK_GREEN(c2) * alpha / 256;
- + int b2 = RGB_UNPACK_BLUE(c2) * alpha / 256;
- +
- + *pixel1 = LCD_RGBPACK(r1, g1, b1);
- + *pixel2 = LCD_RGBPACK(r2, g2, b2);
- + p1 -= dy;
- + p2 += dy;
- + y1--;
- + y2++;
- + pixel1 -= pixelstep;
- + pixel2 += pixelstep;
- + }
- + }
- + // let the music play...
- + rb->yield();
- +
- + result_rect->top = 0;
- + result_rect->bottom = h - 1;
- + return;
- +}
- +
- +
- +static inline void set_current_slide(int index)
- +{
- + step = 0;
- + center_index = fbound(index, 0, number_of_slides - 1);
- + target = center_index;
- + slide_frame = index << 16;
- + reset_slides();
- +}
- +
- +void start_animation(void)
- +{
- + if (!animation_is_active) {
- + step = (target < center_slide.slide_index) ? -1 : 1;
- + animation_is_active = true;
- + }
- +}
- +
- +void show_previous_slide(void)
- +{
- + if (step >= 0) {
- + if (center_index > 0) {
- + target = center_index - 1;
- + start_animation();
- + }
- + } else {
- + target = fmax(0, center_index - 2);
- + }
- +}
- +
- +void show_next_slide(void)
- +{
- + if (step <= 0) {
- + if (center_index < number_of_slides - 1) {
- + target = center_index + 1;
- + start_animation();
- + }
- + } else {
- + target = fmin(center_index + 2, number_of_slides - 1);
- + }
- +}
- +
- +
- +
- +/**
- + Return true if the rect has size 0
- +*/
- +bool is_empty_rect(struct rect *r)
- +{
- + return ((r->left == 0) && (r->right == 0) && (r->top == 0)
- + && (r->bottom == 0));
- +}
- +
- +
- +/**
- + Render the slides. Updates only the offscreen buffer.
- +*/
- +void render(void)
- +{
- + rb->lcd_set_background(LCD_RGBPACK(0,0,0));
- + rb->lcd_clear_display(); // TODO: Optimizes this by e.g. invalidating rects
- +
- + int nleft = LEFT_SLIDES_COUNT;
- + int nright = RIGHT_SLIDES_COUNT;
- +
- + struct rect r;
- + render_slide(¢er_slide, &r, 256, -1, -1);
- +#ifdef DEBUG_DRAW
- + rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
- +#endif
- + int c1 = r.left;
- + int c2 = r.right;
- + int index;
- + if (step == 0) {
- + // no animation, boring plain rendering
- + for (index = 0; index < nleft - 1; index++) {
- + int alpha = (index < nleft - 2) ? 256 : 128;
- + render_slide(&left_slides[index], &r, alpha, 0, c1 - 1);
- + if (!is_empty_rect(&r)) {
- +#ifdef DEBUG_DRAW
- + rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
- +#endif
- + c1 = r.left;
- + }
- + }
- + for (index = 0; index < nright - 1; index++) {
- + int alpha = (index < nright - 2) ? 256 : 128;
- + render_slide(&right_slides[index], &r, alpha, c2 + 1,
- + BUFFER_WIDTH);
- + if (!is_empty_rect(&r)) {
- +#ifdef DEBUG_DRAW
- + rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
- +#endif
- + c2 = r.right;
- + }
- + }
- + } else {
- + // the first and last slide must fade in/fade out
- + for (index = 0; index < nleft; index++) {
- + int alpha = 256;
- + if (index == nleft - 1)
- + alpha = (step > 0) ? 0 : 128 - fade / 2;
- + if (index == nleft - 2)
- + alpha = (step > 0) ? 128 - fade / 2 : 256 - fade / 2;
- + if (index == nleft - 3)
- + alpha = (step > 0) ? 256 - fade / 2 : 256;
- + render_slide(&left_slides[index], &r, alpha, 0, c1 - 1);
- +
- + if (!is_empty_rect(&r)) {
- +#ifdef DEBUG_DRAW
- + rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
- +#endif
- + c1 = r.left;
- + }
- + }
- + for (index = 0; index < nright; index++) {
- + int alpha = (index < nright - 2) ? 256 : 128;
- + if (index == nright - 1)
- + alpha = (step > 0) ? fade / 2 : 0;
- + if (index == nright - 2)
- + alpha = (step > 0) ? 128 + fade / 2 : fade / 2;
- + if (index == nright - 3)
- + alpha = (step > 0) ? 256 : 128 + fade / 2;
- + render_slide(&right_slides[index], &r, alpha, c2 + 1,
- + BUFFER_WIDTH);
- + if (!is_empty_rect(&r)) {
- +#ifdef DEBUG_DRAW
- + rb->lcd_drawrect(r.left, r.top, r.right - r.left, r.bottom - r.top);
- +#endif
- + c2 = r.right;
- + }
- + }
- + }
- +}
- +
- +
- +/**
- + Updates the animation effect. Call this periodically from a timer.
- +*/
- +void update_animation(void)
- +{
- + if (!animation_is_active)
- + return;
- + if (step == 0)
- + return;
- +
- + int speed = 16384;
- + int i;
- +
- + // deaccelerate when approaching the target
- + if (true) {
- + const int max = 2 * 65536;
- +
- + int fi = slide_frame;
- + fi -= (target << 16);
- + if (fi < 0)
- + fi = -fi;
- + fi = fmin(fi, max);
- +
- + int ia = IANGLE_MAX * (fi - max / 2) / (max * 2);
- + speed = 512 + 16384 * (PFREAL_ONE + fsin(ia)) / PFREAL_ONE;
- + }
- +
- + slide_frame += speed * step;
- +
- + int index = slide_frame >> 16;
- + int pos = slide_frame & 0xffff;
- + int neg = 65536 - pos;
- + int tick = (step < 0) ? neg : pos;
- + PFreal ftick = (tick * PFREAL_ONE) >> 16;
- +
- + // the leftmost and rightmost slide must fade away
- + fade = pos / 256;
- +
- + if (step < 0)
- + index++;
- + if (center_index != index) {
- + center_index = index;
- + slide_frame = index << 16;
- + center_slide.slide_index = center_index;
- + for (i = 0; i < LEFT_SLIDES_COUNT; i++)
- + left_slides[i].slide_index = center_index - 1 - i;
- + for (i = 0; i < RIGHT_SLIDES_COUNT; i++)
- + right_slides[i].slide_index = center_index + 1 + i;
- + }
- +
- + center_slide.angle = (step * tick * itilt) >> 16;
- + center_slide.cx = -step * fmul(offsetX, ftick);
- + center_slide.cy = fmul(offsetY, ftick);
- +
- + if (center_index == target) {
- + reset_slides();
- + animation_is_active = false;
- + step = 0;
- + fade = 256;
- + return;
- + }
- +
- + for (i = 0; i < LEFT_SLIDES_COUNT; i++) {
- + struct slide_data *si = &left_slides[i];
- + si->angle = itilt;
- + si->cx =
- + -(offsetX + spacing * i * PFREAL_ONE + step * spacing * ftick);
- + si->cy = offsetY;
- + }
- +
- + for (i = 0; i < RIGHT_SLIDES_COUNT; i++) {
- + struct slide_data *si = &right_slides[i];
- + si->angle = -itilt;
- + si->cx =
- + offsetX + spacing * i * PFREAL_ONE - step * spacing * ftick;
- + si->cy = offsetY;
- + }
- +
- + if (step > 0) {
- + PFreal ftick = (neg * PFREAL_ONE) >> 16;
- + right_slides[0].angle = -(neg * itilt) >> 16;
- + right_slides[0].cx = fmul(offsetX, ftick);
- + right_slides[0].cy = fmul(offsetY, ftick);
- + } else {
- + PFreal ftick = (pos * PFREAL_ONE) >> 16;
- + left_slides[0].angle = (pos * itilt) >> 16;
- + left_slides[0].cx = -fmul(offsetX, ftick);
- + left_slides[0].cy = fmul(offsetY, ftick);
- + }
- +
- + // must change direction ?
- + if (target < index)
- + if (step > 0)
- + step = -1;
- + if (target > index)
- + if (step < 0)
- + step = 1;
- +}
- +
- +
- +/**
- + Cleanup the plugin
- +*/
- +void cleanup(void *parameter)
- +{
- + (void) parameter;
- +#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- + rb->cpu_boost(false);
- +#endif
- + /* Turn on backlight timeout (revert to settings) */
- + backlight_use_settings(rb); /* backlight control in lib/helper.c */
- +
- + int i;
- + for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
- + rb->bufclose(slide_cache_hid[i]);
- + }
- +}
- +
- +
- +
- +/**
- + Main function that also contain the main plasma
- + algorithm.
- + */
- +int main(void)
- +{
- + if (!create_pf_thread()) {
- + rb->splash(HZ, "Cannot create thread!");
- + return PLUGIN_ERROR;
- + }
- +
- + int i;
- +
- + // initialize
- + for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
- + slide_cache_hid[i] = -1;
- + slide_cache_touched[i] = 0;
- + }
- + slide_cache_in_use = 0;
- + buffer = rb->lcd_framebuffer;
- + animation_is_active = false;
- + zoom = 100;
- + center_index = 0;
- + slide_frame = 0;
- + step = 0;
- + target = 0;
- + fade = 256;
- + show_fps = true;
- + number_of_slides = 100; // this is the album count
- +/*
- + for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
- + if (!read_bmp(i,i)) {
- + rb->splash(HZ, "error reading bmp");
- + return PLUGIN_ERROR;
- + }
- + }
- + */
- + read_bmp(-1,SLIDE_CACHE_SIZE); // empty slide hack... FIXME: make this prettier
- +
- + recalc_table();
- + reset_slides();
- +
- + char fpstxt[10];
- + char albumtxt[30];
- + int button;
- +
- +#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- + rb->cpu_boost(true);
- +#endif
- + int frames = 0;
- + long last_update = *rb->current_tick;
- + long current_update;
- + long update_interval = 100;
- + int fps = 0;
- + int albumtxt_w, albumtxt_h;
- + while (true) {
- + current_update = *rb->current_tick;
- + frames++;
- + update_animation();
- + render();
- +
- + if (current_update - last_update > update_interval) {
- + fps = frames * HZ / (current_update - last_update);
- + last_update = current_update;
- + frames = 0;
- + }
- +
- + if (show_fps) {
- + rb->lcd_set_foreground(LCD_RGBPACK(255, 0, 0));
- + rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
- + rb->lcd_putsxy(0, 0, fpstxt);
- + }
- +
- + rb->snprintf(albumtxt, sizeof(albumtxt), "Index is %d", center_index); // replace with album title
- + rb->lcd_set_foreground(LCD_RGBPACK(255, 255, 255));
- + rb->lcd_getstringsize(albumtxt, &albumtxt_w, &albumtxt_h);
- + rb->lcd_putsxy((LCD_WIDTH - albumtxt_w) /2, LCD_HEIGHT-albumtxt_h-10, albumtxt);
- +
- +
- +
- + rb->lcd_update();
- + rb->yield();
- +
- + button = rb->button_get(false); //always paint -> sucks our battery
- + //button = rb->button_get(!animation_is_active); // we need to wake up here if our thread yells
- + switch (button) {
- + case PICTUREFLOW_QUIT:
- + cleanup(NULL);
- + return PLUGIN_OK;
- + break;
- +
- + case PICTUREFLOW_NEXT_ALBUM:
- + case (PICTUREFLOW_NEXT_ALBUM | BUTTON_REPEAT):
- + show_next_slide();
- + break;
- +
- + case PICTUREFLOW_PREV_ALBUM:
- + case (PICTUREFLOW_PREV_ALBUM | BUTTON_REPEAT):
- + show_previous_slide();
- + break;
- +
- + default:
- + if (rb->default_event_handler_ex(button, cleanup, NULL)
- + == SYS_USB_CONNECTED)
- + return PLUGIN_USB_CONNECTED;
- + break;
- + }
- + //rb->sleep(HZ/100);
- + }
- +}
- +
- +/*************************** Plugin entry point ****************************/
- +
- +enum plugin_status plugin_start(struct plugin_api *api, void *parameter)
- +{
- + int ret;
- +
- + rb = api; // copy to global api pointer
- + (void) parameter;
- +#if LCD_DEPTH > 1
- + rb->lcd_set_backdrop(NULL);
- +#endif
- + /* Turn off backlight timeout */
- + backlight_force_on(rb); /* backlight control in lib/helper.c */
- +
- + ret = main();
- + end_pf_thread();
- + return ret;
- +}
- +
- +#endif /* #ifdef HAVE_LCD_BITMAP */
advertising
Update the Post
Either update this post and resubmit it with changes, or make a new post.
You may also comment on this post.
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.