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