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