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