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

573 lines
16 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* deluxe --- */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)deluxe.c 5.22 2006/03/07 xlockmore";
#endif
/* xscreensaver, Copyright (c) 1999, 2001, 2002 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* adapted for xlockmore : March 2006
*/
#ifdef STANDALONE
#define MODE_deluxe
#define PROGCLASS "Deluxe"
#define HACK_INIT init_deluxe
#define HACK_DRAW draw_deluxe
#define deluxe_opts xlockmore_opts
#define DEFAULTS "*delay: 10000 \n" \
"*size: 4 \n" \
"*ncolors: 8 \n" \
"*fullrandom: True \n" \
"*verbose: False \n" \
".background: black\n",
".foreground: white\n",
"*delay: 5000\n",
"*count: 5\n",
"*thickness: 50\n",
"*speed: 15\n",
"*ncolors: 20\n",
"*nlayers: 0\n",
"*transparent: False\n",
"*doubleBuffer: True\n",
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
"*useDBE: True\n",
"*useDBEClear: True\n",
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
0
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#include "color.h"
#endif /* STANDALONE */
#ifdef MODE_deluxe
#include <math.h>
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
# include "xdbe.h"
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
#define countof(x) (sizeof(x)/sizeof(*(x)))
#define DEF_THICKNESS "50"
#define DEF_SPEED "15"
#define DEF_TRANSPARENT "False"
#define DEF_DB "True"
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
#define DEF_USEDBECLEAR "True"
#endif
#define DEF_MONO "False"
#define DEF_PLANES "0"
static int st_thickness;
static int st_speed;
static Bool st_transparent;
static Bool st_db;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
static Bool st_dbeclear_p;
#endif
static Bool st_mono;
static int st_planes;
struct throbber {
int x, y;
int size;
int max_size;
int thickness;
int speed;
int fuse;
GC gc;
void (*draw) (Display *, Drawable, struct throbber *);
};
typedef struct {
Bool transparent_p;
int nplanes;
unsigned long base_pixel, *plane_masks;
int count;
int ncolors;
Bool dbuf;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
Bool dbeclear_p;
XdbeBackBuffer backb;
#endif
XColor *colors;
GC erase_gc;
struct throbber **throbbers;
XWindowAttributes xgwa;
Pixmap b, ba, bb; /* double-buffer to reduce flicker */
} deluxestruct;
static deluxestruct *deluxes = (deluxestruct *) NULL;
XrmOptionDescRec opts [] = {
{ "-thickness", "deluxe.thickness", XrmoptionSepArg, (caddr_t) NULL },
{ "-speed", "deluxe.speed", XrmoptionSepArg, (caddr_t) NULL },
{ "-planes", "deluxe.planes", XrmoptionSepArg, (caddr_t) NULL },
{ "-transparent", "deluxe.transparent", XrmoptionNoArg, (caddr_t) "on" },
{ "+transparent", "deluxe.transparent", XrmoptionNoArg, (caddr_t) "off" },
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
{ "-useDBEClear", "deluxe.useDBEClear", XrmoptionNoArg, (caddr_t) "on" },
{ "+useDBEClear", "deluxe.useDBEClear", XrmoptionNoArg, (caddr_t) "off" }
#endif
{ "-mono", "deluxe.mono", XrmoptionNoArg, (caddr_t) "on" },
{ "+mono", "deluxe.mono", XrmoptionNoArg, (caddr_t) "off" },
{ "-db", "deluxe.doubleBuffer", XrmoptionNoArg, (caddr_t) "on" },
{ "+db", "deluxe.doubleBuffer", XrmoptionNoArg, (caddr_t) "off" }
};
static argtype vars[] =
{
{(void *) & st_thickness, (char *) "thickness", (char *) "thickness",
(char *) DEF_THICKNESS, t_Int},
{(void *) & st_speed, (char *) "speed", (char *) "speed",
(char *) DEF_SPEED, t_Int},
{(void *) & st_planes, (char *) "planes", (char *) "Planes",
(char *) DEF_PLANES, t_Int},
{(void *) & st_transparent, (char *) "transparent",
(char *) "Transparent", (char *) DEF_TRANSPARENT, t_Bool},
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
{(void *) & st_dbeclear_p, (char *) "useDBEClear",
(char *) "useDBEClear",
(char *) DEF_USEDBECLEAR, t_Bool},
#endif
{(void *) & st_mono, (char *) "mono", (char *) "mono",
(char *) DEF_MONO, t_Bool},
{(void *) & st_db, (char *) "db", (char *) "db",
(char *) DEF_DB, t_Bool}
};
static OptionStruct desc[] =
{
{(char *) "-thickness num", (char *) "Figure thickness"},
{(char *) "-speed num", (char *) "Animation speed"},
{(char *) "-planes num", (char *) "Number of planes"},
{(char *) "-/+transparent", (char *) "turn on/off transparancy"},
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
{(char *) "-/+useDBEClear", (char *) "turn on/off useDBEClear"}
#endif
{(char *) "-/+mono", (char *) "turn on/off monochromatic mode"},
{(char *) "-/+db", (char *) "turn on/off double buffering"}
};
ModeSpecOpt deluxe_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct deluxe_description =
{"deluxe", "init_deluxe", "draw_deluxe", "release_deluxe",
"refresh_deluxe", "init_deluxe", (char *) NULL, &deluxe_opts,
5000, 5, 1, 1, 64, 1.0, "",
"Shows pulsing sequence of stars, circles, and lines.", 0, NULL};
#endif
static void
free_deluxe(Display *dpy, deluxestruct *dlp)
{
int i;
for (i = 0; i < dlp->count; i++)
if ( dlp->throbbers[i] )
{
if (dlp->throbbers[i]->gc != None)
XFreeGC (dpy, dlp->throbbers[i]->gc);
free( dlp->throbbers[i] );
}
if ( dlp->throbbers )
{
free( dlp->throbbers );
dlp->throbbers = ( struct throbber** ) NULL;
}
if ( dlp->colors )
{
free( dlp->colors );
dlp->colors = (XColor *) NULL;
}
if ( dlp->plane_masks )
{
free( dlp->plane_masks );
dlp->plane_masks = (unsigned long*) NULL;
}
if (dlp->erase_gc != None)
{
XFreeGC (dpy, dlp->erase_gc);
dlp->erase_gc = None;
}
}
static void
deluxe_draw_star (Display *dpy, Drawable w, struct throbber *t)
{
XPoint points[11];
int x = t->x;
int y = t->y;
int s = (int) (t->size / 0.383); /* trial and error, I forget how to derive this */
int s2 = t->size;
double c = M_PI * 2.0;
double o = -M_PI / 2.0;
points[0].x = (short) (x + s * cos(o + 0.0*c));
points[0].y = (short) (y + s * sin(o + 0.0*c));
points[1].x = (short) (x + s2 * cos(o + 0.1*c));
points[1].y = (short) (y + s2 * sin(o + 0.1*c));
points[2].x = (short) (x + s * cos(o + 0.2*c));
points[2].y = (short) (y + s * sin(o + 0.2*c));
points[3].x = (short) (x + s2 * cos(o + 0.3*c));
points[3].y = (short) (y + s2 * sin(o + 0.3*c));
points[4].x = (short) (x + s * cos(o + 0.4*c));
points[4].y = (short) (y + s * sin(o + 0.4*c));
points[5].x = (short) (x + s2 * cos(o + 0.5*c));
points[5].y = (short) (y + s2 * sin(o + 0.5*c));
points[6].x = (short) (x + s * cos(o + 0.6*c));
points[6].y = (short) (y + s * sin(o + 0.6*c));
points[7].x = (short) (x + s2 * cos(o + 0.7*c));
points[7].y = (short) (y + s2 * sin(o + 0.7*c));
points[8].x = (short) (x + s * cos(o + 0.8*c));
points[8].y = (short) (y + s * sin(o + 0.8*c));
points[9].x = (short) (x + s2 * cos(o + 0.9*c));
points[9].y = (short) (y + s2 * sin(o + 0.9*c));
points[10] = points[0];
XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
}
static void
draw_circle (Display *dpy, Drawable w, struct throbber *t)
{
XDrawArc (dpy, w, t->gc,
t->x - t->size / 2,
t->y - t->size / 2,
t->size, t->size,
0, 360*64);
}
static void
draw_hlines (Display *dpy, Drawable w, struct throbber *t)
{
XDrawLine (dpy, w, t->gc, 0,
t->y - t->size, t->max_size,
t->y - t->size);
XDrawLine (dpy, w, t->gc, 0,
t->y + t->size, t->max_size,
t->y + t->size);
}
static void
draw_vlines (Display *dpy, Drawable w, struct throbber *t)
{
XDrawLine (dpy, w, t->gc,
t->x - t->size, 0,
t->x - t->size, t->max_size);
XDrawLine (dpy, w, t->gc,
t->x + t->size, 0,
t->x + t->size, t->max_size);
}
static void
draw_corners (Display *dpy, Drawable w, struct throbber *t)
{
int s = (t->size + t->thickness) / 2;
XPoint points[3];
points[0].x = 0; points[0].y = t->y - s;
points[1].x = t->x - s; points[1].y = t->y - s;
points[2].x = t->x - s; points[2].y = 0;
XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
points[0].x = 0; points[0].y = t->y + s;
points[1].x = t->x - s; points[1].y = t->y + s;
points[2].x = t->x - s; points[2].y = t->max_size;
XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
points[0].x = t->x + s; points[0].y = 0;
points[1].x = t->x + s; points[1].y = t->y - s;
points[2].x = t->max_size; points[2].y = t->y - s;
XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
points[0].x = t->x + s; points[0].y = t->max_size;
points[1].x = t->x + s; points[1].y = t->y + s;
points[2].x = t->max_size; points[2].y = t->y + s;
XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
}
static struct throbber *
make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel ,
deluxestruct *dlp )
{
XGCValues gcv;
unsigned long flags;
struct throbber *t = (struct throbber *) malloc (sizeof (*t));
t->x = w / 2;
t->y = h / 2;
t->max_size = w;
t->speed = st_speed;
t->fuse = 1 + (NRAND(4));
t->thickness = st_thickness;
if (t->speed < 0) t->speed = -t->speed;
t->speed += (((NRAND(t->speed)) / 2) - (t->speed / 2));
if (t->speed > 0) t->speed = -t->speed;
if (NRAND(4))
t->size = t->max_size;
else
t->size = t->thickness, t->speed = -t->speed;
flags = GCForeground;
if (dlp->transparent_p)
{
gcv.foreground = (unsigned long) ~0L;
gcv.plane_mask = dlp->base_pixel |
dlp->plane_masks[NRAND(dlp->nplanes)];
flags |= GCPlaneMask;
}
else
{
gcv.foreground = pixel;
}
gcv.line_width = t->thickness;
gcv.line_style = LineSolid;
gcv.cap_style = CapProjecting;
gcv.join_style = JoinMiter;
flags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
t->gc = XCreateGC (dpy, d, flags, &gcv);
switch (NRAND(11)) {
case 0: case 1: case 2: case 3: t->draw = deluxe_draw_star; break;
case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
case 8: t->draw = draw_hlines; break;
case 9: t->draw = draw_vlines; break;
case 10: t->draw = draw_corners; break;
default: abort(); break;
}
return t;
}
static int
throb (Display *dpy, Drawable window, struct throbber *t)
{
t->size += t->speed;
if (t->size <= (t->thickness / 2))
{
t->speed = -t->speed;
t->size += (t->speed * 2);
}
else if (t->size > t->max_size)
{
t->speed = -t->speed;
t->size += (t->speed * 2);
t->fuse--;
}
if (t->fuse <= 0)
{
XFreeGC (dpy, t->gc);
memset (t, 0, sizeof(*t));
free (t);
return -1;
}
else
{
t->draw (dpy, window, t);
return 0;
}
}
void
init_deluxe(ModeInfo * mi)
{
deluxestruct *dlp;
Display *dpy = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
XGCValues gcv;
int i;
/* initialize */
if (deluxes == NULL) {
if ((deluxes = (deluxestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (deluxestruct))) == NULL)
return;
}
dlp = &deluxes[MI_SCREEN(mi)];
free_deluxe(dpy, dlp);
dlp->count = MI_COUNT(mi);
dlp->ncolors = MI_NCOLORS(mi);
dlp->dbuf = st_db;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
dlp->dbeclear_p = st_dbeclear_p;
#endif
dlp->colors = 0;
dlp->erase_gc = 0;
dlp->b=0;
dlp->ba=0;
dlp->bb=0; /* double-buffer to reduce flicker */
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
dlp->backb =0;
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
XGetWindowAttributes (dpy, window, &dlp->xgwa);
dlp->transparent_p = st_transparent;
dlp->colors = (XColor *) calloc (sizeof(XColor), dlp->ncolors);
if ( st_mono )
{
MONO:
dlp->ncolors = 1;
dlp->colors[0].pixel = MI_WHITE_PIXEL(mi);
}
else if (dlp->transparent_p)
{
dlp->nplanes = st_planes;
if (dlp->nplanes <= 0)
dlp->nplanes = NRAND(dlp->xgwa.depth-2) + 2;
allocate_alpha_colors (dlp->xgwa.screen, dlp->xgwa.visual, dlp->xgwa.colormap,
&dlp->nplanes, True, &dlp->plane_masks,
&dlp->base_pixel , mi );
if (dlp->nplanes <= 1)
{
fprintf (stderr,
"deluxe: couldn't allocate any color planes; turning transparency off.\n"
);
dlp->transparent_p = False;
goto COLOR;
}
}
else
{
Bool writeable = (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2);
COLOR:
make_random_colormap (mi , dlp->xgwa.colormap,
dlp->colors, &dlp->ncolors, True, True, &writeable
);
if (dlp->ncolors < 2)
goto MONO;
}
if (dlp->dbuf)
{
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (dlp->dbeclear_p)
dlp->b = xdbe_get_backbuffer (dpy, window, XdbeBackground);
else
dlp->b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
dlp->backb = dlp->b;
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (!dlp->b)
{
dlp->ba = XCreatePixmap (dpy, window, dlp->xgwa.width,
dlp->xgwa.height, dlp->xgwa.depth);
dlp->bb = XCreatePixmap (dpy, window, dlp->xgwa.width,
dlp->xgwa.height, dlp->xgwa.depth);
dlp->b = dlp->ba;
}
}
else
{
dlp->b = window;
}
dlp->throbbers = (struct throbber **) calloc ( dlp->count, sizeof(struct throbber *));
for (i = 0; i < dlp->count; i++)
dlp->throbbers[i] = make_throbber (dpy, dlp->b, dlp->xgwa.width,
dlp->xgwa.height,
dlp->colors[ NRAND( dlp->ncolors )].pixel ,
dlp );
gcv.foreground = MI_BLACK_PIXEL(mi);
dlp->erase_gc = XCreateGC (dpy, dlp->b, GCForeground, &gcv);
if ( dlp->ba) XFillRectangle (dpy, dlp->ba, dlp->erase_gc, 0, 0,
dlp->xgwa.width, dlp->xgwa.height);
if ( dlp->bb) XFillRectangle (dpy, dlp->bb, dlp->erase_gc, 0, 0,
dlp->xgwa.width, dlp->xgwa.height);
}
void draw_deluxe (ModeInfo * mi)
{
deluxestruct *dlp = &deluxes[MI_SCREEN(mi)];
Display *dpy = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
int i;
if (deluxes == NULL)
return;
MI_IS_DRAWN(mi) = True;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (!dlp->dbeclear_p || !dlp->backb )
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
XFillRectangle (dpy, dlp->b, dlp->erase_gc, 0, 0, dlp->xgwa.width,
dlp->xgwa.height);
for (i = 0; i < dlp->count; i++)
if (throb (dpy, dlp->b, dlp->throbbers[i]) < 0)
dlp->throbbers[i] = make_throbber (dpy, dlp->b, dlp->xgwa.width,
dlp->xgwa.height,
dlp->colors[ NRAND( dlp->ncolors )].pixel ,
dlp );
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (dlp->backb)
{
XdbeSwapInfo info[1];
info[0].swap_window = window;
info[0].swap_action = (dlp->dbeclear_p ? XdbeBackground : XdbeUndefined);
XdbeSwapBuffers (dpy, info, 1);
}
else
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (dlp->dbuf)
{
XCopyArea (dpy, dlp->b, window, dlp->erase_gc, 0, 0,
dlp->xgwa.width, dlp->xgwa.height, 0, 0);
dlp->b = (dlp->b == dlp->ba ? dlp->bb : dlp->ba);
}
XSync (dpy, False);
}
void
release_deluxe(ModeInfo * mi)
{
if (deluxes != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_deluxe(MI_DISPLAY(mi), &deluxes[screen]);
free(deluxes);
deluxes = (deluxestruct *) NULL;
}
}
void
refresh_deluxe(ModeInfo * mi)
{
if (deluxes == NULL)
return;
}
#endif /* MODE_deluxe */