d5d3de48adc166254e19b81f5d933149f9c96e7a
[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;
402 /*  GLfloat size_range[2], size;*/
403   GLfloat x, y;
404
405   planetstruct *gp = &planets[MI_SCREEN(mi)];
406   
407 /*    glGetFloatv(GL_POINT_SIZE_RANGE, size_range); */
408   
409 /*    printf("size range: %f\t%f\n", size_range[0], size_range[1]); */
410   gp->starlist = glGenLists(1);
411   glNewList(gp->starlist, GL_COMPILE);
412
413   /* this hackery makes the viewport map one-to-one with Vertex arguments */
414   glMatrixMode(GL_PROJECTION);
415   glPushMatrix();
416   glMatrixMode(GL_PROJECTION);
417   glLoadIdentity();
418   gluOrtho2D(0, width, 0, height);
419   glMatrixMode(GL_MODELVIEW);
420   glLoadIdentity();
421
422   /* disable depth testing for the stars, so they don't obscure the planet */
423   glDisable(GL_DEPTH_TEST);
424   glEnable(GL_POINT_SMOOTH);
425   glEnable(GL_BLEND);
426   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
427   
428   glBegin(GL_POINTS);
429   for(i = 0 ; i < NUM_STARS ; i++)
430         {
431 /*        size = ((random()%size_range[0])) * size_range[1]/2.; */
432 /*    glPointSize(size); */
433           x = random() % width;
434           y = random() % height;
435           glVertex2f(x,y);
436         }
437   glEnd();
438
439   /* return to original PROJECT and MODELVIEW */
440   glMatrixMode(GL_PROJECTION);
441   glPopMatrix();
442   glMatrixMode(GL_MODELVIEW);
443
444
445   glEndList();
446
447 }
448
449 /* Initialization function for screen saver */
450 static void
451 pinit(ModeInfo * mi)
452 {
453   Bool wire = MI_IS_WIREFRAME(mi);
454   planetstruct *gp = &planets[MI_SCREEN(mi)];
455
456   if (wire) {
457         glEnable(GL_LINE_SMOOTH);
458         do_texture = False;
459   }
460
461   /* turn on various options we like */
462   if (do_texture)
463         setup_texture(mi);
464   if (do_light)
465         setup_light();
466
467   setup_face();
468
469   if (do_stars) {
470         glEnable(GL_POINT_SMOOTH);
471         generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
472   }
473
474   gp->platelist=glGenLists(1);
475   glNewList(gp->platelist, GL_COMPILE);
476   glPushMatrix ();
477   glScalef (RADIUS, RADIUS, RADIUS);
478   unit_sphere (STACKS, SLICES, wire);
479   glPopMatrix ();
480   glEndList();
481  }
482
483 static void
484 draw_sphere(ModeInfo * mi)
485 {
486   planetstruct *gp = &planets[MI_SCREEN(mi)];
487
488   glEnable(GL_DEPTH_TEST);
489
490   /* turn on the various attributes for making the sphere look nice */
491   if (do_texture)
492         glEnable(GL_TEXTURE_2D);
493
494   if (do_light)
495         {
496           glEnable(GL_LIGHTING);
497           glEnable(GL_LIGHT0);
498           glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
499           glEnable(GL_COLOR_MATERIAL);
500         }
501
502   glCallList(gp->platelist);
503
504 }
505
506
507 #define RANDSIGN() ((random() & 1) ? 1 : -1)
508
509 static void
510 pick_velocity (ModeInfo * mi)
511 {
512   planetstruct *gp = &planets[MI_SCREEN(mi)];
513
514   gp->box_width =  15.0;
515   gp->box_height = 15.0;
516   gp->box_depth =  5.0;
517
518   gp->tx = 0.0;
519   gp->ty = 0.0;
520   gp->tz = frand(360);
521
522   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
523   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
524   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
525
526   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
527   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
528   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
529 }
530
531
532 static void
533 rotate_and_move (ModeInfo * mi)
534 {
535   planetstruct *gp = &planets[MI_SCREEN(mi)];
536
537   if (do_roll)
538         {
539           gp->tx += gp->dtx;
540           while (gp->tx < 0)   gp->tx += 360;
541           while (gp->tx > 360) gp->tx -= 360;
542
543           gp->ty += gp->dty;
544           while (gp->ty < 0)   gp->ty += 360;
545           while (gp->ty > 360) gp->ty -= 360;
546         }
547
548   if (do_rotate)
549         {
550           gp->tz += gp->dtz;
551           while (gp->tz < 0)   gp->tz += 360;
552           while (gp->tz > 360) gp->tz -= 360;
553         }
554
555   if (do_bounce)
556         {
557       static int frame = 0;
558 #     define SINOID(SCALE,SIZE) \
559         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
560       gp->xpos = SINOID(0.031, gp->box_width);
561       gp->ypos = SINOID(0.023, gp->box_height);
562       gp->zpos = SINOID(0.017, gp->box_depth);
563       frame++;
564         }
565 }
566
567
568 /* Standard reshape function */
569 void
570 reshape_planet(ModeInfo *mi, int width, int height)
571 {
572   GLfloat light[4];
573   GLfloat h = (GLfloat) height / (GLfloat) width;
574
575   light[0] = -1;
576   light[1] = (int) (((random() % 3) & 0xFF) - 1);
577   light[2] = (int) (((random() % 3) & 0xFF) - 1);
578   light[3] = 0;
579
580   glViewport(0, 0, (GLint) width, (GLint) height);
581   glMatrixMode(GL_PROJECTION);
582   glLoadIdentity();
583   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
584   glMatrixMode(GL_MODELVIEW);
585   glLoadIdentity();
586   glTranslatef(0.0, 0.0, -DIST);
587   glLightfv(GL_LIGHT0, GL_POSITION, light);
588   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
589
590 }
591
592
593 void
594 init_planet(ModeInfo * mi)
595 {
596   int         screen = MI_SCREEN(mi);
597
598   planetstruct *gp;
599
600   if (planets == NULL) {
601         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
602                                                                                   sizeof (planetstruct))) == NULL)
603           return;
604   }
605   gp = &planets[screen];
606
607   pick_velocity (mi);
608
609   {
610         char *f = get_string_resource("imageForeground", "Foreground");
611         char *b = get_string_resource("imageBackground", "Background");
612         char *s;
613         if (!f) f = strdup("white");
614         if (!b) b = strdup("black");
615         
616         for (s = f + strlen(f)-1; s > f; s--)
617           if (*s == ' ' || *s == '\t')
618                 *s = 0;
619         for (s = b + strlen(b)-1; s > b; s--)
620           if (*s == ' ' || *s == '\t')
621                 *s = 0;
622
623     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
624       {
625                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
626                 exit(1);
627       }
628     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
629       {
630                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
631                 exit(1);
632       }
633
634         free (f);
635         free (b);
636   }
637
638
639   gp->window = MI_WINDOW(mi);
640   if ((gp->glx_context = init_GL(mi)) != NULL) {
641         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
642         pinit(mi);
643   } else {
644         MI_CLEARWINDOW(mi);
645   }
646 }
647
648 void
649 draw_planet(ModeInfo * mi)
650 {
651   planetstruct *gp = &planets[MI_SCREEN(mi)];
652   Display    *display = MI_DISPLAY(mi);
653   Window      window = MI_WINDOW(mi);
654
655   if (!gp->glx_context)
656         return;
657
658   glDrawBuffer(GL_BACK);
659   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
660
661   glXMakeCurrent(display, window, *(gp->glx_context));
662
663
664   if (do_stars) {
665         /* protect our modelview matrix and attributes */
666         glPushMatrix();
667         glPushAttrib(GL_ALL_ATTRIB_BITS);
668         {
669           glColor3f(1,1,1);
670           /* draw the star field. */
671           glCallList(gp->starlist);
672
673         }
674         glPopMatrix();
675         glPopAttrib();
676   }
677
678   /* protect our modelview matrix and attributes */
679   glPushMatrix();
680   glPushAttrib(GL_ALL_ATTRIB_BITS);
681   {
682         /* this pair of rotations seem to be necessary to orient the earth correctly */
683         glRotatef(90,0,0,1);
684         glRotatef(90,0,1,0);
685
686         glTranslatef(gp->xpos, gp->ypos, gp->zpos);
687         glRotatef(gp->tx, 1, 0, 0);
688         glRotatef(gp->ty, 0, 1, 0);
689         glRotatef(gp->tz, 0, 0, 1);
690         /* draw the sphere */
691         draw_sphere(mi);
692   }
693   glPopMatrix();
694   glPopAttrib();
695
696
697
698   if (mi->fps_p) do_fps (mi);
699   glFinish();
700   glXSwapBuffers(display, window);
701
702   rotate_and_move (mi);
703 }
704
705 void
706 release_planet(ModeInfo * mi)
707 {
708   if (planets != NULL) {
709         int         screen;
710
711         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
712           planetstruct *gp = &planets[screen];
713
714           if (gp->glx_context) {
715                 /* Display lists MUST be freed while their glXContext is current. */
716                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
717
718                 if (glIsList(gp->platelist))
719                   glDeleteLists(gp->platelist, 1);
720                 if (glIsList(gp->starlist))
721                   glDeleteLists(gp->starlist, 1);
722           }
723         }
724         (void) free((void *) planets);
725         planets = NULL;
726   }
727   FreeAllGL(mi);
728 }
729
730
731 #endif
732