summaryrefslogtreecommitdiff
path: root/apps/plugins/pictureflow.c
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2009-05-07 01:23:13 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2009-05-07 01:23:13 +0000
commit5621fd393a4445645b07bb2e89d89d23bb9a6473 (patch)
treeb2b46a056ea1ae599e0a99118ddacdf72a6dac4a /apps/plugins/pictureflow.c
parent580b1a5c4b305c7cb320415267c5e1b88b053948 (diff)
downloadrockbox-5621fd393a4445645b07bb2e89d89d23bb9a6473.zip
rockbox-5621fd393a4445645b07bb2e89d89d23bb9a6473.tar.gz
rockbox-5621fd393a4445645b07bb2e89d89d23bb9a6473.tar.bz2
rockbox-5621fd393a4445645b07bb2e89d89d23bb9a6473.tar.xz
Build pictureflow using overlay on lowmem targets, support JPEG AA in PF on all targets.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20864 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/pictureflow.c')
-rw-r--r--apps/plugins/pictureflow.c2580
1 files changed, 0 insertions, 2580 deletions
diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
deleted file mode 100644
index 7261d7a..0000000
--- a/apps/plugins/pictureflow.c
+++ /dev/null
@@ -1,2580 +0,0 @@
-/***************************************************************************
-* __________ __ ___.
-* Open \______ \ ____ ____ | | _\_ |__ _______ ___
-* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
-* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
-* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
-* \/ \/ \/ \/ \/
-* $Id$
-*
-* Copyright (C) 2007 Jonas Hurrelmann (j@outpo.st)
-* Copyright (C) 2007 Nicolas Pennequin
-* Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) (original Qt Version)
-*
-* Original code: http://code.google.com/p/pictureflow/
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-* KIND, either express or implied.
-*
-****************************************************************************/
-
-#include "plugin.h"
-#include <albumart.h>
-#include "lib/read_image.h"
-#include "lib/pluginlib_actions.h"
-#include "lib/helper.h"
-#include "lib/configfile.h"
-#include "lib/picture.h"
-#include "pluginbitmaps/pictureflow_logo.h"
-#include "lib/grey.h"
-#include "lib/feature_wrappers.h"
-#include "lib/buflib.h"
-
-PLUGIN_HEADER
-
-/******************************* Globals ***********************************/
-
-#define PF_PREV ACTION_STD_PREV
-#define PF_PREV_REPEAT ACTION_STD_PREVREPEAT
-#define PF_NEXT ACTION_STD_NEXT
-#define PF_NEXT_REPEAT ACTION_STD_NEXTREPEAT
-#define PF_SELECT ACTION_STD_OK
-#define PF_CONTEXT ACTION_STD_CONTEXT
-#define PF_BACK ACTION_STD_CANCEL
-#define PF_MENU ACTION_STD_MENU
-#define PF_QUIT (LAST_ACTION_PLACEHOLDER + 1)
-
-const struct button_mapping pf_context_album_scroll[] =
-{
-#ifdef HAVE_TOUCHSCREEN
- {PF_PREV, BUTTON_MIDLEFT, BUTTON_NONE},
- {PF_PREV_REPEAT, BUTTON_MIDLEFT|BUTTON_REPEAT, BUTTON_NONE},
- {PF_NEXT, BUTTON_MIDRIGHT, BUTTON_NONE},
- {PF_NEXT_REPEAT, BUTTON_MIDRIGHT|BUTTON_REPEAT, BUTTON_NONE},
-#endif
-#if CONFIG_KEYPAD == IRIVER_H100_PAD || CONFIG_KEYPAD == IRIVER_H300_PAD || \
- CONFIG_KEYPAD == IAUDIO_X5M5_PAD || CONFIG_KEYPAD == GIGABEAT_PAD || \
- CONFIG_KEYPAD == GIGABEAT_S_PAD || CONFIG_KEYPAD == RECORDER_PAD || \
- CONFIG_KEYPAD == ARCHOS_AV300_PAD || CONFIG_KEYPAD == SANSA_C100_PAD || \
- CONFIG_KEYPAD == SANSA_C200_PAD || CONFIG_KEYPAD == SANSA_CLIP_PAD || \
- CONFIG_KEYPAD == SANSA_M200_PAD || CONFIG_KEYPAD == IRIVER_IFP7XX_PAD || \
- CONFIG_KEYPAD == MROBE100_PAD || CONFIG_KEYPAD == PHILIPS_SA9200_PAD || \
- CONFIG_KEYPAD == IAUDIO67_PAD || CONFIG_KEYPAD == CREATIVEZVM_PAD || \
- CONFIG_KEYPAD == PHILIPS_HDD1630_PAD || CONFIG_KEYPAD == CREATIVEZV_PAD \
- || CONFIG_KEYPAD == SANSA_CLIP_PAD || CONFIG_KEYPAD == LOGIK_DAX_PAD || \
- CONFIG_KEYPAD == MEIZU_M6SL_PAD
- {PF_PREV, BUTTON_LEFT, BUTTON_NONE},
- {PF_PREV_REPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
- {PF_NEXT, BUTTON_RIGHT, BUTTON_NONE},
- {PF_NEXT_REPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
-#elif CONFIG_KEYPAD == ONDIO_PAD
- {PF_PREV, BUTTON_LEFT, BUTTON_NONE},
- {PF_PREV_REPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
- {PF_NEXT, BUTTON_RIGHT, BUTTON_NONE},
- {PF_NEXT_REPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
- {PF_SELECT, BUTTON_UP|BUTTON_REL, BUTTON_UP},
- {PF_CONTEXT, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP},
- {ACTION_NONE, BUTTON_UP, BUTTON_NONE},
- {ACTION_NONE, BUTTON_DOWN, BUTTON_NONE},
- {ACTION_NONE, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
- {ACTION_NONE, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT},
-#elif CONFIG_KEYPAD == IAUDIO_M3_PAD || CONFIG_KEYPAD == MROBE500_PAD
- {PF_PREV, BUTTON_RC_REW, BUTTON_NONE},
- {PF_PREV_REPEAT, BUTTON_RC_REW|BUTTON_REPEAT,BUTTON_NONE},
- {PF_NEXT, BUTTON_RC_FF, BUTTON_NONE},
- {PF_NEXT_REPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE},
-#endif
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|1)
-};
-
-const struct button_mapping pf_context_buttons[] =
-{
-#ifdef HAVE_TOUCHSCREEN
- {PF_SELECT, BUTTON_CENTER, BUTTON_NONE},
- {PF_MENU, BUTTON_TOPLEFT, BUTTON_NONE},
- {PF_BACK, BUTTON_BOTTOMRIGHT, BUTTON_NONE},
-#endif
-#if CONFIG_KEYPAD == ARCHOS_AV300_PAD
- {PF_QUIT, BUTTON_OFF, BUTTON_NONE},
-#elif CONFIG_KEYPAD == SANSA_C100_PAD
- {PF_QUIT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
-#elif CONFIG_KEYPAD == CREATIVEZV_PAD || CONFIG_KEYPAD == CREATIVEZVM_PAD || \
- CONFIG_KEYPAD == PHILIPS_HDD1630_PAD || CONFIG_KEYPAD == IAUDIO67_PAD || \
- CONFIG_KEYPAD == GIGABEAT_PAD || CONFIG_KEYPAD == GIGABEAT_S_PAD || \
- CONFIG_KEYPAD == MROBE100_PAD || CONFIG_KEYPAD == MROBE500_PAD || \
- CONFIG_KEYPAD == PHILIPS_SA9200_PAD || CONFIG_KEYPAD == SANSA_CLIP_PAD || \
- CONFIG_KEYPAD == SANSA_FUZE_PAD
- {PF_QUIT, BUTTON_POWER, BUTTON_NONE},
-/* These all use short press of BUTTON_POWER for menu, map long POWER to quit
-*/
-#elif CONFIG_KEYPAD == SANSA_C200_PAD || CONFIG_KEYPAD == SANSA_M200_PAD || \
- CONFIG_KEYPAD == IRIVER_H10_PAD || CONFIG_KEYPAD == COWOND2_PAD
- {PF_QUIT, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER},
-#if CONFIG_KEYPAD == COWOND2_PAD
- {PF_BACK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
- {ACTION_NONE, BUTTON_POWER, BUTTON_NONE},
-#endif
-#elif CONFIG_KEYPAD == SANSA_E200_PAD
- {PF_QUIT, BUTTON_POWER, BUTTON_NONE},
-#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
- {PF_QUIT, BUTTON_EQ, BUTTON_NONE},
-#elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
- || (CONFIG_KEYPAD == IPOD_3G_PAD) \
- || (CONFIG_KEYPAD == IPOD_4G_PAD)
- {PF_QUIT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
-#elif CONFIG_KEYPAD == LOGIK_DAX_PAD
- {PF_QUIT, BUTTON_POWERPLAY|BUTTON_REPEAT, BUTTON_POWERPLAY},
-#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
- {PF_QUIT, BUTTON_RC_REC, BUTTON_NONE},
-#elif CONFIG_KEYPAD == MEIZU_M6SL_PAD
- {PF_QUIT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
-#elif CONFIG_KEYPAD == IRIVER_H100_PAD || CONFIG_KEYPAD == IRIVER_H300_PAD || \
- CONFIG_KEYPAD == RECORDER_PAD || CONFIG_KEYPAD == ONDIO_PAD
- {PF_QUIT, BUTTON_OFF, BUTTON_NONE},
-#endif
-#if CONFIG_KEYPAD == IAUDIO_M3_PAD
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD|CONTEXT_REMOTE)
-#else
- LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
-#endif
-};
-const struct button_mapping *pf_contexts[] =
-{
- pf_context_album_scroll,
- pf_context_buttons
-};
-
-#if LCD_DEPTH < 8
-#if LCD_DEPTH > 1
-#define N_BRIGHT(y) LCD_BRIGHTNESS(y)
-#else /* LCD_DEPTH <= 1 */
-#define N_BRIGHT(y) ((y > 127) ? 0 : 1)
-#ifdef HAVE_NEGATIVE_LCD /* m:robe 100, Clip */
-#define PICTUREFLOW_DRMODE DRMODE_SOLID
-#else
-#define PICTUREFLOW_DRMODE (DRMODE_SOLID|DRMODE_INVERSEVID)
-#endif
-#endif /* LCD_DEPTH <= 1 */
-#define USEGSLIB
-GREY_INFO_STRUCT
-#define LCD_BUF _grey_info.buffer
-#define MYLCD(fn) grey_ ## fn
-#define G_PIX(r,g,b) \
- (77 * (unsigned)(r) + 150 * (unsigned)(g) + 29 * (unsigned)(b)) / 256
-#define N_PIX(r,g,b) N_BRIGHT(G_PIX(r,g,b))
-#define G_BRIGHT(y) (y)
-#define BUFFER_WIDTH _grey_info.width
-#define BUFFER_HEIGHT _grey_info.height
-typedef unsigned char pix_t;
-#else /* LCD_DEPTH >= 8 */
-#define LCD_BUF rb->lcd_framebuffer
-#define MYLCD(fn) rb->lcd_ ## fn
-#define G_PIX LCD_RGBPACK
-#define N_PIX LCD_RGBPACK
-#define G_BRIGHT(y) LCD_RGBPACK(y,y,y)
-#define N_BRIGHT(y) LCD_RGBPACK(y,y,y)
-#define BUFFER_WIDTH LCD_WIDTH
-#define BUFFER_HEIGHT LCD_HEIGHT
-typedef fb_data pix_t;
-#endif /* LCD_DEPTH >= 8 */
-
-/* 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 IANGLE_MAX 1024
-#define IANGLE_MASK 1023
-
-#define REFLECT_TOP (LCD_HEIGHT * 2 / 3)
-#define REFLECT_HEIGHT (LCD_HEIGHT - REFLECT_TOP)
-#define DISPLAY_HEIGHT REFLECT_TOP
-#define DISPLAY_WIDTH MAX((LCD_HEIGHT * LCD_PIXEL_ASPECT_HEIGHT / \
- LCD_PIXEL_ASPECT_WIDTH / 2), (LCD_WIDTH * 2 / 5))
-#define REFLECT_SC ((0x10000U * 3 + (REFLECT_HEIGHT * 5 - 1)) / \
- (REFLECT_HEIGHT * 5))
-#define DISPLAY_OFFS ((LCD_HEIGHT / 2) - REFLECT_HEIGHT)
-#define CAM_DIST MAX(MIN(LCD_HEIGHT,LCD_WIDTH),120)
-#define CAM_DIST_R (CAM_DIST << PFREAL_SHIFT)
-#define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_HALF)
-#define MAXSLIDE_LEFT_R (PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF)
-
-#define SLIDE_CACHE_SIZE 64 /* probably more than can be loaded */
-
-#define MAX_SLIDES_COUNT 10
-
-#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
-#define CACHE_PREFIX PLUGIN_DEMOS_DIR "/pictureflow"
-
-#define EV_EXIT 9999
-#define EV_WAKEUP 1337
-
-/* maximum number of albums */
-
-#define MAX_TRACKS 50
-#define AVG_TRACK_NAME_LENGTH 20
-
-
-#define UNIQBUF_SIZE (64*1024)
-
-#define EMPTY_SLIDE CACHE_PREFIX "/emptyslide.pfraw"
-#define EMPTY_SLIDE_BMP PLUGIN_DEMOS_DIR "/pictureflow_emptyslide.bmp"
-
-/* Error return values */
-#define ERROR_NO_ALBUMS -1
-#define ERROR_BUFFER_FULL -2
-
-/* current version for cover cache */
-#define CACHE_VERSION 2
-#define CONFIG_VERSION 1
-#define CONFIG_FILE "pictureflow.cfg"
-
-/** structs we use */
-
-struct slide_data {
- int slide_index;
- int angle;
- PFreal cx;
- PFreal cy;
- PFreal distance;
-};
-
-struct slide_cache {
- int index; /* index of the cached slide */
- int hid; /* handle ID of the cached slide */
- short next; /* "next" slide, with LRU last */
- short prev; /* "previous" slide */
-};
-
-struct album_data {
- int name_idx;
- long seek;
-};
-
-struct track_data {
- int name_idx;
- long seek;
-};
-
-struct rect {
- int left;
- int right;
- int top;
- int bottom;
-};
-
-struct load_slide_event_data {
- int slide_index;
- int cache_index;
-};
-
-
-struct pfraw_header {
- int32_t width; /* bmap width in pixels */
- int32_t height; /* bmap height in pixels */
-};
-
-const struct picture logos[]={
- {pictureflow_logo, BMPWIDTH_pictureflow_logo, BMPHEIGHT_pictureflow_logo},
-};
-
-enum show_album_name_values { album_name_hide = 0, album_name_bottom,
- album_name_top };
-static char* show_album_name_conf[] =
-{
- "hide",
- "bottom",
- "top"
-};
-
-#define MAX_SPACING 40
-#define MAX_MARGIN 80
-
-/* config values and their defaults */
-static int slide_spacing = DISPLAY_WIDTH / 4;
-static int center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12;
-static int num_slides = 4;
-static int zoom = 100;
-static bool show_fps = false;
-static bool resize = true;
-static int cache_version = 0;
-static int show_album_name = (LCD_HEIGHT > 100)
- ? album_name_top : album_name_bottom;
-
-static struct configdata config[] =
-{
- { TYPE_INT, 0, MAX_SPACING, { .int_p = &slide_spacing }, "slide spacing",
- NULL },
- { TYPE_INT, 0, MAX_MARGIN, { .int_p = &center_margin }, "center margin",
- NULL },
- { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &num_slides }, "slides count",
- NULL },
- { TYPE_INT, 0, 300, { .int_p = &zoom }, "zoom", NULL },
- { TYPE_BOOL, 0, 1, { .bool_p = &show_fps }, "show fps", NULL },
- { TYPE_BOOL, 0, 1, { .bool_p = &resize }, "resize", NULL },
- { TYPE_INT, 0, 100, { .int_p = &cache_version }, "cache version", NULL },
- { TYPE_ENUM, 0, 2, { .int_p = &show_album_name }, "show album name",
- show_album_name_conf }
-};
-
-#define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata))
-
-/** below we allocate the memory we want to use **/
-
-static pix_t *buffer; /* for now it always points to the lcd framebuffer */
-static uint8_t reflect_table[REFLECT_HEIGHT];
-static struct slide_data center_slide;
-static struct slide_data left_slides[MAX_SLIDES_COUNT];
-static struct slide_data right_slides[MAX_SLIDES_COUNT];
-static int slide_frame;
-static int step;
-static int target;
-static int fade;
-static int center_index = 0; /* index of the slide that is in the center */
-static int itilt;
-static PFreal offsetX;
-static PFreal offsetY;
-static int number_of_slides;
-
-static struct slide_cache cache[SLIDE_CACHE_SIZE];
-static int cache_free;
-static int cache_used = -1;
-static int cache_left_index = -1;
-static int cache_right_index = -1;
-static int cache_center_index = -1;
-
-/* use long for aligning */
-unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
-/* queue (as array) for scheduling load_surface */
-
-static int empty_slide_hid;
-
-unsigned int thread_id;
-struct event_queue thread_q;
-
-static struct tagcache_search tcs;
-
-static struct buflib_context buf_ctx;
-
-static struct album_data *album;
-static char *album_names;
-static int album_count;
-
-static char track_names[MAX_TRACKS * AVG_TRACK_NAME_LENGTH];
-static struct track_data tracks[MAX_TRACKS];
-static int track_count;
-static int track_index;
-static int selected_track;
-static int selected_track_pulse;
-void reset_track_list(void);
-
-void * buf;
-size_t buf_size;
-
-static bool thread_is_running;
-
-static int cover_animation_keyframe;
-static int extra_fade;
-
-static int albumtxt_x = 0;
-static int albumtxt_dir = -1;
-static int prev_center_index = -1;
-
-static int start_index_track_list = 0;
-static int track_list_visible_entries = 0;
-static int track_list_y;
-static int track_list_h;
-static int track_scroll_index = 0;
-static int track_scroll_dir = 1;
-
-/*
- Proposals for transitions:
-
- pf_idle -> pf_scrolling : NEXT_ALBUM/PREV_ALBUM pressed
- -> pf_cover_in -> pf_show_tracks : SELECT_ALBUM clicked
-
- pf_scrolling -> pf_idle : NEXT_ALBUM/PREV_ALBUM released
-
- pf_show_tracks -> pf_cover_out -> pf_idle : SELECT_ALBUM pressed
-
- TODO:
- pf_show_tracks -> pf_cover_out -> pf_idle : MENU_PRESSED pressed
- pf_show_tracks -> play_track() -> exit() : SELECT_ALBUM pressed
-
- pf_idle, pf_scrolling -> show_menu(): MENU_PRESSED
-*/
-enum pf_states {
- pf_idle = 0,
- pf_scrolling,
- pf_cover_in,
- pf_show_tracks,
- pf_cover_out
-};
-
-static int pf_state;
-
-/** code */
-static inline unsigned fade_color(pix_t c, unsigned a);
-bool save_pfraw(char* filename, struct bitmap *bm);
-bool load_new_slide(void);
-int load_surface(int);
-
-static inline PFreal fmul(PFreal a, PFreal b)
-{
- return (a*b) >> PFREAL_SHIFT;
-}
-
-/**
- * This version preshifts each operand, which is useful when we know how many
- * of the least significant bits will be empty, or are worried about overflow
- * in a particular calculation
- */
-static inline PFreal fmuln(PFreal a, PFreal b, int ps1, int ps2)
-{
- return ((a >> ps1) * (b >> ps2)) >> (PFREAL_SHIFT - ps1 - ps2);
-}
-
-/* ARMv5+ has a clz instruction equivalent to our function.
- */
-#if (defined(CPU_ARM) && (ARM_ARCH > 4))
-static inline int clz(uint32_t v)
-{
- return __builtin_clz(v);
-}
-
-/* Otherwise, use our clz, which can be inlined */
-#elif defined(CPU_COLDFIRE)
-/* This clz is based on the log2(n) implementation at
- * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
- * A clz benchmark plugin showed this to be about 14% faster on coldfire
- * than the LUT-based version.
- */
-static inline int clz(uint32_t v)
-{
- int r = 32;
- if (v >= 0x10000)
- {
- v >>= 16;
- r -= 16;
- }
- if (v & 0xff00)
- {
- v >>= 8;
- r -= 8;
- }
- if (v & 0xf0)
- {
- v >>= 4;
- r -= 4;
- }
- if (v & 0xc)
- {
- v >>= 2;
- r -= 2;
- }
- if (v & 2)
- {
- v >>= 1;
- r -= 1;
- }
- r -= v;
- return r;
-}
-#else
-static const char clz_lut[16] = { 4, 3, 2, 2, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0 };
-/* This clz is based on the log2(n) implementation at
- * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
- * It is not any faster than the one above, but trades 16B in the lookup table
- * for a savings of 12B per each inlined call.
- */
-static inline int clz(uint32_t v)
-{
- int r = 28;
- if (v >= 0x10000)
- {
- v >>= 16;
- r -= 16;
- }
- if (v & 0xff00)
- {
- v >>= 8;
- r -= 8;
- }
- if (v & 0xf0)
- {
- v >>= 4;
- r -= 4;
- }
- return r + clz_lut[v];
-}
-#endif
-
-/* Return the maximum possible left shift for a signed int32, without
- * overflow
- */
-static inline int allowed_shift(int32_t val)
-{
- uint32_t uval = val ^ (val >> 31);
- return clz(uval) - 1;
-}
-
-/* Calculate num/den, with the result shifted left by PFREAL_SHIFT, by shifting
- * num and den before dividing.
- */
-static inline PFreal fdiv(PFreal num, PFreal den)
-{
- int shift = allowed_shift(num);
- shift = MIN(PFREAL_SHIFT, shift);
- num <<= shift;
- den >>= PFREAL_SHIFT - shift;
- return num / den;
-}
-
-#define fmin(a,b) (((a) < (b)) ? (a) : (b))
-#define fmax(a,b) (((a) > (b)) ? (a) : (b))
-#define fabs(a) (a < 0 ? -a : a)
-#define fbound(min,val,max) (fmax((min),fmin((max),(val))))
-
-#if CONFIG_CPU == SH7034
-/* 16*16->32 bit multiplication is a single instrcution on the SH1 */
-#define MULUQ(a, b) ((uint32_t) (((uint16_t) (a)) * ((uint16_t) (b))))
-#else
-#define MULUQ(a, b) ((a) * (b))
-#endif
-
-
-#if 0
-#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;
-}
-#endif
-
-/* warning: regenerate the table if IANGLE_MAX and PFREAL_SHIFT are changed! */
-static const short sin_tab[] = {
- 0, 100, 200, 297, 392, 483, 569, 650,
- 724, 792, 851, 903, 946, 980, 1004, 1019,
- 1024, 1019, 1004, 980, 946, 903, 851, 792,
- 724, 650, 569, 483, 392, 297, 200, 100,
- 0, -100, -200, -297, -392, -483, -569, -650,
- -724, -792, -851, -903, -946, -980, -1004, -1019,
- -1024, -1019, -1004, -980, -946, -903, -851, -792,
- -724, -650, -569, -483, -392, -297, -200, -100,
- 0
-};
-
-static inline PFreal fsin(int iangle)
-{
- iangle &= IANGLE_MASK;
-
- int i = (iangle >> 4);
- PFreal p = sin_tab[i];
- PFreal q = sin_tab[(i+1)];
- PFreal g = (q - p);
- return p + g * (iangle-i*16)/16;
-}
-
-static inline PFreal fcos(int iangle)
-{
- return fsin(iangle + (IANGLE_MAX >> 2));
-}
-
-static inline uint32_t div255(uint32_t val)
-{
- return ((((val >> 8) + val) >> 8) + val) >> 8;
-}
-
-#define SCALE_VAL(val,out) div255((val) * (out) + 127)
-
-static void output_row_transposed(uint32_t row, void * row_in,
- struct scaler_context *ctx)
-{
- pix_t *dest = (pix_t*)ctx->bm->data + row;
- pix_t *end = dest + ctx->bm->height * ctx->bm->width;
-#ifdef USEGSLIB
- uint32_t *qp = (uint32_t*)row_in;
- for (; dest < end; dest += ctx->bm->height)
- *dest = SC_MUL((*qp++) + ctx->round, ctx->divisor);
-#else
- struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
- uint32_t rb_mul = SCALE_VAL(ctx->divisor, 31),
- rb_rnd = SCALE_VAL(ctx->round, 31),
- g_mul = SCALE_VAL(ctx->divisor, 63),
- g_rnd = SCALE_VAL(ctx->round, 63);
- int r, g, b;
- for (; dest < end; dest += ctx->bm->height)
- {
- r = SC_MUL(qp->r + rb_rnd, rb_mul);
- g = SC_MUL(qp->g + g_rnd, g_mul);
- b = SC_MUL(qp->b + rb_rnd, rb_mul);
- qp++;
- *dest = LCD_RGBPACK_LCD(r,g,b);
- }
-#endif
-}
-
-#ifdef HAVE_LCD_COLOR
-static void output_row_transposed_fromyuv(uint32_t row, void * row_in,
- struct scaler_context *ctx)
-{
- pix_t *dest = (pix_t*)ctx->bm->data + row;
- pix_t *end = dest + ctx->bm->height * ctx->bm->width;
- struct uint32_rgb *qp = (struct uint32_rgb*)row_in;
- for (; dest < end; dest += ctx->bm->height)
- {
- unsigned r, g, b, y, u, v;
- y = SC_MUL(qp->b + ctx->round, ctx->divisor);
- u = SC_MUL(qp->g + ctx->round, ctx->divisor);
- v = SC_MUL(qp->r + ctx->round, ctx->divisor);
- qp++;
- yuv_to_rgb(y, u, v, &r, &g, &b);
- r = (31 * r + (r >> 3) + 127) >> 8;
- g = (63 * g + (g >> 2) + 127) >> 8;
- b = (31 * b + (b >> 3) + 127) >> 8;
- *dest = LCD_RGBPACK_LCD(r, g, b);
- }
-}
-#endif
-
-static unsigned int get_size(struct bitmap *bm)
-{
- return bm->width * bm->height * sizeof(pix_t);
-}
-
-const struct custom_format format_transposed = {
-#ifdef HAVE_LCD_COLOR
- .output_row = {
- output_row_transposed,
- output_row_transposed_fromyuv
- },
-#else
- .output_row = output_row_transposed,
-#endif
- .get_size = get_size
-};
-
-static const struct button_mapping* get_context_map(int context)
-{
- return pf_contexts[context & ~CONTEXT_CUSTOM];
-}
-
-/* Create the lookup table with the scaling values for the reflections */
-void init_reflect_table(void)
-{
- int i;
- for (i = 0; i < REFLECT_HEIGHT; i++)
- reflect_table[i] =
- (768 * (REFLECT_HEIGHT - i) + (5 * REFLECT_HEIGHT / 2)) /
- (5 * REFLECT_HEIGHT);
-}
-
-/**
- Create an index of all albums from the database.
- Also store the album names so we can access them later.
- */
-int create_album_index(void)
-{
- buf_size -= UNIQBUF_SIZE * sizeof(long);
- long *uniqbuf = (long *)(buf_size + (char *)buf);
- album = ((struct album_data *)uniqbuf) - 1;
- rb->memset(&tcs, 0, sizeof(struct tagcache_search) );
- album_count = 0;
- rb->tagcache_search(&tcs, tag_album);
- rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, UNIQBUF_SIZE);
- unsigned int l, old_l = 0;
- album_names = buf;
- album[0].name_idx = 0;
- while (rb->tagcache_get_next(&tcs))
- {
- buf_size -= sizeof(struct album_data);
- l = rb->strlen(tcs.result) + 1;
- if ( album_count > 0 )
- album[-album_count].name_idx = album[1-album_count].name_idx + old_l;
-
- if ( l > buf_size )
- /* not enough memory */
- return ERROR_BUFFER_FULL;
-
- rb->strcpy(buf, tcs.result);
- buf_size -= l;
- buf = l + (char *)buf;
- album[-album_count].seek = tcs.result_seek;
- old_l = l;
- album_count++;
- }
- rb->tagcache_search_finish(&tcs);
- ALIGN_BUFFER(buf, buf_size, 4);
- int i;
- struct album_data* tmp_album = (struct album_data*)buf;
- for (i = album_count - 1; i >= 0; i--)
- tmp_album[i] = album[-i];
- album = tmp_album;
- buf = album + album_count;
- buf_size += UNIQBUF_SIZE * sizeof(long);
- return (album_count > 0) ? 0 : ERROR_NO_ALBUMS;
-}
-
-/**
- Return a pointer to the album name of the given slide_index
- */
-char* get_album_name(const int slide_index)
-{
- return album_names + album[slide_index].name_idx;
-}
-
-/**
- Return a pointer to the track name of the active album
- create_track_index has to be called first.
- */
-char* get_track_name(const int track_index)
-{
- if ( track_index < track_count )
- return track_names + tracks[track_index].name_idx;
- return 0;
-}
-
-/**
- Create the track index of the given slide_index.
- */
-int create_track_index(const int slide_index)
-{
- if ( slide_index == track_index ) {
- return -1;
- }
-
- if (!rb->tagcache_search(&tcs, tag_title))
- return -1;
-
- int ret = 0;
- char temp_titles[MAX_TRACKS][AVG_TRACK_NAME_LENGTH*4];
- int temp_seeks[MAX_TRACKS];
-
- rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek);
- track_count=0;
- int string_index = 0;
- int l, track_num, heighest_index = 0;
-
- for(l=0;l<MAX_TRACKS;l++)
- temp_titles[l][0] = '\0';
- while (rb->tagcache_get_next(&tcs) && track_count < MAX_TRACKS)
- {
- track_num = rb->tagcache_get_numeric(&tcs, tag_tracknumber) - 1;
- if (track_num >= 0)
- {
- rb->snprintf(temp_titles[track_num],sizeof(temp_titles[track_num]),
- "%d: %s", track_num+1, tcs.result);
- temp_seeks[track_num] = tcs.result_seek;
- }
- else
- {
- track_num = 0;
- while (temp_titles[track_num][0] != '\0')
- track_num++;
- rb->strcpy(temp_titles[track_num], tcs.result);
- temp_seeks[track_num] = tcs.result_seek;
- }
- if (track_num > heighest_index)
- heighest_index = track_num;
- track_count++;
- }
-
- rb->tagcache_search_finish(&tcs);
- track_index = slide_index;
-
- /* now fix the track list order */
- l = 0;
- track_count = 0;
- while (l <= heighest_index &&
- string_index < MAX_TRACKS*AVG_TRACK_NAME_LENGTH)
- {
- if (temp_titles[l][0] != '\0')
- {
- rb->strcpy(track_names + string_index, temp_titles[l]);
- tracks[track_count].name_idx = string_index;
- tracks[track_count].seek = temp_seeks[l];
- string_index += rb->strlen(temp_titles[l]) + 1;
- track_count++;
- }
- l++;
- }
- if (ret != 0)
- return ret;
- else
- return (track_count > 0) ? 0 : -1;
-}
-
-/**
- Determine filename of the album art for the given slide_index and
- store the result in buf.
- The algorithm looks for the first track of the given album uses
- find_albumart to find the filename.
- */
-bool get_albumart_for_index_from_db(const int slide_index, char *buf,
- int buflen)
-{
- if ( slide_index == -1 )
- {
- rb->strncpy( buf, EMPTY_SLIDE, buflen );
- }
-
- if (!rb->tagcache_search(&tcs, tag_filename))
- return false;
-
- bool result;
- /* find the first track of the album */
- rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek);
-
- if ( rb->tagcache_get_next(&tcs) ) {
- struct mp3entry id3;
- int fd;
-
- fd = rb->open(tcs.result, O_RDONLY);
- rb->get_metadata(&id3, fd, tcs.result);
- rb->close(fd);
- if ( search_albumart_files(&id3, "", buf, buflen) )
- result = true;
- else
- result = false;
- }
- else {
- /* did not find a matching track */
- result = false;
- }
- rb->tagcache_search_finish(&tcs);
- return result;
-}
-
-/**
- Draw the PictureFlow logo
- */
-void draw_splashscreen(void)
-{
- struct screen* display = rb->screens[0];
- const struct picture* logo = &(logos[display->screen_type]);
-
-#if LCD_DEPTH > 1
- rb->lcd_set_background(N_BRIGHT(0));
- rb->lcd_set_foreground(N_BRIGHT(255));
-#else
- rb->lcd_set_drawmode(PICTUREFLOW_DRMODE);
-#endif
- rb->lcd_clear_display();
-
-#if LCD_DEPTH == 1 /* Mono LCDs need the logo inverted */
- rb->lcd_set_drawmode(PICTUREFLOW_DRMODE ^ DRMODE_INVERSEVID);
- picture_draw(display, logo, (LCD_WIDTH - logo->width) / 2, 10);
- rb->lcd_set_drawmode(PICTUREFLOW_DRMODE);
-#else
- picture_draw(display, logo, (LCD_WIDTH - logo->width) / 2, 10);
-#endif
-
- rb->lcd_update();
-}
-
-
-/**
- Draw a simple progress bar
- */
-void draw_progressbar(int step)
-{
- int txt_w, txt_h;
- const int bar_height = 22;
- const int w = LCD_WIDTH - 20;
- const int x = 10;
-
- rb->lcd_getstringsize("Preparing album artwork", &txt_w, &txt_h);
-
- int y = (LCD_HEIGHT - txt_h)/2;
-
- rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, "Preparing album artwork");
- y += (txt_h + 5);
-
-#if LCD_DEPTH > 1
- rb->lcd_set_foreground(N_BRIGHT(100));
-#endif
- rb->lcd_drawrect(x, y, w+2, bar_height);
-#if LCD_DEPTH > 1
- rb->lcd_set_foreground(N_PIX(165, 231, 82));
-#endif
-
- rb->lcd_fillrect(x+1, y+1, step * w / album_count, bar_height-2);
-#if LCD_DEPTH > 1
- rb->lcd_set_foreground(N_BRIGHT(255));
-#endif
- rb->lcd_update();
- rb->yield();
-}
-
-/**
- Precomupte the album art images and store them in CACHE_PREFIX.
- */
-bool create_albumart_cache(void)
-{
- int ret;
-
- int i, slides = 0;
- struct bitmap input_bmp;
-
- char pfraw_file[MAX_PATH];
- char albumart_file[MAX_PATH];
- unsigned int format = FORMAT_NATIVE;
- cache_version = 0;
- configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
- if (resize)
- format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT;
- for (i=0; i < album_count; i++)
- {
- rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%d.pfraw",
- i);
- /* delete existing cache, so it's a true rebuild */
- if(rb->file_exists(pfraw_file))
- rb->remove(pfraw_file);
- draw_progressbar(i);
- if (!get_albumart_for_index_from_db(i, albumart_file, MAX_PATH))
- continue;
-
- input_bmp.data = buf;
- input_bmp.width = DISPLAY_WIDTH;
- input_bmp.height = DISPLAY_HEIGHT;
-#if PLUGIN_BUFFER_SIZE > 0x10000
- ret = read_image_file(albumart_file, &input_bmp,
- buf_size, format, &format_transposed);
-#else
- ret = scaled_read_bmp_file(albumart_file, &input_bmp,
- buf_size, format, &format_transposed);
-#endif
- if (ret <= 0) {
- rb->splash(HZ, "Could not read bmp");
- continue; /* skip missing/broken files */
- }
- if (!save_pfraw(pfraw_file, &input_bmp))
- {
- rb->splash(HZ, "Could not write bmp");
- }
- slides++;
- if ( rb->button_get(false) == PF_MENU ) return false;
- }
- if ( slides == 0 ) {
- /* Warn the user that we couldn't find any albumart */
- rb->splash(2*HZ, "No album art found");
- return false;
- }
- return true;
-}
-
-/**
- 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;
- }
- while ( load_new_slide() ) {
- rb->yield();
- switch (ev.id) {
- case EV_EXIT:
- return;
- }
- }
- }
-}
-
-
-/**
- End the thread by posting the EV_EXIT event
- */
-void end_pf_thread(void)
-{
- if ( thread_is_running ) {
- 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);
- thread_is_running = false;
- }
-
-}
-
-
-/**
- Create the thread an setup the event queue
- */
-bool create_pf_thread(void)
-{
- /* put the thread's queue in the bcast list */
- rb->queue_init(&thread_q, true);
- if ((thread_id = rb->create_thread(
- thread,
- thread_stack,
- sizeof(thread_stack),
- 0,
- "Picture load thread"
- IF_PRIO(, MAX(PRIORITY_USER_INTERFACE / 2,
- PRIORITY_REALTIME + 1))
- IF_COP(, CPU)
- )
- ) == 0) {
- return false;
- }
- thread_is_running = true;
- rb->queue_post(&thread_q, EV_WAKEUP, 0);
- return true;
-}
-
-/**
- Safe the given bitmap as filename in the pfraw format
- */
-bool save_pfraw(char* filename, struct bitmap *bm)
-{
- struct pfraw_header bmph;
- bmph.width = bm->width;
- bmph.height = bm->height;
- int fh = rb->creat( filename );
- if( fh < 0 ) return false;
- rb->write( fh, &bmph, sizeof( struct pfraw_header ) );
- int y;
- for( y = 0; y < bm->height; y++ )
- {
- pix_t *d = (pix_t*)( bm->data ) + (y*bm->width);
- rb->write( fh, d, sizeof( pix_t ) * bm->width );
- }
- rb->close( fh );
- return true;
-}
-
-
-/*
- * The following functions implement the linked-list-in-array used to manage
- * the LRU cache of slides, and the list of free cache slots.
- */
-
-#define seek_right_while(start, cond) \
-({ \
- int ind_, next_ = (start); \
- do { \
- ind_ = next_; \
- next_ = cache[ind_].next; \
- } while (next_ != cache_used && (cond)); \
- ind_; \
-})
-
-#define seek_left_while(start, cond) \
-({ \
- int ind_, next_ = (start); \
- do { \
- ind_ = next_; \
- next_ = cache[ind_].prev; \
- } while (ind_ != cache_used && (cond)); \
- ind_; \
-})
-
-/**
- Pop the given item from the linked list starting at *head, returning the next
- item, or -1 if the list is now empty.
-*/
-static inline int lla_pop_item (int *head, int i)
-{
- int prev = cache[i].prev;
- int next = cache[i].next;
- if (i == next)
- {
- *head = -1;
- return -1;
- }
- else if (i == *head)
- *head = next;
- cache[next].prev = prev;
- cache[prev].next = next;
- return next;
-}
-
-
-/**
- Pop the head item from the list starting at *head, returning the index of the
- item, or -1 if the list is already empty.
-*/
-static inline int lla_pop_head (int *head)
-{
- int i = *head;
- if (i != -1)
- lla_pop_item(head, i);
- return i;
-}
-
-/**
- Insert the item at index i before the one at index p.
-*/
-static inline void lla_insert (int i, int p)
-{
- int next = p;
- int prev = cache[next].prev;
- cache[next].prev = i;
- cache[prev].next = i;
- cache[i].next = next;
- cache[i].prev = prev;
-}
-
-
-/**
- Insert the item at index i at the end of the list starting at *head.
-*/
-static inline void lla_insert_tail (int *head, int i)
-{
- if (*head == -1)
- {
- *head = i;
- cache[i].next = i;
- cache[i].prev = i;
- } else
- lla_insert(i, *head);
-}
-
-/**
- Insert the item at index i before the one at index p.
-*/
-static inline void lla_insert_after(int i, int p)
-{
- p = cache[p].next;
- lla_insert(i, p);
-}
-
-
-/**
- Insert the item at index i before the one at index p in the list starting at
- *head
-*/
-static inline void lla_insert_before(int *head, int i, int p)
-{
- lla_insert(i, p);
- if (*head == p)
- *head = i;
-}
-
-
-/**
- Free the used slide at index i, and its buffer, and move it to the free
- slides list.
-*/
-static inline void free_slide(int i)
-{
- if (cache[i].hid != empty_slide_hid)
- buflib_free(&buf_ctx, cache[i].hid);
- cache[i].index = -1;
- lla_pop_item(&cache_used, i);
- lla_insert_tail(&cache_free, i);
- if (cache_used == -1)
- {
- cache_right_index = -1;
- cache_left_index = -1;
- cache_center_index = -1;
- }
-}
-
-
-/**
- Free one slide ranked above the given priority. If no such slide can be found,
- return false.
-*/
-static inline int free_slide_prio(int prio)
-{
- if (cache_used == -1)
- return false;
- int i, l = cache_used, r = cache[cache_used].prev, prio_max;
- int prio_l = cache[l].index < center_index ?
- center_index - cache[l].index : 0;
- int prio_r = cache[r].index > center_index ?
- cache[r].index - center_index : 0;
- if (prio_l > prio_r)
- {
- i = l;
- prio_max = prio_l;
- } else {
- i = r;
- prio_max = prio_r;
- }
- if (prio_max > prio)
- {
- if (i == cache_left_index)
- cache_left_index = cache[i].next;
- if (i == cache_right_index)
- cache_right_index = cache[i].prev;
- free_slide(i);
- return true;
- } else
- return false;
-}
-
-/**
- Read the pfraw image given as filename and return the hid of the buffer
- */
-int read_pfraw(char* filename, int prio)
-{
- struct pfraw_header bmph;
- int fh = rb->open(filename, O_RDONLY);
- if( fh < 0 )
- return empty_slide_hid;
- else
- rb->read(fh, &bmph, sizeof(struct pfraw_header));
-
- int size = sizeof(struct bitmap) + sizeof( pix_t ) *
- bmph.width * bmph.height;
-
- int hid;
- while (!(hid = buflib_alloc(&buf_ctx, size)) && free_slide_prio(prio));
-
- if (!hid) {
- rb->close( fh );
- return 0;
- }
-
- struct dim *bm = buflib_get_data(&buf_ctx, hid);
-
- bm->width = bmph.width;
- bm->height = bmph.height;
- pix_t *data = (pix_t*)(sizeof(struct dim) + (char *)bm);
-
- int y;
- for( y = 0; y < bm->height; y++ )
- {
- rb->read( fh, data , sizeof( pix_t ) * bm->width );
- data += bm->width;
- }
- rb->close( fh );
- return hid;
-}
-
-
-/**
- Load the surface for the given slide_index into the cache at cache_index.
- */
-static inline bool load_and_prepare_surface(const int slide_index,
- const int cache_index,
- const int prio)
-{
- char tmp_path_name[MAX_PATH+1];
- rb->snprintf(tmp_path_name, sizeof(tmp_path_name), CACHE_PREFIX "/%d.pfraw",
- slide_index);
-
- int hid = read_pfraw(tmp_path_name, prio);
- if (!hid)
- return false;
-
- cache[cache_index].hid = hid;
-
- if ( cache_index < SLIDE_CACHE_SIZE ) {
- cache[cache_index].index = slide_index;
- }
-
- return true;
-}
-
-
-/**
- Load the "next" slide that we can load, freeing old slides if needed, provided
- that they are further from center_index than the current slide
-*/
-bool load_new_slide(void)
-{
- int i = -1;
- if (cache_center_index != -1)
- {
- int next, prev;
- if (cache[cache_center_index].index != center_index)
- {
- if (cache[cache_center_index].index < center_index)
- {
- cache_center_index = seek_right_while(cache_center_index,
- cache[next_].index <= center_index);
- prev = cache_center_index;
- next = cache[cache_center_index].next;
- }
- else
- {
- cache_center_index = seek_left_while(cache_center_index,
- cache[next_].index >= center_index);
- next = cache_center_index;
- prev = cache[cache_center_index].prev;
- }
- if (cache[cache_center_index].index != center_index)
- {
- if (cache_free == -1)
- free_slide_prio(0);
- i = lla_pop_head(&cache_free);
- if (!load_and_prepare_surface(center_index, i, 0))
- goto fail_and_refree;
- if (cache[next].index == -1)
- {
- if (cache[prev].index == -1)
- goto insert_first_slide;
- else
- next = cache[prev].next;
- }
- lla_insert(i, next);
- if (cache[i].index < cache[cache_used].index)
- cache_used = i;
- cache_center_index = i;
- cache_left_index = i;
- cache_right_index = i;
- return true;
- }
- }
- if (cache[cache_left_index].index >
- cache[cache_center_index].index)
- cache_left_index = cache_center_index;
- if (cache[cache_right_index].index <
- cache[cache_center_index].index)
- cache_right_index = cache_center_index;
- cache_left_index = seek_left_while(cache_left_index,
- cache[ind_].index - 1 == cache[next_].index);
- cache_right_index = seek_right_while(cache_right_index,
- cache[ind_].index - 1 == cache[next_].index);
- int prio_l = cache[cache_center_index].index -
- cache[cache_left_index].index + 1;
- int prio_r = cache[cache_right_index].index -
- cache[cache_center_index].index + 1;
- if ((prio_l < prio_r ||
- cache[cache_right_index].index >= number_of_slides) &&
- cache[cache_left_index].index > 0)
- {
- if (cache_free == -1 && !free_slide_prio(prio_l))
- return false;
- i = lla_pop_head(&cache_free);
- if (load_and_prepare_surface(cache[cache_left_index].index
- - 1, i, prio_l))
- {
- lla_insert_before(&cache_used, i, cache_left_index);
- cache_left_index = i;
- return true;
- }
- } else if(cache[cache_right_index].index < number_of_slides - 1)
- {
- if (cache_free == -1 && !free_slide_prio(prio_r))
- return false;
- i = lla_pop_head(&cache_free);
- if (load_and_prepare_surface(cache[cache_right_index].index
- + 1, i, prio_r))
- {
- lla_insert_after(i, cache_right_index);
- cache_right_index = i;
- return true;
- }
- }
- } else {
- i = lla_pop_head(&cache_free);
- if (load_and_prepare_surface(center_index, i, 0))
- {
-insert_first_slide:
- cache[i].next = i;
- cache[i].prev = i;
- cache_center_index = i;
- cache_left_index = i;
- cache_right_index = i;
- cache_used = i;
- return true;
- }
- }
-fail_and_refree:
- if (i != -1)
- {
- lla_insert_tail(&cache_free, i);
- }
- return false;
-}
-
-
-/**
- Get a slide from the buffer
- */
-static inline struct dim *get_slide(const int hid)
-{
- if (!hid)
- return NULL;
-
- struct dim *bmp;
-
- bmp = buflib_get_data(&buf_ctx, hid);
-
- return bmp;
-}
-
-
-/**
- Return the requested surface
-*/
-static inline struct dim *surface(const int slide_index)
-{
- if (slide_index < 0)
- return 0;
- if (slide_index >= number_of_slides)
- return 0;
- int i;
- if ((i = cache_used ) != -1)
- {
- do {
- if (cache[i].index == slide_index)
- return get_slide(cache[i].hid);
- i = cache[i].next;
- } while (i != cache_used);
- }
- return get_slide(empty_slide_hid);
-}
-
-/**
- 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.distance = 0;
- center_slide.slide_index = center_index;
-
- int i;
- for (i = 0; i < num_slides; i++) {
- struct slide_data *si = &left_slides[i];
- si->angle = itilt;
- si->cx = -(offsetX + slide_spacing * i * PFREAL_ONE);
- si->cy = offsetY;
- si->slide_index = center_index - 1 - i;
- si->distance = 0;
- }
-
- for (i = 0; i < num_slides; i++) {
- struct slide_data *si = &right_slides[i];
- si->angle = -itilt;
- si->cx = offsetX + slide_spacing * i * PFREAL_ONE;
- si->cy = offsetY;
- si->slide_index = center_index + 1 + i;
- si->distance = 0;
- }
-}
-
-
-/**
- Updates look-up table and other stuff necessary for the rendering.
- Call this when the viewport size or slide dimension is changed.
- *
- * To calculate the offset that will provide the proper margin, we use the same
- * projection used to render the slides. The solution for xc, the slide center,
- * is:
- * xp * (zo + xs * sin(r))
- * xc = xp - xs * cos(r) + ───────────────────────
- * z
- * TODO: support moving the side slides toward or away from the camera
- */
-void recalc_offsets(void)
-{
- PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF;
- PFreal zo;
- PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + center_margin *
- PFREAL_ONE) * zoom / 100;
- PFreal cosr, sinr;
-
- itilt = 70 * IANGLE_MAX / 360; /* approx. 70 degrees tilted */
- cosr = fcos(-itilt);
- sinr = fsin(-itilt);
- zo = CAM_DIST_R * 100 / zoom - CAM_DIST_R +
- fmuln(MAXSLIDE_LEFT_R, sinr, PFREAL_SHIFT - 2, 0);
- offsetX = xp - fmul(xs, cosr) + fmuln(xp,
- zo + fmuln(xs, sinr, PFREAL_SHIFT - 2, 0), PFREAL_SHIFT - 2, 0)
- / CAM_DIST;
- offsetY = DISPLAY_WIDTH / 2 * (fsin(itilt) + PFREAL_ONE / 2);
-}
-
-
-/**
- Fade the given color by spreading the fb_data (ushort)
- to an uint, multiply and compress the result back to a ushort.
- */
-#if (LCD_PIXELFORMAT == RGB565SWAPPED)
-static inline unsigned fade_color(pix_t c, unsigned a)
-{
- unsigned int result;
- c = swap16(c);
- a = (a + 2) & 0x1fc;
- result = ((c & 0xf81f) * a) & 0xf81f00;
- result |= ((c & 0x7e0) * a) & 0x7e000;
- result >>= 8;
- return swap16(result);
-}
-#elif LCD_PIXELFORMAT == RGB565
-static inline unsigned fade_color(pix_t c, unsigned a)
-{
- unsigned int result;
- a = (a + 2) & 0x1fc;
- result = ((c & 0xf81f) * a) & 0xf81f00;
- result |= ((c & 0x7e0) * a) & 0x7e000;
- result >>= 8;
- return result;
-}
-#else
-static inline unsigned fade_color(pix_t c, unsigned a)
-{
- unsigned val = c;
- return MULUQ(val, a) >> 8;
-}
-#endif
-
-/**
- * Render a single slide
- * Where xc is the slide's horizontal offset from center, xs is the horizontal
- * on the slide from its center, zo is the slide's depth offset from the plane
- * of the display, r is the angle at which the slide is tilted, and xp is the
- * point on the display corresponding to xs on the slide, the projection
- * formulas are:
- *
- * z * (xc + xs * cos(r))
- * xp = ──────────────────────
- * z + zo + xs * sin(r)
- *
- * z * (xc - xp) - xp * zo
- * xs = ────────────────────────
- * xp * sin(r) - z * cos(r)
- *
- * We use the xp projection once, to find the left edge of the slide on the
- * display. From there, we use the xs reverse projection to find the horizontal
- * offset from the slide center of each column on the screen, until we reach
- * the right edge of the slide, or the screen. The reverse projection can be
- * optimized by saving the numerator and denominator of the fraction, which can
- * then be incremented by (z + zo) and sin(r) respectively.
- */
-void render_slide(struct slide_data *slide, const int alpha)
-{
- struct dim *bmp = surface(slide->slide_index);
- if (!bmp) {
- return;
- }
- if (slide->angle > 255 || slide->angle < -255)
- return;
- pix_t *src = (pix_t*)(sizeof(struct dim) + (char *)bmp);
-
- const int sw = bmp->width;
- const int sh = bmp->height;
- const PFreal slide_left = -sw * PFREAL_HALF + PFREAL_HALF;
- const int w = LCD_WIDTH;
-
- uint8_t reftab[REFLECT_HEIGHT]; /* on stack, which is in IRAM on several targets */
-
- if (alpha == 256) { /* opaque -> copy table */
- rb->memcpy(reftab, reflect_table, sizeof(reftab));
- } else { /* precalculate faded table */
- int i, lalpha;
- for (i = 0; i < REFLECT_HEIGHT; i++) {
- lalpha = reflect_table[i];
- reftab[i] = (MULUQ(lalpha, alpha) + 129) >> 8;
- }
- }
-
- PFreal cosr = fcos(slide->angle);
- PFreal sinr = fsin(slide->angle);
- PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / zoom
- - CAM_DIST_R - fmuln(MAXSLIDE_LEFT_R, fabs(sinr), PFREAL_SHIFT - 2, 0);
- PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni;
- PFreal xp = fdiv(CAM_DIST * (slide->cx + fmul(xs, cosr)),
- (CAM_DIST_R + zo + fmul(xs,sinr)));
-
- /* Since we're finding the screen position of the left edge of the slide,
- * we round up.
- */
- int xi = (fmax(DISPLAY_LEFT_R, xp) - DISPLAY_LEFT_R + PFREAL_ONE - 1)
- >> PFREAL_SHIFT;
- xp = DISPLAY_LEFT_R + xi * PFREAL_ONE;
- if (xi >= w) {
- return;
- }
- xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0);
- xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr;
- xs = fdiv(xsnum, xsden);
-
- xsnumi = -CAM_DIST_R - zo;
- xsdeni = sinr;
- int x;
- int dy = PFREAL_ONE;
- for (x = xi; x < w; x++) {
- int column = (xs - slide_left) / PFREAL_ONE;
- if (column >= sw)
- break;
- if (zo || slide->angle)
- dy = (CAM_DIST_R + zo + fmul(xs, sinr)) / CAM_DIST;
-
- const pix_t *ptr = &src[column * bmp->height];
- const int pixelstep = BUFFER_WIDTH;
-
- int p = (bmp->height-1-DISPLAY_OFFS) * PFREAL_ONE;
- int plim = MAX(0, p - (LCD_HEIGHT/2-1) * dy);
- pix_t *pixel = &buffer[((LCD_HEIGHT/2)-1)*BUFFER_WIDTH + x];
-
- if (alpha == 256) {
- while (p >= plim) {
- *pixel = ptr[((unsigned)p) >> PFREAL_SHIFT];
- p -= dy;
- pixel -= pixelstep;
- }
- } else {
- while (p >= plim) {
- *pixel = fade_color(ptr[((unsigned)p) >> PFREAL_SHIFT], alpha);
- p -= dy;
- pixel -= pixelstep;
- }
- }
- p = (bmp->height-DISPLAY_OFFS) * PFREAL_ONE;
- plim = MIN(sh * PFREAL_ONE, p + (LCD_HEIGHT/2) * dy);
- int plim2 = MIN(MIN(sh + REFLECT_HEIGHT, sh * 2) * PFREAL_ONE,
- p + (LCD_HEIGHT/2) * dy);
- pixel = &buffer[(LCD_HEIGHT/2)*BUFFER_WIDTH + x];
-
- if (alpha == 256) {
- while (p < plim) {
- *pixel = ptr[((unsigned)p) >> PFREAL_SHIFT];
- p += dy;
- pixel += pixelstep;
- }
- } else {
- while (p < plim) {
- *pixel = fade_color(ptr[((unsigned)p) >> PFREAL_SHIFT], alpha);
- p += dy;
- pixel += pixelstep;
- }
- }
- while (p < plim2) {
- int ty = (((unsigned)p) >> PFREAL_SHIFT) - sh;
- int lalpha = reftab[ty];
- *pixel = fade_color(ptr[sh - 1 - ty], lalpha);
- p += dy;
- pixel += pixelstep;
- }
-
- if (zo || slide->angle)
- {
- xsnum += xsnumi;
- xsden += xsdeni;
- xs = fdiv(xsnum, xsden);
- } else
- xs += PFREAL_ONE;
-
- }
- /* let the music play... */
- rb->yield();
- return;
-}
-
-
-/**
- Jump the the given slide_index
- */
-static inline void set_current_slide(const int slide_index)
-{
- int old_center_index = center_index;
- step = 0;
- center_index = fbound(slide_index, 0, number_of_slides - 1);
- if (old_center_index != center_index)
- rb->queue_post(&thread_q, EV_WAKEUP, 0);
- target = center_index;
- slide_frame = slide_index << 16;
- reset_slides();
-}
-
-/**
- Start the animation for changing slides
- */
-void start_animation(void)
-{
- step = (target < center_slide.slide_index) ? -1 : 1;
- pf_state = pf_scrolling;
-}
-
-/**
- Go to the previous slide
- */
-void show_previous_slide(void)
-{
- if (step == 0) {
- if (center_index > 0) {
- target = center_index - 1;
- start_animation();
- }
- } else if ( step > 0 ) {
- target = center_index;
- start_animation();
- } else {
- target = fmax(0, center_index - 2);
- }
-}
-
-
-/**
- Go to the next slide
- */
-void show_next_slide(void)
-{
- if (step == 0) {
- if (center_index < number_of_slides - 1) {
- target = center_index + 1;
- start_animation();
- }
- } else if ( step < 0 ) {
- target = center_index;
- start_animation();
- } else {
- target = fmin(center_index + 2, number_of_slides - 1);
- }
-}
-
-
-/**
- Render the slides. Updates only the offscreen buffer.
-*/
-void render_all_slides(void)
-{
- MYLCD(set_background)(G_BRIGHT(0));
- /* TODO: Optimizes this by e.g. invalidating rects */
- MYLCD(clear_display)();
-
- int nleft = num_slides;
- int nright = num_slides;
-
- int index;
- if (step == 0) {
- /* no animation, boring plain rendering */
- for (index = nleft - 2; index >= 0; index--) {
- int alpha = (index < nleft - 2) ? 256 : 128;
- alpha -= extra_fade;
- if (alpha > 0 )
- render_slide(&left_slides[index], alpha);
- }
- for (index = nright - 2; index >= 0; index--) {
- int alpha = (index < nright - 2) ? 256 : 128;
- alpha -= extra_fade;
- if (alpha > 0 )
- render_slide(&right_slides[index], alpha);
- }
- } else {
- /* the first and last slide must fade in/fade out */
- for (index = nleft - 1; index >= 0; 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], alpha);
- }
- for (index = nright - 1; index >= 0; 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], alpha);
- }
- }
- render_slide(&center_slide, 256);
-}
-
-
-/**
- Updates the animation effect. Call this periodically from a timer.
-*/
-void update_scroll_animation(void)
-{
- 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;
- rb->queue_post(&thread_q, EV_WAKEUP, 0);
- slide_frame = index << 16;
- center_slide.slide_index = center_index;
- for (i = 0; i < num_slides; i++)
- left_slides[i].slide_index = center_index - 1 - i;
- for (i = 0; i < num_slides; 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();
- pf_state = pf_idle;
- step = 0;
- fade = 256;
- return;
- }
-
- for (i = 0; i < num_slides; i++) {
- struct slide_data *si = &left_slides[i];
- si->angle = itilt;
- si->cx =
- -(offsetX + slide_spacing * i * PFREAL_ONE + step
- * slide_spacing * ftick);
- si->cy = offsetY;
- }
-
- for (i = 0; i < num_slides; i++) {
- struct slide_data *si = &right_slides[i];
- si->angle = -itilt;
- si->cx =
- offsetX + slide_spacing * i * PFREAL_ONE - step
- * slide_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;
- /* Turn on backlight timeout (revert to settings) */
- backlight_use_settings(); /* backlight control in lib/helper.c */
-
-#ifdef USEGSLIB
- grey_release();
-#endif
-}
-
-/**
- Create the "?" slide, that is shown while loading
- or when no cover was found.
- */
-int create_empty_slide(bool force)
-{
- if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) {
- struct bitmap input_bmp;
- int ret;
- input_bmp.width = DISPLAY_WIDTH;
- input_bmp.height = DISPLAY_HEIGHT;
-#if LCD_DEPTH > 1
- input_bmp.format = FORMAT_NATIVE;
-#endif
- input_bmp.data = (char*)buf;
- ret = scaled_read_bmp_file(EMPTY_SLIDE_BMP, &input_bmp,
- buf_size,
- FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT,
- &format_transposed);
- if (!save_pfraw(EMPTY_SLIDE, &input_bmp))
- return false;
- }
-
- return true;
-}
-
-/**
- Shows the album name setting menu
-*/
-int album_name_menu(void)
-{
- int selection = show_album_name;
-
- MENUITEM_STRINGLIST(album_name_menu,"Show album title",NULL,
- "Hide album title", "Show at the bottom", "Show at the top");
- rb->do_menu(&album_name_menu, &selection, NULL, false);
-
- show_album_name = selection;
- return GO_TO_PREVIOUS;
-}
-
-/**
- Shows the settings menu
- */
-int settings_menu(void)
-{
- int selection = 0;
- bool old_val;
-
- MENUITEM_STRINGLIST(settings_menu, "PictureFlow Settings", NULL, "Show FPS",
- "Spacing", "Centre margin", "Number of slides", "Zoom",
- "Show album title", "Resize Covers", "Rebuild cache");
-
- do {
- selection=rb->do_menu(&settings_menu,&selection, NULL, false);
- switch(selection) {
- case 0:
- rb->set_bool("Show FPS", &show_fps);
- reset_track_list();
- break;
-
- case 1:
- rb->set_int("Spacing between slides", "", 1,
- &slide_spacing,
- NULL, 1, 0, 100, NULL );
- recalc_offsets();
- reset_slides();
- break;
-
- case 2:
- rb->set_int("Centre margin", "", 1,
- &center_margin,
- NULL, 1, 0, 80, NULL );
- recalc_offsets();
- reset_slides();
- break;
-
- case 3:
- rb->set_int("Number of slides", "", 1, &num_slides,
- NULL, 1, 1, MAX_SLIDES_COUNT, NULL );
- recalc_offsets();
- reset_slides();
- break;
-
- case 4:
- rb->set_int("Zoom", "", 1, &zoom,
- NULL, 1, 10, 300, NULL );
- recalc_offsets();
- reset_slides();
- break;
- case 5:
- album_name_menu();
- reset_track_list();
- recalc_offsets();
- reset_slides();
- break;
- case 6:
- old_val = resize;
- rb->set_bool("Resize Covers", &resize);
- if (old_val == resize) /* changed? */
- break;
- /* fallthrough if changed, since cache needs to be rebuilt */
- case 7:
- cache_version = 0;
- rb->remove(EMPTY_SLIDE);
- rb->splash(HZ, "Cache will be rebuilt on next restart");
- break;
-
- case MENU_ATTACHED_USB:
- return PLUGIN_USB_CONNECTED;
- }
- } while ( selection >= 0 );
- configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
- return 0;
-}
-
-/**
- Show the main menu
- */
-int main_menu(void)
-{
- int selection = 0;
- int result;
-
-#if LCD_DEPTH > 1
- rb->lcd_set_foreground(N_BRIGHT(255));
-#endif
-
- MENUITEM_STRINGLIST(main_menu,"PictureFlow Main Menu",NULL,
- "Settings", "Return", "Quit");
- while (1) {
- switch (rb->do_menu(&main_menu,&selection, NULL, false)) {
- case 0:
- result = settings_menu();
- if ( result != 0 ) return result;
- break;
-
- case 1:
- return 0;
-
- case 2:
- return -1;
-
- case MENU_ATTACHED_USB:
- return PLUGIN_USB_CONNECTED;
-
- default:
- return 0;
- }
- }
-}
-
-/**
- Animation step for zooming into the current cover
- */
-void update_cover_in_animation(void)
-{
- cover_animation_keyframe++;
- if( cover_animation_keyframe < 20 ) {
- center_slide.distance-=5;
- center_slide.angle+=1;
- extra_fade += 13;
- }
- else if( cover_animation_keyframe < 35 ) {
- center_slide.angle+=16;
- }
- else {
- cover_animation_keyframe = 0;
- pf_state = pf_show_tracks;
- }
-}
-
-/**
- Animation step for zooming out the current cover
- */
-void update_cover_out_animation(void)
-{
- cover_animation_keyframe++;
- if( cover_animation_keyframe <= 15 ) {
- center_slide.angle-=16;
- }
- else if( cover_animation_keyframe < 35 ) {
- center_slide.distance+=5;
- center_slide.angle-=1;
- extra_fade -= 13;
- }
- else {
- cover_animation_keyframe = 0;
- pf_state = pf_idle;
- }
-}
-
-/**
- Draw a blue gradient at y with height h
- */
-static inline void draw_gradient(int y, int h)
-{
- static int r, inc, c;
- inc = (100 << 8) / h;
- c = 0;
- selected_track_pulse = (selected_track_pulse+1) % 10;
- int c2 = selected_track_pulse - 5;
- for (r=0; r<h; r++) {
-#ifdef HAVE_LCD_COLOR
- MYLCD(set_foreground)(G_PIX(c2+80-(c >> 9), c2+100-(c >> 9),
- c2+250-(c >> 8)));
-#else
- MYLCD(set_foreground)(G_BRIGHT(c2+160-(c >> 8)));
-#endif
- MYLCD(hline)(0, LCD_WIDTH, r+y);
- if ( r > h/2 )
- c-=inc;
- else
- c+=inc;
- }
-}
-
-
-static void track_list_yh(int char_height)
-{
- switch (show_album_name)
- {
- case album_name_hide:
- track_list_y = (show_fps ? char_height : 0);
- track_list_h = LCD_HEIGHT - track_list_y;
- break;
- case album_name_bottom:
- track_list_y = (show_fps ? char_height : 0);
- track_list_h = LCD_HEIGHT - track_list_y - char_height * 2;
- break;
- default: /* case album_name_top */
- track_list_y = char_height * 2;
- track_list_h = LCD_HEIGHT - track_list_y -
- (show_fps ? char_height : 0);
- break;
- }
-}
-
-/**
- Reset the track list after a album change
- */
-void reset_track_list(void)
-{
- int albumtxt_h = rb->screens[SCREEN_MAIN]->getcharheight();
- track_list_yh(albumtxt_h);
- track_list_visible_entries = fmin( track_list_h/albumtxt_h , track_count );
- start_index_track_list = 0;
- track_scroll_index = 0;
- track_scroll_dir = 1;
- selected_track = 0;
-
- /* let the tracklist start more centered
- * if the screen isn't filled with tracks */
- if (track_count*albumtxt_h < track_list_h)
- {
- track_list_h = track_count * albumtxt_h;
- track_list_y = LCD_HEIGHT / 2 - (track_list_h / 2);
- }
-}
-
-/**
- Display the list of tracks
- */
-void show_track_list(void)
-{
- MYLCD(clear_display)();
- if ( center_slide.slide_index != track_index ) {
- create_track_index(center_slide.slide_index);
- reset_track_list();
- }
- static int titletxt_w, titletxt_x, color, titletxt_h;
- titletxt_h = rb->screens[SCREEN_MAIN]->getcharheight();
-
- int titletxt_y = track_list_y;
- int track_i;
- track_i = start_index_track_list;
- for (;track_i < track_list_visible_entries+start_index_track_list;
- track_i++)
- {
- MYLCD(getstringsize)(get_track_name(track_i), &titletxt_w, NULL);
- titletxt_x = (LCD_WIDTH-titletxt_w)/2;
- if ( track_i == selected_track ) {
- draw_gradient(titletxt_y, titletxt_h);
- MYLCD(set_foreground)(G_BRIGHT(255));
- if (titletxt_w > LCD_WIDTH ) {
- if ( titletxt_w + track_scroll_index <= LCD_WIDTH )
- track_scroll_dir = 1;
- else if ( track_scroll_index >= 0 ) track_scroll_dir = -1;
- track_scroll_index += track_scroll_dir*2;
- titletxt_x = track_scroll_index;
- }
- MYLCD(putsxy)(titletxt_x,titletxt_y,get_track_name(track_i));
- }
- else {
- color = 250 - (abs(selected_track - track_i) * 200 / track_count);
- MYLCD(set_foreground)(G_BRIGHT(color));
- MYLCD(putsxy)(titletxt_x,titletxt_y,get_track_name(track_i));
- }
- titletxt_y += titletxt_h;
- }
-}
-
-void select_next_track(void)
-{
- if ( selected_track < track_count - 1 ) {
- selected_track++;
- track_scroll_index = 0;
- track_scroll_dir = 1;
- if (selected_track==(track_list_visible_entries+start_index_track_list))
- start_index_track_list++;
- }
-}
-
-void select_prev_track(void)
-{
- if (selected_track > 0 ) {
- if (selected_track==start_index_track_list) start_index_track_list--;
- track_scroll_index = 0;
- track_scroll_dir = 1;
- selected_track--;
- }
-}
-
-/**
- Draw the current album name
- */
-void draw_album_text(void)
-{
- if (0 == show_album_name)
- return;
-
- int albumtxt_w, albumtxt_h;
- int albumtxt_y = 0;
-
- char *albumtxt;
- int c;
- /* Draw album text */
- if ( pf_state == pf_scrolling ) {
- c = ((slide_frame & 0xffff )/ 255);
- if (step < 0) c = 255-c;
- if (c > 128 ) { /* half way to next slide .. still not perfect! */
- albumtxt = get_album_name(center_index+step);
- c = (c-128)*2;
- }
- else {
- albumtxt = get_album_name(center_index);
- c = (128-c)*2;
- }
- }
- else {
- c= 255;
- albumtxt = get_album_name(center_index);
- }
-
- MYLCD(set_foreground)(G_BRIGHT(c));
- MYLCD(getstringsize)(albumtxt, &albumtxt_w, &albumtxt_h);
- if (center_index != prev_center_index) {
- albumtxt_x = 0;
- albumtxt_dir = -1;
- prev_center_index = center_index;
- }
-
- if (show_album_name == album_name_top)
- albumtxt_y = albumtxt_h / 2;
- else
- albumtxt_y = LCD_HEIGHT - albumtxt_h - albumtxt_h/2;
-
- if (albumtxt_w > LCD_WIDTH ) {
- MYLCD(putsxy)(albumtxt_x, albumtxt_y , albumtxt);
- if ( pf_state == pf_idle || pf_state == pf_show_tracks ) {
- if ( albumtxt_w + albumtxt_x <= LCD_WIDTH ) albumtxt_dir = 1;
- else if ( albumtxt_x >= 0 ) albumtxt_dir = -1;
- albumtxt_x += albumtxt_dir;
- }
- }
- else {
- MYLCD(putsxy)((LCD_WIDTH - albumtxt_w) /2, albumtxt_y , albumtxt);
- }
-
-
-}
-
-
-/**
- Main function that also contain the main plasma
- algorithm.
- */
-int main(void)
-{
- int ret;
-
- rb->lcd_setfont(FONT_UI);
- draw_splashscreen();
-
- if ( ! rb->dir_exists( CACHE_PREFIX ) ) {
- if ( rb->mkdir( CACHE_PREFIX ) < 0 ) {
- rb->splash(HZ, "Could not create directory " CACHE_PREFIX );
- return PLUGIN_ERROR;
- }
- }
-
- configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
-
- init_reflect_table();
-
- ALIGN_BUFFER(buf, buf_size, 4);
- ret = create_album_index();
- if (ret == ERROR_BUFFER_FULL) {
- rb->splash(HZ, "Not enough memory for album names");
- return PLUGIN_ERROR;
- } else if (ret == ERROR_NO_ALBUMS) {
- rb->splash(HZ, "No albums found. Please enable database");
- return PLUGIN_ERROR;
- }
-
- ALIGN_BUFFER(buf, buf_size, 4);
- number_of_slides = album_count;
- if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) {
- rb->splash(HZ, "Could not create album art cache");
- return PLUGIN_ERROR;
- }
-
- if (!create_empty_slide(cache_version != CACHE_VERSION)) {
- rb->splash(HZ, "Could not load the empty slide");
- return PLUGIN_ERROR;
- }
- cache_version = CACHE_VERSION;
- configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
-
-
-#ifdef USEGSLIB
- long grey_buf_used;
- if (!grey_init(buf, buf_size, GREY_BUFFERED|GREY_ON_COP,
- LCD_WIDTH, LCD_HEIGHT, &grey_buf_used))
- {
- rb->splash(HZ, "Greylib init failed!");
- return PLUGIN_ERROR;
- }
- grey_setfont(FONT_UI);
- buf_size -= grey_buf_used;
- buf = (void*)(grey_buf_used + (char*)buf);
-#endif
- buflib_init(&buf_ctx, (void *)buf, buf_size);
-
- if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0)))
- {
- rb->splash(HZ, "Unable to load empty slide image");
- return PLUGIN_ERROR;
- }
-
- if (!create_pf_thread()) {
- rb->splash(HZ, "Cannot create thread!");
- return PLUGIN_ERROR;
- }
-
- int i;
-
- /* initialize */
- for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
- cache[i].hid = 0;
- cache[i].index = 0;
- cache[i].next = i + 1;
- cache[i].prev = i - 1;
- }
- cache[0].prev = i - 1;
- cache[i - 1].next = 0;
- cache_free = 0;
- buffer = LCD_BUF;
-
- pf_state = pf_idle;
-
- track_index = -1;
- extra_fade = 0;
- slide_frame = 0;
- step = 0;
- target = 0;
- fade = 256;
-
- recalc_offsets();
- reset_slides();
-
- char fpstxt[10];
- int button;
-
- int frames = 0;
- long last_update = *rb->current_tick;
- long current_update;
- long update_interval = 100;
- int fps = 0;
- int fpstxt_y;
-
- bool instant_update;
-#ifdef USEGSLIB
- grey_show(true);
- grey_set_drawmode(DRMODE_FG);
-#endif
- rb->lcd_set_drawmode(DRMODE_FG);
- while (true) {
- current_update = *rb->current_tick;
- frames++;
-
- /* Initial rendering */
- instant_update = false;
-
- /* Handle states */
- switch ( pf_state ) {
- case pf_scrolling:
- update_scroll_animation();
- render_all_slides();
- instant_update = true;
- break;
- case pf_cover_in:
- update_cover_in_animation();
- render_all_slides();
- instant_update = true;
- break;
- case pf_cover_out:
- update_cover_out_animation();
- render_all_slides();
- instant_update = true;
- break;
- case pf_show_tracks:
- show_track_list();
- break;
- case pf_idle:
- render_all_slides();
- break;
- }
-
- /* Calculate FPS */
- if (current_update - last_update > update_interval) {
- fps = frames * HZ / (current_update - last_update);
- last_update = current_update;
- frames = 0;
- }
- /* Draw FPS */
- if (show_fps)
- {
-#ifdef USEGSLIB
- MYLCD(set_foreground)(G_BRIGHT(255));
-#else
- MYLCD(set_foreground)(G_PIX(255,0,0));
-#endif
- rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
- if (show_album_name == album_name_top)
- fpstxt_y = LCD_HEIGHT -
- rb->screens[SCREEN_MAIN]->getcharheight();
- else
- fpstxt_y = 0;
- MYLCD(putsxy)(0, fpstxt_y, fpstxt);
- }
- draw_album_text();
-
-
- /* Copy offscreen buffer to LCD and give time to other threads */
- MYLCD(update)();
- rb->yield();
-
- /*/ Handle buttons */
- button = rb->get_custom_action(CONTEXT_CUSTOM|
- (pf_state == pf_show_tracks ? 1 : 0),
- instant_update ? 0 : HZ/16,
- get_context_map);
-
- switch (button) {
- case PF_QUIT:
- return PLUGIN_OK;
-
- case PF_BACK:
- if ( pf_state == pf_show_tracks )
- pf_state = pf_cover_out;
- if (pf_state == pf_idle || pf_state == pf_scrolling)
- return PLUGIN_OK;
- break;
-
- case PF_MENU:
-#ifdef USEGSLIB
- grey_show(false);
-#endif
- ret = main_menu();
- if ( ret == -1 ) return PLUGIN_OK;
- if ( ret != 0 ) return i;
-#ifdef USEGSLIB
- grey_show(true);
-#endif
- MYLCD(set_drawmode)(DRMODE_FG);
- break;
-
- case PF_NEXT:
- case PF_NEXT_REPEAT:
- if ( pf_state == pf_show_tracks )
- select_next_track();
- if ( pf_state == pf_idle || pf_state == pf_scrolling )
- show_next_slide();
- break;
-
- case PF_PREV:
- case PF_PREV_REPEAT:
- if ( pf_state == pf_show_tracks )
- select_prev_track();
- if ( pf_state == pf_idle || pf_state == pf_scrolling )
- show_previous_slide();
- break;
-
- case PF_SELECT:
- if ( pf_state == pf_idle ) {
- pf_state = pf_cover_in;
- }
- break;
-
- default:
- if (rb->default_event_handler_ex(button, cleanup, NULL)
- == SYS_USB_CONNECTED)
- return PLUGIN_USB_CONNECTED;
- break;
- }
- }
-
-
-}
-
-/*************************** Plugin entry point ****************************/
-
-enum plugin_status plugin_start(const void *parameter)
-{
- int ret;
- (void) parameter;
-#if LCD_DEPTH > 1
- rb->lcd_set_backdrop(NULL);
-#endif
- /* Turn off backlight timeout */
- backlight_force_on(); /* backlight control in lib/helper.c */
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(true);
-#endif
-#if PLUGIN_BUFFER_SIZE > 0x10000
- buf = rb->plugin_get_buffer(&buf_size);
-#else
- buf = rb->plugin_get_audio_buffer(&buf_size);
-#endif
- ret = main();
-#ifdef HAVE_ADJUSTABLE_CPU_FREQ
- rb->cpu_boost(false);
-#endif
- if ( ret == PLUGIN_OK ) {
- if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS,
- CONFIG_VERSION))
- {
- rb->splash(HZ, "Error writing config.");
- ret = PLUGIN_ERROR;
- }
- }
-
- end_pf_thread();
- cleanup(NULL);
- return ret;
-}