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