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