1 /*
2  *  xcl.c
3  *  Control-Line in a box
4  *  Copyright (c) 2000 by Martin Berentsen <berentsen@sent5.uni-duisburg.de>
5  *
6  * change-log
7  * 0.4pl2 -> 0.5pl0 25/07/2000
8  * -singl command line option becomes to -count num
9  * 0.5pl0 -> 0.5pl1 02.02.2001
10  * bugs in -oldcolor and -randomstart option removed
11  *
12  * TODO as next:
13  * - a user defined speed for every used plane
14  *
15  */
16 
17 #if 0
18 static const char sccsid[] = "@(#)xcl.c    5.00 2000/11/01 xlockmore";
19 
20 #endif
21 
22 #define RAND(x)    (((my_random() % x )- x/2))  /* random number around 0 */
23 #define ROTATEDELAY 20000      /* delay for view-model rotating */
24 #define STARTUPDELAY 5000      /* delay for the first calibration loop */
25 #define REGULATE 25                    /* regulate delay every xx frames */
26 #define FRAMETIME 45000                /* time for one frame */
27 #define MINPLANES 1           /* define the min number of planes */
28 #define MAXCOUNT 30           /* define the max number of planes */
29 
30 #ifdef STANDALONE
31 #define MODE_xcl
32 #define DEFAULTS "*delay: 20000 \n" \
33 	"*count: 2 \n" \
34 
35 # define free_xcl 0
36 # define reshape_xcl 0
37 # define xcl_handle_event 0
38 #define UNIFORM_COLORS
39 #include "xlockmore.h"        /* in xscreensaver distribution */
40 #else /* STANDALONE */
41 #include "xlock.h"        /* in xlockmore distribution */
42 #endif
43 
44 #ifdef WIN32
45 #include <sys/time.h>
46 #endif
47 
48 #include "xcl.h"             /* model line data file */
49 
50 #ifdef MODE_xcl
51 
52 /* all parameters are global */
53 static float speed[MAXCOUNT];     /* Speed in km/h */
54 static float speed_in;       /* speed set by user */
55 static int frametime;       /* time for one frame in usecs */
56 static int line_length;     /* lines in mm*/
57 static float spectator;     /* spectator distance from zero*/
58 static Bool viewmodel;      /* shows one rotating model*/
59 static Bool oldcolor;       /* use the old yellow/red color combination */
60 static Bool debug;          /* debug modus */
61 static Bool automatic;      /* automatic scale for fit into window */
62 static Bool randomstart;    /* don't use the same start position */
63 static int random_pid;
64 
65 
66 #define DEF_SPEED_IN  "105.0"
67 #define DEF_FRAMETIME  "45000"
68 #define DEF_LINE_LENGTH  "15910"
69 #define DEF_SPECTATOR  "22000"
70 #define DEF_VIEWMODEL  "False"
71 #define DEF_OLDCOLOR  "False"
72 #define DEF_XCLDEBUG  "False"
73 #define DEF_AUTOMATIC  "True"
74 #define DEF_RANDOMSTART  "False"
75 
76 
77 static XrmOptionDescRec opts[] =
78 {
79   {(char *) "-speed", (char *) ".xcl.speed", XrmoptionSepArg, (caddr_t) NULL},
80   {(char *) "-frametime", (char *) ".xcl.frametime", XrmoptionSepArg, (caddr_t) NULL},
81   {(char *) "-line_length", (char *) ".xcl.line_length", XrmoptionSepArg, (caddr_t) NULL},
82   {(char *) "-spectator", (char *) ".xcl.spectator", XrmoptionSepArg, (caddr_t) NULL},
83   {(char *) "-viewmodel", (char *) ".xcl.viewmodel", XrmoptionNoArg, (caddr_t) "on"},
84   {(char *) "+viewmodel", (char *) ".xcl.viewmodel", XrmoptionNoArg, (caddr_t) "off"},
85   {(char *) "-oldcolor", (char *) ".xcl.oldcolor", XrmoptionNoArg, (caddr_t) "on"},
86   {(char *) "+oldcolor", (char *) ".xcl.oldcolor", XrmoptionNoArg, (caddr_t) "off"},
87   {(char *) "-xcldebug", (char *) ".xcl.xcldebug", XrmoptionNoArg, (caddr_t) "on"},
88   {(char *) "+xcldebug", (char *) ".xcl.xcldebug", XrmoptionNoArg, (caddr_t) "off"},
89   {(char *) "-automatic", (char *) ".xcl.automatic", XrmoptionNoArg, (caddr_t) "on"},
90   {(char *) "+automatic", (char *) ".xcl.automatic", XrmoptionNoArg, (caddr_t) "off"},
91   {(char *) "-randomstart", (char *) ".xcl.randomstart", XrmoptionNoArg, (caddr_t) "on"},
92   {(char *) "+randomstart", (char *) ".xcl.randomstart", XrmoptionNoArg, (caddr_t) "off"}
93 };
94 static argtype vars[] =
95 {
96   {(void *) & speed_in, (char *) "speed", (char *) "Speed", (char *) DEF_SPEED_IN, t_Float},
97   {(void *) & frametime, (char *) "frametime", (char *) "frametime", (char *) DEF_FRAMETIME, t_Int},
98   {(void *) & line_length, (char *) "line_length", (char *) "Line_length", (char *) DEF_LINE_LENGTH, t_Int},
99   {(void *) & spectator, (char *) "spectator", (char *) "Spectator", (char *) DEF_SPECTATOR, t_Float},
100   {(void *) & viewmodel, (char *) "viewmodel", (char *) "Viewmodel", (char *) DEF_VIEWMODEL, t_Bool},
101   {(void *) & oldcolor, (char *) "oldcolor", (char *) "Oldcolor", (char *) DEF_OLDCOLOR, t_Bool},
102   {(void *) & debug, (char *) "xcldebug", (char *) "Xcldebug", (char *) DEF_XCLDEBUG, t_Bool},
103   {(void *) & automatic, (char *) "automatic", (char *) "Automatic", (char *) DEF_AUTOMATIC, t_Bool},
104   {(void *) & randomstart, (char *) "randomstart", (char *) "Randomstart", (char *) DEF_RANDOMSTART, t_Bool}
105 };
106 static OptionStruct desc[] =
107 {
108   {(char *) "-speed num", (char *) "speed for the planes in km/h "},
109   {(char *) "-frametime num", (char *) "time for one frame on the screen in usecs "},
110   {(char *) "-line_length num", (char *) "distance between the pilot and the plane in mm "},
111   {(char *) "-spectator num", (char *) "distance  between  spectator  and  pilot in mm"},
112   {(char *) "-/+viewmodel", (char *) "turn on/off an anim view of one model"},
113   {(char *) "-/+oldcolor", (char *) "turn on/off the old yellow/red combination"},
114   {(char *) "-/+xcldebug", (char *) "turn on/off some timing information"},
115   {(char *) "-/+automatic", (char *) "turn on/off auto scale for fit into the window"},
116   {(char *) "-/+randomstart", (char *) "turn on/off a random start point for models at startup"}
117 };
118 
119 ENTRYPOINT ModeSpecOpt xcl_opts =
120 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
121 
122 #ifdef USE_MODULES    /* for xlockmore */
123 ModStruct   xcl_description =
124 {"xcl", "init_xcl", "draw_xcl", "release_xcl",
125  "draw_xcl", "init_xcl", (char *) NULL, &xcl_opts ,
126  20000, -3, 1, 1, 64, 1.0, "",
127  "Shows a control line combat model race", 0, NULL};
128 #endif
129 
130 typedef struct
131 {
132   int planes;    /* number of planes viewed*/
133   int lines;     /* number of lines counted in model */
134   double az[MAXCOUNT];  /* azimuth of plane */
135   double el[MAXCOUNT];  /* elevation of plane */
136   int width;
137   int height;
138   int mid_x;
139   int mid_y;
140   float Alpha;   /* rotate.1 */
141   float Beta;    /* rotate.2 */
142   float Gamma;   /* rotate.3 */
143   float Vx;      /* width from zero in X */
144   float Vy;      /* width from zero in Y */
145   float Vz;      /* width from zero in Z */
146   float G;       /* ZOOM  */
147   float Ca,Cb,Cc,Sa,Sb,Sc; /* only for faster calculation */
148   float Bx,By ;
149   struct timeval tv1;
150   double time1, time2, time3;        /* calibrate time */
151   int drawtime;
152   double alpha[MAXCOUNT];            /* direction */
153   double omega_const[MAXCOUNT];      /*  constant omega speed */
154   double delta_az[MAXCOUNT];
155   double delta_el[MAXCOUNT];
156   int turn[MAXCOUNT];
157   int turn_direction[MAXCOUNT];
158   int random_pid;
159   long planecolor[MAXCOUNT],bg;      /* used colours */
160   GC gc[MAXCOUNT];
161   GC erase_gc;
162   XSegment *xseg[MAXCOUNT];
163   XSegment *xseg_old[MAXCOUNT];
164   int xcldelay;
165   int no_preset;
166 } xclstruct;
167 
168 static xclstruct *xcls = (xclstruct *) NULL;
169 
my_random(void)170 static int my_random(void)  /* not really good, but it works */
171 {
172   static int number;
173   number -= random_pid;
174   return ( 0x0fff & (number));
175 }
176 
countlines(void)177 static int countlines(void)
178 {
179   int array;
180   int count = 0;
181   for(array = 0;array<LINEARRAYS;array++) {
182     count += model_data2[array][0] - 1;
183   }
184   return(count);
185 }
186 
um2(int X,int Y,int Z,xclstruct * dp)187 static void um2(int X, int Y, int Z, xclstruct *dp)
188 {
189   float X2,X3,X4,Y1,Y3,Y4,Z1,Z2,Z4;
190 
191   Y1 = dp->Ca * Y - dp->Sa * Z;
192   Z1 = dp->Sa * Y + dp->Ca * Z;
193   X2 = dp->Cb * X - dp->Sb * Z1;
194   Z2 = dp->Sb * X + dp->Cb * Z1;
195   X3 = dp->Cc * X2 - dp->Sc * Y1;
196   Y3 = dp->Sc * X2 + dp->Cc * Y1;
197   X4 = X3 + dp->Vx;
198   Y4 = Y3 + dp->Vy;
199   Z4 = Z2 + dp->Vz;
200 
201   dp->Bx = dp->mid_x + (-X4 / Y4 * dp->G);
202   dp->By = dp->mid_y - (-Z4 / Y4 * dp->G);
203 }
204 
view_3d(XSegment * xseg,xclstruct * dp)205 static void view_3d(XSegment *xseg, xclstruct *dp)
206 {
207   int count = 0;
208   int I,J;
209   float BX [ENDPOINTS];
210   float BY [ENDPOINTS];
211 
212   dp->Ca = cos(dp->Alpha);
213   dp->Cb = cos(dp->Beta);
214   dp->Cc = cos(dp->Gamma);
215   dp->Sa = sin(dp->Alpha);
216   dp->Sb = sin(dp->Beta);
217   dp->Sc = sin(dp->Gamma);
218 
219   for(I = 0; I < ENDPOINTS; I++) {
220     um2( model_data1 [ I * 3 + 0], model_data1 [ I * 3 + 1],
221          model_data1 [ I * 3 + 2],dp);
222     BX [I] = dp->Bx;
223     BY [I] = dp->By;
224   }
225   for (I = 0; I < LINEARRAYS; I++) {
226     for (J = 1; J < model_data2[I][0]; J++) {
227       xseg[count].x1 = (short) BX[(model_data2[I][J])-1];
228       xseg[count].y1 = (short) BY[(model_data2[I][J])-1]+(dp->mid_y/2);
229       xseg[count].x2 = (short) BX[(model_data2[I][J+1])-1];
230       xseg[count].y2 = (short) BY[(model_data2[I][J+1])-1]+(dp->mid_y/2);
231       count++;
232     }
233   }
234 }
235 
get_color(ModeInfo * mi,char * color,XColor * final_color)236 static long get_color(ModeInfo *mi, char *color, XColor *final_color)
237 {
238   Display *display = MI_DISPLAY(mi);
239   XColor cdef;
240   Colormap cmap;
241   cmap = DefaultColormap(display, MI_SCREEN(mi));
242 
243   if (!XParseColor(display, cmap, color, &cdef) ||
244       !XAllocColor(display, cmap, &cdef))
245     {
246       (void) fprintf(stderr, "Color \"%s\" wasn't found\n", color);
247     }
248 
249   if (final_color != NULL) *final_color = cdef;  /* copy the final color. */
250 
251   return(cdef.pixel);
252 }
253 
get_GC(Display * dpy,Window win,GC * gc,long color)254 static Bool get_GC(Display *dpy,Window win,GC *gc,long color)
255 {
256   unsigned long valuemask = 0;  /*ignore XGCvalues and use defaults */
257   XGCValues values;
258   unsigned int line_width = 1;
259   int line_style = LineSolid;   /* LineOnOffDash;*/
260   int cap_style = CapRound;
261   int join_style = JoinRound;
262 
263   if ((*gc = XCreateGC(dpy, win, valuemask , &values)) == None)
264     return False;
265   XSetForeground(dpy, *gc, color);
266 
267   XSetLineAttributes(dpy, *gc, line_width, line_style,
268              cap_style, join_style);
269   return True;
270 }
271 
272 static void
free_xcl_screen(Display * display,xclstruct * dp)273 free_xcl_screen(Display *display, xclstruct  *dp)
274 {
275     int plane;
276 
277     if (dp == NULL) {
278       return;
279     }
280     for (plane = 0; plane < dp->planes; plane++) {
281       if (dp->xseg[plane] != NULL) {
282         free(dp->xseg[plane]);
283         dp->xseg[plane] = (XSegment *) NULL;
284       }
285       if (dp->xseg_old[plane] != NULL) {
286         free(dp->xseg_old[plane]);
287         dp->xseg_old[plane] = (XSegment *) NULL;
288       }
289       if (dp->gc[plane] != None) {
290         XFreeGC(display, dp->gc[plane]);
291         dp->gc[plane] = None;
292       }
293     }
294     if (dp->erase_gc != None) {
295       XFreeGC(display, dp->erase_gc);
296       dp->erase_gc = None;
297     }
298     dp = NULL;
299 }
300 
301 ENTRYPOINT void
init_xcl(ModeInfo * mi)302 init_xcl(ModeInfo * mi)
303 {
304   Display *display = MI_DISPLAY(mi);
305   int i;            /* scratch */
306   xclstruct *dp;
307 
308   MI_INIT(mi, xcls);
309   dp = &xcls[MI_SCREEN(mi)];
310 
311   /* Update every time */
312   dp->width = MI_WIDTH(mi);
313   dp->height = MI_HEIGHT(mi);
314   dp->mid_x = (dp->width / 2);
315   dp->mid_y = (dp->height / 2);
316 
317   if(dp->no_preset != 1) {
318     dp->no_preset = 1;
319     /* some presettings */
320     dp->planes = MI_COUNT(mi);
321     if (dp->planes < -MINPLANES) {
322       dp->planes = NRAND(-MI_COUNT(mi) -MINPLANES + 1) + MINPLANES;
323     } else if (dp->planes < MINPLANES) {
324       dp->planes = MINPLANES;
325     }
326     if(dp->planes > MAXCOUNT)
327       dp->planes = MAXCOUNT;
328     dp->Alpha = 0.0;          /* rotate.1 */
329     dp->Beta  = 0.0;          /* rotate.2 */
330     dp->Gamma = 0.0;          /* rotate.3 */
331     dp->Vx = 1;               /* width from zero in X */
332     dp->Vy = 800;             /* width from zero in Y */
333     dp->Vz = -300;            /* width from zero in Z */
334     dp->G =  500.0;           /* ZOOM  */
335     dp->time3 = 1.0;
336     dp->drawtime = 25000;
337     dp->xcldelay = STARTUPDELAY;
338     for(i=0;i< dp->planes; i++) {
339       dp->az[i] = 2 * M_PI * i / (float)((dp->planes));
340       dp->el[i] = 0.0;
341       dp->alpha[i] = 0.75;      /* direction */
342       dp->turn[i] = 0;
343       dp->turn_direction[i] = 1;
344 
345       speed[i] = speed_in;  /* see TODO */
346     }
347 
348     random_pid = NRAND(31); /* goes here first for randomstart */
349 
350     if(randomstart) {
351       for(i=0;i< dp->planes; i++) {
352         switch(i) {
353         case 0:
354           dp->az[0] += (random_pid % 31) / 5.0;
355           break;
356         default:
357           dp->az[i] = dp->az[0] + 2 * M_PI * i / (float)((dp->planes));
358         }
359       }
360     }
361 
362     dp->bg = MI_BLACK_PIXEL(mi);
363 
364     if(MI_NPIXELS(mi) <= 2)
365       for(i=0;i< dp->planes; i++) {
366         dp->planecolor[i] = MI_WHITE_PIXEL(mi);
367       }
368     else {
369       if(!oldcolor) {
370         for(i=0;i< dp->planes; i++) {
371           dp->planecolor[i] = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
372         }
373       }
374       else { /* with count >2 no so good */
375         for(i=0;i< dp->planes; i++) {
376           switch(i) {
377           case 0:
378             dp->planecolor[0] = get_color(mi, (char *) "yellow",
379 		(XColor *) NULL);
380             break;
381           case 1:
382             dp->planecolor[1] = get_color(mi, (char *) "red",
383 		(XColor *) NULL);
384             break;
385           default:
386             dp->planecolor[i] = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi)));
387           }
388         }
389       }
390     }
391 
392     if(dp->erase_gc == None)
393       if (!get_GC(display, MI_WINDOW(mi), &(dp->erase_gc),dp->bg)) {
394         free_xcl_screen(display, dp);
395         return;
396       }
397 
398     dp->lines = countlines();
399 
400     for(i=0;i< dp->planes; i++) {
401       if(dp->gc[i] == None)
402         if (!get_GC(display, MI_WINDOW(mi), &(dp->gc[i]),
403                     dp->planecolor[i])) {
404           free_xcl_screen(display, dp);
405           return;
406         }
407       dp->omega_const[i] = speed[i]/3.6 /line_length*1000.0;
408 
409       if(dp->xseg[i] == NULL)
410         if ((dp-> xseg[i] = (XSegment *) malloc(sizeof(XSegment) *
411                                                 dp->lines)) == NULL) {
412           free_xcl_screen(display, dp);
413           return;
414         }
415       if(dp->xseg_old[i] == NULL)
416         if ((dp->xseg_old[i] = (XSegment *) malloc(sizeof(XSegment) *
417                                                    dp->lines)) == NULL) {
418           free_xcl_screen(display, dp);
419           return;
420         }
421     }
422 
423     if(MI_IS_VERBOSE(mi)) {
424       (void) printf("X control line combat in a box\n");
425 #if 0
426       (void) printf("Version: %s\n",sccsid);
427 #endif
428       (void) printf("Line length: %gm\n",line_length/1000.0);
429       (void) printf("Speed %g km/h  \n",speed[0]);
430       (void) printf("Lines per plane: %d\n",dp->lines);
431       (void) printf("Spectator at %gm\n",spectator/1000.0);
432       (void) printf("Try %g frames per Second (frametime: %dus)\n",
433                     1000000.0/frametime,frametime);
434       (void) printf("Calibration at %d frames\n",REGULATE);
435     }
436   }
437 
438   /* clear the screen */
439 
440   MI_CLEARWINDOW(mi);
441 
442   (void) gettimeofday(&(dp->tv1),0);
443   dp->time1 = (double)dp->tv1.tv_sec +
444     (double)dp->tv1.tv_usec/(double)1000000;
445 
446   dp->xcldelay = frametime;
447 }
448 
449 ENTRYPOINT void
draw_xcl(ModeInfo * mi)450 draw_xcl(ModeInfo * mi)
451 {
452   static int count = 0;
453   int i;
454   xclstruct *dp;
455 
456   if (xcls == NULL)
457     return;
458   dp = &xcls[MI_SCREEN(mi)];
459   if (dp->erase_gc == None)
460     return;
461 
462   MI_IS_DRAWN(mi) = True;
463 
464   if(viewmodel == True)
465     {
466       dp->Vx = 1;                     /* movement in X (width,negative)*/
467       if(dp->width < 900)
468         dp->Vy = 800*800/dp->width;   /*  Y (deep)*/
469       else
470         dp->Vy = 800*1200/dp->width;  /*  Y (deep)*/
471       dp->Vz = -300;                  /*  Z (height) */
472       dp->G = 350.0;          /* make it smaller when display is smaller */
473       dp->Alpha += 0.03;
474       dp->Beta += 0.006;
475       dp->Gamma += 0.009;
476 
477       if (count != 0) {
478         XDrawSegments(MI_DISPLAY(mi),MI_WINDOW(mi),dp->erase_gc,
479                       dp->xseg_old[0],dp->lines);
480         XDrawSegments(MI_DISPLAY(mi),MI_WINDOW(mi),dp->gc[0],
481                       dp->xseg[0],dp->lines);
482         (void) usleep(ROTATEDELAY * 2);
483       }
484       (void) memcpy(dp->xseg_old[0],dp->xseg[0],sizeof(XSegment)*dp->lines);
485       view_3d(dp->xseg[0],dp);
486       count ++;
487     }
488   else {
489     if(automatic)
490       dp->G = dp->width / 2.1 ;
491 
492     for(i=0;i<dp->planes;i++) {
493       (void) memcpy(dp->xseg_old[i],dp->xseg[i],sizeof(XSegment)*dp->lines);
494 
495       dp->Alpha = - dp->alpha[i];
496       dp->Beta = - dp->el[i];
497       dp->Gamma = dp->az[i];
498 
499       dp->Vx = -(int)(cos(dp->az[i]) * cos(dp->el[i]) * line_length);
500       dp->Vy = spectator -
501         (int)(sin(dp->az[i]) * cos(dp->el[i]) * line_length);
502       dp->Vz = (int)(sin(dp->el[i]) * line_length);
503 
504       view_3d(dp->xseg[i],dp);
505       XDrawSegments(MI_DISPLAY(mi),MI_WINDOW(mi),dp->erase_gc,
506                     dp->xseg_old[i],dp->lines);
507       XDrawSegments(MI_DISPLAY(mi),MI_WINDOW(mi),dp->gc[i],
508                     dp->xseg[i],dp->lines);
509     }
510 
511     XFlush(MI_DISPLAY(mi));
512 
513     /* now move all planes */
514     for(i=0;i<dp->planes;i++) {
515       dp->delta_az[i] = cos(dp->alpha[i]) * dp->omega_const[i] *
516         frametime/1000000;
517       dp->delta_el[i] = sin(dp->alpha[i]) * dp->omega_const[i] *
518         frametime/1000000;
519 
520       dp->az[i] -= dp->delta_az[i];
521       dp->el[i] -= dp->delta_el[i];
522 
523       if (dp->el[i] >= 0.0)
524         switch (dp->turn[i]) {
525         case 0:
526           dp->turn_direction[i] *= -1;
527           dp->alpha[i] += 0.62831853 * dp->turn_direction[i];
528           dp->turn[i] ++;
529           break;
530         case 1:
531         case 2:
532         case 3:
533         case 4:
534         case 5:
535           dp->alpha[i] += 0.62831853 * dp->turn_direction[i];
536           dp->turn[i] ++;
537           break;
538         default:
539           dp->turn[i] ++;
540           break;
541         }
542       else
543         dp->turn[i] = 0;
544       if (dp->el[i] <= -(M_PI / 2.0))
545         {
546           dp->alpha[i] += M_PI;
547           dp->az[i] += M_PI;
548           /* el[i] = el[i] + (M_PI / 2.0) ; */
549         }
550       else
551         if(dp->turn[i] == 0)
552           dp->alpha[i] += (double)(RAND(600))  / 6283.0 * 2.0 * M_PI;
553     } /* for (i) */
554 
555     count++;
556 
557     (void) usleep(dp->xcldelay);
558     if((count % REGULATE) == 0) {
559       (void) gettimeofday(&(dp->tv1),0);
560       dp->time2 = (double)dp->tv1.tv_sec + (double)dp->tv1.tv_usec/
561         (double)1000000;
562       dp->time3 = dp->time2 - dp->time1;
563       dp->time1 = dp->time2;
564       dp->drawtime = (int) (dp->time3 * (1000000/REGULATE))
565         - dp->xcldelay;
566       if((dp->xcldelay = frametime - dp->drawtime) <= 0) {
567         dp->xcldelay = 10;  /* 1 is possible xor xscreensaver mode */
568       }
569       if(debug == True)
570         (void) printf("t_draw: %d, t_delay: %d\n",dp->drawtime,
571                       dp->xcldelay);
572     }
573   }
574 }
575 
576 ENTRYPOINT void
release_xcl(ModeInfo * mi)577 release_xcl(ModeInfo * mi)
578 {
579   if (xcls != NULL) {
580     int screen;
581     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
582       free_xcl_screen(MI_DISPLAY(mi), &xcls[screen]);
583     free(xcls);
584     xcls = (xclstruct *) NULL;
585   }
586 }
587 
588 XSCREENSAVER_MODULE ("Xcl", xcl)
589 
590 #endif /* MODE_xcl */
591