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