-/* tessellimage, Copyright (c) 2014 Jamie Zawinski <jwz@jwz.org>
+/* tessellimage, Copyright (c) 2014-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
int delay;
Bool outline_p, cache_p, fill_p;
double duration, duration2;
- int max_depth;
+ int max_depth, max_resolution;
double start_time, start_time2;
XImage *img, *delta;
st->max_depth = get_integer_resource (st->dpy, "maxDepth", "MaxDepth");
if (st->max_depth < 100) st->max_depth = 100;
+ st->max_resolution = get_integer_resource (st->dpy,
+ "maxResolution", "MaxResolution");
+ if (st->max_resolution < 0) st->max_resolution = 0;
+
st->duration = get_float_resource (st->dpy, "duration", "Seconds");
if (st->duration < 1) st->duration = 1;
XCopyArea (st->dpy,
st->cache[st->thresh],
st->output, st->pgc,
- 0, 0, st->delta->width, st->delta->height,
+ 0, 0, st->xgwa.width, st->xgwa.height,
0, 0);
}
else if (ticked_p)
int nv = 0;
int ntri = 0;
int x, y, i;
+ double wscale = st->xgwa.width / (double) st->delta->width;
#if 0
fprintf(stderr, "%s: thresh %d/%d = %d=%d\n",
if (st->output)
XFreePixmap (st->dpy, st->output);
st->output = XCreatePixmap (st->dpy, st->window,
- st->delta->width, st->delta->height,
+ st->xgwa.width, st->xgwa.height,
st->xgwa.depth);
XFillRectangle (st->dpy, st->output, st->pgc,
- 0, 0, st->delta->width, st->delta->height);
+ 0, 0, st->xgwa.width, st->xgwa.height);
#ifdef DO_VORONOI
{
XPoint xp[3];
unsigned long color;
- xp[0].x = p[v[i].p1].x; xp[0].y = p[v[i].p1].y;
- xp[1].x = p[v[i].p2].x; xp[1].y = p[v[i].p2].y;
- xp[2].x = p[v[i].p3].x; xp[2].y = p[v[i].p3].y;
+ xp[0].x = p[v[i].p1].x * wscale; xp[0].y = p[v[i].p1].y * wscale;
+ xp[1].x = p[v[i].p2].x * wscale; xp[1].y = p[v[i].p2].y * wscale;
+ xp[2].x = p[v[i].p3].x * wscale; xp[2].y = p[v[i].p3].y * wscale;
/* Set the color of this triangle to the pixel at its midpoint. */
color = XGetPixel (st->img,
- (xp[0].x + xp[1].x + xp[2].x) / 3,
- (xp[0].y + xp[1].y + xp[2].y) / 3);
+ (xp[0].x + xp[1].x + xp[2].x) / (3 * wscale),
+ (xp[0].y + xp[1].y + xp[2].y) / (3 * wscale));
XSetForeground (st->dpy, st->pgc, color);
XFillPolygon (st->dpy, st->output, st->pgc, xp, countof(xp),
{
st->cache[st->thresh] =
XCreatePixmap (st->dpy, st->window,
- st->delta->width, st->delta->height,
+ st->xgwa.width, st->xgwa.height,
st->xgwa.depth);
if (! st->cache[st->thresh])
{
st->output,
st->cache[st->thresh],
st->pgc,
- 0, 0, st->delta->width, st->delta->height,
+ 0, 0, st->xgwa.width, st->xgwa.height,
0, 0);
}
}
get_deltap (struct state *st)
{
int x, y;
- int w = st->delta->width;
- int h = st->delta->height;
+ int w = st->xgwa.width;
+ int h = st->xgwa.height;
+ double wscale = st->xgwa.width / (double) st->delta->width;
XImage *dimg;
Visual *v = st->xgwa.visual;
for (y = 0; y < h; y++)
for (x = 0; x < w; x++)
{
- unsigned long v = XGetPixel (st->delta, x, y) << 5;
+ unsigned long v = XGetPixel (st->delta, x / wscale, y / wscale) << 5;
unsigned long p = (((v << rpos) & rmsk) |
((v << gpos) & gmsk) |
((v << bpos) & bmsk));
if (!st->img_loader &&
st->start_time + st->duration < double_time()) {
+ int w = st->xgwa.width;
+ int h = st->xgwa.height;
+
+ /* Analysing a full-resolution image on a Retina display is too slow,
+ so scale down the source at image-load time. */
+ if (st->max_resolution > 10)
+ {
+ if (w > h && w > st->max_resolution)
+ h = st->max_resolution * h / w, w = st->max_resolution;
+ else if (h > st->max_resolution)
+ w = st->max_resolution * w / h, h = st->max_resolution;
+ }
+ /* fprintf(stderr,"%s: loading %d x %d\n", progname, w, h); */
+
XClearWindow (st->dpy, st->window);
if (st->image) XFreePixmap (dpy, st->image);
- st->image = XCreatePixmap (st->dpy, st->window,
- st->xgwa.width, st->xgwa.height,
- st->xgwa.depth);
+ st->image = XCreatePixmap (st->dpy, st->window, w, h, st->xgwa.depth);
st->img_loader = load_image_async_simple (0, st->xgwa.screen, st->window,
st->image, 0, &st->geom);
goto DONE;
XCopyArea (st->dpy,
(st->button_down_p ? get_deltap (st) : st->output),
st->window, st->wgc,
- 0, 0, st->delta->width, st->delta->height,
- (st->xgwa.width - st->delta->width) / 2,
- (st->xgwa.height - st->delta->height) / 2);
+ 0, 0, st->xgwa.width, st->xgwa.height, 0, 0);
else if (!st->nthreshes)
XCopyArea (st->dpy,
st->image,
st->window, st->wgc,
- 0, 0, st->xgwa.width, st->xgwa.height,
- 0,
- 0);
+ 0, 0, st->xgwa.width, st->xgwa.height, 0, 0);
DONE:
static const char *tessellimage_defaults [] = {
".background: black",
".foreground: white",
+ ".lowrez: True",
"*dontClearRoot: True",
"*fpsSolid: true",
"*delay: 30000",
"*duration: 120",
"*duration2: 0.4",
"*maxDepth: 30000",
+ "*maxResolution: 1024",
"*outline: True",
"*fillScreen: True",
"*cache: True",
{ "-duration", ".duration", XrmoptionSepArg, 0 },
{ "-duration2", ".duration2", XrmoptionSepArg, 0 },
{ "-max-depth", ".maxDepth", XrmoptionSepArg, 0 },
+ { "-max-resolution", ".maxResolution", XrmoptionSepArg, 0 },
{ "-outline", ".outline", XrmoptionNoArg, "True" },
{ "-no-outline", ".outline", XrmoptionNoArg, "False" },
{ "-fill-screen", ".fillScreen", XrmoptionNoArg, "True" },