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