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