summaryrefslogtreecommitdiffstats
path: root/hacks/rotzoomer.c
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/rotzoomer.c
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'hacks/rotzoomer.c')
-rw-r--r--hacks/rotzoomer.c585
1 files changed, 585 insertions, 0 deletions
diff --git a/hacks/rotzoomer.c b/hacks/rotzoomer.c
new file mode 100644
index 0000000..58f805c
--- /dev/null
+++ b/hacks/rotzoomer.c
@@ -0,0 +1,585 @@
+/* rotzoomer - creates a collage of rotated and scaled portions of the screen
+ * Copyright (C) 2001-2016 Claudio Matsuoka <claudio@helllabs.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.
+ */
+
+/* Circle-mode by jwz, 2014, 2016. */
+
+/*
+ * Options:
+ *
+ * -shm enable MIT shared memory extension
+ * -no-shm disable MIT shared memory extension
+ * -n <num> number of zoomboxes
+ * -move enable mobile zoomboxes
+ * -sweep enable sweep mode
+ * -circle enable circle mode
+ * -anim enable snapshot mode
+ * -no-anim enable snapshot mode
+ * -delay delay in milliseconds
+ */
+
+#include <math.h>
+#include "screenhack.h"
+#include "xshm.h"
+
+struct zoom_area {
+ int w, h; /* rectangle width and height */
+ int inc1, inc2; /* rotation and zoom angle increments */
+ int dx, dy; /* translation increments */
+ int a1, a2; /* rotation and zoom angular variables */
+ int ox, oy; /* origin in the background copy */
+ int xx, yy; /* left-upper corner position (* 256) */
+ int x, y; /* left-upper corner position */
+ int ww, hh; /* valid area to place left-upper corner */
+ int n; /* number of iteractions */
+ int count; /* current iteraction */
+};
+
+struct state {
+ Display *dpy;
+ Window window;
+
+ GC gc;
+ Visual *visual;
+ XImage *orig_map, *buffer_map;
+ Colormap colormap;
+
+ int width, height;
+ struct zoom_area **zoom_box;
+ int num_zoom;
+ int move;
+ int sweep;
+ int circle;
+ int delay;
+ int anim;
+ int duration;
+ time_t start_time;
+
+ async_load_state *img_loader;
+ Pixmap pm;
+
+ XShmSegmentInfo shm_info;
+};
+
+
+static void
+rotzoom (struct state *st, struct zoom_area *za)
+{
+ int x, y, c, s, zoom, z;
+ int x2 = za->x + za->w - 1, y2 = za->y + za->h - 1;
+ int ox = 0, oy = 0;
+ int w2 = (za->w/2) * (za->w/2);
+
+ z = 8100 * sin (M_PI * za->a2 / 8192);
+ zoom = 8192 + z;
+
+ for (y = za->y; y <= y2; y++) {
+ for (x = za->x; x <= x2; x++) {
+ Bool copyp = True;
+ double a = M_PI * za->a1 / 8192;
+ c = zoom * cos (a);
+ s = zoom * sin (a);
+ if (st->circle) {
+ int cx = za->x + za->w / 2;
+ int cy = za->y + za->h / 2;
+ int dx = x - cx;
+ int dy = y - cy;
+ int d2 = (dx*dx) + (dy*dy);
+
+ if (d2 > w2) {
+ copyp = False;
+ } else {
+ double r = sqrt ((double) d2);
+ double th = atan ((double)dy / (double) (dx == 0 ? 1 : dx));
+ copyp = 1;
+ if (dx < 0) th += M_PI;
+ th += M_PI * (za->a1 / 600.0);
+ ox = cx + (int) (r * cos(th));
+ oy = cy + (int) (r * sin(th));
+ }
+ } else {
+ ox = (x * c + y * s) >> 13;
+ oy = (-x * s + y * c) >> 13;
+ }
+
+ if (copyp) {
+ while (ox < 0)
+ ox += st->width;
+ while (oy < 0)
+ oy += st->height;
+ while (ox >= st->width)
+ ox -= st->width;
+ while (oy >= st->height)
+ oy -= st->height;
+
+ XPutPixel (st->buffer_map, x, y, XGetPixel (st->orig_map, ox, oy));
+ }
+ }
+ }
+
+ za->a1 += za->inc1; /* Rotation angle */
+ za->a1 &= 0x3fff;
+
+ za->a2 += za->inc2; /* Zoom */
+ za->a2 &= 0x3fff;
+
+ za->ox = ox; /* Save state for next iteration */
+ za->oy = oy;
+
+ if (st->circle && za->n <= 1)
+ {
+ /* Done rotating the circle: copy the bits from the working set back
+ into the origin, so that subsequent rotations pick up these changes.
+ */
+ int cx = za->x + za->w / 2;
+ int cy = za->y + za->h / 2;
+ int w2 = (za->w/2) * (za->w/2);
+ for (y = za->y; y < za->y + za->h; y++)
+ for (x = za->x; x < za->x + za->w; x++)
+ {
+ int dx = x - cx;
+ int dy = y - cy;
+ int d2 = (dx*dx) + (dy*dy);
+ if (d2 <= w2)
+ XPutPixel (st->orig_map, x, y, XGetPixel (st->buffer_map, x, y));
+ }
+ }
+
+ za->count++;
+}
+
+
+static void
+reset_zoom (struct state *st, struct zoom_area *za)
+{
+ if (st->sweep) {
+ int speed = random () % 100 + 100;
+ switch (random () % 4) {
+ case 0:
+ za->w = st->width;
+ za->h = 10;
+ za->x = 0;
+ za->y = 0;
+ za->dx = 0;
+ za->dy = speed;
+ za->n = (st->height - 10) * 256 / speed;
+ break;
+ case 1:
+ za->w = 10;
+ za->h = st->height;
+ za->x = st->width - 10;
+ za->y = 0;
+ za->dx = -speed;
+ za->dy = 0;
+ za->n = (st->width - 10) * 256 / speed;
+ break;
+ case 2:
+ za->w = st->width;
+ za->h = 10;
+ za->x = 0;
+ za->y = st->height - 10;
+ za->dx = 0;
+ za->dy = -speed;
+ za->n = (st->height - 10) * 256 / speed;
+ break;
+ case 3:
+ za->w = 10;
+ za->h = st->height;
+ za->x = 0;
+ za->y = 0;
+ za->dx = speed;
+ za->dy = 0;
+ za->n = (st->width - 10) * 256 / speed;
+ break;
+ }
+ za->ww = st->width - za->w;
+ za->hh = st->height - za->h;
+
+ /* We want smaller angle increments in sweep mode (looks better) */
+
+ za->a1 = 0;
+ za->a2 = 0;
+ za->inc1 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
+ za->inc2 = ((2 * (random() & 1)) - 1) * (1 + random () % 7);
+ } else if (st->circle) {
+
+ za->w = 50 + random() % 300;
+ if (za->w > st->width / 3)
+ za->w = st->width / 3;
+ if (za->w > st->height / 3)
+ za->w = st->height / 3;
+ za->h = za->w;
+
+ za->ww = st->width - za->w;
+ za->hh = st->height - za->h;
+
+ za->x = (za->ww ? random() % za->ww : 0);
+ za->y = (za->hh ? random() % za->hh : 0);
+ za->dx = 0;
+ za->dy = 0;
+ za->a1 = 0;
+ za->a2 = 0;
+ za->count = 0;
+
+ /* #### If we go clockwise, it doesn't start rotating from 0.
+ So only go counter-clockwise for now. Sigh. */
+ za->inc1 = (random () % 30);
+ za->inc2 = 0;
+ za->n = 50 + random() % 100;
+
+ if (!st->anim) {
+ za->count = random() % (za->n / 2);
+ za->a1 = random();
+ }
+
+ } else {
+ za->w = 50 + random() % 300;
+ za->h = 50 + random() % 300;
+
+ if (za->w > st->width / 3)
+ za->w = st->width / 3;
+ if (za->h > st->height / 3)
+ za->h = st->height / 3;
+
+ za->ww = st->width - za->w;
+ za->hh = st->height - za->h;
+
+ za->x = (za->ww ? random() % za->ww : 0);
+ za->y = (za->hh ? random() % za->hh : 0);
+
+ za->dx = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
+ za->dy = ((2 * (random() & 1)) - 1) * (100 + random() % 300);
+
+ if (st->anim) {
+ za->n = 50 + random() % 1000;
+ za->a1 = 0;
+ za->a2 = 0;
+ } else {
+ za->n = 5 + random() % 10;
+ za->a1 = random ();
+ za->a2 = random ();
+ }
+
+ za->inc1 = ((2 * (random() & 1)) - 1) * (random () % 30);
+ za->inc2 = ((2 * (random() & 1)) - 1) * (random () % 30);
+ }
+
+ za->xx = za->x * 256;
+ za->yy = za->y * 256;
+
+ za->count = 0;
+}
+
+
+static struct zoom_area *
+create_zoom (struct state *st)
+{
+ struct zoom_area *za;
+
+ za = calloc (1, sizeof (struct zoom_area));
+ reset_zoom (st, za);
+
+ return za;
+}
+
+
+static void
+update_position (struct zoom_area *za)
+{
+ za->xx += za->dx;
+ za->yy += za->dy;
+
+ za->x = za->xx >> 8;
+ za->y = za->yy >> 8;
+
+ if (za->x < 0) {
+ za->x = 0;
+ za->dx = 100 + random() % 100;
+ }
+
+ if (za->y < 0) {
+ za->y = 0;
+ za->dy = 100 + random() % 100;
+ }
+
+ if (za->x > za->ww) {
+ za->x = za->ww;
+ za->dx = -(100 + random() % 100);
+ }
+
+ if (za->y > za->hh) {
+ za->y = za->hh;
+ za->dy = -(100 + random() % 100);
+ }
+}
+
+
+static void
+DisplayImage (struct state *st, int x, int y, int w, int h)
+{
+ put_xshm_image (st->dpy, st->window, st->gc, st->buffer_map, x, y, x, y,
+ w, h, &st->shm_info);
+}
+
+
+static void
+set_mode(struct state *st)
+{
+ char *s = get_string_resource (st->dpy, "mode", "Mode");
+ if (!s || !*s || !strcasecmp (s, "random"))
+ {
+ switch (random() % 4) {
+ case 0: s = "stationary"; break;
+ case 1: s = "move"; break;
+ case 2: s = "sweep"; break;
+ case 3: s = "circle"; break;
+ default: abort();
+ }
+ }
+
+ st->move = False;
+ st->sweep = False;
+ st->circle = False;
+
+ if (!strcasecmp (s, "stationary"))
+ ;
+ else if (!strcasecmp (s, "move"))
+ st->move = True;
+ else if (!strcasecmp (s, "sweep"))
+ st->sweep = True;
+ else if (!strcasecmp (s, "circle"))
+ st->circle = True;
+ else
+ fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s);
+}
+
+
+static void
+init_hack (struct state *st)
+{
+ int i;
+
+ set_mode (st);
+
+ st->start_time = time ((time_t *) 0);
+ st->zoom_box = calloc (st->num_zoom, sizeof (struct zoom_area *));
+ for (i = 0; i < st->num_zoom; i++) {
+ st->zoom_box[i] = create_zoom (st);
+ }
+
+ if (st->height && st->orig_map->data)
+ memcpy (st->buffer_map->data, st->orig_map->data,
+ st->height * st->buffer_map->bytes_per_line);
+
+ DisplayImage(st, 0, 0, st->width, st->height);
+}
+
+
+static unsigned long
+rotzoomer_draw (Display *disp, Window win, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ int delay = st->delay;
+ int i;
+
+ if (st->img_loader) /* still loading */
+ {
+ st->img_loader = load_image_async_simple (st->img_loader, 0, 0, 0, 0, 0);
+ if (! st->img_loader) { /* just finished */
+ if (! st->pm) abort();
+ st->orig_map = XGetImage (st->dpy, st->pm,
+ 0, 0, st->width, st->height,
+ ~0L, ZPixmap);
+ init_hack (st);
+ }
+ return st->delay;
+ }
+
+ if (!st->img_loader &&
+ st->start_time + st->duration < time ((time_t *) 0)) {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes(st->dpy, st->window, &xgwa);
+ /* On MacOS X11, XGetImage on a Window often gets an inexplicable BadMatch,
+ possibly due to the window manager having occluded something? It seems
+ nondeterministic. Loading the image into a pixmap instead fixes it. */
+ if (st->pm) XFreePixmap (st->dpy, st->pm);
+ st->pm = XCreatePixmap (st->dpy, st->window,
+ xgwa.width, xgwa.height, xgwa.depth);
+ st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+ st->pm, 0, 0);
+ st->start_time = time ((time_t *) 0);
+ return st->delay;
+ }
+
+ for (i = 0; i < st->num_zoom; i++) {
+ if (st->move || st->sweep)
+ update_position (st->zoom_box[i]);
+
+ if (st->zoom_box[i]->n > 0) {
+ if (st->anim || st->zoom_box[i]->count == 0) {
+ rotzoom (st, st->zoom_box[i]);
+ } else {
+ delay = 1000000;
+ }
+ st->zoom_box[i]->n--;
+ } else {
+ reset_zoom (st, st->zoom_box[i]);
+ }
+ }
+
+ for (i = 0; i < st->num_zoom; i++) {
+ DisplayImage(st, st->zoom_box[i]->x, st->zoom_box[i]->y,
+ st->zoom_box[i]->w, st->zoom_box[i]->h);
+ }
+
+ return delay;
+}
+
+
+static void
+setup_X (struct state *st)
+{
+ XWindowAttributes xgwa;
+ int depth;
+ XGCValues gcv;
+ long gcflags;
+
+ XGetWindowAttributes (st->dpy, st->window, &xgwa);
+ depth = xgwa.depth;
+ st->colormap = xgwa.colormap;
+ st->width = xgwa.width;
+ st->height = xgwa.height;
+ st->visual = xgwa.visual;
+
+ if (st->width % 2)
+ st->width--;
+ if (st->height % 2)
+ st->height--;
+
+ gcv.function = GXcopy;
+ gcv.subwindow_mode = IncludeInferiors;
+ gcflags = GCFunction;
+ if (use_subwindow_mode_p (xgwa.screen, st->window)) /* see grabscreen.c */
+ gcflags |= GCSubwindowMode;
+ st->gc = XCreateGC (st->dpy, st->window, gcflags, &gcv);
+ if (st->pm) XFreePixmap (st->dpy, st->pm);
+ st->pm = XCreatePixmap (st->dpy, st->window,
+ xgwa.width, xgwa.height, xgwa.depth);
+ st->img_loader = load_image_async_simple (0, xgwa.screen, st->window,
+ st->pm, 0, 0);
+
+ st->buffer_map = create_xshm_image(st->dpy, xgwa.visual, depth,
+ ZPixmap, &st->shm_info, st->width, st->height);
+}
+
+
+static void *
+rotzoomer_init (Display *dpy, Window window)
+{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
+ st->dpy = dpy;
+ st->window = window;
+ st->num_zoom = get_integer_resource (st->dpy, "numboxes", "Integer");
+
+ set_mode(st);
+
+ st->anim = get_boolean_resource (st->dpy, "anim", "Boolean");
+ st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+ st->duration = get_integer_resource (st->dpy, "duration", "Seconds");
+ if (st->delay < 0) st->delay = 0;
+ if (st->duration < 1) st->duration = 1;
+
+ /* In sweep or static mode, we want only one box */
+ if (st->sweep || !st->anim)
+ st->num_zoom = 1;
+
+ /* Can't have static sweep mode */
+ if (!st->anim)
+ st->sweep = 0;
+
+ if (st->circle) {
+ st->move = 0;
+ st->sweep = 0;
+ }
+
+ st->start_time = time ((time_t *) 0);
+
+ setup_X (st);
+
+ return st;
+}
+
+static void
+rotzoomer_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+}
+
+static Bool
+rotzoomer_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ struct state *st = (struct state *) closure;
+ if (screenhack_event_helper (dpy, window, event))
+ {
+ st->start_time = 0;
+ return True;
+ }
+ return False;
+}
+
+static void
+rotzoomer_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ if (st->pm) XFreePixmap (dpy, st->pm);
+ free (st);
+}
+
+
+static const char *rotzoomer_defaults[] = {
+ ".background: black",
+ ".foreground: white",
+ "*fpsSolid: true",
+#ifdef HAVE_XSHM_EXTENSION
+ "*useSHM: True",
+#else
+ "*useSHM: False",
+#endif
+ "*anim: True",
+ "*mode: random",
+ "*numboxes: 2",
+ "*delay: 10000",
+ "*duration: 120",
+#ifdef HAVE_MOBILE
+ "*ignoreRotation: True",
+ "*rotateImages: True",
+#endif
+ 0
+};
+
+
+static XrmOptionDescRec rotzoomer_options[] = {
+ { "-shm", ".useSHM", XrmoptionNoArg, "True" },
+ { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
+ { "-mode", ".mode", XrmoptionSepArg, 0 },
+ { "-move", ".mode", XrmoptionNoArg, "move" },
+ { "-sweep", ".mode", XrmoptionNoArg, "sweep" },
+ { "-circle", ".mode", XrmoptionNoArg, "circle"},
+ { "-anim", ".anim", XrmoptionNoArg, "True" },
+ { "-no-anim", ".anim", XrmoptionNoArg, "False" },
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ {"-duration", ".duration", XrmoptionSepArg, 0 },
+ { "-n", ".numboxes", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("RotZoomer", rotzoomer)