xenocara/app/xlockmore/modes/bubble.c
2006-11-26 11:07:42 +00:00

313 lines
7.8 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* bubble --- simple exploding bubbles */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)bubble.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Copyright (c) 1998 by Charles Vidal <cvidal@ivsweb.com>
* http://www.chez.com/vidalc
* and David Bagley
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* Revision History:
* 01-Nov-2000: Allocation checks
* 10-Jan-1998: Written.
*/
#ifdef STANDALONE
#define MODE_bubble
#define PROGCLASS "Bubble"
#define HACK_INIT init_bubble
#define HACK_DRAW draw_bubble
#define bubble_opts xlockmore_opts
#define DEFAULTS "*delay: 100000 \n" \
"*count: 25 \n" \
"*size: 100 \n" \
"*ncolors: 200 \n" \
"*fullrandom: True \n"
#define UNIFORM_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#ifdef MODE_bubble
#define DEF_BOIL "False"
static Bool boil;
static XrmOptionDescRec opts[] =
{
{(char *) "-boil", (char *) ".bubble.boil", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+boil", (char *) ".bubble.boil", XrmoptionNoArg, (caddr_t) "off"}
};
static argtype vars[] =
{
{(void *) & boil, (char *) "boil", (char *) "Boil", (char *) DEF_BOIL, t_Bool}
};
static OptionStruct desc[] =
{
{(char *) "-/+boil", (char *) "turn on/off boil"}
};
ModeSpecOpt bubble_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct bubble_description =
{"bubble", "init_bubble", "draw_bubble", "release_bubble",
"refresh_bubble", "init_bubble", (char *) NULL, &bubble_opts,
100000, 25, 1, 100, 64, 0.6, "",
"Shows popping bubbles", 0, NULL};
#endif
typedef struct {
int x, y, life;
} bubbletype;
#define MINSIZE 20
#define MINBUBBLES 1
typedef struct {
int direction;
int color;
int width, height;
int nbubbles;
Bool boil;
bubbletype *bubble;
int d;
Pixmap dbuf;
GC dbuf_gc;
} bubblestruct;
static bubblestruct *bubbles = (bubblestruct *) NULL;
static void
updateBubble(ModeInfo * mi, int i)
{
bubblestruct *bp = &bubbles[MI_SCREEN(mi)];
int x, diameter, x4, y4, diameter4;
if (bp->bubble[i].life + 1 > bp->d - NRAND(16) ||
bp->bubble[i].y < 0) {
bp->bubble[i].life = 0;
return;
}
++bp->bubble[i].life;
diameter = bp->bubble[i].life;
x = bp->bubble[i].x;
if (bp->boil) {
bp->bubble[i].y -= diameter / 2;
x += (int) (cos((double) (diameter +
bp->bubble[i].x) / (M_PI / 5.0)) * (double) diameter);
}
/* SunOS 4.1.X xnews server may crash without this */
if (diameter < 4) {
XFillRectangle(MI_DISPLAY(mi), bp->dbuf, bp->dbuf_gc,
x - diameter / 2, bp->bubble[i].y - diameter / 2,
diameter, diameter);
} else {
XDrawArc(MI_DISPLAY(mi), bp->dbuf, bp->dbuf_gc,
x - diameter / 2, bp->bubble[i].y - diameter / 2,
diameter, diameter, 0, 23040);
}
diameter4 = diameter / 4;
if (diameter4 > 0) {
x4 = x - diameter4 / 2 +
((bp->direction / 2) ? (-1) : 1) * diameter / 6;
y4 = bp->bubble[i].y - diameter4 / 2 +
((bp->direction % 2) ? 1 : (-1)) * diameter / 6;
/* SunOS 4.1.X xnews server may crash without this */
if (diameter4 < 4) {
XFillRectangle(MI_DISPLAY(mi), bp->dbuf, bp->dbuf_gc,
x4, y4, diameter4, diameter4);
} else {
XFillArc(MI_DISPLAY(mi), bp->dbuf, bp->dbuf_gc,
x4, y4, diameter4, diameter4, 0, 23040);
}
}
}
static void
changeBubble(ModeInfo * mi)
{
bubblestruct *bp = &bubbles[MI_SCREEN(mi)];
int i;
for (i = 0; i < bp->nbubbles; i++) {
if (bp->bubble[i].life != 0)
updateBubble(mi, i);
}
i = NRAND(bp->nbubbles);
if (bp->bubble[i].life == 0) {
bp->bubble[i].x = NRAND(bp->width);
if (bp->boil)
bp->bubble[i].y = bp->height -
((bp->height >= 16) ? NRAND(bp->height / 16) : 0);
else
bp->bubble[i].y = NRAND(bp->height);
updateBubble(mi, i);
}
}
static void
free_bubble(Display *display, bubblestruct *bp)
{
if (bp->dbuf != None) {
XFreePixmap(display, bp->dbuf);
bp->dbuf = None;
}
if (bp->dbuf_gc != None) {
XFreeGC(display, bp->dbuf_gc);
bp->dbuf_gc = None;
}
if (bp->bubble != NULL) {
free(bp->bubble);
bp->bubble = (bubbletype *) NULL;
}
}
void
init_bubble(ModeInfo * mi)
{
bubblestruct *bp;
int size = MI_SIZE(mi);
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
XGCValues gcv;
if (bubbles == NULL) {
if ((bubbles = (bubblestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (bubblestruct))) == NULL)
return;
}
bp = &bubbles[MI_SCREEN(mi)];
bp->width = MI_WIDTH(mi);
bp->height = MI_HEIGHT(mi);
bp->direction = NRAND(4);
if (MI_IS_FULLRANDOM(mi))
bp->boil = (Bool) (LRAND() & 1);
else
bp->boil = boil;
if (size < -MINSIZE)
bp->d = NRAND(MIN(-size, MAX(MINSIZE,
MIN(bp->width, bp->height) / 2)) - MINSIZE + 1) + MINSIZE;
else if (size < MINSIZE) {
if (!size)
bp->d = MAX(MINSIZE, MIN(bp->width, bp->height) / 2);
else
bp->d = MINSIZE;
} else
bp->d = MIN(size, MAX(MINSIZE,
MIN(bp->width, bp->height) / 2));
bp->nbubbles = MI_COUNT(mi);
if (bp->nbubbles < -MINBUBBLES) {
bp->nbubbles = NRAND(-bp->nbubbles - MINBUBBLES + 1) + MINBUBBLES;
} else if (bp->nbubbles < MINBUBBLES)
bp->nbubbles = MINBUBBLES;
if (bp->bubble != NULL)
free(bp->bubble);
if ((bp->bubble = (bubbletype *) calloc(bp->nbubbles,
sizeof (bubbletype))) == NULL) {
free_bubble(display, bp);
return;
}
if (MI_NPIXELS(mi) > 2)
bp->color = NRAND(MI_NPIXELS(mi));
if (bp->dbuf != None)
XFreePixmap(display, bp->dbuf);
if ((bp->dbuf = XCreatePixmap(display, window, bp->width, bp->height,
1)) == None) {
free_bubble(display, bp);
return;
}
/* Do not want any exposure events from XCopyPlane */
XSetGraphicsExposures(display, MI_GC(mi), False);
gcv.foreground = 1;
gcv.background = 0;
gcv.function = GXcopy;
gcv.graphics_exposures = False;
gcv.line_width = 2;
if (bp->dbuf_gc)
XFreeGC(display, bp->dbuf_gc);
if ((bp->dbuf_gc = XCreateGC(display, bp->dbuf,
GCForeground | GCBackground | GCLineWidth | GCFunction,
&gcv)) == None) {
free_bubble(display, bp);
return;
}
MI_CLEARWINDOW(mi);
}
void
draw_bubble(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
bubblestruct *bp;
if (bubbles == NULL)
return;
bp = &bubbles[MI_SCREEN(mi)];
if (bp->bubble == NULL)
return;
MI_IS_DRAWN(mi) = True;
if (MI_NPIXELS(mi) <= 2)
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
else {
bp->color = (bp->color + 1) % MI_NPIXELS(mi);
XSetForeground(display, gc, MI_PIXEL(mi, bp->color));
}
if (bp->dbuf) {
XSetForeground(display, bp->dbuf_gc, 0);
XFillRectangle(display, bp->dbuf, bp->dbuf_gc,
0, 0, bp->width, bp->height);
XSetForeground(display, bp->dbuf_gc, 1);
changeBubble(mi);
XCopyPlane(display, bp->dbuf, window, gc,
0, 0, bp->width, bp->height, 0, 0, 1);
}
}
void
release_bubble(ModeInfo * mi)
{
if (bubbles != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_bubble(MI_DISPLAY(mi), &bubbles[screen]);
free(bubbles);
bubbles = (bubblestruct *) NULL;
}
}
void
refresh_bubble(ModeInfo * mi)
{
/* Do nothing, it will refresh by itself */
}
#endif /* MODE_bubble */