1 /* thebox --- 3D bouncing balls that explode */
4 static const char sccsid[] = "@(#)boxed.c 0.9 01/09/26 xlockmore";
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.
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.
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.
28 #include <X11/Intrinsic.h>
32 **----------------------------------------------------------------------------
34 **----------------------------------------------------------------------------
38 # define PROGCLASS "boxed"
39 # define HACK_INIT init_boxed
40 # define HACK_DRAW draw_boxed
41 # define HACK_RESHAPE reshape_boxed
42 # define boxed_opts xlockmore_opts
43 # define DEFAULTS "*delay: 20000 \n" \
44 "*showFPS: False \n" \
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() (frand(1.0))
60 GLfloat speed; /* jwz -- overall speed factor applied to all motion */
63 static XrmOptionDescRec opts[] = {
64 {"-speed", ".boxed.speed", XrmoptionSepArg, 0},
67 static argtype vars[] = {
68 {&speed, "speed", "Speed", "1.0", t_Float},
71 ModeSpecOpt boxed_opts = {countof(opts), opts, countof(vars), vars, NULL};
75 ModStruct boxed_description = {
76 "boxed", "init_boxed", "draw_boxed", "release_boxed",
77 "draw_boxed", "init_boxed", NULL, &boxed_opts,
78 1000, 1, 2, 1, 4, 1.0, "",
79 "Shows GL's boxed balls", 0, NULL};
87 /* rendering defines */
91 #define BOX_SIZE 20.0f
94 #define CAM_HEIGHT 100.0f
95 #define CAMDISTANCE_MIN 20.0
96 #define CAMDISTANCE_MAX 150.0
97 #define CAMDISTANCE_SPEED 1.5
99 /* rendering the sphere */
101 #define SPHERE_VERTICES (2+MESH_SIZE*MESH_SIZE*2)
102 #define SPHERE_INDICES ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
104 #define EXPLOSION 10.0f
107 #define BALLSIZE 3.0f;
110 **-----------------------------------------------------------------------------
112 **-----------------------------------------------------------------------------
167 float cam_x_speed, cam_z_speed, cam_y_speed;
170 vectorf spherev[SPHERE_VERTICES];
171 GLint spherei[SPHERE_INDICES];
174 GLXContext *glx_context;
182 #define GLL_PATTERN 0
187 **----------------------------------------------------------------------------
189 **----------------------------------------------------------------------------
192 static boxedstruct *boxed = NULL;
196 **----------------------------------------------------------------------------
198 **----------------------------------------------------------------------------
204 static inline void addvectors(vectorf *dest, vectorf *s1, vectorf *s2)
206 dest->x = s1->x + s2->x;
207 dest->y = s1->y + s2->y;
208 dest->z = s1->z + s2->z;
214 static inline void subvectors(vectorf *dest, vectorf* s1, vectorf *s2)
216 dest->x = s1->x - s2->x;
217 dest->y = s1->y - s2->y;
218 dest->z = s1->z - s2->z;
222 * Multiply vector with scalar (scale vector)
224 static inline void scalevector(vectorf *dest, vectorf *source, GLfloat sc)
226 dest->x = source->x * sc;
227 dest->y = source->y * sc;
228 dest->z = source->z * sc;
234 static inline void copyvector(vectorf *dest, vectorf* source)
242 static inline GLfloat
243 dotproduct(vectorf * v1, vectorf * v2)
245 return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
248 static inline GLfloat
249 squaremagnitude(vectorf * v)
251 return v->x * v->x + v->y * v->y + v->z * v->z;
257 * Generate the Sphere data
262 static void generatesphere(void)
264 float dj = M_PI/(MESH_SIZE+1.0f);
265 float di = M_PI/MESH_SIZE;
266 int v; /* vertex offset */
267 int ind; /* indices offset */
269 GLfloat r_y_plane, h_y_plane;
274 * generate the sphere data
275 * vertices 0 and 1 are the north and south poles
278 spherei = boxed->spherei;
279 spherev = boxed->spherev;
281 spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
282 spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
284 for (j=0; j<MESH_SIZE; j++) {
285 r_y_plane = (float)sin((j+1) * dj);
286 h_y_plane = (float)cos((j+1) * dj);
287 for (i=0; i<MESH_SIZE*2; i++) {
288 si = 2+i+j*MESH_SIZE*2;
289 spherev[si].y = h_y_plane;
290 spherev[si].x = (float) sin(i * di) * r_y_plane;
291 spherev[si].z = (float) cos(i * di) * r_y_plane;
295 /* generate indices */
296 for (i=0; i<MESH_SIZE*2; i++) {
298 spherei[3*i+1] = i+2;
299 spherei[3*i+2] = i+3;
300 if (i==MESH_SIZE*2-1)
304 /* the middle strips */
305 for (j=0; j<MESH_SIZE-1; j++) {
307 ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
308 for (i=0; i<MESH_SIZE*2; i++) {
309 spherei[6*i+ind] = v+i;
310 spherei[6*i+2+ind] = v+i+1;
311 spherei[6*i+1+ind] = v+i+MESH_SIZE*2;
313 spherei[6*i+ind+3] = v+i+MESH_SIZE*2;
314 spherei[6*i+2+ind+3] = v+i+1;
315 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
316 if (i==MESH_SIZE*2-1) {
317 spherei[6*i+2+ind] = v+i+1-2*MESH_SIZE;
318 spherei[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
319 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
324 v = SPHERE_VERTICES-MESH_SIZE*2;
325 ind = SPHERE_INDICES-3*MESH_SIZE*2;
326 for (i=0; i<MESH_SIZE*2; i++) {
327 spherei[3*i+ind] = 1;
328 spherei[3*i+1+ind] = v+i+1;
329 spherei[3*i+2+ind] = v+i;
330 if (i==MESH_SIZE*2-1)
331 spherei[3*i+1+ind] = v;
342 void createball(ball *newball)
344 float r=0.0f,g=0.0f,b=0.0f;
345 newball->loc.x = 5-10*rnd();
346 newball->loc.y = 35+20*rnd();
347 newball->loc.z = 5-10*rnd();
348 newball->dir.x = (0.5f-rnd()) * speed;
349 newball->dir.y = 0.0;
350 newball->dir.z = (0.5-rnd()) * speed;
351 newball->offside = 0;
352 newball->bounced = FALSE;
353 newball->radius = BALLSIZE;
354 while (r+g+b < 1.7f ) {
355 newball->color.x = r=rnd();
356 newball->color.y = g=rnd();
357 newball->color.z = b=rnd();
359 newball->justcreated = TRUE;
362 /* Update position of each ball */
364 void updateballs(ballman *bman)
367 vectorf dvect,richting,relspeed,influence;
370 for (b=0;b<bman->num_balls;b++) {
372 GLfloat gravity = 0.15f * speed;
375 bman->balls[b].dir.y -= gravity;
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)
467 vectorf avgdir,dvect;
469 tman->scalefac = b->radius;
470 copyvector(&tman->color,&b->color);
471 explosion = 1.0f + tman->explosion * 2.0 * rnd();
473 tman->num_tri = ind_num/3;
475 /* reserveer geheugen voor de poly's in een bal */
477 tman->tris = (tri *)malloc(tman->num_tri * sizeof(tri));
478 tman->vertices = (vectorf *)malloc(ind_num * sizeof(vectorf));
479 tman->normals = (vectorf *)malloc(ind_num/3 * sizeof(vectorf));
481 for (i=0; i<(tman->num_tri); i++) {
482 tman->tris[i].far = FALSE;
484 /* kopieer elke poly apart naar een tri structure */
485 copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
486 copyvector(&tman->vertices[pos+1],&spherev[spherei[pos+1]]);
487 copyvector(&tman->vertices[pos+2],&spherev[spherei[pos+2]]);
488 /* Calculate average direction of shrapnel */
489 addvectors(&avgdir,&tman->vertices[pos+0],&tman->vertices[pos+1]);
490 addvectors(&avgdir,&avgdir,&tman->vertices[pos+2]);
491 scalevector(&avgdir,&avgdir,0.33333);
493 /* should normalize first, NYI */
494 copyvector(&tman->normals[i],&avgdir);
496 /* copy de lokatie */
497 addvectors(&tman->tris[i].loc,&b->loc,&avgdir);
498 /* en translate alle triangles terug naar hun eigen oorsprong */
499 tman->vertices[pos+0].x -= avgdir.x;
500 tman->vertices[pos+0].y -= avgdir.y;
501 tman->vertices[pos+0].z -= avgdir.z;
502 tman->vertices[pos+1].x -= avgdir.x;
503 tman->vertices[pos+1].y -= avgdir.y;
504 tman->vertices[pos+1].z -= avgdir.z;
505 tman->vertices[pos+2].x -= avgdir.x;
506 tman->vertices[pos+2].y -= avgdir.y;
507 tman->vertices[pos+2].z -= avgdir.z;
508 /* alwaar opschaling plaatsvindt */
509 scale = b->radius * 2;
510 scalevector(&tman->vertices[pos+0],&tman->vertices[pos+0],scale);
511 scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
512 scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
514 /* bereken nieuwe richting */
515 scalevector(&tman->tris[i].dir,&avgdir,explosion);
516 dvect.x = (0.1f - 0.2f*rnd());
517 dvect.y = (0.15f - 0.3f*rnd());
518 dvect.z = (0.1f - 0.2f*rnd());
519 addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
525 * update position of each tri
528 void updatetris(triman *t)
533 for (b=0;b<t->num_tri;b++) {
535 t->tris[b].dir.y -= (0.1f * speed);
537 addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
539 if (t->tris[b].far) continue;
540 if (t->tris[b].loc.y < 0) { /* onder bodem ? */
541 if ((t->tris[b].loc.x > -100.0f) &
542 (t->tris[b].loc.x < 100.0f) &
543 (t->tris[b].loc.z > -100.0f) &
544 (t->tris[b].loc.z < 100.0f)) { /* in veld */
545 t->tris[b].dir.y = -(t->tris[b].dir.y);
546 t->tris[b].loc.y = -t->tris[b].loc.y;
547 scalevector(&t->tris[b].dir,&t->tris[b].dir,0.80f); /* dampening */
550 t->tris[b].far = TRUE;
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? */
560 xd = zd = 999.0f; /* big */
561 if ((t->tris[b].loc.x > -21.0f) &
562 (t->tris[b].loc.x < 0)) {
563 xd = t->tris[b].loc.x + 21.0f;
565 if ((t->tris[b].loc.x < 21.0f) &
566 (t->tris[b].loc.x > 0)) {
567 xd = 21.0f - t->tris[b].loc.x;
569 if ((t->tris[b].loc.z > -21.0f) &
570 (t->tris[b].loc.z < 0)) {
571 zd = t->tris[b].loc.z + 21.0f;
573 if ((t->tris[b].loc.z < 21.0f) &
574 (t->tris[b].loc.z > 0)) {
575 zd = 21.0f - t->tris[b].loc.z;
579 if (t->tris[b].dir.x < 0)
580 t->tris[b].loc.x += (21.0f - t->tris[b].loc.x);
582 t->tris[b].loc.x += (-21.0f - t->tris[b].loc.x);
583 t->tris[b].dir.x = -t->tris[b].dir.x;
586 if (t->tris[b].dir.z < 0)
587 t->tris[b].loc.z += (21.0f - t->tris[b].loc.z);
589 t->tris[b].loc.z += (-21.0f - t->tris[b].loc.z);
590 t->tris[b].dir.z = -t->tris[b].dir.z;
599 * free memory allocated by a tri manager
601 void freetris(triman *t)
604 if (t->tris) free(t->tris);
605 if (t->vertices) free(t->vertices);
606 if (t->normals) free(t->normals);
616 *load defaults in config structure
618 void setdefaultconfig(boxed_config *config)
620 config->numballs = NUMBALLS;
621 config->textures = TRUE;
622 config->transparent = FALSE;
623 config->explosion = 25.0f;
624 config->ballsize = BALLSIZE;
625 config->camspeed = 35.0f;
632 static void drawfilledbox(boxedstruct *boxed)
634 /* draws texture filled box,
635 top is drawn using the entire texture,
636 the sides are drawn using the edge of the texture
642 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);
651 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);
660 glVertex3f(-1.0,1.0,1.0);
662 glVertex3f(-1.0,-1.0,1.0);
664 glVertex3f(-1.0,-1.0,-1.0);
666 glVertex3f(-1.0,1.0,-1.0);
669 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 glTexCoord2f(0.0,0.0);
678 glVertex3f(-1.0,1.0,1.0);
679 glTexCoord2f(0.0,1.0);
680 glVertex3f(-1.0,1.0,-1.0);
681 glTexCoord2f(1.0,1.0);
682 glVertex3f(1.0,1.0,-1.0);
683 glTexCoord2f(1.0,0.0);
684 glVertex3f(1.0,1.0,1.0);
687 glVertex3f(-1.0,-1.0,1.0);
689 glVertex3f(-1.0,-1.0,-1.0);
691 glVertex3f(1.0,-1.0,-1.0);
693 glVertex3f(1.0,-1.0,1.0);
699 * Draw a box made of lines
701 static void drawbox(boxedstruct *boxed)
704 glBegin(GL_LINE_STRIP);
705 glVertex3f(-1.0,1.0,1.0);
706 glVertex3f(-1.0,1.0,-1.0);
707 glVertex3f(1.0,1.0,-1.0);
708 glVertex3f(1.0,1.0,1.0);
709 glVertex3f(-1.0,1.0,1.0);
712 glBegin(GL_LINE_STRIP);
713 glVertex3f(-1.0,-1.0,1.0);
714 glVertex3f(1.0,-1.0,1.0);
715 glVertex3f(1.0,-1.0,-1.0);
716 glVertex3f(-1.0,-1.0,-1.0);
717 glVertex3f(-1.0,-1.0,1.0);
719 /* connect top & bottom */
721 glVertex3f(-1.0,1.0,1.0);
722 glVertex3f(-1.0,-1.0,1.0);
723 glVertex3f(1.0,1.0,1.0);
724 glVertex3f(1.0,-1.0,1.0);
725 glVertex3f(1.0,1.0,-1.0);
726 glVertex3f(1.0,-1.0,-1.0);
727 glVertex3f(-1.0,1.0,-1.0);
728 glVertex3f(-1.0,-1.0,-1.0);
737 static void drawball(boxedstruct *gp, ball *b)
740 GLint *spherei = gp->spherei;
741 vectorf *spherev = gp->spherev;
746 glTranslatef(b->loc.x,b->loc.y,b->loc.z);
747 glScalef(b->radius,b->radius,b->radius);
748 glColor3f(b->color.x,b->color.y,b->color.z);
752 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
756 glMaterialfv(GL_FRONT, GL_EMISSION,col);
758 if (!gp->gllists[GLL_BALL]) {
759 glNewList(gp->listobjects + GLL_BALL,GL_COMPILE);
760 cnt = SPHERE_INDICES/3;
761 for (i=0; i<cnt; i++) {
763 glBegin(GL_TRIANGLES);
764 glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
765 glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
766 glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
767 glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
768 glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
769 glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
773 gp->gllists[GLL_BALL] = 1;
775 glCallList(gp->listobjects + GLL_BALL);
783 * Draw all triangles in triman
785 static void drawtriman(triman *t)
788 vectorf *spherev = t->vertices;
792 glColor3f(t->color.x,t->color.y,t->color.z);
796 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
800 glMaterialfv(GL_FRONT, GL_EMISSION,col);
802 for (i=0; i<t->num_tri; i++) {
805 glTranslatef(t->tris[i].loc.x,t->tris[i].loc.y,t->tris[i].loc.z);
806 glBegin(GL_TRIANGLES);
807 glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
808 glVertex3f(spherev[pos+0].x,spherev[pos+0].y,spherev[pos+0].z);
809 glVertex3f(spherev[pos+1].x,spherev[pos+1].y,spherev[pos+1].z);
810 glVertex3f(spherev[pos+2].x,spherev[pos+2].y,spherev[pos+2].z);
820 static void drawpattern(boxedstruct *boxed)
822 if (!boxed->gllists[GLL_PATTERN]) {
823 glNewList(boxed->listobjects + GLL_PATTERN, GL_COMPILE);
825 glBegin(GL_LINE_STRIP);
826 glVertex3f(-25.0f, 0.0f, 35.0f);
827 glVertex3f(-15.0f, 0.0f, 35.0f);
828 glVertex3f(-5.0f, 0.0f, 25.0f);
829 glVertex3f(5.0f, 0.0f, 25.0f);
830 glVertex3f(15.0f, 0.0f, 35.0f);
831 glVertex3f(25.0f, 0.0f, 35.0f);
832 glVertex3f(35.0f, 0.0f, 25.0f);
833 glVertex3f(35.0f, 0.0f, 15.0f);
834 glVertex3f(25.0f, 0.0f, 5.0f);
835 glVertex3f(25.0f, 0.0f, -5.0f);
836 glVertex3f(35.0f, 0.0f, -15.0f);
837 glVertex3f(35.0f, 0.0f, -25.0f);
838 glVertex3f(25.0f, 0.0f, -35.0f);
839 glVertex3f(15.0f, 0.0f,-35.0f);
840 glVertex3f(5.0f, 0.0f, -25.0f);
841 glVertex3f(-5.0f, 0.0f, -25.0f);
842 glVertex3f(-15.0f, 0.0f,-35.0f);
843 glVertex3f(-25.0f, 0.0f,-35.0f);
844 glVertex3f(-35.0f, 0.0f, -25.0f);
845 glVertex3f(-35.0f, 0.0f, -15.0f);
846 glVertex3f(-25.0f, 0.0f, -5.0f);
847 glVertex3f(-25.0f, 0.0f, 5.0f);
848 glVertex3f(-35.0f, 0.0f, 15.0f);
849 glVertex3f(-35.0f, 0.0f, 25.0f);
850 glVertex3f(-25.0f, 0.0f, 35.0f);
853 glBegin(GL_LINE_STRIP);
854 glVertex3f(-5.0f, 0.0f, 15.0f);
855 glVertex3f(5.0f, 0.0f, 15.0f);
856 glVertex3f(15.0f, 0.0f, 5.0f);
857 glVertex3f(15.0f, 0.0f, -5.0f);
858 glVertex3f(5.0f, 0.0f, -15.0f);
859 glVertex3f(-5.0f, 0.0f, -15.0f);
860 glVertex3f(-15.0f, 0.0f, -5.0f);
861 glVertex3f(-15.0f, 0.0f, 5.0f);
862 glVertex3f(-5.0f, 0.0f, 15.0f);
866 boxed->gllists[GLL_PATTERN] = 1;
868 glCallList(boxed->listobjects + GLL_PATTERN);
875 * main rendering loop
877 static void draw(ModeInfo * mi)
879 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
885 GLfloat dgray[4] = {0.3f, 0.3f, 0.3f, 1.0f};
886 GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
887 GLfloat lblue[4] = {0.4f,0.6f,1.0f };
889 GLfloat l0_ambient[] = {0.0, 0.0, 0.0, 1.0};
890 GLfloat l0_specular[] = {1.0, 1.0, 1.0, 1.0};
891 GLfloat l0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
892 GLfloat l0_position[] = {0.0, 0.0, 0.0, 1.0}; /* w != 0 -> positional light */
893 GLfloat l1_ambient[] = {0.0, 0.0, 0.0, 1.0};
894 GLfloat l1_specular[] = {1.0, 1.0, 1.0, 1.0};
895 GLfloat l1_diffuse[] = {0.5, 0.5, 0.5, 1.0};
896 GLfloat l1_position[] = {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
898 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
903 /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
904 dcam = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos((gp->tic/CAMDISTANCE_SPEED) * speed);
905 v1.x = dcam * sin((gp->tic/gp->cam_x_speed) * speed);
906 v1.z = dcam * cos((gp->tic/gp->cam_z_speed) * speed);
907 v1.y = CAM_HEIGHT * sin((gp->tic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT;
908 gluLookAt(v1.x,v1.y,v1.z,0.0,0.0,0.0,0.0,1.0,0.0);
910 glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient);
911 glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse);
912 glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular);
913 glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
914 glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient);
915 glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse);
916 glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular);
917 glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
923 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
924 glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
925 glMaterialfv(GL_FRONT,GL_AMBIENT,black);
926 glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
929 /* draw ground grid */
930 /* glDisable(GL_DEPTH_TEST); */
931 glDisable(GL_LIGHTING);
933 glColor3f(0.1,0.1,0.6);
934 for (dx= -2; dx<3; dx++) {
935 for (dz= -2; dz<3; dz++) {
937 glTranslatef(dx*30.0f, 0.0f, dz*30.0f);
943 /* Set drawing mode for the boxes */
944 glEnable(GL_DEPTH_TEST);
945 glEnable(GL_TEXTURE_2D);
947 glColor3f(1.0,1.0,1.0);
948 glScalef(20.0,0.25,20.0);
949 glTranslatef(0.0,2.0,0.0);
952 glDisable(GL_TEXTURE_2D);
955 glColor3f(0.2,0.5,0.2);
956 glScalef(20.0,20.0,0.25);
957 glTranslatef(0.0,1.0,81.0);
962 glColor3f(0.2,0.5,0.2);
963 glScalef(20.0,20.0,0.25);
964 glTranslatef(0.0,1.0,-81.0);
969 glColor3f(0.2,0.5,0.2);
970 glScalef(.25,20.0,20.0);
971 glTranslatef(-81.0,1.0,0.0);
976 glColor3f(0.2,0.5,0.2);
977 glScalef(.25,20.0,20.0);
978 glTranslatef(81.0,1.0,0.0);
982 glEnable(GL_LIGHTING);
984 glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
985 glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
987 /* move the balls and shrapnel */
988 updateballs(&gp->bman);
991 for (i=0;i<gp->bman.num_balls;i++) {
992 if (gp->bman.balls[i].justcreated) {
993 gp->bman.balls[i].justcreated = FALSE;
994 freetris(&gp->tman[i]);
996 if (gp->bman.balls[i].bounced) {
997 if (gp->tman[i].vertices == NULL) {
998 createtrisfromball(&gp->tman[i],gp->spherev,gp->spherei,SPHERE_INDICES,&gp->bman.balls[i]);
1000 updatetris(&gp->tman[i]);
1002 glDisable(GL_CULL_FACE);
1003 drawtriman(&gp->tman[i]);
1004 glEnable(GL_CULL_FACE);
1006 drawball(gp, &gp->bman.balls[i]);
1016 * new window size or exposure
1018 void reshape_boxed(ModeInfo *mi, int width, int height)
1020 GLfloat h = (GLfloat) height / (GLfloat) width;
1022 glViewport(0, 0, (GLint) width, (GLint) height);
1023 glMatrixMode(GL_PROJECTION);
1025 gluPerspective(50.0,1/h,2.0,1000.0);
1026 glMatrixMode (GL_MODELVIEW);
1034 pinit(ModeInfo * mi)
1036 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1040 char *texpixeltarget;
1042 glShadeModel(GL_SMOOTH);
1044 glClearColor(0.0,0.05,0.1,0.0);
1045 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1047 /* Load configuration */
1048 setdefaultconfig(&gp->config);
1052 bman->balls = (ball *)malloc(gp->config.numballs * sizeof(ball));
1053 bman->num_balls = gp->config.numballs;
1054 bman->ballsize = gp->config.ballsize;
1055 bman->explosion = gp->config.explosion;
1057 gp->tman = (triman *)malloc(bman->num_balls * sizeof(triman));
1058 memset(gp->tman,0,bman->num_balls * sizeof(triman));
1060 for(i=0;i<bman->num_balls;i++) {
1061 gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
1062 gp->tman[i].vertices = NULL;
1063 gp->tman[i].normals = NULL;
1064 gp->tman[i].tris = NULL;
1065 createball(&bman->balls[i]);
1066 bman->balls[i].loc.y *= rnd();
1071 glEnable(GL_CULL_FACE);
1072 glEnable(GL_LIGHTING);
1074 /* define cam path */
1075 gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1076 gp->cam_z_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1077 gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
1078 if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
1079 if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
1082 gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
1083 texpixels = 256*256; /*width*height;*/
1084 texpixeldata = header_data;
1085 texpixeltarget = gp->tex1;
1086 for (i=0; i < texpixels; i++) {
1087 HEADER_PIXEL(texpixeldata,texpixeltarget);
1088 texpixeltarget += 3;
1092 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1095 i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
1096 GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
1099 const char *s = (char *) gluErrorString (i);
1100 fprintf (stderr, "%s: error mipmapping texture: %s\n",
1101 progname, (s ? s : "(unknown)"));
1104 check_gl_error("mipmapping");
1106 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1107 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1108 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1109 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1110 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1117 init_boxed(ModeInfo * mi)
1119 int screen = MI_SCREEN(mi);
1121 /* Colormap cmap; */
1122 /* Boolean rgba, doublebuffer, cmap_installed; */
1125 if (boxed == NULL) {
1126 if ((boxed = (boxedstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (boxedstruct))) == NULL) return;
1128 gp = &boxed[screen];
1129 gp->window = MI_WINDOW(mi);
1131 if ((gp->glx_context = init_GL(mi)) != NULL) {
1132 reshape_boxed(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1133 glDrawBuffer(GL_BACK);
1134 if (!glIsList(gp->listobjects)) {
1135 gp->listobjects = glGenLists(3);
1148 draw_boxed(ModeInfo * mi)
1150 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1151 Display *display = MI_DISPLAY(mi);
1152 Window window = MI_WINDOW(mi);
1154 if (!gp->glx_context)
1157 glDrawBuffer(GL_BACK);
1159 glXMakeCurrent(display, window, *(gp->glx_context));
1162 if (mi->fps_p) do_fps (mi);
1164 glXSwapBuffers(display, window);
1168 release_boxed(ModeInfo * mi)
1172 if (boxed != NULL) {
1175 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1176 boxedstruct *gp = &boxed[screen];
1178 if (gp->glx_context) {
1179 /* Display lists MUST be freed while their glXContext is current. */
1180 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1182 if (glIsList(gp->listobjects))
1183 glDeleteLists(gp->listobjects, 3);
1185 for (i=0;i<gp->bman.num_balls;i++) {
1186 if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
1188 free (gp->bman.balls);
1195 (void) free((void *) boxed);
1202 /*********************************************************/