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
29 * 2006: opts work. added option -decay
31 * 2008: opts work. added option -momentum
38 **----------------------------------------------------------------------------
40 **----------------------------------------------------------------------------
44 # define DEFAULTS "*delay: 15000 \n" \
45 "*showFPS: False \n" \
46 "*wireframe: False \n"
48 # define refresh_boxed 0
49 # define release_boxed 0
50 # define boxed_handle_event 0
51 # include "xlockmore.h" /* from the xscreensaver distribution */
52 #else /* !STANDALONE */
53 # include "xlock.h" /* from the xlockmore distribution */
54 #endif /* !STANDALONE */
58 # define DEF_SPEED "0.5"
59 # define DEF_BALLS "20"
60 # define DEF_BALLSIZE "3.0"
61 # define DEF_EXPLOSION "15.0"
62 # define DEF_DECAY "0.07"
63 # define DEF_MOMENTUM "0.6"
66 #define countof(x) (int)(sizeof((x))/sizeof((*x)))
68 #define rnd() (frand(1.0))
70 static GLfloat speed; /* jwz -- overall speed factor applied to all motion */
72 static GLfloat cfg_ballsize;
73 static GLfloat cfg_explosion;
74 static GLfloat cfg_decay;
75 static GLfloat cfg_momentum;
78 static XrmOptionDescRec opts[] = {
79 {"-speed", ".boxed.speed", XrmoptionSepArg, 0},
80 {"-balls", ".boxed.balls", XrmoptionSepArg, 0},
81 {"-ballsize", ".boxed.ballsize", XrmoptionSepArg, 0},
82 {"-explosion", ".boxed.explosion", XrmoptionSepArg, 0},
83 {"-decay", ".boxed.decay", XrmoptionSepArg, 0},
84 {"-momentum", ".boxed.momentum", XrmoptionSepArg, 0},
87 static argtype vars[] = {
88 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
89 {&cfg_balls, "balls", "Balls", DEF_BALLS, t_Int},
90 {&cfg_ballsize, "ballsize", "Ball Size", DEF_BALLSIZE, t_Float},
91 {&cfg_explosion, "explosion", "Explosion", DEF_EXPLOSION, t_Float},
92 {&cfg_decay, "decay", "Explosion Decay", DEF_DECAY, t_Float},
93 {&cfg_momentum, "momentum", "Explosion Momentum", DEF_MOMENTUM, t_Float},
96 ENTRYPOINT ModeSpecOpt boxed_opts = {countof(opts), opts, countof(vars), vars, NULL};
100 ModStruct boxed_description = {
101 "boxed", "init_boxed", "draw_boxed", NULL,
102 "draw_boxed", "init_boxed", NULL, &boxed_opts,
103 1000, 1, 2, 1, 4, 1.0, "",
104 "Shows GL's boxed balls", 0, NULL};
113 #define CAM_HEIGHT 80.0f
114 #define CAMDISTANCE_MIN 35.0
115 #define CAMDISTANCE_MAX 150.0
116 #define CAMDISTANCE_SPEED 1.5
117 #define LOOKAT_R 30.0
119 /* rendering the sphere */
121 #define SPHERE_VERTICES (2+MESH_SIZE*MESH_SIZE*2)
122 #define SPHERE_INDICES ((MESH_SIZE*4 + MESH_SIZE*4*(MESH_SIZE-1))*3)
125 **-----------------------------------------------------------------------------
127 **-----------------------------------------------------------------------------
187 float cam_x_speed, cam_z_speed, cam_y_speed;
191 vectorf spherev[SPHERE_VERTICES];
192 GLint spherei[SPHERE_INDICES];
195 GLXContext *glx_context;
204 #define GLL_PATTERN 0
209 **----------------------------------------------------------------------------
211 **----------------------------------------------------------------------------
214 static boxedstruct *boxed = NULL;
218 **----------------------------------------------------------------------------
220 **----------------------------------------------------------------------------
226 static inline void addvectors(vectorf *dest, vectorf *s1, vectorf *s2)
228 dest->x = s1->x + s2->x;
229 dest->y = s1->y + s2->y;
230 dest->z = s1->z + s2->z;
236 static inline void subvectors(vectorf *dest, vectorf* s1, vectorf *s2)
238 dest->x = s1->x - s2->x;
239 dest->y = s1->y - s2->y;
240 dest->z = s1->z - s2->z;
244 * Multiply vector with scalar (scale vector)
246 static inline void scalevector(vectorf *dest, vectorf *source, GLfloat sc)
248 dest->x = source->x * sc;
249 dest->y = source->y * sc;
250 dest->z = source->z * sc;
256 static inline void copyvector(vectorf *dest, vectorf* source)
264 static inline GLfloat
265 dotproduct(vectorf * v1, vectorf * v2)
267 return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
270 static inline GLfloat
271 squaremagnitude(vectorf * v)
273 return v->x * v->x + v->y * v->y + v->z * v->z;
276 static inline GLfloat
277 squaremagnitudehorz(vectorf * v)
279 return v->x * v->x + v->z * v->z;
285 * Generate the Sphere data
290 static void generatesphere(boxedstruct *gp)
292 float dj = M_PI/(MESH_SIZE+1.0f);
293 float di = M_PI/MESH_SIZE;
294 int v; /* vertex offset */
295 int ind; /* indices offset */
297 GLfloat r_y_plane, h_y_plane;
302 * generate the sphere data
303 * vertices 0 and 1 are the north and south poles
306 spherei = gp->spherei;
307 spherev = gp->spherev;
309 spherev[0].x = 0.0f; spherev[0].y =1.0f; spherev[0].z = 0.0f;
310 spherev[1].x = 0.0f; spherev[1].y =-1.0f; spherev[1].z = 0.0f;
312 for (j=0; j<MESH_SIZE; j++) {
313 r_y_plane = (float)sin((j+1) * dj);
314 h_y_plane = (float)cos((j+1) * dj);
315 for (i=0; i<MESH_SIZE*2; i++) {
316 si = 2+i+j*MESH_SIZE*2;
317 spherev[si].y = h_y_plane;
318 spherev[si].x = (float) sin(i * di) * r_y_plane;
319 spherev[si].z = (float) cos(i * di) * r_y_plane;
323 /* generate indices */
324 for (i=0; i<MESH_SIZE*2; i++) {
326 spherei[3*i+1] = i+2;
327 spherei[3*i+2] = i+3;
328 if (i==MESH_SIZE*2-1)
332 /* the middle strips */
333 for (j=0; j<MESH_SIZE-1; j++) {
335 ind = 3*MESH_SIZE*2 + j*6*MESH_SIZE*2;
336 for (i=0; i<MESH_SIZE*2; i++) {
337 spherei[6*i+ind] = v+i;
338 spherei[6*i+2+ind] = v+i+1;
339 spherei[6*i+1+ind] = v+i+MESH_SIZE*2;
341 spherei[6*i+ind+3] = v+i+MESH_SIZE*2;
342 spherei[6*i+2+ind+3] = v+i+1;
343 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1;
344 if (i==MESH_SIZE*2-1) {
345 spherei[6*i+2+ind] = v+i+1-2*MESH_SIZE;
346 spherei[6*i+2+ind+3] = v+i+1-2*MESH_SIZE;
347 spherei[6*i+1+ind+3] = v+i+MESH_SIZE*2+1-2*MESH_SIZE;
352 v = SPHERE_VERTICES-MESH_SIZE*2;
353 ind = SPHERE_INDICES-3*MESH_SIZE*2;
354 for (i=0; i<MESH_SIZE*2; i++) {
355 spherei[3*i+ind] = 1;
356 spherei[3*i+1+ind] = v+i+1;
357 spherei[3*i+2+ind] = v+i;
358 if (i==MESH_SIZE*2-1)
359 spherei[3*i+1+ind] = v;
370 static void createball(ball *newball)
372 float r=0.0f,g=0.0f,b=0.0f;
373 newball->loc.x = 5-10*rnd();
374 newball->loc.y = 35+20*rnd();
375 newball->loc.z = 5-10*rnd();
376 newball->dir.x = (0.5f-rnd()) * speed;
377 newball->dir.y = 0.0;
378 newball->dir.z = (0.5-rnd()) * speed;
379 newball->offside = 0;
380 newball->bounced = FALSE;
381 newball->radius = cfg_ballsize;
382 while (r+g+b < 1.8f ) {
383 newball->color.x = r=rnd();
384 newball->color.y = g=rnd();
385 newball->color.z = b=rnd();
387 newball->justcreated = TRUE;
390 /* Update position of each ball */
392 static void updateballs(ballman *bman)
395 vectorf dvect,richting,relspeed,influence;
398 for (b=0;b<bman->num_balls;b++) {
400 GLfloat gravity = 0.30f * speed;
403 bman->balls[b].dir.y -= gravity;
405 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
407 if (bman->balls[b].loc.y < bman->balls[b].radius) { /* ball onder bodem? (bodem @ y=0) */
408 if ((bman->balls[b].loc.x < -95.0) ||
409 (bman->balls[b].loc.x > 95.0) ||
410 (bman->balls[b].loc.z < -95.0) ||
411 (bman->balls[b].loc.z > 95.0)) {
412 if (bman->balls[b].loc.y < -2000.0)
413 createball(&bman->balls[b]);
415 bman->balls[b].loc.y = bman->balls[b].radius + (bman->balls[b].radius - bman->balls[b].loc.y);
416 bman->balls[b].dir.y = -bman->balls[b].dir.y;
417 if (bman->balls[b].offside) {
418 bman->balls[b].bounced = TRUE; /* temporary disable painting ball */
419 scalevector(&bman->balls[b].dir,&bman->balls[b].dir,0.80f);
420 if (squaremagnitude(&bman->balls[b].dir) < 0.08f) {
421 createball(&bman->balls[b]);
423 if (squaremagnitudehorz(&bman->balls[b].dir) < 0.005f) {
424 createball(&bman->balls[b]);
430 if (!bman->balls[b].offside) {
431 if (bman->balls[b].loc.x - bman->balls[b].radius < -20.0f) { /* x ondergrens */
432 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
434 bman->balls[b].dir.x = -bman->balls[b].dir.x;
435 bman->balls[b].loc.x = -20.0f + bman->balls[b].radius;
438 if (bman->balls[b].loc.x + bman->balls[b].radius > 20.0f) { /* x bovengrens */
439 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
441 bman->balls[b].dir.x = -bman->balls[b].dir.x;
442 bman->balls[b].loc.x = 20.0f - bman->balls[b].radius;
445 if (bman->balls[b].loc.z - bman->balls[b].radius < -20.0f) { /* z ondergrens */
446 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
448 bman->balls[b].dir.z = -bman->balls[b].dir.z;
449 bman->balls[b].loc.z = -20.0f + bman->balls[b].radius;
452 if (bman->balls[b].loc.z + bman->balls[b].radius > 20.0f) { /* z bovengrens */
453 if (bman->balls[b].loc.y > 41+bman->balls[b].radius) bman->balls[b].offside=1;
455 bman->balls[b].dir.z = -bman->balls[b].dir.z;
456 bman->balls[b].loc.z = 20.0f - bman->balls[b].radius;
459 } /* end if !offside */
461 /* check voor stuiteren */
462 for (j=b+1;j<bman->num_balls;j++) {
463 squaredist = (bman->balls[b].radius * bman->balls[b].radius) + (bman->balls[j].radius * bman->balls[j].radius);
464 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
465 if ( squaremagnitude(&dvect) < squaredist ) { /* balls b and j touch */
466 subvectors(&richting,&bman->balls[j].loc,&bman->balls[b].loc);
467 subvectors(&relspeed,&bman->balls[b].dir,&bman->balls[j].dir);
468 /* calc mutual influence direction and magnitude */
469 scalevector(&influence,&richting,(dotproduct(&richting,&relspeed)/squaremagnitude(&richting)));
471 subvectors(&bman->balls[b].dir,&bman->balls[b].dir,&influence);
472 addvectors(&bman->balls[j].dir,&bman->balls[j].dir,&influence);
473 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
474 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
476 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
477 while (squaremagnitude(&dvect) < squaredist) {
478 addvectors(&bman->balls[b].loc,&bman->balls[b].loc,&bman->balls[b].dir);
479 addvectors(&bman->balls[j].loc,&bman->balls[j].loc,&bman->balls[j].dir);
480 subvectors(&dvect,&bman->balls[b].loc,&bman->balls[j].loc);
489 * explode ball into triangles
492 static void createtrisfromball(triman* tman, vectorf *spherev, GLint *spherei, int ind_num, ball *b)
499 vectorf avgdir,dvect,mvect;
501 tman->scalefac = b->radius;
502 copyvector(&tman->color,&b->color);
503 explosion = 1.0f + tman->explosion * 2.0 * rnd();
504 momentum = tman->momentum;
506 tman->num_tri = ind_num/3;
508 /* reserveer geheugen voor de poly's in een bal */
510 tman->tris = (tri *)malloc(tman->num_tri * sizeof(tri));
511 tman->vertices = (vectorf *)malloc(ind_num * sizeof(vectorf));
512 tman->normals = (vectorf *)malloc(ind_num/3 * sizeof(vectorf));
514 for (i=0; i<(tman->num_tri); i++) {
515 tman->tris[i].far = FALSE;
516 tman->tris[i].gone = 0;
518 /* kopieer elke poly apart naar een tri structure */
519 copyvector(&tman->vertices[pos+0],&spherev[spherei[pos+0]]);
520 copyvector(&tman->vertices[pos+1],&spherev[spherei[pos+1]]);
521 copyvector(&tman->vertices[pos+2],&spherev[spherei[pos+2]]);
522 /* Calculate average direction of shrapnel */
523 addvectors(&avgdir,&tman->vertices[pos+0],&tman->vertices[pos+1]);
524 addvectors(&avgdir,&avgdir,&tman->vertices[pos+2]);
525 scalevector(&avgdir,&avgdir,0.33333);
527 /* should normalize first, NYI */
528 copyvector(&tman->normals[i],&avgdir);
530 /* copy de lokatie */
531 addvectors(&tman->tris[i].loc,&b->loc,&avgdir);
532 /* en translate alle triangles terug naar hun eigen oorsprong */
533 tman->vertices[pos+0].x -= avgdir.x;
534 tman->vertices[pos+0].y -= avgdir.y;
535 tman->vertices[pos+0].z -= avgdir.z;
536 tman->vertices[pos+1].x -= avgdir.x;
537 tman->vertices[pos+1].y -= avgdir.y;
538 tman->vertices[pos+1].z -= avgdir.z;
539 tman->vertices[pos+2].x -= avgdir.x;
540 tman->vertices[pos+2].y -= avgdir.y;
541 tman->vertices[pos+2].z -= avgdir.z;
542 /* alwaar opschaling plaatsvindt */
543 scale = b->radius * 2;
544 scalevector(&tman->vertices[pos+0],&tman->vertices[pos+0],scale);
545 scalevector(&tman->vertices[pos+1],&tman->vertices[pos+1],scale);
546 scalevector(&tman->vertices[pos+2],&tman->vertices[pos+2],scale);
548 tman->vertices[pos+0].x += avgdir.x;
549 tman->vertices[pos+0].y += avgdir.y;
550 tman->vertices[pos+0].z += avgdir.z;
551 tman->vertices[pos+1].x += avgdir.x;
552 tman->vertices[pos+1].y += avgdir.y;
553 tman->vertices[pos+1].z += avgdir.z;
554 tman->vertices[pos+2].x += avgdir.x;
555 tman->vertices[pos+2].y += avgdir.y;
556 tman->vertices[pos+2].z += avgdir.z;
558 /* bereken nieuwe richting */
559 scalevector(&tman->tris[i].dir,&avgdir,explosion);
560 dvect.x = (0.1f - 0.2f*rnd());
561 dvect.y = (0.15f - 0.3f*rnd());
562 dvect.z = (0.1f - 0.2f*rnd());
563 addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&dvect);
565 /* add ball's momentum to each piece of the exploded ball */
566 mvect.x = b->dir.x * momentum;
568 mvect.z = b->dir.z * momentum;
569 addvectors(&tman->tris[i].dir,&tman->tris[i].dir,&mvect);
575 * update position of each tri
578 static void updatetris(triman *t)
583 for (b=0;b<t->num_tri;b++) {
584 /* the exploded triangles disappear over time */
585 if (rnd() < t->decay) {
586 if (t->tris[b].gone == 0)
590 t->tris[b].dir.y -= (0.1f * speed);
592 addvectors(&t->tris[b].loc,&t->tris[b].loc,&t->tris[b].dir);
594 if (t->tris[b].far) continue;
595 if (t->tris[b].loc.y < 0) { /* onder bodem ? */
596 if ((t->tris[b].loc.x > -95.0f) &
597 (t->tris[b].loc.x < 95.0f) &
598 (t->tris[b].loc.z > -95.0f) &
599 (t->tris[b].loc.z < 95.0f)) { /* in veld */
600 t->tris[b].dir.y = -(t->tris[b].dir.y);
601 t->tris[b].loc.y = -t->tris[b].loc.y;
602 scalevector(&t->tris[b].dir,&t->tris[b].dir,0.80f); /* dampening */
605 t->tris[b].far = TRUE;
610 if ((t->tris[b].loc.x > -21.0f) &
611 (t->tris[b].loc.x < 21.0f) &
612 (t->tris[b].loc.z > -21.0f) &
613 (t->tris[b].loc.z < 21.0f)) { /* in box? */
615 xd = zd = 999.0f; /* big */
616 if ((t->tris[b].loc.x > -21.0f) &
617 (t->tris[b].loc.x < 0)) {
618 xd = t->tris[b].loc.x + 21.0f;
620 if ((t->tris[b].loc.x < 21.0f) &
621 (t->tris[b].loc.x > 0)) {
622 xd = 21.0f - t->tris[b].loc.x;
624 if ((t->tris[b].loc.z > -21.0f) &
625 (t->tris[b].loc.z < 0)) {
626 zd = t->tris[b].loc.z + 21.0f;
628 if ((t->tris[b].loc.z < 21.0f) &
629 (t->tris[b].loc.z > 0)) {
630 zd = 21.0f - t->tris[b].loc.z;
634 if (t->tris[b].dir.x < 0)
635 t->tris[b].loc.x += (21.0f - t->tris[b].loc.x);
637 t->tris[b].loc.x += (-21.0f - t->tris[b].loc.x);
638 t->tris[b].dir.x = -t->tris[b].dir.x;
641 if (t->tris[b].dir.z < 0)
642 t->tris[b].loc.z += (21.0f - t->tris[b].loc.z);
644 t->tris[b].loc.z += (-21.0f - t->tris[b].loc.z);
645 t->tris[b].dir.z = -t->tris[b].dir.z;
654 * free memory allocated by a tri manager
656 static void freetris(triman *t)
659 if (t->tris) free(t->tris);
660 if (t->vertices) free(t->vertices);
661 if (t->normals) free(t->normals);
671 *load defaults in config structure
673 static void setdefaultconfig(boxed_config *config)
675 cfg_balls = MAX(3,MIN(40,cfg_balls));
676 cfg_ballsize = MAX(1.0f,MIN(5.0f,cfg_ballsize));
677 cfg_explosion = MAX(0.0f,MIN(50.0f,cfg_explosion));
678 cfg_decay = MAX(0.02f,MIN(0.90f,cfg_decay));
679 cfg_momentum = MAX(0.0f,MIN(1.0f,cfg_momentum));
681 config->numballs = cfg_balls;
682 config->textures = TRUE;
683 config->transparent = FALSE;
684 config->explosion = cfg_explosion;
685 config->decay = cfg_decay;
686 config->momentum = cfg_momentum;
687 config->ballsize = cfg_ballsize;
688 config->camspeed = 35.0f;
695 static int drawfilledbox(boxedstruct *boxed, int wire)
697 /* draws texture filled box,
698 top is drawn using the entire texture,
699 the sides are drawn using the edge of the texture
704 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
706 glVertex3f(-1.0,1.0,1.0);
708 glVertex3f(1.0,1.0,1.0);
710 glVertex3f(1.0,-1.0,1.0);
712 glVertex3f(-1.0,-1.0,1.0);
716 glVertex3f(1.0,1.0,-1.0);
718 glVertex3f(-1.0,1.0,-1.0);
720 glVertex3f(-1.0,-1.0,-1.0);
722 glVertex3f(1.0,-1.0,-1.0);
726 glVertex3f(-1.0,1.0,1.0);
728 glVertex3f(-1.0,-1.0,1.0);
730 glVertex3f(-1.0,-1.0,-1.0);
732 glVertex3f(-1.0,1.0,-1.0);
736 glVertex3f(1.0,1.0,1.0);
738 glVertex3f(1.0,1.0,-1.0);
740 glVertex3f(1.0,-1.0,-1.0);
742 glVertex3f(1.0,-1.0,1.0);
745 glTexCoord2f(0.0,0.0);
746 glVertex3f(-1.0,1.0,1.0);
747 glTexCoord2f(0.0,1.0);
748 glVertex3f(-1.0,1.0,-1.0);
749 glTexCoord2f(1.0,1.0);
750 glVertex3f(1.0,1.0,-1.0);
751 glTexCoord2f(1.0,0.0);
752 glVertex3f(1.0,1.0,1.0);
756 glVertex3f(-1.0,-1.0,1.0);
758 glVertex3f(-1.0,-1.0,-1.0);
760 glVertex3f(1.0,-1.0,-1.0);
762 glVertex3f(1.0,-1.0,1.0);
771 * Draw a box made of lines
773 static int drawbox(boxedstruct *boxed)
777 glBegin(GL_LINE_STRIP);
778 glVertex3f(-1.0,1.0,1.0);
779 glVertex3f(-1.0,1.0,-1.0); polys++;
780 glVertex3f(1.0,1.0,-1.0); polys++;
781 glVertex3f(1.0,1.0,1.0); polys++;
782 glVertex3f(-1.0,1.0,1.0); polys++;
785 glBegin(GL_LINE_STRIP);
786 glVertex3f(-1.0,-1.0,1.0);
787 glVertex3f(1.0,-1.0,1.0); polys++;
788 glVertex3f(1.0,-1.0,-1.0); polys++;
789 glVertex3f(-1.0,-1.0,-1.0); polys++;
790 glVertex3f(-1.0,-1.0,1.0); polys++;
792 /* connect top & bottom */
794 glVertex3f(-1.0,1.0,1.0);
795 glVertex3f(-1.0,-1.0,1.0); polys++;
796 glVertex3f(1.0,1.0,1.0);
797 glVertex3f(1.0,-1.0,1.0); polys++;
798 glVertex3f(1.0,1.0,-1.0);
799 glVertex3f(1.0,-1.0,-1.0); polys++;
800 glVertex3f(-1.0,1.0,-1.0);
801 glVertex3f(-1.0,-1.0,-1.0); polys++;
811 static int drawball(boxedstruct *gp, ball *b, int wire)
815 GLint *spherei = gp->spherei;
816 vectorf *spherev = gp->spherev;
821 glTranslatef(b->loc.x,b->loc.y,b->loc.z);
822 glScalef(b->radius,b->radius,b->radius);
823 glColor3f(b->color.x,b->color.y,b->color.z);
827 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
831 glMaterialfv(GL_FRONT, GL_EMISSION,col);
833 if (!gp->gllists[GLL_BALL]) {
834 glNewList(gp->listobjects + GLL_BALL,GL_COMPILE);
835 glBegin(wire ? GL_LINES : GL_TRIANGLES);
836 cnt = SPHERE_INDICES/3;
837 for (i=0; i<cnt; i++) {
839 glNormal3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
840 glVertex3f(spherev[spherei[pos+0]].x,spherev[spherei[pos+0]].y,spherev[spherei[pos+0]].z);
841 glNormal3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
842 gp->list_polys[GLL_BALL]++;
843 glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
845 glVertex3f(spherev[spherei[pos+1]].x,spherev[spherei[pos+1]].y,spherev[spherei[pos+1]].z);
846 glNormal3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
847 glVertex3f(spherev[spherei[pos+2]].x,spherev[spherei[pos+2]].y,spherev[spherei[pos+2]].z);
848 gp->list_polys[GLL_BALL]++;
852 gp->gllists[GLL_BALL] = 1;
854 glCallList(gp->listobjects + GLL_BALL);
855 polys += gp->list_polys[GLL_BALL];
864 * Draw a single triangle
866 static void drawtri(triman *t, int wire, int i)
868 const vectorf *spherev = t->vertices + i*3;
869 const vectorf *loc = &t->tris[i].loc;
871 glNormal3f(t->normals[i].x,t->normals[i].y,t->normals[i].z);
872 glVertex3f(spherev[0].x+loc->x,spherev[0].y+loc->y,spherev[0].z+loc->z);
873 glVertex3f(spherev[1].x+loc->x,spherev[1].y+loc->y,spherev[1].z+loc->z);
875 glVertex3f(spherev[1].x+loc->x,spherev[1].y+loc->y,spherev[1].z+loc->z);
876 glVertex3f(spherev[2].x+loc->x,spherev[2].y+loc->y,spherev[2].z+loc->z);
878 glVertex3f(spherev[2].x+loc->x,spherev[2].y+loc->y,spherev[2].z+loc->z);
879 glVertex3f(spherev[0].x+loc->x,spherev[0].y+loc->y,spherev[0].z+loc->z);
885 * Draw all triangles in triman
887 static int drawtriman(triman *t, int wire)
894 glColor3f(t->color.x,t->color.y,t->color.z);
898 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
902 glMaterialfv(GL_FRONT, GL_EMISSION,col);
903 glBegin(wire ? GL_LINES : GL_TRIANGLES);
905 for (i=0; i<t->num_tri; i++) {
906 if (t->tris[i].gone > 3) { continue; }
907 if (t->tris[i].gone > 0) {
908 glColor3f(t->color.x,t->color.y,t->color.z);
912 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
916 glMaterialfv(GL_FRONT, GL_EMISSION,col);
921 glColor3f(t->color.x,t->color.y,t->color.z);
925 glMaterialfv(GL_FRONT, GL_DIFFUSE, col);
929 glMaterialfv(GL_FRONT, GL_EMISSION,col);
946 static int drawpattern(boxedstruct *gp)
949 if (!gp->gllists[GLL_PATTERN]) {
950 glNewList(gp->listobjects + GLL_PATTERN, GL_COMPILE);
952 glBegin(GL_LINE_STRIP);
953 glVertex3f(-25.0f, 0.0f, 35.0f);
954 glVertex3f(-15.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
955 glVertex3f(-5.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
956 glVertex3f(5.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
957 glVertex3f(15.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
958 glVertex3f(25.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
959 glVertex3f(35.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
960 glVertex3f(35.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
961 glVertex3f(25.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
962 glVertex3f(25.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
963 glVertex3f(35.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
964 glVertex3f(35.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
965 glVertex3f(25.0f, 0.0f, -35.0f); gp->list_polys[GLL_PATTERN]++;
966 glVertex3f(15.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
967 glVertex3f(5.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
968 glVertex3f(-5.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
969 glVertex3f(-15.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
970 glVertex3f(-25.0f, 0.0f,-35.0f); gp->list_polys[GLL_PATTERN]++;
971 glVertex3f(-35.0f, 0.0f, -25.0f); gp->list_polys[GLL_PATTERN]++;
972 glVertex3f(-35.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
973 glVertex3f(-25.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
974 glVertex3f(-25.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
975 glVertex3f(-35.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
976 glVertex3f(-35.0f, 0.0f, 25.0f); gp->list_polys[GLL_PATTERN]++;
977 glVertex3f(-25.0f, 0.0f, 35.0f); gp->list_polys[GLL_PATTERN]++;
980 glBegin(GL_LINE_STRIP);
981 glVertex3f(-5.0f, 0.0f, 15.0f);
982 glVertex3f(5.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
983 glVertex3f(15.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
984 glVertex3f(15.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
985 glVertex3f(5.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
986 glVertex3f(-5.0f, 0.0f, -15.0f); gp->list_polys[GLL_PATTERN]++;
987 glVertex3f(-15.0f, 0.0f, -5.0f); gp->list_polys[GLL_PATTERN]++;
988 glVertex3f(-15.0f, 0.0f, 5.0f); gp->list_polys[GLL_PATTERN]++;
989 glVertex3f(-5.0f, 0.0f, 15.0f); gp->list_polys[GLL_PATTERN]++;
993 gp->gllists[GLL_PATTERN] = 1;
995 glCallList(gp->listobjects + GLL_PATTERN);
996 polys += gp->list_polys[GLL_PATTERN];
1004 * main rendering loop
1006 static void draw(ModeInfo * mi)
1008 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1009 int wire = MI_IS_WIREFRAME (mi);
1015 GLfloat dgray[4] = {0.3f, 0.3f, 0.3f, 1.0f};
1016 GLfloat black[4] = {0.0f, 0.0f, 0.0f, 1.0f};
1017 GLfloat lblue[4] = {0.4f,0.6f,1.0f };
1019 GLfloat l0_ambient[] = {0.0, 0.0, 0.0, 1.0};
1020 GLfloat l0_specular[] = {1.0, 1.0, 1.0, 1.0};
1021 GLfloat l0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
1022 GLfloat l0_position[] = {0.0, 0.0, 0.0, 1.0}; /* w != 0 -> positional light */
1023 GLfloat l1_ambient[] = {0.0, 0.0, 0.0, 1.0};
1024 GLfloat l1_specular[] = {1.0, 1.0, 1.0, 1.0};
1025 GLfloat l1_diffuse[] = {0.5, 0.5, 0.5, 1.0};
1026 GLfloat l1_position[] = {0.0, 1.0, 0.0, 0.0}; /* w = 0 -> directional light */
1028 mi->polygon_count = 0;
1030 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1033 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
1035 GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
1036 int o = (int) current_device_rotation();
1037 if (o != 0 && o != 180 && o != -180)
1038 glScalef (1/h, 1/h, 1/h);
1039 glRotatef(o, 0, 0, 1);
1044 gp->camtic += 0.01f + 0.01f * sin(gp->tic * speed);
1046 /* rotate camera around (0,0,0), looking at (0,0,0), up is (0,1,0) */
1047 r = CAMDISTANCE_MIN + (CAMDISTANCE_MAX - CAMDISTANCE_MIN) + (CAMDISTANCE_MAX - CAMDISTANCE_MIN)*cos((gp->camtic/CAMDISTANCE_SPEED) * speed);
1048 v1.x = r * sin((gp->camtic/gp->cam_x_speed) * speed);
1049 v1.z = r * cos((gp->camtic/gp->cam_x_speed) * speed);
1050 v1.y = CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT;
1052 v2.x = LOOKAT_R * sin((gp->camtic/(gp->cam_x_speed * 5.0f)) * speed);
1053 v2.z = LOOKAT_R * cos((gp->camtic/(gp->cam_x_speed * 5.0f)) * speed);
1054 v2.y = (CAM_HEIGHT * sin((gp->camtic/gp->cam_y_speed) * speed) + 1.02 * CAM_HEIGHT)/10.0;
1056 gluLookAt(v1.x,v1.y,v1.z,v2.x,v2.y,v2.x,0.0,1.0,0.0);
1059 glLightfv(GL_LIGHT0, GL_AMBIENT, l0_ambient);
1060 glLightfv(GL_LIGHT0, GL_DIFFUSE, l0_diffuse);
1061 glLightfv(GL_LIGHT0, GL_SPECULAR, l0_specular);
1062 glLightfv(GL_LIGHT0, GL_POSITION, l0_position);
1063 glLightfv(GL_LIGHT1, GL_AMBIENT, l1_ambient);
1064 glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diffuse);
1065 glLightfv(GL_LIGHT1, GL_SPECULAR, l1_specular);
1066 glLightfv(GL_LIGHT1, GL_POSITION, l1_position);
1067 glEnable(GL_LIGHT0);
1068 glEnable(GL_LIGHT1);
1072 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
1073 glMaterialfv(GL_FRONT, GL_EMISSION, lblue);
1074 glMaterialfv(GL_FRONT,GL_AMBIENT,black);
1075 glMaterialf(GL_FRONT, GL_SHININESS, 5.0);
1079 /* draw ground grid */
1080 /* glDisable(GL_DEPTH_TEST); */
1081 glDisable(GL_LIGHTING);
1083 glColor3f(0.1,0.1,0.6);
1084 for (dx= -2; dx<3; dx++) {
1085 for (dz= -2; dz<3; dz++) {
1087 glTranslatef(dx*30.0f, 0.0f, dz*30.0f);
1093 /* Set drawing mode for the boxes */
1094 glEnable(GL_DEPTH_TEST);
1095 if (!wire) glEnable(GL_TEXTURE_2D);
1097 glColor3f(1.0,1.0,1.0);
1098 glScalef(20.0,0.25,20.0);
1099 glTranslatef(0.0,2.0,0.0);
1100 mi->polygon_count += drawfilledbox(gp, wire);
1102 glDisable(GL_TEXTURE_2D);
1105 glColor3f(0.2,0.5,0.2);
1106 glScalef(20.0,20.0,0.25);
1107 glTranslatef(0.0,1.0,81.0);
1108 mi->polygon_count += drawbox(gp);
1112 glColor3f(0.2,0.5,0.2);
1113 glScalef(20.0,20.0,0.25);
1114 glTranslatef(0.0,1.0,-81.0);
1115 mi->polygon_count += drawbox(gp);
1119 glColor3f(0.2,0.5,0.2);
1120 glScalef(.25,20.0,20.0);
1121 glTranslatef(-81.0,1.0,0.0);
1122 mi->polygon_count += drawbox(gp);
1126 glColor3f(0.2,0.5,0.2);
1127 glScalef(.25,20.0,20.0);
1128 glTranslatef(81.0,1.0,0.0);
1129 mi->polygon_count += drawbox(gp);
1133 glEnable(GL_LIGHTING);
1135 glMaterialfv(GL_FRONT, GL_DIFFUSE, dgray);
1136 glMaterialfv(GL_FRONT, GL_EMISSION, black); /* turn it off before painting the balls */
1139 /* move the balls and shrapnel */
1140 updateballs(&gp->bman);
1142 glFrontFace(GL_CCW);
1143 for (i=0;i<gp->bman.num_balls;i++) {
1144 if (gp->bman.balls[i].justcreated) {
1145 gp->bman.balls[i].justcreated = FALSE;
1146 freetris(&gp->tman[i]);
1148 if (gp->bman.balls[i].bounced) {
1149 if (gp->tman[i].vertices == NULL) {
1150 createtrisfromball(&gp->tman[i],gp->spherev,gp->spherei,SPHERE_INDICES,&gp->bman.balls[i]);
1152 updatetris(&gp->tman[i]);
1154 glDisable(GL_CULL_FACE);
1155 mi->polygon_count += drawtriman(&gp->tman[i], wire);
1156 if (!wire) glEnable(GL_CULL_FACE);
1158 mi->polygon_count += drawball(gp, &gp->bman.balls[i], wire);
1168 * new window size or exposure
1170 ENTRYPOINT void reshape_boxed(ModeInfo *mi, int width, int height)
1172 GLfloat h = (GLfloat) height / (GLfloat) width;
1174 glViewport(0, 0, (GLint) width, (GLint) height);
1175 glMatrixMode(GL_PROJECTION);
1177 gluPerspective(50.0,1/h,2.0,1000.0);
1178 glMatrixMode (GL_MODELVIEW);
1186 pinit(ModeInfo * mi)
1188 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1189 int wire = MI_IS_WIREFRAME (mi);
1193 char *texpixeltarget;
1195 glShadeModel(GL_SMOOTH);
1197 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1199 /* Load configuration */
1200 setdefaultconfig(&gp->config);
1202 /* give the decay parameter a better curve */
1203 if (gp->config.decay <= 0.8182) { gp->config.decay = gp->config.decay / 3; }
1204 else { gp->config.decay = (gp->config.decay - 0.75) * 4; }
1208 bman->balls = (ball *)malloc(gp->config.numballs * sizeof(ball));
1209 bman->num_balls = gp->config.numballs;
1210 bman->ballsize = gp->config.ballsize;
1211 bman->explosion = gp->config.explosion;
1213 gp->tman = (triman *)malloc(bman->num_balls * sizeof(triman));
1214 memset(gp->tman,0,bman->num_balls * sizeof(triman));
1216 for(i=0;i<bman->num_balls;i++) {
1217 gp->tman[i].explosion = (float) (((int)gp->config.explosion) / 15.0f );
1218 gp->tman[i].decay = gp->config.decay;
1219 gp->tman[i].momentum = gp->config.momentum;
1220 gp->tman[i].vertices = NULL;
1221 gp->tman[i].normals = NULL;
1222 gp->tman[i].tris = NULL;
1223 createball(&bman->balls[i]);
1224 bman->balls[i].loc.y *= rnd();
1230 glEnable(GL_CULL_FACE);
1231 glEnable(GL_LIGHTING);
1234 /* define cam path */
1235 gp->cam_x_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1236 gp->cam_z_speed = 1.0f/((float)gp->config.camspeed/50.0 + rnd()*((float)gp->config.camspeed/50.0));
1237 gp->cam_y_speed = 1.0f/((float)gp->config.camspeed/250.0 + rnd()*((float)gp->config.camspeed/250.0));
1238 if (rnd() < 0.5f) gp->cam_x_speed = -gp->cam_x_speed;
1239 if (rnd() < 0.5f) gp->cam_z_speed = -gp->cam_z_speed;
1241 /* define initial cam position */
1242 gp->tic = gp->camtic = rnd() * 100.0f;
1244 /* define tex1 (bottom plate) */
1245 gp->tex1 = (char *)malloc(3*width*height*sizeof(GLuint));
1246 texpixels = 256*256; /*width*height;*/
1247 texpixeldata = header_data;
1248 texpixeltarget = gp->tex1;
1249 for (i=0; i < texpixels; i++) {
1250 HEADER_PIXEL(texpixeldata,texpixeltarget);
1251 texpixeltarget += 3;
1255 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1259 i = gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 256, 256,
1260 GL_RGB, GL_UNSIGNED_BYTE, gp->tex1);
1263 const char *s = (char *) gluErrorString (i);
1264 fprintf (stderr, "%s: error mipmapping texture: %s\n",
1265 progname, (s ? s : "(unknown)"));
1268 check_gl_error("mipmapping");
1270 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0,
1271 GL_RGB, GL_UNSIGNED_BYTE,
1273 check_gl_error("texture");
1276 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1277 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1278 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1279 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1280 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1286 static void free_boxed(ModeInfo * mi);
1289 init_boxed(ModeInfo * mi)
1291 int screen = MI_SCREEN(mi);
1293 /* Colormap cmap; */
1294 /* Boolean rgba, doublebuffer, cmap_installed; */
1297 MI_INIT(mi, boxed, free_boxed);
1298 gp = &boxed[screen];
1299 gp->window = MI_WINDOW(mi);
1301 if ((gp->glx_context = init_GL(mi)) != NULL) {
1302 reshape_boxed(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1303 glDrawBuffer(GL_BACK);
1304 if (!glIsList(gp->listobjects)) {
1305 gp->listobjects = glGenLists(3);
1318 draw_boxed(ModeInfo * mi)
1320 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1321 Display *display = MI_DISPLAY(mi);
1322 Window window = MI_WINDOW(mi);
1324 if (!gp->glx_context)
1327 glDrawBuffer(GL_BACK);
1329 glXMakeCurrent(display, window, *(gp->glx_context));
1332 if (mi->fps_p) do_fps (mi);
1334 glXSwapBuffers(display, window);
1338 free_boxed(ModeInfo * mi)
1340 boxedstruct *gp = &boxed[MI_SCREEN(mi)];
1343 if (gp->glx_context) {
1344 /* Display lists MUST be freed while their glXContext is current. */
1345 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1347 if (glIsList(gp->listobjects))
1348 glDeleteLists(gp->listobjects, 3);
1350 for (i=0;i<gp->bman.num_balls;i++) {
1351 if (gp->bman.balls[i].bounced) freetris(&gp->tman[i]);
1353 free (gp->bman.balls);
1362 XSCREENSAVER_MODULE ("Boxed", boxed)
1364 /*********************************************************/