/* -*- 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 * 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 */