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