~ubuntu-branches/ubuntu/lucid/xscreensaver/lucid

« back to all changes in this revision

Viewing changes to hacks/critical.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2007-12-06 09:53:12 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20071206095312-fkzcwe4vqm50z208
Tags: 5.04-1ubuntu1
* Merge from debian unstable, remaining changes:
  - split xscreensaver into xscreensaver, xscreensaver-data (hacks we ship),
    xscreensaver-data-extra (hacks in universe). split out gl hacks for
    universe to xscreensaver-gl-extra
  - use fridge for rss screensavers
  - create and install .desktop files for gnome-screensaver

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include <stdlib.h>
27
27
#include <assert.h>
28
28
 
29
 
char *progclass = "Critical";
30
 
 
31
29
 
32
30
typedef struct {
33
31
  int width, height;            /* in cells */
40
38
} CriticalSettings;
41
39
 
42
40
 
43
 
CriticalModel * model_allocate (int w, int h);
44
 
void model_initialize (CriticalModel *model);
45
 
 
46
 
/* Options this module understands.  */
47
 
XrmOptionDescRec options[] = {
48
 
  { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
49
 
  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
50
 
  { "-colorscheme",     ".colorscheme", XrmoptionSepArg, 0 },
51
 
  { "-restart",         ".restart",     XrmoptionSepArg, 0 },
52
 
  { "-cellsize",        ".cellsize",    XrmoptionSepArg, 0 },
53
 
  { "-batchcount",      ".batchcount",  XrmoptionSepArg, 0 },
54
 
  { "-trail",           ".trail",       XrmoptionSepArg, 0 },
55
 
  { 0, 0, 0, 0 }                /* end */
56
 
};
57
 
 
58
 
 
59
 
/* Default xrm resources. */
60
 
char *defaults[] = {
61
 
  ".background:                 black",
62
 
  "*colorscheme:                smooth",
63
 
  "*delay:                      10000", 
64
 
  "*ncolors:                    64",
65
 
  "*restart:                    8",
66
 
  "*batchcount:                 1500",
67
 
  "*trail:                      50",
68
 
  0                             /* end */
69
 
};
70
 
 
71
 
 
72
 
int
 
41
/* Number of screens that should be drawn before reinitializing the
 
42
   model, and count of the number of screens done so far. */
 
43
 
 
44
struct state {
 
45
  Display *dpy;
 
46
  Window window;
 
47
 
 
48
  int n_restart, i_restart;
 
49
  XWindowAttributes     wattr;
 
50
  CriticalModel         *model;
 
51
  int                   batchcount;
 
52
  XPoint                *history; /* in cell coords */
 
53
  long                  delay_usecs;
 
54
  GC                    fgc, bgc;
 
55
  XGCValues             gcv;
 
56
  CriticalSettings      settings;
 
57
 
 
58
  int                   d_n_colors;
 
59
  XColor                        *d_colors;
 
60
  int                   lines_per_color;
 
61
  int                   d_i_color;
 
62
  int                   d_pos;
 
63
  int                   d_wrapped;
 
64
 
 
65
  int d_i_batch;
 
66
  eraser_state *eraser;
 
67
 
 
68
};
 
69
 
 
70
 
 
71
static CriticalModel * model_allocate (int w, int h);
 
72
static void model_initialize (CriticalModel *);
 
73
 
 
74
 
 
75
static int
73
76
clip (int low, int val, int high)
74
77
{
75
78
  if (val < low)
84
87
/* Allocate an return a new simulation model datastructure.
85
88
 */
86
89
 
87
 
CriticalModel *
 
90
static CriticalModel *
88
91
model_allocate (int model_w, int model_h)
89
92
{
90
 
  CriticalModel         *model;
91
 
 
92
 
  model = malloc (sizeof (CriticalModel));
93
 
  if (!model)
94
 
    return 0;
95
 
 
96
 
  model->width = model_w;
97
 
  model->height = model_h;
98
 
 
99
 
  model->cells = malloc (sizeof (unsigned short) * model_w * model_h);
100
 
  if (!model->cells)
101
 
    return 0;
102
 
 
103
 
  return model;
 
93
  CriticalModel         *mm;
 
94
 
 
95
  mm = malloc (sizeof (CriticalModel));
 
96
  if (!mm)
 
97
    return 0;
 
98
 
 
99
  mm->width = model_w;
 
100
  mm->height = model_h;
 
101
 
 
102
  mm->cells = malloc (sizeof (unsigned short) * model_w * model_h);
 
103
  if (!mm->cells)
 
104
    return 0;
 
105
 
 
106
  return mm;
104
107
}
105
108
 
106
109
 
123
126
*/
124
127
 
125
128
 
126
 
void
127
 
model_initialize (CriticalModel *model)
 
129
static void
 
130
model_initialize (CriticalModel *mm)
128
131
{
129
132
  int i;
130
133
  
131
 
  for (i = model->width * model->height - 1; i >= 0; i--)
 
134
  for (i = mm->width * mm->height - 1; i >= 0; i--)
132
135
    {
133
 
      model->cells[i] = (unsigned short) random ();
 
136
      mm->cells[i] = (unsigned short) random ();
134
137
    }
135
138
}
136
139
 
143
146
   Neighbours that fall off the edge of the model are simply
144
147
   ignored. */
145
148
static void
146
 
model_step (CriticalModel *model, XPoint *ptop)
 
149
model_step (CriticalModel *mm, XPoint *ptop)
147
150
{
148
151
  int                   x, y, i;
149
152
  int                   dx, dy;
153
156
  /* Find the top cell */
154
157
  top_value = 0;
155
158
  i = 0;
156
 
  for (y = 0; y < model->height; y++)
157
 
    for (x = 0; x < model->width; x++)
 
159
  for (y = 0; y < mm->height; y++)
 
160
    for (x = 0; x < mm->width; x++)
158
161
      {
159
 
        if (model->cells[i] >= top_value)
 
162
        if (mm->cells[i] >= top_value)
160
163
          {
161
 
            top_value = model->cells[i];
 
164
            top_value = mm->cells[i];
162
165
            top_x = x;
163
166
            top_y = y;
164
167
          }
168
171
  /* Replace it and its neighbours with new random values */
169
172
  for (dy = -1; dy <= 1; dy++)
170
173
    {
171
 
      int y = top_y + dy;
172
 
      if (y < 0  ||  y >= model->height)
 
174
      int yy = top_y + dy;
 
175
      if (yy < 0  ||  yy >= mm->height)
173
176
        continue;
174
177
      
175
178
      for (dx = -1; dx <= 1; dx++)
176
179
        {
177
 
          int x = top_x + dx;
178
 
          if (x < 0  ||  x >= model->width)
 
180
          int xx = top_x + dx;
 
181
          if (xx < 0  ||  xx >= mm->width)
179
182
            continue;
180
183
          
181
 
          model->cells[y * model->width + x] = (unsigned short) random();
 
184
          mm->cells[yy * mm->width + xx] = (unsigned short) random();
182
185
        }
183
186
    }
184
187
 
189
192
 
190
193
/* Construct and return in COLORS and N_COLORS a new set of colors,
191
194
   depending on the resource settings.  */
192
 
void
193
 
setup_colormap (Display *dpy, XWindowAttributes *wattr,
194
 
                XColor **colors,
195
 
                int *n_colors)
 
195
static void
 
196
setup_colormap (struct state *st, XColor **colors, int *n_colors)
196
197
{
197
198
  Bool                  writable;
198
199
  char const *          color_scheme;
199
200
 
200
201
  /* Make a colormap */
201
 
  *n_colors = get_integer_resource ("ncolors", "Integer");
 
202
  *n_colors = get_integer_resource (st->dpy, "ncolors", "Integer");
202
203
  if (*n_colors < 3)
203
204
    *n_colors = 3;
204
205
  
211
212
    }
212
213
 
213
214
  writable = False;
214
 
  color_scheme = get_string_resource ("colorscheme", "ColorScheme");
 
215
  color_scheme = get_string_resource (st->dpy, "colorscheme", "ColorScheme");
215
216
  
216
217
  if (!strcmp (color_scheme, "random"))
217
218
    {
218
 
      make_random_colormap (dpy, wattr->visual,
219
 
                            wattr->colormap,
 
219
      make_random_colormap (st->dpy, st->wattr.visual,
 
220
                            st->wattr.colormap,
220
221
                            *colors, n_colors,
221
222
                            True, True, &writable, True);
222
223
    }
223
224
  else if (!strcmp (color_scheme, "smooth"))
224
225
    {
225
 
      make_smooth_colormap (dpy, wattr->visual,
226
 
                            wattr->colormap,
 
226
      make_smooth_colormap (st->dpy, st->wattr.visual,
 
227
                            st->wattr.colormap,
227
228
                            *colors, n_colors,
228
229
                            True, &writable, True);
229
230
    }
230
231
  else 
231
232
    {
232
 
      make_uniform_colormap (dpy, wattr->visual,
233
 
                             wattr->colormap,
 
233
      make_uniform_colormap (st->dpy, st->wattr.visual,
 
234
                             st->wattr.colormap,
234
235
                             *colors, n_colors, True,
235
236
                             &writable, True);
236
237
    }
239
240
 
240
241
/* Free allocated colormap created by setup_colormap. */
241
242
static void
242
 
free_colormap (Display *dpy, XWindowAttributes *wattr,
243
 
               XColor **colors, int n_colors)
 
243
free_colormap (struct state *st, XColor **colors, int n_colors)
244
244
{
245
 
  free_colors (dpy, wattr->colormap, *colors, n_colors);
 
245
  free_colors (st->dpy, st->wattr.colormap, *colors, n_colors);
246
246
  free (*colors);
247
247
}
248
248
 
250
250
 
251
251
/* Draw one step of the hack.  Positions are cell coordinates. */
252
252
static void
253
 
draw_step (CriticalSettings *settings,
254
 
           Display *dpy, Window window, GC gc,
255
 
           int pos, XPoint *history)
 
253
draw_step (struct state *st, GC gc, int pos)
256
254
{
257
 
  int cell_size = settings->cell_size;
 
255
  int cell_size = st->settings.cell_size;
258
256
  int half = cell_size/2;
259
 
  int old_pos = (pos + settings->trail - 1) % settings->trail;
 
257
  int old_pos = (pos + st->settings.trail - 1) % st->settings.trail;
260
258
  
261
 
  pos = pos % settings->trail;
 
259
  pos = pos % st->settings.trail;
262
260
 
263
 
  XDrawLine (dpy, window, gc, 
264
 
             history[pos].x * cell_size + half,
265
 
             history[pos].y * cell_size + half,
266
 
             history[old_pos].x * cell_size + half,
267
 
             history[old_pos].y * cell_size + half);
 
261
  XDrawLine (st->dpy, st->window, gc, 
 
262
             st->history[pos].x * cell_size + half,
 
263
             st->history[pos].y * cell_size + half,
 
264
             st->history[old_pos].x * cell_size + half,
 
265
             st->history[old_pos].y * cell_size + half);
268
266
}
269
267
 
270
268
 
271
269
 
272
 
/* Display a self-organizing criticality screen hack.  The program
273
 
   runs indefinately on the root window. */
274
 
void
275
 
screenhack (Display *dpy, Window window)
 
270
static void *
 
271
critical_init (Display *dpy, Window window)
276
272
{
277
 
  int                   n_colors;
278
 
  XColor                *colors;
 
273
  struct state *st = (struct state *) calloc (1, sizeof(*st));
279
274
  int                   model_w, model_h;
280
 
  CriticalModel         *model;
281
 
  int                   lines_per_color = 10;
282
 
  int                   i_color = 0;
283
 
  long                  delay_usecs;
284
 
  int                   batchcount;
285
 
  XPoint                *history; /* in cell coords */
286
 
  int                   pos = 0;
287
 
  int                   wrapped = 0;
288
 
  GC                    fgc, bgc;
289
 
  XGCValues             gcv;
290
 
  XWindowAttributes     wattr;
291
 
  CriticalSettings      settings;
292
 
 
293
 
  /* Number of screens that should be drawn before reinitializing the
294
 
     model, and count of the number of screens done so far. */
295
 
  int                   n_restart, i_restart;
 
275
  st->dpy = dpy;
 
276
  st->window = window;
296
277
 
297
278
  /* Find window attributes */
298
 
  XGetWindowAttributes (dpy, window, &wattr);
299
 
 
300
 
  batchcount = get_integer_resource ("batchcount", "Integer");
301
 
  if (batchcount < 5)
302
 
    batchcount = 5;
 
279
  XGetWindowAttributes (st->dpy, st->window, &st->wattr);
 
280
 
 
281
  st->batchcount = get_integer_resource (st->dpy, "batchcount", "Integer");
 
282
  if (st->batchcount < 5)
 
283
    st->batchcount = 5;
 
284
 
 
285
  st->lines_per_color = 10;
303
286
 
304
287
  /* For the moment the model size is just fixed -- making it vary
305
288
     with the screen size just makes the hack boring on large
306
289
     screens. */
307
290
  model_w = 80;
308
 
  settings.cell_size = wattr.width / model_w;
309
 
  model_h = wattr.height / settings.cell_size;
 
291
  st->settings.cell_size = st->wattr.width / model_w;
 
292
  model_h = st->settings.cell_size ?
 
293
    st->wattr.height / st->settings.cell_size : 0;
310
294
 
311
295
  /* Construct the initial model state. */
312
296
 
313
 
  settings.trail = clip(2, get_integer_resource ("trail", "Integer"), 1000);
 
297
  st->settings.trail = clip(2, get_integer_resource (st->dpy, "trail", "Integer"), 1000);
314
298
  
315
 
  history = malloc (sizeof history[0] * settings.trail);
316
 
  if (!history)
 
299
  st->history = calloc (st->settings.trail, sizeof (st->history[0]));
 
300
  if (!st->history)
317
301
    {
318
302
      fprintf (stderr, "critical: "
319
303
               "couldn't allocate trail history of %d cells\n",
320
 
               settings.trail);
321
 
      return;
 
304
               st->settings.trail);
 
305
      abort();
322
306
    }
323
307
 
324
 
  model = model_allocate (model_w, model_h);
325
 
  if (!model)
 
308
  st->model = model_allocate (model_w, model_h);
 
309
  if (!st->model)
326
310
    {
327
311
      fprintf (stderr, "critical: error preparing the model\n");
328
 
      return;
 
312
      abort();
329
313
    }
330
314
  
331
315
  /* make a black gc for the background */
332
 
  gcv.foreground = get_pixel_resource ("background", "Background",
333
 
                                       dpy, wattr.colormap);
334
 
  bgc = XCreateGC (dpy, window, GCForeground, &gcv);
335
 
 
336
 
  fgc = XCreateGC (dpy, window, 0, &gcv);
337
 
 
338
 
  delay_usecs = get_integer_resource ("delay", "Integer");
339
 
  n_restart = get_integer_resource ("restart", "Integer");
340
 
    
341
 
  /* xscreensaver will kill or stop us when the user does something
342
 
   * that deserves attention. */
343
 
  i_restart = 0;
344
 
  
345
 
  while (1) {
346
 
    int i_batch;
347
 
 
348
 
    if (i_restart == 0)
349
 
      {
350
 
        /* Time to start a new simulation, this one has probably got
351
 
           to be a bit boring. */
352
 
        setup_colormap (dpy, &wattr, &colors, &n_colors);
353
 
        erase_full_window (dpy, window);
354
 
        model_initialize (model);
355
 
        model_step (model, &history[0]);
356
 
        pos = 1;
357
 
        wrapped = 0;
358
 
      }
359
 
    
360
 
    for (i_batch = batchcount; i_batch; i_batch--)
361
 
      {
362
 
        /* Set color */
363
 
        if ((i_batch % lines_per_color) == 0)
364
 
          {
365
 
            i_color = (i_color + 1) % n_colors;
366
 
            gcv.foreground = colors[i_color].pixel;
367
 
            XChangeGC (dpy, fgc, GCForeground, &gcv);
368
 
          }
369
 
        
370
 
        assert(pos >= 0 && pos < settings.trail);
371
 
        model_step (model, &history[pos]);
372
 
 
373
 
        draw_step (&settings, dpy, window, fgc, pos, history);
374
 
 
375
 
        /* we use the history as a ring buffer, but don't start erasing until
376
 
           we've wrapped around once. */
377
 
        if (++pos >= settings.trail)
378
 
          {
379
 
            pos -= settings.trail;
380
 
            wrapped = 1;
381
 
          }
382
 
 
383
 
        if (wrapped)
384
 
          {
385
 
            draw_step (&settings, dpy, window, bgc, pos+1, history);
386
 
          }
387
 
 
388
 
        XSync (dpy, False); 
389
 
        screenhack_handle_events (dpy);
390
 
        
391
 
        if (delay_usecs)
392
 
          usleep (delay_usecs);
393
 
 
394
 
      }
395
 
    
396
 
    i_restart = (i_restart + 1) % n_restart;
397
 
 
398
 
    if (i_restart == 0)
399
 
      {
400
 
        /* Clean up after completing a simulation. */
401
 
        free_colormap (dpy, &wattr, &colors, n_colors);
402
 
      }
 
316
  st->gcv.foreground = get_pixel_resource (st->dpy, st->wattr.colormap,
 
317
                                       "background", "Background");
 
318
  st->bgc = XCreateGC (st->dpy, st->window, GCForeground, &st->gcv);
 
319
 
 
320
  st->fgc = XCreateGC (st->dpy, st->window, 0, &st->gcv);
 
321
 
 
322
#ifdef HAVE_COCOA
 
323
  jwxyz_XSetAntiAliasing (dpy, st->fgc, False);
 
324
  jwxyz_XSetAntiAliasing (dpy, st->bgc, False);
 
325
#endif
 
326
 
 
327
  st->delay_usecs = get_integer_resource (st->dpy, "delay", "Integer");
 
328
  st->n_restart = get_integer_resource (st->dpy, "restart", "Integer");
 
329
    
 
330
  setup_colormap (st, &st->d_colors, &st->d_n_colors);
 
331
  model_initialize (st->model);
 
332
  model_step (st->model, &st->history[0]);
 
333
  st->d_pos = 1;
 
334
  st->d_wrapped = 0;
 
335
  st->i_restart = 0;
 
336
  st->d_i_batch = st->batchcount;
 
337
 
 
338
  return st;
 
339
}
 
340
 
 
341
static unsigned long
 
342
critical_draw (Display *dpy, Window window, void *closure)
 
343
{
 
344
  struct state *st = (struct state *) closure;
 
345
 
 
346
  if (st->eraser) {
 
347
    st->eraser = erase_window (st->dpy, st->window, st->eraser);
 
348
    return st->delay_usecs;
403
349
  }
404
 
}
 
350
 
 
351
  /* for (d_i_batch = batchcount; d_i_batch; d_i_batch--) */
 
352
    {
 
353
      /* Set color */
 
354
      if ((st->d_i_batch % st->lines_per_color) == 0)
 
355
        {
 
356
          st->d_i_color = (st->d_i_color + 1) % st->d_n_colors;
 
357
          st->gcv.foreground = st->d_colors[st->d_i_color].pixel;
 
358
          XChangeGC (st->dpy, st->fgc, GCForeground, &st->gcv);
 
359
        }
 
360
        
 
361
      assert(st->d_pos >= 0 && st->d_pos < st->settings.trail);
 
362
      model_step (st->model, &st->history[st->d_pos]);
 
363
 
 
364
      draw_step (st, st->fgc, st->d_pos);
 
365
 
 
366
      /* we use the history as a ring buffer, but don't start erasing until
 
367
         we've d_wrapped around once. */
 
368
      if (++st->d_pos >= st->settings.trail)
 
369
        {
 
370
          st->d_pos -= st->settings.trail;
 
371
          st->d_wrapped = 1;
 
372
        }
 
373
 
 
374
      if (st->d_wrapped)
 
375
        {
 
376
          draw_step (st, st->bgc, st->d_pos+1);
 
377
        }
 
378
 
 
379
    }
 
380
    
 
381
  st->d_i_batch--;
 
382
  if (st->d_i_batch < 0)
 
383
    st->d_i_batch = st->batchcount;
 
384
  else
 
385
    return st->delay_usecs;
 
386
 
 
387
  st->i_restart = (st->i_restart + 1) % st->n_restart;
 
388
 
 
389
  if (st->i_restart == 0)
 
390
    {
 
391
      /* Time to start a new simulation, this one has probably got
 
392
         to be a bit boring. */
 
393
      free_colormap (st, &st->d_colors, st->d_n_colors);
 
394
      setup_colormap (st, &st->d_colors, &st->d_n_colors);
 
395
      st->eraser = erase_window (st->dpy, st->window, st->eraser);
 
396
      model_initialize (st->model);
 
397
      model_step (st->model, &st->history[0]);
 
398
      st->d_pos = 1;
 
399
      st->d_wrapped = 0;
 
400
      st->d_i_batch = st->batchcount;
 
401
    }
 
402
 
 
403
  return st->delay_usecs;
 
404
}
 
405
 
 
406
static void
 
407
critical_reshape (Display *dpy, Window window, void *closure, 
 
408
                 unsigned int w, unsigned int h)
 
409
{
 
410
}
 
411
 
 
412
static Bool
 
413
critical_event (Display *dpy, Window window, void *closure, XEvent *event)
 
414
{
 
415
  return False;
 
416
}
 
417
 
 
418
static void
 
419
critical_free (Display *dpy, Window window, void *closure)
 
420
{
 
421
  struct state *st = (struct state *) closure;
 
422
  free (st);
 
423
}
 
424
 
 
425
 
 
426
/* Options this module understands.  */
 
427
static XrmOptionDescRec critical_options[] = {
 
428
  { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
 
429
  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
 
430
  { "-colorscheme",     ".colorscheme", XrmoptionSepArg, 0 },
 
431
  { "-restart",         ".restart",     XrmoptionSepArg, 0 },
 
432
  { "-batchcount",      ".batchcount",  XrmoptionSepArg, 0 },
 
433
  { "-trail",           ".trail",       XrmoptionSepArg, 0 },
 
434
  { 0, 0, 0, 0 }                /* end */
 
435
};
 
436
 
 
437
 
 
438
/* Default xrm resources. */
 
439
static const char *critical_defaults[] = {
 
440
  ".background:                 black",
 
441
  "*colorscheme:                smooth",
 
442
  "*delay:                      10000", 
 
443
  "*ncolors:                    64",
 
444
  "*restart:                    8",
 
445
  "*batchcount:                 1500",
 
446
  "*trail:                      50",
 
447
  0                             /* end */
 
448
};
 
449
 
 
450
 
 
451
XSCREENSAVER_MODULE ("Critical", critical)