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