269 lines
7.3 KiB
C
269 lines
7.3 KiB
C
/* -*- Mode: C; tab-width: 4 -*- */
|
|
/* munch --- munching squares */
|
|
|
|
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)munch.c 5.00 2000/11/01 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* 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.
|
|
*
|
|
* Tim Showalter <tjs@andrew.cmu.edu>
|
|
*
|
|
* Copyright 1997, Tim Showalter
|
|
* Permission is granted to copy, modify, and use this as long
|
|
* as this notice remains intact. No warranties are expressed or implied.
|
|
* CMU Sucks.
|
|
*
|
|
* Some code stolen from / This is meant to work with
|
|
* xscreensaver, Copyright (c) 1992, 1995, 1996
|
|
* 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.
|
|
*
|
|
* Revision History:
|
|
* 01-Nov-2000: Allocation checks
|
|
*/
|
|
|
|
/*-
|
|
* Munching Squares is this simplistic, silly screen hack (according to
|
|
* HAKMEM, discovered by Jackson Wright in 1962) where you take Y = X XOR T
|
|
* and graph it over and over. According to HAKMEM, it takes 5 instructions
|
|
* of PDP-1 assembly. This is a little more complicated than that, mostly X's
|
|
* fault, but it does some other random things.
|
|
* http://www.inwap.com/pdp10/hbaker/hakmem/hacks.html#item146
|
|
*/
|
|
|
|
#ifdef STANDALONE
|
|
#define MODE_munch
|
|
#define PROGCLASS "Munch"
|
|
#define HACK_INIT init_munch
|
|
#define HACK_DRAW draw_munch
|
|
#define munch_opts xlockmore_opts
|
|
#define DEFAULTS "*delay: 5000 \n" \
|
|
"*cycles: 7 \n"
|
|
#include "xlockmore.h" /* from the xscreensaver distribution */
|
|
#else /* !STANDALONE */
|
|
#include "xlock.h" /* from the xlockmore distribution */
|
|
#endif /* !STANDALONE */
|
|
|
|
#ifdef MODE_munch
|
|
|
|
ModeSpecOpt munch_opts =
|
|
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
|
|
|
|
#ifdef USE_MODULES
|
|
ModStruct munch_description =
|
|
{"munch", "init_munch", "draw_munch", "release_munch",
|
|
"init_munch", "init_munch", (char *) NULL, &munch_opts,
|
|
5000, 1, 7, 1, 64, 1.0, "",
|
|
"Shows munching squares", 0, NULL};
|
|
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
/* flags for random things. Must be < log2(random's maximum), incidentially. */
|
|
#define SHIFT_KX (0x01)
|
|
#define SHIFT_KT (0x02)
|
|
#define SHIFT_KY (0x04)
|
|
#define GRAV (0x08)
|
|
|
|
typedef struct {
|
|
int width, height;
|
|
int logminwidth;
|
|
int logmaxwidth;
|
|
GC gc;
|
|
int thiswidth;
|
|
int t;
|
|
int atX, atY;
|
|
int kX, kT, kY;
|
|
int grav;
|
|
} munchstruct;
|
|
|
|
static munchstruct *munches = (munchstruct *) NULL;
|
|
|
|
static void
|
|
munchBit(ModeInfo * mi, int width, /* pixels */
|
|
int atX, int atY, /* pixels */
|
|
int kX, int kT, int kY, /* pixels */
|
|
int grav /* 0 or not */ )
|
|
{
|
|
munchstruct *mp = &munches[MI_SCREEN(mi)];
|
|
|
|
int x, y;
|
|
int drawX, drawY;
|
|
|
|
#if 0
|
|
(void) fprintf(stderr, "Doing width %d at %d %d shift %d %d %d grav %d\n",
|
|
width, atX, atY, kX, kT, kY, grav);
|
|
#endif
|
|
|
|
for (x = 0; x < width; x++) {
|
|
/* figure out the next point */
|
|
y = ((x ^ ((mp->t + kT) % width)) + kY) % width;
|
|
|
|
drawX = ((x + kX) % width) + atX;
|
|
drawY = (grav ? y + atY : atY + width - 1 - y);
|
|
|
|
/* used to be bugs where it would draw partially offscreen.
|
|
while that might be a pretty feature, I didn't want it to do
|
|
that yet. if these trigger, please let me know.
|
|
*/
|
|
#ifdef DEBUG
|
|
assert(drawX >= 0 && drawX < MI_WIDTH(mi));
|
|
assert(drawY >= 0 && drawY < MI_HEIGHT(mi));
|
|
#endif
|
|
|
|
XDrawPoint(MI_DISPLAY(mi), MI_WINDOW(mi), mp->gc, drawX, drawY);
|
|
/* XXX may want to change this to XDrawPoints,
|
|
but it's fast enough without it for the moment. */
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
* dumb way to get # of digits in number. Probably faster than actually
|
|
* doing a log and a division, maybe.
|
|
*/
|
|
static int
|
|
dumb_log_2(int k)
|
|
{
|
|
int r = -1;
|
|
|
|
while (k > 0) {
|
|
k >>= 1;
|
|
r++;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void
|
|
init_munch(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
munchstruct *mp;
|
|
|
|
if (munches == NULL) {
|
|
if ((munches = (munchstruct *) calloc(MI_NUM_SCREENS(mi),
|
|
sizeof (munchstruct))) == NULL)
|
|
return;
|
|
}
|
|
mp = &munches[MI_SCREEN(mi)];
|
|
|
|
if (mp->gc == None) {
|
|
if ((mp->gc = XCreateGC(display, MI_WINDOW(mi),
|
|
(unsigned long) 0, (XGCValues *) NULL)) == None)
|
|
return;
|
|
}
|
|
mp->width = MI_WIDTH(mi);
|
|
mp->height = MI_HEIGHT(mi);
|
|
|
|
/* We need a square; limit on screen size? */
|
|
/* we want a power of 2 for the width or the munch doesn't fill up. */
|
|
mp->logmaxwidth = (int)
|
|
dumb_log_2((mp->height < mp->width) ? mp->height : mp->width);
|
|
|
|
XSetFunction(display, mp->gc, GXxor);
|
|
|
|
mp->logminwidth = MI_CYCLES(mi);
|
|
if (mp->logminwidth < 2 || MI_IS_ICONIC(mi))
|
|
mp->logminwidth = 2;
|
|
|
|
if (mp->logmaxwidth < mp->logminwidth)
|
|
mp->logmaxwidth = mp->logminwidth;
|
|
|
|
mp->t = 0;
|
|
|
|
MI_CLEARWINDOW(mi);
|
|
}
|
|
|
|
void
|
|
draw_munch(ModeInfo * mi)
|
|
{
|
|
munchstruct *mp;
|
|
|
|
if (munches == NULL)
|
|
return;
|
|
mp = &munches[MI_SCREEN(mi)];
|
|
if (mp->gc == None)
|
|
return;
|
|
|
|
MI_IS_DRAWN(mi) = True;
|
|
if (!mp->t) { /* New one */
|
|
int randflags = (int) LRAND();
|
|
|
|
/* choose size -- power of two */
|
|
mp->thiswidth = (int) (1 << (mp->logminwidth +
|
|
(LRAND() % (1 + mp->logmaxwidth - mp->logminwidth))));
|
|
|
|
if (MI_NPIXELS(mi) > 2)
|
|
XSetForeground(MI_DISPLAY(mi), mp->gc,
|
|
MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))));
|
|
else /* Xor'red so WHITE may not be appropriate */
|
|
XSetForeground(MI_DISPLAY(mi), mp->gc, 1);
|
|
|
|
mp->atX = (int) (LRAND() %
|
|
((mp->width <= mp->thiswidth) ? 1 : mp->width - mp->thiswidth));
|
|
mp->atY = (int) (LRAND() %
|
|
((mp->height <= mp->thiswidth) ? 1 : mp->height - mp->thiswidth));
|
|
|
|
/* wrap-around by these values; no need to %
|
|
as we end up doing that later anyway */
|
|
mp->kX = (int) ((randflags & SHIFT_KX) ? LRAND() % mp->thiswidth : 0);
|
|
mp->kT = (int) ((randflags & SHIFT_KT) ? LRAND() % mp->thiswidth : 0);
|
|
mp->kY = (int) ((randflags & SHIFT_KY) ? LRAND() % mp->thiswidth : 0);
|
|
|
|
/* set the gravity of the munch, or rather,
|
|
which direction we draw stuff in. */
|
|
mp->grav = randflags & GRAV;
|
|
}
|
|
/* Finally draw this munching square. */
|
|
munchBit(mi,
|
|
mp->thiswidth, /* Width, in pixels */
|
|
/* draw at this location */
|
|
mp->atX, mp->atY, mp->kX, mp->kT, mp->kY, mp->grav);
|
|
|
|
mp->t++;
|
|
if (mp->t == mp->thiswidth)
|
|
mp->t = 0;
|
|
}
|
|
|
|
void
|
|
release_munch(ModeInfo * mi)
|
|
{
|
|
if (munches != NULL) {
|
|
int screen;
|
|
|
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
|
|
munchstruct *mp = &munches[screen];
|
|
|
|
if (mp->gc != None)
|
|
XFreeGC(MI_DISPLAY(mi), mp->gc);
|
|
}
|
|
free(munches);
|
|
munches = (munchstruct *) NULL;
|
|
}
|
|
}
|
|
|
|
#endif /* MODE_munch */
|