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