--- /dev/null
+/* -*- Mode: C; tab-width: 4 -*-
+ * laser --- draws swinging laser beams.
+ */
+#if !defined( lint ) && !defined( SABER )
+static const char sccsid[] = "@(#)laser.c 4.00 97/01/01 xlockmore";
+#endif
+
+/* Copyright (c) 1995 Pascal Pensa <pensa@aurora.unice.fr>
+ *
+ * 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.
+ *
+ * Revision History:
+ * 10-May-97: jwz@jwz.org: turned into a standalone program.
+ */
+
+#ifdef STANDALONE
+# define PROGCLASS "Laser"
+# define HACK_INIT init_laser
+# define HACK_DRAW draw_laser
+# define laser_opts xlockmore_opts
+# define DEFAULTS "*count: 10 \n" \
+ "*cycles: 200 \n" \
+ "*delay: 40000 \n" \
+ "*ncolors: 64 \n"
+# define SMOOTH_COLORS
+# include "xlockmore.h" /* from the xscreensaver distribution */
+#else /* !STANDALONE */
+# include "xlock.h" /* from the xlockmore distribution */
+#endif /* !STANDALONE */
+
+ModeSpecOpt laser_opts = {
+ 0, NULL, 0, NULL, NULL };
+
+#define MINREDRAW 3 /* Number of redrawn on each frame */
+#define MAXREDRAW 8
+
+#define MINLASER 1 /* Laser number */
+
+#define MINWIDTH 2 /* Laser ray width range */
+#define MAXWIDTH 40
+
+#define MINSPEED 2 /* Speed range */
+#define MAXSPEED 17
+
+#define MINDIST 10 /* Minimal distance from edges */
+
+#define COLORSTEP 2 /* Laser color step */
+
+#define RANGE_RAND(min,max) ((min) + LRAND() % ((max) - (min)))
+
+typedef enum {
+ TOP, RIGHT, BOTTOM, LEFT
+} border;
+
+typedef struct {
+ int bx; /* border x */
+ int by; /* border y */
+ border bn; /* active border */
+ int dir; /* direction */
+ int speed; /* laser velocity from MINSPEED to MAXSPEED */
+ int sx[MAXWIDTH]; /* x stack */
+ int sy[MAXWIDTH]; /* x stack */
+ XGCValues gcv; /* for color */
+} laserstruct;
+
+typedef struct {
+ int width;
+ int height;
+ int cx; /* center x */
+ int cy; /* center y */
+ int lw; /* laser width */
+ int ln; /* laser number */
+ int lr; /* laser redraw */
+ int sw; /* stack width */
+ int so; /* stack offset */
+ int time; /* up time */
+ GC stippledGC;
+ XGCValues gcv_black; /* for black color */
+ laserstruct *laser;
+} lasersstruct;
+
+static lasersstruct *lasers = NULL;
+
+
+void
+init_laser(ModeInfo * mi)
+{
+ int i, c = 0;
+ lasersstruct *lp;
+
+ if (lasers == NULL) {
+ if ((lasers = (lasersstruct *) calloc(MI_NUM_SCREENS(mi),
+ sizeof (lasersstruct))) == NULL)
+ return;
+ }
+ lp = &lasers[MI_SCREEN(mi)];
+
+ lp->width = MI_WIN_WIDTH(mi);
+ lp->height = MI_WIN_HEIGHT(mi);
+ lp->time = 0;
+
+ lp->ln = MI_BATCHCOUNT(mi);
+ if (lp->ln < -MINLASER) {
+ /* if lp->ln is random ... the size can change */
+ if (lp->laser != NULL) {
+ (void) free((void *) lp->laser);
+ lp->laser = NULL;
+ }
+ lp->ln = NRAND(-lp->ln - MINLASER + 1) + MINLASER;
+ } else if (lp->ln < MINLASER)
+ lp->ln = MINLASER;
+
+ if (!lp->laser) {
+ lp->laser = (laserstruct *) malloc(lp->ln * sizeof (laserstruct));
+ }
+ if (lp->stippledGC == NULL) {
+ XGCValues gcv;
+
+ gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
+ gcv.background = MI_WIN_BLACK_PIXEL(mi);
+ lp->gcv_black.foreground = MI_WIN_BLACK_PIXEL(mi);
+ lp->stippledGC = XCreateGC(MI_DISPLAY(mi), MI_WINDOW(mi),
+ GCForeground | GCBackground, &gcv);
+ }
+ XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
+
+ if (MINDIST < lp->width - MINDIST)
+ lp->cx = RANGE_RAND(MINDIST, lp->width - MINDIST);
+ else
+ lp->cx = RANGE_RAND(0, lp->width);
+ if (MINDIST < lp->height - MINDIST)
+ lp->cy = RANGE_RAND(MINDIST, lp->height - MINDIST);
+ else
+ lp->cy = RANGE_RAND(0, lp->height);
+ lp->lw = RANGE_RAND(MINWIDTH, MAXWIDTH);
+ lp->lr = RANGE_RAND(MINREDRAW, MAXREDRAW);
+ lp->sw = 0;
+ lp->so = 0;
+
+ if (MI_NPIXELS(mi) > 2)
+ c = NRAND(MI_NPIXELS(mi));
+
+ for (i = 0; i < lp->ln; i++) {
+ laserstruct *l = &lp->laser[i];
+
+ l->bn = (border) NRAND(4);
+
+ switch (l->bn) {
+ case TOP:
+ l->bx = NRAND(lp->width);
+ l->by = 0;
+ break;
+ case RIGHT:
+ l->bx = lp->width;
+ l->by = NRAND(lp->height);
+ break;
+ case BOTTOM:
+ l->bx = NRAND(lp->width);
+ l->by = lp->height;
+ break;
+ case LEFT:
+ l->bx = 0;
+ l->by = NRAND(lp->height);
+ }
+
+ l->dir = LRAND() & 1;
+ l->speed = ((RANGE_RAND(MINSPEED, MAXSPEED) * lp->width) / 1000) + 1;
+ if (MI_NPIXELS(mi) > 2) {
+ l->gcv.foreground = MI_PIXEL(mi, c);
+ c = (c + COLORSTEP) % MI_NPIXELS(mi);
+ } else
+ l->gcv.foreground = MI_WIN_WHITE_PIXEL(mi);
+ }
+}
+
+static void
+draw_laser_once(ModeInfo * mi)
+{
+ Display *display = MI_DISPLAY(mi);
+ lasersstruct *lp = &lasers[MI_SCREEN(mi)];
+ int i;
+
+ for (i = 0; i < lp->ln; i++) {
+ laserstruct *l = &lp->laser[i];
+
+ if (lp->sw >= lp->lw) {
+ XChangeGC(display, lp->stippledGC, GCForeground, &(lp->gcv_black));
+ XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
+ lp->cx, lp->cy,
+ l->sx[lp->so], l->sy[lp->so]);
+ }
+ if (l->dir) {
+ switch (l->bn) {
+ case TOP:
+ l->bx -= l->speed;
+ if (l->bx < 0) {
+ l->by = -l->bx;
+ l->bx = 0;
+ l->bn = LEFT;
+ }
+ break;
+ case RIGHT:
+ l->by -= l->speed;
+ if (l->by < 0) {
+ l->bx = lp->width + l->by;
+ l->by = 0;
+ l->bn = TOP;
+ }
+ break;
+ case BOTTOM:
+ l->bx += l->speed;
+ if (l->bx >= lp->width) {
+ l->by = lp->height - l->bx % lp->width;
+ l->bx = lp->width;
+ l->bn = RIGHT;
+ }
+ break;
+ case LEFT:
+ l->by += l->speed;
+ if (l->by >= lp->height) {
+ l->bx = l->by % lp->height;
+ l->by = lp->height;
+ l->bn = BOTTOM;
+ }
+ }
+ } else {
+ switch (l->bn) {
+ case TOP:
+ l->bx += l->speed;
+ if (l->bx >= lp->width) {
+ l->by = l->bx % lp->width;
+ l->bx = lp->width;
+ l->bn = RIGHT;
+ }
+ break;
+ case RIGHT:
+ l->by += l->speed;
+ if (l->by >= lp->height) {
+ l->bx = lp->width - l->by % lp->height;
+ l->by = lp->height;
+ l->bn = BOTTOM;
+ }
+ break;
+ case BOTTOM:
+ l->bx -= l->speed;
+ if (l->bx < 0) {
+ l->by = lp->height + l->bx;
+ l->bx = 0;
+ l->bn = LEFT;
+ }
+ break;
+ case LEFT:
+ l->by -= l->speed;
+ if (l->by < 0) {
+ l->bx = -l->bx;
+ l->by = 0;
+ l->bn = TOP;
+ }
+ }
+ }
+
+ XChangeGC(display, lp->stippledGC, GCForeground, &l->gcv);
+ XDrawLine(display, MI_WINDOW(mi), lp->stippledGC,
+ lp->cx, lp->cy, l->bx, l->by);
+
+ l->sx[lp->so] = l->bx;
+ l->sy[lp->so] = l->by;
+
+ }
+
+ if (lp->sw < lp->lw)
+ ++lp->sw;
+
+ lp->so = (lp->so + 1) % lp->lw;
+}
+
+void
+draw_laser(ModeInfo * mi)
+{
+ lasersstruct *lp = &lasers[MI_SCREEN(mi)];
+ int i;
+
+ for (i = 0; i < lp->lr; i++)
+ draw_laser_once(mi);
+
+ if (++lp->time > MI_CYCLES(mi))
+ init_laser(mi);
+}
+
+void
+release_laser(ModeInfo * mi)
+{
+ if (lasers != NULL) {
+ int screen;
+
+ for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
+ lasersstruct *lp = &lasers[screen];
+
+ if (lp->laser != NULL)
+ (void) free((void *) lp->laser);
+ if (lp->stippledGC != NULL)
+ XFreeGC(MI_DISPLAY(mi), lp->stippledGC);
+ }
+ (void) free((void *) lasers);
+ lasers = NULL;
+ }
+}
+
+void
+refresh_laser(ModeInfo * mi)
+{
+ /* Do nothing, it will refresh by itself */
+}