/* xscreensaver, Copyright (c) 1999-2018 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.
*/
#include <math.h>
#include "screenhack.h"
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
# include "xdbe.h"
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
#define countof(x) (sizeof(x)/sizeof(*(x)))
#define ABS(x) ((x)<0?-(x):(x))
#define MAX(x,y) ((x)<(y)?(y):(x))
#define MIN(x,y) ((x)>(y)?(y):(x))
#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
#define RANDSIGN() ((random() & 1) ? 1 : -1)
struct state {
Display *dpy;
Window window;
int delay;
Bool dbuf;
struct disc *discs[4];
int x, y, size, size2;
GC ptr_gc;
GC erase_gc;
XWindowAttributes xgwa;
Pixmap b, ba, bb; /* double-buffer to reduce flicker */
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
XdbeBackBuffer backb;
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
};
struct disc {
int theta; /* 0 - 360*64 */
int velocity;
int acceleration;
int limit;
GC gc;
void (*draw) (struct state *, Drawable, struct disc *,
int x, int y, int radius);
};
static void
draw_letters (struct state *st, Drawable d, struct disc *disc,
int x, int y, int radius)
{
XPoint points[50];
double th2 = 2 * M_PI * (disc->theta / ((double) 360*64));
double th;
/* W */
th = th2;
points[0].x = x + radius * 0.8 * cos(th - 0.07);
points[0].y = y + radius * 0.8 * sin(th - 0.07);
points[1].x = x + radius * 0.7 * cos(th - 0.05);
points[1].y = y + radius * 0.7 * sin(th - 0.05);
points[2].x = x + radius * 0.78 * cos(th);
points[2].y = y + radius * 0.78 * sin(th);
points[3].x = x + radius * 0.7 * cos(th + 0.05);
points[3].y = y + radius * 0.7 * sin(th + 0.05);
points[4].x = x + radius * 0.8 * cos(th + 0.07);
points[4].y = y + radius * 0.8 * sin(th + 0.07);
XDrawLines (st->dpy, d, disc->gc, points, 5, CoordModeOrigin);
/* 30 (1) */
th = th2 + (2 * M_PI * 0.08333);
points[0].x = x + radius * 0.78 * cos(th - 0.13);
points[0].y = y + radius * 0.78 * sin(th - 0.13);
points[1].x = x + radius * 0.8 * cos(th - 0.08);
points[1].y = y + radius * 0.8 * sin(th - 0.08);
points[2].x = x + radius * 0.78 * cos(th - 0.03);
points[2].y = y + radius * 0.78 * sin(th - 0.03);
points[3].x = x + radius * 0.76 * cos(th - 0.03);
points[3].y = y + radius * 0.76 * sin(th - 0.03);
points[4].x = x + radius * 0.75 * cos(th - 0.08);
points[4].y = y + radius * 0.75 * sin(th - 0.08);
points[5].x = x + radius * 0.74 * cos(th - 0.03);
points[5].y = y + radius * 0.74 * sin(th - 0.03);
points[6].x = x + radius * 0.72 * cos(th - 0.03);
points[6].y = y + radius * 0.72 * sin(th - 0.03);
points[7].x = x + radius * 0.7 * cos(th - 0.08);
points[7].y = y + radius * 0.7 * sin(th - 0.08);
points[8].x = x + radius * 0.72 * cos(th - 0.13);
points[8].y = y + radius * 0.72 * sin(th - 0.13);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* 30 (2) */
points[0].x = x + radius * 0.78 * cos(th + 0.03);
points[0].y = y + radius * 0.78 * sin(th + 0.03);
points[1].x = x + radius * 0.8 * cos(th + 0.08);
points[1].y = y + radius * 0.8 * sin(th + 0.08);
points[2].x = x + radius * 0.78 * cos(th + 0.13);
points[2].y = y + radius * 0.78 * sin(th + 0.13);
points[3].x = x + radius * 0.72 * cos(th + 0.13);
points[3].y = y + radius * 0.72 * sin(th + 0.13);
points[4].x = x + radius * 0.7 * cos(th + 0.08);
points[4].y = y + radius * 0.7 * sin(th + 0.08);
points[5].x = x + radius * 0.72 * cos(th + 0.03);
points[5].y = y + radius * 0.72 * sin(th + 0.03);
points[6] = points[0];
XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin);
/* 33 (1) */
th = th2 + (2 * M_PI * 0.16666);
points[0].x = x + radius * 0.78 * cos(th - 0.13);
points[0].y = y + radius * 0.78 * sin(th - 0.13);
points[1].x = x + radius * 0.8 * cos(th - 0.08);
points[1].y = y + radius * 0.8 * sin(th - 0.08);
points[2].x = x + radius * 0.78 * cos(th - 0.03);
points[2].y = y + radius * 0.78 * sin(th - 0.03);
points[3].x = x + radius * 0.76 * cos(th - 0.03);
points[3].y = y + radius * 0.76 * sin(th - 0.03);
points[4].x = x + radius * 0.75 * cos(th - 0.08);
points[4].y = y + radius * 0.75 * sin(th - 0.08);
points[5].x = x + radius * 0.74 * cos(th - 0.03);
points[5].y = y + radius * 0.74 * sin(th - 0.03);
points[6].x = x + radius * 0.72 * cos(th - 0.03);
points[6].y = y + radius * 0.72 * sin(th - 0.03);
points[7].x = x + radius * 0.7 * cos(th - 0.08);
points[7].y = y + radius * 0.7 * sin(th - 0.08);
points[8].x = x + radius * 0.72 * cos(th - 0.13);
points[8].y = y + radius * 0.72 * sin(th - 0.13);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* 33 (2) */
points[0].x = x + radius * 0.78 * cos(th + 0.03);
points[0].y = y + radius * 0.78 * sin(th + 0.03);
points[1].x = x + radius * 0.8 * cos(th + 0.08);
points[1].y = y + radius * 0.8 * sin(th + 0.08);
points[2].x = x + radius * 0.78 * cos(th + 0.13);
points[2].y = y + radius * 0.78 * sin(th + 0.13);
points[3].x = x + radius * 0.76 * cos(th + 0.13);
points[3].y = y + radius * 0.76 * sin(th + 0.13);
points[4].x = x + radius * 0.75 * cos(th + 0.08);
points[4].y = y + radius * 0.75 * sin(th + 0.08);
points[5].x = x + radius * 0.74 * cos(th + 0.13);
points[5].y = y + radius * 0.74 * sin(th + 0.13);
points[6].x = x + radius * 0.72 * cos(th + 0.13);
points[6].y = y + radius * 0.72 * sin(th + 0.13);
points[7].x = x + radius * 0.7 * cos(th + 0.08);
points[7].y = y + radius * 0.7 * sin(th + 0.08);
points[8].x = x + radius * 0.72 * cos(th + 0.03);
points[8].y = y + radius * 0.72 * sin(th + 0.03);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* N */
th = th2 + (2 * M_PI * 0.25);
points[0].x = x + radius * 0.7 * cos(th - 0.05);
points[0].y = y + radius * 0.7 * sin(th - 0.05);
points[1].x = x + radius * 0.8 * cos(th - 0.05);
points[1].y = y + radius * 0.8 * sin(th - 0.05);
points[2].x = x + radius * 0.7 * cos(th + 0.05);
points[2].y = y + radius * 0.7 * sin(th + 0.05);
points[3].x = x + radius * 0.8 * cos(th + 0.05);
points[3].y = y + radius * 0.8 * sin(th + 0.05);
XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin);
/* 3 */
th = th2 + (2 * M_PI * 0.33333);
points[0].x = x + radius * 0.78 * cos(th - 0.05);
points[0].y = y + radius * 0.78 * sin(th - 0.05);
points[1].x = x + radius * 0.8 * cos(th);
points[1].y = y + radius * 0.8 * sin(th);
points[2].x = x + radius * 0.78 * cos(th + 0.05);
points[2].y = y + radius * 0.78 * sin(th + 0.05);
points[3].x = x + radius * 0.76 * cos(th + 0.05);
points[3].y = y + radius * 0.76 * sin(th + 0.05);
points[4].x = x + radius * 0.75 * cos(th);
points[4].y = y + radius * 0.75 * sin(th);
points[5].x = x + radius * 0.74 * cos(th + 0.05);
points[5].y = y + radius * 0.74 * sin(th + 0.05);
points[6].x = x + radius * 0.72 * cos(th + 0.05);
points[6].y = y + radius * 0.72 * sin(th + 0.05);
points[7].x = x + radius * 0.7 * cos(th);
points[7].y = y + radius * 0.7 * sin(th);
points[8].x = x + radius * 0.72 * cos(th - 0.05);
points[8].y = y + radius * 0.72 * sin(th - 0.05);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* 6 */
th = th2 + (2 * M_PI * 0.41666);
points[0].x = x + radius * 0.78 * cos(th + 0.05);
points[0].y = y + radius * 0.78 * sin(th + 0.05);
points[1].x = x + radius * 0.8 * cos(th);
points[1].y = y + radius * 0.8 * sin(th);
points[2].x = x + radius * 0.78 * cos(th - 0.05);
points[2].y = y + radius * 0.78 * sin(th - 0.05);
points[3].x = x + radius * 0.72 * cos(th - 0.05);
points[3].y = y + radius * 0.72 * sin(th - 0.05);
points[4].x = x + radius * 0.7 * cos(th);
points[4].y = y + radius * 0.7 * sin(th);
points[5].x = x + radius * 0.72 * cos(th + 0.05);
points[5].y = y + radius * 0.72 * sin(th + 0.05);
points[6].x = x + radius * 0.74 * cos(th + 0.05);
points[6].y = y + radius * 0.74 * sin(th + 0.05);
points[7].x = x + radius * 0.76 * cos(th);
points[7].y = y + radius * 0.76 * sin(th);
points[8].x = x + radius * 0.74 * cos(th - 0.05);
points[8].y = y + radius * 0.74 * sin(th - 0.05);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* E */
th = th2 + (2 * M_PI * 0.5);
points[0].x = x + radius * 0.8 * cos(th + 0.05);
points[0].y = y + radius * 0.8 * sin(th + 0.05);
points[1].x = x + radius * 0.8 * cos(th - 0.05);
points[1].y = y + radius * 0.8 * sin(th - 0.05);
points[2].x = x + radius * 0.75 * cos(th - 0.05);
points[2].y = y + radius * 0.75 * sin(th - 0.05);
points[3].x = x + radius * 0.75 * cos(th + 0.025);
points[3].y = y + radius * 0.75 * sin(th + 0.025);
points[4].x = x + radius * 0.75 * cos(th - 0.05);
points[4].y = y + radius * 0.75 * sin(th - 0.05);
points[5].x = x + radius * 0.7 * cos(th - 0.05);
points[5].y = y + radius * 0.7 * sin(th - 0.05);
points[6].x = x + radius * 0.7 * cos(th + 0.05);
points[6].y = y + radius * 0.7 * sin(th + 0.05);
XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin);
/* 12 (1) */
th = th2 + (2 * M_PI * 0.58333);
points[0].x = x + radius * 0.77 * cos(th - 0.06);
points[0].y = y + radius * 0.77 * sin(th - 0.06);
points[1].x = x + radius * 0.8 * cos(th - 0.03);
points[1].y = y + radius * 0.8 * sin(th - 0.03);
points[2].x = x + radius * 0.7 * cos(th - 0.03);
points[2].y = y + radius * 0.7 * sin(th - 0.03);
XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin);
/* 12 (2) */
points[0].x = x + radius * 0.78 * cos(th + 0.02);
points[0].y = y + radius * 0.78 * sin(th + 0.02);
points[1].x = x + radius * 0.8 * cos(th + 0.07);
points[1].y = y + radius * 0.8 * sin(th + 0.07);
points[2].x = x + radius * 0.78 * cos(th + 0.11);
points[2].y = y + radius * 0.78 * sin(th + 0.11);
points[3].x = x + radius * 0.76 * cos(th + 0.11);
points[3].y = y + radius * 0.76 * sin(th + 0.11);
points[4].x = x + radius * 0.74 * cos(th + 0.02);
points[4].y = y + radius * 0.74 * sin(th + 0.02);
points[5].x = x + radius * 0.71 * cos(th + 0.03);
points[5].y = y + radius * 0.71 * sin(th + 0.03);
points[6].x = x + radius * 0.7 * cos(th + 0.03);
points[6].y = y + radius * 0.7 * sin(th + 0.03);
points[7].x = x + radius * 0.7 * cos(th + 0.13);
points[7].y = y + radius * 0.7 * sin(th + 0.13);
XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin);
/* 15 (1) */
th = th2 + (2 * M_PI * 0.66666);
points[0].x = x + radius * 0.77 * cos(th - 0.06);
points[0].y = y + radius * 0.77 * sin(th - 0.06);
points[1].x = x + radius * 0.8 * cos(th - 0.03);
points[1].y = y + radius * 0.8 * sin(th - 0.03);
points[2].x = x + radius * 0.7 * cos(th - 0.03);
points[2].y = y + radius * 0.7 * sin(th - 0.03);
XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin);
/* 15 (2) */
points[0].x = x + radius * 0.8 * cos(th + 0.11);
points[0].y = y + radius * 0.8 * sin(th + 0.11);
points[1].x = x + radius * 0.8 * cos(th + 0.02);
points[1].y = y + radius * 0.8 * sin(th + 0.02);
points[2].x = x + radius * 0.76 * cos(th + 0.02);
points[2].y = y + radius * 0.76 * sin(th + 0.02);
points[3].x = x + radius * 0.77 * cos(th + 0.06);
points[3].y = y + radius * 0.77 * sin(th + 0.06);
points[4].x = x + radius * 0.76 * cos(th + 0.10);
points[4].y = y + radius * 0.76 * sin(th + 0.10);
points[5].x = x + radius * 0.73 * cos(th + 0.11);
points[5].y = y + radius * 0.73 * sin(th + 0.11);
points[6].x = x + radius * 0.72 * cos(th + 0.10);
points[6].y = y + radius * 0.72 * sin(th + 0.10);
points[7].x = x + radius * 0.7 * cos(th + 0.06);
points[7].y = y + radius * 0.7 * sin(th + 0.06);
points[8].x = x + radius * 0.72 * cos(th + 0.02);
points[8].y = y + radius * 0.72 * sin(th + 0.02);
XDrawLines (st->dpy, d, disc->gc, points, 9, CoordModeOrigin);
/* S */
th = th2 + (2 * M_PI * 0.75);
points[0].x = x + radius * 0.78 * cos(th + 0.05);
points[0].y = y + radius * 0.78 * sin(th + 0.05);
points[1].x = x + radius * 0.8 * cos(th);
points[1].y = y + radius * 0.8 * sin(th);
points[2].x = x + radius * 0.78 * cos(th - 0.05);
points[2].y = y + radius * 0.78 * sin(th - 0.05);
points[3].x = x + radius * 0.76 * cos(th - 0.05);
points[3].y = y + radius * 0.76 * sin(th - 0.05);
points[4].x = x + radius * 0.74 * cos(th + 0.05);
points[4].y = y + radius * 0.74 * sin(th + 0.05);
points[5].x = x + radius * 0.72 * cos(th + 0.05);
points[5].y = y + radius * 0.72 * sin(th + 0.05);
points[6].x = x + radius * 0.7 * cos(th);
points[6].y = y + radius * 0.7 * sin(th);
points[7].x = x + radius * 0.72 * cos(th - 0.05);
points[7].y = y + radius * 0.72 * sin(th - 0.05);
XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin);
/* 21 (1) */
th = th2 + (2 * M_PI * 0.83333);
points[0].x = x + radius * 0.78 * cos(th - 0.13);
points[0].y = y + radius * 0.78 * sin(th - 0.13);
points[1].x = x + radius * 0.8 * cos(th - 0.08);
points[1].y = y + radius * 0.8 * sin(th - 0.08);
points[2].x = x + radius * 0.78 * cos(th - 0.03);
points[2].y = y + radius * 0.78 * sin(th - 0.03);
points[3].x = x + radius * 0.76 * cos(th - 0.03);
points[3].y = y + radius * 0.76 * sin(th - 0.03);
points[4].x = x + radius * 0.74 * cos(th - 0.12);
points[4].y = y + radius * 0.74 * sin(th - 0.12);
points[5].x = x + radius * 0.71 * cos(th - 0.13);
points[5].y = y + radius * 0.71 * sin(th - 0.13);
points[6].x = x + radius * 0.7 * cos(th - 0.13);
points[6].y = y + radius * 0.7 * sin(th - 0.13);
points[7].x = x + radius * 0.7 * cos(th - 0.02);
points[7].y = y + radius * 0.7 * sin(th - 0.02);
XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin);
/* 21 (2) */
points[0].x = x + radius * 0.77 * cos(th + 0.03);
points[0].y = y + radius * 0.77 * sin(th + 0.03);
points[1].x = x + radius * 0.8 * cos(th + 0.06);
points[1].y = y + radius * 0.8 * sin(th + 0.06);
points[2].x = x + radius * 0.7 * cos(th + 0.06);
points[2].y = y + radius * 0.7 * sin(th + 0.06);
XDrawLines (st->dpy, d, disc->gc, points, 3, CoordModeOrigin);
/* 24 (1) */
th = th2 + (2 * M_PI * 0.91666);
points[0].x = x + radius * 0.78 * cos(th - 0.13);
points[0].y = y + radius * 0.78 * sin(th - 0.13);
points[1].x = x + radius * 0.8 * cos(th - 0.08);
points[1].y = y + radius * 0.8 * sin(th - 0.08);
points[2].x = x + radius * 0.78 * cos(th - 0.03);
points[2].y = y + radius * 0.78 * sin(th - 0.03);
points[3].x = x + radius * 0.76 * cos(th - 0.03);
points[3].y = y + radius * 0.76 * sin(th - 0.03);
points[4].x = x + radius * 0.74 * cos(th - 0.12);
points[4].y = y + radius * 0.74 * sin(th - 0.12);
points[5].x = x + radius * 0.71 * cos(th - 0.13);
points[5].y = y + radius * 0.71 * sin(th - 0.13);
points[6].x = x + radius * 0.7 * cos(th - 0.13);
points[6].y = y + radius * 0.7 * sin(th - 0.13);
points[7].x = x + radius * 0.7 * cos(th - 0.02);
points[7].y = y + radius * 0.7 * sin(th - 0.02);
XDrawLines (st->dpy, d, disc->gc, points, 8, CoordModeOrigin);
/* 24 (2) */
points[0].x = x + radius * 0.69 * cos(th + 0.09);
points[0].y = y + radius * 0.69 * sin(th + 0.09);
points[1].x = x + radius * 0.8 * cos(th + 0.09);
points[1].y = y + radius * 0.8 * sin(th + 0.09);
points[2].x = x + radius * 0.72 * cos(th + 0.01);
points[2].y = y + radius * 0.72 * sin(th + 0.01);
points[3].x = x + radius * 0.72 * cos(th + 0.13);
points[3].y = y + radius * 0.72 * sin(th + 0.13);
XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin);
}
static void
draw_ticks (struct state *st, Drawable d, struct disc *disc,
int x, int y, int radius)
{
XSegment segs[72];
int i;
double tick = (M_PI * 2) / 72;
for (i = 0; i < 72; i++)
{
int radius2 = radius;
double th = (i * tick) + (2 * M_PI * (disc->theta / ((double) 360*64)));
if (i % 6)
radius2 -= radius / 16;
else
radius2 -= radius / 8;
segs[i].x1 = x + radius * cos(th);
segs[i].y1 = y + radius * sin(th);
segs[i].x2 = x + radius2 * cos(th);
segs[i].y2 = y + radius2 * sin(th);
}
XDrawSegments (st->dpy, d, disc->gc, segs, countof(segs));
draw_letters (st, d, disc, x, y, radius);
}
static void
draw_thin_arrow (struct state *st, Drawable d, struct disc *disc,
int x, int y, int radius)
{
XPoint points[3];
double th;
int radius2;
double tick = ((M_PI * 2) / 72) * 2;
radius *= 0.9;
radius2 = radius - (radius / 8) * 3;
th = 2 * M_PI * (disc->theta / ((double) 360*64));
points[0].x = x + radius * cos(th); /* tip */
points[0].y = y + radius * sin(th);
points[1].x = x + radius2 * cos(th - tick); /* tip left */
points[1].y = y + radius2 * sin(th - tick);
points[2].x = x + radius2 * cos(th + tick); /* tip right */
points[2].y = y + radius2 * sin(th + tick);
XDrawLine (st->dpy, d, disc->gc,
(int) (x + radius2 * cos(th)),
(int) (y + radius2 * sin(th)),
(int) (x + -radius * cos(th)),
(int) (y + -radius * sin(th)));
XFillPolygon (st->dpy, d, disc->gc, points, 3, Convex, CoordModeOrigin);
}
static void
draw_thick_arrow (struct state *st, Drawable d, struct disc *disc,
int x, int y, int radius)
{
XPoint points[10];
double th;
int radius2, radius3;
double tick = ((M_PI * 2) / 72) * 2;
radius *= 0.9;
radius2 = radius - (radius / 8) * 3;
radius3 = radius - (radius / 8) * 2;
th = 2 * M_PI * (disc->theta / ((double) 360*64));
points[0].x = x + radius * cos(th); /* tip */
points[0].y = y + radius * sin(th);
points[1].x = x + radius2 * cos(th - tick); /* tip left */
points[1].y = y + radius2 * sin(th - tick);
points[2].x = x + radius2 * cos(th + tick); /* tip right */
points[2].y = y + radius2 * sin(th + tick);
points[3] = points[0];
XDrawLines (st->dpy, d, disc->gc, points, 4, CoordModeOrigin);
points[0].x = x + radius2 * cos(th - tick/2); /* top left */
points[0].y = y + radius2 * sin(th - tick/2);
points[1].x = x + -radius2 * cos(th + tick/2); /* bottom left */
points[1].y = y + -radius2 * sin(th + tick/2);
points[2].x = x + -radius3 * cos(th); /* bottom */
points[2].y = y + -radius3 * sin(th);
points[3].x = x + -radius * cos(th); /* bottom spike */
points[3].y = y + -radius * sin(th);
points[4] = points[2]; /* return */
points[5].x = x + -radius2 * cos(th - tick/2); /* bottom right */
points[5].y = y + -radius2 * sin(th - tick/2);
points[6].x = x + radius2 * cos(th + tick/2); /* top right */
points[6].y = y + radius2 * sin(th + tick/2);
XDrawLines (st->dpy, d, disc->gc, points, 7, CoordModeOrigin);
}
static void
roll_disc (struct disc *disc)
{
double th = disc->theta;
if (th < 0)
th = -(th + disc->velocity);
else
th = (th + disc->velocity);
if (th > (360*64))
th -= (360*64);
else if (th < 0)
th += (360*64);
disc->theta = (disc->theta > 0 ? th : -th);
disc->velocity += disc->acceleration;
if (disc->velocity > disc->limit ||
disc->velocity < -disc->limit)
disc->acceleration = -disc->acceleration;
/* Alter direction of rotational acceleration randomly. */
if (! (random() % 120))
disc->acceleration = -disc->acceleration;
/* Change acceleration very occasionally. */
if (! (random() % 200))
{
if (random() & 1)
disc->acceleration *= 1.2;
else
disc->acceleration *= 0.8;
}
}
static void
init_spin (struct disc *disc)
{
disc->limit = 5*64;
disc->theta = RAND(360*64);
disc->velocity = RAND(16) * RANDSIGN();
disc->acceleration = RAND(16) * RANDSIGN();
}
static void
draw_compass (struct state *st)
{
int i = 0;
while (st->discs[i])
{
st->discs[i]->draw (st, st->b, st->discs[i], st->x, st->y, st->size);
roll_disc (st->discs[i]);
i++;
}
}
static void
draw_pointer (struct state *st)
{
int radius = st->size;
GC dot_gc = st->discs[0]->gc;
XPoint points[3];
int size = radius * 0.1;
/* top */
points[0].x = st->x - size;
points[0].y = st->y - radius - size;
points[1].x = st->x + size;
points[1].y = st->y - radius - size;
points[2].x = st->x;
points[2].y = st->y - radius;
XFillPolygon (st->dpy, st->b, st->ptr_gc, points, 3, Convex, CoordModeOrigin);
/* top right */
points[0].x = st->x - (radius * 0.85);
points[0].y = st->y - (radius * 0.8);
points[1].x = st->x - (radius * 1.1);
points[1].y = st->y - (radius * 0.55);
points[2].x = st->x - (radius * 0.6);
points[2].y = st->y - (radius * 0.65);
XFillPolygon (st->dpy, st->b, st->ptr_gc, points, 3, Convex, CoordModeOrigin);
/* left */
points[0].x = st->x - (radius * 1.05);
points[0].y = st->y;
points[1].x = st->x - (radius * 1.1);
points[1].y = st->y - (radius * 0.025);
points[2].x = st->x - (radius * 1.1);
points[2].y = st->y + (radius * 0.025);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
/* right */
points[0].x = st->x + (radius * 1.05);
points[0].y = st->y;
points[1].x = st->x + (radius * 1.1);
points[1].y = st->y - (radius * 0.025);
points[2].x = st->x + (radius * 1.1);
points[2].y = st->y + (radius * 0.025);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
/* bottom */
points[0].x = st->x;
points[0].y = st->y + (radius * 1.05);
points[1].x = st->x - (radius * 0.025);
points[1].y = st->y + (radius * 1.1);
points[2].x = st->x + (radius * 0.025);
points[2].y = st->y + (radius * 1.1);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
/* bottom left */
points[0].x = st->x + (radius * 0.74);
points[0].y = st->y + (radius * 0.74);
points[1].x = st->x + (radius * 0.78);
points[1].y = st->y + (radius * 0.75);
points[2].x = st->x + (radius * 0.75);
points[2].y = st->y + (radius * 0.78);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
/* top left */
points[0].x = st->x + (radius * 0.74);
points[0].y = st->y - (radius * 0.74);
points[1].x = st->x + (radius * 0.78);
points[1].y = st->y - (radius * 0.75);
points[2].x = st->x + (radius * 0.75);
points[2].y = st->y - (radius * 0.78);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
/* bottom right */
points[0].x = st->x - (radius * 0.74);
points[0].y = st->y + (radius * 0.74);
points[1].x = st->x - (radius * 0.78);
points[1].y = st->y + (radius * 0.75);
points[2].x = st->x - (radius * 0.75);
points[2].y = st->y + (radius * 0.78);
XFillPolygon (st->dpy, st->b, dot_gc, points, 3, Convex, CoordModeOrigin);
}
static void *
compass_init (Display *dpy, Window window)
{
struct state *st = (struct state *) calloc (1, sizeof(*st));
XGCValues gcv;
st->dpy = dpy;
st->window = window;
st->delay = get_integer_resource (st->dpy, "delay", "Integer");
st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean");
# ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
st->dbuf = False;
# endif
XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
st->size2 = MIN(st->xgwa.width, st->xgwa.height);
if (st->xgwa.width > st->xgwa.height * 5 || /* goofy aspect ratio */
st->xgwa.height > st->xgwa.width * 5)
st->size2 = MAX(st->xgwa.width, st->xgwa.height);
{
int max = 600;
if (st->xgwa.width > 2560) max *= 2; /* Retina displays */
if (st->size2 > max) st->size2 = max;
}
st->size = (st->size2 / 2) * 0.8;
st->x = st->xgwa.width/2;
st->y = st->xgwa.height/2;
if (st->dbuf)
{
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
st->b = st->backb = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (!st->b)
{
st->x = st->size2/2;
st->y = st->size2/2;
st->ba = XCreatePixmap (st->dpy, st->window, st->size2, st->size2, st->xgwa.depth);
st->bb = XCreatePixmap (st->dpy, st->window, st->size2, st->size2, st->xgwa.depth);
st->b = st->ba;
}
}
else
{
st->b = st->window;
}
st->discs[0] = (struct disc *) calloc (1, sizeof (struct disc));
st->discs[1] = (struct disc *) calloc (1, sizeof (struct disc));
st->discs[2] = (struct disc *) calloc (1, sizeof (struct disc));
st->discs[3] = 0;
gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
"foreground", "Foreground");
gcv.line_width = MAX(2, (st->size/60));
gcv.join_style = JoinBevel;
st->discs[0]->draw = draw_ticks;
st->discs[0]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth|GCJoinStyle,
&gcv);
init_spin (st->discs[0]);
gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
"arrow2Foreground", "Foreground");
gcv.line_width = MAX(4, (st->size / 30));
st->discs[1]->draw = draw_thick_arrow;
st->discs[1]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv);
init_spin (st->discs[1]);
gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
"arrow1Foreground", "Foreground");
gcv.line_width = MAX(4, (st->size / 30));
st->discs[2]->draw = draw_thin_arrow;
st->discs[2]->gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv);
init_spin (st->discs[2]);
gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
"pointerForeground", "Foreground");
st->ptr_gc = XCreateGC (st->dpy, st->b, GCForeground|GCLineWidth, &gcv);
gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
"background", "Background");
st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv);
if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->size2, st->size2);
if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->size2, st->size2);
return st;
}
static unsigned long
compass_draw (Display *dpy, Window window, void *closure)
{
struct state *st = (struct state *) closure;
XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
draw_compass (st);
draw_pointer (st);
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
if (st->backb)
{
XdbeSwapInfo info[1];
info[0].swap_window = st->window;
info[0].swap_action = XdbeUndefined;
XdbeSwapBuffers (st->dpy, info, 1);
}
else
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
if (st->dbuf)
{
XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0,
st->size2, st->size2,
st->xgwa.width/2 - st->x,
st->xgwa.height/2 - st->y);
st->b = (st->b == st->ba ? st->bb : st->ba);
}
return st->delay;
}
static void
compass_reshape (Display *dpy, Window window, void *closure,
unsigned int w, unsigned int h)
{
struct state *st = (struct state *) closure;
XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
st->size2 = MIN(st->xgwa.width, st->xgwa.height);
st->x = st->xgwa.width/2;
st->y = st->xgwa.height/2;
}
static Bool
compass_event (Display *dpy, Window window, void *closure, XEvent *event)
{
return False;
}
static void
compass_free (Display *dpy, Window window, void *closure)
{
}
static const char *compass_defaults [] = {
".background: #000000",
".foreground: #DDFFFF",
"*arrow1Foreground: #FFF66A",
"*arrow2Foreground: #F7D64A",
"*pointerForeground: #FF0000",
"*delay: 20000",
"*doubleBuffer: True",
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
"*useDBE: True",
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
0
};
static XrmOptionDescRec compass_options [] = {
{ "-delay", ".delay", XrmoptionSepArg, 0 },
{ "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
{ "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
{ 0, 0, 0, 0 }
};
XSCREENSAVER_MODULE ("Compass", compass)