a156e5abc9efcc2c214c645017832692b77a0735
[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 latlonglist;
171   GLuint starlist;
172   int screen_width, screen_height;
173   GLXContext *glx_context;
174   Window window;
175   XColor fg, bg;
176   GLfloat sunpos[4];
177   double z;
178   rotator *rot;
179   trackball_state *trackball;
180   Bool button_down_p;
181 } planetstruct;
182
183
184 static planetstruct *planets = NULL;
185
186
187 static inline void
188 normalize(GLfloat v[3])
189 {
190   GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] +
191                                        v[1] * v[1] +
192                                        v[2] * v[2]));
193   if (d != 0)
194     {
195       v[0] /= d;
196       v[1] /= d;
197       v[2] /= d;
198         }
199   else
200     {
201       v[0] = v[1] = v[2] = 0;
202         }
203 }
204
205
206 /* Set up and enable texturing on our object */
207 static void
208 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
209 {
210   XImage *image = xpm_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
211                                   MI_COLORMAP (mi), xpm_data);
212   char buf[1024];
213   clear_gl_error();
214   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
215                image->width, image->height, 0,
216                GL_RGBA, GL_UNSIGNED_BYTE, image->data);
217   sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
218   check_gl_error(buf);
219
220   /* setup parameters for texturing */
221   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
222   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
223   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
224   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
225   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
226   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
227 }
228
229
230 static void
231 setup_file_texture (ModeInfo *mi, char *filename)
232 {
233   Display *dpy = mi->dpy;
234   Visual *visual = mi->xgwa.visual;
235   char buf[1024];
236
237   Colormap cmap = mi->xgwa.colormap;
238   XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
239
240   clear_gl_error();
241   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
242                image->width, image->height, 0,
243                GL_RGBA, GL_UNSIGNED_BYTE, image->data);
244   sprintf (buf, "texture: %.100s (%dx%d)",
245            filename, image->width, image->height);
246   check_gl_error(buf);
247
248   /* setup parameters for texturing */
249   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
250   glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
251
252   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
253   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
254   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
255   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
256   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
257 }
258
259
260 static void
261 setup_texture(ModeInfo * mi)
262 {
263 /*  planetstruct *gp = &planets[MI_SCREEN(mi)];*/
264
265   glEnable(GL_TEXTURE_2D);
266
267   if (!which_image ||
268           !*which_image ||
269           !strcmp(which_image, "BUILTIN"))
270         setup_xpm_texture (mi, earth_xpm);
271   else
272         setup_file_texture (mi, which_image);
273
274   check_gl_error("texture initialization");
275
276   /* Need to flip the texture top for bottom for some reason. */
277   glMatrixMode (GL_TEXTURE);
278   glScalef (1, -1, 1);
279   glMatrixMode (GL_MODELVIEW);
280 }
281
282
283 void
284 init_stars (ModeInfo *mi)
285 {
286   int i, j;
287   GLfloat max_size = 3;
288   GLfloat inc = 0.5;
289   int steps = max_size / inc;
290   int width  = MI_WIDTH(mi);
291   int height = MI_HEIGHT(mi);
292
293   planetstruct *gp = &planets[MI_SCREEN(mi)];
294   Bool wire = MI_IS_WIREFRAME(mi);
295   
296   if (!wire)
297     glEnable (GL_POINT_SMOOTH);
298
299   gp->starlist = glGenLists(1);
300   glNewList(gp->starlist, GL_COMPILE);
301
302   glScalef (1.0/width, 1.0/height, 1);
303
304   for (j = 1; j <= steps; j++)
305     {
306       glPointSize(inc * j);
307       glBegin(GL_POINTS);
308       for (i = 0 ; i < NUM_STARS / steps; i++)
309         {
310           glColor3f (0.6 + frand(0.3),
311                      0.6 + frand(0.3),
312                      0.6 + frand(0.3));
313           glVertex2f ((GLfloat) (random() % width),
314                       (GLfloat) (random() % height));
315         }
316       glEnd();
317     }
318   glEndList();
319
320   check_gl_error("stars initialization");
321 }
322
323
324 void
325 draw_stars (ModeInfo * mi)
326 {
327   int width  = MI_WIDTH(mi);
328   int height = MI_HEIGHT(mi);
329
330   planetstruct *gp = &planets[MI_SCREEN(mi)];
331   
332   /* Sadly, this causes a stall of the graphics pipeline (as would the
333      equivalent calls to glGet*.)  But there's no way around this, short
334      of having each caller set up the specific display matrix we need
335      here, which would kind of defeat the purpose of centralizing this
336      code in one file.
337    */
338   glPushAttrib(GL_TRANSFORM_BIT |  /* for matrix contents */
339                GL_ENABLE_BIT |     /* for various glDisable calls */
340                GL_CURRENT_BIT |    /* for glColor3f() */
341                GL_LIST_BIT);       /* for glListBase() */
342   {
343     check_gl_error ("glPushAttrib");
344
345     /* disable lighting and texturing when drawing stars!
346        (glPopAttrib() restores these.)
347      */
348     glDisable(GL_TEXTURE_2D);
349     glDisable(GL_LIGHTING);
350     glDisable(GL_DEPTH_TEST);
351
352     /* glPopAttrib() does not restore matrix changes, so we must
353        push/pop the matrix stacks to be non-intrusive there.
354      */
355     glMatrixMode(GL_PROJECTION);
356     glPushMatrix();
357     {
358       check_gl_error ("glPushMatrix");
359       glLoadIdentity();
360
361       /* Each matrix mode has its own stack, so we need to push/pop
362          them separately. */
363       glMatrixMode(GL_MODELVIEW);
364       glPushMatrix();
365       {
366         check_gl_error ("glPushMatrix");
367         glLoadIdentity();
368
369         gluOrtho2D (0, width, 0, height);
370         check_gl_error ("gluOrtho2D");
371
372         /* Draw the stars */
373         glScalef (width, height, 1);
374         glCallList(gp->starlist);
375         check_gl_error ("drawing stars");
376       }
377       glPopMatrix();
378     }
379     glMatrixMode(GL_PROJECTION);
380     glPopMatrix();
381
382   }
383   /* clean up after our state changes */
384   glPopAttrib();
385   check_gl_error ("glPopAttrib");
386 }
387
388
389
390 /* Set up lighting */
391 static void
392 init_sun (ModeInfo * mi)
393 {
394   planetstruct *gp = &planets[MI_SCREEN(mi)];
395
396   GLfloat lamb[4] = { 0.1, 0.1, 0.1, 1.0 };
397   GLfloat ldif[4] = { 1.0, 1.0, 1.0, 1.0 };
398   GLfloat spec[4] = { 1.0, 1.0, 1.0, 1.0 };
399
400   GLfloat mamb[4] = { 0.5, 0.5, 0.5, 1.0 };
401   GLfloat mdif[4] = { 1.0, 1.0, 1.0, 1.0 };
402   GLfloat mpec[4] = { 1.0, 1.0, 1.0, 1.0 };
403   GLfloat shiny = .4;
404
405   {
406     double h =  0.1 + frand(0.8);   /* east-west position - screen-side. */
407     double v = -0.3 + frand(0.6);   /* north-south position */
408
409     if (h > 0.3 && h < 0.8)         /* avoid having the sun at the camera */
410       h += (h > 0.5 ? 0.2 : -0.2);
411
412     gp->sunpos[0] = cos(h * M_PI);
413     gp->sunpos[1] = sin(h * M_PI);
414     gp->sunpos[2] = sin(v * M_PI);
415     gp->sunpos[3] =  0.00;
416   }
417
418   glEnable(GL_LIGHTING);
419   glEnable(GL_LIGHT0);
420
421   glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
422   glLightfv (GL_LIGHT0, GL_AMBIENT,  lamb);
423   glLightfv (GL_LIGHT0, GL_DIFFUSE,  ldif);
424   glLightfv (GL_LIGHT0, GL_SPECULAR, spec);
425
426   glMaterialfv (GL_FRONT, GL_AMBIENT,  mamb);
427   glMaterialfv (GL_FRONT, GL_DIFFUSE,  mdif);
428   glMaterialfv (GL_FRONT, GL_SPECULAR, mpec);
429   glMaterialf  (GL_FRONT, GL_SHININESS, shiny);
430
431
432   glEnable(GL_BLEND);
433   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
434   glShadeModel(GL_SMOOTH);
435
436   check_gl_error("lighting");
437 }
438
439
440 #define RANDSIGN() ((random() & 1) ? 1 : -1)
441
442 static void
443 pick_velocity (ModeInfo * mi)
444 {
445 #if 0
446   planetstruct *gp = &planets[MI_SCREEN(mi)];
447
448   gp->box_width =  15.0;
449   gp->box_height = 15.0;
450   gp->box_depth =  5.0;
451
452   gp->tx = 0.0;
453   gp->ty = 0.0;
454   gp->tz = frand(360);
455
456   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
457   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
458   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
459
460   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
461   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
462   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
463 #endif
464 }
465
466
467 void
468 reshape_planet (ModeInfo *mi, int width, int height)
469 {
470   GLfloat h = (GLfloat) height / (GLfloat) width;
471
472   glViewport(0, 0, (GLint) width, (GLint) height);
473   glMatrixMode(GL_PROJECTION);
474   glLoadIdentity();
475   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
476   glMatrixMode(GL_MODELVIEW);
477   glLoadIdentity();
478   glTranslatef(0.0, 0.0, -DIST);
479
480   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
481 }
482
483
484 Bool
485 planet_handle_event (ModeInfo *mi, XEvent *event)
486 {
487   planetstruct *gp = &planets[MI_SCREEN(mi)];
488
489   if (event->xany.type == ButtonPress &&
490       event->xbutton.button & Button1)
491     {
492       gp->button_down_p = True;
493       gltrackball_start (gp->trackball,
494                          event->xbutton.x, event->xbutton.y,
495                          MI_WIDTH (mi), MI_HEIGHT (mi));
496       return True;
497     }
498   else if (event->xany.type == ButtonRelease &&
499            event->xbutton.button & Button1)
500     {
501       gp->button_down_p = False;
502       return True;
503     }
504   else if (event->xany.type == MotionNotify &&
505            gp->button_down_p)
506     {
507       gltrackball_track (gp->trackball,
508                          event->xmotion.x, event->xmotion.y,
509                          MI_WIDTH (mi), MI_HEIGHT (mi));
510       return True;
511     }
512
513   return False;
514 }
515
516
517 void
518 init_planet (ModeInfo * mi)
519 {
520   planetstruct *gp;
521   int screen = MI_SCREEN(mi);
522   Bool wire = MI_IS_WIREFRAME(mi);
523
524   if (planets == NULL) {
525         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
526                                                                                   sizeof (planetstruct))) == NULL)
527           return;
528   }
529   gp = &planets[screen];
530
531   pick_velocity (mi);
532
533   if ((gp->glx_context = init_GL(mi)) != NULL) {
534         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
535   }
536
537   {
538         char *f = get_string_resource("imageForeground", "Foreground");
539         char *b = get_string_resource("imageBackground", "Background");
540         char *s;
541         if (!f) f = strdup("white");
542         if (!b) b = strdup("black");
543         
544         for (s = f + strlen(f)-1; s > f; s--)
545           if (*s == ' ' || *s == '\t')
546                 *s = 0;
547         for (s = b + strlen(b)-1; s > b; s--)
548           if (*s == ' ' || *s == '\t')
549                 *s = 0;
550
551     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
552       {
553                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
554                 exit(1);
555       }
556     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
557       {
558                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
559                 exit(1);
560       }
561
562         free (f);
563         free (b);
564   }
565
566   {
567     double spin_speed   = 1.0;
568     double wander_speed = 0.05;
569     gp->rot = make_rotator (do_roll ? spin_speed : 0,
570                             do_roll ? spin_speed : 0,
571                             0, 1,
572                             do_wander ? wander_speed : 0,
573                             True);
574     gp->z = frand (1.0);
575     gp->trackball = gltrackball_init ();
576   }
577
578   if (wire)
579     {
580       do_texture = False;
581       do_light = False;
582       glEnable (GL_LINE_SMOOTH);
583     }
584
585   if (do_texture)
586     setup_texture (mi);
587
588   if (do_light)
589         init_sun (mi);
590
591   if (do_stars)
592     init_stars (mi);
593
594   glEnable(GL_DEPTH_TEST);
595   glEnable(GL_CULL_FACE);
596   glCullFace(GL_BACK); 
597
598   /* construct the polygons of the planet
599    */
600   gp->platelist = glGenLists(1);
601   glNewList (gp->platelist, GL_COMPILE);
602   glColor3f (1,1,1);
603   glPushMatrix ();
604   glScalef (RADIUS, RADIUS, RADIUS);
605   glRotatef (90, 1, 0, 0);
606   unit_sphere (resolution, resolution, wire);
607   mi->polygon_count += resolution*resolution;
608   glPopMatrix ();
609   glEndList();
610
611   /* construct the polygons of the latitude/longitude/axis lines.
612    */
613   gp->latlonglist = glGenLists(1);
614   glNewList (gp->latlonglist, GL_COMPILE);
615   glPushMatrix ();
616   if (do_texture) glDisable (GL_TEXTURE_2D);
617   if (do_light)   glDisable (GL_LIGHTING);
618   glColor3f (0.1, 0.3, 0.1);
619   glScalef (RADIUS, RADIUS, RADIUS);
620   glScalef (1.01, 1.01, 1.01);
621   glRotatef (90, 1, 0, 0);
622   unit_sphere (12, 24, 1);
623   glBegin(GL_LINES);
624   glVertex3f(0, -2, 0);
625   glVertex3f(0,  2, 0);
626   glEnd();
627   if (do_light)   glEnable(GL_LIGHTING);
628   if (do_texture) glEnable(GL_TEXTURE_2D);
629   glPopMatrix ();
630   glEndList();
631 }
632
633 void
634 draw_planet (ModeInfo * mi)
635 {
636   planetstruct *gp = &planets[MI_SCREEN(mi)];
637   Display    *display = MI_DISPLAY(mi);
638   Window      window = MI_WINDOW(mi);
639   double x, y, z;
640
641   if (!gp->glx_context)
642         return;
643
644   glDrawBuffer(GL_BACK);
645   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
646
647   glXMakeCurrent (display, window, *(gp->glx_context));
648
649   if (do_stars)
650     draw_stars (mi);
651
652   glPushMatrix();
653
654   get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
655   glTranslatef((x - 0.5) * 15,
656                (y - 0.5) * 15,
657                (z - 0.5) * 8);
658
659   gltrackball_rotate (gp->trackball);
660
661   glRotatef (90,1,0,0);
662
663   if (do_roll)
664     {
665       get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
666       glRotatef (x * 360, 1.0, 0.0, 0.0);
667       glRotatef (y * 360, 0.0, 1.0, 0.0);
668     }
669
670   glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
671
672   glRotatef (gp->z * 360, 0.0, 0.0, 1.0);
673   if (do_rotate && !gp->button_down_p)
674     {
675       gp->z += 0.01;
676       if (gp->z > 1) gp->z -= 1;
677     }
678
679   glCallList (gp->platelist);
680   if (gp->button_down_p)
681     glCallList (gp->latlonglist);
682   glPopMatrix();
683
684   if (mi->fps_p) do_fps (mi);
685   glFinish();
686   glXSwapBuffers(display, window);
687 }
688
689
690 void
691 release_planet (ModeInfo * mi)
692 {
693   if (planets != NULL) {
694         int screen;
695
696         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
697           planetstruct *gp = &planets[screen];
698
699           if (gp->glx_context) {
700                 /* Display lists MUST be freed while their glXContext is current. */
701                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
702
703                 if (glIsList(gp->platelist))
704                   glDeleteLists(gp->platelist, 1);
705                 if (glIsList(gp->starlist))
706                   glDeleteLists(gp->starlist, 1);
707           }
708         }
709         (void) free((void *) planets);
710         planets = NULL;
711   }
712   FreeAllGL(mi);
713 }
714
715
716 #endif
717