http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / ccurve.c
1 /* ccurve, Copyright (c) 1998, 1999
2  *  Rick Campbell <rick@campbellcentral.org>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or
10  * implied warranty.
11  *
12  */
13
14 /* Draw self-similar linear fractals including the classic ``C Curve''
15  * 
16  * 16 Aug 1999  Rick Campbell <rick@campbellcentral.org>
17  *      Eliminated sub-windows-with-backing-store-double-buffering crap in
18  *      favor of drawing the new image in a pixmap and then splatting that on
19  *      the window.
20  *
21  * 19 Dec 1998  Rick Campbell <rick@campbellcentral.org>
22  *      Original version.
23  */
24
25 #include <assert.h>
26 #include <math.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
30
31 #include "screenhack.h"
32 #include "colors.h"
33 #include "erase.h"
34
35 #define SQRT3 (1.73205080756887729353)
36 #define MAXIMUM_COLOR_COUNT (256)
37 #define EPSILON (1e-5)
38
39 typedef struct Position_struct
40 {
41     double x;
42     double y;
43 }
44 Position;
45
46 typedef struct Segment_struct
47 {
48     double angle;
49     double length;
50 }
51 Segment;
52
53 struct state {
54   Display *dpy;
55   Window window;
56
57   int                  color_count;
58   int                  color_index;
59   Colormap             color_map;
60   XColor               colors [MAXIMUM_COLOR_COUNT];
61   int                  line_count;
62   int                  maximum_lines;
63   double               plot_maximum_x;
64   double               plot_maximum_y;
65   double               plot_minimum_x;
66   double               plot_minimum_y;
67   int                  total_lines;
68
69   unsigned long int    background;
70   GC                   context;
71   Pixmap               pixmap;
72   int                  width;
73   int                  height;
74   float                delay;
75   float                delay2;
76
77   int    draw_index;
78
79   int draw_iterations;
80   double draw_maximum_x;
81   double draw_maximum_y;
82   double draw_minimum_x;
83   double draw_minimum_y;
84   int draw_segment_count;
85   Segment* draw_segments;
86   double draw_x1;
87   double draw_y1;
88   double draw_x2;
89   double draw_y2;
90 };
91
92
93
94
95 /* normalize alters the sequence to go from (0,0) to (1,0) */
96 static void
97 normalized_plot (int       segment_count,
98                  Segment*  segments,
99                  Position* points)
100 {
101     double   angle = 0.0;
102     double   cosine = 0.0;
103     int      index = 0;
104     double   length = 0.0;
105     double   sine = 0.0;
106     double   x = 0.0;
107     double   y = 0.0;
108
109     for (index = 0; index < segment_count; ++index)
110     {
111         Segment* segment = segments + index;
112         double length = segment->length;
113         double angle = segment->angle;
114
115         x += length * cos (angle);
116         y += length * sin (angle);
117         points [index].x = x;
118         points [index].y = y;
119     }
120     angle = -(atan2 (y, x));
121     cosine = cos (angle);
122     sine = sin (angle);
123     length = sqrt ((x * x) + (y * y));
124     /* rotate and scale */
125     for (index = 0; index < segment_count; ++index)
126     {
127         double temp_x = points [index].x;
128         double temp_y = points [index].y;
129         points [index].x = ((temp_x * cosine) + (temp_y * (-sine))) / length;
130         points [index].y = ((temp_x * sine) + (temp_y * cosine)) / length;
131     }
132 }
133
134 static void
135 copy_points (int       segment_count,
136              Position* source,
137              Position* target)
138 {
139     int      index = 0;
140
141     for (index = 0; index < segment_count; ++index)
142     {
143         target [index] = source [index];
144     }
145 }
146
147 static void
148 realign (double    x1,
149          double    y1,
150          double    x2,
151          double    y2,
152          int       segment_count,
153          Position* points)
154 {
155     double angle = 0.0;
156     double cosine = 0.0;
157     double delta_x = 0.0;
158     double delta_y = 0.0;
159     int    index = 0;
160     double length = 0.0;
161     double sine = 0.0;
162
163     delta_x = x2 - x1;
164     delta_y = y2 - y1;
165     angle = atan2 (delta_y, delta_x);
166     cosine = cos (angle);
167     sine = sin (angle);
168     length = sqrt ((delta_x * delta_x) + (delta_y * delta_y));
169     /* rotate, scale, then shift */
170     for (index = 0; index < segment_count; ++index)
171     {
172         double temp_x = points [index].x;
173         double temp_y = points [index].y;
174         points [index].x
175             = (length * ((temp_x * cosine) + (temp_y * (-sine)))) + x1;
176         points [index].y
177             = (length * ((temp_x * sine) + (temp_y * cosine))) + y1;
178     }
179 }
180
181 static void
182 self_similar_normalized (struct state *st,
183                          int       iterations,
184                          double    x1,
185                          double    y1,
186                          double    x2,
187                          double    y2,
188                          double    maximum_x,
189                          double    maximum_y,
190                          double    minimum_x,
191                          double    minimum_y,
192                          int       segment_count,
193                          Position* points)
194 {
195     if (iterations == 0)
196     {
197         double delta_x = maximum_x - minimum_x;
198         double delta_y = maximum_y - minimum_y;
199         st->color_index = (int)(((double)(st->line_count * st->color_count))
200                             / ((double)st->total_lines));
201         ++st->line_count;
202         XSetForeground (st->dpy, st->context, st->colors [st->color_index].pixel);
203         if (st->plot_maximum_x < x1) st->plot_maximum_x = x1;
204         if (st->plot_maximum_x < x2) st->plot_maximum_x = x2;
205         if (st->plot_maximum_y < y1) st->plot_maximum_y = y1;
206         if (st->plot_maximum_y < y2) st->plot_maximum_y = y2;
207         if (st->plot_minimum_x > x1) st->plot_minimum_x = x1;
208         if (st->plot_minimum_x > x2) st->plot_minimum_x = x2;
209         if (st->plot_minimum_y > y1) st->plot_minimum_y = y1;
210         if (st->plot_minimum_y > y2) st->plot_minimum_y = y2;
211         XDrawLine (st->dpy, st->pixmap, st->context,
212                    (int)(((x1 - minimum_x) / delta_x) * st->width),
213                    (int)(((maximum_y - y1) / delta_y) * st->height),
214                    (int)(((x2 - minimum_x) / delta_x) * st->width),
215                    (int)(((maximum_y - y2) / delta_y) * st->height));
216     }
217     else
218     {
219         int       index = 0;
220         double    next_x = 0.0;
221         double    next_y = 0.0;
222         Position* replacement = (Position*)NULL;
223         double    x = 0.0;
224         double    y = 0.0;
225
226         replacement = (Position*)(malloc (segment_count * sizeof (Segment)));
227         copy_points (segment_count, points, replacement);
228         assert (fabs ((replacement [segment_count - 1].x) - 1.0) < EPSILON);
229         assert (fabs (replacement [segment_count - 1].y) < EPSILON);
230         realign (x1, y1, x2, y2, segment_count, replacement);
231         assert (fabs (x2 - (replacement [segment_count - 1].x)) < EPSILON);
232         assert (fabs (y2 - (replacement [segment_count - 1].y)) < EPSILON);
233         x = x1;
234         y = y1;
235         for (index = 0; index < segment_count; ++index)
236         {
237             next_x = replacement [index].x;
238             next_y = replacement [index].y;
239             self_similar_normalized (st, 
240                                      iterations - 1, x, y, next_x, next_y,
241                                      maximum_x, maximum_y,
242                                      minimum_x, minimum_y,
243                                      segment_count, points);
244             x = next_x;
245             y = next_y;
246         }
247         free((void*)replacement);
248     }
249 }
250
251 static void
252 self_similar (struct state *st,
253               Pixmap   pixmap,
254               GC       context,
255               int      width,
256               int      height,
257               int      iterations,
258               double   x1,
259               double   y1,
260               double   x2,
261               double   y2,
262               double   maximum_x,
263               double   maximum_y,
264               double   minimum_x,
265               double   minimum_y,
266               int      segment_count,
267               Segment* segments)
268 {
269     Position* points = (Position*)NULL;
270
271     points = (Position*)(malloc (segment_count * sizeof (Position)));
272     normalized_plot (segment_count, segments, points);
273     assert (fabs ((points [segment_count - 1].x) - 1.0) < EPSILON);
274     assert (fabs (points [segment_count - 1].y) < EPSILON);
275     self_similar_normalized (st, iterations,
276                              x1, y1, x2, y2,
277                              maximum_x, maximum_y,
278                              minimum_x, minimum_y,
279                              segment_count, points);
280     free((void*)points);
281 }
282
283 static
284 double
285 random_double (double base,
286                double limit,
287                double epsilon)
288 {
289     double       range = 0.0;
290     unsigned int steps = 0;
291
292     assert (base < limit);
293     assert (epsilon > 0.0);
294     range = limit - base;
295     steps = (unsigned int)(floor (range / epsilon));
296     return base + ((random () % steps) * epsilon);
297 }
298
299 static void
300 select_2_pattern (Segment* segments)
301 {
302     if ((random () % 2) == 0)
303     {
304         if ((random () % 2) == 0)
305         {
306             segments [0].angle  = -M_PI_4;
307             segments [0].length = M_SQRT2;
308             segments [1].angle  = M_PI_4;
309             segments [1].length = M_SQRT2;
310         }
311         else
312         {
313             segments [0].angle  = M_PI_4;
314             segments [0].length = M_SQRT2;
315             segments [1].angle  = -M_PI_4;
316             segments [1].length = M_SQRT2;
317         }
318     }
319     else
320     {
321         segments [0].angle
322             = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0);
323         segments [0].length = random_double (0.25, 0.67, 0.001);
324         if ((random () % 2) == 0)
325         {
326             segments [1].angle = -(segments [0].angle);
327             segments [1].length = segments [0].length;
328         }
329         else
330         {
331             segments [1].angle = random_double ((-M_PI) / 3.0,
332                                                 (-M_PI) / 6.0,
333                                                 M_PI / 180.0);
334             segments [1].length = random_double (0.25, 0.67, 0.001);
335         }       
336     }
337 }
338
339 static void
340 select_3_pattern (Segment* segments)
341 {
342     switch (random () % 5)
343     {
344      case 0:
345         if ((random () % 2) == 0)
346         {
347             segments [0].angle  = M_PI_4;
348             segments [0].length = M_SQRT2 / 4.0;
349             segments [1].angle  = -M_PI_4;
350             segments [1].length = M_SQRT2 / 2.0;
351             segments [2].angle  = M_PI_4;
352             segments [2].length = M_SQRT2 / 4.0;
353         }
354         else
355         {
356             segments [0].angle  = -M_PI_4;
357             segments [0].length = M_SQRT2 / 4.0;
358             segments [1].angle  = M_PI_4;
359             segments [1].length = M_SQRT2 / 2.0;
360             segments [2].angle  = -M_PI_4;
361             segments [2].length = M_SQRT2 / 4.0;
362         }
363         break;
364      case 1:
365         if ((random () % 2) == 0)
366         {
367             segments [0].angle  = M_PI / 6.0;
368             segments [0].length = 1.0;
369             segments [1].angle  = -M_PI_2;
370             segments [1].length = 1.0;
371             segments [2].angle  = M_PI / 6.0;
372             segments [2].length = 1.0;
373         }
374         else
375         {
376             segments [0].angle  = -M_PI / 6.0;
377             segments [0].length = 1.0;
378             segments [1].angle  = M_PI_2;
379             segments [1].length = 1.0;
380             segments [2].angle  = -M_PI / 6.0;
381             segments [2].length = 1.0;
382         }
383         break;
384      case 2:
385      case 3:
386      case 4:
387         segments [0].angle
388             = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0);
389         segments [0].length = random_double (0.25, 0.67, 0.001);
390         segments [1].angle
391             = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0);
392         segments [1].length = random_double (0.25, 0.67, 0.001);
393         if ((random () % 3) == 0)
394         {
395             if ((random () % 2) == 0)
396             {
397                 segments [2].angle = segments [0].angle;
398             }
399             else
400             {
401                 segments [2].angle = -(segments [0].angle);
402             }
403             segments [2].length = segments [0].length;
404         }
405         else
406         {
407             segments [2].angle
408                 = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0);
409             segments [2].length = random_double (0.25, 0.67, 0.001);
410         }
411         break;
412     }
413 }
414
415 static void
416 select_4_pattern (Segment* segments)
417 {
418     switch (random () % 9)
419     {
420      case 0:
421         if ((random () % 2) == 0)
422         {
423             double length = random_double (0.25, 0.50, 0.001);
424
425             segments [0].angle  = 0.0;
426             segments [0].length = 0.5;
427             segments [1].angle  = M_PI_2;
428             segments [1].length = length;
429             segments [2].angle  = -M_PI_2;
430             segments [2].length = length;
431             segments [3].angle  = 0.0;
432             segments [3].length = 0.5;
433         }
434         else
435         {
436             double length = random_double (0.25, 0.50, 0.001);
437
438             segments [0].angle  = 0.0;
439             segments [0].length = 0.5;
440             segments [1].angle  = -M_PI_2;
441             segments [1].length = length;
442             segments [2].angle  = M_PI_2;
443             segments [2].length = length;
444             segments [3].angle  = 0.0;
445             segments [3].length = 0.5;
446         }
447         break;
448      case 1:
449         if ((random () % 2) == 0)
450         {
451             segments [0].angle  = 0.0;
452             segments [0].length = 0.5;
453             segments [1].angle  = M_PI_2;
454             segments [1].length = 0.45;
455             segments [2].angle  = -M_PI_2;
456             segments [2].length = 0.45;
457             segments [3].angle  = 0.0;
458             segments [3].length = 0.5;
459         }
460         else
461         {
462             segments [0].angle  = 0.0;
463             segments [0].length = 0.5;
464             segments [1].angle  = -M_PI_2;
465             segments [1].length = 0.45;
466             segments [2].angle  = M_PI_2;
467             segments [2].length = 0.45;
468             segments [3].angle  = 0.0;
469             segments [3].length = 0.5;
470         }
471         break;
472      case 2:
473         if ((random () % 2) == 0)
474         {
475             segments [0].angle  = 0.0;
476             segments [0].length = 1.0;
477             segments [1].angle  = (5.0 * M_PI) / 12.0;
478             segments [1].length = 1.2;
479             segments [2].angle  = (-5.0 * M_PI) / 12.0;
480             segments [2].length = 1.2;
481             segments [3].angle  = 0.0;
482             segments [3].length = 1.0;
483         }
484         else
485         {
486             segments [0].angle  = 0.0;
487             segments [0].length = 1.0;
488             segments [1].angle  = (-5.0 * M_PI) / 12.0;
489             segments [1].length = 1.2;
490             segments [2].angle  = (5.0 * M_PI) / 12.0;
491             segments [2].length = 1.2;
492             segments [3].angle  = 0.0;
493             segments [3].length = 1.0;
494         }
495         break;
496      case 3:
497         if ((random () % 2) == 0)
498         {
499             double angle
500                 = random_double (M_PI / 4.0,
501                                  M_PI_2,
502                                  M_PI / 180.0);
503
504             segments [0].angle  = 0.0;
505             segments [0].length = 1.0;
506             segments [1].angle  = angle;
507             segments [1].length = 1.2;
508             segments [2].angle  = (-angle);
509             segments [2].length = 1.2;
510             segments [3].angle  = 0.0;
511             segments [3].length = 1.0;
512         }
513         else
514         {
515             double angle
516                 = random_double (M_PI / 4.0,
517                                  M_PI_2,
518                                  M_PI / 180.0);
519
520             segments [0].angle  = 0.0;
521             segments [0].length = 1.0;
522             segments [1].angle  = (-angle);
523             segments [1].length = 1.2;
524             segments [2].angle  = angle;
525             segments [2].length = 1.2;
526             segments [3].angle  = 0.0;
527             segments [3].length = 1.0;
528         }
529         break;
530      case 4:
531         if ((random () % 2) == 0)
532         {
533             double angle
534                 = random_double (M_PI / 4.0,
535                                  M_PI_2,
536                                  M_PI / 180.0);
537
538             segments [0].angle  = 0.0;
539             segments [0].length = 1.0;
540             segments [1].angle  = angle;
541             segments [1].length = 1.2;
542             segments [2].angle  = (-angle);
543             segments [2].length = 1.2;
544             segments [3].angle  = 0.0;
545             segments [3].length = 1.0;
546         }
547         else
548         {
549             double angle
550                 = random_double (M_PI / 4.0,
551                                  M_PI_2,
552                                  M_PI / 180.0);
553
554             segments [0].angle  = 0.0;
555             segments [0].length = 1.0;
556             segments [1].angle  = (-angle);
557             segments [1].length = 1.2;
558             segments [2].angle  = angle;
559             segments [2].length = 1.2;
560             segments [3].angle  = 0.0;
561             segments [3].length = 1.0;
562         }
563         break;
564      case 5:
565         if ((random () % 2) == 0)
566         {
567             double angle
568                 = random_double (M_PI / 4.0,
569                                  M_PI_2,
570                                  M_PI / 180.0);
571             double length = random_double (0.25, 0.50, 0.001);
572
573             segments [0].angle  = 0.0;
574             segments [0].length = 1.0;
575             segments [1].angle  = angle;
576             segments [1].length = length;
577             segments [2].angle  = (-angle);
578             segments [2].length = length;
579             segments [3].angle  = 0.0;
580             segments [3].length = 1.0;
581         }
582         else
583         {
584             double angle
585                 = random_double (M_PI / 4.0,
586                                  M_PI_2,
587                                  M_PI / 180.0);
588             double length = random_double (0.25, 0.50, 0.001);
589
590             segments [0].angle  = 0.0;
591             segments [0].length = 1.0;
592             segments [1].angle  = (-angle);
593             segments [1].length = length;
594             segments [2].angle  = angle;
595             segments [2].length = length;
596             segments [3].angle  = 0.0;
597             segments [3].length = 1.0;
598         }
599         break;
600      case 6:
601      case 7:
602      case 8:
603         segments [0].angle
604             = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
605         segments [0].length = random_double (0.25, 0.50, 0.001);
606         segments [1].angle
607             = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
608         segments [1].length = random_double (0.25, 0.50, 0.001);
609         if ((random () % 3) == 0)
610         {
611             segments [2].angle
612                 = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
613             segments [2].length = random_double (0.25, 0.50, 0.001);
614             segments [3].angle
615                 = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
616             segments [3].length = random_double (0.25, 0.50, 0.001);
617         }
618         else
619         {
620             if ((random () % 2) == 0)
621             {
622                 segments [2].angle = -(segments [1].angle);
623                 segments [2].length = segments [1].length;
624                 segments [3].angle = -(segments [0].angle);
625                 segments [3].length = segments [0].length;
626             }
627             else
628             {
629                 segments [2].angle = segments [1].angle;
630                 segments [2].length = segments [1].length;
631                 segments [3].angle = segments [0].angle;
632                 segments [3].length = segments [0].length;
633             }
634         }
635         break;
636     }
637 }
638
639 static void
640 select_pattern (int      segment_count,
641                 Segment* segments)
642 {
643     switch (segment_count)
644     {
645      case 2:
646         select_2_pattern (segments);
647         break;
648      case 3:
649         select_3_pattern (segments);
650         break;
651      case 4:
652         select_4_pattern (segments);
653         break;
654      default:
655         fprintf (stderr, "\nBad segment count, must be 2, 3, or 4.\n");
656         exit (1);
657     }
658 }
659
660 #define Y_START (0.5)
661
662 static void *
663 ccurve_init (Display *dpy, Window window)
664 {
665   struct state *st = (struct state *) calloc (1, sizeof(*st));
666     unsigned long int    black           = 0;
667     int                  depth           = 0;
668     XWindowAttributes    hack_attributes;
669     XGCValues            values;
670     unsigned long int    white           = 0;
671
672     st->dpy = dpy;
673     st->window = window;
674
675     st->delay = get_float_resource (st->dpy, "delay", "Integer");
676     st->delay2 = get_float_resource (st->dpy, "pause", "Integer");
677     st->maximum_lines = get_integer_resource (st->dpy, "limit", "Integer");
678     black = BlackPixel (st->dpy, DefaultScreen (st->dpy));
679     white = WhitePixel (st->dpy, DefaultScreen (st->dpy));
680     st->background = black;
681     XGetWindowAttributes (st->dpy, st->window, &hack_attributes);
682     st->width = hack_attributes.width;
683     st->height = hack_attributes.height;
684     depth = hack_attributes.depth;
685     st->color_map = hack_attributes.colormap;
686     st->pixmap = XCreatePixmap (st->dpy, st->window, st->width, st->height, depth);
687     values.foreground = white;
688     values.background = black;
689     st->context = XCreateGC (st->dpy, st->window, GCForeground | GCBackground,
690                          &values);
691     st->color_count = MAXIMUM_COLOR_COUNT;
692     make_color_loop (st->dpy, st->color_map,
693                      0,   1, 1,
694                      120, 1, 1,
695                      240, 1, 1,
696                      st->colors, &st->color_count, True, False);
697     if (st->color_count <= 0)
698     {
699         st->color_count = 1;
700         st->colors [0].red = st->colors [0].green = st->colors [0].blue = 0xFFFF;
701         XAllocColor (st->dpy, st->color_map, &st->colors [0]);
702     }
703
704     st->draw_maximum_x =  1.20;
705     st->draw_maximum_y =  0.525;
706     st->draw_minimum_x = -0.20;
707     st->draw_minimum_y = -0.525;
708     st->draw_x2 = 1.0;
709
710     return st;
711 }
712
713 static unsigned long
714 ccurve_draw (Display *dpy, Window window, void *closure)
715 {
716   struct state *st = (struct state *) closure;
717         static const int lengths [] = { 4, 4, 4, 4, 4, 3, 3, 3, 2 };
718
719         if (st->draw_index == 0)
720           {
721         st->draw_segment_count
722             = lengths [random () % (sizeof (lengths) / sizeof (int))];
723         st->draw_segments
724             = (Segment*)(malloc ((st->draw_segment_count) * sizeof (Segment)));
725         select_pattern (st->draw_segment_count, st->draw_segments);
726         st->draw_iterations = floor (log (st->maximum_lines)
727                                 / log (((double)(st->draw_segment_count))));
728         if ((random () % 3) != 0)
729         {
730             double factor = 0.45;
731             st->draw_x1 += random_double (-factor, factor, 0.001);
732             st->draw_y1 += random_double (-factor, factor, 0.001);
733             st->draw_x2 += random_double (-factor, factor, 0.001);
734             st->draw_y2 += random_double (-factor, factor, 0.001);
735         }
736 /*      background = (random () % 2) ? black : white; */
737
738         }
739
740         /* for (st->draw_index = 0; st->draw_index < st->draw_iterations; ++st->draw_index) */
741         {
742             double delta_x = 0.0;
743             double delta_y = 0.0;
744
745             XSetForeground (st->dpy, st->context, st->background);
746             XFillRectangle (st->dpy, st->pixmap, st->context, 0, 0, st->width, st->height);
747             st->line_count = 0;
748             st->total_lines = (int)(pow ((double)(st->draw_segment_count),
749                                      (double)st->draw_index));
750             st->plot_maximum_x = -1000.00;
751             st->plot_maximum_y = -1000.00;
752             st->plot_minimum_x =  1000.00;
753             st->plot_minimum_y =  1000.00;
754             self_similar (st, st->pixmap, st->context, st->width, st->height, st->draw_index,
755                           st->draw_x1, st->draw_y1, st->draw_x2, st->draw_y2,
756                           st->draw_maximum_x,
757                           st->draw_maximum_y,
758                           st->draw_minimum_x,
759                           st->draw_minimum_y,
760                           st->draw_segment_count, st->draw_segments);
761             delta_x = st->plot_maximum_x - st->plot_minimum_x;
762             delta_y = st->plot_maximum_y - st->plot_minimum_y;
763             st->draw_maximum_x = st->plot_maximum_x + (delta_x * 0.2);
764             st->draw_maximum_y = st->plot_maximum_y + (delta_y * 0.2);
765             st->draw_minimum_x = st->plot_minimum_x - (delta_x * 0.2);
766             st->draw_minimum_y = st->plot_minimum_y - (delta_y * 0.2);
767             delta_x = st->draw_maximum_x - st->draw_minimum_x;
768             delta_y = st->draw_maximum_y - st->draw_minimum_y;
769             if ((delta_y / delta_x) > (((double)st->height) / ((double)st->width)))
770             {
771                 double new_delta_x
772                     = (delta_y * ((double)st->width)) / ((double)st->height);
773                 st->draw_minimum_x -= (new_delta_x - delta_x) / 2.0;
774                 st->draw_maximum_x += (new_delta_x - delta_x) / 2.0;
775             }
776             else
777             {
778                 double new_delta_y
779                     = (delta_x * ((double)st->height)) / ((double)st->width);
780                 st->draw_minimum_y -= (new_delta_y - delta_y) / 2.0;
781                 st->draw_maximum_y += (new_delta_y - delta_y) / 2.0;
782             }
783             XCopyArea (st->dpy, st->pixmap, st->window, st->context, 0, 0, st->width, st->height,
784                        0, 0);
785         }
786         st->draw_index++;
787
788         if (st->draw_index >= st->draw_iterations)
789           {
790             st->draw_index = 0;
791             free((void*)st->draw_segments);
792             st->draw_segments = 0;
793             return (int) (1000000 * st->delay);
794           }
795         else
796           return (int) (1000000 * st->delay2);
797 }
798
799 static void
800 ccurve_reshape (Display *dpy, Window window, void *closure, 
801                  unsigned int w, unsigned int h)
802 {
803 }
804
805 static Bool
806 ccurve_event (Display *dpy, Window window, void *closure, XEvent *event)
807 {
808   return False;
809 }
810
811 static void
812 ccurve_free (Display *dpy, Window window, void *closure)
813 {
814 }
815
816
817 static const char *ccurve_defaults [] =
818 {
819     ".background:  black",
820     ".foreground:  white",
821     ".delay:      3",
822     ".pause:      0.4",
823     ".limit: 200000",
824     0
825 };
826
827 static XrmOptionDescRec ccurve_options [] =
828 {
829     { "-delay", ".delay", XrmoptionSepArg, 0 },
830     { "-pause", ".pause", XrmoptionSepArg, 0 },
831     { "-limit", ".limit", XrmoptionSepArg, 0 },
832     { 0, 0, 0, 0 }
833 };
834
835 XSCREENSAVER_MODULE ("CCurve", ccurve)