2bff1ec01219afb893d79f38cccdfb0ba3129a74
[xscreensaver] / hacks / glx / boxed.c
1 /* boxed --- 3D bouncing balls that explode */
2
3 #if 0
4 static const char sccsid[] = "@(#)boxed.c       0.9 01/09/26 xlockmore";
5 #endif
6
7 /*-
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose and without fee is hereby granted,
10  * provided that the above copyright notice appear in all copies and that
11  * both that copyright notice and this permission notice appear in
12  * supporting documentation.
13  *
14  * This file is provided AS IS with no warranties of any kind.  The author
15  * shall have no liability with respect to the infringement of copyrights,
16  * trade secrets or any patents by this file or any part thereof.  In no
17  * event will the author be liable for any lost revenue or profits or
18  * other special, indirect and consequential damages.
19  *
20  * Revision History:
21  *
22  * 2001: Written by Sander van Grieken <mailsander@gmx.net> 
23  *       as an OpenGL screensaver for the xscreensaver package.
24  *       Lots of hardcoded values still in place. Also, there are some
25  *       copy/paste leftovers from the gears hack. opts don't work.
26  *
27  * 2005: opts work. added options -balls, -ballsize, -explosion
28  *
29  */
30
31 #include "boxed.h"
32
33 /*
34 **----------------------------------------------------------------------------
35 ** Defines
36 **----------------------------------------------------------------------------
37 */
38
39 #ifdef STANDALONE
40 # define DEFAULTS       "*delay:     20000   \n" \
41                         "*showFPS:   False   \n" \
42                         "*wireframe: False   \n"
43
44 # define refresh_boxed 0
45 # define boxed_handle_event 0
46 # include "xlockmore.h"         /* from the xscreensaver distribution */
47 #else  /* !STANDALONE */
48 # include "xlock.h"             /* from the xlockmore distribution */
49 #endif /* !STANDALONE */
50
51 #ifdef USE_GL
52
53 # define DEF_SPEED      "0.5"
54 # define DEF_BALLS      "25"
55 # define DEF_BALLSIZE   "2.0"
56 # define DEF_EXPLOSION  "25.0f"
57
58 #undef countof 
59 #define countof(x) (int)(sizeof((x))/sizeof((*x)))
60 #undef rnd
61 #define rnd() (frand(1.0))
62
63 static GLfloat speed;  /* jwz -- overall speed factor applied to all motion */
64 static int cfg_balls;
65 static GLfloat cfg_ballsize;
66 static GLfloat cfg_explosion;
67
68
69 static XrmOptionDescRec opts[] = {
70     {"-speed", ".boxed.speed", XrmoptionSepArg, 0},
71     {"-balls", ".boxed.balls", XrmoptionSepArg, 0},
72     {"-ballsize", ".boxed.ballsize", XrmoptionSepArg, 0},
73     {"-explosion", ".boxed.explosion", XrmoptionSepArg, 0},
74 };
75
76 static argtype vars[] = {
77     {&speed, "speed", "Speed", DEF_SPEED, t_Float},
78     {&cfg_balls, "balls", "Balls", DEF_BALLS, t_Int},
79     {&cfg_ballsize, "ballsize", "Ball Size", DEF_BALLSIZE, t_Float},
80     {&cfg_explosion, "explosion", "Exlosion", DEF_BALLSIZE, t_Float},
81 };
82
83 ENTRYPOINT ModeSpecOpt boxed_opts = {countof(opts), opts, countof(vars), vars, NULL};
84
85 #ifdef USE_MODULES
86
87 ModStruct   boxed_description = { 
88      "boxed", "init_boxed", "draw_boxed", "release_boxed",
89      "draw_boxed", "init_boxed", NULL, &boxed_opts,
90      1000, 1, 2, 1, 4, 1.0, "",
91      "Shows GL's boxed balls", 0, NULL};
92
93 #endif
94
95 #define BOOL int
96 #define TRUE 1
97 #define FALSE 0
98
99 /* camera */
100 #define CAM_HEIGHT      100.0f
101 #define CAMDISTANCE_MIN 20.0
102 #define CAMDISTANCE_MAX 150.0
103 #define CAMDISTANCE_SPEED 1.5
104
105 /* rendering the sphere */
106 #define MESH_SIZE       10
107 #define SPHERE_VERTICES (2+MESH_SIZE*MESH_SIZE*2)
108 #define SPHERE_INDICES  ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
109
110 /*
111 **-----------------------------------------------------------------------------
112 **      Typedefs
113 **-----------------------------------------------------------------------------
114 */
115
116 typedef struct {
117    GLfloat x;
118    GLfloat y;
119    GLfloat z;
120 } vectorf;
121
122 typedef struct {
123    vectorf      loc;
124    vectorf      dir;
125    vectorf      color;
126    float        radius;
127    BOOL         bounced;
128    int          offside;
129    BOOL         justcreated;
130 } ball;
131
132 typedef struct {
133    int          num_balls;
134    float        ballsize;
135    float        explosion;
136    ball         *balls;
137 } ballman;
138
139 typedef struct {
140    vectorf      loc;
141    vectorf      dir;
142    BOOL         far;
143 } tri;
144
145 typedef struct {
146    int          num_tri;
147    int          lifetime;
148    float        scalefac;
149    float        explosion;
150    vectorf      color;
151    tri          *tris;
152    GLint        *indices;
153    vectorf      *normals;
154    vectorf      *vertices;
155 } triman;
156
157 typedef struct {
158    int numballs;
159    float ballsize;
160    float explosion;
161    BOOL textures;
162    BOOL transparent;
163    float camspeed;
164 } boxed_config;
165
166
167 typedef struct {
168    float          cam_x_speed, cam_z_speed, cam_y_speed;
169    boxed_config  config;
170    float          tic;
171    float          camtic;
172    vectorf        spherev[SPHERE_VERTICES];
173    GLint          spherei[SPHERE_INDICES];
174    ballman        bman;
175    triman         *tman;
176    GLXContext     *glx_context;
177    GLuint         listobjects;
178    GLuint         gllists[3];
179    Window         window;
180    BOOL           stop;
181    char           *tex1;
182 } boxedstruct;
183
184 #define GLL_PATTERN 0
185 #define GLL_BALL    1
186 #define GLL_BOX     2
187
188 /*
189 **----------------------------------------------------------------------------
190 ** Local Variables
191 **----------------------------------------------------------------------------
192 */
193
194 static boxedstruct *boxed = NULL;
195
196
197 /*
198 **----------------------------------------------------------------------------
199 ** Functions
200 **----------------------------------------------------------------------------
201 */
202
203 /*
204  * Add 2 vectors
205  */ 
206 static inline void addvectors(vectorf *dest, vectorf *s1, vectorf *s2) 
207 {
208    dest->x = s1->x + s2->x;
209    dest->y = s1->y + s2->y;
210    dest->z = s1->z + s2->z;
211 }
212
213 /*
214  * Sub 2 vectors
215  */ 
216 static inline void subvectors(vectorf *dest, vectorf* s1, vectorf *s2) 
217 {
218    dest->x = s1->x - s2->x;
219    dest->y = s1->y - s2->y;
220    dest->z = s1->z - s2->z;
221 }
222
223 /*
224  * Multiply vector with scalar (scale vector)
225  */ 
226 static inline void scalevector(vectorf *dest, vectorf *source, GLfloat sc)
227 {
228    dest->x = source->x * sc;
229    dest->y = source->y * sc;
230    dest->z = source->z * sc;
231 }
232
233 /*
234  * Copy vector
235  */
236 static inline void copyvector(vectorf *dest, vectorf* source) 
237 {
238    dest->x = source->x;
239    dest->y = source->y;
240    dest->z = source->z;
241 }
242
243
244 static inline GLfloat
245 dotproduct(vectorf * v1, vectorf * v2)
246 {
247    return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
248 }
249
250 static inline GLfloat
251 squaremagnitude(vectorf * v)
252 {
253    return v->x * v->x + v->y * v->y + v->z * v->z;
254 }
255
256
257
258 /*
259  * Generate the Sphere data
260  * 
261  * Input: 
262  */ 
263
264 static void generatesphere(boxedstruct *gp)
265 {
266    float   dj = M_PI/(MESH_SIZE+1.0f);
267    float   di = M_PI/MESH_SIZE;
268    int     v;   /* vertex offset */
269    int     ind; /* indices offset */
270    int     i,j,si;
271    GLfloat r_y_plane, h_y_plane;
272    vectorf *spherev;
273    GLint   *spherei;
274    
275    /*
276     * generate the sphere data
277     * vertices 0 and 1 are the north and south poles
278     */
279    
280    spherei = gp->spherei;
281    spherev = gp->spherev;
282    
283    spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
284    spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
285    
286    for (j=0; j<MESH_SIZE; j++) {
287       r_y_plane = (float)sin((j+1) * dj);
288       h_y_plane = (float)cos((j+1) * dj);
289       for (i=0; i<MESH_SIZE*2; i++) {
290          si = 2+i+j*MESH_SIZE*2;
291          spherev[si].y = h_y_plane;
292          spherev[si].x = (float) sin(i * di) * r_y_plane;
293          spherev[si].z = (float) cos(i * di) * r_y_plane;
294       }
295    }
296    
297    /* generate indices */
298    for (i=0; i<MESH_SIZE*2; i++) {
299       spherei[3*i] = 0;
300       spherei[3*i+1] = i+2;
301       spherei[3*i+2] = i+3;
302       if (i==MESH_SIZE*2-1)
303         spherei[3*i+2] = 2;
304    }
305    
306    /* the middle strips */
307    for (j=0; j<MESH_SIZE-1; j++) {
308       v = 2+j*MESH_SIZE*2;
309       ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
310       for (i=0; i<MESH_SIZE*2; i++) {
311          spherei[6*i+ind] = v+i;
312          spherei[6*i+2+ind] = v+i+1;
313          spherei[6*i+1+ind] = v+i+MESH_SIZE*2;
314          
315          spherei[6*i+ind+3] = v+i+MESH_SIZE*2;
316          spherei[6*i+2+ind+3] = v+i+1;
317          spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
318          if (i==MESH_SIZE*2-1) {
319             spherei[6*i+2+ind] = v+i+1-2*MESH_SIZE;
320             spherei[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
321             spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
322          }
323       }
324    }
325    
326    v = SPHERE_VERTICES-MESH_SIZE*2;
327    ind = SPHERE_INDICES-3*MESH_SIZE*2;
328    for (i=0; i<MESH_SIZE*2; i++) {
329       spherei[3*i+ind] = 1;
330       spherei[3*i+1+ind] = v+i+1;
331       spherei[3*i+2+ind] = v+i;
332       if (i==MESH_SIZE*2-1)
333         spherei[3*i+1+ind] = v;
334    }
335 }
336
337       
338       
339     
340 /*
341  * create fresh ball 
342  */
343
344 static void createball(ball *newball) 
345 {
346    float r=0.0f,g=0.0f,b=0.0f;
347    newball->loc.x = 5-10*rnd();
348    newball->loc.y = 35+20*rnd();
349    newball->loc.z = 5-10*rnd();
350    newball->dir.x = (0.5f-rnd()) * speed;
351    newball->dir.y = 0.0;
352    newball->dir.z = (0.5-rnd())  * speed;
353    newball->offside = 0;
354    newball->bounced = FALSE;
355    newball->radius = cfg_ballsize;
356    while (r+g+b < 1.8f ) {
357       newball->color.x = r=rnd();
358       newball->color.y = g=rnd();
359       newball->color.z = b=rnd();
360    }
361    newball->justcreated = TRUE;
362 }
363
364 /* Update position of each ball */
365
366 static void updateballs(ballman *bman) 
367 {
368    register int b,j;
369    vectorf dvect,richting,relspeed,influence;
370    GLfloat squaredist;
371
372    for (b=0;b<bman->num_balls;b++) {
373
374      GLfloat gravity = 0.30f * speed;
375
376       /* apply gravity */
377       bman->balls[b].dir.y -= gravity;
378       /* apply movement */
379       addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
380       /* boundary check */
381       if (bman->balls[b].loc.y < bman->balls[b].radius) { /* ball onder bodem? (bodem @ y=0) */
382          if ((bman->balls[b].loc.x < -95.0) || 
383              (bman->balls[b].loc.x > 95.0) ||
384              (bman->balls[b].loc.z < -95.0) ||
385              (bman->balls[b].loc.z > 95.0)) {
386             if (bman->balls[b].loc.y < -1000.0)
387               createball(&bman->balls[b]);
388          } else {
389             bman->balls[b].loc.y = bman->balls[b].radius  + (bman->balls[b].radius - bman->balls[b].loc.y);
390             bman->balls[b].dir.y = -bman->balls[b].dir.y;
391             if (bman->balls[b].offside) {
392                bman->balls[b].bounced = TRUE; /* temporary disable painting ball */
393                scalevector(&bman->balls[b].dir,&bman->balls[b].dir,0.80f);
394                if (squaremagnitude(&bman->balls[b].dir) < 0.08f) {
395                   createball(&bman->balls[b]);
396                }
397             }
398          }
399          
400       }
401       if (!bman->balls[b].offside) {
402          if (bman->balls[b].loc.x - bman->balls[b].radius < -20.0f) { /* x ondergrens */
403             if (bman->balls[b].loc.y > 41+bman->balls[b].radius)  bman->balls[b].offside=1;
404             else {
405                bman->balls[b].dir.x = -bman->balls[b].dir.x;
406                bman->balls[b].loc.x = -20.0f + bman->balls[b].radius;
407             }
408          }
409          if (bman->balls[b].loc.x + bman->balls[b].radius > 20.0f) { /* x bovengrens */
410             if (bman->balls[b].loc.y > 41+bman->balls[b].radius)  bman->balls[b].offside=1;
411             else {
412                bman->balls[b].dir.x = -bman->balls[b].dir.x;
413                bman->balls[b].loc.x = 20.0f - bman->balls[b].radius;
414             }
415          }
416          if (bman->balls[b].loc.z - bman->balls[b].radius < -20.0f) { /* z ondergrens */
417             if (bman->balls[b].loc.y > 41+bman->balls[b].radius)  bman->balls[b].offside=1;
418             else {
419                bman->balls[b].dir.z = -bman->balls[b].dir.z;
420                bman->balls[b].loc.z = -20.0f + bman->balls[b].radius;
421             }
422          }
423          if (bman->balls[b].loc.z + bman->balls[b].radius > 20.0f) { /* z bovengrens */
424             if (bman->balls[b].loc.y > 41+bman->balls[b].radius)  bman->balls[b].offside=1;
425             else {
426                bman->balls[b].dir.z = -bman->balls[b].dir.z;
427                bman->balls[b].loc.z = 20.0f - bman->balls[b].radius;
428             }
429          }
430       } /* end if !offside */
431    
432       /* check voor stuiteren */
433       for (j=b+1;j<bman->num_balls;j++) {
434          squaredist = (bman->balls[b].radius * bman->balls[b].radius) + (bman->balls[j].radius * bman->balls[j].radius);
435          subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
436          if ( squaremagnitude(&dvect) < squaredist ) { /* balls b and j touch */
437             subvectors(&richting,&bman->balls[j].loc,&bman->balls[b].loc);
438             subvectors(&relspeed,&bman->balls[b].dir,&bman->balls[j].dir);
439             /* calc mutual influence direction and magnitude */
440             scalevector(&influence,&richting,(dotproduct(&richting,&relspeed)/squaremagnitude(&richting)));
441             
442             subvectors(&bman->balls[b].dir,&bman->balls[b].dir,&influence);
443             addvectors(&bman->balls[j].dir,&bman->balls[j].dir,&influence);
444             addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
445             addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
446             
447             subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
448             while (squaremagnitude(&dvect) < squaredist) {
449                addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
450                addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
451                subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
452             }
453          }
454       } /* end for j */
455    } /* end for b */
456 }
457
458
459 /*
460 * explode ball into triangles
461 */
462
463 static void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b)
464 {
465    int pos;
466    float explosion;
467    float scale;
468    register int i;
469    vectorf avgdir,dvect;
470
471    tman->scalefac = b->radius;
472    copyvector(&tman->color,&b->color);
473    explosion = 1.0f + tman->explosion * 2.0 * rnd();
474
475    tman->num_tri = ind_num/3;
476    
477    /* reserveer geheugen voor de poly's in een bal */
478    
479    tman->tris = (tri *)malloc(tman->num_tri * sizeof(tri));
480    tman->vertices = (vectorf *)malloc(ind_num * sizeof(vectorf));
481    tman->normals = (vectorf *)malloc(ind_num/3 * sizeof(vectorf));
482    
483    for (i=0; i<(tman->num_tri); i++) {
484       tman->tris[i].far = FALSE;
485       pos = i * 3;
486       /* kopieer elke poly apart naar een tri structure */
487       copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
488       copyvector(&tman->vertices[pos+1],&spherev[spherei[pos+1]]);
489       copyvector(&tman->vertices[pos+2],&spherev[spherei[pos+2]]);
490       /* Calculate average direction of shrapnel */
491       addvectors(&avgdir,&tman->vertices[pos+0],&tman->vertices[pos+1]);
492       addvectors(&avgdir,&avgdir,&tman->vertices[pos+2]);
493       scalevector(&avgdir,&avgdir,0.33333);
494       
495       /* should normalize first, NYI */
496       copyvector(&tman->normals[i],&avgdir);
497      
498       /* copy de lokatie */
499       addvectors(&tman->tris[i].loc,&b->loc,&avgdir);
500       /* en translate alle triangles terug naar hun eigen oorsprong */
501       tman->vertices[pos+0].x -= avgdir.x;
502       tman->vertices[pos+0].y -= avgdir.y;
503       tman->vertices[pos+0].z -= avgdir.z;
504       tman->vertices[pos+1].x -= avgdir.x;
505       tman->vertices[pos+1].y -= avgdir.y;
506       tman->vertices[pos+1].z -= avgdir.z;
507       tman->vertices[pos+2].x -= avgdir.x;
508       tman->vertices[pos+2].y -= avgdir.y;
509       tman->vertices[pos+2].z -= avgdir.z;
510       /* alwaar opschaling plaatsvindt */
511       scale = b->radius * 2;
512       scalevector(&tman->vertices[pos+0],&tman->vertices[pos+0],scale);
513       scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
514       scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
515             
516       tman->vertices[pos+0].x += avgdir.x;
517       tman->vertices[pos+0].y += avgdir.y;
518       tman->vertices[pos+0].z += avgdir.z;
519       tman->vertices[pos+1].x += avgdir.x;
520       tman->vertices[pos+1].y += avgdir.y;
521       tman->vertices[pos+1].z += avgdir.z;
522       tman->vertices[pos+2].x += avgdir.x;
523       tman->vertices[pos+2].y += avgdir.y;
524       tman->vertices[pos+2].z += avgdir.z;
525
526       /* bereken nieuwe richting */
527       scalevector(&tman->tris[i].dir,&avgdir,explosion);
528       dvect.x = (0.1f - 0.2f*rnd());
529       dvect.y = (0.15f - 0.3f*rnd());
530       dvect.z = (0.1f - 0.2f*rnd());
531       addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
532    }
533 }
534
535
536 /*
537 * update position of each tri
538 */
539
540 static void updatetris(triman *t) 
541 {
542    int b;
543    GLfloat xd,zd;
544    
545    for (b=0;b<t->num_tri;b++) {
546       /* apply gravity */
547       t->tris[b].dir.y -= (0.1f * speed);
548       /* apply movement */
549       addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
550       /* boundary check */
551       if (t->tris[b].far) continue;
552       if (t->tris[b].loc.y < 0) { /* onder bodem ? */
553          if ((t->tris[b].loc.x > -95.0f) &
554              (t->tris[b].loc.x < 95.0f) &
555              (t->tris[b].loc.z > -95.0f) &
556              (t->tris[b].loc.z < 95.0f)) {  /* in veld  */
557             t->tris[b].dir.y = -(t->tris[b].dir.y);
558             t->tris[b].loc.y = -t->tris[b].loc.y;
559             scalevector(&t->tris[b].dir,&t->tris[b].dir,0.80f); /* dampening */
560          }
561          else {
562             t->tris[b].far = TRUE;
563             continue;
564          }
565       }
566       
567       if ((t->tris[b].loc.x > -21.0f) &
568           (t->tris[b].loc.x < 21.0f) &
569           (t->tris[b].loc.z > -21.0f) &
570           (t->tris[b].loc.z < 21.0f)) { /* in box? */
571
572          xd = zd = 999.0f; /* big */
573          if ((t->tris[b].loc.x > -21.0f) &
574              (t->tris[b].loc.x < 0)) {
575             xd = t->tris[b].loc.x + 21.0f;
576          }
577          if ((t->tris[b].loc.x < 21.0f) &
578              (t->tris[b].loc.x > 0)) {
579             xd = 21.0f - t->tris[b].loc.x;
580          }
581          if ((t->tris[b].loc.z > -21.0f) &
582              (t->tris[b].loc.z < 0)) {
583             zd = t->tris[b].loc.z + 21.0f;
584          }
585          if ((t->tris[b].loc.z < 21.0f) &
586              (t->tris[b].loc.z > 0)) {
587             zd = 21.0f - t->tris[b].loc.z;
588          }
589          if (xd < zd) {
590             /* bounce x */
591             if (t->tris[b].dir.x < 0) 
592               t->tris[b].loc.x += (21.0f - t->tris[b].loc.x);
593             else
594               t->tris[b].loc.x += (-21.0f - t->tris[b].loc.x);
595             t->tris[b].dir.x = -t->tris[b].dir.x;
596          } else { 
597             /* bounce z */
598             if (t->tris[b].dir.z < 0)
599               t->tris[b].loc.z += (21.0f - t->tris[b].loc.z);
600             else
601               t->tris[b].loc.z += (-21.0f - t->tris[b].loc.z);
602             t->tris[b].dir.z = -t->tris[b].dir.z;
603          }       
604                
605       }
606    } /* end for b */
607
608
609              
610 /*
611  * free memory allocated by a tri manager
612  */
613 static void freetris(triman *t) 
614 {
615    if (!t) return;
616    if (t->tris) free(t->tris);
617    if (t->vertices) free(t->vertices);
618    if (t->normals) free(t->normals);
619    t->tris = NULL;
620    t->vertices = NULL;
621    t->normals = NULL;
622    t->num_tri = 0;
623    t->lifetime = 0;
624 }
625
626
627 /*
628  *load defaults in config structure
629  */
630 static void setdefaultconfig(boxed_config *config) 
631 {
632   cfg_balls = MAX(3,MIN(40,cfg_balls));
633   cfg_ballsize = MAX(1.0f,MIN(5.0f,cfg_ballsize));
634   cfg_explosion = MAX(0.0f,MIN(50.0f,cfg_explosion));
635   config->numballs = cfg_balls;
636   config->textures = TRUE;
637   config->transparent = FALSE;
638   config->explosion = cfg_explosion;
639   config->ballsize = cfg_ballsize;
640   config->camspeed = 35.0f;
641 }
642
643
644 /*
645  * draw bottom
646  */ 
647 static void drawfilledbox(boxedstruct *boxed, int wire)
648 {   
649    /* draws texture filled box, 
650       top is drawn using the entire texture, 
651       the sides are drawn using the edge of the texture
652     */
653    
654    /* front */
655    glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
656    glTexCoord2f(0,1);
657    glVertex3f(-1.0,1.0,1.0);
658    glTexCoord2f(1,1);
659    glVertex3f(1.0,1.0,1.0);
660    glTexCoord2f(1,1);
661    glVertex3f(1.0,-1.0,1.0);
662    glTexCoord2f(0,1);
663    glVertex3f(-1.0,-1.0,1.0);
664    /* rear */
665    glTexCoord2f(0,1);
666    glVertex3f(1.0,1.0,-1.0);
667    glTexCoord2f(1,1);
668    glVertex3f(-1.0,1.0,-1.0);
669    glTexCoord2f(1,1);
670    glVertex3f(-1.0,-1.0,-1.0);
671    glTexCoord2f(0,1);
672    glVertex3f(1.0,-1.0,-1.0);
673    /* left */
674    glTexCoord2f(1,1);
675    glVertex3f(-1.0,1.0,1.0);
676    glTexCoord2f(1,1);
677    glVertex3f(-1.0,-1.0,1.0);
678    glTexCoord2f(0,1);
679    glVertex3f(-1.0,-1.0,-1.0);
680    glTexCoord2f(0,1);
681    glVertex3f(-1.0,1.0,-1.0);
682    /* right */
683    glTexCoord2f(0,1);
684    glVertex3f(1.0,1.0,1.0);
685    glTexCoord2f(1,1);
686    glVertex3f(1.0,1.0,-1.0);
687    glTexCoord2f(1,1);
688    glVertex3f(1.0,-1.0,-1.0);
689    glTexCoord2f(0,1);
690    glVertex3f(1.0,-1.0,1.0);
691    /* top */
692    glTexCoord2f(0.0,0.0);
693    glVertex3f(-1.0,1.0,1.0);
694    glTexCoord2f(0.0,1.0);
695    glVertex3f(-1.0,1.0,-1.0);
696    glTexCoord2f(1.0,1.0);
697    glVertex3f(1.0,1.0,-1.0);
698    glTexCoord2f(1.0,0.0);
699    glVertex3f(1.0,1.0,1.0);
700    /* bottom */
701    glTexCoord2f(0,0);
702    glVertex3f(-1.0,-1.0,1.0);
703    glTexCoord2f(0,1);
704    glVertex3f(-1.0,-1.0,-1.0);
705    glTexCoord2f(1,1);
706    glVertex3f(1.0,-1.0,-1.0);
707    glTexCoord2f(1,0);
708    glVertex3f(1.0,-1.0,1.0);
709    glEnd();
710 }
711
712
713 /*
714  * Draw a box made of lines
715  */ 
716 static void drawbox(boxedstruct *boxed)
717 {
718    /* top */
719    glBegin(GL_LINE_STRIP);
720    glVertex3f(-1.0,1.0,1.0);
721    glVertex3f(-1.0,1.0,-1.0);
722    glVertex3f(1.0,1.0,-1.0);
723    glVertex3f(1.0,1.0,1.0);
724    glVertex3f(-1.0,1.0,1.0);
725    glEnd();
726    /* bottom */
727    glBegin(GL_LINE_STRIP);
728    glVertex3f(-1.0,-1.0,1.0);
729    glVertex3f(1.0,-1.0,1.0);
730    glVertex3f(1.0,-1.0,-1.0);
731    glVertex3f(-1.0,-1.0,-1.0);
732    glVertex3f(-1.0,-1.0,1.0);
733    glEnd();
734    /* connect top & bottom */
735    glBegin(GL_LINES);
736    glVertex3f(-1.0,1.0,1.0);
737    glVertex3f(-1.0,-1.0,1.0);
738    glVertex3f(1.0,1.0,1.0);
739    glVertex3f(1.0,-1.0,1.0);
740    glVertex3f(1.0,1.0,-1.0);
741    glVertex3f(1.0,-1.0,-1.0);
742    glVertex3f(-1.0,1.0,-1.0);
743    glVertex3f(-1.0,-1.0,-1.0);
744    glEnd();
745 }
746
747
748   
749 /* 
750  * Draw ball
751  */
752 static void drawball(boxedstruct *gp, ball *b, int wire)
753 {
754    int i,pos,cnt;
755    GLint *spherei = gp->spherei;
756    vectorf *spherev = gp->spherev;
757    GLfloat col[3];
758    
759    glPushMatrix();
760    
761    glTranslatef(b->loc.x,b->loc.y,b->loc.z);
762    glScalef(b->radius,b->radius,b->radius);
763    glColor3f(b->color.x,b->color.y,b->color.z);
764    col[0] = b->color.x;
765    col[1] = b->color.y;
766    col[2] = b->color.z;
767    glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
768    col[0] *= 0.5;
769    col[1] *= 0.5;
770    col[2] *= 0.5;
771    glMaterialfv(GL_FRONT, GL_EMISSION,col);
772
773    if (!gp->gllists[GLL_BALL]) {
774       glNewList(gp->listobjects + GLL_BALL,GL_COMPILE);
775       cnt = SPHERE_INDICES/3;
776       for (i=0; i<cnt; i++) {
777          pos = i * 3;
778          glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
779          glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
780          glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
781          glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
782          glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
783          glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
784          glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
785          glEnd();
786       }
787       glEndList();
788       gp->gllists[GLL_BALL] = 1;
789    } else {
790       glCallList(gp->listobjects + GLL_BALL);
791    }
792    
793    glPopMatrix();
794 }
795
796     
797 /* 
798  * Draw all triangles in triman
799  */
800 static void drawtriman(triman *t, int wire) 
801 {
802    int i,pos;
803    vectorf *spherev = t->vertices;
804    GLfloat col[3];
805    
806    glPushMatrix();
807    glColor3f(t->color.x,t->color.y,t->color.z);
808    col[0] = t->color.x;
809    col[1] = t->color.y;
810    col[2] = t->color.z;
811    glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
812    col[0] *= 0.3;
813    col[1] *= 0.3;
814    col[2] *= 0.3;
815    glMaterialfv(GL_FRONT, GL_EMISSION,col);
816    
817    for (i=0; i<t->num_tri; i++) {
818       pos = i*3;
819       glPushMatrix();
820       glTranslatef(t->tris[i].loc.x,t->tris[i].loc.y,t->tris[i].loc.z);
821       glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
822       glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
823       glVertex3f(spherev[pos+0].x,spherev[pos+0].y,spherev[pos+0].z);
824       glVertex3f(spherev[pos+1].x,spherev[pos+1].y,spherev[pos+1].z);
825       glVertex3f(spherev[pos+2].x,spherev[pos+2].y,spherev[pos+2].z);
826       glEnd();
827       glPopMatrix();
828    }   
829    glPopMatrix();   
830 }
831       
832 /* 
833  * draw floor pattern
834  */   
835 static void drawpattern(boxedstruct *gp)
836 {
837    if (!gp->gllists[GLL_PATTERN]) {
838       glNewList(gp->listobjects + GLL_PATTERN, GL_COMPILE);
839      
840       glBegin(GL_LINE_STRIP);
841       glVertex3f(-25.0f, 0.0f, 35.0f);
842       glVertex3f(-15.0f, 0.0f, 35.0f);
843       glVertex3f(-5.0f, 0.0f, 25.0f);
844       glVertex3f(5.0f, 0.0f, 25.0f);
845       glVertex3f(15.0f, 0.0f, 35.0f);
846       glVertex3f(25.0f, 0.0f, 35.0f);
847       glVertex3f(35.0f, 0.0f, 25.0f);
848       glVertex3f(35.0f, 0.0f, 15.0f);
849       glVertex3f(25.0f, 0.0f, 5.0f);
850       glVertex3f(25.0f, 0.0f, -5.0f);
851       glVertex3f(35.0f, 0.0f, -15.0f);
852       glVertex3f(35.0f, 0.0f, -25.0f);
853       glVertex3f(25.0f, 0.0f, -35.0f);
854       glVertex3f(15.0f, 0.0f,-35.0f);
855       glVertex3f(5.0f, 0.0f, -25.0f);
856       glVertex3f(-5.0f, 0.0f, -25.0f);
857       glVertex3f(-15.0f, 0.0f,-35.0f);
858       glVertex3f(-25.0f, 0.0f,-35.0f);
859       glVertex3f(-35.0f, 0.0f, -25.0f);
860       glVertex3f(-35.0f, 0.0f, -15.0f);
861       glVertex3f(-25.0f, 0.0f, -5.0f);
862       glVertex3f(-25.0f, 0.0f, 5.0f);
863       glVertex3f(-35.0f, 0.0f, 15.0f);
864       glVertex3f(-35.0f, 0.0f, 25.0f);
865       glVertex3f(-25.0f, 0.0f, 35.0f);
866       glEnd();
867       
868       glBegin(GL_LINE_STRIP);
869       glVertex3f(-5.0f, 0.0f, 15.0f);
870       glVertex3f(5.0f, 0.0f, 15.0f);
871       glVertex3f(15.0f, 0.0f, 5.0f);
872       glVertex3f(15.0f, 0.0f, -5.0f);
873       glVertex3f(5.0f, 0.0f, -15.0f);
874       glVertex3f(-5.0f, 0.0f, -15.0f);
875       glVertex3f(-15.0f, 0.0f, -5.0f);
876       glVertex3f(-15.0f, 0.0f, 5.0f);
877       glVertex3f(-5.0f, 0.0f, 15.0f);
878       glEnd();
879
880       glEndList();
881       gp->gllists[GLL_PATTERN] = 1;
882    } else {
883       glCallList(gp->listobjects + GLL_PATTERN);
884    }    
885
886 }
887       
888       
889 /*
890  * main rendering loop
891  */
892 static void draw(ModeInfo * mi)
893 {
894    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
895    int wire = MI_IS_WIREFRAME (mi);
896    vectorf v1;
897    GLfloat dcam;
898    int dx, dz;
899    int i;   
900    
901    GLfloat dgray[4] = {0.3f, 0.3f, 0.3f, 1.0f};
902    GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
903    GLfloat lblue[4] = {0.4f,0.6f,1.0f };
904    
905    GLfloat l0_ambient[] =    {0.0, 0.0, 0.0, 1.0};
906    GLfloat l0_specular[] =    {1.0, 1.0, 1.0, 1.0};
907    GLfloat l0_diffuse[] =    {1.0, 1.0, 1.0, 1.0};
908    GLfloat l0_position[] =  {0.0, 0.0, 0.0, 1.0}; /* w != 0 -> positional light */
909    GLfloat l1_ambient[] =    {0.0, 0.0, 0.0, 1.0};
910    GLfloat l1_specular[] =    {1.0, 1.0, 1.0, 1.0};
911    GLfloat l1_diffuse[] =    {0.5, 0.5, 0.5, 1.0};
912    GLfloat l1_position[] =  {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
913    
914    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
915    glLoadIdentity();
916    
917    gp->tic += 0.01f;
918    gp->camtic += 0.01f + 0.01f * sin(gp->tic * speed);
919    
920    /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
921    dcam = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos((gp->camtic/CAMDISTANCE_SPEED) * speed);
922    v1.x = dcam * sin((gp->camtic/gp->cam_x_speed) * speed);
923    v1.z = dcam * cos((gp->camtic/gp->cam_z_speed) * speed);
924    v1.y = CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT;
925    gluLookAt(v1.x,v1.y,v1.z,0.0,0.0,0.0,0.0,1.0,0.0); 
926
927    if (!wire) {
928      glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient); 
929      glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse); 
930      glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular); 
931      glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
932      glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient); 
933      glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse); 
934      glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular); 
935      glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
936      glEnable(GL_LIGHT0);
937      glEnable(GL_LIGHT1);
938    
939      glFrontFace(GL_CW);
940    
941      glMaterialfv(GL_FRONT, GL_SPECULAR, black);
942      glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
943      glMaterialfv(GL_FRONT,GL_AMBIENT,black);
944      glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
945    }
946    
947    
948    /* draw ground grid */
949    /* glDisable(GL_DEPTH_TEST); */
950    glDisable(GL_LIGHTING);
951    
952    glColor3f(0.1,0.1,0.6);
953    for (dx= -2; dx<3; dx++) {
954       for (dz= -2; dz<3; dz++) {
955          glPushMatrix();
956          glTranslatef(dx*30.0f, 0.0f, dz*30.0f);
957          drawpattern(gp);
958          glPopMatrix();
959       }   
960    }
961    
962    /* Set drawing mode for the boxes */
963    glEnable(GL_DEPTH_TEST);
964    if (!wire) glEnable(GL_TEXTURE_2D);
965    glPushMatrix();
966    glColor3f(1.0,1.0,1.0);
967    glScalef(20.0,0.25,20.0);
968    glTranslatef(0.0,2.0,0.0);
969    drawfilledbox(gp, wire);
970    glPopMatrix();
971    glDisable(GL_TEXTURE_2D);
972
973    glPushMatrix();
974    glColor3f(0.2,0.5,0.2);
975    glScalef(20.0,20.0,0.25);
976    glTranslatef(0.0,1.0,81.0);
977    drawbox(gp);
978    glPopMatrix();
979
980    glPushMatrix();
981    glColor3f(0.2,0.5,0.2);
982    glScalef(20.0,20.0,0.25);
983    glTranslatef(0.0,1.0,-81.0);
984    drawbox(gp);
985    glPopMatrix();
986
987    glPushMatrix();
988    glColor3f(0.2,0.5,0.2);
989    glScalef(.25,20.0,20.0);
990    glTranslatef(-81.0,1.0,0.0);
991    drawbox(gp);
992    glPopMatrix();
993
994    glPushMatrix();
995    glColor3f(0.2,0.5,0.2);
996    glScalef(.25,20.0,20.0);
997    glTranslatef(81.0,1.0,0.0);
998    drawbox(gp);
999    glPopMatrix();
1000
1001    if (!wire) {
1002      glEnable(GL_LIGHTING);
1003    
1004      glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
1005      glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
1006    }
1007
1008    /* move the balls and shrapnel */
1009    updateballs(&gp->bman);
1010
1011    glFrontFace(GL_CCW);
1012    for (i=0;i<gp->bman.num_balls;i++) {
1013       if (gp->bman.balls[i].justcreated) {
1014          gp->bman.balls[i].justcreated = FALSE;
1015          freetris(&gp->tman[i]);
1016       }
1017       if (gp->bman.balls[i].bounced) { 
1018          if (gp->tman[i].vertices == NULL) {
1019             createtrisfromball(&gp->tman[i],gp->spherev,gp->spherei,SPHERE_INDICES,&gp->bman.balls[i]);
1020          } else {
1021             updatetris(&gp->tman[i]);
1022          }
1023          glDisable(GL_CULL_FACE);
1024          drawtriman(&gp->tman[i], wire);
1025          if (!wire) glEnable(GL_CULL_FACE);
1026       } else {
1027          drawball(gp, &gp->bman.balls[i], wire);
1028       }
1029    }
1030       
1031    glFlush();
1032 }
1033
1034
1035
1036 /* 
1037  * new window size or exposure 
1038  */
1039 ENTRYPOINT void reshape_boxed(ModeInfo *mi, int width, int height)
1040 {
1041    GLfloat     h = (GLfloat) height / (GLfloat) width;
1042    
1043    glViewport(0, 0, (GLint) width, (GLint) height);
1044    glMatrixMode(GL_PROJECTION);
1045    glLoadIdentity();
1046    gluPerspective(50.0,1/h,2.0,1000.0);
1047    glMatrixMode (GL_MODELVIEW);
1048    
1049    glLineWidth(1);
1050    glPointSize(1);   
1051 }
1052
1053
1054 static void
1055 pinit(ModeInfo * mi)
1056 {
1057    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1058    int wire = MI_IS_WIREFRAME (mi);
1059    ballman *bman;
1060    int i,texpixels;
1061    char *texpixeldata;
1062    char *texpixeltarget;
1063
1064    glShadeModel(GL_SMOOTH);
1065    glClearDepth(1.0);
1066    glClearColor(0.0,0.05,0.1,0.0);
1067    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1068    
1069    /* Load configuration */
1070    setdefaultconfig(&gp->config);
1071    
1072    bman = &gp->bman;
1073    
1074    bman->balls = (ball *)malloc(gp->config.numballs * sizeof(ball));
1075    bman->num_balls = gp->config.numballs;
1076    bman->ballsize = gp->config.ballsize;
1077    bman->explosion = gp->config.explosion;
1078    
1079    gp->tman = (triman *)malloc(bman->num_balls * sizeof(triman));
1080    memset(gp->tman,0,bman->num_balls * sizeof(triman));
1081    
1082    for(i=0;i<bman->num_balls;i++) {
1083       gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
1084       gp->tman[i].vertices = NULL;
1085       gp->tman[i].normals = NULL;
1086       gp->tman[i].tris = NULL;
1087       createball(&bman->balls[i]);
1088       bman->balls[i].loc.y *= rnd();
1089    }
1090
1091    generatesphere(gp);
1092    
1093    if (!wire) {
1094      glEnable(GL_CULL_FACE);
1095      glEnable(GL_LIGHTING);
1096    }
1097
1098    /* define cam path */
1099    gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1100    gp->cam_z_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1101    gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
1102    if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
1103    if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
1104
1105    /* define initial cam position */
1106    gp->tic = gp->camtic = rnd() * 100.0f;
1107    
1108    /* define tex1 (bottom plate) */
1109    gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
1110    texpixels = 256*256; /*width*height;*/
1111    texpixeldata = header_data;
1112    texpixeltarget = gp->tex1;
1113    for (i=0; i < texpixels; i++) {
1114         HEADER_PIXEL(texpixeldata,texpixeltarget);
1115         texpixeltarget += 3;
1116    }
1117    
1118    
1119    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1120
1121    clear_gl_error();
1122    i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
1123                          GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
1124    if (i)
1125      {
1126        const char *s = (char *) gluErrorString (i);
1127        fprintf (stderr, "%s: error mipmapping texture: %s\n",
1128                 progname, (s ? s : "(unknown)"));
1129        exit (1);
1130      }
1131    check_gl_error("mipmapping");
1132
1133    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1134    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1135    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1136    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1137    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1138    
1139 }
1140
1141  
1142
1143 ENTRYPOINT void
1144 init_boxed(ModeInfo * mi)
1145 {
1146    int screen = MI_SCREEN(mi);
1147    
1148    /* Colormap    cmap; */
1149    /* Boolean     rgba, doublebuffer, cmap_installed; */
1150    boxedstruct *gp;
1151
1152    if (boxed == NULL) {
1153       if ((boxed = (boxedstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (boxedstruct))) == NULL) return;
1154    }
1155    gp = &boxed[screen];
1156    gp->window = MI_WINDOW(mi);
1157    
1158    if ((gp->glx_context = init_GL(mi)) != NULL) {
1159       reshape_boxed(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1160       glDrawBuffer(GL_BACK);
1161       if (!glIsList(gp->listobjects))   {
1162          gp->listobjects = glGenLists(3);
1163          gp->gllists[0] = 0;
1164          gp->gllists[1] = 0;
1165          gp->gllists[2] = 0;
1166       }
1167       pinit(mi);
1168    } else {
1169       MI_CLEARWINDOW(mi);
1170    }
1171 }
1172
1173
1174 ENTRYPOINT void
1175 draw_boxed(ModeInfo * mi)
1176 {
1177    boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1178    Display    *display = MI_DISPLAY(mi);
1179    Window      window = MI_WINDOW(mi);
1180    
1181    if (!gp->glx_context)
1182      return;
1183    
1184    glDrawBuffer(GL_BACK);
1185    
1186    glXMakeCurrent(display, window, *(gp->glx_context));
1187    draw(mi);
1188    
1189    if (mi->fps_p) do_fps (mi);
1190    glFinish();
1191    glXSwapBuffers(display, window);
1192 }
1193
1194 ENTRYPOINT void
1195 release_boxed(ModeInfo * mi)
1196 {
1197    int i;
1198    
1199    if (boxed != NULL) {
1200       int screen;
1201       
1202       for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1203          boxedstruct *gp = &boxed[screen];
1204          
1205          if (gp->glx_context) {
1206             /* Display lists MUST be freed while their glXContext is current. */
1207             glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1208             
1209             if (glIsList(gp->listobjects))
1210               glDeleteLists(gp->listobjects, 3);
1211             
1212             for (i=0;i<gp->bman.num_balls;i++) {
1213                if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
1214             }
1215             free (gp->bman.balls);
1216             free (gp->tman);
1217             free (gp->tex1);
1218                  
1219             
1220          }
1221       }
1222       (void) free((void *) boxed);
1223       boxed = NULL;
1224    }
1225    FreeAllGL(mi);
1226 }
1227
1228
1229 XSCREENSAVER_MODULE ("Boxed", boxed)
1230
1231 /*********************************************************/
1232
1233 #endif