1555d88d127541f8890964b9c675ad12f7fd9e3c
[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 static int                  color_count = 0;
54 static int                  color_index = 0;
55 static Colormap             color_map = (Colormap)NULL;
56 static XColor               colors [MAXIMUM_COLOR_COUNT];
57 static int                  line_count = 0;
58 static int                  maximum_lines = 0;
59 static double               plot_maximum_x = -1000.00;
60 static double               plot_maximum_y = -1000.00;
61 static double               plot_minimum_x =  1000.00;
62 static double               plot_minimum_y =  1000.00;
63 static int                  total_lines = 0;
64
65 /* normalize alters the sequence to go from (0,0) to (1,0) */
66 static
67 void
68 normalized_plot (int       segment_count,
69                  Segment*  segments,
70                  Position* points)
71 {
72     double   angle = 0.0;
73     double   cosine = 0.0;
74     int      index = 0;
75     double   length = 0.0;
76     double   sine = 0.0;
77     double   x = 0.0;
78     double   y = 0.0;
79
80     for (index = 0; index < segment_count; ++index)
81     {
82         Segment* segment = segments + index;
83         double length = segment->length;
84         double angle = segment->angle;
85
86         x += length * cos (angle);
87         y += length * sin (angle);
88         points [index].x = x;
89         points [index].y = y;
90     }
91     angle = -(atan2 (y, x));
92     cosine = cos (angle);
93     sine = sin (angle);
94     length = sqrt ((x * x) + (y * y));
95     /* rotate and scale */
96     for (index = 0; index < segment_count; ++index)
97     {
98         double temp_x = points [index].x;
99         double temp_y = points [index].y;
100         points [index].x = ((temp_x * cosine) + (temp_y * (-sine))) / length;
101         points [index].y = ((temp_x * sine) + (temp_y * cosine)) / length;
102     }
103 }
104
105 static
106 void
107 copy_points (int       segment_count,
108              Position* source,
109              Position* target)
110 {
111     int      index = 0;
112
113     for (index = 0; index < segment_count; ++index)
114     {
115         target [index] = source [index];
116     }
117 }
118
119 static
120 void
121 realign (double    x1,
122          double    y1,
123          double    x2,
124          double    y2,
125          int       segment_count,
126          Position* points)
127 {
128     double angle = 0.0;
129     double cosine = 0.0;
130     double delta_x = 0.0;
131     double delta_y = 0.0;
132     int    index = 0;
133     double length = 0.0;
134     double sine = 0.0;
135
136     delta_x = x2 - x1;
137     delta_y = y2 - y1;
138     angle = atan2 (delta_y, delta_x);
139     cosine = cos (angle);
140     sine = sin (angle);
141     length = sqrt ((delta_x * delta_x) + (delta_y * delta_y));
142     /* rotate, scale, then shift */
143     for (index = 0; index < segment_count; ++index)
144     {
145         double temp_x = points [index].x;
146         double temp_y = points [index].y;
147         points [index].x
148             = (length * ((temp_x * cosine) + (temp_y * (-sine)))) + x1;
149         points [index].y
150             = (length * ((temp_x * sine) + (temp_y * cosine))) + y1;
151     }
152 }
153
154 static
155 void
156 self_similar_normalized (Display*  display,
157                          Pixmap    pixmap,
158                          GC        context,
159                          int       width,
160                          int       height,
161                          int       iterations,
162                          double    x1,
163                          double    y1,
164                          double    x2,
165                          double    y2,
166                          double    maximum_x,
167                          double    maximum_y,
168                          double    minimum_x,
169                          double    minimum_y,
170                          int       segment_count,
171                          Position* points)
172 {
173     if (iterations == 0)
174     {
175         double delta_x = maximum_x - minimum_x;
176         double delta_y = maximum_y - minimum_y;
177         color_index = (int)(((double)(line_count * color_count))
178                             / ((double)total_lines));
179         ++line_count;
180         XSetForeground (display, context, colors [color_index].pixel);
181         if (plot_maximum_x < x1) plot_maximum_x = x1;
182         if (plot_maximum_x < x2) plot_maximum_x = x2;
183         if (plot_maximum_y < y1) plot_maximum_y = y1;
184         if (plot_maximum_y < y2) plot_maximum_y = y2;
185         if (plot_minimum_x > x1) plot_minimum_x = x1;
186         if (plot_minimum_x > x2) plot_minimum_x = x2;
187         if (plot_minimum_y > y1) plot_minimum_y = y1;
188         if (plot_minimum_y > y2) plot_minimum_y = y2;
189         XDrawLine (display, pixmap, context,
190                    (int)(((x1 - minimum_x) / delta_x) * width),
191                    (int)(((maximum_y - y1) / delta_y) * height),
192                    (int)(((x2 - minimum_x) / delta_x) * width),
193                    (int)(((maximum_y - y2) / delta_y) * height));
194     }
195     else
196     {
197         int       index = 0;
198         double    next_x = 0.0;
199         double    next_y = 0.0;
200         Position* replacement = (Position*)NULL;
201         double    x = 0.0;
202         double    y = 0.0;
203
204         replacement = (Position*)(malloc (segment_count * sizeof (Segment)));
205         copy_points (segment_count, points, replacement);
206         assert (fabs ((replacement [segment_count - 1].x) - 1.0) < EPSILON);
207         assert (fabs (replacement [segment_count - 1].y) < EPSILON);
208         realign (x1, y1, x2, y2, segment_count, replacement);
209         assert (fabs (x2 - (replacement [segment_count - 1].x)) < EPSILON);
210         assert (fabs (y2 - (replacement [segment_count - 1].y)) < EPSILON);
211         x = x1;
212         y = y1;
213         for (index = 0; index < segment_count; ++index)
214         {
215             next_x = replacement [index].x;
216             next_y = replacement [index].y;
217             self_similar_normalized (display, pixmap, context, width, height,
218                                      iterations - 1, x, y, next_x, next_y,
219                                      maximum_x, maximum_y,
220                                      minimum_x, minimum_y,
221                                      segment_count, points);
222             x = next_x;
223             y = next_y;
224         }
225         free((void*)replacement);
226     }
227 }
228
229 static
230 void
231 self_similar (Display* display,
232               Pixmap   pixmap,
233               GC       context,
234               int      width,
235               int      height,
236               int      iterations,
237               double   x1,
238               double   y1,
239               double   x2,
240               double   y2,
241               double   maximum_x,
242               double   maximum_y,
243               double   minimum_x,
244               double   minimum_y,
245               int      segment_count,
246               Segment* segments)
247 {
248     Position* points = (Position*)NULL;
249
250     points = (Position*)(malloc (segment_count * sizeof (Position)));
251     normalized_plot (segment_count, segments, points);
252     assert (fabs ((points [segment_count - 1].x) - 1.0) < EPSILON);
253     assert (fabs (points [segment_count - 1].y) < EPSILON);
254     self_similar_normalized (display, pixmap, context,
255                              width, height, iterations,
256                              x1, y1, x2, y2,
257                              maximum_x, maximum_y,
258                              minimum_x, minimum_y,
259                              segment_count, points);
260     free((void*)points);
261 }
262
263 static
264 double
265 random_double (double base,
266                double limit,
267                double epsilon)
268 {
269     double       range = 0.0;
270     unsigned int steps = 0;
271
272     assert (base < limit);
273     assert (epsilon > 0.0);
274     range = limit - base;
275     steps = (unsigned int)(floor (range / epsilon));
276     return base + ((random () % steps) * epsilon);
277 }
278
279 static
280 void
281 select_2_pattern (Segment* segments)
282 {
283     if ((random () % 2) == 0)
284     {
285         if ((random () % 2) == 0)
286         {
287             segments [0].angle  = -M_PI_4;
288             segments [0].length = M_SQRT2;
289             segments [1].angle  = M_PI_4;
290             segments [1].length = M_SQRT2;
291         }
292         else
293         {
294             segments [0].angle  = M_PI_4;
295             segments [0].length = M_SQRT2;
296             segments [1].angle  = -M_PI_4;
297             segments [1].length = M_SQRT2;
298         }
299     }
300     else
301     {
302         segments [0].angle
303             = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0);
304         segments [0].length = random_double (0.25, 0.67, 0.001);
305         if ((random () % 2) == 0)
306         {
307             segments [1].angle = -(segments [0].angle);
308             segments [1].length = segments [0].length;
309         }
310         else
311         {
312             segments [1].angle = random_double ((-M_PI) / 3.0,
313                                                 (-M_PI) / 6.0,
314                                                 M_PI / 180.0);
315             segments [1].length = random_double (0.25, 0.67, 0.001);
316         }       
317     }
318 }
319
320 static
321 void
322 select_3_pattern (Segment* segments)
323 {
324     switch (random () % 5)
325     {
326      case 0:
327         if ((random () % 2) == 0)
328         {
329             segments [0].angle  = M_PI_4;
330             segments [0].length = M_SQRT2 / 4.0;
331             segments [1].angle  = -M_PI_4;
332             segments [1].length = M_SQRT2 / 2.0;
333             segments [2].angle  = M_PI_4;
334             segments [2].length = M_SQRT2 / 4.0;
335         }
336         else
337         {
338             segments [0].angle  = -M_PI_4;
339             segments [0].length = M_SQRT2 / 4.0;
340             segments [1].angle  = M_PI_4;
341             segments [1].length = M_SQRT2 / 2.0;
342             segments [2].angle  = -M_PI_4;
343             segments [2].length = M_SQRT2 / 4.0;
344         }
345         break;
346      case 1:
347         if ((random () % 2) == 0)
348         {
349             segments [0].angle  = M_PI / 6.0;
350             segments [0].length = 1.0;
351             segments [1].angle  = -M_PI_2;
352             segments [1].length = 1.0;
353             segments [2].angle  = M_PI / 6.0;
354             segments [2].length = 1.0;
355         }
356         else
357         {
358             segments [0].angle  = -M_PI / 6.0;
359             segments [0].length = 1.0;
360             segments [1].angle  = M_PI_2;
361             segments [1].length = 1.0;
362             segments [2].angle  = -M_PI / 6.0;
363             segments [2].length = 1.0;
364         }
365         break;
366      case 2:
367      case 3:
368      case 4:
369         segments [0].angle
370             = random_double (M_PI / 6.0, M_PI / 3.0, M_PI / 180.0);
371         segments [0].length = random_double (0.25, 0.67, 0.001);
372         segments [1].angle
373             = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0);
374         segments [1].length = random_double (0.25, 0.67, 0.001);
375         if ((random () % 3) == 0)
376         {
377             if ((random () % 2) == 0)
378             {
379                 segments [2].angle = segments [0].angle;
380             }
381             else
382             {
383                 segments [2].angle = -(segments [0].angle);
384             }
385             segments [2].length = segments [0].length;
386         }
387         else
388         {
389             segments [2].angle
390                 = random_double (-M_PI / 3.0, -M_PI / 6.0, M_PI / 180.0);
391             segments [2].length = random_double (0.25, 0.67, 0.001);
392         }
393         break;
394     }
395 }
396
397 static
398 void
399 select_4_pattern (Segment* segments)
400 {
401     switch (random () % 9)
402     {
403      case 0:
404         if ((random () % 2) == 0)
405         {
406             double length = random_double (0.25, 0.50, 0.001);
407
408             segments [0].angle  = 0.0;
409             segments [0].length = 0.5;
410             segments [1].angle  = M_PI_2;
411             segments [1].length = length;
412             segments [2].angle  = -M_PI_2;
413             segments [2].length = length;
414             segments [3].angle  = 0.0;
415             segments [3].length = 0.5;
416         }
417         else
418         {
419             double length = random_double (0.25, 0.50, 0.001);
420
421             segments [0].angle  = 0.0;
422             segments [0].length = 0.5;
423             segments [1].angle  = -M_PI_2;
424             segments [1].length = length;
425             segments [2].angle  = M_PI_2;
426             segments [2].length = length;
427             segments [3].angle  = 0.0;
428             segments [3].length = 0.5;
429         }
430         break;
431      case 1:
432         if ((random () % 2) == 0)
433         {
434             segments [0].angle  = 0.0;
435             segments [0].length = 0.5;
436             segments [1].angle  = M_PI_2;
437             segments [1].length = 0.45;
438             segments [2].angle  = -M_PI_2;
439             segments [2].length = 0.45;
440             segments [3].angle  = 0.0;
441             segments [3].length = 0.5;
442         }
443         else
444         {
445             segments [0].angle  = 0.0;
446             segments [0].length = 0.5;
447             segments [1].angle  = -M_PI_2;
448             segments [1].length = 0.45;
449             segments [2].angle  = M_PI_2;
450             segments [2].length = 0.45;
451             segments [3].angle  = 0.0;
452             segments [3].length = 0.5;
453         }
454         break;
455      case 2:
456         if ((random () % 2) == 0)
457         {
458             segments [0].angle  = 0.0;
459             segments [0].length = 1.0;
460             segments [1].angle  = (5.0 * M_PI) / 12.0;
461             segments [1].length = 1.2;
462             segments [2].angle  = (-5.0 * M_PI) / 12.0;
463             segments [2].length = 1.2;
464             segments [3].angle  = 0.0;
465             segments [3].length = 1.0;
466         }
467         else
468         {
469             segments [0].angle  = 0.0;
470             segments [0].length = 1.0;
471             segments [1].angle  = (-5.0 * M_PI) / 12.0;
472             segments [1].length = 1.2;
473             segments [2].angle  = (5.0 * M_PI) / 12.0;
474             segments [2].length = 1.2;
475             segments [3].angle  = 0.0;
476             segments [3].length = 1.0;
477         }
478         break;
479      case 3:
480         if ((random () % 2) == 0)
481         {
482             double angle
483                 = random_double (M_PI / 4.0,
484                                  M_PI_2,
485                                  M_PI / 180.0);
486
487             segments [0].angle  = 0.0;
488             segments [0].length = 1.0;
489             segments [1].angle  = angle;
490             segments [1].length = 1.2;
491             segments [2].angle  = (-angle);
492             segments [2].length = 1.2;
493             segments [3].angle  = 0.0;
494             segments [3].length = 1.0;
495         }
496         else
497         {
498             double angle
499                 = random_double (M_PI / 4.0,
500                                  M_PI_2,
501                                  M_PI / 180.0);
502
503             segments [0].angle  = 0.0;
504             segments [0].length = 1.0;
505             segments [1].angle  = (-angle);
506             segments [1].length = 1.2;
507             segments [2].angle  = angle;
508             segments [2].length = 1.2;
509             segments [3].angle  = 0.0;
510             segments [3].length = 1.0;
511         }
512         break;
513      case 4:
514         if ((random () % 2) == 0)
515         {
516             double angle
517                 = random_double (M_PI / 4.0,
518                                  M_PI_2,
519                                  M_PI / 180.0);
520
521             segments [0].angle  = 0.0;
522             segments [0].length = 1.0;
523             segments [1].angle  = angle;
524             segments [1].length = 1.2;
525             segments [2].angle  = (-angle);
526             segments [2].length = 1.2;
527             segments [3].angle  = 0.0;
528             segments [3].length = 1.0;
529         }
530         else
531         {
532             double angle
533                 = random_double (M_PI / 4.0,
534                                  M_PI_2,
535                                  M_PI / 180.0);
536
537             segments [0].angle  = 0.0;
538             segments [0].length = 1.0;
539             segments [1].angle  = (-angle);
540             segments [1].length = 1.2;
541             segments [2].angle  = angle;
542             segments [2].length = 1.2;
543             segments [3].angle  = 0.0;
544             segments [3].length = 1.0;
545         }
546         break;
547      case 5:
548         if ((random () % 2) == 0)
549         {
550             double angle
551                 = random_double (M_PI / 4.0,
552                                  M_PI_2,
553                                  M_PI / 180.0);
554             double length = random_double (0.25, 0.50, 0.001);
555
556             segments [0].angle  = 0.0;
557             segments [0].length = 1.0;
558             segments [1].angle  = angle;
559             segments [1].length = length;
560             segments [2].angle  = (-angle);
561             segments [2].length = length;
562             segments [3].angle  = 0.0;
563             segments [3].length = 1.0;
564         }
565         else
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         break;
583      case 6:
584      case 7:
585      case 8:
586         segments [0].angle
587             = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
588         segments [0].length = random_double (0.25, 0.50, 0.001);
589         segments [1].angle
590             = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
591         segments [1].length = random_double (0.25, 0.50, 0.001);
592         if ((random () % 3) == 0)
593         {
594             segments [2].angle
595                 = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
596             segments [2].length = random_double (0.25, 0.50, 0.001);
597             segments [3].angle
598                 = random_double (M_PI / 12.0, (11.0 * M_PI) / 12.0, 0.001);
599             segments [3].length = random_double (0.25, 0.50, 0.001);
600         }
601         else
602         {
603             if ((random () % 2) == 0)
604             {
605                 segments [2].angle = -(segments [1].angle);
606                 segments [2].length = segments [1].length;
607                 segments [3].angle = -(segments [0].angle);
608                 segments [3].length = segments [0].length;
609             }
610             else
611             {
612                 segments [2].angle = segments [1].angle;
613                 segments [2].length = segments [1].length;
614                 segments [3].angle = segments [0].angle;
615                 segments [3].length = segments [0].length;
616             }
617         }
618         break;
619     }
620 }
621
622 static void
623 select_pattern (int      segment_count,
624                 Segment* segments)
625 {
626     switch (segment_count)
627     {
628      case 2:
629         select_2_pattern (segments);
630         break;
631      case 3:
632         select_3_pattern (segments);
633         break;
634      case 4:
635         select_4_pattern (segments);
636         break;
637      default:
638         fprintf (stderr, "\nBad segment count, must be 2, 3, or 4.\n");
639         exit (1);
640     }
641 }
642
643 char *progclass = "Ccurve";
644
645 char *defaults [] =
646 {
647     ".delay:      1",
648     ".pause:      3",
649     ".limit: 200000",
650     0
651 };
652
653 XrmOptionDescRec options [] =
654 {
655     { "-delay", ".delay", XrmoptionSepArg, 0 },
656     { "-pause", ".pause", XrmoptionSepArg, 0 },
657     { "-limit", ".limit", XrmoptionSepArg, 0 },
658     { 0, 0, 0, 0 }
659 };
660
661 #define Y_START (0.5)
662
663 void
664 screenhack (Display* display,
665             Window   window)
666 {
667     unsigned long int    background      = 0;
668     unsigned long int    black           = 0;
669     GC                   context;
670     int                  delay           = 0;
671     int                  depth           = 0;
672     Pixmap               pixmap           = (Pixmap)NULL;
673     XWindowAttributes    hack_attributes;
674     int                  height          = 0;
675     int                  iterations      = 0;
676     int                  pause           = 0;
677     XGCValues            values;
678     unsigned long int    white           = 0;
679     int                  width           = 0;
680
681     delay = get_integer_resource ("delay", "Integer");
682     pause = get_integer_resource ("pause", "Integer");
683     maximum_lines = get_integer_resource ("limit", "Integer");
684     black = BlackPixel (display, DefaultScreen (display));
685     white = WhitePixel (display, DefaultScreen (display));
686     background = black;
687     XGetWindowAttributes (display, window, &hack_attributes);
688     width = hack_attributes.width;
689     height = hack_attributes.height;
690     depth = hack_attributes.depth;
691     color_map = hack_attributes.colormap;
692     pixmap = XCreatePixmap (display, window, width, height, depth);
693     values.foreground = white;
694     values.background = black;
695     context = XCreateGC (display, window, GCForeground | GCBackground,
696                          &values);
697     color_count = MAXIMUM_COLOR_COUNT;
698     make_color_loop (display, color_map,
699                      0,   1, 1,
700                      120, 1, 1,
701                      240, 1, 1,
702                      colors, &color_count, True, False);
703     if (color_count <= 0)
704     {
705         color_count = 1;
706         colors [0].red = colors [0].green = colors [0].blue = 0xFFFF;
707         XAllocColor (display, color_map, &colors [0]);
708     }
709
710     while (1)
711     {
712         int    index = 0;
713         double maximum_x =  1.20;
714         double maximum_y =  0.525;
715         double minimum_x = -0.20;
716         double minimum_y = -0.525;
717         static int lengths [] = { 4, 4, 4, 4, 4, 3, 3, 3, 2 };
718         int segment_count = 0;
719         Segment* segments = (Segment*)NULL;
720         double x1 = 0.0;
721         double y1 = 0.0;
722         double x2 = 1.0;
723         double y2 = 0.0;
724
725         segment_count
726             = lengths [random () % (sizeof (lengths) / sizeof (int))];
727         segments
728             = (Segment*)(malloc ((segment_count) * sizeof (Segment)));
729         select_pattern (segment_count, segments);
730         iterations = floor (log (maximum_lines)
731                                 / log (((double)(segment_count))));
732         if ((random () % 3) != 0)
733         {
734             double factor = 0.45;
735             x1 += random_double (-factor, factor, 0.001);
736             y1 += random_double (-factor, factor, 0.001);
737             x2 += random_double (-factor, factor, 0.001);
738             y2 += random_double (-factor, factor, 0.001);
739         }
740 /*      background = (random () % 2) ? black : white; */
741         for (index = 0; index < iterations; ++index)
742         {
743             double delta_x = 0.0;
744             double delta_y = 0.0;
745
746             XSetForeground (display, context, background);
747             XFillRectangle (display, pixmap, context, 0, 0, width, height);
748             line_count = 0;
749             total_lines = (int)(pow ((double)(segment_count),
750                                      (double)index));
751             plot_maximum_x = -1000.00;
752             plot_maximum_y = -1000.00;
753             plot_minimum_x =  1000.00;
754             plot_minimum_y =  1000.00;
755             self_similar (display, pixmap, context, width, height, index,
756                           x1, y1, x2, y2,
757                           maximum_x,
758                           maximum_y,
759                           minimum_x,
760                           minimum_y,
761                           segment_count, segments);
762             delta_x = plot_maximum_x - plot_minimum_x;
763             delta_y = plot_maximum_y - plot_minimum_y;
764             maximum_x = plot_maximum_x + (delta_x * 0.2);
765             maximum_y = plot_maximum_y + (delta_y * 0.2);
766             minimum_x = plot_minimum_x - (delta_x * 0.2);
767             minimum_y = plot_minimum_y - (delta_y * 0.2);
768             delta_x = maximum_x - minimum_x;
769             delta_y = maximum_y - minimum_y;
770             if ((delta_y / delta_x) > (((double)height) / ((double)width)))
771             {
772                 double new_delta_x
773                     = (delta_y * ((double)width)) / ((double)height);
774                 minimum_x -= (new_delta_x - delta_x) / 2.0;
775                 maximum_x += (new_delta_x - delta_x) / 2.0;
776             }
777             else
778             {
779                 double new_delta_y
780                     = (delta_x * ((double)height)) / ((double)width);
781                 minimum_y -= (new_delta_y - delta_y) / 2.0;
782                 maximum_y += (new_delta_y - delta_y) / 2.0;
783             }
784             XCopyArea (display, pixmap, window, context, 0, 0, width, height,
785                        0, 0);
786             if (delay) sleep (delay);
787             screenhack_handle_events (display);
788         }
789         free((void*)segments);
790         if (pause) sleep (pause);
791         erase_full_window (display, window);
792     }
793 }