ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.21.tar.gz
[xscreensaver] / hacks / glx / glplanet.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* glplanet --- 3D rotating planet, e.g., Earth.
3  *
4  * Permission to use, copy, modify, and distribute this software and its
5  * documentation for any purpose and without fee is hereby granted,
6  * provided that the above copyright notice appear in all copies and that
7  * both that copyright notice and this permission notice appear in
8  * supporting documentation.
9  *
10  * This file is provided AS IS with no warranties of any kind.  The author
11  * shall have no liability with respect to the infringement of copyrights,
12  * trade secrets or any patents by this file or any part thereof.  In no
13  * event will the author be liable for any lost revenue or profits or
14  * other special, indirect and consequential damages.
15  *
16  * Revision History:
17  *
18  * 16-Jan-02: jwz@jwz.org   gdk_pixbuf support.
19  * 21-Mar-01: jwz@jwz.org   Broke sphere routine out into its own file.
20  *
21  * 9-Oct-98:  dek@cgl.ucsf.edu  Added stars.
22  *
23  * 8-Oct-98:  jwz@jwz.org   Made the 512x512x1 xearth image be built in.
24  *                          Made it possible to load XPM or XBM files.
25  *                          Made the planet bounce and roll around.
26  *
27  * 8-Oct-98: Released initial version of "glplanet"
28  * (David Konerding, dek@cgl.ucsf.edu)
29  *
30  * BUGS:
31  * -bounce is broken
32  * 
33  *   For even more spectacular results, grab the images from the "SSystem"
34  *   package (http://www.msu.edu/user/kamelkev/) and use its JPEGs!
35  */
36
37
38 #ifdef STANDALONE
39 # define PROGCLASS                                              "Planet"
40 # define HACK_INIT                                              init_planet
41 # define HACK_DRAW                                              draw_planet
42 # define HACK_RESHAPE                                   reshape_planet
43 # define HACK_HANDLE_EVENT                              planet_handle_event
44 # define EVENT_MASK                                             PointerMotionMask
45 # define planet_opts                                    xlockmore_opts
46 #define DEFAULTS        "*delay:                        20000   \n"     \
47                                         "*showFPS:                      False   \n" \
48                                         "*wireframe:            False   \n"     \
49                                         "*imageForeground:      Green   \n" \
50                                         "*imageBackground:      Blue    \n"
51
52 # include "xlockmore.h"                         /* from the xscreensaver distribution */
53 #else  /* !STANDALONE */
54 # include "xlock.h"                                     /* from the xlockmore distribution */
55 #endif /* !STANDALONE */
56
57 #ifdef USE_GL /* whole file */
58
59 #include "sphere.h"
60
61 #ifdef HAVE_XMU
62 # ifndef VMS
63 #  include <X11/Xmu/Drawing.h>
64 #else  /* VMS */
65 #  include <Xmu/Drawing.h>
66 # endif /* VMS */
67 #endif
68
69
70 #include <GL/glu.h>
71
72 #define DEF_ROTATE  "True"
73 #define DEF_ROLL    "True"
74 #define DEF_WANDER  "True"
75 #define DEF_TEXTURE "True"
76 #define DEF_STARS   "True"
77 #define DEF_LIGHT   "True"
78 #define DEF_RESOLUTION "128"
79 #define DEF_IMAGE   "BUILTIN"
80
81 #undef countof
82 #define countof(x) (sizeof((x))/sizeof((*x)))
83
84 static int do_rotate;
85 static int do_roll;
86 static int do_wander;
87 static int do_texture;
88 static int do_stars;
89 static int do_light;
90 static char *which_image;
91 static int resolution;
92
93 static XrmOptionDescRec opts[] = {
94   {"-rotate",  ".glplanet.rotate",  XrmoptionNoArg, "true" },
95   {"+rotate",  ".glplanet.rotate",  XrmoptionNoArg, "false" },
96   {"-roll",    ".glplanet.roll",    XrmoptionNoArg, "true" },
97   {"+roll",    ".glplanet.roll",    XrmoptionNoArg, "false" },
98   {"-wander",  ".glplanet.wander",  XrmoptionNoArg, "true" },
99   {"+wander",  ".glplanet.wander",  XrmoptionNoArg, "false" },
100   {"-texture", ".glplanet.texture", XrmoptionNoArg, "true" },
101   {"+texture", ".glplanet.texture", XrmoptionNoArg, "false" },
102   {"-stars",   ".glplanet.stars",   XrmoptionNoArg, "true" },
103   {"+stars",   ".glplanet.stars",   XrmoptionNoArg, "false" },
104   {"-light",   ".glplanet.light",   XrmoptionNoArg, "true" },
105   {"+light",   ".glplanet.light",   XrmoptionNoArg, "false" },
106   {"-image",   ".glplanet.image",  XrmoptionSepArg, 0 },
107   {"-resolution", ".glplanet.resolution", XrmoptionSepArg, 0 },
108 };
109
110 static argtype vars[] = {
111   {&do_rotate,   "rotate",  "Rotate",  DEF_ROTATE,  t_Bool},
112   {&do_roll,     "roll",    "Roll",    DEF_ROLL,    t_Bool},
113   {&do_wander,   "wander",  "Wander",  DEF_WANDER,  t_Bool},
114   {&do_texture,  "texture", "Texture", DEF_TEXTURE, t_Bool},
115   {&do_stars,    "stars",   "Stars",   DEF_STARS,   t_Bool},
116   {&do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
117   {&which_image, "image",   "Image",   DEF_IMAGE,   t_String},
118   {&resolution,  "resolution","Resolution", DEF_RESOLUTION, t_Int},
119 };
120
121 ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
122
123 #ifdef USE_MODULES
124 ModStruct   planet_description =
125 {"planet", "init_planet", "draw_planet", "release_planet",
126  "draw_planet", "init_planet", NULL, &planet_opts,
127  1000, 1, 2, 1, 4, 1.0, "",
128  "Animates texture mapped sphere (planet)", 0, NULL};
129 #endif
130
131 # ifdef __GNUC__
132   __extension__  /* don't warn about "string length is greater than the length
133                     ISO C89 compilers are required to support" when including
134                     the following XPM file... */
135 # endif
136 #include "../images/earth.xpm"
137
138 #include "xpm-ximage.h"
139 #include "rotator.h"
140 #include "gltrackball.h"
141
142
143 /*-
144  * slices and stacks are used in the sphere parameterization routine.
145  * more slices and stacks will increase the quality of the sphere,
146  * at the expense of rendering speed
147  */
148
149 #define NUM_STARS 1000
150
151 /* radius of the sphere- fairly arbitrary */
152 #define RADIUS 4
153
154 /* distance away from the sphere model */
155 #define DIST 40
156
157
158
159 /* structure for holding the planet data */
160 typedef struct {
161   GLuint platelist;
162   GLuint latlonglist;
163   GLuint starlist;
164   int screen_width, screen_height;
165   GLXContext *glx_context;
166   Window window;
167   XColor fg, bg;
168   GLfloat sunpos[4];
169   double z;
170   rotator *rot;
171   trackball_state *trackball;
172   Bool button_down_p;
173 } planetstruct;
174
175
176 static planetstruct *planets = NULL;
177
178
179 /* Set up and enable texturing on our object */
180 static void
181 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
182 {
183   XImage *image = xpm_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
184                                   MI_COLORMAP (mi), xpm_data);
185   char buf[1024];
186   clear_gl_error();
187   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
188                image->width, image->height, 0,
189                GL_RGBA,
190                /* GL_UNSIGNED_BYTE, */
191                GL_UNSIGNED_INT_8_8_8_8_REV,
192                image->data);
193   sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
194   check_gl_error(buf);
195
196   /* setup parameters for texturing */
197   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
198   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
199   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
200   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
201   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
202   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
203 }
204
205
206 static void
207 setup_file_texture (ModeInfo *mi, char *filename)
208 {
209   Display *dpy = mi->dpy;
210   Visual *visual = mi->xgwa.visual;
211   char buf[1024];
212
213   Colormap cmap = mi->xgwa.colormap;
214   XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
215
216   clear_gl_error();
217   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
218                image->width, image->height, 0,
219                GL_RGBA,
220                /* GL_UNSIGNED_BYTE, */
221                GL_UNSIGNED_INT_8_8_8_8_REV,
222                image->data);
223   sprintf (buf, "texture: %.100s (%dx%d)",
224            filename, image->width, image->height);
225   check_gl_error(buf);
226
227   /* setup parameters for texturing */
228   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
229   glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
230
231   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
232   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
233   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
234   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
235   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
236 }
237
238
239 static void
240 setup_texture(ModeInfo * mi)
241 {
242 /*  planetstruct *gp = &planets[MI_SCREEN(mi)];*/
243
244   glEnable(GL_TEXTURE_2D);
245
246   if (!which_image ||
247           !*which_image ||
248           !strcmp(which_image, "BUILTIN"))
249         setup_xpm_texture (mi, earth_xpm);
250   else
251         setup_file_texture (mi, which_image);
252
253   check_gl_error("texture initialization");
254
255   /* Need to flip the texture top for bottom for some reason. */
256   glMatrixMode (GL_TEXTURE);
257   glScalef (1, -1, 1);
258   glMatrixMode (GL_MODELVIEW);
259 }
260
261
262 void
263 init_stars (ModeInfo *mi)
264 {
265   int i, j;
266   GLfloat max_size = 3;
267   GLfloat inc = 0.5;
268   int steps = max_size / inc;
269   int width  = MI_WIDTH(mi);
270   int height = MI_HEIGHT(mi);
271
272   planetstruct *gp = &planets[MI_SCREEN(mi)];
273   Bool wire = MI_IS_WIREFRAME(mi);
274   
275   if (!wire)
276     glEnable (GL_POINT_SMOOTH);
277
278   gp->starlist = glGenLists(1);
279   glNewList(gp->starlist, GL_COMPILE);
280
281   glScalef (1.0/width, 1.0/height, 1);
282
283   for (j = 1; j <= steps; j++)
284     {
285       glPointSize(inc * j);
286       glBegin(GL_POINTS);
287       for (i = 0 ; i < NUM_STARS / steps; i++)
288         {
289           glColor3f (0.6 + frand(0.3),
290                      0.6 + frand(0.3),
291                      0.6 + frand(0.3));
292           glVertex2f ((GLfloat) (random() % width),
293                       (GLfloat) (random() % height));
294         }
295       glEnd();
296     }
297   glEndList();
298
299   check_gl_error("stars initialization");
300 }
301
302
303 void
304 draw_stars (ModeInfo * mi)
305 {
306   int width  = MI_WIDTH(mi);
307   int height = MI_HEIGHT(mi);
308
309   planetstruct *gp = &planets[MI_SCREEN(mi)];
310   
311   /* Sadly, this causes a stall of the graphics pipeline (as would the
312      equivalent calls to glGet*.)  But there's no way around this, short
313      of having each caller set up the specific display matrix we need
314      here, which would kind of defeat the purpose of centralizing this
315      code in one file.
316    */
317   glPushAttrib(GL_TRANSFORM_BIT |  /* for matrix contents */
318                GL_ENABLE_BIT |     /* for various glDisable calls */
319                GL_CURRENT_BIT |    /* for glColor3f() */
320                GL_LIST_BIT);       /* for glListBase() */
321   {
322     check_gl_error ("glPushAttrib");
323
324     /* disable lighting and texturing when drawing stars!
325        (glPopAttrib() restores these.)
326      */
327     glDisable(GL_TEXTURE_2D);
328     glDisable(GL_LIGHTING);
329     glDisable(GL_DEPTH_TEST);
330
331     /* glPopAttrib() does not restore matrix changes, so we must
332        push/pop the matrix stacks to be non-intrusive there.
333      */
334     glMatrixMode(GL_PROJECTION);
335     glPushMatrix();
336     {
337       check_gl_error ("glPushMatrix");
338       glLoadIdentity();
339
340       /* Each matrix mode has its own stack, so we need to push/pop
341          them separately. */
342       glMatrixMode(GL_MODELVIEW);
343       glPushMatrix();
344       {
345         check_gl_error ("glPushMatrix");
346         glLoadIdentity();
347
348         gluOrtho2D (0, width, 0, height);
349         check_gl_error ("gluOrtho2D");
350
351         /* Draw the stars */
352         glScalef (width, height, 1);
353         glCallList(gp->starlist);
354         check_gl_error ("drawing stars");
355       }
356       glPopMatrix();
357     }
358     glMatrixMode(GL_PROJECTION);
359     glPopMatrix();
360
361   }
362   /* clean up after our state changes */
363   glPopAttrib();
364   check_gl_error ("glPopAttrib");
365 }
366
367
368
369 /* Set up lighting */
370 static void
371 init_sun (ModeInfo * mi)
372 {
373   planetstruct *gp = &planets[MI_SCREEN(mi)];
374
375   GLfloat lamb[4] = { 0.1, 0.1, 0.1, 1.0 };
376   GLfloat ldif[4] = { 1.0, 1.0, 1.0, 1.0 };
377   GLfloat spec[4] = { 1.0, 1.0, 1.0, 1.0 };
378
379   GLfloat mamb[4] = { 0.5, 0.5, 0.5, 1.0 };
380   GLfloat mdif[4] = { 1.0, 1.0, 1.0, 1.0 };
381   GLfloat mpec[4] = { 1.0, 1.0, 1.0, 1.0 };
382   GLfloat shiny = .4;
383
384   {
385     double h =  0.1 + frand(0.8);   /* east-west position - screen-side. */
386     double v = -0.3 + frand(0.6);   /* north-south position */
387
388     if (h > 0.3 && h < 0.8)         /* avoid having the sun at the camera */
389       h += (h > 0.5 ? 0.2 : -0.2);
390
391     gp->sunpos[0] = cos(h * M_PI);
392     gp->sunpos[1] = sin(h * M_PI);
393     gp->sunpos[2] = sin(v * M_PI);
394     gp->sunpos[3] =  0.00;
395   }
396
397   glEnable(GL_LIGHTING);
398   glEnable(GL_LIGHT0);
399
400   glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
401   glLightfv (GL_LIGHT0, GL_AMBIENT,  lamb);
402   glLightfv (GL_LIGHT0, GL_DIFFUSE,  ldif);
403   glLightfv (GL_LIGHT0, GL_SPECULAR, spec);
404
405   glMaterialfv (GL_FRONT, GL_AMBIENT,  mamb);
406   glMaterialfv (GL_FRONT, GL_DIFFUSE,  mdif);
407   glMaterialfv (GL_FRONT, GL_SPECULAR, mpec);
408   glMaterialf  (GL_FRONT, GL_SHININESS, shiny);
409
410
411   glEnable(GL_BLEND);
412   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
413   glShadeModel(GL_SMOOTH);
414
415   check_gl_error("lighting");
416 }
417
418
419 #define RANDSIGN() ((random() & 1) ? 1 : -1)
420
421 void
422 reshape_planet (ModeInfo *mi, int width, int height)
423 {
424   GLfloat h = (GLfloat) height / (GLfloat) width;
425
426   glViewport(0, 0, (GLint) width, (GLint) height);
427   glMatrixMode(GL_PROJECTION);
428   glLoadIdentity();
429   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
430   glMatrixMode(GL_MODELVIEW);
431   glLoadIdentity();
432   glTranslatef(0.0, 0.0, -DIST);
433
434   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
435 }
436
437
438 Bool
439 planet_handle_event (ModeInfo *mi, XEvent *event)
440 {
441   planetstruct *gp = &planets[MI_SCREEN(mi)];
442
443   if (event->xany.type == ButtonPress &&
444       event->xbutton.button == Button1)
445     {
446       gp->button_down_p = True;
447       gltrackball_start (gp->trackball,
448                          event->xbutton.x, event->xbutton.y,
449                          MI_WIDTH (mi), MI_HEIGHT (mi));
450       return True;
451     }
452   else if (event->xany.type == ButtonRelease &&
453            event->xbutton.button == Button1)
454     {
455       gp->button_down_p = False;
456       return True;
457     }
458   else if (event->xany.type == ButtonPress &&
459            (event->xbutton.button == Button4 ||
460             event->xbutton.button == Button5))
461     {
462       gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
463                               !!event->xbutton.state);
464       return True;
465     }
466   else if (event->xany.type == MotionNotify &&
467            gp->button_down_p)
468     {
469       gltrackball_track (gp->trackball,
470                          event->xmotion.x, event->xmotion.y,
471                          MI_WIDTH (mi), MI_HEIGHT (mi));
472       return True;
473     }
474
475   return False;
476 }
477
478
479 void
480 init_planet (ModeInfo * mi)
481 {
482   planetstruct *gp;
483   int screen = MI_SCREEN(mi);
484   Bool wire = MI_IS_WIREFRAME(mi);
485
486   if (planets == NULL) {
487         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
488                                                                                   sizeof (planetstruct))) == NULL)
489           return;
490   }
491   gp = &planets[screen];
492
493   if ((gp->glx_context = init_GL(mi)) != NULL) {
494         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
495   }
496
497   {
498         char *f = get_string_resource("imageForeground", "Foreground");
499         char *b = get_string_resource("imageBackground", "Background");
500         char *s;
501         if (!f) f = strdup("white");
502         if (!b) b = strdup("black");
503         
504         for (s = f + strlen(f)-1; s > f; s--)
505           if (*s == ' ' || *s == '\t')
506                 *s = 0;
507         for (s = b + strlen(b)-1; s > b; s--)
508           if (*s == ' ' || *s == '\t')
509                 *s = 0;
510
511     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
512       {
513                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
514                 exit(1);
515       }
516     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
517       {
518                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
519                 exit(1);
520       }
521
522         free (f);
523         free (b);
524   }
525
526   {
527     double spin_speed   = 0.5;
528     double wander_speed = 0.02;
529     gp->rot = make_rotator (do_roll ? spin_speed : 0,
530                             do_roll ? spin_speed : 0,
531                             0, 1,
532                             do_wander ? wander_speed : 0,
533                             True);
534     gp->z = frand (1.0);
535     gp->trackball = gltrackball_init ();
536   }
537
538   if (wire)
539     {
540       do_texture = False;
541       do_light = False;
542       glEnable (GL_LINE_SMOOTH);
543     }
544
545   if (do_texture)
546     setup_texture (mi);
547
548   if (do_light)
549         init_sun (mi);
550
551   if (do_stars)
552     init_stars (mi);
553
554   glEnable(GL_DEPTH_TEST);
555   glEnable(GL_CULL_FACE);
556   glCullFace(GL_BACK); 
557
558   /* construct the polygons of the planet
559    */
560   gp->platelist = glGenLists(1);
561   glNewList (gp->platelist, GL_COMPILE);
562   glColor3f (1,1,1);
563   glPushMatrix ();
564   glScalef (RADIUS, RADIUS, RADIUS);
565   glRotatef (90, 1, 0, 0);
566   unit_sphere (resolution, resolution, wire);
567   mi->polygon_count += resolution*resolution;
568   glPopMatrix ();
569   glEndList();
570
571   /* construct the polygons of the latitude/longitude/axis lines.
572    */
573   gp->latlonglist = glGenLists(1);
574   glNewList (gp->latlonglist, GL_COMPILE);
575   glPushMatrix ();
576   if (do_texture) glDisable (GL_TEXTURE_2D);
577   if (do_light)   glDisable (GL_LIGHTING);
578   glColor3f (0.1, 0.3, 0.1);
579   glScalef (RADIUS, RADIUS, RADIUS);
580   glScalef (1.01, 1.01, 1.01);
581   glRotatef (90, 1, 0, 0);
582   unit_sphere (12, 24, 1);
583   glBegin(GL_LINES);
584   glVertex3f(0, -2, 0);
585   glVertex3f(0,  2, 0);
586   glEnd();
587   if (do_light)   glEnable(GL_LIGHTING);
588   if (do_texture) glEnable(GL_TEXTURE_2D);
589   glPopMatrix ();
590   glEndList();
591 }
592
593 void
594 draw_planet (ModeInfo * mi)
595 {
596   planetstruct *gp = &planets[MI_SCREEN(mi)];
597   Display    *display = MI_DISPLAY(mi);
598   Window      window = MI_WINDOW(mi);
599   double x, y, z;
600
601   if (!gp->glx_context)
602         return;
603
604   glDrawBuffer(GL_BACK);
605   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
606
607   glXMakeCurrent (display, window, *(gp->glx_context));
608
609   if (do_stars)
610     draw_stars (mi);
611
612   glPushMatrix();
613
614   get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
615   glTranslatef((x - 0.5) * 15,
616                (y - 0.5) * 15,
617                (z - 0.5) * 8);
618
619   gltrackball_rotate (gp->trackball);
620
621   glRotatef (90,1,0,0);
622
623   if (do_roll)
624     {
625       get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
626       glRotatef (x * 360, 1.0, 0.0, 0.0);
627       glRotatef (y * 360, 0.0, 1.0, 0.0);
628     }
629
630   glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
631
632   glRotatef (gp->z * 360, 0.0, 0.0, 1.0);
633   if (do_rotate && !gp->button_down_p)
634     {
635       gp->z -= 0.005;     /* the sun sets in the west */
636       if (gp->z < 0) gp->z += 1;
637     }
638
639   glCallList (gp->platelist);
640   if (gp->button_down_p)
641     glCallList (gp->latlonglist);
642   glPopMatrix();
643
644   if (mi->fps_p) do_fps (mi);
645   glFinish();
646   glXSwapBuffers(display, window);
647 }
648
649
650 void
651 release_planet (ModeInfo * mi)
652 {
653   if (planets != NULL) {
654         int screen;
655
656         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
657           planetstruct *gp = &planets[screen];
658
659           if (gp->glx_context) {
660                 /* Display lists MUST be freed while their glXContext is current. */
661                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
662
663                 if (glIsList(gp->platelist))
664                   glDeleteLists(gp->platelist, 1);
665                 if (glIsList(gp->starlist))
666                   glDeleteLists(gp->starlist, 1);
667           }
668         }
669         (void) free((void *) planets);
670         planets = NULL;
671   }
672   FreeAllGL(mi);
673 }
674
675
676 #endif
677