rockbox/apps/plugins/plasma.c
Thomas Martitz a1842c04f9 lcd-24bit: Introduce a 24-bit mid-level LCD driver
With LCD driver all calculation will be performed on RGB888 and the hardware/OS
can display from our 24bit framebuffer.

It is not yet as performance optimized as the existing drivers but should be
good enough.The vast number of small changes is due to the fact that
fb_data can be a struct type now, while most of the code expected a scalar type.

lcd-as-memframe ASM code does not work with 24bit currently so the with 24bit
it enforces the generic C code.

All plugins are ported over. Except for rockpaint. It uses so much memory that
it wouldnt fit into the 512k plugin buffer anymore (patches welcome).

Change-Id: Ibb1964545028ce0d8ff9833ccc3ab66be3ee0754
2014-06-21 00:15:53 +02:00

327 lines
8.5 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Plasma demo plugin
*
* My crack at making a 80's style retro plasma effect for the fantastic
* rockbox!
* Okay, I could've hard-coded the sine wave values, I just wanted the
* challange of calculating them! silly: maybe, fun: yes!
*
* 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 "fixedpoint.h"
#include "lib/helper.h"
#include "lib/pluginlib_actions.h"
#include "lib/pluginlib_exit.h"
#ifndef HAVE_LCD_COLOR
#include "lib/grey.h"
#endif
/******************************* Globals ***********************************/
static unsigned char wave_array[256]; /* Pre calculated wave array */
#ifdef HAVE_LCD_COLOR
static fb_data colours[256]; /* Smooth transition of shades */
static int redfactor = 1, greenfactor = 2, bluefactor = 3;
static int redphase = 0, greenphase = 50, bluephase = 100;
/* lower chance of gray at regular intervals */
#else
GREY_INFO_STRUCT
static unsigned char colours[256]; /* Smooth transition of shades */
static unsigned char greybuffer[LCD_HEIGHT*LCD_WIDTH]; /* off screen buffer */
static unsigned char *gbuf;
static size_t gbuf_size = 0;
#endif
static unsigned char sp1, sp2, sp3, sp4; /* Speed of plasma */
static int plasma_frequency;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
static bool boosted = false;
#endif
static const struct button_mapping* plugin_contexts[]= {
pla_main_ctx,
#if defined(HAVE_REMOTE_LCD)
pla_remote_ctx,
#endif
};
#define WAV_AMP 90
/*
* Main wave function so we don't have to re-calc the sine
* curve every time. Mess around WAV_AMP and FREQ to make slighlty
* weirder looking plasmas!
*/
static void wave_table_generate(void)
{
int i;
for (i=0;i<256;++i)
{
wave_array[i] = (unsigned char)((WAV_AMP
* (fp14_sin((i * 360 * plasma_frequency) / 256))) / 16384);
}
}
#ifdef HAVE_LCD_COLOR
/* Make a smooth colour cycle. */
static void shades_generate(int time)
{
int i;
unsigned red, green, blue;
unsigned r = time * redfactor + redphase;
unsigned g = time * greenfactor + greenphase;
unsigned b = time * bluefactor + bluephase;
for(i=0; i < 256; ++i)
{
r &= 0xFF; g &= 0xFF; b &= 0xFF;
red = 2 * r;
if (red > 255)
red = 510 - red;
green = 2 * g;
if (green > 255)
green = 510 - green;
blue = 2 * b;
if (blue > 255)
blue= 510 - blue;
colours[i] = FB_RGBPACK(red, green, blue);
r++; g++; b++;
}
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_pal256_update_pal(colours);
#endif
}
#else
/* Make a smooth shade from black into white and back into black again. */
static void shades_generate(void)
{
int i, y;
for(i=0; i < 256; ++i)
{
y = 2 * i;
if (y > 255)
y = 510 - y;
colours[i] = y;
}
}
#endif
static void cleanup(void)
{
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
if (boosted)
rb->cpu_boost(false);
#endif
#ifndef HAVE_LCD_COLOR
grey_release();
#endif
/* Turn on backlight timeout (revert to settings) */
backlight_use_settings();
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_set_mode(LCD_MODE_RGB565);
#endif
}
/*
* Main function that also contain the main plasma
* algorithm.
*/
int main(void)
{
plasma_frequency = 1;
int action, x, y;
unsigned char p1,p2,p3,p4,t1,t2,t3,t4, z,z0;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
long last_tick = *rb->current_tick;
int delay;
int cumulated_lag = 0;
#endif
#ifdef HAVE_LCD_COLOR
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
unsigned char *ptr;
#else
fb_data *ptr;
#endif
int time=0;
#else
unsigned char *ptr;
#endif
/*Generate the neccesary pre calced stuff*/
wave_table_generate();
#ifndef HAVE_LCD_COLOR
shades_generate(); /* statically */
/* get the remainder of the plugin buffer */
gbuf = (unsigned char *) rb->plugin_get_buffer(&gbuf_size);
if (!grey_init(gbuf, gbuf_size, GREY_ON_COP, LCD_WIDTH, LCD_HEIGHT, NULL))
{
rb->splash(HZ, "Couldn't init greyscale display");
return PLUGIN_ERROR;
}
/* switch on greyscale overlay */
grey_show(true);
#endif
atexit(cleanup);
sp1 = 4;
sp2 = 2;
sp3 = 4;
sp4 = 2;
p1=p2=p3=p4=0;
while (true)
{
#ifdef HAVE_LCD_COLOR
shades_generate(time++); /* dynamically */
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
ptr = (unsigned char*)rb->lcd_framebuffer;
#else
ptr = rb->lcd_framebuffer;
#endif
#else
ptr = greybuffer;
#endif
t1=p1;
t2=p2;
for(y = 0; y < LCD_HEIGHT; ++y)
{
t3=p3;
t4=p4;
z0 = wave_array[t1] + wave_array[t2];
for(x = 0; x < LCD_WIDTH; ++x)
{
z = z0 + wave_array[t3] + wave_array[t4];
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
*ptr++ = z;
#else
*ptr++ = colours[z];
#endif
t3+=1;
t4+=2;
}
t1+=2;
t2+=1;
rb->yield();
}
p1+=sp1;
p2-=sp2;
p3+=sp3;
p4-=sp4;
#ifdef HAVE_LCD_COLOR
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_blit_pal256( (unsigned char*)rb->lcd_framebuffer,
0,0,0,0,LCD_WIDTH,LCD_HEIGHT);
#else
rb->lcd_update();
#endif
#else
grey_ub_gray_bitmap(greybuffer, 0, 0, LCD_WIDTH, LCD_HEIGHT);
#endif
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
delay = last_tick - *rb->current_tick + HZ/33;
if (!boosted && delay < 0)
{
cumulated_lag -= delay; /* proportional increase */
if (cumulated_lag >= HZ)
rb->cpu_boost(boosted = true);
}
else if (boosted && delay > 1) /* account for jitter */
{
if (--cumulated_lag <= 0) /* slow decrease */
rb->cpu_boost(boosted = false);
}
last_tick = *rb->current_tick;
#endif
action = pluginlib_getaction(0, plugin_contexts,
ARRAYLEN(plugin_contexts));
switch(action)
{
case PLA_EXIT:
case PLA_CANCEL:
return PLUGIN_OK;
break;
#ifdef HAVE_SCROLLWHEEL
case PLA_SCROLL_FWD:
case PLA_SCROLL_FWD_REPEAT:
#endif
case PLA_UP:
case PLA_UP_REPEAT:
++plasma_frequency;
wave_table_generate();
break;
#ifdef HAVE_SCROLLWHEEL
case PLA_SCROLL_BACK:
case PLA_SCROLL_BACK_REPEAT:
#endif
case PLA_DOWN:
case PLA_DOWN_REPEAT:
if(plasma_frequency>1)
{
--plasma_frequency;
wave_table_generate();
}
break;
#ifdef HAVE_LCD_COLOR
case PLA_SELECT:
redfactor=rb->rand()%4;
greenfactor=rb->rand()%4;
bluefactor=rb->rand()%4;
redphase=rb->rand()%256;
greenphase=rb->rand()%256;
bluephase=rb->rand()%256;
break;
#endif
default:
exit_on_usb(action);
break;
}
}
}
/*************************** Plugin entry point ****************************/
enum plugin_status plugin_start(const void* parameter)
{
(void)parameter;
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
/* Turn off backlight timeout */
backlight_ignore_timeout();
#if defined(HAVE_LCD_MODES) && (HAVE_LCD_MODES & LCD_MODE_PAL256)
rb->lcd_set_mode(LCD_MODE_PAL256);
#endif
return main();
}