1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* sproingies.c - 3D sproingies */
5 static const char sccsid[] = "@(#)sproingies.c 4.04 97/07/28 xlockmore";
9 * sproingies.c - Copyright 1996 by Ed Mackey, freely distributable.
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
29 #endif /* HAVE_CONFIG_H */
32 # include "xlockmoreI.h" /* from the xscreensaver distribution */
33 #else /* !STANDALONE */
34 # include "xlock.h" /* from the xlockmore distribution */
35 #endif /* !STANDALONE */
39 #if !defined(HAVE_JWZGLES) && !defined(HAVE_COCOA)
44 #include "sproingies.h"
46 #define MAXSPROING 100
47 #define TARGET_COUNT 40
49 #define NO_FRAME (-10)
50 #define RESET_SPROINGIE_LIFE (-30 + myrand(28))
51 #define NEW_SPROINGIE_LIFE (40 + myrand(200))
58 * The sproingies have six "real" frames, (s1_1 to s1_6) that show a
59 * sproingie jumping off a block, headed down and to the right.
60 * The frames are numbered from 0 (FIRST_FRAME) to 5 (LAST_FRAME).
62 * There are other frame numbers for special cases (e.g. BOOM_FRAME).
65 extern const struct gllist *s1_1;
66 extern const struct gllist *s1_2;
67 extern const struct gllist *s1_3;
68 extern const struct gllist *s1_4;
69 extern const struct gllist *s1_5;
70 extern const struct gllist *s1_6;
71 extern const struct gllist *s1_b;
76 return ((int) (((float) range) * LRAND() / (MAXRAND)));
79 static int smart_sproingies = 0;
82 build_TopsSides(int wireframe)
85 GLfloat mat_color[4] =
88 dl_num = glGenLists(2);
90 return (0); /* 0 means out of display lists. */
93 glNewList(dl_num, GL_COMPILE);
94 mat_color[0] = 0.392157;
95 mat_color[1] = 0.784314;
96 mat_color[2] = 0.941176;
98 glColor3fv(mat_color);
100 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_color);
105 glNewList(dl_num + 1, GL_COMPILE);
107 glColor3fv(mat_color);
109 /* jwz: in wireframe mode, color tops and sides the same. */
110 mat_color[0] = 0.156863;
111 mat_color[1] = 0.156863;
112 mat_color[2] = 0.392157;
113 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_color);
120 LayGround(int sx, int sy, int sz, int width, int height, sp_instance * si)
123 GLenum begin_polygon;
126 begin_polygon = GL_LINE_LOOP;
128 begin_polygon = GL_POLYGON;
130 if (!si->wireframe) {
132 glCallList(si->TopsSides); /* Render the tops */
133 glNormal3f(0.0, 1.0, 0.0);
135 for (h = 0; h < height; ++h) {
139 for (w = 0; w < width; ++w) {
140 glBegin(begin_polygon);
142 glVertex3i(x, y, z - 1);
143 glVertex3i(x + 1, y, z - 1);
144 glVertex3i(x + 1, y, z);
146 glBegin(begin_polygon);
147 glVertex3i(x + 1, y - 1, z);
148 glVertex3i(x + 1, y - 1, z - 1);
149 glVertex3i(x + 2, y - 1, z - 1);
150 glVertex3i(x + 2, y - 1, z);
158 glCallList(si->TopsSides + 1); /* Render the sides */
160 glNormal3f(0.0, 0.0, 1.0);
162 for (h = 0; h < height; ++h) {
166 for (w = 0; w < width; ++w) {
167 glBegin(begin_polygon);
169 glVertex3i(x + 1, y, z);
170 glVertex3i(x + 1, y - 1, z);
171 glVertex3i(x, y - 1, z);
173 glBegin(begin_polygon);
174 glVertex3i(x + 1, y - 1, z);
175 glVertex3i(x + 2, y - 1, z);
176 glVertex3i(x + 2, y - 2, z);
177 glVertex3i(x + 1, y - 2, z);
179 * PURIFY 4.0.1 reports an unitialized memory read on the next line when using
180 * MesaGL 2.2 and -mono. This has been fixed in MesaGL 2.3 and later. */
187 /* Render the other sides */
189 glNormal3f(1.0, 0.0, 0.0);
191 for (h = 0; h < height; ++h) {
195 for (w = 0; w < width; ++w) {
196 glBegin(begin_polygon);
197 glVertex3i(x + 1, y, z);
198 glVertex3i(x + 1, y, z - 1);
199 glVertex3i(x + 1, y - 1, z - 1);
200 glVertex3i(x + 1, y - 1, z);
202 glBegin(begin_polygon);
203 glVertex3i(x + 2, y - 1, z);
204 glVertex3i(x + 2, y - 1, z - 1);
205 glVertex3i(x + 2, y - 2, z - 1);
206 glVertex3i(x + 2, y - 2, z);
215 glCallList(si->TopsSides); /* Render the tops */
217 for (h = 0; h < height; ++h) {
221 for (w = 0; w < width; ++w) {
222 glBegin(begin_polygon);
224 glVertex3i(x, y, z - 1);
225 glVertex3i(x + 1, y, z - 1);
226 glVertex3i(x + 1, y, z);
228 glBegin(begin_polygon);
229 glVertex3i(x + 1, y - 1, z);
230 glVertex3i(x + 1, y - 1, z - 1);
231 glVertex3i(x + 2, y - 1, z - 1);
232 glVertex3i(x + 2, y - 1, z);
242 AdvanceSproingie(int t, sp_instance * si)
244 int g_higher, g_back, t2;
245 struct sPosColor *thisSproingie = &(si->positions[t]);
246 struct sPosColor *S2 = &(si->positions[0]);
248 if (thisSproingie->life > 0) {
249 if ((++(thisSproingie->frame)) > LAST_FRAME) {
250 if (thisSproingie->frame >= BOOM_FRAME) {
251 if ((thisSproingie->r -= 0.08) < 0.0)
252 thisSproingie->r = 0.0;
253 if ((thisSproingie->g -= 0.08) < 0.0)
254 thisSproingie->g = 0.0;
255 if ((thisSproingie->b -= 0.08) < 0.0)
256 thisSproingie->b = 0.0;
257 if ((--(thisSproingie->life)) < 1) {
258 thisSproingie->life = RESET_SPROINGIE_LIFE;
262 thisSproingie->frame = FIRST_FRAME;
264 /* Check for collisions */
265 for (t2 = 0; t2 < si->maxsproingies; ++t2) {
266 if ((t2 != t) && (thisSproingie->x == S2->x) &&
267 (thisSproingie->y == S2->y) && (thisSproingie->z == S2->z) &&
268 (S2->life > 10) && (S2->frame < LAST_FRAME + 1)) {
270 if (thisSproingie->life > S2->life) {
274 if (thisSproingie->life > 10) {
275 thisSproingie->life = 10;
276 thisSproingie->frame = BOOM_FRAME;
277 if ((thisSproingie->r += 0.5) > 1.0)
278 thisSproingie->r = 1.0;
279 if ((thisSproingie->g += 0.5) > 1.0)
280 thisSproingie->g = 1.0;
281 if ((thisSproingie->b += 0.5) > 1.0)
282 thisSproingie->b = 1.0;
291 /* Time to disappear... */
292 if (!((thisSproingie->life == 10) &&
293 (thisSproingie->frame > FIRST_FRAME) &&
294 (thisSproingie->frame < BOOM_FRAME))) {
295 if ((--(thisSproingie->life)) < 1) {
296 thisSproingie->life = RESET_SPROINGIE_LIFE;
297 } else if (thisSproingie->life < 9) {
298 thisSproingie->frame -= 2;
300 } /* ... else wait here for frame FIRST_FRAME to come about. */
301 } else if (++(thisSproingie->life) >= 0) {
303 g_higher = -3 + myrand(5);
304 g_back = -2 + myrand(5);
306 g_higher = -2 + myrand(3);
307 g_back = -1 + myrand(3);
313 thisSproingie->x = (-g_higher - g_back);
314 thisSproingie->y = (g_higher << 1);
315 thisSproingie->z = (g_back - g_higher);
316 thisSproingie->life = NEW_SPROINGIE_LIFE;
317 thisSproingie->frame = NO_FRAME;
318 thisSproingie->r = (GLfloat) (40 + myrand(200)) / 255.0;
319 thisSproingie->g = (GLfloat) (40 + myrand(200)) / 255.0;
320 thisSproingie->b = (GLfloat) (40 + myrand(200)) / 255.0;
322 for (t2 = 0; t2 < si->maxsproingies; ++t2) {
323 if ((t2 != t) && (thisSproingie->x == S2->x) &&
324 (thisSproingie->y == S2->y) && (thisSproingie->z == S2->z) &&
325 (S2->life > 10) && (S2->frame < FIRST_FRAME)) {
326 /* If another is already on this place, wait. */
327 thisSproingie->life = -1;
335 NextSproingie(sp_instance *si)
338 struct sPosColor *thisSproingie = &(si->positions[0]);
340 /* Although the sproingies cycle has six frames, the blocks cycle */
341 /* has twelve. After a full cycle (12 frames), re-center positions */
343 if (++si->sframe > 11) {
344 si->sframe = FIRST_FRAME;
345 for (t = 0; t < si->maxsproingies; ++t) {
346 thisSproingie->x -= 1;
347 thisSproingie->y += 2;
348 thisSproingie->z -= 1;
353 for (t = 0; t < si->maxsproingies; ++t) {
354 AdvanceSproingie(t, si);
357 if (si->target_count < 0) { /* track to current target */
358 if (si->target_rx < si->rotx)
360 else if (si->target_rx > si->rotx)
363 if (si->target_ry < si->roty)
365 else if (si->target_ry > si->roty)
368 ddx = (si->target_dist - si->dist) / 8;
371 else if (si->target_dist < si->dist)
373 else if (si->target_dist > si->dist)
376 if ((si->target_rx == si->rotx) && (si->target_ry == si->roty) &&
377 (si->target_dist == si->dist)) {
378 si->target_count = TARGET_COUNT;
379 if (si->target_dist <= 32)
380 si->target_count >>= 2;
382 } else if (--si->target_count < 0) { /* make up new target */
383 si->target_rx = myrand(100) - 35;
384 si->target_ry = -myrand(90);
385 si->target_dist = 32 << myrand(2); /* could be 32, 64, or 128, (previously or 256) */
387 if (si->target_dist >= si->dist) /* no duplicate distances */
388 si->target_dist <<= 1;
390 /* Otherwise just hang loose for a while here */
399 for (t = 0; t < maxsproingies; ++t) {
400 if (positions[t].life > 0)
403 (void) printf("RotX: %d, RotY: %d, Dist: %d. Targets: X %d, Y %d, D %d. Visible: %d\n",
404 rotx, roty, dist, target_rx, target_ry, target_dist, count);
412 for (t = 0; t < maxsproingies; ++t) {
416 positions[t].life = -2;
417 positions[t].frame = FIRST_FRAME;
424 if (dist < (1 << 16 << 4))
438 rotx = (rotx + 5) % 360;
444 rotx = (rotx - 5) % 360;
450 roty = (roty + 5) % 360;
456 roty = (roty - 5) % 360;
462 rotx = (rotx + 45) % 360;
468 rotx = (rotx - 45) % 360;
474 roty = (roty + 45) % 360;
480 roty = (roty - 45) % 360;
483 #endif /* __AUXFUNCS__ */
486 RenderSproingie(int t, sp_instance * si)
488 GLfloat scale, pointsize, mat_color[4] =
489 {0.0, 0.0, 0.0, 1.0};
491 GLdouble clipplane[4] =
492 {0.0, 1.0, 0.0, 0.0};
494 struct sPosColor *thisSproingie = &(si->positions[t]);
496 if (thisSproingie->life < 1)
502 mat_color[0] = thisSproingie->r;
503 mat_color[1] = thisSproingie->g;
504 mat_color[2] = thisSproingie->b;
506 glColor3fv(mat_color);
508 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_color);
512 if (thisSproingie->frame < FIRST_FRAME) {
513 glEnable(GL_CLIP_PLANE0);
514 glTranslatef((GLfloat) (thisSproingie->x),
515 (GLfloat) (thisSproingie->y) +
516 ((GLfloat) (thisSproingie->frame) / 9.0),
517 (GLfloat) (thisSproingie->z));
520 /* OpenGLES doesn't have this but it doesn't seem to matter */
521 clipplane[3] = ((GLdouble) (thisSproingie->frame) / 9.0) +
522 (si->wireframe ? 0.0 : 0.1);
523 glClipPlane(GL_CLIP_PLANE0, clipplane);
526 /** glCallList(si->sproingies[0]);*/
527 /**/ renderList(si->sproingies[0], si->wireframe);
528 glDisable(GL_CLIP_PLANE0);
529 } else if (thisSproingie->frame >= BOOM_FRAME) {
530 glTranslatef((GLfloat) (thisSproingie->x) + 0.5,
531 (GLfloat) (thisSproingie->y) + 0.5,
532 (GLfloat) (thisSproingie->z) - 0.5);
534 int boom_scale = thisSproingie->frame - BOOM_FRAME;
535 if (boom_scale >= 31) boom_scale = 31;
536 scale = (GLfloat) (1 << boom_scale);
538 glScalef(scale, scale, scale);
539 if (!si->wireframe) {
541 glColor3fv(mat_color);
542 glDisable(GL_LIGHTING);
544 pointsize = (GLfloat) ((BOOM_FRAME + 8) - thisSproingie->frame) -
546 glPointSize((pointsize < 1.0) ? 1.0 : pointsize);
548 * PURIFY 4.0.1 reports an unitialized memory read on the next line when using
549 * MesaGL 2.2. This has been tracked to MesaGL 2.2 src/points.c line 313. */
550 /** glCallList(si->SproingieBoom);*/
551 /**/ renderList(si->SproingieBoom, si->wireframe);
553 if (!si->wireframe) {
554 glEnable(GL_LIGHTING);
557 if (thisSproingie->direction == JUMP_LEFT) {
558 /* When the sproingie jumps to the left, the frames must be */
559 /* rotated and translated */
560 glTranslatef((GLfloat) (thisSproingie->x ),
561 (GLfloat) (thisSproingie->y ),
562 (GLfloat) (thisSproingie->z - 1));
563 glRotatef((GLfloat) - 90.0, 0.0, 1.0, 0.0);
564 if (thisSproingie->frame == LAST_FRAME) {
565 thisSproingie->x -= 0;
566 thisSproingie->y -= 1;
567 thisSproingie->z += 1;
570 glTranslatef((GLfloat) (thisSproingie->x),
571 (GLfloat) (thisSproingie->y),
572 (GLfloat) (thisSproingie->z));
573 glRotatef((GLfloat) - 0.0, 0.0, 1.0, 0.0);
574 if (thisSproingie->frame == LAST_FRAME) {
575 thisSproingie->x += 1;
576 thisSproingie->y -= 1;
577 thisSproingie->z -= 0;
581 /** glCallList(si->sproingies[thisSproingie->frame]);*/
582 /**/ renderList(si->sproingies[thisSproingie->frame], si->wireframe);
584 /* Every 6 frame cycle... */
585 if (thisSproingie->frame == LAST_FRAME) {
586 /* ...check if the sproingies have gone out of the bricks */
587 if (((thisSproingie->x - thisSproingie->z == 6) &&
588 (2*thisSproingie->x + thisSproingie->y == 6)) ||
589 ((thisSproingie->z - thisSproingie->x == 5) &&
590 (2*thisSproingie->x + thisSproingie->y == -5))) {
591 /* If they have, then they die */
592 if (thisSproingie->life > 0 && thisSproingie->frame < BOOM_FRAME && thisSproingie->frame > FIRST_FRAME) {
593 thisSproingie->frame = BOOM_FRAME;
596 /* If not, they choose a direction for the next hop */
597 if (smart_sproingies) {
598 if ((thisSproingie->x - thisSproingie->z == 5) &&
599 (2*thisSproingie->x + thisSproingie->y == 5)) {
600 thisSproingie->direction = JUMP_LEFT;
601 } else if ((thisSproingie->z - thisSproingie->x == 4) &&
602 (2*thisSproingie->x + thisSproingie->y == -4)) {
603 thisSproingie->direction = JUMP_RIGHT;
605 thisSproingie->direction = myrand(2);
608 thisSproingie->direction = myrand(2);
619 ComputeGround(sp_instance * si)
621 int g_higher, g_back, g_width, g_height;
623 /* higher: x-1, y+2, z-1 */
624 /* back: x-1, y, z+1 */
626 if (si->groundlevel == 0) {
629 } else if (si->groundlevel == 1) {
637 if ((g_higher = si->dist >> 3) < 4)
641 g_height = g_higher << 1;
644 g_higher += (g_higher >> 2);
645 else if (si->rotx > 10)
646 g_higher -= (g_higher >> 2);
649 if (si->dist > 128) {
653 } else if (si->dist > 64) {
656 } else if (si->dist > 32) {
657 /* nothing special */
660 g_higher = g_back = 4;
665 /* startx, starty, startz, width, height */
666 LayGround((-g_higher - g_back), (g_higher << 1), (g_back - g_higher),
667 (g_width), (g_height), si);
671 DisplaySproingies(sp_instance *si)
675 {8.0, 5.0, -2.0, 0.1};
678 glClear(GL_COLOR_BUFFER_BIT);
680 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
683 glTranslatef(0.0, 0.0, -(GLfloat) (si->dist) / 16.0); /* viewing transform */
684 glRotatef((GLfloat) si->rotx, 1.0, 0.0, 0.0);
685 glRotatef((GLfloat) si->roty, 0.0, 1.0, 0.0);
688 glLightfv(GL_LIGHT0, GL_POSITION, position);
690 #if 0 /* Show light pos */
692 glTranslatef(position[0], position[1], position[2]);
693 glColor3f(1.0, 1.0, 1.0);
694 if (!si->wireframe) {
695 glDisable(GL_LIGHTING);
697 glCallList(si->SproingieBoom);
698 if (!si->wireframe) {
699 glEnable(GL_LIGHTING);
704 glTranslatef((GLfloat) si->sframe * (-1.0 / 12.0) - 0.75,
705 (GLfloat) si->sframe * (2.0 / 12.0) - 0.5,
706 (GLfloat) si->sframe * (-1.0 / 12.0) + 0.75);
711 for (t = 0; t < si->maxsproingies; ++t) {
712 RenderSproingie(t, si);
723 NextSproingieDisplay(sp_instance *si)
726 /* if (pause) usleep(pause); don't do this! -jwz */
727 DisplaySproingies(si);
731 ReshapeSproingies(int w, int h)
733 glViewport(0, 0, w, h);
734 glMatrixMode(GL_PROJECTION);
736 gluPerspective(65.0, (GLfloat) w / (GLfloat) h, 0.1, 2000.0); /* was 200000.0 */
737 glMatrixMode(GL_MODELVIEW);
742 CleanupSproingies(sp_instance *si)
748 if (si->SproingieBoom) {
749 for (t = 0; t < 6; ++t)
750 glDeleteLists(si->sproingies[t], 1);
752 glDeleteLists(si->TopsSides, 2);
753 glDeleteLists(si->SproingieBoom, 1);
755 si->SproingieBoom = 0;
759 glDeleteLists(si->TopsSides, 2);
762 (void) free((void *) (si->positions));
763 si->positions = NULL;
768 InitSproingies(sp_instance *si, int wfmode, int grnd, int mspr, int smrtspr,
772 {0.2, 0.2, 0.2, 1.0};
774 {10.0, 1.0, 1.0, 10.0};
775 GLfloat mat_diffuse[] =
776 {0.6, 0.6, 0.6, 1.0};
777 GLfloat mat_specular[] =
778 {0.8, 0.8, 0.8, 1.0};
779 GLfloat mat_shininess[] =
784 memset (si, 0, sizeof(*si));
788 if (mspr >= MAXSPROING)
789 mspr = MAXSPROING - 1;
791 smart_sproingies = smrtspr;
795 si->dist = (16 << 2);
797 si->target_count = 0;
800 si->wireframe = si->flatshade = 0;
807 si->groundlevel = grnd;
808 si->maxsproingies = mspr;
810 if (si->maxsproingies) {
811 si->positions = (struct sPosColor *) calloc(si->maxsproingies,
812 sizeof (struct sPosColor));
814 if (!(si->positions))
815 si->maxsproingies = 0;
817 for (t = 0; t < si->maxsproingies; ++t) {
818 si->positions[t].x = 0;
819 si->positions[t].y = 0;
820 si->positions[t].z = 0;
821 si->positions[t].life = (-t * ((si->maxsproingies > 19) ? 1 : 4)) - 2;
822 si->positions[t].frame = FIRST_FRAME;
823 si->positions[t].direction = myrand(2);
826 #if 0 /* Test boom */
827 si->positions[0].x = 0;
828 si->positions[0].y = 0;
829 si->positions[0].z = 0;
830 si->positions[0].life = 10;
831 si->positions[0].frame = BOOM_FRAME;
832 si->positions[0].r = 0.656863;
833 si->positions[0].g = 1.0;
834 si->positions[0].b = 0.656863;
837 if (!(si->TopsSides = build_TopsSides(si->wireframe)))
838 (void) fprintf(stderr, "build_TopsSides\n");
840 if (!(si->sproingies[0] = BuildLWO(si->wireframe, &LWO_s1_1)))
841 (void) fprintf(stderr, "BuildLWO - 1\n");
842 if (!(si->sproingies[1] = BuildLWO(si->wireframe, &LWO_s1_2)))
843 (void) fprintf(stderr, "BuildLWO - 2\n");
844 if (!(si->sproingies[2] = BuildLWO(si->wireframe, &LWO_s1_3)))
845 (void) fprintf(stderr, "BuildLWO - 3\n");
846 if (!(si->sproingies[3] = BuildLWO(si->wireframe, &LWO_s1_4)))
847 (void) fprintf(stderr, "BuildLWO - 4\n");
848 if (!(si->sproingies[4] = BuildLWO(si->wireframe, &LWO_s1_5)))
849 (void) fprintf(stderr, "BuildLWO - 5\n");
850 if (!(si->sproingies[5] = BuildLWO(si->wireframe, &LWO_s1_6)))
851 (void) fprintf(stderr, "BuildLWO - 6\n");
853 if (!(si->SproingieBoom = BuildLWO(si->wireframe, &LWO_s1_b)))
854 (void) fprintf(stderr, "BuildLWO - b\n");
856 si->sproingies[0]=s1_1;
857 si->sproingies[1]=s1_2;
858 si->sproingies[2]=s1_3;
859 si->sproingies[3]=s1_4;
860 si->sproingies[4]=s1_5;
861 si->sproingies[5]=s1_6;
862 si->SproingieBoom=s1_b;
865 glShadeModel(GL_FLAT);
866 glDisable(GL_LIGHTING);
869 glShadeModel(GL_FLAT);
873 glEnable(GL_LIGHTING);
875 glDepthFunc(GL_LEQUAL);
876 glEnable(GL_DEPTH_TEST);
878 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
879 glLightfv(GL_LIGHT0, GL_POSITION, position);
881 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
882 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
883 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
885 /* glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); */
887 glEnable(GL_CULL_FACE);
890 /* glEnable(GL_NORMALIZE); */
896 /* End of sproingies.c */