1 /* boxed --- 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.
27 * 2005: opts work. added options -balls, -ballsize, -explosion
34 **----------------------------------------------------------------------------
36 **----------------------------------------------------------------------------
40 # define DEFAULTS "*delay: 20000 \n" \
41 "*showFPS: False \n" \
42 "*wireframe: False \n"
44 # define refresh_boxed 0
45 # define boxed_handle_event 0
46 # include "xlockmore.h" /* from the xscreensaver distribution */
47 #else /* !STANDALONE */
48 # include "xlock.h" /* from the xlockmore distribution */
49 #endif /* !STANDALONE */
53 # define DEF_SPEED "0.5"
54 # define DEF_BALLS "25"
55 # define DEF_BALLSIZE "2.0"
56 # define DEF_EXPLOSION "15.0"
57 # define DEF_DECAY "0.1"
60 #define countof(x) (int)(sizeof((x))/sizeof((*x)))
62 #define rnd() (frand(1.0))
64 static GLfloat speed; /* jwz -- overall speed factor applied to all motion */
66 static GLfloat cfg_ballsize;
67 static GLfloat cfg_explosion;
68 static GLfloat cfg_decay;
71 static XrmOptionDescRec opts[] = {
72 {"-speed", ".boxed.speed", XrmoptionSepArg, 0},
73 {"-balls", ".boxed.balls", XrmoptionSepArg, 0},
74 {"-ballsize", ".boxed.ballsize", XrmoptionSepArg, 0},
75 {"-explosion", ".boxed.explosion", XrmoptionSepArg, 0},
76 {"-decay", ".boxed.decay", XrmoptionSepArg, 0},
79 static argtype vars[] = {
80 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
81 {&cfg_balls, "balls", "Balls", DEF_BALLS, t_Int},
82 {&cfg_ballsize, "ballsize", "Ball Size", DEF_BALLSIZE, t_Float},
83 {&cfg_explosion, "explosion", "Explosion", DEF_EXPLOSION, t_Float},
84 {&cfg_decay, "decay", "Explosion Decay", DEF_DECAY, t_Float},
87 ENTRYPOINT ModeSpecOpt boxed_opts = {countof(opts), opts, countof(vars), vars, NULL};
91 ModStruct boxed_description = {
92 "boxed", "init_boxed", "draw_boxed", "release_boxed",
93 "draw_boxed", "init_boxed", NULL, &boxed_opts,
94 1000, 1, 2, 1, 4, 1.0, "",
95 "Shows GL's boxed balls", 0, NULL};
104 #define CAM_HEIGHT 100.0f
105 #define CAMDISTANCE_MIN 20.0
106 #define CAMDISTANCE_MAX 150.0
107 #define CAMDISTANCE_SPEED 1.5
109 /* rendering the sphere */
111 #define SPHERE_VERTICES (2+MESH_SIZE*MESH_SIZE*2)
112 #define SPHERE_INDICES ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
115 **-----------------------------------------------------------------------------
117 **-----------------------------------------------------------------------------
175 float cam_x_speed, cam_z_speed, cam_y_speed;
179 vectorf spherev[SPHERE_VERTICES];
180 GLint spherei[SPHERE_INDICES];
183 GLXContext *glx_context;
191 #define GLL_PATTERN 0
196 **----------------------------------------------------------------------------
198 **----------------------------------------------------------------------------
201 static boxedstruct *boxed = NULL;
205 **----------------------------------------------------------------------------
207 **----------------------------------------------------------------------------
213 static inline void addvectors(vectorf *dest, vectorf *s1, vectorf *s2)
215 dest->x = s1->x + s2->x;
216 dest->y = s1->y + s2->y;
217 dest->z = s1->z + s2->z;
223 static inline void subvectors(vectorf *dest, vectorf* s1, vectorf *s2)
225 dest->x = s1->x - s2->x;
226 dest->y = s1->y - s2->y;
227 dest->z = s1->z - s2->z;
231 * Multiply vector with scalar (scale vector)
233 static inline void scalevector(vectorf *dest, vectorf *source, GLfloat sc)
235 dest->x = source->x * sc;
236 dest->y = source->y * sc;
237 dest->z = source->z * sc;
243 static inline void copyvector(vectorf *dest, vectorf* source)
251 static inline GLfloat
252 dotproduct(vectorf * v1, vectorf * v2)
254 return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
257 static inline GLfloat
258 squaremagnitude(vectorf * v)
260 return v->x * v->x + v->y * v->y + v->z * v->z;
266 * Generate the Sphere data
271 static void generatesphere(boxedstruct *gp)
273 float dj = M_PI/(MESH_SIZE+1.0f);
274 float di = M_PI/MESH_SIZE;
275 int v; /* vertex offset */
276 int ind; /* indices offset */
278 GLfloat r_y_plane, h_y_plane;
283 * generate the sphere data
284 * vertices 0 and 1 are the north and south poles
287 spherei = gp->spherei;
288 spherev = gp->spherev;
290 spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
291 spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
293 for (j=0; j<MESH_SIZE; j++) {
294 r_y_plane = (float)sin((j+1) * dj);
295 h_y_plane = (float)cos((j+1) * dj);
296 for (i=0; i<MESH_SIZE*2; i++) {
297 si = 2+i+j*MESH_SIZE*2;
298 spherev[si].y = h_y_plane;
299 spherev[si].x = (float) sin(i * di) * r_y_plane;
300 spherev[si].z = (float) cos(i * di) * r_y_plane;
304 /* generate indices */
305 for (i=0; i<MESH_SIZE*2; i++) {
307 spherei[3*i+1] = i+2;
308 spherei[3*i+2] = i+3;
309 if (i==MESH_SIZE*2-1)
313 /* the middle strips */
314 for (j=0; j<MESH_SIZE-1; j++) {
316 ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
317 for (i=0; i<MESH_SIZE*2; i++) {
318 spherei[6*i+ind] = v+i;
319 spherei[6*i+2+ind] = v+i+1;
320 spherei[6*i+1+ind] = v+i+MESH_SIZE*2;
322 spherei[6*i+ind+3] = v+i+MESH_SIZE*2;
323 spherei[6*i+2+ind+3] = v+i+1;
324 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
325 if (i==MESH_SIZE*2-1) {
326 spherei[6*i+2+ind] = v+i+1-2*MESH_SIZE;
327 spherei[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
328 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
333 v = SPHERE_VERTICES-MESH_SIZE*2;
334 ind = SPHERE_INDICES-3*MESH_SIZE*2;
335 for (i=0; i<MESH_SIZE*2; i++) {
336 spherei[3*i+ind] = 1;
337 spherei[3*i+1+ind] = v+i+1;
338 spherei[3*i+2+ind] = v+i;
339 if (i==MESH_SIZE*2-1)
340 spherei[3*i+1+ind] = v;
351 static void createball(ball *newball)
353 float r=0.0f,g=0.0f,b=0.0f;
354 newball->loc.x = 5-10*rnd();
355 newball->loc.y = 35+20*rnd();
356 newball->loc.z = 5-10*rnd();
357 newball->dir.x = (0.5f-rnd()) * speed;
358 newball->dir.y = 0.0;
359 newball->dir.z = (0.5-rnd()) * speed;
360 newball->offside = 0;
361 newball->bounced = FALSE;
362 newball->radius = cfg_ballsize;
363 while (r+g+b < 1.8f ) {
364 newball->color.x = r=rnd();
365 newball->color.y = g=rnd();
366 newball->color.z = b=rnd();
368 newball->justcreated = TRUE;
371 /* Update position of each ball */
373 static void updateballs(ballman *bman)
376 vectorf dvect,richting,relspeed,influence;
379 for (b=0;b<bman->num_balls;b++) {
381 GLfloat gravity = 0.30f * speed;
384 bman->balls[b].dir.y -= gravity;
386 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
388 if (bman->balls[b].loc.y < bman->balls[b].radius) { /* ball onder bodem? (bodem @ y=0) */
389 if ((bman->balls[b].loc.x < -95.0) ||
390 (bman->balls[b].loc.x > 95.0) ||
391 (bman->balls[b].loc.z < -95.0) ||
392 (bman->balls[b].loc.z > 95.0)) {
393 if (bman->balls[b].loc.y < -1000.0)
394 createball(&bman->balls[b]);
396 bman->balls[b].loc.y = bman->balls[b].radius + (bman->balls[b].radius - bman->balls[b].loc.y);
397 bman->balls[b].dir.y = -bman->balls[b].dir.y;
398 if (bman->balls[b].offside) {
399 bman->balls[b].bounced = TRUE; /* temporary disable painting ball */
400 scalevector(&bman->balls[b].dir,&bman->balls[b].dir,0.80f);
401 if (squaremagnitude(&bman->balls[b].dir) < 0.08f) {
402 createball(&bman->balls[b]);
408 if (!bman->balls[b].offside) {
409 if (bman->balls[b].loc.x - bman->balls[b].radius < -20.0f) { /* x ondergrens */
410 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
412 bman->balls[b].dir.x = -bman->balls[b].dir.x;
413 bman->balls[b].loc.x = -20.0f + bman->balls[b].radius;
416 if (bman->balls[b].loc.x + bman->balls[b].radius > 20.0f) { /* x bovengrens */
417 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
419 bman->balls[b].dir.x = -bman->balls[b].dir.x;
420 bman->balls[b].loc.x = 20.0f - bman->balls[b].radius;
423 if (bman->balls[b].loc.z - bman->balls[b].radius < -20.0f) { /* z ondergrens */
424 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
426 bman->balls[b].dir.z = -bman->balls[b].dir.z;
427 bman->balls[b].loc.z = -20.0f + bman->balls[b].radius;
430 if (bman->balls[b].loc.z + bman->balls[b].radius > 20.0f) { /* z bovengrens */
431 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
433 bman->balls[b].dir.z = -bman->balls[b].dir.z;
434 bman->balls[b].loc.z = 20.0f - bman->balls[b].radius;
437 } /* end if !offside */
439 /* check voor stuiteren */
440 for (j=b+1;j<bman->num_balls;j++) {
441 squaredist = (bman->balls[b].radius * bman->balls[b].radius) + (bman->balls[j].radius * bman->balls[j].radius);
442 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
443 if ( squaremagnitude(&dvect) < squaredist ) { /* balls b and j touch */
444 subvectors(&richting,&bman->balls[j].loc,&bman->balls[b].loc);
445 subvectors(&relspeed,&bman->balls[b].dir,&bman->balls[j].dir);
446 /* calc mutual influence direction and magnitude */
447 scalevector(&influence,&richting,(dotproduct(&richting,&relspeed)/squaremagnitude(&richting)));
449 subvectors(&bman->balls[b].dir,&bman->balls[b].dir,&influence);
450 addvectors(&bman->balls[j].dir,&bman->balls[j].dir,&influence);
451 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
452 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
454 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
455 while (squaremagnitude(&dvect) < squaredist) {
456 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
457 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
458 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
467 * explode ball into triangles
470 static void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b)
476 vectorf avgdir,dvect;
478 tman->scalefac = b->radius;
479 copyvector(&tman->color,&b->color);
480 explosion = 1.0f + tman->explosion * 2.0 * rnd();
482 tman->num_tri = ind_num/3;
484 /* reserveer geheugen voor de poly's in een bal */
486 tman->tris = (tri *)malloc(tman->num_tri * sizeof(tri));
487 tman->vertices = (vectorf *)malloc(ind_num * sizeof(vectorf));
488 tman->normals = (vectorf *)malloc(ind_num/3 * sizeof(vectorf));
490 for (i=0; i<(tman->num_tri); i++) {
491 tman->tris[i].far = FALSE;
492 tman->tris[i].gone = FALSE;
494 /* kopieer elke poly apart naar een tri structure */
495 copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
496 copyvector(&tman->vertices[pos+1],&spherev[spherei[pos+1]]);
497 copyvector(&tman->vertices[pos+2],&spherev[spherei[pos+2]]);
498 /* Calculate average direction of shrapnel */
499 addvectors(&avgdir,&tman->vertices[pos+0],&tman->vertices[pos+1]);
500 addvectors(&avgdir,&avgdir,&tman->vertices[pos+2]);
501 scalevector(&avgdir,&avgdir,0.33333);
503 /* should normalize first, NYI */
504 copyvector(&tman->normals[i],&avgdir);
506 /* copy de lokatie */
507 addvectors(&tman->tris[i].loc,&b->loc,&avgdir);
508 /* en translate alle triangles terug naar hun eigen oorsprong */
509 tman->vertices[pos+0].x -= avgdir.x;
510 tman->vertices[pos+0].y -= avgdir.y;
511 tman->vertices[pos+0].z -= avgdir.z;
512 tman->vertices[pos+1].x -= avgdir.x;
513 tman->vertices[pos+1].y -= avgdir.y;
514 tman->vertices[pos+1].z -= avgdir.z;
515 tman->vertices[pos+2].x -= avgdir.x;
516 tman->vertices[pos+2].y -= avgdir.y;
517 tman->vertices[pos+2].z -= avgdir.z;
518 /* alwaar opschaling plaatsvindt */
519 scale = b->radius * 2;
520 scalevector(&tman->vertices[pos+0],&tman->vertices[pos+0],scale);
521 scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
522 scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
524 tman->vertices[pos+0].x += avgdir.x;
525 tman->vertices[pos+0].y += avgdir.y;
526 tman->vertices[pos+0].z += avgdir.z;
527 tman->vertices[pos+1].x += avgdir.x;
528 tman->vertices[pos+1].y += avgdir.y;
529 tman->vertices[pos+1].z += avgdir.z;
530 tman->vertices[pos+2].x += avgdir.x;
531 tman->vertices[pos+2].y += avgdir.y;
532 tman->vertices[pos+2].z += avgdir.z;
534 /* bereken nieuwe richting */
535 scalevector(&tman->tris[i].dir,&avgdir,explosion);
536 dvect.x = (0.1f - 0.2f*rnd());
537 dvect.y = (0.15f - 0.3f*rnd());
538 dvect.z = (0.1f - 0.2f*rnd());
539 addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
545 * update position of each tri
548 static void updatetris(triman *t)
553 for (b=0;b<t->num_tri;b++) {
554 /* the exploded triangles disappear over time */
555 if (rnd() < t->decay) { t->tris[b].gone = TRUE; }
557 t->tris[b].dir.y -= (0.1f * speed);
559 addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
561 if (t->tris[b].far) continue;
562 if (t->tris[b].loc.y < 0) { /* onder bodem ? */
563 if ((t->tris[b].loc.x > -95.0f) &
564 (t->tris[b].loc.x < 95.0f) &
565 (t->tris[b].loc.z > -95.0f) &
566 (t->tris[b].loc.z < 95.0f)) { /* in veld */
567 t->tris[b].dir.y = -(t->tris[b].dir.y);
568 t->tris[b].loc.y = -t->tris[b].loc.y;
569 scalevector(&t->tris[b].dir,&t->tris[b].dir,0.80f); /* dampening */
572 t->tris[b].far = TRUE;
577 if ((t->tris[b].loc.x > -21.0f) &
578 (t->tris[b].loc.x < 21.0f) &
579 (t->tris[b].loc.z > -21.0f) &
580 (t->tris[b].loc.z < 21.0f)) { /* in box? */
582 xd = zd = 999.0f; /* big */
583 if ((t->tris[b].loc.x > -21.0f) &
584 (t->tris[b].loc.x < 0)) {
585 xd = t->tris[b].loc.x + 21.0f;
587 if ((t->tris[b].loc.x < 21.0f) &
588 (t->tris[b].loc.x > 0)) {
589 xd = 21.0f - t->tris[b].loc.x;
591 if ((t->tris[b].loc.z > -21.0f) &
592 (t->tris[b].loc.z < 0)) {
593 zd = t->tris[b].loc.z + 21.0f;
595 if ((t->tris[b].loc.z < 21.0f) &
596 (t->tris[b].loc.z > 0)) {
597 zd = 21.0f - t->tris[b].loc.z;
601 if (t->tris[b].dir.x < 0)
602 t->tris[b].loc.x += (21.0f - t->tris[b].loc.x);
604 t->tris[b].loc.x += (-21.0f - t->tris[b].loc.x);
605 t->tris[b].dir.x = -t->tris[b].dir.x;
608 if (t->tris[b].dir.z < 0)
609 t->tris[b].loc.z += (21.0f - t->tris[b].loc.z);
611 t->tris[b].loc.z += (-21.0f - t->tris[b].loc.z);
612 t->tris[b].dir.z = -t->tris[b].dir.z;
621 * free memory allocated by a tri manager
623 static void freetris(triman *t)
626 if (t->tris) free(t->tris);
627 if (t->vertices) free(t->vertices);
628 if (t->normals) free(t->normals);
638 *load defaults in config structure
640 static void setdefaultconfig(boxed_config *config)
642 cfg_balls = MAX(3,MIN(40,cfg_balls));
643 cfg_ballsize = MAX(1.0f,MIN(5.0f,cfg_ballsize));
644 cfg_explosion = MAX(0.0f,MIN(50.0f,cfg_explosion));
645 cfg_decay = MAX(0.0f,MIN(1.0f,cfg_decay));
647 config->numballs = cfg_balls;
648 config->textures = TRUE;
649 config->transparent = FALSE;
650 config->explosion = cfg_explosion;
651 config->decay = cfg_decay;
652 config->ballsize = cfg_ballsize;
653 config->camspeed = 35.0f;
660 static void drawfilledbox(boxedstruct *boxed, int wire)
662 /* draws texture filled box,
663 top is drawn using the entire texture,
664 the sides are drawn using the edge of the texture
668 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
670 glVertex3f(-1.0,1.0,1.0);
672 glVertex3f(1.0,1.0,1.0);
674 glVertex3f(1.0,-1.0,1.0);
676 glVertex3f(-1.0,-1.0,1.0);
679 glVertex3f(1.0,1.0,-1.0);
681 glVertex3f(-1.0,1.0,-1.0);
683 glVertex3f(-1.0,-1.0,-1.0);
685 glVertex3f(1.0,-1.0,-1.0);
688 glVertex3f(-1.0,1.0,1.0);
690 glVertex3f(-1.0,-1.0,1.0);
692 glVertex3f(-1.0,-1.0,-1.0);
694 glVertex3f(-1.0,1.0,-1.0);
697 glVertex3f(1.0,1.0,1.0);
699 glVertex3f(1.0,1.0,-1.0);
701 glVertex3f(1.0,-1.0,-1.0);
703 glVertex3f(1.0,-1.0,1.0);
705 glTexCoord2f(0.0,0.0);
706 glVertex3f(-1.0,1.0,1.0);
707 glTexCoord2f(0.0,1.0);
708 glVertex3f(-1.0,1.0,-1.0);
709 glTexCoord2f(1.0,1.0);
710 glVertex3f(1.0,1.0,-1.0);
711 glTexCoord2f(1.0,0.0);
712 glVertex3f(1.0,1.0,1.0);
715 glVertex3f(-1.0,-1.0,1.0);
717 glVertex3f(-1.0,-1.0,-1.0);
719 glVertex3f(1.0,-1.0,-1.0);
721 glVertex3f(1.0,-1.0,1.0);
727 * Draw a box made of lines
729 static void drawbox(boxedstruct *boxed)
732 glBegin(GL_LINE_STRIP);
733 glVertex3f(-1.0,1.0,1.0);
734 glVertex3f(-1.0,1.0,-1.0);
735 glVertex3f(1.0,1.0,-1.0);
736 glVertex3f(1.0,1.0,1.0);
737 glVertex3f(-1.0,1.0,1.0);
740 glBegin(GL_LINE_STRIP);
741 glVertex3f(-1.0,-1.0,1.0);
742 glVertex3f(1.0,-1.0,1.0);
743 glVertex3f(1.0,-1.0,-1.0);
744 glVertex3f(-1.0,-1.0,-1.0);
745 glVertex3f(-1.0,-1.0,1.0);
747 /* connect top & bottom */
749 glVertex3f(-1.0,1.0,1.0);
750 glVertex3f(-1.0,-1.0,1.0);
751 glVertex3f(1.0,1.0,1.0);
752 glVertex3f(1.0,-1.0,1.0);
753 glVertex3f(1.0,1.0,-1.0);
754 glVertex3f(1.0,-1.0,-1.0);
755 glVertex3f(-1.0,1.0,-1.0);
756 glVertex3f(-1.0,-1.0,-1.0);
765 static void drawball(boxedstruct *gp, ball *b, int wire)
768 GLint *spherei = gp->spherei;
769 vectorf *spherev = gp->spherev;
774 glTranslatef(b->loc.x,b->loc.y,b->loc.z);
775 glScalef(b->radius,b->radius,b->radius);
776 glColor3f(b->color.x,b->color.y,b->color.z);
780 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
784 glMaterialfv(GL_FRONT, GL_EMISSION,col);
786 if (!gp->gllists[GLL_BALL]) {
787 glNewList(gp->listobjects + GLL_BALL,GL_COMPILE);
788 cnt = SPHERE_INDICES/3;
789 for (i=0; i<cnt; i++) {
791 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
792 glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
793 glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
794 glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
795 glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
796 glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
797 glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
801 gp->gllists[GLL_BALL] = 1;
803 glCallList(gp->listobjects + GLL_BALL);
811 * Draw all triangles in triman
813 static void drawtriman(triman *t, int wire)
816 vectorf *spherev = t->vertices;
820 glColor3f(t->color.x,t->color.y,t->color.z);
824 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
828 glMaterialfv(GL_FRONT, GL_EMISSION,col);
830 for (i=0; i<t->num_tri; i++) {
831 if (t->tris[i].gone == TRUE) { continue; }
834 glTranslatef(t->tris[i].loc.x,t->tris[i].loc.y,t->tris[i].loc.z);
835 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
836 glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
837 glVertex3f(spherev[pos+0].x,spherev[pos+0].y,spherev[pos+0].z);
838 glVertex3f(spherev[pos+1].x,spherev[pos+1].y,spherev[pos+1].z);
839 glVertex3f(spherev[pos+2].x,spherev[pos+2].y,spherev[pos+2].z);
849 static void drawpattern(boxedstruct *gp)
851 if (!gp->gllists[GLL_PATTERN]) {
852 glNewList(gp->listobjects + GLL_PATTERN, GL_COMPILE);
854 glBegin(GL_LINE_STRIP);
855 glVertex3f(-25.0f, 0.0f, 35.0f);
856 glVertex3f(-15.0f, 0.0f, 35.0f);
857 glVertex3f(-5.0f, 0.0f, 25.0f);
858 glVertex3f(5.0f, 0.0f, 25.0f);
859 glVertex3f(15.0f, 0.0f, 35.0f);
860 glVertex3f(25.0f, 0.0f, 35.0f);
861 glVertex3f(35.0f, 0.0f, 25.0f);
862 glVertex3f(35.0f, 0.0f, 15.0f);
863 glVertex3f(25.0f, 0.0f, 5.0f);
864 glVertex3f(25.0f, 0.0f, -5.0f);
865 glVertex3f(35.0f, 0.0f, -15.0f);
866 glVertex3f(35.0f, 0.0f, -25.0f);
867 glVertex3f(25.0f, 0.0f, -35.0f);
868 glVertex3f(15.0f, 0.0f,-35.0f);
869 glVertex3f(5.0f, 0.0f, -25.0f);
870 glVertex3f(-5.0f, 0.0f, -25.0f);
871 glVertex3f(-15.0f, 0.0f,-35.0f);
872 glVertex3f(-25.0f, 0.0f,-35.0f);
873 glVertex3f(-35.0f, 0.0f, -25.0f);
874 glVertex3f(-35.0f, 0.0f, -15.0f);
875 glVertex3f(-25.0f, 0.0f, -5.0f);
876 glVertex3f(-25.0f, 0.0f, 5.0f);
877 glVertex3f(-35.0f, 0.0f, 15.0f);
878 glVertex3f(-35.0f, 0.0f, 25.0f);
879 glVertex3f(-25.0f, 0.0f, 35.0f);
882 glBegin(GL_LINE_STRIP);
883 glVertex3f(-5.0f, 0.0f, 15.0f);
884 glVertex3f(5.0f, 0.0f, 15.0f);
885 glVertex3f(15.0f, 0.0f, 5.0f);
886 glVertex3f(15.0f, 0.0f, -5.0f);
887 glVertex3f(5.0f, 0.0f, -15.0f);
888 glVertex3f(-5.0f, 0.0f, -15.0f);
889 glVertex3f(-15.0f, 0.0f, -5.0f);
890 glVertex3f(-15.0f, 0.0f, 5.0f);
891 glVertex3f(-5.0f, 0.0f, 15.0f);
895 gp->gllists[GLL_PATTERN] = 1;
897 glCallList(gp->listobjects + GLL_PATTERN);
904 * main rendering loop
906 static void draw(ModeInfo * mi)
908 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
909 int wire = MI_IS_WIREFRAME (mi);
915 GLfloat dgray[4] = {0.3f, 0.3f, 0.3f, 1.0f};
916 GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
917 GLfloat lblue[4] = {0.4f,0.6f,1.0f };
919 GLfloat l0_ambient[] = {0.0, 0.0, 0.0, 1.0};
920 GLfloat l0_specular[] = {1.0, 1.0, 1.0, 1.0};
921 GLfloat l0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
922 GLfloat l0_position[] = {0.0, 0.0, 0.0, 1.0}; /* w != 0 -> positional light */
923 GLfloat l1_ambient[] = {0.0, 0.0, 0.0, 1.0};
924 GLfloat l1_specular[] = {1.0, 1.0, 1.0, 1.0};
925 GLfloat l1_diffuse[] = {0.5, 0.5, 0.5, 1.0};
926 GLfloat l1_position[] = {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
928 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
932 gp->camtic += 0.01f + 0.01f * sin(gp->tic * speed);
934 /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
935 dcam = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos((gp->camtic/CAMDISTANCE_SPEED) * speed);
936 v1.x = dcam * sin((gp->camtic/gp->cam_x_speed) * speed);
937 v1.z = dcam * cos((gp->camtic/gp->cam_z_speed) * speed);
938 v1.y = CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT;
939 gluLookAt(v1.x,v1.y,v1.z,0.0,0.0,0.0,0.0,1.0,0.0);
942 glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient);
943 glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse);
944 glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular);
945 glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
946 glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient);
947 glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse);
948 glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular);
949 glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
955 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
956 glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
957 glMaterialfv(GL_FRONT,GL_AMBIENT,black);
958 glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
962 /* draw ground grid */
963 /* glDisable(GL_DEPTH_TEST); */
964 glDisable(GL_LIGHTING);
966 glColor3f(0.1,0.1,0.6);
967 for (dx= -2; dx<3; dx++) {
968 for (dz= -2; dz<3; dz++) {
970 glTranslatef(dx*30.0f, 0.0f, dz*30.0f);
976 /* Set drawing mode for the boxes */
977 glEnable(GL_DEPTH_TEST);
978 if (!wire) glEnable(GL_TEXTURE_2D);
980 glColor3f(1.0,1.0,1.0);
981 glScalef(20.0,0.25,20.0);
982 glTranslatef(0.0,2.0,0.0);
983 drawfilledbox(gp, wire);
985 glDisable(GL_TEXTURE_2D);
988 glColor3f(0.2,0.5,0.2);
989 glScalef(20.0,20.0,0.25);
990 glTranslatef(0.0,1.0,81.0);
995 glColor3f(0.2,0.5,0.2);
996 glScalef(20.0,20.0,0.25);
997 glTranslatef(0.0,1.0,-81.0);
1002 glColor3f(0.2,0.5,0.2);
1003 glScalef(.25,20.0,20.0);
1004 glTranslatef(-81.0,1.0,0.0);
1009 glColor3f(0.2,0.5,0.2);
1010 glScalef(.25,20.0,20.0);
1011 glTranslatef(81.0,1.0,0.0);
1016 glEnable(GL_LIGHTING);
1018 glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
1019 glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
1022 /* move the balls and shrapnel */
1023 updateballs(&gp->bman);
1025 glFrontFace(GL_CCW);
1026 for (i=0;i<gp->bman.num_balls;i++) {
1027 if (gp->bman.balls[i].justcreated) {
1028 gp->bman.balls[i].justcreated = FALSE;
1029 freetris(&gp->tman[i]);
1031 if (gp->bman.balls[i].bounced) {
1032 if (gp->tman[i].vertices == NULL) {
1033 createtrisfromball(&gp->tman[i],gp->spherev,gp->spherei,SPHERE_INDICES,&gp->bman.balls[i]);
1035 updatetris(&gp->tman[i]);
1037 glDisable(GL_CULL_FACE);
1038 drawtriman(&gp->tman[i], wire);
1039 if (!wire) glEnable(GL_CULL_FACE);
1041 drawball(gp, &gp->bman.balls[i], wire);
1051 * new window size or exposure
1053 ENTRYPOINT void reshape_boxed(ModeInfo *mi, int width, int height)
1055 GLfloat h = (GLfloat) height / (GLfloat) width;
1057 glViewport(0, 0, (GLint) width, (GLint) height);
1058 glMatrixMode(GL_PROJECTION);
1060 gluPerspective(50.0,1/h,2.0,1000.0);
1061 glMatrixMode (GL_MODELVIEW);
1069 pinit(ModeInfo * mi)
1071 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1072 int wire = MI_IS_WIREFRAME (mi);
1076 char *texpixeltarget;
1078 glShadeModel(GL_SMOOTH);
1080 glClearColor(0.0,0.05,0.1,0.0);
1081 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1083 /* Load configuration */
1084 setdefaultconfig(&gp->config);
1088 bman->balls = (ball *)malloc(gp->config.numballs * sizeof(ball));
1089 bman->num_balls = gp->config.numballs;
1090 bman->ballsize = gp->config.ballsize;
1091 bman->explosion = gp->config.explosion;
1093 gp->tman = (triman *)malloc(bman->num_balls * sizeof(triman));
1094 memset(gp->tman,0,bman->num_balls * sizeof(triman));
1096 for(i=0;i<bman->num_balls;i++) {
1097 gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
1098 gp->tman[i].decay = gp->config.decay;
1099 gp->tman[i].vertices = NULL;
1100 gp->tman[i].normals = NULL;
1101 gp->tman[i].tris = NULL;
1102 createball(&bman->balls[i]);
1103 bman->balls[i].loc.y *= rnd();
1109 glEnable(GL_CULL_FACE);
1110 glEnable(GL_LIGHTING);
1113 /* define cam path */
1114 gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1115 gp->cam_z_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1116 gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
1117 if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
1118 if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
1120 /* define initial cam position */
1121 gp->tic = gp->camtic = rnd() * 100.0f;
1123 /* define tex1 (bottom plate) */
1124 gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
1125 texpixels = 256*256; /*width*height;*/
1126 texpixeldata = header_data;
1127 texpixeltarget = gp->tex1;
1128 for (i=0; i < texpixels; i++) {
1129 HEADER_PIXEL(texpixeldata,texpixeltarget);
1130 texpixeltarget += 3;
1134 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1137 i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
1138 GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
1141 const char *s = (char *) gluErrorString (i);
1142 fprintf (stderr, "%s: error mipmapping texture: %s\n",
1143 progname, (s ? s : "(unknown)"));
1146 check_gl_error("mipmapping");
1148 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1149 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1150 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1151 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1152 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1159 init_boxed(ModeInfo * mi)
1161 int screen = MI_SCREEN(mi);
1163 /* Colormap cmap; */
1164 /* Boolean rgba, doublebuffer, cmap_installed; */
1167 if (boxed == NULL) {
1168 if ((boxed = (boxedstruct *) calloc(MI_NUM_SCREENS(mi),sizeof (boxedstruct))) == NULL) return;
1170 gp = &boxed[screen];
1171 gp->window = MI_WINDOW(mi);
1173 if ((gp->glx_context = init_GL(mi)) != NULL) {
1174 reshape_boxed(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1175 glDrawBuffer(GL_BACK);
1176 if (!glIsList(gp->listobjects)) {
1177 gp->listobjects = glGenLists(3);
1190 draw_boxed(ModeInfo * mi)
1192 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1193 Display *display = MI_DISPLAY(mi);
1194 Window window = MI_WINDOW(mi);
1196 if (!gp->glx_context)
1199 glDrawBuffer(GL_BACK);
1201 glXMakeCurrent(display, window, *(gp->glx_context));
1204 if (mi->fps_p) do_fps (mi);
1206 glXSwapBuffers(display, window);
1210 release_boxed(ModeInfo * mi)
1214 if (boxed != NULL) {
1217 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1218 boxedstruct *gp = &boxed[screen];
1220 if (gp->glx_context) {
1221 /* Display lists MUST be freed while their glXContext is current. */
1222 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1224 if (glIsList(gp->listobjects))
1225 glDeleteLists(gp->listobjects, 3);
1227 for (i=0;i<gp->bman.num_balls;i++) {
1228 if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
1230 free (gp->bman.balls);
1237 (void) free((void *) boxed);
1244 XSCREENSAVER_MODULE ("Boxed", boxed)
1246 /*********************************************************/