1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* glplanet --- 3D rotating planet, e.g., Earth.
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.
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.
18 * 16-Jan-02: jwz@jwz.org gdk_pixbuf support.
19 * 21-Mar-01: jwz@jwz.org Broke sphere routine out into its own file.
21 * 9-Oct-98: dek@cgl.ucsf.edu Added stars.
23 * 8-Oct-98: jwz@jwz.org Made the 512x512x1 xearth image be built in.
24 * Made it possible to load XPM or XBM files.
25 * Made the planet bounce and roll around.
27 * 8-Oct-98: Released initial version of "glplanet"
28 * (David Konerding, dek@cgl.ucsf.edu)
33 * For even more spectacular results, grab the images from the "SSystem"
34 * package (http://www.msu.edu/user/kamelkev/) and use its JPEGs!
39 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
40 * otherwise caddr_t is not defined correctly
43 #include <X11/Intrinsic.h>
46 # define PROGCLASS "Planet"
47 # define HACK_INIT init_planet
48 # define HACK_DRAW draw_planet
49 # define HACK_RESHAPE reshape_planet
50 # define planet_opts xlockmore_opts
51 #define DEFAULTS "*delay: 15000 \n" \
52 "*showFPS: False \n" \
56 "*wireframe: False \n" \
60 "*image: BUILTIN \n" \
61 "*imageForeground: Green \n" \
62 "*imageBackground: Blue \n"
64 # include "xlockmore.h" /* from the xscreensaver distribution */
65 #else /* !STANDALONE */
66 # include "xlock.h" /* from the xlockmore distribution */
67 #endif /* !STANDALONE */
69 #ifdef USE_GL /* whole file */
75 # include <X11/Xmu/Drawing.h>
77 # include <Xmu/Drawing.h>
84 #define DEF_ROTATE "True"
85 #define DEF_ROLL "True"
86 #define DEF_WANDER "True"
87 #define DEF_TEXTURE "True"
88 #define DEF_STARS "True"
89 #define DEF_LIGHT "True"
90 #define DEF_IMAGE "BUILTIN"
93 #define countof(x) (sizeof((x))/sizeof((*x)))
98 static int do_texture;
101 static char *which_image;
102 static XrmOptionDescRec opts[] = {
103 {"-rotate", ".glplanet.rotate", XrmoptionNoArg, (caddr_t) "true" },
104 {"+rotate", ".glplanet.rotate", XrmoptionNoArg, (caddr_t) "false" },
105 {"-roll", ".glplanet.roll", XrmoptionNoArg, (caddr_t) "true" },
106 {"+roll", ".glplanet.roll", XrmoptionNoArg, (caddr_t) "false" },
107 {"-wander", ".glplanet.wander", XrmoptionNoArg, (caddr_t) "true" },
108 {"+wander", ".glplanet.wander", XrmoptionNoArg, (caddr_t) "false" },
109 {"-texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "true" },
110 {"+texture", ".glplanet.texture", XrmoptionNoArg, (caddr_t) "false" },
111 {"-stars", ".glplanet.stars", XrmoptionNoArg, (caddr_t) "true" },
112 {"+stars", ".glplanet.stars", XrmoptionNoArg, (caddr_t) "false" },
113 {"-light", ".glplanet.light", XrmoptionNoArg, (caddr_t) "true" },
114 {"+light", ".glplanet.light", XrmoptionNoArg, (caddr_t) "false" },
115 {"-image", ".glplanet.image", XrmoptionSepArg, (caddr_t) 0 },
118 static argtype vars[] = {
119 {(caddr_t *) &do_rotate, "rotate", "Rotate", DEF_ROTATE, t_Bool},
120 {(caddr_t *) &do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
121 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
122 {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
123 {(caddr_t *) &do_stars, "stars", "Stars", DEF_STARS, t_Bool},
124 {(caddr_t *) &do_light, "light", "Light", DEF_LIGHT, t_Bool},
125 {(caddr_t *) &which_image, "image", "Image", DEF_IMAGE, t_String},
128 ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
131 ModStruct planet_description =
132 {"planet", "init_planet", "draw_planet", "release_planet",
133 "draw_planet", "init_planet", NULL, &planet_opts,
134 1000, 1, 2, 1, 4, 1.0, "",
135 "Animates texture mapped sphere (planet)", 0, NULL};
138 #include "../images/earth.xpm"
139 #include "xpm-ximage.h"
143 * slices and stacks are used in the sphere parameterization routine.
144 * more slices and stacks will increase the quality of the sphere,
145 * at the expense of rendering speed
148 #define NUM_STARS 1000
152 /* radius of the sphere- fairly arbitrary */
155 /* distance away from the sphere model */
160 /* structure for holding the planet data */
164 int screen_width, screen_height;
165 GLXContext *glx_context;
171 GLfloat dtx, dty, dtz;
172 GLfloat xpos, ypos, zpos;
174 GLfloat box_width, box_height, box_depth;
181 static planetstruct *planets = NULL;
185 normalize(GLfloat v[3])
187 GLfloat d = (GLfloat) sqrt((double) (v[0] * v[0] +
198 v[0] = v[1] = v[2] = 0;
203 /* Set up and enable texturing on our object */
205 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
207 XImage *image = xpm_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
208 MI_COLORMAP (mi), xpm_data);
210 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
211 image->width, image->height, 0,
212 GL_RGBA, GL_UNSIGNED_BYTE, image->data);
213 check_gl_error("texture");
215 /* setup parameters for texturing */
216 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
217 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
218 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
219 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
220 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
221 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
226 setup_file_texture (ModeInfo *mi, char *filename)
228 Display *dpy = mi->dpy;
229 Visual *visual = mi->xgwa.visual;
231 Colormap cmap = mi->xgwa.colormap;
232 XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
235 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
236 image->width, image->height, 0,
237 GL_RGBA, GL_UNSIGNED_BYTE, image->data);
238 check_gl_error("texture");
240 /* setup parameters for texturing */
241 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
242 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
244 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
245 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
246 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
247 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
248 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
253 setup_texture(ModeInfo * mi)
255 /* planetstruct *gp = &planets[MI_SCREEN(mi)];*/
257 glEnable(GL_TEXTURE_2D);
261 !strcmp(which_image, "BUILTIN"))
262 setup_xpm_texture (mi, earth_xpm);
264 setup_file_texture (mi, which_image);
266 check_gl_error("texture initialization");
271 init_stars (ModeInfo *mi)
274 GLfloat max_size = 3;
276 int steps = max_size / inc;
277 int width = MI_WIDTH(mi);
278 int height = MI_HEIGHT(mi);
280 planetstruct *gp = &planets[MI_SCREEN(mi)];
281 Bool wire = MI_IS_WIREFRAME(mi);
284 glEnable (GL_POINT_SMOOTH);
286 gp->starlist = glGenLists(1);
287 glNewList(gp->starlist, GL_COMPILE);
289 glScalef (1.0/width, 1.0/height, 1);
291 for (j = 1; j <= steps; j++)
293 glPointSize(inc * j);
295 for (i = 0 ; i < NUM_STARS / steps; i++)
297 glColor3f (0.6 + frand(0.3),
300 glVertex2f ((GLfloat) (random() % width),
301 (GLfloat) (random() % height));
307 check_gl_error("stars initialization");
312 draw_stars (ModeInfo * mi)
314 int width = MI_WIDTH(mi);
315 int height = MI_HEIGHT(mi);
317 planetstruct *gp = &planets[MI_SCREEN(mi)];
319 /* Sadly, this causes a stall of the graphics pipeline (as would the
320 equivalent calls to glGet*.) But there's no way around this, short
321 of having each caller set up the specific display matrix we need
322 here, which would kind of defeat the purpose of centralizing this
325 glPushAttrib(GL_TRANSFORM_BIT | /* for matrix contents */
326 GL_ENABLE_BIT | /* for various glDisable calls */
327 GL_CURRENT_BIT | /* for glColor3f() */
328 GL_LIST_BIT); /* for glListBase() */
330 check_gl_error ("glPushAttrib");
332 /* disable lighting and texturing when drawing stars!
333 (glPopAttrib() restores these.)
335 glDisable(GL_TEXTURE_2D);
336 glDisable(GL_LIGHTING);
337 glDisable(GL_DEPTH_TEST);
339 /* glPopAttrib() does not restore matrix changes, so we must
340 push/pop the matrix stacks to be non-intrusive there.
342 glMatrixMode(GL_PROJECTION);
345 check_gl_error ("glPushMatrix");
348 /* Each matrix mode has its own stack, so we need to push/pop
350 glMatrixMode(GL_MODELVIEW);
353 check_gl_error ("glPushMatrix");
356 gluOrtho2D (0, width, 0, height);
357 check_gl_error ("gluOrtho2D");
360 glScalef (width, height, 1);
361 glCallList(gp->starlist);
362 check_gl_error ("drawing stars");
366 glMatrixMode(GL_PROJECTION);
370 /* clean up after our state changes */
372 check_gl_error ("glPopAttrib");
377 /* Set up lighting */
379 init_sun (ModeInfo * mi)
381 planetstruct *gp = &planets[MI_SCREEN(mi)];
383 GLfloat lamb[4] = { 0.0, 0.0, 0.0, 1.0 };
384 GLfloat ldif[4] = { 1.0, 1.0, 1.0, 1.0 };
385 GLfloat spec[4] = { 1.0, 1.0, 1.0, 1.0 };
387 GLfloat mamb[4] = { 0.5, 0.5, 0.5, 1.0 };
388 GLfloat mdif[4] = { 1.0, 1.0, 1.0, 1.0 };
389 GLfloat mpec[4] = { 1.0, 1.0, 1.0, 1.0 };
392 gp->sunpos[0] = 1.00 - frand(2.00);
393 gp->sunpos[1] = 0.25 - frand(0.50);
394 gp->sunpos[2] = -1.00;
395 gp->sunpos[3] = 0.00;
397 glEnable(GL_LIGHTING);
400 glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
401 glLightfv (GL_LIGHT0, GL_AMBIENT, lamb);
402 glLightfv (GL_LIGHT0, GL_DIFFUSE, ldif);
403 glLightfv (GL_LIGHT0, GL_SPECULAR, spec);
405 glMaterialfv (GL_FRONT, GL_AMBIENT, mamb);
406 glMaterialfv (GL_FRONT, GL_DIFFUSE, mdif);
407 glMaterialfv (GL_FRONT, GL_SPECULAR, mpec);
408 glMaterialf (GL_FRONT, GL_SHININESS, shiny);
412 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
413 glShadeModel(GL_SMOOTH);
415 check_gl_error("lighting");
419 #define RANDSIGN() ((random() & 1) ? 1 : -1)
422 pick_velocity (ModeInfo * mi)
424 planetstruct *gp = &planets[MI_SCREEN(mi)];
426 gp->box_width = 15.0;
427 gp->box_height = 15.0;
434 gp->dtx = (frand(0.4) + frand(0.3)) * RANDSIGN();
435 gp->dty = (frand(0.4) + frand(0.3)) * RANDSIGN();
436 gp->dtz = (frand(5.0) + frand(5.0)); /* the sun sets in the west */
438 gp->dx = (frand(0.2) + frand(0.2)) * RANDSIGN();
439 gp->dy = (frand(0.2) + frand(0.2)) * RANDSIGN();
440 gp->dz = (frand(0.2) + frand(0.2)) * RANDSIGN();
445 rotate_and_move (ModeInfo * mi)
447 planetstruct *gp = &planets[MI_SCREEN(mi)];
452 while (gp->tx < 0) gp->tx += 360;
453 while (gp->tx > 360) gp->tx -= 360;
456 while (gp->ty < 0) gp->ty += 360;
457 while (gp->ty > 360) gp->ty -= 360;
463 while (gp->tz < 0) gp->tz += 360;
464 while (gp->tz > 360) gp->tz -= 360;
469 static int frame = 0;
470 # define SINOID(SCALE,SIZE) \
471 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
472 gp->xpos = SINOID(0.031, gp->box_width);
473 gp->ypos = SINOID(0.023, gp->box_height);
474 gp->zpos = SINOID(0.017, gp->box_depth);
481 reshape_planet (ModeInfo *mi, int width, int height)
483 GLfloat h = (GLfloat) height / (GLfloat) width;
485 glViewport(0, 0, (GLint) width, (GLint) height);
486 glMatrixMode(GL_PROJECTION);
488 glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
489 glMatrixMode(GL_MODELVIEW);
491 glTranslatef(0.0, 0.0, -DIST);
493 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
498 init_planet (ModeInfo * mi)
501 int screen = MI_SCREEN(mi);
502 Bool wire = MI_IS_WIREFRAME(mi);
504 if (planets == NULL) {
505 if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
506 sizeof (planetstruct))) == NULL)
509 gp = &planets[screen];
513 if ((gp->glx_context = init_GL(mi)) != NULL) {
514 reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
518 char *f = get_string_resource("imageForeground", "Foreground");
519 char *b = get_string_resource("imageBackground", "Background");
521 if (!f) f = strdup("white");
522 if (!b) b = strdup("black");
524 for (s = f + strlen(f)-1; s > f; s--)
525 if (*s == ' ' || *s == '\t')
527 for (s = b + strlen(b)-1; s > b; s--)
528 if (*s == ' ' || *s == '\t')
531 if (!XParseColor(mi->dpy, mi->xgwa.colormap, f, &gp->fg))
533 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
536 if (!XParseColor(mi->dpy, mi->xgwa.colormap, b, &gp->bg))
538 fprintf(stderr, "%s: unparsable color: \"%s\"\n", progname, f);
550 glEnable (GL_LINE_SMOOTH);
562 glEnable(GL_DEPTH_TEST);
563 glEnable(GL_CULL_FACE);
566 gp->platelist = glGenLists(1);
567 glNewList (gp->platelist, GL_COMPILE);
570 glScalef (RADIUS, RADIUS, RADIUS);
571 unit_sphere (STACKS, SLICES, wire);
577 draw_planet (ModeInfo * mi)
579 planetstruct *gp = &planets[MI_SCREEN(mi)];
580 Display *display = MI_DISPLAY(mi);
581 Window window = MI_WINDOW(mi);
583 if (!gp->glx_context)
586 glDrawBuffer(GL_BACK);
587 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
589 glXMakeCurrent (display, window, *(gp->glx_context));
595 glRotatef (90,1,0,0);
596 glTranslatef (gp->xpos, gp->ypos, gp->zpos);
598 glRotatef (gp->tx, 1, 0, 0);
599 glRotatef (gp->ty, 0, 1, 0);
600 glRotatef (gp->tz, 0, 0, 1);
602 glLightfv (GL_LIGHT0, GL_POSITION, gp->sunpos);
604 glCallList (gp->platelist);
607 if (mi->fps_p) do_fps (mi);
609 glXSwapBuffers(display, window);
611 rotate_and_move (mi);
616 release_planet (ModeInfo * mi)
618 if (planets != NULL) {
621 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
622 planetstruct *gp = &planets[screen];
624 if (gp->glx_context) {
625 /* Display lists MUST be freed while their glXContext is current. */
626 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
628 if (glIsList(gp->platelist))
629 glDeleteLists(gp->platelist, 1);
630 if (glIsList(gp->starlist))
631 glDeleteLists(gp->starlist, 1);
634 (void) free((void *) planets);