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