http://packetstorm.tacticalflex.com/UNIX/admin/xscreensaver-3.27.tar.gz
[xscreensaver] / hacks / glx / glplanet.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* glplanet --- 3D rotating planet, e.g., Earth. */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)plate.c       4.07 97/11/24 xlockmore";
6
7 #endif
8
9 /*-
10  * Permission to use, copy, modify, and distribute this software and its
11  * documentation for any purpose and without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and that
13  * both that copyright notice and this permission notice appear in
14  * supporting documentation.
15  *
16  * This file is provided AS IS with no warranties of any kind.  The author
17  * shall have no liability with respect to the infringement of copyrights,
18  * trade secrets or any patents by this file or any part thereof.  In no
19  * event will the author be liable for any lost revenue or profits or
20  * other special, indirect and consequential damages.
21  *
22  * Revision History:
23  * 9-Oct-98:  dek@cgl.ucsf.edu  Added stars.
24  *
25  * 8-Oct-98:  jwz@jwz.org   Made the 512x512x1 xearth image be built in.
26  *                          Made it possible to load XPM or XBM files.
27  *                          Made the planet bounce and roll around.
28  *
29  * 8-Oct-98: Released initial version of "glplanet"
30  * (David Konerding, dek@cgl.ucsf.edu)
31  *
32  * BUGS:
33  * -bounce is broken
34  * 
35  *   For even more spectacular results, grab the images from the "SSysten"
36  *   package (http://www.msu.edu/user/kamelkev/) and do this:
37  *
38  *     cd ssystem-1.4/hires/
39  *     foreach f ( *.jpg )
40  *       djpeg $f | ppmquant 254 | ppmtoxpm > /tmp/$f:r.xpm
41  *     end
42  *
43  *     cd /tmp
44  *     foreach f ( *.xpm )
45  *       glplanet -image $f
46  *     end
47  */
48
49
50 /*-
51  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
52  * otherwise caddr_t is not defined correctly
53  */
54
55 #include <X11/Intrinsic.h>
56
57 #ifdef STANDALONE
58 # define PROGCLASS                                              "Planet"
59 # define HACK_INIT                                              init_planet
60 # define HACK_DRAW                                              draw_planet
61 # define planet_opts                                    xlockmore_opts
62 #define DEFAULTS        "*delay:                        15000   \n"     \
63                     "*rotate:           True    \n" \
64                     "*roll:             True    \n" \
65                     "*bounce:           True    \n" \
66                                         "*wireframe:            False   \n"     \
67                                         "*light:                        True    \n"     \
68                                         "*texture:                      True    \n" \
69                                         "*stars:                        True    \n" \
70                                         "*image:                        BUILTIN \n" \
71                                         "*imageForeground:      Green   \n" \
72                                         "*imageBackground:      Blue    \n"
73
74 # include "xlockmore.h"                         /* from the xscreensaver distribution */
75 #else  /* !STANDALONE */
76 # include "xlock.h"                                     /* from the xlockmore distribution */
77 #endif /* !STANDALONE */
78
79 #ifdef USE_GL /* whole file */
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 15
165 #define STACKS 15
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 /* Function for determining points on the surface of the sphere */
380 static void inline ParametricSphere(float theta, float rho, GLfloat *vector)
381 {
382   vector[0] = -sin(theta) * sin(rho);
383   vector[1] = cos(theta) * sin(rho);
384   vector[2] = cos(rho);
385
386 #if DO_HELIX
387   vector[0] = -(1- cos(theta)) * cos(rho); 
388   vector[1] = -(1- cos(theta)) * sin(rho); 
389   vector[2] = -(sin(theta) + rho); 
390 #endif /* DO_HELIX */
391
392         return;
393 }
394
395
396 /* lame way to generate some random stars */
397 void generate_stars(int width, int height)
398 {
399   int i;
400 /*  GLfloat size_range[2], size;*/
401   GLfloat x, y;
402
403   planetstruct *gp = &planets[MI_SCREEN(mi)];
404   
405 /*    glGetFloatv(GL_POINT_SIZE_RANGE, size_range); */
406   
407 /*    printf("size range: %f\t%f\n", size_range[0], size_range[1]); */
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_POINT_SMOOTH);
423   glEnable(GL_BLEND);
424   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
425   
426   glBegin(GL_POINTS);
427   for(i = 0 ; i < NUM_STARS ; i++)
428         {
429 /*        size = ((random()%size_range[0])) * size_range[1]/2.; */
430 /*    glPointSize(size); */
431           x = random() % width;
432           y = random() % height;
433           glVertex2f(x,y);
434         }
435   glEnd();
436
437   /* return to original PROJECT and MODELVIEW */
438   glMatrixMode(GL_PROJECTION);
439   glPopMatrix();
440   glMatrixMode(GL_MODELVIEW);
441
442
443   glEndList();
444
445 }
446
447 /* Initialization function for screen saver */
448 static void
449 pinit(ModeInfo * mi)
450 {
451   Bool wire = MI_IS_WIREFRAME(mi);
452   planetstruct *gp = &planets[MI_SCREEN(mi)];
453   int i, j;
454   int stacks=STACKS, slices=SLICES;
455   float radius=RADIUS;
456
457   float drho, dtheta;
458   float rho, theta;
459   GLfloat vector[3];
460   GLfloat ds, dt, t, s;;
461
462   if (wire) {
463         glEnable(GL_LINE_SMOOTH);
464         do_texture = False;
465   }
466
467   /* turn on various options we like */
468   if (do_texture)
469         setup_texture(mi);
470   if (do_light)
471         setup_light();
472
473   setup_face();
474
475   if (do_stars) {
476         glEnable(GL_POINT_SMOOTH);
477         generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
478   }
479
480
481   /*-
482    * Generate a sphere with quadrilaterals.
483    * Quad vertices are determined using a parametric sphere function.
484    * For fun, you could generate practically any parameteric surface and
485    * map an image onto it. 
486    */
487
488   drho = M_PI / stacks;
489   dtheta = 2.0 * M_PI / slices;
490   ds = 1.0 / slices;
491   dt = 1.0 / stacks;
492   
493
494   gp->platelist=glGenLists(1);
495   glNewList(gp->platelist, GL_COMPILE);
496
497   glColor3f(1,1,1);
498   glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
499
500   t = 0.0;
501   for(i=0; i<stacks; i++) {
502         rho = i * drho;
503         s = 0.0;
504         for(j=0; j<slices; j++) {
505           theta = j * dtheta;
506
507
508           glTexCoord2f(s,t);
509           ParametricSphere(theta, rho, vector);
510           normalize(vector);
511           glNormal3fv(vector);
512           ParametricSphere(theta, rho, vector);
513           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
514
515           glTexCoord2f(s,t+dt);
516           ParametricSphere(theta, rho+drho, vector);
517           normalize(vector);
518           glNormal3fv(vector);
519           ParametricSphere(theta, rho+drho, vector);
520           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
521
522           glTexCoord2f(s+ds,t+dt);
523           ParametricSphere(theta + dtheta, rho+drho, vector);
524           normalize(vector);
525           glNormal3fv(vector);
526           ParametricSphere(theta + dtheta, rho+drho, vector);
527           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
528
529           glTexCoord2f(s+ds, t);
530           ParametricSphere(theta + dtheta, rho, vector);
531           normalize(vector);
532           glNormal3fv(vector);
533           ParametricSphere(theta + dtheta, rho, vector);
534           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
535
536           s = s + ds;
537
538         }
539         t = t + dt;
540   }
541   glEnd();
542   glEndList();
543
544
545  }
546
547 static void
548 draw_sphere(ModeInfo * mi)
549 {
550   planetstruct *gp = &planets[MI_SCREEN(mi)];
551
552   glEnable(GL_DEPTH_TEST);
553
554   /* turn on the various attributes for making the sphere look nice */
555   if (do_texture)
556         glEnable(GL_TEXTURE_2D);
557
558   if (do_light)
559         {
560           glEnable(GL_LIGHTING);
561           glEnable(GL_LIGHT0);
562           glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
563           glEnable(GL_COLOR_MATERIAL);
564         }
565
566   glCallList(gp->platelist);
567
568 }
569
570
571 #define RANDSIGN() ((random() & 1) ? 1 : -1)
572
573 static void
574 pick_velocity (ModeInfo * mi)
575 {
576   planetstruct *gp = &planets[MI_SCREEN(mi)];
577
578   gp->box_width =  15.0;
579   gp->box_height = 15.0;
580   gp->box_depth =  5.0;
581
582   gp->tx = 0.0;
583   gp->ty = 0.0;
584   gp->tz = frand(360);
585
586   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
587   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
588   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
589
590   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
591   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
592   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
593 }
594
595
596 static void
597 rotate_and_move (ModeInfo * mi)
598 {
599   planetstruct *gp = &planets[MI_SCREEN(mi)];
600
601   if (do_roll)
602         {
603           gp->tx += gp->dtx;
604           while (gp->tx < 0)   gp->tx += 360;
605           while (gp->tx > 360) gp->tx -= 360;
606
607           gp->ty += gp->dty;
608           while (gp->ty < 0)   gp->ty += 360;
609           while (gp->ty > 360) gp->ty -= 360;
610         }
611
612   if (do_rotate)
613         {
614           gp->tz += gp->dtz;
615           while (gp->tz < 0)   gp->tz += 360;
616           while (gp->tz > 360) gp->tz -= 360;
617         }
618
619   if (do_bounce)
620         {
621           /* Move in the direction we had been moving in. */
622           gp->xpos += gp->dx;
623           gp->ypos += gp->dy;
624           gp->zpos += gp->dz;
625
626           /* Bounce. */
627           if (gp->xpos > gp->box_depth)
628                 gp->xpos = gp->box_depth, gp->dx = -gp->dx;
629           else if (gp->xpos < 0)
630                 gp->xpos = 0, gp->dx = -gp->dx;
631
632           if (gp->ypos > gp->box_width/2)
633                 gp->ypos = gp->box_width/2, gp->dy = -gp->dy;
634           else if (gp->ypos < -gp->box_width/2)
635                 gp->ypos = -gp->box_width/2, gp->dy = -gp->dy;
636
637           if (gp->zpos > gp->box_height/2)
638                 gp->zpos = gp->box_height/2, gp->dz = -gp->dz;
639           else if (gp->zpos < -gp->box_height/2)
640                 gp->zpos = -gp->box_height/2, gp->dz = -gp->dz;
641         }
642 }
643
644
645 /* Standard reshape function */
646 static void
647 reshape(int width, int height)
648 {
649   GLfloat light[4];
650   GLfloat h = (GLfloat) height / (GLfloat) width;
651
652   light[0] = -1;
653   light[1] = (int) (((random() % 3) & 0xFF) - 1);
654   light[2] = (int) (((random() % 3) & 0xFF) - 1);
655   light[3] = 0;
656
657   glViewport(0, 0, (GLint) width, (GLint) height);
658   glMatrixMode(GL_PROJECTION);
659   glLoadIdentity();
660   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
661   glMatrixMode(GL_MODELVIEW);
662   glLoadIdentity();
663   glTranslatef(0.0, 0.0, -DIST);
664   glLightfv(GL_LIGHT0, GL_POSITION, light);
665   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
666
667 }
668
669
670 void
671 init_planet(ModeInfo * mi)
672 {
673   int         screen = MI_SCREEN(mi);
674
675   planetstruct *gp;
676
677   if (planets == NULL) {
678         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
679                                                                                   sizeof (planetstruct))) == NULL)
680           return;
681   }
682   gp = &planets[screen];
683
684   pick_velocity (mi);
685
686   {
687         char *f = get_string_resource("imageForeground", "Foreground");
688         char *b = get_string_resource("imageBackground", "Background");
689         char *s;
690         if (!f) f = strdup("white");
691         if (!b) b = strdup("black");
692         
693         for (s = f + strlen(f)-1; s > f; s--)
694           if (*s == ' ' || *s == '\t')
695                 *s = 0;
696         for (s = b + strlen(b)-1; s > b; s--)
697           if (*s == ' ' || *s == '\t')
698                 *s = 0;
699
700     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
701       {
702                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
703                 exit(1);
704       }
705     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
706       {
707                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
708                 exit(1);
709       }
710
711         free (f);
712         free (b);
713   }
714
715
716   gp->window = MI_WINDOW(mi);
717   if ((gp->glx_context = init_GL(mi)) != NULL) {
718         reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
719         pinit(mi);
720   } else {
721         MI_CLEARWINDOW(mi);
722   }
723 }
724
725 void
726 draw_planet(ModeInfo * mi)
727 {
728   planetstruct *gp = &planets[MI_SCREEN(mi)];
729   Display    *display = MI_DISPLAY(mi);
730   Window      window = MI_WINDOW(mi);
731
732   if (!gp->glx_context)
733         return;
734
735   glDrawBuffer(GL_BACK);
736   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
737
738   glXMakeCurrent(display, window, *(gp->glx_context));
739
740
741   if (do_stars) {
742         /* protect our modelview matrix and attributes */
743         glPushMatrix();
744         glPushAttrib(GL_ALL_ATTRIB_BITS);
745         {
746           glColor3f(1,1,1);
747           /* draw the star field. */
748           glCallList(gp->starlist);
749
750         }
751         glPopMatrix();
752         glPopAttrib();
753   }
754
755   /* protect our modelview matrix and attributes */
756   glPushMatrix();
757   glPushAttrib(GL_ALL_ATTRIB_BITS);
758   {
759         /* this pair of rotations seem to be necessary to orient the earth correctly */
760         glRotatef(90,0,0,1);
761         glRotatef(90,0,1,0);
762
763         glTranslatef(gp->xpos, gp->ypos, gp->zpos);
764         glRotatef(gp->tx, 1, 0, 0);
765         glRotatef(gp->ty, 0, 1, 0);
766         glRotatef(gp->tz, 0, 0, 1);
767         /* draw the sphere */
768         draw_sphere(mi);
769   }
770   glPopMatrix();
771   glPopAttrib();
772
773
774
775   glFinish();
776   glXSwapBuffers(display, window);
777
778   rotate_and_move (mi);
779 }
780
781 void
782 release_planet(ModeInfo * mi)
783 {
784   if (planets != NULL) {
785         int         screen;
786
787         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
788           planetstruct *gp = &planets[screen];
789
790           if (gp->glx_context) {
791                 /* Display lists MUST be freed while their glXContext is current. */
792                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
793
794                 if (glIsList(gp->platelist))
795                   glDeleteLists(gp->platelist, 1);
796                 if (glIsList(gp->starlist))
797                   glDeleteLists(gp->starlist, 1);
798           }
799         }
800         (void) free((void *) planets);
801         planets = NULL;
802   }
803   FreeAllGL(mi);
804 }
805
806
807 #endif
808