http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / glx / sballs.c
1 /* sballs --- balls spinning like crazy in GL */
2
3 #if 0
4 static const char sccsid[] = "@(#)sballs.c      5.02 2001/03/10 xlockmore";
5 #endif
6
7 /* Copyright (c) E. Lassauge, 2001. */
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  * The original code for this mode was written by 
23  * Mustata Bogdan (LoneRunner) <lonerunner@planetquake.com>
24  * and can be found at http://www.cfxweb.net/lonerunner/
25  *
26  * Eric Lassauge  (November-07-2000) <lassauge@mail.dotcom.fr>
27  *                                  http://lassauge.free.fr/linux.html
28  *
29  * REVISION HISTORY:
30  *
31  * E.Lassauge - 03-Oct-2001:
32  *      - minor bugfixes - get ready for xscreensaver
33  * E.Lassauge - 09-Mar-2001:
34  *      - get rid of my framerate options to use showfps
35  * E.Lassauge - 28-Nov-2000:
36  *      - add handling of polyhedrons (like in ico)
37  *      - modified release part to add freeing of GL objects
38  * E.Lassauge - 14-Nov-2000:
39  *      - use new common xpm_to_ximage function
40  *
41  */
42
43 #ifdef STANDALONE       /* xscreensaver mode */
44 #define PROGCLASS       "Sballs"
45 #define HACK_INIT       init_sballs
46 #define HACK_DRAW       draw_sballs
47 #define HACK_RESHAPE    reshape_sballs
48 #define sballs_opts     xlockmore_opts
49 #define DEFAULTS        "*delay:        10000 \n" \
50                         "*size:             0 \n" \
51                         "*cycles:          10 \n" \
52                         "*object:           0 \n" \
53                         "*trackmouse:   False \n" \
54                         "*showFPS:      False \n" \
55                         "*wireframe:    False \n" \
56                         "*texture:      True  \n"
57
58 #define MODE_sballs
59 #include "xlockmore.h"          /* from the xscreensaver distribution */
60 #else                           /* !STANDALONE */
61 #include "xlock.h"              /* from the xlockmore distribution */
62 #include "visgl.h"
63 #endif                          /* !STANDALONE */
64
65 #ifdef MODE_sballs
66
67 #define MINSIZE         32      /* minimal viewport size */
68 #define FRAME           50      /* frame count interval */
69 #define MAX_OBJ         8       /* number of 3D objects */
70
71 #include <GL/gl.h>
72 #include <GL/glx.h>
73 #include <GL/glu.h>
74
75 #if defined( USE_XPM ) || defined( USE_XPMINC ) || defined( HAVE_XPM )
76 /* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
77 # include "xpm-ximage.h"
78 # define I_HAVE_XPM
79
80 # ifdef STANDALONE
81
82 #  ifdef __GNUC__
83    __extension__ /* don't warn about "string length is greater than the length
84                     ISO C89 compilers are required to support" when including
85                     the following XPM file... */
86 #  endif
87 #  include "../images/sball.xpm"
88 #  ifdef __GNUC__
89    __extension__
90 #  endif
91 #  include "../images/sball-bg.xpm"
92 # else /* !STANDALONE */
93 #  include "pixmaps/sball.xpm"
94 #  include "pixmaps/sball-bg.xpm"
95 # endif /* !STANDALONE */
96 #endif /* HAVE_XPM */
97
98 /* Manage option vars */
99 #define DEF_TEXTURE     "True"
100 #define DEF_TRACKMOUSE  "False"
101 #define DEF_OBJECT      "2"
102 #define DEF_OBJECT_INDX 2
103 static Bool do_texture;
104 static Bool do_trackmouse;
105 static int  object;
106 static int  spheres;
107
108 static XrmOptionDescRec opts[] = {
109     {(char *) "-texture", (char *) ".sballs.texture", XrmoptionNoArg, (caddr_t) "on"},
110     {(char *) "+texture", (char *) ".sballs.texture", XrmoptionNoArg, (caddr_t) "off"},
111     {(char *) "-trackmouse", (char *) ".sballs.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
112     {(char *) "+trackmouse", (char *) ".sballs.trackmouse", XrmoptionNoArg, (caddr_t) "off"},
113     {(char *) "-object", (char *) ".sballs.object", XrmoptionSepArg, (caddr_t) NULL},
114
115 };
116
117 static argtype vars[] = {
118     {(caddr_t *) & do_texture, (char *) "texture", (char *) "Texture", (char *) DEF_TEXTURE, t_Bool},
119     {(caddr_t *) & do_trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool},
120     {(caddr_t *) & object, (char *) "object", (char *) "Object", (char *) DEF_OBJECT, t_Int},
121
122 };
123
124 static OptionStruct desc[] = {
125     /*{(char *) "-count spheres", (char *) "set number of spheres"},*/
126     /*{(char *) "-cycles speed", (char *) "set ball speed value"},*/
127     {(char *) "-/+texture", (char *) "turn on/off texturing"},
128     {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"},
129     {(char *) "-object num", (char *) "number of the 3D object (0 means random)"},
130 };
131
132 ModeSpecOpt sballs_opts =
133  { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc };
134
135 #ifdef USE_MODULES
136 ModStruct sballs_description =
137     { "sballs", "init_sballs", "draw_sballs", "release_sballs",
138     "draw_sballs", "change_sballs", (char *) NULL, &sballs_opts,
139     /*
140     delay,count,cycles,size,ncolors,sat
141      */
142     10000, 0, 10, 400, 64, 1.0, "",
143     "balls spinning like crazy in GL", 0, NULL
144 };
145 #endif /* USE_MODULES */
146
147 /* misc types and defines */
148 #define vinit(a,i,j,k) {\
149   (a)[0]=i;\
150   (a)[1]=j;\
151   (a)[2]=k;\
152 }
153 typedef float vec_t;
154 typedef vec_t vec3_t[3];
155
156 #define MAX_BALLS       20
157
158 /* the mode struct, contains all per screen variables */
159 typedef struct {
160     GLint WIDTH, HEIGHT;        /* display dimensions */
161     GLXContext *glx_context;
162
163
164     XImage *btexture;           /* back texture image bits */
165     XImage *ftexture;           /* face texture image bits */
166     GLuint backid;              /* back texture id: GL world */
167     GLuint faceid;              /* face texture id: GL world */
168
169     vec3_t eye;
170     vec3_t rot;
171     vec3_t rotm;
172     int speed;
173     float radius[MAX_BALLS];
174
175 } sballsstruct;
176
177 /* array of sballsstruct indexed by screen number */
178 static sballsstruct *sballs = (sballsstruct *) NULL;
179
180 /* lights */
181 static float LightAmbient[]=   { 1.0f, 1.0f, 1.0f, 1.0f };
182 static float LightDiffuse[]=   { 1.0f, 1.0f, 1.0f, 1.0f };
183 static float LightPosition[]=  { 0.0f, 0.0f, 4.0f, 1.0f };
184
185 /* structure of the polyhedras */
186 typedef struct {
187         const char *longname;   /* long name of object */
188         const char *shortname;  /* short name of object */
189         int         numverts;   /* number of vertices */
190         float       radius;     /* radius */
191         vec3_t      v[MAX_BALLS];/* the vertices */
192 } Polyinfo;
193
194 static Polyinfo polygons[] =
195 {
196
197 /* 0: objtetra - structure values for tetrahedron */
198         {
199                 "tetrahedron", "tetra",         /* long and short names */
200                 4,                              /* number of vertices */
201                 0.8,
202                 {                               /* vertices (x,y,z) */
203                         /* all points must be within radius 2 of the origin */
204 #define T 1.0
205                         {T, T, T},
206                         {T, -T, -T},
207                         {-T, T, -T},
208                         {-T, -T, T},
209 #undef T
210                 }
211         },
212
213 /* 1: objcube - structure values for cube */
214
215         {
216                 "hexahedron", "cube",           /* long and short names */
217                 8,                              /* number of vertices, edges, and faces */
218                 0.6,
219                 {                               /* vertices (x,y,z) */
220                         /* all points must be within radius 2 of the origin */
221 #define T 1.0
222                         {T, T, T},
223                         {T, T, -T},
224                         {T, -T, -T},
225                         {T, -T, T},
226                         {-T, T, T},
227                         {-T, T, -T},
228                         {-T, -T, -T},
229                         {-T, -T, T},
230 #undef T
231                 }
232         },
233
234 /* 2: objocta - structure values for octahedron */
235
236         {
237                 "octahedron", "octa",   /* long and short names */
238                 6,                      /* number of vertices */
239                 0.6,
240                 {                       /* vertices (x,y,z) */
241                         /* all points must be within radius 2 of the origin */
242 #define T 1.5
243                         {T, 0, 0},
244                         {-T, 0, 0},
245                         {0, T, 0},
246                         {0, -T, 0},
247                         {0, 0, T},
248                         {0, 0, -T},
249 #undef T
250                 }
251         },
252 /* 3: objdodec - structure values for dodecahedron */
253
254         {
255                 "dodecahedron", "dodeca",       /* long and short names */
256                 20,                             /* number of vertices */
257                 0.35,
258                 {                               /* vertices (x,y,z) */
259                         /* all points must be within radius 2 of the origin */
260                         {0.000000, 0.500000, 1.000000},
261                         {0.000000, -0.500000, 1.000000},
262                         {0.000000, -0.500000, -1.000000},
263                         {0.000000, 0.500000, -1.000000},
264                         {1.000000, 0.000000, 0.500000},
265                         {-1.000000, 0.000000, 0.500000},
266                         {-1.000000, 0.000000, -0.500000},
267                         {1.000000, 0.000000, -0.500000},
268                         {0.500000, 1.000000, 0.000000},
269                         {-0.500000, 1.000000, 0.000000},
270                         {-0.500000, -1.000000, 0.000000},
271                         {0.500000, -1.000000, 0.000000},
272                         {0.750000, 0.750000, 0.750000},
273                         {-0.750000, 0.750000, 0.750000},
274                         {-0.750000, -0.750000, 0.750000},
275                         {0.750000, -0.750000, 0.750000},
276                         {0.750000, -0.750000, -0.750000},
277                         {0.750000, 0.750000, -0.750000},
278                         {-0.750000, 0.750000, -0.750000},
279                         {-0.750000, -0.750000, -0.750000},
280                 }
281         },
282
283 /* 4: objicosa - structure values for icosahedron */
284
285         {
286                 "icosahedron", "icosa",         /* long and short names */
287                 12,                             /* number of vertices */
288                 0.4,
289                 {                               /* vertices (x,y,z) */
290                         /* all points must be within radius 2 of the origin */
291                         {0.00000000, 0.00000000, -0.95105650},
292                         {0.00000000, 0.85065080, -0.42532537},
293                         {0.80901698, 0.26286556, -0.42532537},
294                         {0.50000000, -0.68819095, -0.42532537},
295                         {-0.50000000, -0.68819095, -0.42532537},
296                         {-0.80901698, 0.26286556, -0.42532537},
297                         {0.50000000, 0.68819095, 0.42532537},
298                         {0.80901698, -0.26286556, 0.42532537},
299                         {0.00000000, -0.85065080, 0.42532537},
300                         {-0.80901698, -0.26286556, 0.42532537},
301                         {-0.50000000, 0.68819095, 0.42532537},
302                         {0.00000000, 0.00000000, 0.95105650}
303                 }
304         },
305
306 /* 5: objplane - structure values for plane */
307
308         {
309                 "plane", "plane",       /* long and short names */
310                 4,                      /* number of vertices */
311                 0.7,
312                 {                       /* vertices (x,y,z) */
313                         /* all points must be within radius 2 of the origin */
314 #define T 1.1
315                         {T, 0, 0},
316                         {-T, 0, 0},
317                         {0, T, 0},
318                         {0, -T, 0},
319 #undef T
320                 }
321         },
322
323 /* 6: objpyr - structure values for pyramid */
324
325         {
326                 "pyramid", "pyramid",   /* long and short names */
327                 5,                      /* number of vertices */ 
328                 0.5,
329                 {                       /* vertices (x,y,z) */
330                         /* all points must be within radius 1 of the origin */
331 #define T 1.0
332                         {T, 0, 0},
333                         {-T, 0, 0},
334                         {0, T, 0},
335                         {0, -T, 0},
336                         {0, 0, T},
337 #undef T
338                 }
339         },
340
341 /* 7: objstar - structure values for octahedron star (stellated octahedron?) */
342         {
343                 "star", "star", /* long and short names */
344                 8,              /* number of vertices */
345                 0.7,
346                 {               /* vertices (x,y,z) */
347                         /* all points must be within radius 1 of the origin */
348 #define T 0.9
349                         {T, T, T},
350                         {T, -T, -T},
351                         {-T, T, -T},
352                         {-T, -T, T},
353                         {-T, -T, -T},
354                         {-T, T, T},
355                         {T, -T, T},
356                         {T, T, -T},
357 #undef T
358                 }
359         },
360
361 };
362
363
364
365
366 /*
367  *-----------------------------------------------------------------------------
368  *-----------------------------------------------------------------------------
369  *    Misc funcs.
370  *-----------------------------------------------------------------------------
371  *-----------------------------------------------------------------------------
372  */
373
374 static void clamp(vec3_t v)
375 {
376     int i;
377
378     for (i = 0; i < 3; i ++)
379         if (v[i] > 360 || v[i] < -360)
380             v[i] = 0;
381 }
382
383 /* track the mouse in a joystick manner : not perfect but it works */
384 static void trackmouse(ModeInfo * mi)
385 {
386     sballsstruct *sb = &sballs[MI_SCREEN(mi)];
387     /* we keep static values (not per screen) for the mouse stuff: in general you have only one mouse :-> */
388     static int max[2] = { 0, 0 };
389     static int min[2] = { 0x7fffffff, 0x7fffffff }, center[2];
390     Window r, c;
391     int rx, ry, cx, cy;
392     unsigned int m;
393
394     (void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
395                          &r, &c, &rx, &ry, &cx, &cy, &m);
396
397     if (max[0] < cx)
398         max[0] = cx;
399     if (min[0] > cx)
400         min[0] = cx;
401     center[0] = (max[0] + min[0]) / 2;
402
403     if (max[1] < cy)
404         max[1] = cy;
405     if (min[1] > cy)
406         min[1] = cy;
407     center[1] = (max[1] + min[1]) / 2;
408
409     if (fabs(center[0] - (float) cx) > 0.1 * (max[0] - min[0]))
410         sb->rot[0] -= ((center[0] - (float) cx) / (max[0] - min[0]) * 180.0f) / 200.0f;
411     if (fabs(center[1] - (float) cy) > 0.1 * (max[1] - min[1]))
412         sb->rot[1] -= ((center[1] - (float) cy) / (max[1] - min[1]) * 180.0f) / 200.0f;;
413     clamp(sb->rot);
414
415     /* oops: can't get those buttons */
416     if (m & Button4Mask)
417         sb->speed++;
418     if (m & Button5Mask)
419         sb->speed--;
420
421 }
422
423 /* initialise textures */
424 static void inittextures(ModeInfo * mi)
425 {
426     sballsstruct *sb = &sballs[MI_SCREEN(mi)];
427
428 #if defined( I_HAVE_XPM )
429     if (do_texture) {
430
431         glGenTextures(1, &sb->backid);
432 #ifdef HAVE_GLBINDTEXTURE
433         glBindTexture(GL_TEXTURE_2D, sb->backid);
434 #endif /* HAVE_GLBINDTEXTURE */
435
436         sb->btexture = xpm_to_ximage(MI_DISPLAY(mi),
437                                      MI_VISUAL(mi),
438                                      MI_COLORMAP(mi),
439                                      sball_bg);
440         if (!(sb->btexture)) {
441             (void) fprintf(stderr, "Error reading the background texture.\n");
442             glDeleteTextures(1, &sb->backid);
443             do_texture = False;
444             sb->faceid = 0;       /* default textures */
445             sb->backid = 0;
446             return;
447         }
448
449         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
450         clear_gl_error();
451         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
452                      sb->btexture->width, sb->btexture->height, 0,
453                      GL_RGBA,
454                      /* GL_UNSIGNED_BYTE, */
455                      GL_UNSIGNED_INT_8_8_8_8_REV,
456                      sb->btexture->data);
457         check_gl_error("texture");
458
459         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
460         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
461
462         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
463         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
464
465         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
466
467         glGenTextures(1, &sb->faceid);
468 #ifdef HAVE_GLBINDTEXTURE
469         glBindTexture(GL_TEXTURE_2D, sb->faceid);
470 #endif /* HAVE_GLBINDTEXTURE */
471
472         sb->ftexture = xpm_to_ximage(MI_DISPLAY(mi),
473                                      MI_VISUAL(mi),
474                                      MI_COLORMAP(mi),
475                                      sball);
476         if (!(sb->ftexture)) {
477             (void) fprintf(stderr, "Error reading the face texture.\n");
478             glDeleteTextures(1, &sb->faceid);
479             sb->faceid = 0;
480             return;
481         }
482
483         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
484         clear_gl_error();
485         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
486                      sb->ftexture->width, sb->ftexture->height, 0,
487                      GL_RGBA,
488                      /* GL_UNSIGNED_BYTE, */
489                      GL_UNSIGNED_INT_8_8_8_8_REV,
490                      sb->ftexture->data);
491         check_gl_error("texture");
492
493         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
494         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
495
496         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
497         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
498
499         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
500     }
501     else
502     {
503         sb->faceid = 0;       /* default textures */
504         sb->backid = 0;
505     }
506 #else /* !I_HAVE_XPM */
507   do_texture = False;
508   sb->faceid = 0;       /* default textures */
509   sb->backid = 0;
510 #endif /* !I_HAVE_XPM */
511 }
512
513 static void drawSphere(ModeInfo * mi,int sphere_num)
514 {
515   sballsstruct *sb = &sballs[MI_SCREEN(mi)];
516   float x = polygons[object].v[sphere_num][0];
517   float y = polygons[object].v[sphere_num][1];
518   float z = polygons[object].v[sphere_num][2];
519   int numMajor = 10;
520   int numMinor = 10;
521   float radius = sb->radius[sphere_num];
522   double majorStep = (M_PI / numMajor);
523   double minorStep = (2.0 * M_PI / numMinor);
524   int i, j;
525
526   glPushMatrix();
527   glTranslatef(x, y, z);
528
529   glColor4f(1, 1, 1, 1);
530   for (i = 0; i < numMajor; ++i)
531   {
532     double a = i * majorStep;
533     double b = a + majorStep;
534     double r0 = radius * sin(a);
535     double r1 = radius * sin(b);
536     GLfloat z0 = radius * cos(a);
537     GLfloat z1 = radius * cos(b);
538
539     glBegin(MI_IS_WIREFRAME(mi) ? GL_LINE_STRIP: GL_TRIANGLE_STRIP);
540     for (j = 0; j <= numMinor; ++j)
541         {
542       double c = j * minorStep;
543       GLfloat x = cos(c);
544       GLfloat y = sin(c);
545
546       glNormal3f((x * r0) / radius, (y * r0) / radius, z0 / radius);
547       glTexCoord2f(j / (GLfloat) numMinor, i / (GLfloat) numMajor);
548       glVertex3f(x * r0, y * r0, z0);
549
550       glNormal3f((x * r1) / radius, (y * r1) / radius, z1 / radius);
551       glTexCoord2f(j / (GLfloat) numMinor, (i + 1) / (GLfloat) numMajor);
552       glVertex3f(x * r1, y * r1, z1);
553     }
554     glEnd();
555   }
556
557   glPopMatrix();
558 }
559
560 /*
561  *-----------------------------------------------------------------------------
562  *-----------------------------------------------------------------------------
563  *    GL funcs.
564  *-----------------------------------------------------------------------------
565  *-----------------------------------------------------------------------------
566  */
567
568 #ifndef STANDALONE
569 static void Reshape(ModeInfo * mi)
570 #else
571 void reshape_sballs(ModeInfo * mi, int width, int height)
572 #endif
573 {
574
575     sballsstruct *sb = &sballs[MI_SCREEN(mi)];
576     int size = MI_SIZE(mi);
577
578     /* Viewport is specified size if size >= MINSIZE && size < screensize */
579     if (size <= 1) {
580         sb->WIDTH = MI_WIDTH(mi);
581         sb->HEIGHT = MI_HEIGHT(mi);
582     } else if (size < MINSIZE) {
583         sb->WIDTH = MINSIZE;
584         sb->HEIGHT = MINSIZE;
585     } else {
586         sb->WIDTH = (size > MI_WIDTH(mi)) ? MI_WIDTH(mi) : size;
587         sb->HEIGHT = (size > MI_HEIGHT(mi)) ? MI_HEIGHT(mi) : size;
588     }
589     glViewport((MI_WIDTH(mi) - sb->WIDTH) / 2, (MI_HEIGHT(mi) - sb->HEIGHT) / 2, sb->WIDTH, sb->HEIGHT);
590     glMatrixMode(GL_PROJECTION);
591     glLoadIdentity();
592     gluPerspective(55.0, (float)sb->WIDTH / (float) sb->HEIGHT, 1.0, 300.0);
593
594     glMatrixMode(GL_MODELVIEW);
595
596 }
597
598 static void Draw(ModeInfo * mi)
599 {
600     sballsstruct *sb = &sballs[MI_SCREEN(mi)];
601     int sphere;
602
603     if (do_trackmouse && !MI_IS_ICONIC(mi))
604         trackmouse(mi);
605
606     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
607
608     glPushMatrix();
609     glEnable(GL_DEPTH_TEST);
610
611     /* move eyes */
612     glTranslatef (-sb->eye[0], -sb->eye[1], -sb->eye[2]);
613
614     /* draw background */
615     if (do_texture)
616     {
617        glEnable(GL_LIGHTING);
618        glEnable(GL_TEXTURE_2D);
619        glColor3f(1, 1, 1);
620 #ifdef HAVE_GLBINDTEXTURE
621        glBindTexture(GL_TEXTURE_2D, sb->backid);
622 #endif /* HAVE_GLBINDTEXTURE */
623     }
624     else
625     {
626        glColor3f(0, 0, 0);
627     }
628     glBegin(GL_QUAD_STRIP);
629     glNormal3f(0, 0, 1); glTexCoord2f(0,0); glVertex3f(8, 4.1, -4);
630     glNormal3f(0, 0, 1); glTexCoord2f(0,1); glVertex3f(8, -4.1, -4);
631     glNormal3f(0, 0, 1); glTexCoord2f(1,0); glVertex3f(-8, 4.1, -4);
632     glNormal3f(0, 0, 1); glTexCoord2f(1,1); glVertex3f(-8, -4.1, -4);
633     glEnd();
634
635     /* rotate the mouse */
636     glRotatef(sb->rot[0], 1.0f, 0.0f, 0.0f);
637     glRotatef(sb->rot[1], 0.0f, 1.0f, 0.0f);
638     glRotatef(sb->rot[2], 0.0f, 0.0f, 1.0f);
639
640     /* rotate the balls */
641     glRotatef(sb->rotm[0], 1.0f, 0.0f, 0.0f);
642     glRotatef(sb->rotm[1], 0.0f, 1.0f, 0.0f);
643     glRotatef(sb->rotm[2], 0.0f, 0.0f, 1.0f);
644
645     sb->rotm[0] += sb->speed;
646     sb->rotm[1] += -(sb->speed);
647     sb->rotm[2] += 0;
648
649     /* draw the balls */
650     if (do_texture)
651 #ifdef HAVE_GLBINDTEXTURE
652        glBindTexture(GL_TEXTURE_2D, sb->faceid);
653 #endif /* HAVE_GLBINDTEXTURE */
654     else
655        glEnable(GL_LIGHTING);
656     for (sphere=0;sphere<spheres;sphere++)
657     {
658         drawSphere(mi,sphere);
659     }
660
661     glDisable(GL_TEXTURE_2D);
662     glDisable(GL_DEPTH_TEST);
663     glDisable(GL_LIGHTING);
664
665     /* manage framerate display */
666     if (MI_IS_FPS(mi)) do_fps (mi);
667     glPopMatrix();
668 }
669
670
671 static void Init(ModeInfo * mi)
672 {
673     sballsstruct *sb = &sballs[MI_SCREEN(mi)];
674     int i;
675
676     /* Default settings */
677     if (MI_IS_WIREFRAME(mi))
678         do_texture = False;
679     if (do_texture)
680         inittextures(mi);
681     else
682     {
683         sb->btexture = (XImage*) NULL;
684         sb->ftexture = (XImage*) NULL;
685     }
686
687     vinit(sb->eye   ,0.0f, 0.0f, 6.0f);
688     vinit(sb->rot   ,0.0f, 0.0f, 0.0f);
689     vinit(sb->rotm  ,0.0f, 0.0f, 0.0f);
690     sb->speed = MI_CYCLES(mi);
691
692     /* initialise object number */
693     if (object == 0)
694         object = NRAND(MAX_OBJ);
695     if ((object == 0) || (object > MAX_OBJ))
696         object = DEF_OBJECT_INDX;
697     object--;
698
699     /* initialise sphere number */
700     spheres = MI_COUNT(mi);
701     if (MI_COUNT(mi) > polygons[object].numverts)
702         spheres = polygons[object].numverts;
703     if (MI_COUNT(mi) < 1)
704         spheres = polygons[object].numverts;
705     /* initialise sphere radius */
706     for(i=0; i < spheres;i++)
707     {
708 #if RANDOM_RADIUS
709         sb->radius[i] = ((float) LRAND() / (float) MAXRAND);
710         if (sb->radius[i] < 0.3)
711             sb->radius[i] = 0.3;
712         if (sb->radius[i] > 0.7)
713             sb->radius[i] = 0.7;
714 #else
715         sb->radius[i] = polygons[object].radius;
716 #endif
717     }
718
719     if (MI_IS_DEBUG(mi)) {
720         (void) fprintf(stderr,
721                        "%s:\n\tobject=%s\n\tspheres=%d\n\tspeed=%d\n\ttexture=%s\n",
722                        MI_NAME(mi),
723                        polygons[object].shortname,
724                        spheres,
725                        (int) MI_CYCLES(mi),
726                        do_texture ? "on" : "off"
727                         );
728     }
729
730         glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
731         glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
732         glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
733         glEnable(GL_LIGHT1);
734
735         glClearColor(0, 0, 0, 0);
736 }
737
738 /*
739  *-----------------------------------------------------------------------------
740  *-----------------------------------------------------------------------------
741  *    Xlock hooks.
742  *-----------------------------------------------------------------------------
743  *-----------------------------------------------------------------------------
744  */
745
746 /*
747  *-----------------------------------------------------------------------------
748  *    Initialize sballs.  Called each time the window changes.
749  *-----------------------------------------------------------------------------
750  */
751
752 void init_sballs(ModeInfo * mi)
753 {
754     sballsstruct *sb;
755
756     if (sballs == NULL) {
757         if ((sballs = (sballsstruct *) calloc(MI_NUM_SCREENS(mi),
758                                           sizeof(sballsstruct))) == NULL)
759             return;
760     }
761     sb = &sballs[MI_SCREEN(mi)];
762
763     if ((sb->glx_context = init_GL(mi)) != NULL) {
764
765 #ifndef STANDALONE
766         Reshape(mi); /* xlock mode */
767 #else
768         reshape_sballs(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
769 #endif
770         glDrawBuffer(GL_BACK);
771         Init(mi);
772
773     } else {
774         MI_CLEARWINDOW(mi);
775     }
776 }
777
778 /*
779  *-----------------------------------------------------------------------------
780  *    Called by the mainline code periodically to update the display.
781  *-----------------------------------------------------------------------------
782  */
783 void draw_sballs(ModeInfo * mi)
784 {
785     Display *display = MI_DISPLAY(mi);
786     Window window = MI_WINDOW(mi);
787     sballsstruct *sb;
788
789     if (sballs == NULL)
790             return;
791     sb = &sballs[MI_SCREEN(mi)];
792
793     MI_IS_DRAWN(mi) = True;
794     if (!sb->glx_context)
795         return;
796
797     glXMakeCurrent(display, window, *(sb->glx_context));
798     Draw(mi);
799 #ifndef STANDALONE
800     Reshape(mi); /* xlock mode */
801 #else
802     reshape_sballs(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
803 #endif
804
805     glFinish();
806     glXSwapBuffers(display, window);
807 }
808
809
810 /*
811  *-----------------------------------------------------------------------------
812  *    The display is being taken away from us.  Free up malloc'ed
813  *      memory and X resources that we've alloc'ed.  Only called
814  *      once, we must zap everything for every screen.
815  *-----------------------------------------------------------------------------
816  */
817
818 void release_sballs(ModeInfo * mi)
819 {
820     int screen;
821
822     if (sballs != NULL) {
823         for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
824             sballsstruct *sb = &sballs[screen];
825             if (sb->btexture)
826             {
827                 glDeleteTextures(1,&sb->backid);
828                 XDestroyImage(sb->btexture);
829             }
830             if (sb->ftexture)
831             {
832                 glDeleteTextures(1,&sb->faceid);
833                 XDestroyImage(sb->ftexture);
834             }
835         }
836         (void) free((void *) sballs);
837         sballs = (sballsstruct *) NULL;
838     }
839     FreeAllGL(mi);
840 }
841
842 void change_sballs(ModeInfo * mi)
843 {
844     sballsstruct *sb;
845
846     if (sballs == NULL)
847             return;
848     sb = &sballs[MI_SCREEN(mi)];
849
850     if (!sb->glx_context)
851         return;
852
853     /* initialise object number */
854     if (object == 0)
855         object = NRAND(MAX_OBJ);
856     if ((object == 0) || (object > MAX_OBJ))
857         object = DEF_OBJECT_INDX;
858     object--;
859
860     /* correct sphere number */
861     spheres = MI_COUNT(mi);
862     if (MI_COUNT(mi) > polygons[object].numverts)
863         spheres = polygons[object].numverts;
864     if (MI_COUNT(mi) < 1)
865         spheres = polygons[object].numverts;
866
867     if (MI_IS_DEBUG(mi)) {
868         (void) fprintf(stderr,
869                        "%s:\n\tobject=%s\n\tspheres=%d\n\tspeed=%d\n\ttexture=%s\n",
870                        MI_NAME(mi),
871                        polygons[object].shortname,
872                        spheres,
873                        (int) MI_CYCLES(mi),
874                        do_texture ? "on" : "off"
875                         );
876     }
877     glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(sb->glx_context));
878
879 }
880 #endif /* MODE_sballs */