source: trunk/third/xscreensaver/hacks/halftone.c @ 20148

Revision 20148, 11.3 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* halftone, Copyright (c) 2002 by Peter Jaric <peter@jaric.org>
2 *
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
9 * implied warranty.
10 *
11 * Description:
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.
15 */
16
17#include <math.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include "screenhack.h"
21
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
30
31char *progclass = "Halftone";
32
33char *defaults [] = {
34  "*delay:              10000",
35  "*count:              10",
36  "*minMass:            0.001",
37  "*maxMass:            0.02",
38  "*minSpeed:           0.001",
39  "*maxSpeed:           0.02",
40  "*spacing:            14",
41  "*sizeFactor:         1.5",
42  "*colors:             200",
43  "*cycleSpeed:         10",
44  0
45};
46
47XrmOptionDescRec 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 },
58  { 0, 0, 0, 0 }
59};
60
61typedef struct
62{
63  /* halftone dots */
64  double * dots;
65  int dots_width;
66  int dots_height;
67  int spacing;
68  int max_dot_size;
69
70  /* Moving gravity points */
71  int gravity_point_count;
72
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;
78
79  /* X stuff */
80  Display *display;
81  Window window;
82  GC gc;
83
84  int ncolors;
85  XColor *colors;
86  int color0, color1;
87  int color_tick, cycle_speed;
88
89  /* Off screen buffer */
90  Pixmap buffer;
91  GC buffer_gc;
92  int buffer_width;
93  int buffer_height;
94} halftone_screen;
95
96
97static void update_buffer(halftone_screen *halftone, XWindowAttributes * attrs)
98{
99  if (halftone->buffer_width != attrs->width ||
100      halftone->buffer_height != attrs->height)
101  {
102    XGCValues gc_values;
103
104    if (halftone->buffer_width != -1 &&
105        halftone->buffer_height != -1)
106    {
107      XFreePixmap(halftone->display, halftone->buffer);
108      XFreeGC(halftone->display, halftone->buffer_gc);
109    }
110
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);
114
115    halftone->buffer_gc = XCreateGC(halftone->display, halftone->buffer, GCForeground|GCBackground, &gc_values);
116  }
117}
118
119static void update_dot_attributes(halftone_screen *halftone, XWindowAttributes * attrs)
120
121  double dots_width = attrs->width / halftone->spacing + 1;
122  double dots_height = attrs->height / halftone->spacing + 1;
123
124  if (halftone->dots == NULL ||
125      (dots_width != halftone->dots_width ||
126       dots_height != halftone->dots_height))
127  {
128    if (halftone->dots != NULL)
129      free(halftone->dots);
130
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));
134  }
135}
136
137static halftone_screen * init_halftone(Display *display, Window window)
138{
139  int x, y, i;
140  int count;
141  int spacing;
142  double factor;
143  double min_mass;
144  double max_mass;
145  double min_speed;
146  double max_speed;
147  XGCValues gc_values;
148  XWindowAttributes attrs;
149  halftone_screen *halftone;
150
151  halftone = (halftone_screen *) calloc (1, sizeof(halftone_screen));
152
153  halftone->display = display;
154  halftone->window = window;
155
156  halftone->gc = XCreateGC (halftone->display, halftone->window, GCForeground | GCBackground, &gc_values);
157
158  halftone->buffer_width = -1;
159  halftone->buffer_height = -1;
160  halftone->dots = NULL;
161
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;
165
166  spacing = get_integer_resource ("spacing", "Integer");
167  halftone->spacing = spacing < 1 ? DEFAULT_SPACING : spacing;
168
169  factor = get_float_resource ("sizeFactor", "Double");
170  halftone->max_dot_size =
171    (factor < 0 ? DEFAULT_SIZE_FACTOR : factor) * halftone->spacing;
172
173  min_mass = get_float_resource ("minMass", "Double");
174  min_mass = min_mass < 0 ? DEFAULT_MIN_MASS : min_mass;
175
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;
179
180  min_speed = get_float_resource ("minSpeed", "Double");
181  min_speed = min_speed < 0 ? DEFAULT_MIN_SPEED : min_speed;
182
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;
186
187
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));
194
195  for (i = 0; i < halftone->gravity_point_count; i++)
196  {
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);
202  }
203
204
205  /* Set up the dots. */
206  XGetWindowAttributes(halftone->display, halftone->window, &attrs); 
207
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,
213                        True, 0, False);
214  halftone->color0 = 0;
215  halftone->color1 = halftone->ncolors / 2;
216  halftone->cycle_speed = get_integer_resource ("cycleSpeed", "CycleSpeed");
217  halftone->color_tick = 0;
218
219  update_buffer(halftone, &attrs);
220  update_dot_attributes(halftone, &attrs);
221
222  for (x = 0; x < halftone->dots_width; x++)
223    for (y = 0; y < halftone->dots_height; y++)
224    {
225        halftone->dots[x + y * halftone->dots_width] = 0;
226    }
227
228  return halftone;
229}
230
231
232
233static void fill_circle(Display *display, Window window, GC gc, int x, int y, int size)
234{
235  int start_x = x - (size / 2);
236  int start_y = y - (size / 2);
237  unsigned int width = size;
238  unsigned int height = size;
239  int angle1 = 0;
240  int angle2 = 360 * 64; /* A full circle */
241
242  XFillArc (display, window, gc,
243            start_x, start_y, width, height,
244            angle1, angle2);
245}
246
247static void repaint_halftone(halftone_screen *halftone)
248{
249  int x, y;
250  /*
251  int x_offset = halftone->spacing / 2;
252  int y_offset = halftone->spacing / 2;
253  */
254  int x_offset = 0;
255  int y_offset = 0;
256
257 
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);
262
263  /* Draw dots on buffer */
264  XSetForeground (halftone->display, halftone->buffer_gc,
265                  halftone->colors[halftone->color1].pixel);
266
267  if (halftone->color_tick++ >= halftone->cycle_speed)
268    {
269      halftone->color_tick = 0;
270      halftone->color0 = (halftone->color0 + 1) % halftone->ncolors;
271      halftone->color1 = (halftone->color1 + 1) % halftone->ncolors;
272    }
273
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]);
279
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);
282}
283
284static double calculate_gravity(halftone_screen *halftone, int x, int y)
285{
286  int i;
287  double gx = 0;
288  double gy = 0;
289
290  for (i = 0; i < halftone->gravity_point_count; i++)
291  {
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);
295   
296    if (distance != 0)
297    {
298      double gravity = halftone->gravity_point_mass[i] / (distance * distance  / (halftone->dots_width * halftone->dots_height));
299     
300      gx += (dx / distance) * gravity;
301      gy += (dy / distance) * gravity;
302    }
303  } 
304 
305  return sqrt(gx * gx + gy * gy);
306}
307
308static void update_halftone(halftone_screen *halftone)
309{
310  int x, y, i;
311  XWindowAttributes attrs;
312
313  XGetWindowAttributes(halftone->display, halftone->window, &attrs);
314
315  /* Make sure we have a valid buffer */
316  update_buffer(halftone, &attrs);
317 
318  /* Make sure all dot attributes (spacing, width, height, etc) are correct */
319  update_dot_attributes(halftone, &attrs);
320 
321  /* Move gravity points */
322  for (i = 0; i < halftone->gravity_point_count; i++)
323  {
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]);
332
333    halftone->gravity_point_x[i] += halftone->gravity_point_x_inc[i];
334    halftone->gravity_point_y[i] += halftone->gravity_point_y_inc[i];
335  }
336
337  /* Update gravity in each dot .*/
338  for (x = 0; x < halftone->dots_width; x++)
339    for (y = 0; y < halftone->dots_height; y++)
340    {
341      double gravity = calculate_gravity(halftone, x, y);
342
343      halftone->dots[x + y * halftone->dots_width] = (gravity > 1 ? 1 : (gravity < 0 ? 0 : gravity));
344    }
345}
346
347
348void screenhack (Display *display, Window window)
349{
350  halftone_screen *halftone = init_halftone(display, window);
351  int delay = get_integer_resource ("delay", "Integer");
352  delay = (delay < 0 ? DEFAULT_DELAY : delay);
353
354  while (1)
355    {
356      repaint_halftone(halftone);
357      update_halftone(halftone);
358      screenhack_handle_events (display);
359
360      if (delay != 0)
361        usleep (delay);
362    }
363}
Note: See TracBrowser for help on using the repository browser.