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