047abbf6c5ba61daa61fc9eef9b95c56d26c1ef7
[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  * 21-Mar-01: jwz@jwz.org   Broke sphere routine out into its own file.
18  *
19  * 9-Oct-98:  dek@cgl.ucsf.edu  Added stars.
20  *
21  * 8-Oct-98:  jwz@jwz.org   Made the 512x512x1 xearth image be built in.
22  *                          Made it possible to load XPM or XBM files.
23  *                          Made the planet bounce and roll around.
24  *
25  * 8-Oct-98: Released initial version of "glplanet"
26  * (David Konerding, dek@cgl.ucsf.edu)
27  *
28  * BUGS:
29  * -bounce is broken
30  * 
31  *   For even more spectacular results, grab the images from the "SSysten"
32  *   package (http://www.msu.edu/user/kamelkev/) and do this:
33  *
34  *     cd ssystem-1.4/hires/
35  *     foreach f ( *.jpg )
36  *       djpeg $f | ppmquant 254 | ppmtoxpm > /tmp/$f:r.xpm
37  *     end
38  *
39  *     cd /tmp
40  *     foreach f ( *.xpm )
41  *       glplanet -image $f
42  *     end
43  */
44
45
46 /*-
47  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
48  * otherwise caddr_t is not defined correctly
49  */
50
51 #include <X11/Intrinsic.h>
52
53 #ifdef STANDALONE
54 # define PROGCLASS                                              "Planet"
55 # define HACK_INIT                                              init_planet
56 # define HACK_DRAW                                              draw_planet
57 # define HACK_RESHAPE                                   reshape_planet
58 # define planet_opts                                    xlockmore_opts
59 #define DEFAULTS        "*delay:                        15000   \n"     \
60                                         "*showFPS:                      False   \n" \
61                     "*rotate:           True    \n" \
62                     "*roll:             True    \n" \
63                     "*bounce:           True    \n" \
64                                         "*wireframe:            False   \n"     \
65                                         "*light:                        True    \n"     \
66                                         "*texture:                      True    \n" \
67                                         "*stars:                        True    \n" \
68                                         "*image:                        BUILTIN \n" \
69                                         "*imageForeground:      Green   \n" \
70                                         "*imageBackground:      Blue    \n"
71
72 # include "xlockmore.h"                         /* from the xscreensaver distribution */
73 #else  /* !STANDALONE */
74 # include "xlock.h"                                     /* from the xlockmore distribution */
75 #endif /* !STANDALONE */
76
77 #ifdef USE_GL /* whole file */
78
79 #include "sphere.h"
80
81 #ifdef HAVE_XPM
82 # include <X11/xpm.h>
83 # ifndef PIXEL_ALREADY_TYPEDEFED
84 #  define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
85 # endif
86 #endif
87
88 #ifdef HAVE_XMU
89 # ifndef VMS
90 #  include <X11/Xmu/Drawing.h>
91 #else  /* VMS */
92 #  include <Xmu/Drawing.h>
93 # endif /* VMS */
94 #endif
95
96
97 #include <GL/glu.h>
98
99 #define DEF_ROTATE  "True"
100 #define DEF_ROLL    "True"
101 #define DEF_BOUNCE  "True"
102 #define DEF_TEXTURE "True"
103 #define DEF_STARS "True"
104 #define DEF_LIGHT   "True"
105 #define DEF_IMAGE   "BUILTIN"
106
107 #undef countof
108 #define countof(x) (sizeof((x))/sizeof((*x)))
109
110 static int do_rotate;
111 static int do_roll;
112 static int do_bounce;
113 static int do_texture;
114 static int do_stars;
115 static int do_light;
116 static char *which_image;
117 static XrmOptionDescRec opts[] = {
118   {"-rotate",  ".glplanet.rotate",  XrmoptionNoArg, (caddr_t) "true" },
119   {"+rotate",  ".glplanet.rotate",  XrmoptionNoArg, (caddr_t) "false" },
120   {"-roll",    ".glplanet.roll",    XrmoptionNoArg, (caddr_t) "true" },
121   {"+roll",    ".glplanet.roll",    XrmoptionNoArg, (caddr_t) "false" },
122   {"-bounce",  ".glplanet.bounce",  XrmoptionNoArg, (caddr_t) "true" },
123   {"+bounce",  ".glplanet.bounce",  XrmoptionNoArg, (caddr_t) "false" },
124   {"-texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "true" },
125   {"+texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "false" },
126   {"-stars",   ".glplanet.stars",   XrmoptionNoArg, (caddr_t) "true" },
127   {"+stars",   ".glplanet.stars",   XrmoptionNoArg, (caddr_t) "false" },
128   {"-light",   ".glplanet.light",   XrmoptionNoArg, (caddr_t) "true" },
129   {"+light",   ".glplanet.light",   XrmoptionNoArg, (caddr_t) "false" },
130   {"-image",   ".glplanet.image",  XrmoptionSepArg, (caddr_t) 0 },
131 };
132
133 static argtype vars[] = {
134   {(caddr_t *) &do_rotate,   "rotate",  "Rotate",  DEF_ROTATE,  t_Bool},
135   {(caddr_t *) &do_roll,     "roll",    "Roll",    DEF_ROLL,    t_Bool},
136   {(caddr_t *) &do_bounce,   "bounce",  "Bounce",  DEF_BOUNCE,  t_Bool},
137   {(caddr_t *) &do_texture,  "texture", "Texture", DEF_TEXTURE, t_Bool},
138   {(caddr_t *) &do_stars,  "stars", "Stars", DEF_STARS, t_Bool},
139   {(caddr_t *) &do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
140   {(caddr_t *) &which_image, "image",   "Image",   DEF_IMAGE,   t_String},
141 };
142
143 ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
144
145 #ifdef USE_MODULES
146 ModStruct   planet_description =
147 {"planet", "init_planet", "draw_planet", "release_planet",
148  "draw_planet", "init_planet", NULL, &planet_opts,
149  1000, 1, 2, 1, 4, 1.0, "",
150  "Animates texture mapped sphere (planet)", 0, NULL};
151 #endif
152
153 #include "../images/earth.xbm"
154 #include "xpm-ximage.h"
155
156
157 /*-
158  * slices and stacks are used in the sphere parameterization routine.
159  * more slices and stacks will increase the quality of the sphere,
160  * at the expense of rendering speed
161  */
162
163 #define NUM_STARS 1000
164 #define SLICES 32
165 #define STACKS 32
166
167 /* radius of the sphere- fairly arbitrary */
168 #define RADIUS 4
169
170 /* distance away from the sphere model */
171 #define DIST 40
172
173
174
175 /* structure for holding the planet data */
176 typedef struct {
177   GLuint platelist;
178   GLuint starlist;
179   int screen_width, screen_height;
180   GLXContext *glx_context;
181   Window window;
182
183   XColor fg, bg;
184
185   GLfloat tx, ty, tz;
186   GLfloat dtx, dty, dtz;
187   GLfloat xpos, ypos, zpos;
188   GLfloat dx, dy, dz;
189   GLfloat box_width, box_height, box_depth;
190
191 } planetstruct;
192
193
194 static planetstruct *planets = NULL;
195
196
197 static inline void
198 normalize(GLfloat v[3])
199 {
200         GLfloat     d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
201
202         if (d != 0) {
203                 v[0] /= d;
204                 v[1] /= d;
205                 v[2] /= d;
206         } else {
207                 v[0] = v[1] = v[2] = 0;
208         }
209 }
210
211
212 /* Set up and enable texturing on our object */
213 static void
214 setup_xbm_texture (char *bits, int width, int height,
215                                    XColor *fgc, XColor *bgc)
216 {
217   unsigned int fg = (((fgc->red  >> 8) << 16) |
218                                          ((fgc->green >> 8) << 8) |
219                                          ((fgc->blue >> 8)));
220   unsigned int bg = (((bgc->red  >> 8) << 16) |
221                                          ((bgc->green >> 8) << 8) |
222                                          ((bgc->blue >> 8)));
223
224   unsigned char *data = (unsigned char *)
225         malloc ((width * height * 24) / 8);
226   unsigned char *out = data;
227   int x, y;
228
229   for (y = 0; y < height; y++)
230         for (x = 0; x < width; x++)
231           {
232                 unsigned char byte = bits [(y * (width / 8) + (x / 8))];
233                 unsigned char bit = (byte & (1 << (x % 8))) >> (x % 8);
234                 unsigned int word = (bit ? bg : fg);
235                 *out++ = (word & 0xFF0000) >> 16;
236                 *out++ = (word & 0x00FF00) >> 8;
237                 *out++ = (word & 0x0000FF);
238           }
239
240   clear_gl_error();
241   glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
242                            GL_RGB, GL_UNSIGNED_BYTE, data);
243   check_gl_error("texture");
244
245   /* setup parameters for texturing */
246   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
247   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
248   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
249   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
250   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
251   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
252 }
253
254
255 static void
256 setup_file_texture (ModeInfo *mi, char *filename)
257 {
258   Display *dpy = mi->dpy;
259   Visual *visual = mi->xgwa.visual;
260   Colormap cmap = mi->xgwa.colormap;
261
262 #ifdef HAVE_XPM
263   {
264         char **xpm_data = 0;
265         int result = XpmReadFileToData (filename, &xpm_data);
266         switch (result) {
267         case XpmSuccess:
268           {
269                 XImage *image = xpm_to_ximage (dpy, visual, cmap, xpm_data);
270
271         clear_gl_error();
272                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
273                                          image->width, image->height, 0,
274                                          GL_RGBA, GL_UNSIGNED_BYTE, image->data);
275         check_gl_error("texture");
276
277                 /* setup parameters for texturing */
278                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
279                 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
280
281                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
282                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
283                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
284                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
285                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
286                 return;
287           }
288           break;
289
290         case XpmOpenFailed:
291           fprintf (stderr, "%s: file %s doesn't exist.\n", progname, filename);
292           exit (-1);
293           break;
294
295         case XpmFileInvalid:
296           /* Fall through and try it as an XBM. */
297           break;
298
299         case XpmNoMemory:
300           fprintf (stderr, "%s: XPM: out of memory\n", progname);
301           exit (-1);
302           break;
303
304         default:
305           fprintf (stderr, "%s: XPM: unknown error code %d\n", progname, result);
306           exit (-1);
307           break;
308         }
309   }
310 #endif /* HAVE_XPM */
311
312 #ifdef HAVE_XMU
313   {
314         planetstruct *gp = &planets[MI_SCREEN(mi)];
315         unsigned int width = 0;
316         unsigned int height = 0;
317         unsigned char *data = 0;
318         int xhot, yhot;
319         int status = XmuReadBitmapDataFromFile (filename, &width, &height, &data,
320                                                                                         &xhot, &yhot);
321         if (status != Success)
322           {
323 # ifdef HAVE_XPM
324                 fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
325 # endif
326                 fprintf (stderr, "%s: not an XBM file: %s\n", progname, filename);
327                 exit (1);
328           }
329
330         setup_xbm_texture ((char *) data, width, height, &gp->fg, &gp->bg);
331   }
332 #else  /* !XMU */
333
334 # ifdef HAVE_XPM
335   fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
336 # endif
337   fprintf (stderr, "%s: your vendor doesn't ship the standard Xmu library.\n",
338                    progname);
339   fprintf (stderr, "%s: we can't load XBM files without it.\n",progname);
340   exit (1);
341 #endif /* !XMU */
342 }
343
344
345 static void
346 setup_texture(ModeInfo * mi)
347 {
348   planetstruct *gp = &planets[MI_SCREEN(mi)];
349   if (!which_image ||
350           !*which_image ||
351           !strcmp(which_image, "BUILTIN"))
352         setup_xbm_texture (earth_bits, earth_width, earth_height,
353                                            &gp->fg, &gp->bg);
354   else
355         setup_file_texture (mi, which_image);
356 }
357
358
359 /* Set up and enable lighting */
360 static void
361 setup_light(void)
362 {
363   /* set a number of parameters which make the scene look much nicer */
364   glEnable(GL_BLEND);
365   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
366   glShadeModel(GL_SMOOTH);
367 }
368
369
370 /* Set up and enable face culling so we don't see the inside of the sphere */
371 static void
372 setup_face(void)
373 {
374   glEnable(GL_CULL_FACE);
375   glCullFace(GL_BACK); 
376 }
377
378
379 #if 0
380 /* Function for determining points on the surface of the sphere */
381 static void inline ParametricSphere(float theta, float rho, GLfloat *vector)
382 {
383   vector[0] = -sin(theta) * sin(rho);
384   vector[1] = cos(theta) * sin(rho);
385   vector[2] = cos(rho);
386
387 #if DO_HELIX
388   vector[0] = -(1- cos(theta)) * cos(rho); 
389   vector[1] = -(1- cos(theta)) * sin(rho); 
390   vector[2] = -(sin(theta) + rho); 
391 #endif /* DO_HELIX */
392
393         return;
394 }
395 #endif
396
397
398 /* lame way to generate some random stars */
399 void generate_stars(int width, int height)
400 {
401   int i, j;
402   int max_size = 3;
403   GLfloat inc = 0.5;
404   int steps = max_size / inc;
405
406   planetstruct *gp = &planets[MI_SCREEN(mi)];
407   
408   gp->starlist = glGenLists(1);
409   glNewList(gp->starlist, GL_COMPILE);
410
411   /* this hackery makes the viewport map one-to-one with Vertex arguments */
412   glMatrixMode(GL_PROJECTION);
413   glPushMatrix();
414   glMatrixMode(GL_PROJECTION);
415   glLoadIdentity();
416   gluOrtho2D(0, width, 0, height);
417   glMatrixMode(GL_MODELVIEW);
418   glLoadIdentity();
419
420   /* disable depth testing for the stars, so they don't obscure the planet */
421   glDisable(GL_DEPTH_TEST);
422   glEnable(GL_BLEND);
423   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
424   
425   glColor3f(1,1,1);
426
427   glEnable(GL_POINT_SMOOTH);
428
429   for (j = 1; j <= steps; j++)
430     {
431       glPointSize(inc * j);
432       glBegin(GL_POINTS);
433       for(i = 0 ; i < NUM_STARS / steps; i++)
434         {
435           glColor3f (0.6 + frand(0.3),
436                      0.6 + frand(0.3),
437                      0.6 + frand(0.3));
438           glVertex2f ((GLfloat) (random() % width),
439                       (GLfloat) (random() % height));
440         }
441       glEnd();
442     }
443
444   /* return to original PROJECT and MODELVIEW */
445   glMatrixMode(GL_PROJECTION);
446   glPopMatrix();
447   glMatrixMode(GL_MODELVIEW);
448
449
450   glEndList();
451
452 }
453
454 /* Set up lighting */
455 static void
456 init_sun (ModeInfo * mi)
457 {
458   GLfloat light[4];
459   light[0] = frand(2.0) - 1.0;
460   light[1] = frand(2.0) - 1.0;
461   light[2] = 1.0;
462   light[3] = 0;
463
464   glLightfv(GL_LIGHT0, GL_POSITION, light);
465 }
466
467
468 /* Initialization function for screen saver */
469 static void
470 pinit(ModeInfo * mi)
471 {
472   Bool wire = MI_IS_WIREFRAME(mi);
473   planetstruct *gp = &planets[MI_SCREEN(mi)];
474
475   if (wire) {
476         glEnable(GL_LINE_SMOOTH);
477         do_texture = False;
478   }
479
480   /* turn on various options we like */
481   if (do_texture)
482         setup_texture(mi);
483   if (do_light)
484         setup_light();
485
486   setup_face();
487
488   if (do_stars) {
489         glEnable(GL_POINT_SMOOTH);
490         generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
491   }
492
493   gp->platelist=glGenLists(1);
494   glNewList(gp->platelist, GL_COMPILE);
495   glPushMatrix ();
496   glScalef (RADIUS, RADIUS, RADIUS);
497   unit_sphere (STACKS, SLICES, wire);
498   glPopMatrix ();
499   glEndList();
500
501   init_sun (mi);
502 }
503
504 static void
505 draw_sphere(ModeInfo * mi)
506 {
507   planetstruct *gp = &planets[MI_SCREEN(mi)];
508
509   glEnable(GL_DEPTH_TEST);
510
511   /* turn on the various attributes for making the sphere look nice */
512   if (do_texture)
513         glEnable(GL_TEXTURE_2D);
514
515   if (do_light)
516         {
517           glEnable(GL_LIGHTING);
518           glEnable(GL_LIGHT0);
519           glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
520           glEnable(GL_COLOR_MATERIAL);
521         }
522
523   glCallList(gp->platelist);
524
525 }
526
527
528 #define RANDSIGN() ((random() & 1) ? 1 : -1)
529
530 static void
531 pick_velocity (ModeInfo * mi)
532 {
533   planetstruct *gp = &planets[MI_SCREEN(mi)];
534
535   gp->box_width =  15.0;
536   gp->box_height = 15.0;
537   gp->box_depth =  5.0;
538
539   gp->tx = 0.0;
540   gp->ty = 0.0;
541   gp->tz = frand(360);
542
543   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
544   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
545   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
546
547   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
548   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
549   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
550 }
551
552
553 static void
554 rotate_and_move (ModeInfo * mi)
555 {
556   planetstruct *gp = &planets[MI_SCREEN(mi)];
557
558   if (do_roll)
559         {
560           gp->tx += gp->dtx;
561           while (gp->tx < 0)   gp->tx += 360;
562           while (gp->tx > 360) gp->tx -= 360;
563
564           gp->ty += gp->dty;
565           while (gp->ty < 0)   gp->ty += 360;
566           while (gp->ty > 360) gp->ty -= 360;
567         }
568
569   if (do_rotate)
570         {
571           gp->tz += gp->dtz;
572           while (gp->tz < 0)   gp->tz += 360;
573           while (gp->tz > 360) gp->tz -= 360;
574         }
575
576   if (do_bounce)
577         {
578       static int frame = 0;
579 #     define SINOID(SCALE,SIZE) \
580         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
581       gp->xpos = SINOID(0.031, gp->box_width);
582       gp->ypos = SINOID(0.023, gp->box_height);
583       gp->zpos = SINOID(0.017, gp->box_depth);
584       frame++;
585         }
586 }
587
588
589 /* Standard reshape function */
590 void
591 reshape_planet(ModeInfo *mi, int width, int height)
592 {
593   GLfloat h = (GLfloat) height / (GLfloat) width;
594
595   glViewport(0, 0, (GLint) width, (GLint) height);
596   glMatrixMode(GL_PROJECTION);
597   glLoadIdentity();
598   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
599   glMatrixMode(GL_MODELVIEW);
600   glLoadIdentity();
601   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
602   glTranslatef(0.0, 0.0, -DIST);
603 }
604
605
606 void
607 init_planet(ModeInfo * mi)
608 {
609   int         screen = MI_SCREEN(mi);
610
611   planetstruct *gp;
612
613   if (planets == NULL) {
614         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
615                                                                                   sizeof (planetstruct))) == NULL)
616           return;
617   }
618   gp = &planets[screen];
619
620   pick_velocity (mi);
621
622   {
623         char *f = get_string_resource("imageForeground", "Foreground");
624         char *b = get_string_resource("imageBackground", "Background");
625         char *s;
626         if (!f) f = strdup("white");
627         if (!b) b = strdup("black");
628         
629         for (s = f + strlen(f)-1; s > f; s--)
630           if (*s == ' ' || *s == '\t')
631                 *s = 0;
632         for (s = b + strlen(b)-1; s > b; s--)
633           if (*s == ' ' || *s == '\t')
634                 *s = 0;
635
636     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
637       {
638                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
639                 exit(1);
640       }
641     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
642       {
643                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
644                 exit(1);
645       }
646
647         free (f);
648         free (b);
649   }
650
651
652   gp->window = MI_WINDOW(mi);
653   if ((gp->glx_context = init_GL(mi)) != NULL) {
654         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
655         pinit(mi);
656   } else {
657         MI_CLEARWINDOW(mi);
658   }
659 }
660
661 void
662 draw_planet(ModeInfo * mi)
663 {
664   planetstruct *gp = &planets[MI_SCREEN(mi)];
665   Display    *display = MI_DISPLAY(mi);
666   Window      window = MI_WINDOW(mi);
667
668   if (!gp->glx_context)
669         return;
670
671   glDrawBuffer(GL_BACK);
672   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
673
674   glXMakeCurrent(display, window, *(gp->glx_context));
675
676
677   if (do_stars) {
678         /* protect our modelview matrix and attributes */
679         glPushMatrix();
680     glCallList(gp->starlist);
681         glPopMatrix();
682   }
683
684   /* protect our modelview matrix and attributes */
685   glPushMatrix();
686   glPushAttrib(GL_ALL_ATTRIB_BITS);
687   {
688         /* this pair of rotations seem to be necessary to orient the earth correctly */
689         glRotatef(90,0,0,1);
690         glRotatef(90,0,1,0);
691
692         glTranslatef(gp->xpos, gp->ypos, gp->zpos);
693         glRotatef(gp->tx, 1, 0, 0);
694         glRotatef(gp->ty, 0, 1, 0);
695         glRotatef(gp->tz, 0, 0, 1);
696         /* draw the sphere */
697         draw_sphere(mi);
698   }
699   glPopMatrix();
700   glPopAttrib();
701
702
703
704   if (mi->fps_p) do_fps (mi);
705   glFinish();
706   glXSwapBuffers(display, window);
707
708   rotate_and_move (mi);
709 }
710
711 void
712 release_planet(ModeInfo * mi)
713 {
714   if (planets != NULL) {
715         int         screen;
716
717         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
718           planetstruct *gp = &planets[screen];
719
720           if (gp->glx_context) {
721                 /* Display lists MUST be freed while their glXContext is current. */
722                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
723
724                 if (glIsList(gp->platelist))
725                   glDeleteLists(gp->platelist, 1);
726                 if (glIsList(gp->starlist))
727                   glDeleteLists(gp->starlist, 1);
728           }
729         }
730         (void) free((void *) planets);
731         planets = NULL;
732   }
733   FreeAllGL(mi);
734 }
735
736
737 #endif
738