1 /* thebox --- 3D bouncing balls that explode */
3 #if !defined( lint ) && !defined( SABER )
4 static const char sccsid[] = "@(#)boxed.c 0.9 01/09/26 xlockmore";
9 * Permission to use, copy, modify, and distribute this software and its
10 * documentation for any purpose and without fee is hereby granted,
11 * provided that the above copyright notice appear in all copies and that
12 * both that copyright notice and this permission notice appear in
13 * supporting documentation.
15 * This file is provided AS IS with no warranties of any kind. The author
16 * shall have no liability with respect to the infringement of copyrights,
17 * trade secrets or any patents by this file or any part thereof. In no
18 * event will the author be liable for any lost revenue or profits or
19 * other special, indirect and consequential damages.
23 * 2001: Written by Sander van Grieken <mailsander@gmx.net>
24 * as an OpenGL screensaver for the xscreensaver package.
25 * Lots of hardcoded values still in place. Also, there are some
26 * copy/paste leftovers from the gears hack. opts don't work.
29 #include <X11/Intrinsic.h>
33 **----------------------------------------------------------------------------
35 **----------------------------------------------------------------------------
39 # define PROGCLASS "boxed"
40 # define HACK_INIT init_boxed
41 # define HACK_DRAW draw_boxed
42 # define HACK_RESHAPE reshape_boxed
43 # define boxed_opts xlockmore_opts
44 # define DEFAULTS "*delay: 20000 \n" \
45 "*showFPS: False \n" \
47 # include "xlockmore.h" /* from the xscreensaver distribution */
48 #else /* !STANDALONE */
49 # include "xlock.h" /* from the xlockmore distribution */
50 #endif /* !STANDALONE */
56 #define countof(x) (int)(sizeof((x))/sizeof((*x)))
58 #define rnd() ( ((float)random()) / ((float)RAND_MAX * 2.0) )
60 /* #define DEF_PLANETARY "False"
64 static XrmOptionDescRec opts[] = {
65 {"-planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "true" },
66 {"+planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "false" },
69 static argtype vars[] = {
70 {(caddr_t *) &planetary, "planetary", "Planetary", DEF_PLANETARY, t_Bool},
74 /* ModeSpecOpts boxed_opts = {countof(opts), opts, countof(vars), vars, NULL}; */
76 ModeSpecOpt boxed_opts = {0, NULL, 0, NULL, NULL};
80 ModStruct boxed_description = {
81 "boxed", "init_boxed", "draw_boxed", "release_boxed",
82 "draw_boxed", "init_boxed", NULL, &boxed_opts,
83 1000, 1, 2, 1, 4, 1.0, "",
84 "Shows GL's boxed balls", 0, NULL};
92 /* rendering defines */
95 #define BOX_SIZE 20.0f
98 #define CAM_HEIGHT 100.0f
99 #define CAMDISTANCE_MIN 20.0
100 #define CAMDISTANCE_MAX 150.0
101 #define CAMDISTANCE_SPEED 1.5
103 /* rendering the sphere */
105 #define SPHERE_VERTICES (2+MESH_SIZE*MESH_SIZE*2)
106 #define SPHERE_INDICES ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
108 #define EXPLOSION 10.0f
111 #define BALLSIZE 3.0f;
114 **-----------------------------------------------------------------------------
116 **-----------------------------------------------------------------------------
171 float cam_x_speed, cam_z_speed, cam_y_speed;
174 vectorf spherev[SPHERE_VERTICES];
175 GLint spherei[SPHERE_INDICES];
178 GLXContext *glx_context;
186 #define GLL_PATTERN 1
191 **----------------------------------------------------------------------------
193 **----------------------------------------------------------------------------
196 static boxedstruct *boxed = NULL;
200 **----------------------------------------------------------------------------
202 **----------------------------------------------------------------------------
208 static inline void addvectors(vectorf *dest, vectorf *s1, vectorf *s2)
210 dest->x = s1->x + s2->x;
211 dest->y = s1->y + s2->y;
212 dest->z = s1->z + s2->z;
218 static inline void subvectors(vectorf *dest, vectorf* s1, vectorf *s2)
220 dest->x = s1->x - s2->x;
221 dest->y = s1->y - s2->y;
222 dest->z = s1->z - s2->z;
226 * Multiply vector with scalar (scale vector)
228 static inline void scalevector(vectorf *dest, vectorf *source, GLfloat sc)
230 dest->x = source->x * sc;
231 dest->y = source->y * sc;
232 dest->z = source->z * sc;
238 static inline void copyvector(vectorf *dest, vectorf* source)
246 static inline GLfloat
247 dotproduct(vectorf * v1, vectorf * v2)
249 return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
252 static inline GLfloat
253 squaremagnitude(vectorf * v)
255 return v->x * v->x + v->y * v->y + v->z * v->z;
261 * Generate the Sphere data
266 static void generatesphere(void)
268 float dj = M_PI/(MESH_SIZE+1.0f);
269 float di = M_PI/MESH_SIZE;
270 int v; /* vertex offset */
271 int ind; /* indices offset */
273 GLfloat r_y_plane, h_y_plane;
278 * generate the sphere data
279 * vertices 0 and 1 are the north and south poles
282 spherei = boxed->spherei;
283 spherev = boxed->spherev;
285 spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
286 spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
288 for (j=0; j<MESH_SIZE; j++) {
289 r_y_plane = (float)sin((j+1) * dj);
290 h_y_plane = (float)cos((j+1) * dj);
291 for (i=0; i<MESH_SIZE*2; i++) {
292 si = 2+i+j*MESH_SIZE*2;
293 spherev[si].y = h_y_plane;
294 spherev[si].x = (float) sin(i * di) * r_y_plane;
295 spherev[si].z = (float) cos(i * di) * r_y_plane;
299 /* generate indices */
300 for (i=0; i<MESH_SIZE*2; i++) {
302 spherei[3*i+1] = i+2;
303 spherei[3*i+2] = i+3;
304 if (i==MESH_SIZE*2-1)
308 /* the middle strips */
309 for (j=0; j<MESH_SIZE-1; j++) {
311 ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
312 for (i=0; i<MESH_SIZE*2; i++) {
313 spherei[6*i+ind] = v+i;
314 spherei[6*i+2+ind] = v+i+1;
315 spherei[6*i+1+ind] = v+i+MESH_SIZE*2;
317 spherei[6*i+ind+3] = v+i+MESH_SIZE*2;
318 spherei[6*i+2+ind+3] = v+i+1;
319 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
320 if (i==MESH_SIZE*2-1) {
321 spherei[6*i+2+ind] = v+i+1-2*MESH_SIZE;
322 spherei[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
323 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
328 v = SPHERE_VERTICES-MESH_SIZE*2;
329 ind = SPHERE_INDICES-3*MESH_SIZE*2;
330 for (i=0; i<MESH_SIZE*2; i++) {
331 spherei[3*i+ind] = 1;
332 spherei[3*i+1+ind] = v+i+1;
333 spherei[3*i+2+ind] = v+i;
334 if (i==MESH_SIZE*2-1)
335 spherei[3*i+1+ind] = v;
346 void createball(ball *newball) {
347 float r=0.0f,g=0.0f,b=0.0f;
348 newball->loc.x = 5-10*rnd();
349 newball->loc.y = 35+20*rnd();
350 newball->loc.z = 5-10*rnd();
351 newball->dir.x = 0.5f-rnd();
352 newball->dir.y = 0.0;
353 newball->dir.z = 0.5-rnd();
354 newball->offside = 0;
355 newball->bounced = FALSE;
356 newball->radius = BALLSIZE;
357 while (r+g+b < 1.7f ) {
358 newball->color.x = r=rnd();
359 newball->color.y = g=rnd();
360 newball->color.z = b=rnd();
362 newball->justcreated = TRUE;
365 /* Update position of each ball */
367 void updateballs(ballman *bman) {
369 vectorf dvect,richting,relspeed,influence;
372 for (b=0;b<bman->num_balls;b++) {
375 bman->balls[b].dir.y -= 0.15f;
377 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
379 if (bman->balls[b].loc.y < bman->balls[b].radius) { /* ball onder bodem? (bodem @ y=0) */
380 if ((bman->balls[b].loc.x < -100.0) ||
381 (bman->balls[b].loc.x > 100.0) ||
382 (bman->balls[b].loc.z < -100.0) ||
383 (bman->balls[b].loc.z > 100.0)) {
384 if (bman->balls[b].loc.y < -1000.0)
385 createball(&bman->balls[b]);
387 bman->balls[b].loc.y = bman->balls[b].radius + (bman->balls[b].radius - bman->balls[b].loc.y);
388 bman->balls[b].dir.y = -bman->balls[b].dir.y;
389 if (bman->balls[b].offside) {
390 bman->balls[b].bounced = TRUE; /* temporary disable painting ball */
391 scalevector(&bman->balls[b].dir,&bman->balls[b].dir,0.80f);
392 if (squaremagnitude(&bman->balls[b].dir) < 0.08f) {
393 createball(&bman->balls[b]);
399 if (!bman->balls[b].offside) {
400 if (bman->balls[b].loc.x - bman->balls[b].radius < -20.0f) { /* x ondergrens */
401 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
403 bman->balls[b].dir.x = -bman->balls[b].dir.x;
404 bman->balls[b].loc.x = -20.0f + bman->balls[b].radius;
407 if (bman->balls[b].loc.x + bman->balls[b].radius > 20.0f) { /* x bovengrens */
408 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
410 bman->balls[b].dir.x = -bman->balls[b].dir.x;
411 bman->balls[b].loc.x = 20.0f - bman->balls[b].radius;
414 if (bman->balls[b].loc.z - bman->balls[b].radius < -20.0f) { /* z ondergrens */
415 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
417 bman->balls[b].dir.z = -bman->balls[b].dir.z;
418 bman->balls[b].loc.z = -20.0f + bman->balls[b].radius;
421 if (bman->balls[b].loc.z + bman->balls[b].radius > 20.0f) { /* z bovengrens */
422 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
424 bman->balls[b].dir.z = -bman->balls[b].dir.z;
425 bman->balls[b].loc.z = 20.0f - bman->balls[b].radius;
428 } /* end if !offside */
430 /* check voor stuiteren */
431 for (j=b+1;j<bman->num_balls;j++) {
432 squaredist = (bman->balls[b].radius * bman->balls[b].radius) + (bman->balls[j].radius * bman->balls[j].radius);
433 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
434 if ( squaremagnitude(&dvect) < squaredist ) { /* balls b and j touch */
435 subvectors(&richting,&bman->balls[j].loc,&bman->balls[b].loc);
436 subvectors(&relspeed,&bman->balls[b].dir,&bman->balls[j].dir);
437 /* calc mutual influence direction and magnitude */
438 scalevector(&influence,&richting,(dotproduct(&richting,&relspeed)/squaremagnitude(&richting)));
440 subvectors(&bman->balls[b].dir,&bman->balls[b].dir,&influence);
441 addvectors(&bman->balls[j].dir,&bman->balls[j].dir,&influence);
442 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
443 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
445 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
446 while (squaremagnitude(&dvect) < squaredist) {
447 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
448 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
449 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
458 * explode ball into triangles
461 void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b) {
466 vectorf avgdir,dvect;
468 tman->scalefac = b->radius;
469 copyvector(&tman->color,&b->color);
470 explosion = 1.0f + tman->explosion * 2.0 * rnd();
472 tman->num_tri = ind_num/3;
474 /* reserveer geheugen voor de poly's in een bal */
476 tman->tris = (tri *)malloc(tman->num_tri * sizeof(tri));
477 tman->vertices = (vectorf *)malloc(ind_num * sizeof(vectorf));
478 tman->normals = (vectorf *)malloc(ind_num/3 * sizeof(vectorf));
480 for (i=0; i<(tman->num_tri); i++) {
481 tman->tris[i].far = FALSE;
483 /* kopieer elke poly apart naar een tri structure */
484 copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
485 copyvector(&tman->vertices[pos+1],&spherev[spherei[pos+1]]);
486 copyvector(&tman->vertices[pos+2],&spherev[spherei[pos+2]]);
487 /* Calculate average direction of shrapnel */
488 addvectors(&avgdir,&tman->vertices[pos+0],&tman->vertices[pos+1]);
489 addvectors(&avgdir,&avgdir,&tman->vertices[pos+2]);
490 scalevector(&avgdir,&avgdir,0.33333);
492 /* should normalize first, NYI */
493 copyvector(&tman->normals[i],&avgdir);
495 /* copy de lokatie */
496 addvectors(&tman->tris[i].loc,&b->loc,&avgdir);
497 /* en translate alle triangles terug naar hun eigen oorsprong */
498 tman->vertices[pos+0].x -= avgdir.x;
499 tman->vertices[pos+0].y -= avgdir.y;
500 tman->vertices[pos+0].z -= avgdir.z;
501 tman->vertices[pos+1].x -= avgdir.x;
502 tman->vertices[pos+1].y -= avgdir.y;
503 tman->vertices[pos+1].z -= avgdir.z;
504 tman->vertices[pos+2].x -= avgdir.x;
505 tman->vertices[pos+2].y -= avgdir.y;
506 tman->vertices[pos+2].z -= avgdir.z;
507 /* alwaar opschaling plaatsvindt */
508 scale = b->radius * 2;
509 scalevector(&tman->vertices[pos+0],&tman->vertices[pos+0],scale);
510 scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
511 scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
513 /* bereken nieuwe richting */
514 scalevector(&tman->tris[i].dir,&avgdir,explosion);
515 dvect.x = 0.1f - 0.2f*rnd();
516 dvect.y = 0.15f - 0.3f*rnd();
517 dvect.z = 0.1f - 0.2f*rnd();
518 addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
524 * update position of each tri
527 void updatetris(triman *t) {
530 for (b=0;b<t->num_tri;b++) {
532 t->tris[b].dir.y -= 0.1f;
534 addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
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.75f); /* dampening */
547 t->tris[b].far = TRUE;
552 /* this should be replaced with code that determines
553 * the correct wall the tri bounces in to. this code sucks.
555 if ((t->tris[b].loc.x > -21.0f) &
556 (t->tris[b].loc.x < 21.0f) &
557 (t->tris[b].loc.z > -21.0f) &
558 (t->tris[b].loc.z < 21.0f)) { /* in box? */
559 if ((t->tris[b].loc.x > -21.0f) &
560 (t->tris[b].loc.x < 0)) {
561 t->tris[b].loc.x = -21.0f;
562 t->tris[b].dir.x = -t->tris[b].dir.x;
564 if ((t->tris[b].loc.x < 21.0f) &
565 (t->tris[b].loc.x > 0)) {
566 t->tris[b].loc.x = 21.0f;
567 t->tris[b].dir.x = -t->tris[b].dir.x;
569 if ((t->tris[b].loc.z > -21.0f) &
570 (t->tris[b].loc.z < 0)) {
571 t->tris[b].loc.z = -21.0f;
572 t->tris[b].dir.z = -t->tris[b].dir.z;
574 if ((t->tris[b].loc.z < 21.0f) &
575 (t->tris[b].loc.z > 0)) {
576 t->tris[b].loc.z = 21.0f;
577 t->tris[b].dir.z = -t->tris[b].dir.z;
585 * free memory allocated by a tri manager
587 void freetris(triman *t) {
589 if (t->tris) free(t->tris);
590 if (t->vertices) free(t->vertices);
591 if (t->normals) free(t->normals);
601 *load defaults in config structure
603 void setdefaultconfig(boxed_config *config) {
604 config->numballs = NUMBALLS;
605 config->textures = TRUE;
606 config->transparent = FALSE;
607 config->explosion = 25.0f;
608 config->ballsize = BALLSIZE;
609 config->camspeed = 35.0f;
616 static void drawfilledbox(boxedstruct *boxed)
618 /* draws texture filled box,
619 top is drawn using the entire texture,
620 the sides are drawn using the edge of the texture
626 glVertex3f(-1.0,1.0,1.0);
628 glVertex3f(1.0,1.0,1.0);
630 glVertex3f(1.0,-1.0,1.0);
632 glVertex3f(-1.0,-1.0,1.0);
635 glVertex3f(1.0,1.0,-1.0);
637 glVertex3f(-1.0,1.0,-1.0);
639 glVertex3f(-1.0,-1.0,-1.0);
641 glVertex3f(1.0,-1.0,-1.0);
644 glVertex3f(-1.0,1.0,1.0);
646 glVertex3f(-1.0,-1.0,1.0);
648 glVertex3f(-1.0,-1.0,-1.0);
650 glVertex3f(-1.0,1.0,-1.0);
653 glVertex3f(1.0,1.0,1.0);
655 glVertex3f(1.0,1.0,-1.0);
657 glVertex3f(1.0,-1.0,-1.0);
659 glVertex3f(1.0,-1.0,1.0);
661 glTexCoord2f(0.0,0.0);
662 glVertex3f(-1.0,1.0,1.0);
663 glTexCoord2f(0.0,1.0);
664 glVertex3f(-1.0,1.0,-1.0);
665 glTexCoord2f(1.0,1.0);
666 glVertex3f(1.0,1.0,-1.0);
667 glTexCoord2f(1.0,0.0);
668 glVertex3f(1.0,1.0,1.0);
671 glVertex3f(-1.0,-1.0,1.0);
673 glVertex3f(-1.0,-1.0,-1.0);
675 glVertex3f(1.0,-1.0,-1.0);
677 glVertex3f(1.0,-1.0,1.0);
683 * Draw a box made of lines
685 static void drawbox(boxedstruct *boxed)
688 glBegin(GL_LINE_STRIP);
689 glVertex3f(-1.0,1.0,1.0);
690 glVertex3f(-1.0,1.0,-1.0);
691 glVertex3f(1.0,1.0,-1.0);
692 glVertex3f(1.0,1.0,1.0);
693 glVertex3f(-1.0,1.0,1.0);
696 glBegin(GL_LINE_STRIP);
697 glVertex3f(-1.0,-1.0,1.0);
698 glVertex3f(1.0,-1.0,1.0);
699 glVertex3f(1.0,-1.0,-1.0);
700 glVertex3f(-1.0,-1.0,-1.0);
701 glVertex3f(-1.0,-1.0,1.0);
703 /* connect top & bottom */
705 glVertex3f(-1.0,1.0,1.0);
706 glVertex3f(-1.0,-1.0,1.0);
707 glVertex3f(1.0,1.0,1.0);
708 glVertex3f(1.0,-1.0,1.0);
709 glVertex3f(1.0,1.0,-1.0);
710 glVertex3f(1.0,-1.0,-1.0);
711 glVertex3f(-1.0,1.0,-1.0);
712 glVertex3f(-1.0,-1.0,-1.0);
721 static void drawball(boxedstruct *gp, ball *b)
724 GLint *spherei = gp->spherei;
725 vectorf *spherev = gp->spherev;
730 glTranslatef(b->loc.x,b->loc.y,b->loc.z);
731 glScalef(b->radius,b->radius,b->radius);
732 glColor3f(b->color.x,b->color.y,b->color.z);
736 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
740 glMaterialfv(GL_FRONT, GL_EMISSION,col);
742 if (!gp->gllists[GLL_BALL]) {
743 glNewList(gp->listobjects + GLL_BALL,GL_COMPILE_AND_EXECUTE);
744 cnt = SPHERE_INDICES/3;
745 for (i=0; i<cnt; i++) {
747 glBegin(GL_TRIANGLES);
748 glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
749 glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
750 glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
751 glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
752 glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
753 glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
757 gp->gllists[GLL_BALL] = 1;
759 glCallList(gp->listobjects + GLL_BALL);
767 * Draw all triangles in triman
769 static void drawtriman(triman *t)
772 vectorf *spherev = t->vertices;
776 glColor3f(t->color.x,t->color.y,t->color.z);
780 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
784 glMaterialfv(GL_FRONT, GL_EMISSION,col);
786 for (i=0; i<t->num_tri; i++) {
789 glTranslatef(t->tris[i].loc.x,t->tris[i].loc.y,t->tris[i].loc.z);
790 glBegin(GL_TRIANGLES);
791 glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
792 glVertex3f(spherev[pos+0].x,spherev[pos+0].y,spherev[pos+0].z);
793 glVertex3f(spherev[pos+1].x,spherev[pos+1].y,spherev[pos+1].z);
794 glVertex3f(spherev[pos+2].x,spherev[pos+2].y,spherev[pos+2].z);
804 static void drawpattern(boxedstruct *boxed)
806 if (!boxed->gllists[GLL_PATTERN]) {
807 glNewList(boxed->listobjects + GLL_PATTERN,GL_COMPILE_AND_EXECUTE);
809 glBegin(GL_LINE_STRIP);
810 glVertex3f(-25.0f, 0.0f, 35.0f);
811 glVertex3f(-15.0f, 0.0f, 35.0f);
812 glVertex3f(-5.0f, 0.0f, 25.0f);
813 glVertex3f(5.0f, 0.0f, 25.0f);
814 glVertex3f(15.0f, 0.0f, 35.0f);
815 glVertex3f(25.0f, 0.0f, 35.0f);
816 glVertex3f(35.0f, 0.0f, 25.0f);
817 glVertex3f(35.0f, 0.0f, 15.0f);
818 glVertex3f(25.0f, 0.0f, 5.0f);
819 glVertex3f(25.0f, 0.0f, -5.0f);
820 glVertex3f(35.0f, 0.0f, -15.0f);
821 glVertex3f(35.0f, 0.0f, -25.0f);
822 glVertex3f(25.0f, 0.0f, -35.0f);
823 glVertex3f(15.0f, 0.0f,-35.0f);
824 glVertex3f(5.0f, 0.0f, -25.0f);
825 glVertex3f(-5.0f, 0.0f, -25.0f);
826 glVertex3f(-15.0f, 0.0f,-35.0f);
827 glVertex3f(-25.0f, 0.0f,-35.0f);
828 glVertex3f(-35.0f, 0.0f, -25.0f);
829 glVertex3f(-35.0f, 0.0f, -15.0f);
830 glVertex3f(-25.0f, 0.0f, -5.0f);
831 glVertex3f(-25.0f, 0.0f, 5.0f);
832 glVertex3f(-35.0f, 0.0f, 15.0f);
833 glVertex3f(-35.0f, 0.0f, 25.0f);
834 glVertex3f(-25.0f, 0.0f, 35.0f);
837 glBegin(GL_LINE_STRIP);
838 glVertex3f(-5.0f, 0.0f, 15.0f);
839 glVertex3f(5.0f, 0.0f, 15.0f);
840 glVertex3f(15.0f, 0.0f, 5.0f);
841 glVertex3f(15.0f, 0.0f, -5.0f);
842 glVertex3f(5.0f, 0.0f, -15.0f);
843 glVertex3f(-5.0f, 0.0f, -15.0f);
844 glVertex3f(-15.0f, 0.0f, -5.0f);
845 glVertex3f(-15.0f, 0.0f, 5.0f);
846 glVertex3f(-5.0f, 0.0f, 15.0f);
849 boxed->gllists[GLL_PATTERN] = 1;
851 glCallList(boxed->listobjects + GLL_PATTERN);
857 * main rendering loop
859 static void draw(ModeInfo * mi)
861 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
867 GLfloat dgray[4] = {0.3f, 0.3f, 0.3f, 1.0f};
868 GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
869 GLfloat lblue[4] = {0.4f,0.6f,1.0f };
871 GLfloat l0_ambient[] = {0.0, 0.0, 0.0, 1.0};
872 GLfloat l0_specular[] = {1.0, 1.0, 1.0, 1.0};
873 GLfloat l0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
874 GLfloat l0_position[] = {0.0, 0.0, 0.0, 1.0}; /* w != 0 -> positional light */
875 GLfloat l1_ambient[] = {0.0, 0.0, 0.0, 1.0};
876 GLfloat l1_specular[] = {1.0, 1.0, 1.0, 1.0};
877 GLfloat l1_diffuse[] = {0.5, 0.5, 0.5, 1.0};
878 GLfloat l1_position[] = {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
880 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
885 /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
886 dcam = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos(gp->tic/CAMDISTANCE_SPEED);
887 v1.x = dcam * sin(gp->tic/gp->cam_x_speed);
888 v1.z = dcam * cos(gp->tic/gp->cam_z_speed);
889 v1.y = CAM_HEIGHT * sin(gp->tic/gp->cam_y_speed) + 1.02 * CAM_HEIGHT;
890 gluLookAt(v1.x,v1.y,v1.z,0.0,0.0,0.0,0.0,1.0,0.0);
892 glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient);
893 glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse);
894 glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular);
895 glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
896 glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient);
897 glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse);
898 glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular);
899 glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
905 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
906 glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
907 glMaterialfv(GL_FRONT,GL_AMBIENT,black);
908 glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
911 /* draw ground grid */
912 /* glDisable(GL_DEPTH_TEST); */
913 glDisable(GL_LIGHTING);
915 glColor3f(0.1,0.1,0.6);
916 for (dx= -2; dx<3; dx++) {
917 for (dz= -2; dz<3; dz++) {
919 glTranslatef(dx*30.0f, 0.0f, dz*30.0f);
925 /* Set drawing mode for the boxes */
926 glEnable(GL_DEPTH_TEST);
927 glEnable(GL_TEXTURE_2D);
929 glColor3f(1.0,1.0,1.0);
930 glScalef(20.0,0.25,20.0);
931 glTranslatef(0.0,2.0,0.0);
934 glDisable(GL_TEXTURE_2D);
937 glColor3f(0.2,0.5,0.2);
938 glScalef(20.0,20.0,0.25);
939 glTranslatef(0.0,1.0,81.0);
944 glColor3f(0.2,0.5,0.2);
945 glScalef(20.0,20.0,0.25);
946 glTranslatef(0.0,1.0,-81.0);
951 glColor3f(0.2,0.5,0.2);
952 glScalef(.25,20.0,20.0);
953 glTranslatef(-81.0,1.0,0.0);
958 glColor3f(0.2,0.5,0.2);
959 glScalef(.25,20.0,20.0);
960 glTranslatef(81.0,1.0,0.0);
964 glEnable(GL_LIGHTING);
966 glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
967 glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
969 /* move the balls and shrapnel */
970 updateballs(&gp->bman);
973 for (i=0;i<gp->bman.num_balls;i++) {
974 if (gp->bman.balls[i].justcreated) {
975 gp->bman.balls[i].justcreated = FALSE;
976 freetris(&gp->tman[i]);
978 if ((gp->bman.balls[i].bounced) & (gp->tman[i].vertices == NULL)) {
979 createtrisfromball(&gp->tman[i],gp->spherev,gp->spherei,SPHERE_INDICES,&gp->bman.balls[i]);
981 if (gp->bman.balls[i].bounced) {
982 updatetris(&gp->tman[i]);
983 glDisable(GL_CULL_FACE);
984 drawtriman(&gp->tman[i]);
985 glEnable(GL_CULL_FACE);
987 drawball(gp, &gp->bman.balls[i]);
997 * new window size or exposure
999 void reshape_boxed(ModeInfo *mi, int width, int height)
1001 GLfloat h = (GLfloat) height / (GLfloat) width;
1003 glViewport(0, 0, (GLint) width, (GLint) height);
1004 glMatrixMode(GL_PROJECTION);
1006 gluPerspective(50.0,1/h,2.0,1000.0);
1007 glMatrixMode (GL_MODELVIEW);
1015 pinit(ModeInfo * mi)
1017 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1021 char *texpixeltarget;
1023 glShadeModel(GL_SMOOTH);
1025 glClearColor(0.0,0.05,0.1,0.0);
1026 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1028 /* Load configuration */
1029 setdefaultconfig(&gp->config);
1033 bman->balls = (ball *)malloc(gp->config.numballs * sizeof(ball));
1034 bman->num_balls = gp->config.numballs;
1035 bman->ballsize = gp->config.ballsize;
1036 bman->explosion = gp->config.explosion;
1038 gp->tman = (triman *)malloc(bman->num_balls * sizeof(triman));
1039 memset(gp->tman,0,bman->num_balls * sizeof(triman));
1041 for(i=0;i<bman->num_balls;i++) {
1042 gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
1043 gp->tman[i].vertices = NULL;
1044 gp->tman[i].normals = NULL;
1045 gp->tman[i].tris = NULL;
1046 createball(&bman->balls[i]);
1047 bman->balls[i].loc.y *= rnd();
1052 glEnable(GL_CULL_FACE);
1053 glEnable(GL_LIGHTING);
1055 /* define cam path */
1056 gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1057 gp->cam_z_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1058 gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
1059 if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
1060 if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
1063 gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
1064 texpixels = 256*256; /*width*height;*/
1065 texpixeldata = header_data;
1066 texpixeltarget = gp->tex1;
1067 for (i=0; i < texpixels; i++) {
1068 HEADER_PIXEL(texpixeldata,texpixeltarget);
1069 texpixeltarget += 3;
1073 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1076 i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
1077 GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
1080 const char *s = gluErrorString (i);
1081 fprintf (stderr, "%s: error mipmapping texture: %s\n",
1082 progname, (s ? s : "(unknown)"));
1085 check_gl_error("mipmapping");
1087 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1088 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1089 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1090 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1091 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1098 init_boxed(ModeInfo * mi)
1100 int screen = MI_SCREEN(mi);
1102 /* Colormap cmap; */
1103 /* Boolean rgba, doublebuffer, cmap_installed; */
1106 if (boxed == NULL) {
1107 if ((boxed = (boxedstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (boxedstruct))) == NULL) return;
1109 gp = &boxed[screen];
1110 gp->window = MI_WINDOW(mi);
1112 if ((gp->glx_context = init_GL(mi)) != NULL) {
1113 reshape_boxed(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1114 glDrawBuffer(GL_BACK);
1115 if (!glIsList(gp->listobjects)) {
1116 gp->listobjects = glGenLists(3);
1129 draw_boxed(ModeInfo * mi)
1131 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1132 Display *display = MI_DISPLAY(mi);
1133 Window window = MI_WINDOW(mi);
1135 if (!gp->glx_context)
1138 glDrawBuffer(GL_BACK);
1140 glXMakeCurrent(display, window, *(gp->glx_context));
1143 if (mi->fps_p) do_fps (mi);
1145 glXSwapBuffers(display, window);
1149 release_boxed(ModeInfo * mi)
1151 if (boxed != NULL) {
1154 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1155 boxedstruct *gp = &boxed[screen];
1157 if (gp->glx_context) {
1158 /* Display lists MUST be freed while their glXContext is current. */
1159 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1161 /*if (glIsList(gp->gear1))
1162 glDeleteLists(gp->gear1, 1);
1163 if (glIsList(gp->gear2))
1164 glDeleteLists(gp->gear2, 1);
1165 if (glIsList(gp->gear3))
1166 glDeleteLists(gp->gear3, 1);
1167 if (glIsList(gp->gear_inner))
1168 glDeleteLists(gp->gear_inner, 1);
1169 if (glIsList(gp->gear_outer))
1170 glDeleteLists(gp->gear_outer, 1);
1176 * free all sphere indices & vertices
1181 (void) free((void *) boxed);
1188 /*********************************************************/