diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:09:41 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:09:41 +0000 |
commit | 95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (patch) | |
tree | 06d3ffa4312e568c4157f69fe1bddaddec9bc497 /app/xlockmore/modes/ball.c | |
parent | 3928433848e2d6a9356f3d438a14b32a4f87f660 (diff) |
Importing xlockmore 5.22
Diffstat (limited to 'app/xlockmore/modes/ball.c')
-rw-r--r-- | app/xlockmore/modes/ball.c | 540 |
1 files changed, 540 insertions, 0 deletions
diff --git a/app/xlockmore/modes/ball.c b/app/xlockmore/modes/ball.c new file mode 100644 index 000000000..81b09c5e7 --- /dev/null +++ b/app/xlockmore/modes/ball.c @@ -0,0 +1,540 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* ball --- bouncing balls with random drawing functions that leave a trail */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)ball.c 5.00 2000/11/01 xlockmore"; + +#endif + +/*- + * Copyright (c) 1995 by Heath Rice <rice@asl.dl.nec.com>. + * + * 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 + */ + +#ifdef STANDALONE +#define MODE_ball +#define PROGCLASS "Ball" +#define HACK_INIT init_ball +#define HACK_DRAW draw_ball +#define ball_opts xlockmore_opts +#define DEFAULTS "*delay: 10000 \n" \ + "*count: 10 \n" \ + "*cycles: 20 \n" \ + "*size: -100 \n" \ + "*ncolors: 200 \n" +#include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +#include "xlock.h" /* in xlockmore distribution */ +#endif /* STANDALONE */ + +#ifdef MODE_ball + +ModeSpecOpt ball_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +const ModStruct ball_description = +{"ball", "init_ball", "draw_ball", "release_ball", + "refresh_ball", "init_ball", (char *) NULL, &ball_opts, + 10000, 10, 20, -100, 64, 1.0, "", + "Shows bouncing balls", 0, NULL}; + +#endif + +#define NONE 0 /* not in a window */ +#define V 1 /* vertical */ +#define H 2 /* horizontal */ +#define B 3 /* ball */ + +#define MINBALLS 1 +#define MINSIZE 2 +#define MINGRIDSIZE 4 + +#define DEFNO 6 +#define SPEED 156 +#define SQLIMIT (SPEED*SPEED/(30*30)) /* square of lower speed limit */ +#define RATE 600 + +typedef struct { + int x, y; /* x and y coords */ + int dx, dy; /* x and y velocity */ + int rad; + int bounce; + int dyold; + int started; + int def; + GC GcF, GcB; +} balltype; + +typedef struct { + Bool painted; + balltype *bt; + int rad; + int size; + int width, height; + int bounce; + int nballs; + int dispx, dispy; +} ballstruct; + +static ballstruct *balls = (ballstruct *) NULL; + +static void +collided(ModeInfo * mi, int i, int n, int *dx, int *dy, int td) +{ + ballstruct *bp = &balls[MI_SCREEN(mi)]; + balltype *bti = &bp->bt[i]; + balltype *btn = &bp->bt[n]; + int rx1, ry1, rx2, ry2; + int Vx1, Vy1, Vx2, Vy2; + int NVx1, NVy1, NVx2, NVy2; + + float Ux1, Uy1, Ux2, Uy2; + float mag1, mag2, imp; + + rx1 = bti->x; + ry1 = bti->y; + Vx1 = bti->dx; + Vy1 = bti->dy; + + rx2 = btn->x; + ry2 = btn->y; + Vx2 = btn->dx; + Vy2 = btn->dy; + + Ux1 = rx1 - rx2; + Uy1 = ry1 - ry2; + mag1 = sqrt(((Ux1 * Ux1) + (Uy1 * Uy1))); + Ux1 = Ux1 / mag1; + Uy1 = Uy1 / mag1; + + Ux2 = rx2 - rx1; + Uy2 = ry2 - ry1; + mag2 = sqrt(((Ux2 * Ux2) + (Uy2 * Uy2))); + Ux2 = Ux2 / mag2; + Uy2 = Uy2 / mag2; + + imp = ((Vx1 * Ux2) + (Vy1 * Uy2)) + ((Vx2 * Ux1) + (Vy2 * Uy1)); + + NVx1 = Vx1 + (int) (imp * Ux1); + NVy1 = Vy1 + (int) (imp * Uy1); + + NVx2 = Vx2 + (int) (imp * Ux2); + NVy2 = Vy2 + (int) (imp * Uy2); + + bti->dx = NVx1; + bti->dy = NVy1; + + btn->dx = NVx2; + btn->dy = NVy2; + + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), btn->GcB, + btn->x - (btn->rad / 2), btn->y - (btn->rad / 2), + btn->rad, btn->rad, 0, 360 * 64); + if (bp->dispx > 100) { + *dx = (td * btn->dx) / RATE; + *dy = (td * btn->dy) / RATE; + } else { + *dx = (td * btn->dx) / 150; + *dy = (td * btn->dy) / 150; + } + + btn->x += (*dx / 2); + btn->y += (*dy / 2); + XFillArc(MI_DISPLAY(mi), MI_WINDOW(mi), btn->GcF, + btn->x - (btn->rad / 2), btn->y - (btn->rad / 2), + btn->rad, btn->rad, 0, 360 * 64); + + if (bp->dispx > 100) { + *dx = (td * bti->dx) / RATE; + *dy = (td * bti->dy) / RATE; + } else { + *dx = (td * bti->dx) / 150; + *dy = (td * bti->dy) / 150; + } + + bti->x += (*dx / 2); + bti->y += (*dy / 2); +} + +static int +inwin(ballstruct * bp, int x, int y, int *n, int rad) +{ + int i, diffx, diffy; + + if ((x < 0) || (x > bp->dispx)) { + return (V); + } + if ((y < 0) || (y > bp->dispy)) { + return (H); + } + if (bp->dispx > 100) { + for (i = 0; i < bp->nballs; i++) { + if ((i == (*n)) || (!bp->bt[i].def)) + continue; + diffx = (bp->bt[i].x - x); + diffy = (bp->bt[i].y - y); + if ((diffx * diffx + diffy * diffy) < + (((rad / 2) * (rad / 2) * 2) + + ((bp->bt[i].rad / 2) * (bp->bt[i].rad / 2) * 2))) { + (*n) = i; + return (B); + } + } + } + return (NONE); +} + +static void +randomball(ModeInfo * mi, int i) +{ + ballstruct *bp = &balls[MI_SCREEN(mi)]; + balltype *bti = &bp->bt[i]; + Display *display = MI_DISPLAY(mi); + int x, y, bn; + int dum; + int attempts; + unsigned long randbg; + + attempts = 0; + if (bp->bounce == -2) + bn = 30 + NRAND(69L); + else + bn = bp->bounce; + + if (bn > 100) + bn = 100; + if (bn < 0) + bn = 0; + bn = (0 - bn); + + if (bp->dispx > 100) { + bti->dx = NRAND(2L * SPEED) + SPEED; + bti->dy = NRAND(2L * SPEED) + (SPEED / 2); + } else { + bti->dx = NRAND(4L * SPEED) + (SPEED / 20); + bti->dy = NRAND(2L * SPEED) + (SPEED / 40); + } + + switch (NRAND(9L) % 2) { + case 0: + break; + case 1: + bti->dx = (0 - bti->dx); + break; + } + + bti->bounce = bn; + bti->dyold = 0; + bti->rad = bp->rad; /* Pretty lame... should be different sizes */ + + do { + dum = i; + x = NRAND((long) bp->dispx); + y = 0; + attempts++; + if (attempts > 5) { + bti->def = 0; + return; + } + } while ((inwin(bp, x, y, &dum, bti->rad) != NONE) || + (inwin(bp, bti->dx + x, bti->dy + y, &dum, bti->rad) != NONE)); + + bti->def = 1; + bti->x = x; + bti->y = y; + + /* set background color for ball */ + + if (MI_NPIXELS(mi) > 2) { + randbg = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + } else { + randbg = MI_BLACK_PIXEL(mi); + } + XSetForeground(display, bti->GcB, randbg); + + /* set foreground color for ball */ + + if (MI_NPIXELS(mi) > 2) { + randbg = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + } else { + randbg = MI_WHITE_PIXEL(mi); + } + XSetForeground(display, bti->GcF, randbg); + + XFillArc(display, MI_WINDOW(mi), + bti->GcB, bti->x - (bti->rad / 2), bti->y - (bti->rad / 2), + bti->rad, bti->rad, 0, 360 * 64); +} + +static void +free_ball(Display *display, ballstruct *bp) +{ + if (bp->bt != NULL) { + int i; + + for (i = 0; i < bp->nballs; i++) { + if (bp->bt[i].GcF != None) { + XFreeGC(display, bp->bt[i].GcF); + bp->bt[i].GcF = None; + } + if (bp->bt[i].GcB != None) { + XFreeGC(display, bp->bt[i].GcB); + bp->bt[i].GcB = None; + } + } + free(bp->bt); + bp->bt = (balltype *) NULL; + } +} + +void +init_ball(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int GcLp, i; + int size = MI_SIZE(mi); + ballstruct *bp; + + if (balls == NULL) { + if ((balls = (ballstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (ballstruct))) == NULL) + return; + } + bp = &balls[MI_SCREEN(mi)]; + + bp->bounce = 85; + bp->width = MI_WIDTH(mi); + bp->height = MI_HEIGHT(mi); + + bp->nballs = MI_COUNT(mi); + if (bp->nballs < -MINBALLS) { + /* if bp->nballs is random ... the size can change */ + if (bp->bt != NULL) { + free(bp->bt); + bp->bt = (balltype *) NULL; + } + bp->nballs = NRAND(-bp->nballs - MINBALLS + 1) + MINBALLS; + } else if (bp->nballs < MINBALLS) + bp->nballs = MINBALLS; + if (bp->bt == NULL) { + if ((bp->bt = (balltype *) calloc(bp->nballs, sizeof (balltype))) == + NULL) { + free_ball(display, bp); + return; + } + } + if (size == 0 || + MINGRIDSIZE * size > bp->width || MINGRIDSIZE * size > bp->height) { + bp->rad = MAX(MINSIZE, MIN(bp->width, bp->height) / MINGRIDSIZE); + } else { + if (size < -MINSIZE) + bp->rad = NRAND(MIN(-size, MAX(MINSIZE, MIN(bp->width, bp->height) / + MINGRIDSIZE)) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) + bp->rad = MINSIZE; + else + bp->rad = MIN(size, MAX(MINSIZE, MIN(bp->width, bp->height) / + MINGRIDSIZE)); + } + + /* clearballs */ + MI_CLEARWINDOW(mi); + bp->painted = False; + XFlush(display); + if (bp->nballs <= 0) + bp->nballs = 1; + if (!bp->bt[0].GcB) { + XGCValues gcv; + + gcv.foreground = MI_WHITE_PIXEL(mi); + gcv.background = MI_BLACK_PIXEL(mi); + for (GcLp = 0; GcLp < bp->nballs; GcLp++) { + if ((bp->bt[GcLp].GcB = XCreateGC(display, window, + GCForeground | GCBackground, &gcv)) == None) { + free_ball(display, bp); + return; + } + if ((bp->bt[GcLp].GcF = XCreateGC(display, window, + GCForeground | GCBackground, &gcv)) == None) { + free_ball(display, bp); + return; + } + } + } + for (GcLp = 0; GcLp < bp->nballs; GcLp++) { + if (MI_NPIXELS(mi) > 2) { + XSetFunction(display, bp->bt[GcLp].GcB, NRAND(16L)); + XSetFunction(display, bp->bt[GcLp].GcF, NRAND(16L)); + } else { + XSetFunction(display, bp->bt[GcLp].GcB, NRAND(8L)); + XSetFunction(display, bp->bt[GcLp].GcF, NRAND(8L)); + } + } + + bp->dispx = MI_WIDTH(mi); + bp->dispy = MI_HEIGHT(mi); + + XFlush(display); + for (i = 0; i < bp->nballs; i++) { + randomball(mi, i); + } +} + +void +draw_ball(ModeInfo * mi) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int i, n; + int td; + int dx, dy; + int redo; + ballstruct *bp; + + if (balls == NULL) + return; + bp = &balls[MI_SCREEN(mi)]; + if (bp->bt == NULL) + return; + + MI_IS_DRAWN(mi) = True; + td = 10; + bp->painted = True; + for (i = 0; i < bp->nballs; i++) { + if (!bp->bt[i].def) + randomball(mi, i); + } + + for (i = 0; i < bp->nballs; i++) { + if (!bp->bt[i].def) { + continue; + } + XFillArc(display, window, bp->bt[i].GcB, + bp->bt[i].x - (bp->bt[i].rad / 2), bp->bt[i].y - (bp->bt[i].rad / 2), + bp->bt[i].rad, bp->bt[i].rad, 0, 360 * 64); + redo = 0; + if (((bp->bt[i].dx * bp->bt[i].dx + bp->bt[i].dy * bp->bt[i].dy) < + SQLIMIT) && (bp->bt[i].y >= (bp->dispy - 3))) { + redo = 25; + } + do { + if (bp->dispx > 100) { + dx = (td * bp->bt[i].dx) / RATE; + dy = (td * bp->bt[i].dy) / RATE; + } else { + dx = (td * bp->bt[i].dx) / 150; + dy = (td * bp->bt[i].dy) / 150; + } + + if (redo > 5) { + redo = 0; + randomball(mi, i); + if (!bp->bt[i].def) + continue; + XFillArc(display, window, bp->bt[i].GcF, + bp->bt[i].x - (bp->bt[i].rad / 2), + bp->bt[i].y - (bp->bt[i].rad / 2), + bp->bt[i].rad, bp->bt[i].rad, 0, 360 * 64); + } + n = i; + switch (inwin(bp, dx + bp->bt[i].x, dy + bp->bt[i].y, &n, + bp->bt[i].rad)) { + case NONE: + bp->bt[i].x += dx; + bp->bt[i].y += dy; + redo = 0; + break; + case V: + bp->bt[i].dx = (int) (((float) bp->bt[i].bounce * + (float) bp->bt[i].dx) / (float) 100); + redo++; + break; + case H: + bp->bt[i].dy = (int) (((float) bp->bt[i].bounce * + (float) bp->bt[i].dy) / (float) 100); + if (bp->bt[i].bounce != 100) { + if ((bp->bt[i].y >= (bp->dispy - 3)) && (bp->bt[i].dy > -250) && + (bp->bt[i].dy < 0)) { + redo = 15; + } + if ((bp->bt[i].y >= (bp->dispy - 3)) && + (bp->bt[i].dy == bp->bt[i].dyold)) { + redo = 10; + } + bp->bt[i].dyold = bp->bt[i].dy; + } + redo++; + break; + case B: + if (redo > 5) { + if (bp->bt[i].y >= (bp->dispy - 3)) { + randomball(mi, i); + redo = 0; + } else if (bp->bt[n].y >= (bp->dispy - 3)) { + randomball(mi, n); + redo = 0; + } else + redo = 0; + } else { + collided(mi, i, n, &dx, &dy, td); + redo = 0; + } + break; + } + } + while (redo); + bp->bt[i].dy += td; + + if (bp->bt[i].def) + XFillArc(display, window, bp->bt[i].GcF, + bp->bt[i].x - (bp->bt[i].rad / 2), bp->bt[i].y - (bp->bt[i].rad / 2), + bp->bt[i].rad, bp->bt[i].rad, 0, 360 * 64); + } + + XFlush(display); +} + +void +release_ball(ModeInfo * mi) +{ + if (balls != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) + free_ball(MI_DISPLAY(mi), &balls[screen]); + free(balls); + balls = (ballstruct *) NULL; + } +} + +void +refresh_ball(ModeInfo * mi) +{ + ballstruct *bp; + + if (balls == NULL) + return; + bp = &balls[MI_SCREEN(mi)]; + + if (bp->painted) + MI_CLEARWINDOW(mi); +} + +#endif /* MODE_ball */ |