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