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