342 lines
7.8 KiB
C
342 lines
7.8 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* slip --- lots of slipping blits */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)slip.c 5.00 2000/11/01 xlockmore";
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*-
|
||
|
* Copyright (c) 1992 by Scott Draves <spot@cs.cmu.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.
|
||
|
*
|
||
|
* 01-Nov-2000: Allocation checks
|
||
|
* 10-May-1997: Jamie Zawinski <jwz@jwz.org> compatible with xscreensaver
|
||
|
* 01-Dec-1995: Patched for VMS <joukj@hrem.stm.tudelft.nl>
|
||
|
*/
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
#define MODE_slip
|
||
|
#define PROGCLASS "Slip"
|
||
|
#define HACK_INIT init_slip
|
||
|
#define HACK_DRAW draw_slip
|
||
|
#define slip_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 50000 \n" \
|
||
|
"*count: 35 \n" \
|
||
|
"*cycles: 50 \n" \
|
||
|
"*ncolors: 200 \n"
|
||
|
#include "xlockmore.h" /* in xscreensaver distribution */
|
||
|
#else /* STANDALONE */
|
||
|
#include "xlock.h" /* in xlockmore distribution */
|
||
|
#endif /* STANDALONE */
|
||
|
|
||
|
#ifdef MODE_slip
|
||
|
|
||
|
ModeSpecOpt slip_opts =
|
||
|
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
|
||
|
|
||
|
#ifdef USE_MODULES
|
||
|
ModStruct slip_description =
|
||
|
{"slip", "init_slip", "draw_slip", "release_slip",
|
||
|
"init_slip", "init_slip", (char *) NULL, &slip_opts,
|
||
|
50000, 35, 50, 1, 64, 1.0, "",
|
||
|
"Shows slipping blits", 0, NULL};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
typedef struct {
|
||
|
int width, height;
|
||
|
int nblits_remaining;
|
||
|
int blit_width, blit_height;
|
||
|
int mode;
|
||
|
int first_time;
|
||
|
int backwards;
|
||
|
short lasthalf;
|
||
|
int stage;
|
||
|
unsigned long r;
|
||
|
} slipstruct;
|
||
|
static slipstruct *slips = (slipstruct *) NULL;
|
||
|
|
||
|
static short
|
||
|
halfrandom(slipstruct *sp, int mv)
|
||
|
{
|
||
|
unsigned long r;
|
||
|
|
||
|
if (sp->lasthalf) {
|
||
|
r = sp->lasthalf;
|
||
|
sp->lasthalf = 0;
|
||
|
} else {
|
||
|
r = LRAND();
|
||
|
sp->lasthalf = (short) (r >> 16);
|
||
|
}
|
||
|
return r % mv;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
erandom(slipstruct *sp, int mv)
|
||
|
{
|
||
|
int res;
|
||
|
|
||
|
if (0 == sp->stage) {
|
||
|
sp->r = LRAND();
|
||
|
sp->stage = 7;
|
||
|
}
|
||
|
res = (int) (sp->r & 0xf);
|
||
|
sp->r = sp->r >> 4;
|
||
|
sp->stage--;
|
||
|
if (res & 8)
|
||
|
return res & mv;
|
||
|
else
|
||
|
return -(res & mv);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
prepare_screen(ModeInfo * mi, slipstruct * sp)
|
||
|
{
|
||
|
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
GC gc = MI_GC(mi);
|
||
|
int i, n, w = sp->width / 20;
|
||
|
int not_solid = halfrandom(sp, 10);
|
||
|
|
||
|
#ifdef STANDALONE /* jwz -- sometimes hack the desktop image! */
|
||
|
if (halfrandom(sp, 2) == 0) {
|
||
|
#if 0
|
||
|
Pixmap p =
|
||
|
#endif
|
||
|
grab_screen_image(DefaultScreenOfDisplay(display),
|
||
|
MI_WINDOW(mi));
|
||
|
|
||
|
#if 0
|
||
|
if (p)
|
||
|
XFreePixmap(display, p);
|
||
|
return;
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
sp->backwards = (int) (LRAND() & 1); /* jwz: go the other way sometimes */
|
||
|
|
||
|
if (sp->first_time || !halfrandom(sp, 10)) {
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
n = 300;
|
||
|
} else {
|
||
|
if (halfrandom(sp, 5))
|
||
|
return;
|
||
|
if (halfrandom(sp, 5))
|
||
|
n = 100;
|
||
|
else
|
||
|
n = 2000;
|
||
|
}
|
||
|
|
||
|
if (MI_NPIXELS(mi) > 2)
|
||
|
XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
|
||
|
else if (halfrandom(sp, 2))
|
||
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
||
|
else
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
|
||
|
for (i = 0; i < n; i++) {
|
||
|
int ww = ((w / 2) + halfrandom(sp, MAX(w, 1)));
|
||
|
|
||
|
if (not_solid) {
|
||
|
if (MI_NPIXELS(mi) > 2)
|
||
|
XSetForeground(display, gc, MI_PIXEL(mi, halfrandom(sp, MI_NPIXELS(mi))));
|
||
|
else if (halfrandom(sp, 2))
|
||
|
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
|
||
|
else
|
||
|
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
|
||
|
}
|
||
|
XFillRectangle(display, MI_WINDOW(mi), gc,
|
||
|
halfrandom(sp, MAX(sp->width - ww, 1)),
|
||
|
halfrandom(sp, MAX(sp->height - ww, 1)),
|
||
|
ww, ww);
|
||
|
}
|
||
|
sp->first_time = 0;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
quantize(double d)
|
||
|
{
|
||
|
int i = (int) floor(d);
|
||
|
double f = d - i;
|
||
|
|
||
|
if ((LRAND() & 0xff) < f * 0xff)
|
||
|
i++;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_slip(ModeInfo * mi)
|
||
|
{
|
||
|
slipstruct *sp;
|
||
|
|
||
|
if (slips == NULL) {
|
||
|
if ((slips = (slipstruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof (slipstruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
sp = &slips[MI_SCREEN(mi)];
|
||
|
|
||
|
sp->width = MI_WIDTH(mi);
|
||
|
sp->height = MI_HEIGHT(mi);
|
||
|
|
||
|
sp->blit_width = sp->width / 25;
|
||
|
sp->blit_height = sp->height / 25;
|
||
|
sp->nblits_remaining = 0;
|
||
|
sp->mode = 0;
|
||
|
sp->first_time = 1;
|
||
|
|
||
|
/* no "NoExpose" events from XCopyArea wanted */
|
||
|
XSetGraphicsExposures(MI_DISPLAY(mi), MI_GC(mi), False);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
draw_slip(ModeInfo * mi)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
GC gc = MI_GC(mi);
|
||
|
int timer;
|
||
|
slipstruct *sp;
|
||
|
|
||
|
if (slips == NULL)
|
||
|
return;
|
||
|
sp = &slips[MI_SCREEN(mi)];
|
||
|
|
||
|
timer = MI_COUNT(mi) * MI_CYCLES(mi);
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
|
||
|
while (timer--) {
|
||
|
int xi = halfrandom(sp, MAX(sp->width - sp->blit_width, 1));
|
||
|
int yi = halfrandom(sp, MAX(sp->height - sp->blit_height, 1));
|
||
|
double x, y, dx = 0, dy = 0, t, s1, s2;
|
||
|
|
||
|
if (0 == sp->nblits_remaining--) {
|
||
|
static int lut[] =
|
||
|
{0, 0, 0, 1, 1, 1, 2};
|
||
|
|
||
|
prepare_screen(mi, sp);
|
||
|
sp->nblits_remaining = MI_COUNT(mi) *
|
||
|
(2000 + halfrandom(sp, 1000) + halfrandom(sp, 1000));
|
||
|
if (sp->mode == 2)
|
||
|
sp->mode = halfrandom(sp, 2);
|
||
|
else
|
||
|
sp->mode = lut[halfrandom(sp, 7)];
|
||
|
}
|
||
|
x = (2 * xi + sp->blit_width) / (double) sp->width - 1;
|
||
|
y = (2 * yi + sp->blit_height) / (double) sp->height - 1;
|
||
|
|
||
|
/* (x,y) is in biunit square */
|
||
|
switch (sp->mode) {
|
||
|
case 0: /* rotor */
|
||
|
dx = x;
|
||
|
dy = y;
|
||
|
|
||
|
if (dy < 0) {
|
||
|
dy += 0.04;
|
||
|
if (dy > 0)
|
||
|
dy = 0.00;
|
||
|
}
|
||
|
if (dy > 0) {
|
||
|
dy -= 0.04;
|
||
|
if (dy < 0)
|
||
|
dy = 0.00;
|
||
|
}
|
||
|
t = dx * dx + dy * dy + 1e-10;
|
||
|
s1 = 2 * dx * dx / t - 1;
|
||
|
s2 = 2 * dx * dy / t;
|
||
|
dx = s1 * 5;
|
||
|
dy = s2 * 5;
|
||
|
|
||
|
if (sp->backwards) { /* jwz: go the other way sometimes */
|
||
|
dx = -dx;
|
||
|
dy = -dy;
|
||
|
}
|
||
|
break;
|
||
|
case 1: /* shuffle */
|
||
|
dx = erandom(sp, 3);
|
||
|
dy = erandom(sp, 3);
|
||
|
break;
|
||
|
case 2: /* explode */
|
||
|
dx = x * 3;
|
||
|
dy = y * 3;
|
||
|
break;
|
||
|
}
|
||
|
{
|
||
|
int qx = xi + quantize(dx), qy = yi + quantize(dy);
|
||
|
int wrap;
|
||
|
|
||
|
if (qx < 0 || qy < 0 ||
|
||
|
qx >= sp->width - sp->blit_width ||
|
||
|
qy >= sp->height - sp->blit_height)
|
||
|
continue;
|
||
|
|
||
|
/*-
|
||
|
Seems to cause problems using Exceed
|
||
|
with PseudoColor
|
||
|
X Error of failed request: BadGC (invalid GC parameter)
|
||
|
with TrueColor
|
||
|
X Error of failed request: BadDrawable (invalid Pixmap or Window parameter)
|
||
|
Major opcode of failed request: 62 (X_CopyArea)
|
||
|
*/
|
||
|
XCopyArea(display, window, window, gc, xi, yi,
|
||
|
sp->blit_width, sp->blit_height,
|
||
|
qx, qy);
|
||
|
switch (sp->mode) {
|
||
|
case 0:
|
||
|
/* wrap */
|
||
|
wrap = sp->width - (2 * sp->blit_width);
|
||
|
if (qx > wrap ) {
|
||
|
XCopyArea(display, window, window, gc, qx, qy,
|
||
|
sp->blit_width, sp->blit_height,
|
||
|
qx - wrap, qy);
|
||
|
}
|
||
|
if (qx < 2 * sp->blit_width) {
|
||
|
XCopyArea(display, window, window, gc, qx, qy,
|
||
|
sp->blit_width, sp->blit_height,
|
||
|
qx + wrap, qy);
|
||
|
}
|
||
|
wrap = sp->height - (2 * sp->blit_height);
|
||
|
if (qy > wrap) {
|
||
|
XCopyArea(display, window, window, gc, qx, qy,
|
||
|
sp->blit_width, sp->blit_height,
|
||
|
qx, qy - wrap);
|
||
|
}
|
||
|
if (qy < 2 * sp->blit_height) {
|
||
|
XCopyArea(display, window, window, gc, qx, qy,
|
||
|
sp->blit_width, sp->blit_height,
|
||
|
qx, qy + wrap);
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
case 2:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_slip(ModeInfo * mi)
|
||
|
{
|
||
|
if (slips != NULL) {
|
||
|
free(slips);
|
||
|
slips = (slipstruct *) NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif /* MODE_slip */
|