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