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