477 lines
13 KiB
C
477 lines
13 KiB
C
/* -*- Mode: C; tab-width: 4 -*- */
|
|
/* tube --- animated tube */
|
|
|
|
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)tube.c 5.09 2003/06/30 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* Copyright (c) 1997 Dan Stromberg <strombrg@nis.acs.uci.edu>
|
|
*
|
|
* 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:
|
|
* 30-Jun-2003: Changed writeable mode to be more consistent with
|
|
* xscreensaver's starfish
|
|
* 01-Nov-2000: Allocation checks
|
|
* 10-May-1997: Compatible with xscreensaver
|
|
* 04-Mar-1997: Memory leak fix by Tom Schmidt <tschmidt@micron.com>
|
|
* 07-Feb-1997: Written by Dan Stromberg <strombrg@nis.acs.uci.edu>
|
|
*/
|
|
|
|
|
|
#ifdef STANDALONE
|
|
#define MODE_tube
|
|
#define PROGCLASS "Tube"
|
|
#define HACK_INIT init_tube
|
|
#define HACK_DRAW draw_tube
|
|
#define tube_opts xlockmore_opts
|
|
#define DEFAULTS "*delay: 25000 \n" \
|
|
"*cycles: 20000 \n" \
|
|
"*size: -200 \n" \
|
|
"*ncolors: 200 \n"
|
|
#define SMOOTH_COLORS
|
|
#define WRITABLE_COLORS
|
|
#include "xlockmore.h" /* from the xscreensaver distribution */
|
|
#else /* !STANDALONE */
|
|
#include "xlock.h" /* from the xlockmore distribution */
|
|
#include "color.h"
|
|
#endif /* !STANDALONE */
|
|
|
|
#ifdef MODE_tube
|
|
|
|
#define DEF_CYCLE "True"
|
|
|
|
static Bool cycle_p;
|
|
|
|
static XrmOptionDescRec opts[] =
|
|
{
|
|
{(char *) "-cycle", (char *) ".tube.cycle", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+cycle", (char *) ".tube.cycle", XrmoptionNoArg, (caddr_t) "off"}
|
|
};
|
|
|
|
static argtype vars[] =
|
|
{
|
|
{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool}
|
|
};
|
|
static OptionStruct desc[] =
|
|
{
|
|
{(char *) "-/+cycle", (char *) "turn on/off colour cycling"}
|
|
};
|
|
|
|
ModeSpecOpt tube_opts =
|
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
|
|
|
#ifdef USE_MODULES
|
|
ModStruct tube_description =
|
|
{"tube", "init_tube", "draw_tube", "release_tube",
|
|
NULL, "init_tube", (char *) NULL, &tube_opts,
|
|
25000, -9, 20000, -200, 64, 1.0, "",
|
|
"Shows an animated tube", 0, NULL};
|
|
|
|
#endif
|
|
|
|
#define MINSIZE 3
|
|
#define MINSHAPE 1
|
|
|
|
typedef struct {
|
|
int dx1, dy1;
|
|
int x1, y1;
|
|
int width, height, average, linewidth;
|
|
int shape;
|
|
XPoint *pts, *proto_pts;
|
|
unsigned int cur_color;
|
|
GC gc;
|
|
Colormap cmap;
|
|
unsigned long blackpixel, whitepixel, fg, bg;
|
|
int direction;
|
|
XColor *colors;
|
|
int counter;
|
|
int ncolors;
|
|
Bool cycle_p, mono_p, no_colors, reverse;
|
|
ModeInfo *mi;
|
|
} tubestruct;
|
|
|
|
static tubestruct *tubes = (tubestruct *) NULL;
|
|
|
|
static void
|
|
free_pts(tubestruct *tp)
|
|
{
|
|
if (tp->pts != NULL) {
|
|
free(tp->pts);
|
|
tp->pts = (XPoint *) NULL;
|
|
}
|
|
if (tp->proto_pts != NULL) {
|
|
free(tp->proto_pts);
|
|
tp->proto_pts = (XPoint *) NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
free_tube(Display *display, tubestruct *tp)
|
|
{
|
|
ModeInfo *mi = tp->mi;
|
|
|
|
free_pts(tp);
|
|
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
MI_WHITE_PIXEL(mi) = tp->whitepixel;
|
|
MI_BLACK_PIXEL(mi) = tp->blackpixel;
|
|
#ifndef STANDALONE
|
|
MI_FG_PIXEL(mi) = tp->fg;
|
|
MI_BG_PIXEL(mi) = tp->bg;
|
|
#endif
|
|
if (tp->colors != NULL) {
|
|
if (tp->ncolors && !tp->no_colors)
|
|
free_colors(display, tp->cmap, tp->colors, tp->ncolors);
|
|
free(tp->colors);
|
|
tp->colors = (XColor *) NULL;
|
|
}
|
|
if (tp->cmap != None) {
|
|
XFreeColormap(display, tp->cmap);
|
|
tp->cmap = None;
|
|
}
|
|
}
|
|
if (tp->gc != None) {
|
|
XFreeGC(display, tp->gc);
|
|
tp->gc = None;
|
|
}
|
|
}
|
|
|
|
#ifndef STANDALONE
|
|
extern char *background;
|
|
extern char *foreground;
|
|
#endif
|
|
|
|
void
|
|
init_tube(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
int screen_width, screen_height;
|
|
int size = MI_SIZE(mi);
|
|
int star = 1, lw;
|
|
tubestruct *tp;
|
|
|
|
if (tubes == NULL) {
|
|
if ((tubes = (tubestruct *) calloc(MI_NUM_SCREENS(mi),
|
|
sizeof (tubestruct))) == NULL)
|
|
return;
|
|
}
|
|
tp = &tubes[MI_SCREEN(mi)];
|
|
tp->mi = mi;
|
|
|
|
screen_width = MI_WIDTH(mi);
|
|
screen_height = MI_HEIGHT(mi);
|
|
|
|
if (size < -MINSIZE) {
|
|
tp->width = NRAND(MIN(-size, MAX(MINSIZE, screen_width / 2)) -
|
|
MINSIZE + 1) + MINSIZE;
|
|
tp->height = NRAND(MIN(-size, MAX(MINSIZE, screen_height / 2)) -
|
|
MINSIZE + 1) + MINSIZE;
|
|
} else if (size < MINSIZE) {
|
|
if (!size) {
|
|
tp->width = MAX(MINSIZE, screen_width / 2);
|
|
tp->height = MAX(MINSIZE, screen_height / 2);
|
|
} else {
|
|
tp->width = MINSIZE;
|
|
tp->height = MINSIZE;
|
|
}
|
|
} else {
|
|
tp->width = MIN(size, MAX(MINSIZE, screen_width / 2));
|
|
tp->height = MIN(size, MAX(MINSIZE, screen_height / 2));
|
|
}
|
|
tp->average = (tp->width + tp->height) / 2;
|
|
tp->reverse = (Bool) (LRAND() & 1);
|
|
tp->dx1 = LRAND() & 1;
|
|
if (tp->dx1 == 0)
|
|
tp->dx1 = -1;
|
|
tp->dy1 = LRAND() & 1;
|
|
if (tp->dy1 == 0)
|
|
tp->dy1 = -1;
|
|
free_pts(tp);
|
|
tp->shape = MI_COUNT(mi);
|
|
if (tp->shape < -MINSHAPE) {
|
|
tp->shape = NRAND(-tp->shape - MINSHAPE + 1) + MINSHAPE;
|
|
} else if (tp->shape < MINSHAPE)
|
|
tp->shape = MINSHAPE;
|
|
|
|
if (tp->shape >= 3) {
|
|
int i;
|
|
float start;
|
|
|
|
tp->width = tp->height = tp->average;
|
|
if (((tp->pts = (XPoint *) malloc((tp->shape + 1) *
|
|
sizeof (XPoint))) == NULL) ||
|
|
((tp->proto_pts = (XPoint *) malloc((tp->shape + 1) *
|
|
sizeof (XPoint))) == NULL)) {
|
|
free_tube(display, tp);
|
|
return;
|
|
}
|
|
start = (float) NRAND(360);
|
|
do {
|
|
star = NRAND(tp->shape / 2) + 1; /* Not always a star but thats ok. */
|
|
} while ((star != 1) && (!(tp->shape % star)));
|
|
for (i = 0; i < tp->shape; i++) {
|
|
tp->proto_pts[i].x = tp->average / 2 +
|
|
(int) (cos((double) start * 2.0 * M_PI / 360.0) * tp->average / 2.0);
|
|
tp->proto_pts[i].y = tp->average / 2 +
|
|
(int) (sin((double) start * 2.0 * M_PI / 360.0) * tp->average / 2.0);
|
|
start += star * 360 / tp->shape;
|
|
}
|
|
tp->proto_pts[tp->shape] = tp->proto_pts[0];
|
|
}
|
|
tp->linewidth = NRAND(tp->average / 6 + 1) + 1;
|
|
if (star > 1) /* Make the width less */
|
|
tp->linewidth = NRAND(tp->linewidth / 2 + 1) + 1;
|
|
lw = tp->linewidth / 2;
|
|
tp->x1 = NRAND(screen_width - tp->width - 2 * lw) + lw;
|
|
tp->y1 = NRAND(screen_height - tp->height - 2 * lw) + lw;
|
|
|
|
tp->counter = 0;
|
|
|
|
if (!tp->gc) {
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
XColor color;
|
|
|
|
#ifndef STANDALONE
|
|
tp->fg = MI_FG_PIXEL(mi);
|
|
tp->bg = MI_BG_PIXEL(mi);
|
|
#endif
|
|
tp->blackpixel = MI_BLACK_PIXEL(mi);
|
|
tp->whitepixel = MI_WHITE_PIXEL(mi);
|
|
if ((tp->cmap = XCreateColormap(display, window,
|
|
MI_VISUAL(mi), AllocNone)) == None) {
|
|
free_tube(display, tp);
|
|
return;
|
|
}
|
|
XSetWindowColormap(display, window, tp->cmap);
|
|
(void) XParseColor(display, tp->cmap, "black", &color);
|
|
(void) XAllocColor(display, tp->cmap, &color);
|
|
MI_BLACK_PIXEL(mi) = color.pixel;
|
|
(void) XParseColor(display, tp->cmap, "white", &color);
|
|
(void) XAllocColor(display, tp->cmap, &color);
|
|
MI_WHITE_PIXEL(mi) = color.pixel;
|
|
#ifndef STANDALONE
|
|
(void) XParseColor(display, tp->cmap, background, &color);
|
|
(void) XAllocColor(display, tp->cmap, &color);
|
|
MI_BG_PIXEL(mi) = color.pixel;
|
|
(void) XParseColor(display, tp->cmap, foreground, &color);
|
|
(void) XAllocColor(display, tp->cmap, &color);
|
|
MI_FG_PIXEL(mi) = color.pixel;
|
|
#endif
|
|
tp->colors = (XColor *) NULL;
|
|
tp->ncolors = 0;
|
|
}
|
|
if ((tp->gc = XCreateGC(display, MI_WINDOW(mi),
|
|
(unsigned long) 0, (XGCValues *) NULL)) == None) {
|
|
free_tube(display, tp);
|
|
return;
|
|
}
|
|
}
|
|
MI_CLEARWINDOW(mi);
|
|
|
|
/* Set up colour map */
|
|
tp->direction = (LRAND() & 1) ? 1 : -1;
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (tp->colors != NULL) {
|
|
if (tp->ncolors && !tp->no_colors)
|
|
free_colors(display, tp->cmap, tp->colors, tp->ncolors);
|
|
free(tp->colors);
|
|
tp->colors = (XColor *) NULL;
|
|
}
|
|
tp->ncolors = MI_NCOLORS(mi);
|
|
if (tp->ncolors < 2)
|
|
tp->ncolors = 2;
|
|
if (tp->ncolors <= 2)
|
|
tp->mono_p = True;
|
|
else
|
|
tp->mono_p = False;
|
|
|
|
if (tp->mono_p)
|
|
tp->colors = (XColor *) NULL;
|
|
else
|
|
if ((tp->colors = (XColor *) malloc(sizeof (*tp->colors) *
|
|
(tp->ncolors + 1))) == NULL) {
|
|
free_tube(display, tp);
|
|
return;
|
|
}
|
|
tp->cycle_p = has_writable_cells(mi);
|
|
if (tp->cycle_p) {
|
|
if (MI_IS_FULLRANDOM(mi)) {
|
|
if (!NRAND(8))
|
|
tp->cycle_p = False;
|
|
else
|
|
tp->cycle_p = True;
|
|
} else {
|
|
tp->cycle_p = cycle_p;
|
|
}
|
|
}
|
|
if (!tp->mono_p) {
|
|
if (!(LRAND() % 10))
|
|
make_random_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
tp->cmap, tp->colors, &tp->ncolors,
|
|
True, True, &tp->cycle_p);
|
|
else if (!(LRAND() % 2))
|
|
make_uniform_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
tp->cmap, tp->colors, &tp->ncolors,
|
|
True, &tp->cycle_p);
|
|
else
|
|
make_smooth_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
tp->cmap, tp->colors, &tp->ncolors,
|
|
True, &tp->cycle_p);
|
|
}
|
|
XInstallColormap(display, tp->cmap);
|
|
if (tp->ncolors < 2) {
|
|
tp->ncolors = 2;
|
|
tp->no_colors = True;
|
|
} else
|
|
tp->no_colors = False;
|
|
if (tp->ncolors <= 2)
|
|
tp->mono_p = True;
|
|
|
|
if (tp->mono_p)
|
|
tp->cycle_p = False;
|
|
|
|
}
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (tp->mono_p) {
|
|
tp->cur_color = MI_BLACK_PIXEL(mi);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
draw_tube(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
unsigned int i;
|
|
int lw;
|
|
tubestruct *tp;
|
|
|
|
if (tubes == NULL)
|
|
return;
|
|
tp = &tubes[MI_SCREEN(mi)];
|
|
|
|
if (tp->no_colors) {
|
|
init_tube(mi);
|
|
return;
|
|
}
|
|
if (tp->shape >= 3 && tp->pts == NULL)
|
|
return;
|
|
|
|
MI_IS_DRAWN(mi) = True;
|
|
lw = tp->linewidth / 2;
|
|
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (tp->mono_p) {
|
|
XSetForeground(display, tp->gc, tp->cur_color);
|
|
} else {
|
|
tp->cur_color = (tp->cur_color + 1) % tp->ncolors;
|
|
XSetForeground(display, tp->gc, tp->colors[tp->cur_color].pixel);
|
|
}
|
|
} else {
|
|
if (MI_NPIXELS(mi) > 2)
|
|
XSetForeground(display, tp->gc, MI_PIXEL(mi, tp->cur_color));
|
|
else if (tp->cur_color)
|
|
XSetForeground(display, tp->gc, MI_BLACK_PIXEL(mi));
|
|
else
|
|
XSetForeground(display, tp->gc, MI_WHITE_PIXEL(mi));
|
|
if (++tp->cur_color >= (unsigned int) MI_NPIXELS(mi))
|
|
tp->cur_color = 0;
|
|
}
|
|
|
|
/* Rotate colours */
|
|
if (tp->cycle_p) {
|
|
rotate_colors(display, tp->cmap, tp->colors, tp->ncolors,
|
|
tp->direction);
|
|
if (!(LRAND() % 1000))
|
|
tp->direction = -tp->direction;
|
|
}
|
|
|
|
/* move rectangle forward, horiz */
|
|
tp->x1 += tp->dx1;
|
|
if (tp->x1 < lw) {
|
|
tp->x1 = lw;
|
|
tp->dx1 = -tp->dx1;
|
|
}
|
|
if (tp->x1 + tp->width + lw >= MI_WIDTH(mi)) {
|
|
tp->x1 = MI_WIDTH(mi) - tp->width - 1 - lw;
|
|
tp->dx1 = -tp->dx1;
|
|
}
|
|
/* move rectange forward, vert */
|
|
tp->y1 += tp->dy1;
|
|
if (tp->y1 < lw) {
|
|
tp->y1 = lw;
|
|
tp->dy1 = -tp->dy1;
|
|
}
|
|
if (tp->y1 + tp->height + lw >= MI_HEIGHT(mi)) {
|
|
tp->y1 = MI_HEIGHT(mi) - tp->height - 1 - lw;
|
|
tp->dy1 = -tp->dy1;
|
|
}
|
|
XSetLineAttributes(display, tp->gc, tp->linewidth + (tp->shape >= 2),
|
|
LineSolid, CapNotLast, JoinRound);
|
|
if (tp->shape < 2)
|
|
XDrawRectangle(display, window, tp->gc,
|
|
tp->x1, tp->y1, tp->width, tp->height);
|
|
else if (tp->shape == 2)
|
|
XDrawArc(display, window, tp->gc,
|
|
tp->x1, tp->y1, tp->width, tp->height, 0, 23040);
|
|
else {
|
|
for (i = 0; i <= (unsigned int) tp->shape; i++) {
|
|
tp->pts[i].x = tp->x1 + tp->proto_pts[i].x;
|
|
tp->pts[i].y = tp->y1 + tp->proto_pts[i].y;
|
|
}
|
|
XDrawLines(display, window, tp->gc, tp->pts, tp->shape + 1,
|
|
CoordModeOrigin);
|
|
}
|
|
XSetLineAttributes(display, tp->gc, 1, LineSolid, CapNotLast, JoinRound);
|
|
|
|
tp->counter++;
|
|
if (tp->counter > MI_CYCLES(mi)) {
|
|
init_tube(mi);
|
|
}
|
|
}
|
|
|
|
void
|
|
release_tube(ModeInfo * mi)
|
|
{
|
|
if (tubes != NULL) {
|
|
int screen;
|
|
|
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
|
|
free_tube(MI_DISPLAY(mi), &tubes[screen]);
|
|
free(tubes);
|
|
tubes = (tubestruct *) NULL;
|
|
}
|
|
}
|
|
|
|
#endif /* MODE_tube */
|