1 /* halftone, Copyright (c) 2002 by Peter Jaric <peter@jaric.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 * Draws the gravitational force in each point on the screen seen
13 * through a halftone dot pattern. The force is calculated from a set
14 * of moving mass points. View it from a distance for best effect.
20 #include "screenhack.h"
22 #define DEFAULT_DELAY 10000
23 #define DEFAULT_SPACING 14
24 #define DEFAULT_SIZE_FACTOR 1.5
25 #define DEFAULT_COUNT 10
26 #define DEFAULT_MIN_MASS 0.001
27 #define DEFAULT_MAX_MASS 0.02
28 #define DEFAULT_MIN_SPEED 0.001
29 #define DEFAULT_MAX_SPEED 0.02
31 char *progclass = "Halftone";
47 XrmOptionDescRec options [] = {
48 { "-delay", ".delay", XrmoptionSepArg, 0 },
49 { "-count", ".count", XrmoptionSepArg, 0 },
50 { "-minmass", ".minMass", XrmoptionSepArg, 0 },
51 { "-maxmass", ".maxMass", XrmoptionSepArg, 0 },
52 { "-minspeed", ".minSpeed", XrmoptionSepArg, 0 },
53 { "-maxspeed", ".maxSpeed", XrmoptionSepArg, 0 },
54 { "-spacing", ".spacing", XrmoptionSepArg, 0 },
55 { "-sizefactor", ".sizeFactor", XrmoptionSepArg, 0 },
56 { "-colors", ".colors", XrmoptionSepArg, 0 },
57 { "-cycle-speed", ".cycleSpeed", XrmoptionSepArg, 0 },
70 /* Moving gravity points */
71 int gravity_point_count;
73 double* gravity_point_x;
74 double* gravity_point_y;
75 double* gravity_point_mass;
76 double* gravity_point_x_inc;
77 double* gravity_point_y_inc;
87 int color_tick, cycle_speed;
89 /* Off screen buffer */
97 static void update_buffer(halftone_screen *halftone, XWindowAttributes * attrs)
99 if (halftone->buffer_width != attrs->width ||
100 halftone->buffer_height != attrs->height)
104 if (halftone->buffer_width != -1 &&
105 halftone->buffer_height != -1)
107 XFreePixmap(halftone->display, halftone->buffer);
108 XFreeGC(halftone->display, halftone->buffer_gc);
111 halftone->buffer_width = attrs->width;
112 halftone->buffer_height = attrs->height;
113 halftone->buffer = XCreatePixmap(halftone->display, halftone->window, halftone->buffer_width, halftone->buffer_height, attrs->depth);
115 halftone->buffer_gc = XCreateGC(halftone->display, halftone->buffer, GCForeground|GCBackground, &gc_values);
119 static void update_dot_attributes(halftone_screen *halftone, XWindowAttributes * attrs)
121 double dots_width = attrs->width / halftone->spacing + 1;
122 double dots_height = attrs->height / halftone->spacing + 1;
124 if (halftone->dots == NULL ||
125 (dots_width != halftone->dots_width ||
126 dots_height != halftone->dots_height))
128 if (halftone->dots != NULL)
129 free(halftone->dots);
131 halftone->dots_width = dots_width;
132 halftone->dots_height = dots_height;
133 halftone->dots = (double *) malloc(halftone->dots_width * halftone->dots_height * sizeof(double));
137 static halftone_screen * init_halftone(Display *display, Window window)
148 XWindowAttributes attrs;
149 halftone_screen *halftone;
151 halftone = (halftone_screen *) calloc (1, sizeof(halftone_screen));
153 halftone->display = display;
154 halftone->window = window;
156 halftone->gc = XCreateGC (halftone->display, halftone->window, GCForeground | GCBackground, &gc_values);
158 halftone->buffer_width = -1;
159 halftone->buffer_height = -1;
160 halftone->dots = NULL;
162 /* Read command line arguments and set all settings. */
163 count = get_integer_resource ("count", "Count");
164 halftone->gravity_point_count = count < 1 ? DEFAULT_COUNT : count;
166 spacing = get_integer_resource ("spacing", "Integer");
167 halftone->spacing = spacing < 1 ? DEFAULT_SPACING : spacing;
169 factor = get_float_resource ("sizeFactor", "Double");
170 halftone->max_dot_size =
171 (factor < 0 ? DEFAULT_SIZE_FACTOR : factor) * halftone->spacing;
173 min_mass = get_float_resource ("minMass", "Double");
174 min_mass = min_mass < 0 ? DEFAULT_MIN_MASS : min_mass;
176 max_mass = get_float_resource ("maxMass", "Double");
177 max_mass = max_mass < 0 ? DEFAULT_MAX_MASS : max_mass;
178 max_mass = max_mass < min_mass ? min_mass : max_mass;
180 min_speed = get_float_resource ("minSpeed", "Double");
181 min_speed = min_speed < 0 ? DEFAULT_MIN_SPEED : min_speed;
183 max_speed = get_float_resource ("maxSpeed", "Double");
184 max_speed = max_speed < 0 ? DEFAULT_MAX_SPEED : max_speed;
185 max_speed = max_speed < min_speed ? min_speed : max_speed;
188 /* Set up the moving gravity points. */
189 halftone->gravity_point_x = (double *) malloc(halftone->gravity_point_count * sizeof(double));
190 halftone->gravity_point_y = (double *) malloc(halftone->gravity_point_count * sizeof(double));
191 halftone->gravity_point_mass = (double *) malloc(halftone->gravity_point_count * sizeof(double));
192 halftone->gravity_point_x_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double));
193 halftone->gravity_point_y_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double));
195 for (i = 0; i < halftone->gravity_point_count; i++)
197 halftone->gravity_point_x[i] = frand(1);
198 halftone->gravity_point_y[i] = frand(1);
199 halftone->gravity_point_mass[i] = min_mass + (max_mass - min_mass) * frand(1);
200 halftone->gravity_point_x_inc[i] = min_speed + (max_speed - min_speed) * frand(1);
201 halftone->gravity_point_y_inc[i] = min_speed + (max_speed - min_speed) * frand(1);
205 /* Set up the dots. */
206 XGetWindowAttributes(halftone->display, halftone->window, &attrs);
208 halftone->ncolors = get_integer_resource ("colors", "Colors");
209 if (halftone->ncolors < 4) halftone->ncolors = 4;
210 halftone->colors = (XColor *) calloc(halftone->ncolors, sizeof(XColor));
211 make_smooth_colormap (display, attrs.visual, attrs.colormap,
212 halftone->colors, &halftone->ncolors,
214 halftone->color0 = 0;
215 halftone->color1 = halftone->ncolors / 2;
216 halftone->cycle_speed = get_integer_resource ("cycleSpeed", "CycleSpeed");
217 halftone->color_tick = 0;
219 update_buffer(halftone, &attrs);
220 update_dot_attributes(halftone, &attrs);
222 for (x = 0; x < halftone->dots_width; x++)
223 for (y = 0; y < halftone->dots_height; y++)
225 halftone->dots[x + y * halftone->dots_width] = 0;
233 static void fill_circle(Display *display, Window window, GC gc, int x, int y, int size)
235 int start_x = x - (size / 2);
236 int start_y = y - (size / 2);
237 unsigned int width = size;
238 unsigned int height = size;
240 int angle2 = 360 * 64; /* A full circle */
242 XFillArc (display, window, gc,
243 start_x, start_y, width, height,
247 static void repaint_halftone(halftone_screen *halftone)
251 int x_offset = halftone->spacing / 2;
252 int y_offset = halftone->spacing / 2;
258 /* Fill buffer with background color */
259 XSetForeground (halftone->display, halftone->buffer_gc,
260 halftone->colors[halftone->color0].pixel);
261 XFillRectangle(halftone->display, halftone->buffer, halftone->buffer_gc, 0, 0, halftone->buffer_width, halftone->buffer_height);
263 /* Draw dots on buffer */
264 XSetForeground (halftone->display, halftone->buffer_gc,
265 halftone->colors[halftone->color1].pixel);
267 if (halftone->color_tick++ >= halftone->cycle_speed)
269 halftone->color_tick = 0;
270 halftone->color0 = (halftone->color0 + 1) % halftone->ncolors;
271 halftone->color1 = (halftone->color1 + 1) % halftone->ncolors;
274 for (x = 0; x < halftone->dots_width; x++)
275 for (y = 0; y < halftone->dots_height; y++)
276 fill_circle(halftone->display, halftone->buffer, halftone->buffer_gc,
277 x_offset + x * halftone->spacing, y_offset + y * halftone->spacing,
278 halftone->max_dot_size * halftone->dots[x + y * halftone->dots_width]);
280 /* Copy buffer to window */
281 XCopyArea(halftone->display, halftone->buffer, halftone->window, halftone->gc, 0, 0, halftone->buffer_width, halftone->buffer_height, 0, 0);
284 static double calculate_gravity(halftone_screen *halftone, int x, int y)
290 for (i = 0; i < halftone->gravity_point_count; i++)
292 double dx = ((double) x) - halftone->gravity_point_x[i] * halftone->dots_width;
293 double dy = ((double) y) - halftone->gravity_point_y[i] * halftone->dots_height;
294 double distance = sqrt(dx * dx + dy * dy);
298 double gravity = halftone->gravity_point_mass[i] / (distance * distance / (halftone->dots_width * halftone->dots_height));
300 gx += (dx / distance) * gravity;
301 gy += (dy / distance) * gravity;
305 return sqrt(gx * gx + gy * gy);
308 static void update_halftone(halftone_screen *halftone)
311 XWindowAttributes attrs;
313 XGetWindowAttributes(halftone->display, halftone->window, &attrs);
315 /* Make sure we have a valid buffer */
316 update_buffer(halftone, &attrs);
318 /* Make sure all dot attributes (spacing, width, height, etc) are correct */
319 update_dot_attributes(halftone, &attrs);
321 /* Move gravity points */
322 for (i = 0; i < halftone->gravity_point_count; i++)
324 halftone->gravity_point_x_inc[i] =
325 (halftone->gravity_point_x[i] >= 1 || halftone->gravity_point_x[i] <= 0 ?
326 -halftone->gravity_point_x_inc[i] :
327 halftone->gravity_point_x_inc[i]);
328 halftone->gravity_point_y_inc[i] =
329 (halftone->gravity_point_y[i] >= 1 || halftone->gravity_point_y[i] <= 0 ?
330 -halftone->gravity_point_y_inc[i] :
331 halftone->gravity_point_y_inc[i]);
333 halftone->gravity_point_x[i] += halftone->gravity_point_x_inc[i];
334 halftone->gravity_point_y[i] += halftone->gravity_point_y_inc[i];
337 /* Update gravity in each dot .*/
338 for (x = 0; x < halftone->dots_width; x++)
339 for (y = 0; y < halftone->dots_height; y++)
341 double gravity = calculate_gravity(halftone, x, y);
343 halftone->dots[x + y * halftone->dots_width] = (gravity > 1 ? 1 : (gravity < 0 ? 0 : gravity));
348 void screenhack (Display *display, Window window)
350 halftone_screen *halftone = init_halftone(display, window);
351 int delay = get_integer_resource ("delay", "Integer");
352 delay = (delay < 0 ? DEFAULT_DELAY : delay);
356 repaint_halftone(halftone);
357 update_halftone(halftone);
358 screenhack_handle_events (display);