http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.29.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 HACK_RESHAPE                                   reshape_planet
62 # define planet_opts                                    xlockmore_opts
63 #define DEFAULTS        "*delay:                        15000   \n"     \
64                                         "*showFPS:                      False   \n" \
65                     "*rotate:           True    \n" \
66                     "*roll:             True    \n" \
67                     "*bounce:           True    \n" \
68                                         "*wireframe:            False   \n"     \
69                                         "*light:                        True    \n"     \
70                                         "*texture:                      True    \n" \
71                                         "*stars:                        True    \n" \
72                                         "*image:                        BUILTIN \n" \
73                                         "*imageForeground:      Green   \n" \
74                                         "*imageBackground:      Blue    \n"
75
76 # include "xlockmore.h"                         /* from the xscreensaver distribution */
77 #else  /* !STANDALONE */
78 # include "xlock.h"                                     /* from the xlockmore distribution */
79 #endif /* !STANDALONE */
80
81 #ifdef USE_GL /* whole file */
82
83 #ifdef HAVE_XPM
84 # include <X11/xpm.h>
85 # ifndef PIXEL_ALREADY_TYPEDEFED
86 #  define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
87 # endif
88 #endif
89
90 #ifdef HAVE_XMU
91 # ifndef VMS
92 #  include <X11/Xmu/Drawing.h>
93 #else  /* VMS */
94 #  include <Xmu/Drawing.h>
95 # endif /* VMS */
96 #endif
97
98
99 #include <GL/glu.h>
100
101 #define DEF_ROTATE  "True"
102 #define DEF_ROLL    "True"
103 #define DEF_BOUNCE  "True"
104 #define DEF_TEXTURE "True"
105 #define DEF_STARS "True"
106 #define DEF_LIGHT   "True"
107 #define DEF_IMAGE   "BUILTIN"
108
109 #undef countof
110 #define countof(x) (sizeof((x))/sizeof((*x)))
111
112 static int do_rotate;
113 static int do_roll;
114 static int do_bounce;
115 static int do_texture;
116 static int do_stars;
117 static int do_light;
118 static char *which_image;
119 static XrmOptionDescRec opts[] = {
120   {"-rotate",  ".glplanet.rotate",  XrmoptionNoArg, (caddr_t) "true" },
121   {"+rotate",  ".glplanet.rotate",  XrmoptionNoArg, (caddr_t) "false" },
122   {"-roll",    ".glplanet.roll",    XrmoptionNoArg, (caddr_t) "true" },
123   {"+roll",    ".glplanet.roll",    XrmoptionNoArg, (caddr_t) "false" },
124   {"-bounce",  ".glplanet.bounce",  XrmoptionNoArg, (caddr_t) "true" },
125   {"+bounce",  ".glplanet.bounce",  XrmoptionNoArg, (caddr_t) "false" },
126   {"-texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "true" },
127   {"+texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "false" },
128   {"-stars",   ".glplanet.stars",   XrmoptionNoArg, (caddr_t) "true" },
129   {"+stars",   ".glplanet.stars",   XrmoptionNoArg, (caddr_t) "false" },
130   {"-light",   ".glplanet.light",   XrmoptionNoArg, (caddr_t) "true" },
131   {"+light",   ".glplanet.light",   XrmoptionNoArg, (caddr_t) "false" },
132   {"-image",   ".glplanet.image",  XrmoptionSepArg, (caddr_t) 0 },
133 };
134
135 static argtype vars[] = {
136   {(caddr_t *) &do_rotate,   "rotate",  "Rotate",  DEF_ROTATE,  t_Bool},
137   {(caddr_t *) &do_roll,     "roll",    "Roll",    DEF_ROLL,    t_Bool},
138   {(caddr_t *) &do_bounce,   "bounce",  "Bounce",  DEF_BOUNCE,  t_Bool},
139   {(caddr_t *) &do_texture,  "texture", "Texture", DEF_TEXTURE, t_Bool},
140   {(caddr_t *) &do_stars,  "stars", "Stars", DEF_STARS, t_Bool},
141   {(caddr_t *) &do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
142   {(caddr_t *) &which_image, "image",   "Image",   DEF_IMAGE,   t_String},
143 };
144
145 ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
146
147 #ifdef USE_MODULES
148 ModStruct   planet_description =
149 {"planet", "init_planet", "draw_planet", "release_planet",
150  "draw_planet", "init_planet", NULL, &planet_opts,
151  1000, 1, 2, 1, 4, 1.0, "",
152  "Animates texture mapped sphere (planet)", 0, NULL};
153 #endif
154
155 #include "../images/earth.xbm"
156 #include "xpm-ximage.h"
157
158
159 /*-
160  * slices and stacks are used in the sphere parameterization routine.
161  * more slices and stacks will increase the quality of the sphere,
162  * at the expense of rendering speed
163  */
164
165 #define NUM_STARS 1000
166 #define SLICES 32
167 #define STACKS 32
168
169 /* radius of the sphere- fairly arbitrary */
170 #define RADIUS 4
171
172 /* distance away from the sphere model */
173 #define DIST 40
174
175
176
177 /* structure for holding the planet data */
178 typedef struct {
179   GLuint platelist;
180   GLuint starlist;
181   int screen_width, screen_height;
182   GLXContext *glx_context;
183   Window window;
184
185   XColor fg, bg;
186
187   GLfloat tx, ty, tz;
188   GLfloat dtx, dty, dtz;
189   GLfloat xpos, ypos, zpos;
190   GLfloat dx, dy, dz;
191   GLfloat box_width, box_height, box_depth;
192
193 } planetstruct;
194
195
196 static planetstruct *planets = NULL;
197
198
199 static inline void
200 normalize(GLfloat v[3])
201 {
202         GLfloat     d = (GLfloat) sqrt((double) (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
203
204         if (d != 0) {
205                 v[0] /= d;
206                 v[1] /= d;
207                 v[2] /= d;
208         } else {
209                 v[0] = v[1] = v[2] = 0;
210         }
211 }
212
213
214 /* Set up and enable texturing on our object */
215 static void
216 setup_xbm_texture (char *bits, int width, int height,
217                                    XColor *fgc, XColor *bgc)
218 {
219   unsigned int fg = (((fgc->red  >> 8) << 16) |
220                                          ((fgc->green >> 8) << 8) |
221                                          ((fgc->blue >> 8)));
222   unsigned int bg = (((bgc->red  >> 8) << 16) |
223                                          ((bgc->green >> 8) << 8) |
224                                          ((bgc->blue >> 8)));
225
226   unsigned char *data = (unsigned char *)
227         malloc ((width * height * 24) / 8);
228   unsigned char *out = data;
229   int x, y;
230
231   for (y = 0; y < height; y++)
232         for (x = 0; x < width; x++)
233           {
234                 unsigned char byte = bits [(y * (width / 8) + (x / 8))];
235                 unsigned char bit = (byte & (1 << (x % 8))) >> (x % 8);
236                 unsigned int word = (bit ? bg : fg);
237                 *out++ = (word & 0xFF0000) >> 16;
238                 *out++ = (word & 0x00FF00) >> 8;
239                 *out++ = (word & 0x0000FF);
240           }
241
242   clear_gl_error();
243   glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
244                            GL_RGB, GL_UNSIGNED_BYTE, data);
245   check_gl_error("texture");
246
247   /* setup parameters for texturing */
248   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
249   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
250   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
251   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
252   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
253   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
254 }
255
256
257 static void
258 setup_file_texture (ModeInfo *mi, char *filename)
259 {
260   Display *dpy = mi->dpy;
261   Visual *visual = mi->xgwa.visual;
262   Colormap cmap = mi->xgwa.colormap;
263
264 #ifdef HAVE_XPM
265   {
266         char **xpm_data = 0;
267         int result = XpmReadFileToData (filename, &xpm_data);
268         switch (result) {
269         case XpmSuccess:
270           {
271                 XImage *image = xpm_to_ximage (dpy, visual, cmap, xpm_data);
272
273         clear_gl_error();
274                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
275                                          image->width, image->height, 0,
276                                          GL_RGBA, GL_UNSIGNED_BYTE, image->data);
277         check_gl_error("texture");
278
279                 /* setup parameters for texturing */
280                 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
281                 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
282
283                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
284                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
285                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
286                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
287                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
288                 return;
289           }
290           break;
291
292         case XpmOpenFailed:
293           fprintf (stderr, "%s: file %s doesn't exist.\n", progname, filename);
294           exit (-1);
295           break;
296
297         case XpmFileInvalid:
298           /* Fall through and try it as an XBM. */
299           break;
300
301         case XpmNoMemory:
302           fprintf (stderr, "%s: XPM: out of memory\n", progname);
303           exit (-1);
304           break;
305
306         default:
307           fprintf (stderr, "%s: XPM: unknown error code %d\n", progname, result);
308           exit (-1);
309           break;
310         }
311   }
312 #endif /* HAVE_XPM */
313
314 #ifdef HAVE_XMU
315   {
316         planetstruct *gp = &planets[MI_SCREEN(mi)];
317         unsigned int width = 0;
318         unsigned int height = 0;
319         unsigned char *data = 0;
320         int xhot, yhot;
321         int status = XmuReadBitmapDataFromFile (filename, &width, &height, &data,
322                                                                                         &xhot, &yhot);
323         if (status != Success)
324           {
325 # ifdef HAVE_XPM
326                 fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
327 # endif
328                 fprintf (stderr, "%s: not an XBM file: %s\n", progname, filename);
329                 exit (1);
330           }
331
332         setup_xbm_texture ((char *) data, width, height, &gp->fg, &gp->bg);
333   }
334 #else  /* !XMU */
335
336 # ifdef HAVE_XPM
337   fprintf (stderr, "%s: not an XPM file: %s\n", progname, filename);
338 # endif
339   fprintf (stderr, "%s: your vendor doesn't ship the standard Xmu library.\n",
340                    progname);
341   fprintf (stderr, "%s: we can't load XBM files without it.\n",progname);
342   exit (1);
343 #endif /* !XMU */
344 }
345
346
347 static void
348 setup_texture(ModeInfo * mi)
349 {
350   planetstruct *gp = &planets[MI_SCREEN(mi)];
351   if (!which_image ||
352           !*which_image ||
353           !strcmp(which_image, "BUILTIN"))
354         setup_xbm_texture (earth_bits, earth_width, earth_height,
355                                            &gp->fg, &gp->bg);
356   else
357         setup_file_texture (mi, which_image);
358 }
359
360
361 /* Set up and enable lighting */
362 static void
363 setup_light(void)
364 {
365   /* set a number of parameters which make the scene look much nicer */
366   glEnable(GL_BLEND);
367   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
368   glShadeModel(GL_SMOOTH);
369 }
370
371
372 /* Set up and enable face culling so we don't see the inside of the sphere */
373 static void
374 setup_face(void)
375 {
376   glEnable(GL_CULL_FACE);
377   glCullFace(GL_BACK); 
378 }
379
380
381 /* Function for determining points on the surface of the sphere */
382 static void inline ParametricSphere(float theta, float rho, GLfloat *vector)
383 {
384   vector[0] = -sin(theta) * sin(rho);
385   vector[1] = cos(theta) * sin(rho);
386   vector[2] = cos(rho);
387
388 #if DO_HELIX
389   vector[0] = -(1- cos(theta)) * cos(rho); 
390   vector[1] = -(1- cos(theta)) * sin(rho); 
391   vector[2] = -(sin(theta) + rho); 
392 #endif /* DO_HELIX */
393
394         return;
395 }
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   int i, j;
456   int stacks=STACKS, slices=SLICES;
457   float radius=RADIUS;
458
459   float drho, dtheta;
460   float rho, theta;
461   GLfloat vector[3];
462   GLfloat ds, dt, t, s;;
463
464   if (wire) {
465         glEnable(GL_LINE_SMOOTH);
466         do_texture = False;
467   }
468
469   /* turn on various options we like */
470   if (do_texture)
471         setup_texture(mi);
472   if (do_light)
473         setup_light();
474
475   setup_face();
476
477   if (do_stars) {
478         glEnable(GL_POINT_SMOOTH);
479         generate_stars(MI_WIDTH(mi), MI_HEIGHT(mi));
480   }
481
482
483   /*-
484    * Generate a sphere with quadrilaterals.
485    * Quad vertices are determined using a parametric sphere function.
486    * For fun, you could generate practically any parameteric surface and
487    * map an image onto it. 
488    */
489
490   drho = M_PI / stacks;
491   dtheta = 2.0 * M_PI / slices;
492   ds = 1.0 / slices;
493   dt = 1.0 / stacks;
494   
495
496   gp->platelist=glGenLists(1);
497   glNewList(gp->platelist, GL_COMPILE);
498
499   glColor3f(1,1,1);
500   glBegin( wire ? GL_LINE_LOOP : GL_QUADS );
501
502   t = 0.0;
503   for(i=0; i<stacks; i++) {
504         rho = i * drho;
505         s = 0.0;
506         for(j=0; j<slices; j++) {
507           theta = j * dtheta;
508
509
510           glTexCoord2f(s,t);
511           ParametricSphere(theta, rho, vector);
512           normalize(vector);
513           glNormal3fv(vector);
514           ParametricSphere(theta, rho, vector);
515           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
516
517           glTexCoord2f(s,t+dt);
518           ParametricSphere(theta, rho+drho, vector);
519           normalize(vector);
520           glNormal3fv(vector);
521           ParametricSphere(theta, rho+drho, vector);
522           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
523
524           glTexCoord2f(s+ds,t+dt);
525           ParametricSphere(theta + dtheta, rho+drho, vector);
526           normalize(vector);
527           glNormal3fv(vector);
528           ParametricSphere(theta + dtheta, rho+drho, vector);
529           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
530
531           glTexCoord2f(s+ds, t);
532           ParametricSphere(theta + dtheta, rho, vector);
533           normalize(vector);
534           glNormal3fv(vector);
535           ParametricSphere(theta + dtheta, rho, vector);
536           glVertex3f( vector[0]*radius, vector[1]*radius, vector[2]*radius );
537
538           s = s + ds;
539
540         }
541         t = t + dt;
542   }
543   glEnd();
544   glEndList();
545
546
547  }
548
549 static void
550 draw_sphere(ModeInfo * mi)
551 {
552   planetstruct *gp = &planets[MI_SCREEN(mi)];
553
554   glEnable(GL_DEPTH_TEST);
555
556   /* turn on the various attributes for making the sphere look nice */
557   if (do_texture)
558         glEnable(GL_TEXTURE_2D);
559
560   if (do_light)
561         {
562           glEnable(GL_LIGHTING);
563           glEnable(GL_LIGHT0);
564           glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
565           glEnable(GL_COLOR_MATERIAL);
566         }
567
568   glCallList(gp->platelist);
569
570 }
571
572
573 #define RANDSIGN() ((random() & 1) ? 1 : -1)
574
575 static void
576 pick_velocity (ModeInfo * mi)
577 {
578   planetstruct *gp = &planets[MI_SCREEN(mi)];
579
580   gp->box_width =  15.0;
581   gp->box_height = 15.0;
582   gp->box_depth =  5.0;
583
584   gp->tx = 0.0;
585   gp->ty = 0.0;
586   gp->tz = frand(360);
587
588   gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
589   gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
590   gp->dtz = (frand(5.0) + frand(5.0));  /* the sun sets in the west */
591
592   gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
593   gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
594   gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
595 }
596
597
598 static void
599 rotate_and_move (ModeInfo * mi)
600 {
601   planetstruct *gp = &planets[MI_SCREEN(mi)];
602
603   if (do_roll)
604         {
605           gp->tx += gp->dtx;
606           while (gp->tx < 0)   gp->tx += 360;
607           while (gp->tx > 360) gp->tx -= 360;
608
609           gp->ty += gp->dty;
610           while (gp->ty < 0)   gp->ty += 360;
611           while (gp->ty > 360) gp->ty -= 360;
612         }
613
614   if (do_rotate)
615         {
616           gp->tz += gp->dtz;
617           while (gp->tz < 0)   gp->tz += 360;
618           while (gp->tz > 360) gp->tz -= 360;
619         }
620
621   if (do_bounce)
622         {
623       static int frame = 0;
624 #     define SINOID(SCALE,SIZE) \
625         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
626       gp->xpos = SINOID(0.031, gp->box_width);
627       gp->ypos = SINOID(0.023, gp->box_height);
628       gp->zpos = SINOID(0.017, gp->box_depth);
629       frame++;
630         }
631 }
632
633
634 /* Standard reshape function */
635 void
636 reshape_planet(ModeInfo *mi, int width, int height)
637 {
638   GLfloat light[4];
639   GLfloat h = (GLfloat) height / (GLfloat) width;
640
641   light[0] = -1;
642   light[1] = (int) (((random() % 3) & 0xFF) - 1);
643   light[2] = (int) (((random() % 3) & 0xFF) - 1);
644   light[3] = 0;
645
646   glViewport(0, 0, (GLint) width, (GLint) height);
647   glMatrixMode(GL_PROJECTION);
648   glLoadIdentity();
649   glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
650   glMatrixMode(GL_MODELVIEW);
651   glLoadIdentity();
652   glTranslatef(0.0, 0.0, -DIST);
653   glLightfv(GL_LIGHT0, GL_POSITION, light);
654   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
655
656 }
657
658
659 void
660 init_planet(ModeInfo * mi)
661 {
662   int         screen = MI_SCREEN(mi);
663
664   planetstruct *gp;
665
666   if (planets == NULL) {
667         if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
668                                                                                   sizeof (planetstruct))) == NULL)
669           return;
670   }
671   gp = &planets[screen];
672
673   pick_velocity (mi);
674
675   {
676         char *f = get_string_resource("imageForeground", "Foreground");
677         char *b = get_string_resource("imageBackground", "Background");
678         char *s;
679         if (!f) f = strdup("white");
680         if (!b) b = strdup("black");
681         
682         for (s = f + strlen(f)-1; s > f; s--)
683           if (*s == ' ' || *s == '\t')
684                 *s = 0;
685         for (s = b + strlen(b)-1; s > b; s--)
686           if (*s == ' ' || *s == '\t')
687                 *s = 0;
688
689     if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
690       {
691                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
692                 exit(1);
693       }
694     if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
695       {
696                 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
697                 exit(1);
698       }
699
700         free (f);
701         free (b);
702   }
703
704
705   gp->window = MI_WINDOW(mi);
706   if ((gp->glx_context = init_GL(mi)) != NULL) {
707         reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
708         pinit(mi);
709   } else {
710         MI_CLEARWINDOW(mi);
711   }
712 }
713
714 void
715 draw_planet(ModeInfo * mi)
716 {
717   planetstruct *gp = &planets[MI_SCREEN(mi)];
718   Display    *display = MI_DISPLAY(mi);
719   Window      window = MI_WINDOW(mi);
720
721   if (!gp->glx_context)
722         return;
723
724   glDrawBuffer(GL_BACK);
725   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
726
727   glXMakeCurrent(display, window, *(gp->glx_context));
728
729
730   if (do_stars) {
731         /* protect our modelview matrix and attributes */
732         glPushMatrix();
733         glPushAttrib(GL_ALL_ATTRIB_BITS);
734         {
735           glColor3f(1,1,1);
736           /* draw the star field. */
737           glCallList(gp->starlist);
738
739         }
740         glPopMatrix();
741         glPopAttrib();
742   }
743
744   /* protect our modelview matrix and attributes */
745   glPushMatrix();
746   glPushAttrib(GL_ALL_ATTRIB_BITS);
747   {
748         /* this pair of rotations seem to be necessary to orient the earth correctly */
749         glRotatef(90,0,0,1);
750         glRotatef(90,0,1,0);
751
752         glTranslatef(gp->xpos, gp->ypos, gp->zpos);
753         glRotatef(gp->tx, 1, 0, 0);
754         glRotatef(gp->ty, 0, 1, 0);
755         glRotatef(gp->tz, 0, 0, 1);
756         /* draw the sphere */
757         draw_sphere(mi);
758   }
759   glPopMatrix();
760   glPopAttrib();
761
762
763
764   if (mi->fps_p) do_fps (mi);
765   glFinish();
766   glXSwapBuffers(display, window);
767
768   rotate_and_move (mi);
769 }
770
771 void
772 release_planet(ModeInfo * mi)
773 {
774   if (planets != NULL) {
775         int         screen;
776
777         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
778           planetstruct *gp = &planets[screen];
779
780           if (gp->glx_context) {
781                 /* Display lists MUST be freed while their glXContext is current. */
782                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
783
784                 if (glIsList(gp->platelist))
785                   glDeleteLists(gp->platelist, 1);
786                 if (glIsList(gp->starlist))
787                   glDeleteLists(gp->starlist, 1);
788           }
789         }
790         (void) free((void *) planets);
791         planets = NULL;
792   }
793   FreeAllGL(mi);
794 }
795
796
797 #endif
798