rockbox/apps/plugins/fractals/fractal.c
Thomas Martitz abdc5935be Introduce plugin_crt0.c that every plugin links.
It handles exit() properly, calling the handler also when the plugin returns
normally (also it makes exit() more standard compliant while at it).
It also holds PLUGIN_HEADER, so that it doesn't need to be in each plugin anymore.

To work better together with callbacks passed to rb->default_event_handler_ex introduce exit_on_usb() which will call the exit handler before showing the usb screen and exit() after it.
In most cases it was passed a callback which was manually called at all other return points. This can now be done via atexit().

In future plugin_crt0.c could also handle clearing bss, initializing iram and more.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27862 a1c6a512-1295-4272-9138-f99709370657
2010-08-23 16:56:49 +00:00

258 lines
6.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2004 Matthias Wientapper
* Heavily extended 2005 Jens Arnold
* Extended 2009 Tomer Shalev
*
*
* 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"
#ifdef HAVE_LCD_BITMAP
#include "fractal.h"
#include "fractal_rect.h"
#include "fractal_sets.h"
#include "mandelbrot_set.h"
#include "lib/pluginlib_exit.h"
#ifdef USEGSLIB
GREY_INFO_STRUCT
static unsigned char *gbuf;
static size_t gbuf_size = 0;
#endif
#define REDRAW_NONE 0
#define REDRAW_PARTIAL 1
#define REDRAW_FULL 2
#define REDRAW_FULL_OVERLAY 3
/* returns 1 if a button has been pressed, 0 otherwise */
static int button_yield(void *ctx)
{
long *button = (long *)ctx;
*button = rb->button_get(false);
switch (*button)
{
case FRACTAL_QUIT:
case FRACTAL_UP:
case FRACTAL_DOWN:
case FRACTAL_LEFT:
case FRACTAL_RIGHT:
case FRACTAL_ZOOM_IN:
case FRACTAL_ZOOM_OUT:
case FRACTAL_PRECISION_INC:
case FRACTAL_PRECISION_DEC:
case FRACTAL_RESET:
#ifdef FRACTAL_ZOOM_IN2
case FRACTAL_ZOOM_IN2:
#endif
#ifdef FRACTAL_ZOOM_IN_PRE
case FRACTAL_ZOOM_IN_PRE:
#endif
#if defined(FRACTAL_ZOOM_OUT_PRE) && \
(FRACTAL_ZOOM_OUT_PRE != FRACTAL_ZOOM_IN_PRE)
case FRACTAL_ZOOM_OUT_PRE:
#endif
#ifdef FRACTAL_PRECISION_INC_PRE
case FRACTAL_PRECISION_INC_PRE:
#endif
#if defined(FRACTAL_PRECISION_DEC_PRE) && \
(FRACTAL_PRECISION_DEC_PRE != FRACTAL_PRECISION_INC_PRE)
case FRACTAL_PRECISION_DEC_PRE:
#endif
return 1;
default:
*button = BUTTON_NONE;
return 0;
}
}
static void cleanup(void)
{
#ifdef USEGSLIB
grey_release();
#endif
}
enum plugin_status plugin_start(const void* parameter)
{
long lastbutton = BUTTON_NONE;
int redraw = REDRAW_FULL;
struct fractal_ops *ops = &mandelbrot_ops;
(void)parameter;
#ifdef USEGSLIB
/* get the remainder of the plugin buffer */
gbuf = (unsigned char *)rb->plugin_get_buffer(&gbuf_size);
/* initialize the greyscale buffer.*/
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;
}
grey_show(true); /* switch on greyscale overlay */
#endif
/* release greylib on exit */
atexit(cleanup);
#if LCD_DEPTH > 1
rb->lcd_set_backdrop(NULL);
#endif
ops->init();
/* main loop */
while (true)
{
long button = BUTTON_NONE;
if (redraw != REDRAW_NONE)
{
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
switch (redraw)
{
case REDRAW_FULL:
mylcd_ub_clear_display();
mylcd_ub_update();
/* fall-through */
case REDRAW_FULL_OVERLAY:
rects_queue_init();
break;
default:
break;
}
/* paint all rects */
rects_calc_all(ops->calc, button_yield, (void *)&button);
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
/* not interrupted by button press - screen is fully drawn */
redraw = (button == BUTTON_NONE) ? REDRAW_NONE : REDRAW_PARTIAL;
}
if (button == BUTTON_NONE)
button = rb->button_get(true);
switch (button)
{
#ifdef FRACTAL_RC_QUIT
case FRACTAL_RC_QUIT:
#endif
case FRACTAL_QUIT:
return PLUGIN_OK;
case FRACTAL_ZOOM_OUT:
#ifdef FRACTAL_ZOOM_OUT_PRE
if (lastbutton != FRACTAL_ZOOM_OUT_PRE)
break;
#endif
if (!ops->zoom(-1))
redraw = REDRAW_FULL;
break;
case FRACTAL_ZOOM_IN:
#ifdef FRACTAL_ZOOM_IN_PRE
if (lastbutton != FRACTAL_ZOOM_IN_PRE)
break;
#endif
#ifdef FRACTAL_ZOOM_IN2
case FRACTAL_ZOOM_IN2:
#endif
if (!ops->zoom(1))
redraw = REDRAW_FULL;
break;
case FRACTAL_UP:
ops->move(0, +1);
mylcd_ub_scroll_down(LCD_SHIFT_Y);
mylcd_ub_update();
if (redraw != REDRAW_FULL)
redraw = rects_move_down() ? REDRAW_FULL : REDRAW_PARTIAL;
break;
case FRACTAL_DOWN:
ops->move(0, -1);
mylcd_ub_scroll_up(LCD_SHIFT_Y);
mylcd_ub_update();
if (redraw != REDRAW_FULL)
redraw = rects_move_up() ? REDRAW_FULL : REDRAW_PARTIAL;
break;
case FRACTAL_LEFT:
ops->move(-1, 0);
mylcd_ub_scroll_right(LCD_SHIFT_X);
mylcd_ub_update();
if (redraw != REDRAW_FULL)
redraw = rects_move_right() ? REDRAW_FULL : REDRAW_PARTIAL;
break;
case FRACTAL_RIGHT:
ops->move(+1, 0);
mylcd_ub_scroll_left(LCD_SHIFT_X);
mylcd_ub_update();
if (redraw != REDRAW_FULL)
redraw = rects_move_left() ? REDRAW_FULL : REDRAW_PARTIAL;
break;
case FRACTAL_PRECISION_DEC:
#ifdef FRACTAL_PRECISION_DEC_PRE
if (lastbutton != FRACTAL_PRECISION_DEC_PRE)
break;
#endif
if (ops->precision(-1))
redraw = REDRAW_FULL_OVERLAY;
break;
case FRACTAL_PRECISION_INC:
#ifdef FRACTAL_PRECISION_INC_PRE
if (lastbutton != FRACTAL_PRECISION_INC_PRE)
break;
#endif
if (ops->precision(+1))
redraw = REDRAW_FULL_OVERLAY;
break;
case FRACTAL_RESET:
ops->init();
redraw = REDRAW_FULL;
break;
default:
exit_on_usb(button);
break;
}
if (button != BUTTON_NONE)
lastbutton = button;
}
return PLUGIN_OK;
}
#endif