http://www.jwz.org/xscreensaver/xscreensaver-5.11.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 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             event->xbutton.button == Button6 ||
452             event->xbutton.button == Button7))
453     {
454       gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
455                               !!event->xbutton.state);
456       return True;
457     }
458   else if (event->xany.type == MotionNotify &&
459            gp->button_down_p)
460     {
461       gltrackball_track (gp->trackball,
462                          event->xmotion.x, event->xmotion.y,
463                          MI_WIDTH (mi), MI_HEIGHT (mi));
464       return True;
465     }
466
467   return False;
468 }
469
470
471 ENTRYPOINT void
472 init_planet (ModeInfo * mi)
473 {
474   planetstruct *gp;
475   int screen = MI_SCREEN(mi);
476   Bool wire = MI_IS_WIREFRAME(mi);
477
478   if (planets == NULL) {
479         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
480                                                                                   sizeof (planetstruct))) == NULL)
481           return;
482   }
483   gp = &planets[screen];
484
485   if ((gp->glx_context = init_GL(mi)) != NULL) {
486         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
487   }
488
489   {
490         char *f = get_string_resource(mi->dpy, "imageForeground", "Foreground");
491         char *b = get_string_resource(mi->dpy, "imageBackground", "Background");
492         char *s;
493         if (!f) f = strdup("white");
494         if (!b) b = strdup("black");
495         
496         for (s = f + strlen(f)-1; s > f; s--)
497           if (*s == ' ' || *s == '\t')
498                 *s = 0;
499         for (s = b + strlen(b)-1; s > b; s--)
500           if (*s == ' ' || *s == '\t')
501                 *s = 0;
502
503     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
504       {
505                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
506                 exit(1);
507       }
508     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
509       {
510                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
511                 exit(1);
512       }
513
514         free (f);
515         free (b);
516   }
517
518   {
519     double spin_speed   = 0.5;
520     double wander_speed = 0.02;
521     gp->rot = make_rotator (do_roll ? spin_speed : 0,
522                             do_roll ? spin_speed : 0,
523                             0, 1,
524                             do_wander ? wander_speed : 0,
525                             True);
526     gp->z = frand (1.0);
527     gp->trackball = gltrackball_init ();
528   }
529
530   if (wire)
531     {
532       do_texture = False;
533       do_light = False;
534       glEnable (GL_LINE_SMOOTH);
535     }
536
537   if (do_texture)
538     setup_texture (mi);
539
540   if (do_light)
541         init_sun (mi);
542
543   if (do_stars)
544     init_stars (mi);
545
546   glEnable(GL_DEPTH_TEST);
547   glEnable(GL_CULL_FACE);
548   glCullFace(GL_BACK); 
549
550   /* construct the polygons of the planet
551    */
552   gp->platelist = glGenLists(1);
553   glNewList (gp->platelist, GL_COMPILE);
554   glColor3f (1,1,1);
555   glPushMatrix ();
556   glScalef (RADIUS, RADIUS, RADIUS);
557   glRotatef (90, 1, 0, 0);
558   unit_sphere (resolution, resolution, wire);
559   mi->polygon_count += resolution*resolution;
560   glPopMatrix ();
561   glEndList();
562
563   /* construct the polygons of the latitude/longitude/axis lines.
564    */
565   gp->latlonglist = glGenLists(1);
566   glNewList (gp->latlonglist, GL_COMPILE);
567   glPushMatrix ();
568   if (do_texture) glDisable (GL_TEXTURE_2D);
569   if (do_light)   glDisable (GL_LIGHTING);
570   glColor3f (0.1, 0.3, 0.1);
571   glScalef (RADIUS, RADIUS, RADIUS);
572   glScalef (1.01, 1.01, 1.01);
573   glRotatef (90, 1, 0, 0);
574   unit_sphere (12, 24, 1);
575   glBegin(GL_LINES);
576   glVertex3f(0, -2, 0);
577   glVertex3f(0,  2, 0);
578   glEnd();
579   if (do_light)   glEnable(GL_LIGHTING);
580   if (do_texture) glEnable(GL_TEXTURE_2D);
581   glPopMatrix ();
582   glEndList();
583 }
584
585 ENTRYPOINT void
586 draw_planet (ModeInfo * mi)
587 {
588   planetstruct *gp = &planets[MI_SCREEN(mi)];
589   Display    *display = MI_DISPLAY(mi);
590   Window      window = MI_WINDOW(mi);
591   double x, y, z;
592
593   if (!gp->glx_context)
594         return;
595
596   glDrawBuffer(GL_BACK);
597   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
598
599   glXMakeCurrent (display, window, *(gp->glx_context));
600
601   if (do_stars)
602     draw_stars (mi);
603
604   glPushMatrix();
605
606   get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
607   glTranslatef((x - 0.5) * 15,
608                (y - 0.5) * 15,
609                (z - 0.5) * 8);
610
611   gltrackball_rotate (gp->trackball);
612
613   glRotatef (90,1,0,0);
614
615   if (do_roll)
616     {
617       get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
618       glRotatef (x * 360, 1.0, 0.0, 0.0);
619       glRotatef (y * 360, 0.0, 1.0, 0.0);
620     }
621
622   glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
623
624   glRotatef (gp->z * 360, 0.0, 0.0, 1.0);
625   if (do_rotate && !gp->button_down_p)
626     {
627       gp->z -= 0.005;     /* the sun sets in the west */
628       if (gp->z < 0) gp->z += 1;
629     }
630
631   glCallList (gp->platelist);
632   if (gp->button_down_p)
633     glCallList (gp->latlonglist);
634   glPopMatrix();
635
636   if (mi->fps_p) do_fps (mi);
637   glFinish();
638   glXSwapBuffers(display, window);
639 }
640
641
642 ENTRYPOINT void
643 release_planet (ModeInfo * mi)
644 {
645   if (planets != NULL) {
646         int screen;
647
648         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
649           planetstruct *gp = &planets[screen];
650
651           if (gp->glx_context) {
652                 /* Display lists MUST be freed while their glXContext is current. */
653         /* but this gets a BadMatch error. -jwz */
654                 /*glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));*/
655
656                 if (glIsList(gp->platelist))
657                   glDeleteLists(gp->platelist, 1);
658                 if (glIsList(gp->starlist))
659                   glDeleteLists(gp->starlist, 1);
660           }
661         }
662         (void) free((void *) planets);
663         planets = NULL;
664   }
665   FreeAllGL(mi);
666 }
667
668
669 XSCREENSAVER_MODULE_2 ("GLPlanet", glplanet, planet)
670
671 #endif