d20bb409ca8eba6f251b3c4e5aa5f5a715ecb366
[xscreensaver] / 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   glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
241                            GL_RGB, GL_UNSIGNED_BYTE, data);
242
243   /* setup parameters for texturing */
244   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
245   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
246   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
247   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
248   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
249   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
250 }
251
252
253 static void
254 setup_file_texture (ModeInfo *mi, char *filename)
255 {
256   Display *dpy = mi->dpy;
257   Visual *visual = mi->xgwa.visual;
258   Colormap cmap = mi->xgwa.colormap;
259
260 #ifdef HAVE_XPM
261   {
262         char **xpm_data = 0;
263         int result = XpmReadFileToData (filename, &xpm_data);
264         switch (result) {
265         case XpmSuccess:
266           {
267                 XImage *image = xpm_to_ximage (dpy, visual, cmap, xpm_data);
268
269                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
270                                          image->width, image->height, 0,
271                                          GL_RGBA, GL_UNSIGNED_BYTE, image->data);
272
273                 /* setup parameters for texturing */
274                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
275                 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
276
277                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
278                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
279                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
280                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
281                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
282                 return;
283           }
284           break;
285
286         case XpmOpenFailed:
287           fprintf (stderr, "%s: file %s doesn't exist.\n", progname, filename);
288           exit (-1);
289           break;
290
291         case XpmFileInvalid:
292           /* Fall through and try it as an XBM. */
293           break;
294
295         case XpmNoMemory:
296           fprintf (stderr, "%s: XPM: out of memory\n", progname);
297           exit (-1);
298           break;
299
300         default:
301           fprintf (stderr, "%s: XPM: unknown error code %d\n", progname, result);
302           exit (-1);
303           break;
304         }
305   }
306 #endif /* HAVE_XPM */
307
308 #ifdef HAVE_XMU
309   {
310         planetstruct *gp = &planets[MI_SCREEN(mi)];
311         unsigned int width = 0;
312         unsigned int height = 0;
313         unsigned char *data = 0;
314         int xhot, yhot;
315         int status = XmuReadBitmapDataFromFile (filename, &width, &height, &data,
316                                                                                         &xhot, &yhot);
317         if (status != Success)
318           {
319 # ifdef HAVE_XPM
320                 fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
321 # endif
322                 fprintf (stderr, "%s: not an XBM file: %s\n", progname, filename);
323                 exit (1);
324           }
325
326         setup_xbm_texture ((char *) data, width, height, &gp->fg, &gp->bg);
327   }
328 #else  /* !XMU */
329
330 # ifdef HAVE_XPM
331   fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
332 # endif
333   fprintf (stderr, "%s: your vendor doesn't ship the standard Xmu library.\n",
334                    progname);
335   fprintf (stderr, "%s: we can't load XBM files without it.\n",progname);
336   exit (1);
337 #endif /* !XMU */
338 }
339
340
341 static void
342 setup_texture(ModeInfo * mi)
343 {
344   planetstruct *gp = &planets[MI_SCREEN(mi)];
345   if (!which_image ||
346           !*which_image ||
347           !strcmp(which_image, "BUILTIN"))
348         setup_xbm_texture (earth_bits, earth_width, earth_height,
349                                            &gp->fg, &gp->bg);
350   else
351         setup_file_texture (mi, which_image);
352 }
353
354
355 /* Set up and enable lighting */
356 static void
357 setup_light(void)
358 {
359   /* set a number of parameters which make the scene look much nicer */
360   glEnable(GL_BLEND);
361   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
362   glShadeModel(GL_SMOOTH);
363 }
364
365
366 /* Set up and enable face culling so we don't see the inside of the sphere */
367 static void
368 setup_face(void)
369 {
370   glEnable(GL_CULL_FACE);
371   glCullFace(GL_BACK); 
372 }
373
374
375 /* Function for determining points on the surface of the sphere */
376 static void inline ParametricSphere(float theta, float rho, GLfloat *vector)
377 {
378   vector[0] = -sin(theta) * sin(rho);
379   vector[1] = cos(theta) * sin(rho);
380   vector[2] = cos(rho);
381
382 #if DO_HELIX
383   vector[0] = -(1- cos(theta)) * cos(rho); 
384   vector[1] = -(1- cos(theta)) * sin(rho); 
385   vector[2] = -(sin(theta) + rho); 
386 #endif /* DO_HELIX */
387
388         return;
389 }
390
391
392 /* lame way to generate some random stars */
393 void generate_stars(int width, int height)
394 {
395   int i;
396 /*  GLfloat size_range[2], size;*/
397   GLfloat x, y;
398
399   planetstruct *gp = &planets[MI_SCREEN(mi)];
400   
401 /*    glGetFloatv(GL_POINT_SIZE_RANGE, size_range); */
402   
403 /*    printf("size range: %f\t%f\n", size_range[0], size_range[1]); */
404   gp->starlist = glGenLists(1);
405   glNewList(gp->starlist, GL_COMPILE);
406
407   /* this hackery makes the viewport map one-to-one with Vertex arguments */
408   glMatrixMode(GL_PROJECTION);
409   glPushMatrix();
410   glMatrixMode(GL_PROJECTION);
411   glLoadIdentity();
412   gluOrtho2D(0, width, 0, height);
413   glMatrixMode(GL_MODELVIEW);
414   glLoadIdentity();
415
416   /* disable depth testing for the stars, so they don't obscure the planet */
417   glDisable(GL_DEPTH_TEST);
418   glEnable(GL_POINT_SMOOTH);
419   glEnable(GL_BLEND);
420   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
421   
422   glBegin(GL_POINTS);
423   for(i = 0 ; i < NUM_STARS ; i++)
424         {
425 /*        size = (drand48()+size_range[0]) * size_range[1]/2.; */
426 /*    glPointSize(size); */
427           x = random()*width;
428           y = random()*height;
429           glVertex2f(x,y);
430         }
431   glEnd();
432
433   /* return to original PROJECT and MODELVIEW */
434   glMatrixMode(GL_PROJECTION);
435   glPopMatrix();
436   glMatrixMode(GL_MODELVIEW);
437
438
439   glEndList();
440
441 }
442
443 /* Initialization function for screen saver */
444 static void
445 pinit(ModeInfo * mi)
446 {
447   Bool wire = MI_IS_WIREFRAME(mi);
448   planetstruct *gp = &planets[MI_SCREEN(mi)];
449   int i, j;
450   int stacks=STACKS, slices=SLICES;
451   float radius=RADIUS;
452
453   float drho, dtheta;
454   float rho, theta;
455   GLfloat vector[3];
456   GLfloat ds, dt, t, s;;
457
458   if (wire) {
459         glEnable(GL_LINE_SMOOTH);
460         do_texture = False;
461   }
462
463   /* turn on various options we like */
464   if (do_texture)
465         setup_texture(mi);
466   if (do_light)
467         setup_light();
468
469   setup_face();
470
471   if (do_stars) {
472         glEnable(GL_POINT_SMOOTH);
473         generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
474   }
475
476
477   /*-
478    * Generate a sphere with quadrilaterals.
479    * Quad vertices are determined using a parametric sphere function.
480    * For fun, you could generate practically any parameteric surface and
481    * map an image onto it. 
482    */
483
484   drho = M_PI / stacks;
485   dtheta = 2.0 * M_PI / slices;
486   ds = 1.0 / slices;
487   dt = 1.0 / stacks;
488   
489
490   gp->platelist=glGenLists(1);
491   glNewList(gp->platelist, GL_COMPILE);
492
493   glColor3f(1,1,1);
494   glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
495
496   t = 0.0;
497   for(i=0; i<stacks; i++) {
498         rho = i * drho;
499         s = 0.0;
500         for(j=0; j<slices; j++) {
501           theta = j * dtheta;
502
503
504           glTexCoord2f(s,t);
505           ParametricSphere(theta, rho, vector);
506           normalize(vector);
507           glNormal3fv(vector);
508           ParametricSphere(theta, rho, vector);
509           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
510
511           glTexCoord2f(s,t+dt);
512           ParametricSphere(theta, rho+drho, vector);
513           normalize(vector);
514           glNormal3fv(vector);
515           ParametricSphere(theta, rho+drho, vector);
516           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
517
518           glTexCoord2f(s+ds,t+dt);
519           ParametricSphere(theta + dtheta, rho+drho, vector);
520           normalize(vector);
521           glNormal3fv(vector);
522           ParametricSphere(theta + dtheta, rho+drho, vector);
523           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
524
525           glTexCoord2f(s+ds, t);
526           ParametricSphere(theta + dtheta, rho, vector);
527           normalize(vector);
528           glNormal3fv(vector);
529           ParametricSphere(theta + dtheta, rho, vector);
530           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
531
532           s = s + ds;
533
534         }
535         t = t + dt;
536   }
537   glEnd();
538   glEndList();
539
540
541  }
542
543 static void
544 draw_sphere(ModeInfo * mi)
545 {
546   planetstruct *gp = &planets[MI_SCREEN(mi)];
547
548   glEnable(GL_DEPTH_TEST);
549
550   /* turn on the various attributes for making the sphere look nice */
551   if (do_texture)
552         glEnable(GL_TEXTURE_2D);
553
554   if (do_light)
555         {
556           glEnable(GL_LIGHTING);
557           glEnable(GL_LIGHT0);
558           glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
559           glEnable(GL_COLOR_MATERIAL);
560         }
561
562   glCallList(gp->platelist);
563
564 }
565
566
567 #define RANDSIGN() ((random() & 1) ? 1 : -1)
568
569 static void
570 pick_velocity (ModeInfo * mi)
571 {
572   planetstruct *gp = &planets[MI_SCREEN(mi)];
573
574   gp->box_width =  15.0;
575   gp->box_height = 15.0;
576   gp->box_depth =  5.0;
577
578   gp->tx = 0.0;
579   gp->ty = 0.0;
580   gp->tz = frand(360);
581
582   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
583   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
584   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
585
586   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
587   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
588   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
589 }
590
591
592 static void
593 rotate_and_move (ModeInfo * mi)
594 {
595   planetstruct *gp = &planets[MI_SCREEN(mi)];
596
597   if (do_roll)
598         {
599           gp->tx += gp->dtx;
600           while (gp->tx < 0)   gp->tx += 360;
601           while (gp->tx > 360) gp->tx -= 360;
602
603           gp->ty += gp->dty;
604           while (gp->ty < 0)   gp->ty += 360;
605           while (gp->ty > 360) gp->ty -= 360;
606         }
607
608   if (do_rotate)
609         {
610           gp->tz += gp->dtz;
611           while (gp->tz < 0)   gp->tz += 360;
612           while (gp->tz > 360) gp->tz -= 360;
613         }
614
615   if (do_bounce)
616         {
617           /* Move in the direction we had been moving in. */
618           gp->xpos += gp->dx;
619           gp->ypos += gp->dy;
620           gp->zpos += gp->dz;
621
622           /* Bounce. */
623           if (gp->xpos > gp->box_depth)
624                 gp->xpos = gp->box_depth, gp->dx = -gp->dx;
625           else if (gp->xpos < 0)
626                 gp->xpos = 0, gp->dx = -gp->dx;
627
628           if (gp->ypos > gp->box_width/2)
629                 gp->ypos = gp->box_width/2, gp->dy = -gp->dy;
630           else if (gp->ypos < -gp->box_width/2)
631                 gp->ypos = -gp->box_width/2, gp->dy = -gp->dy;
632
633           if (gp->zpos > gp->box_height/2)
634                 gp->zpos = gp->box_height/2, gp->dz = -gp->dz;
635           else if (gp->zpos < -gp->box_height/2)
636                 gp->zpos = -gp->box_height/2, gp->dz = -gp->dz;
637         }
638 }
639
640
641 /* Standard reshape function */
642 static void
643 reshape(int width, int height)
644 {
645   GLfloat light[4];
646   GLfloat h = (GLfloat) height / (GLfloat) width;
647
648   light[0] = -1;
649   light[1] = (int) (((random() % 3) & 0xFF) - 1);
650   light[2] = (int) (((random() % 3) & 0xFF) - 1);
651   light[3] = 0;
652
653   glViewport(0, 0, (GLint) width, (GLint) height);
654   glMatrixMode(GL_PROJECTION);
655   glLoadIdentity();
656   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
657   glMatrixMode(GL_MODELVIEW);
658   glLoadIdentity();
659   glTranslatef(0.0, 0.0, -DIST);
660   glLightfv(GL_LIGHT0, GL_POSITION, light);
661   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
662
663 }
664
665
666 void
667 init_planet(ModeInfo * mi)
668 {
669   int         screen = MI_SCREEN(mi);
670
671   planetstruct *gp;
672
673   if (planets == NULL) {
674         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
675                                                                                   sizeof (planetstruct))) == NULL)
676           return;
677   }
678   gp = &planets[screen];
679
680   pick_velocity (mi);
681
682   {
683         char *f = get_string_resource("imageForeground", "Foreground");
684         char *b = get_string_resource("imageBackground", "Background");
685         char *s;
686         if (!f) f = strdup("white");
687         if (!b) b = strdup("black");
688         
689         for (s = f + strlen(f)-1; s > f; s--)
690           if (*s == ' ' || *s == '\t')
691                 *s = 0;
692         for (s = b + strlen(b)-1; s > b; s--)
693           if (*s == ' ' || *s == '\t')
694                 *s = 0;
695
696     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
697       {
698                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
699                 exit(1);
700       }
701     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
702       {
703                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
704                 exit(1);
705       }
706
707         free (f);
708         free (b);
709   }
710
711
712   gp->window = MI_WINDOW(mi);
713   if ((gp->glx_context = init_GL(mi)) != NULL) {
714         reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
715         pinit(mi);
716   } else {
717         MI_CLEARWINDOW(mi);
718   }
719 }
720
721 void
722 draw_planet(ModeInfo * mi)
723 {
724   planetstruct *gp = &planets[MI_SCREEN(mi)];
725   Display    *display = MI_DISPLAY(mi);
726   Window      window = MI_WINDOW(mi);
727
728   if (!gp->glx_context)
729         return;
730
731   glDrawBuffer(GL_BACK);
732   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
733
734   glXMakeCurrent(display, window, *(gp->glx_context));
735
736
737   if (do_stars) {
738         /* protect our modelview matrix and attributes */
739         glPushMatrix();
740         glPushAttrib(GL_ALL_ATTRIB_BITS);
741         {
742           glColor3f(1,1,1);
743           /* draw the star field. */
744           glCallList(gp->starlist);
745
746         }
747         glPopMatrix();
748         glPopAttrib();
749   }
750
751   /* protect our modelview matrix and attributes */
752   glPushMatrix();
753   glPushAttrib(GL_ALL_ATTRIB_BITS);
754   {
755         /* this pair of rotations seem to be necessary to orient the earth correctly */
756         glRotatef(90,0,0,1);
757         glRotatef(90,0,1,0);
758
759         glTranslatef(gp->xpos, gp->ypos, gp->zpos);
760         glRotatef(gp->tx, 1, 0, 0);
761         glRotatef(gp->ty, 0, 1, 0);
762         glRotatef(gp->tz, 0, 0, 1);
763         /* draw the sphere */
764         draw_sphere(mi);
765   }
766   glPopMatrix();
767   glPopAttrib();
768
769
770
771   glFinish();
772   glXSwapBuffers(display, window);
773
774   rotate_and_move (mi);
775 }
776
777 void
778 release_planet(ModeInfo * mi)
779 {
780   if (planets != NULL) {
781         int         screen;
782
783         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
784           planetstruct *gp = &planets[screen];
785
786           if (gp->glx_context) {
787                 /* Display lists MUST be freed while their glXContext is current. */
788                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
789
790                 if (glIsList(gp->platelist))
791                   glDeleteLists(gp->platelist, 1);
792                 if (glIsList(gp->starlist))
793                   glDeleteLists(gp->starlist, 1);
794           }
795         }
796         (void) free((void *) planets);
797         planets = NULL;
798   }
799   FreeAllGL(mi);
800 }
801
802
803 #endif
804