summaryrefslogtreecommitdiff
path: root/app/xlockmore/modes/ball.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:09:41 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:09:41 +0000
commit95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (patch)
tree06d3ffa4312e568c4157f69fe1bddaddec9bc497 /app/xlockmore/modes/ball.c
parent3928433848e2d6a9356f3d438a14b32a4f87f660 (diff)
Importing xlockmore 5.22
Diffstat (limited to 'app/xlockmore/modes/ball.c')
-rw-r--r--app/xlockmore/modes/ball.c540
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 */