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

335 lines
8.5 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* roll --- rolling ball of points */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)roll.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Copyright (c) 1995 by Charles Vidal <cvidal@ivsweb.com>
* http://www.chez.com/vidalc
*
* 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:
* 01-Nov-2000: Allocation checks
* 10-May-1997: Compatible with xscreensaver
* 1995: Written.
*/
#ifdef STANDALONE
#define MODE_roll
#define PROGCLASS "Roll"
#define HACK_INIT init_roll
#define HACK_DRAW draw_roll
#define roll_opts xlockmore_opts
#define DEFAULTS "*delay: 100000 \n" \
"*count: 25 \n" \
"*size: -64 \n" \
"*ncolors: 200 \n"
#define BRIGHT_COLORS
#define SMOOTH_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#ifdef MODE_roll
ModeSpecOpt roll_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct roll_description =
{"roll", "init_roll", "draw_roll", "release_roll",
"refresh_roll", "init_roll", (char *) NULL, &roll_opts,
100000, 25, 1, -64, 64, 0.6, "",
"Shows a rolling ball", 0, NULL};
#endif
#define MINPTS 1
#define MINSIZE 8
#define FACTOR 8.0
#define SPEED 25.0
typedef struct {
float t, u, v;
float t1, u1, v1;
} ptsstruct;
typedef struct {
ptsstruct *pts;
XPoint *p;
int maxpts, npts;
float alpha, theta, phi, r;
XPoint sphere, direction;
int color;
int width, height;
} rollstruct;
static rollstruct *rolls = (rollstruct *) NULL;
static void
createsphere(rollstruct * rp, int n1, int n2)
{
double i, j;
int n = 0;
for (i = 0.0; i < FACTOR * M_PI; i += (FACTOR * M_PI) / n1)
for (j = 0.0; j < FACTOR * M_PI; j += (FACTOR * M_PI) / n2) {
rp->pts[n].t1 = rp->r * COSF(i) * COSF(j);
rp->pts[n].u1 = rp->r * COSF(i) * SINF(j);
rp->pts[n].v1 = rp->r * SINF(i);
n++;
}
}
static void
rotation3d(rollstruct * rp)
{
float c1, c2, c3, c4, c5, c6, c7, c8, c9, x, y, z;
float sintheta, costheta;
float sinphi, cosphi;
float sinalpha, cosalpha;
int i;
sintheta = SINF(rp->theta);
costheta = COSF(rp->theta);
sinphi = SINF(rp->phi);
cosphi = COSF(rp->phi);
sinalpha = SINF(rp->alpha);
cosalpha = COSF(rp->alpha);
c1 = cosphi * costheta;
c2 = sinphi * costheta;
c3 = -sintheta;
c4 = cosphi * sintheta * sinalpha - sinphi * cosalpha;
c5 = sinphi * sintheta * sinalpha + cosphi * cosalpha;
c6 = costheta * sinalpha;
c7 = cosphi * sintheta * cosalpha + sinphi * sinalpha;
c8 = sinphi * sintheta * cosalpha - cosphi * sinalpha;
c9 = costheta * cosalpha;
for (i = 0; i < rp->maxpts; i++) {
x = rp->pts[i].t;
y = rp->pts[i].u;
z = rp->pts[i].v;
rp->pts[i].t = c1 * x + c2 * y + c3 * z;
rp->pts[i].u = c4 * x + c5 * y + c6 * z;
rp->pts[i].v = c7 * x + c8 * y + c9 * z;
}
}
static void
project(rollstruct * rp)
{
int i;
for (i = 0; i < rp->maxpts; i++) {
rp->p[i].x = (short) (2 * rp->pts[i].t);
rp->p[i].y = (short) (2 * rp->pts[i].u);
}
}
static void
free_roll(rollstruct *rp)
{
if (rp->pts != NULL) {
free(rp->pts);
rp->pts = (ptsstruct *) NULL;
}
if (rp->p != NULL) {
free(rp->p);
rp->p = (XPoint *) NULL;
}
}
void
init_roll(ModeInfo * mi)
{
int i;
int size = MI_SIZE(mi);
double ang;
rollstruct *rp;
if (rolls == NULL) {
if ((rolls = (rollstruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (rollstruct))) == NULL)
return;
}
rp = &rolls[MI_SCREEN(mi)];
ang = (double) NRAND(75) + 7.5;
rp->direction.x = (short) ((2 * (LRAND() & 1)) - 1) * (int)
(SPEED * SINF(ang * M_PI / 180.0));
rp->direction.y = (short) ((2 * (LRAND() & 1)) - 1) * (int)
(SPEED * COSF(ang * M_PI / 180.0));
rp->width = MI_WIDTH(mi);
rp->height = MI_HEIGHT(mi);
if (size < -MINSIZE)
rp->r = NRAND(MIN(-size, MAX(MINSIZE,
MIN(rp->width, rp->height) / 4)) - MINSIZE + 1) + MINSIZE;
else if (size < MINSIZE) {
if (!size)
rp->r = MAX(MINSIZE, MIN(rp->width, rp->height) / 4);
else
rp->r = MINSIZE;
} else
rp->r = MIN(size, MAX(MINSIZE,
MIN(rp->width, rp->height) / 4));
rp->sphere.x = NRAND(MAX(1, rp->width - 4 * (int) rp->r)) +
2 * (int) rp->r;
rp->sphere.y = NRAND(MAX(1, rp->height - 4 * (int) rp->r)) +
2 * (int) rp->r;
rp->alpha = 0;
rp->theta = 0;
rp->phi = 0;
rp->maxpts = MI_COUNT(mi);
if (rp->maxpts < -MINPTS) {
/* if rp->maxpts is random ... the size can change */
if (rp->pts != NULL) {
free(rp->pts);
rp->pts = (ptsstruct *) NULL;
}
rp->maxpts = NRAND(-rp->maxpts - MINPTS + 1) + MINPTS;
} else if (rp->maxpts < MINPTS)
rp->maxpts = MINPTS;
i = rp->maxpts;
rp->maxpts *= rp->maxpts;
rp->npts = 0;
if (rp->pts == NULL)
if ((rp->pts = (ptsstruct *) malloc(rp->maxpts *
sizeof (ptsstruct))) ==NULL) {
free_roll(rp);
return;
}
if (rp->p != NULL) {
free(rp->p);
rp->p = (XPoint *) NULL;
}
if (MI_NPIXELS(mi) > 2)
rp->color = NRAND(MI_NPIXELS(mi));
createsphere(rp, i, i);
MI_CLEARWINDOW(mi);
}
void
draw_roll(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
GC gc = MI_GC(mi);
int i;
rollstruct *rp;
if (rolls == NULL)
return;
rp = &rolls[MI_SCREEN(mi)];
if (rp->pts == NULL)
return;
MI_IS_DRAWN(mi) = True;
for (i = 0; i < rp->maxpts; i++) {
rp->pts[i].t = rp->pts[i].t1;
rp->pts[i].u = rp->pts[i].u1;
rp->pts[i].v = rp->pts[i].v1;
}
rp->alpha += ((FACTOR * M_PI) / 200.0);
rp->theta += ((FACTOR * M_PI) / 200.0);
rp->phi += ((FACTOR * M_PI) / 200.0);
if (rp->alpha > (FACTOR * M_PI))
rp->alpha -= (FACTOR * M_PI);
if (rp->theta > (FACTOR * M_PI))
rp->theta -= (FACTOR * M_PI);
if (rp->phi > (FACTOR * M_PI))
rp->phi -= (FACTOR * M_PI);
if (rp->npts) {
XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
XDrawPoints(display, window, gc, rp->p, rp->npts, CoordModeOrigin);
} else {
if (rp->p)
free(rp->p);
if ((rp->p = (XPoint *) malloc(rp->maxpts *
sizeof (XPoint))) == NULL) {
free_roll(rp);
return;
}
}
rotation3d(rp);
project(rp);
rp->npts = 0;
for (i = 0; i < rp->maxpts; i++) {
if (rp->pts[i].v > 0.0) {
rp->p[rp->npts].x += rp->sphere.x;
rp->p[rp->npts].y += rp->sphere.y;
rp->npts++;
}
}
if (MI_NPIXELS(mi) <= 2)
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
else {
rp->color = (rp->color + 1) % MI_NPIXELS(mi);
XSetForeground(display, gc, MI_PIXEL(mi, rp->color));
}
XDrawPoints(display, window, gc, rp->p, rp->npts, CoordModeOrigin);
if (rp->sphere.x >= rp->width - (int) rp->r && rp->direction.x > 0)
rp->direction.x = -rp->direction.x;
else if (rp->sphere.x <= (int) rp->r && rp->direction.x < 0)
rp->direction.x = -rp->direction.x;
else if (rp->sphere.x < rp->width - 2 * (int) rp->r ||
rp->sphere.x > 2 * (int) rp->r) {
if (rp->sphere.x >= rp->width - 2 * (int) rp->r && rp->direction.x > 0)
rp->direction.x = -rp->direction.x;
else if (rp->sphere.x <= 2 * (int) rp->r && rp->direction.x < 0)
rp->direction.x = -rp->direction.x;
}
if (rp->sphere.y >= rp->height - (int) rp->r && rp->direction.y > 0)
rp->direction.y = -rp->direction.y;
else if (rp->sphere.y <= (int) rp->r && rp->direction.y < 0)
rp->direction.y = -rp->direction.y;
else if (rp->sphere.y < rp->height - 2 * (int) rp->r ||
rp->sphere.y > 2 * (int) rp->r) {
if (rp->sphere.y >= rp->height - 2 * (int) rp->r && rp->direction.y > 0)
rp->direction.y = -rp->direction.y;
else if (rp->sphere.y <= 2 * (int) rp->r && rp->direction.y < 0)
rp->direction.y = -rp->direction.y;
}
rp->sphere.x += rp->direction.x;
rp->sphere.y += rp->direction.y;
}
void
release_roll(ModeInfo * mi)
{
if (rolls != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_roll(&rolls[screen]);
free(rolls);
rolls = (rollstruct *) NULL;
}
}
void
refresh_roll(ModeInfo * mi)
{
MI_CLEARWINDOW(mi);
}
#endif /* MODE_roll */