1 /* glsnake, Copyright (c) 2001,2002
2 * Jamie Wilkinson, Andrew Bennetts, Peter Aylett
3 * jaq@spacepants.org, andrew@puzzling.org, peter@ylett.com
5 * ported to xscreensaver 15th Jan 2002 by Jamie Wilkinson
6 * http://spacepants.org/src/glsnake/
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <X11/Intrinsic.h>
25 extern XtAppContext app;
27 #define PROGCLASS "glsnake"
28 #define HACK_INIT glsnake_init
29 #define HACK_DRAW glsnake_draw
30 #define HACK_RESHAPE glsnake_reshape
31 #define sws_opts xlockmore_opts
33 #define DEF_SPEED "0.05"
34 #define DEF_EXPLODE "0.03"
35 #define DEF_VELOCITY "1.0"
36 #define DEF_ACCEL "0.1"
37 #define DEF_STATICTIME "5000"
38 #define DEF_YSPIN "0.10"
39 #define DEF_ZSPIN "0.14"
40 #define DEF_SCARYCOLOUR "False"
41 #define DEF_LABELS "True"
42 #define DEF_BBOX "False"
44 #define DEFAULTS "*delay: 30000 \n" \
46 "*showFPS: False \n" \
47 "*wireframe: False \n" \
48 "*speed: " DEF_SPEED " \n" \
49 "*explode: " DEF_EXPLODE " \n" \
50 "*velocity: " DEF_VELOCITY " \n" \
51 /* "*accel: " DEF_ACCEL " \n" */ \
52 "*statictime: " DEF_STATICTIME " \n" \
53 "*yspin: " DEF_YSPIN " \n" \
54 "*zspin: " DEF_ZSPIN " \n" \
55 "*scarycolour:" DEF_SCARYCOLOUR " \n" \
56 "*labels: " DEF_LABELS " \n" \
57 "*labelfont: -*-times-bold-r-normal-*-180-*\n" \
58 "*bbox: " DEF_BBOX "\n" \
63 #define countof(x) (sizeof((x))/sizeof((*x)))
65 #include "xlockmore.h"
67 #ifdef USE_GL /* whole file */
78 #include <sys/types.h>
85 typedef struct model_s {
90 typedef struct nodeang_s {
96 GLXContext * glx_context;
98 int node_list; /* name of the display list */
103 struct timeval last_iteration;
104 struct timeval last_morph;
122 } glsnake_configuration;
124 static glsnake_configuration *glc = NULL;
126 static GLfloat speed;
127 static GLfloat explode;
128 static GLfloat velocity;
129 /* static GLfloat accel; */
130 static long statictime;
131 static GLfloat yspin;
132 static GLfloat zspin;
133 static Bool scarycolour;
137 static XrmOptionDescRec opts[] = {
138 { "-speed", ".speed", XrmoptionSepArg, 0 },
139 { "-explode", ".explode", XrmoptionSepArg, 0 },
140 { "-velocity", ".velocity", XrmoptionSepArg, 0 },
141 /* { "-accel", ".accel", XrmoptionSepArg, 0 }, */
142 { "-statictime", ".statictime", XrmoptionSepArg, 0 },
143 { "-yspin", ".yspin", XrmoptionSepArg, 0 },
144 { "-zspin", ".zspin", XrmoptionSepArg, 0 },
145 { "-scarycolour", ".scarycolour", XrmoptionNoArg, "True" },
146 { "+scarycolour", ".scarycolour", XrmoptionNoArg, "False" },
147 { "-labels", ".labels", XrmoptionNoArg, "True" },
148 { "+labels", ".labels", XrmoptionNoArg, "False" },
150 { "-bbox", ".bbox", XrmoptionNoArg, "True" },
151 { "+bbox", ".bbox", XrmoptionNoArg, "False" },
155 static argtype vars[] = {
156 {(caddr_t *) &speed, "speed", "Speed", DEF_SPEED, t_Float},
157 {(caddr_t *) &explode, "explode", "Explode", DEF_EXPLODE, t_Float},
158 {(caddr_t *) &velocity, "velocity", "Velocity", DEF_VELOCITY, t_Float},
159 /* {(caddr_t *) &accel, "accel", "Acceleration", DEF_ACCEL, t_Float}, */
160 {(caddr_t *) &statictime, "statictime", "Static Time", DEF_STATICTIME, t_Int},
161 {(caddr_t *) &yspin, "yspin", "Y Spin", DEF_YSPIN, t_Float},
162 {(caddr_t *) &zspin, "zspin", "Z Spin", DEF_ZSPIN, t_Float},
163 /* {(caddr_t *) &interactive, "interactive", "Interactive", DEF_INTERACTIVE, t_Bool}, */
164 {(caddr_t *) &scarycolour, "scarycolour", "Scary Colour", DEF_SCARYCOLOUR, t_Bool},
165 {(caddr_t *) &labels, "labels", "Labels", DEF_LABELS, t_Bool},
166 {(caddr_t *) &do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool},
169 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
172 #define VOFFSET 0.045
173 float solid_prism_v[][3] = {
174 /* first corner, bottom left front */
175 { VOFFSET, VOFFSET, 1.0 },
176 { VOFFSET, 0.0, 1.0 - VOFFSET },
177 { 0.0, VOFFSET, 1.0 - VOFFSET },
178 /* second corner, rear */
179 { VOFFSET, VOFFSET, 0.00 },
180 { VOFFSET, 0.0, VOFFSET },
181 { 0.0, VOFFSET, VOFFSET },
182 /* third, right front */
183 { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 1.0 },
184 { 1.0 - VOFFSET / M_SQRT1_2, 0.0, 1.0 - VOFFSET },
185 { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, 1.0 - VOFFSET },
186 /* fourth, right rear */
187 { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 0.0 },
188 { 1.0 - VOFFSET / M_SQRT1_2, 0.0, VOFFSET },
189 { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, VOFFSET },
190 /* fifth, upper front */
191 { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 1.0 },
192 { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, 1.0 - VOFFSET },
193 { 0.0, 1.0 - VOFFSET / M_SQRT1_2, 1.0 - VOFFSET},
194 /* sixth, upper rear */
195 { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 0.0 },
196 { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, VOFFSET },
197 { 0.0, 1.0 - VOFFSET / M_SQRT1_2, VOFFSET }
201 float solid_prism_n[][3] = {
203 { -VOFFSET, -VOFFSET, VOFFSET },
204 { VOFFSET, -VOFFSET, VOFFSET },
205 { -VOFFSET, VOFFSET, VOFFSET },
206 { -VOFFSET, -VOFFSET, -VOFFSET },
207 { VOFFSET, -VOFFSET, -VOFFSET },
208 { -VOFFSET, VOFFSET, -VOFFSET },
210 { -VOFFSET, 0.0, VOFFSET },
211 { 0.0, -VOFFSET, VOFFSET },
212 { VOFFSET, VOFFSET, VOFFSET },
213 { -VOFFSET, 0.0, -VOFFSET },
214 { 0.0, -VOFFSET, -VOFFSET },
215 { VOFFSET, VOFFSET, -VOFFSET },
216 { -VOFFSET, -VOFFSET, 0.0 },
217 { VOFFSET, -VOFFSET, 0.0 },
218 { -VOFFSET, VOFFSET, 0.0 },
222 { M_SQRT1_2, M_SQRT1_2, 0.0 },
228 float wire_prism_v[][3] = {
238 float wire_prism_n[][3] = {
241 { M_SQRT1_2, M_SQRT1_2, 0.0},
252 static model_t default_models[] = {
254 { R, R, L, L, R, L, R, R, L, R, L, L, R, R, L, L, R, L, R, R, L, R, L }
257 { R, R, R, R, L, L, L, L, R, R, R, R, L, L, L, L, R, R, R, R, L, L, L }
260 { Z, Z, Z, R, L, R, Z, L, Z, Z, Z, R, L, R, Z, L, Z, Z, Z, R, L, R, Z }
263 { Z, P, Z, Z, Z, Z, Z, P, R, R, P, R, L, P, L, R, P, R, R, Z, Z, Z, P }
266 { Z, P, P, Z, P, P, Z, L, Z, P, P, Z, P, P, Z, P, P, Z, Z, Z, Z, Z, Z }
269 { Z, Z, P, P, Z, L, Z, L, R, P, R, Z, P, P, Z, R, P, R, L, Z, L, Z, P }
273 /* add a model to the model list */
274 model_t * add_model(model_t * models, char * name, int * rotations, int * count)
279 models = realloc(models, sizeof(model_t) * (*count));
280 models[(*count)-1].name = strdup(name);
282 fprintf(stderr, "resized models to %d bytes for model %s\n", sizeof(model_t) * (*count), models[(*count)-1].name);
284 for (i = 0; i < 24; i++) {
285 models[(*count)-1].node[i] = rotations[i] * 90.0;
290 /* filename is the name of the file to load
291 * models is the pointer to where the models will be kept
292 * returns a new pointer to models
293 * count is number of models read
295 model_t * load_modelfile(char * filename, model_t * models, int * count)
304 f = fopen(filename, "r");
306 int error_msg_len = strlen(filename) + 33 + 1;
307 char * error_msg = (char *) malloc(sizeof(char) * error_msg_len);
308 sprintf(error_msg, "Unable to open model data file \"%s\"", filename);
314 while ((c = getc(f)) != EOF) {
316 /* ignore comments */
322 buffy[name-1] = '\0';
328 /* print out the model we just read in */
330 printf("%s: ", buffy);
331 for (i = 0; i < rots; i++) {
332 switch (rotations[i]) {
349 models = add_model(models, buffy, rotations, count);
359 fprintf(stderr, "buffy overflow warning\n");
364 rotations[rots] = ZERO;
369 rotations[rots] = LEFT;
374 rotations[rots] = PIN;
379 rotations[rots] = RIGHT;
392 model_t * load_models(char * dirpath, model_t * models, int * count)
398 if ((dfd = opendir(dirpath)) == NULL) {
399 if (strstr(dirpath, "data") == NULL)
400 /* fprintf(stderr, "load_models: can't read %s/\n", dirpath); */
403 while ((dp = readdir(dfd)) != NULL) {
404 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
406 if (strlen(dirpath) + strlen(dp->d_name) + 2 > sizeof(name))
407 fprintf(stderr, "load_models: name %s/%s too long\n", dirpath, dp->d_name);
409 sprintf(name, "%s/%s", dirpath, dp->d_name);
410 if (strcmp(&name[(int) strlen(name) - 7], "glsnake") == 0) {
412 fprintf(stderr, "load_models: opening %s\n", name);
414 models = load_modelfile(name, models, count);
426 #define GETSCALAR(vec,mask) ((vec)==(mask) ? 1 : ((vec)==-(mask) ? -1 : 0 ))
428 int cross_product(int src_dir, int dest_dir)
430 return X_MASK * (GETSCALAR(src_dir, Y_MASK) * GETSCALAR(dest_dir, Z_MASK) -
431 GETSCALAR(src_dir, Z_MASK) * GETSCALAR(dest_dir, Y_MASK)) +
432 Y_MASK * (GETSCALAR(src_dir, Z_MASK) * GETSCALAR(dest_dir, X_MASK) -
433 GETSCALAR(src_dir, X_MASK) * GETSCALAR(dest_dir, Z_MASK)) +
434 Z_MASK * (GETSCALAR(src_dir, X_MASK) * GETSCALAR(dest_dir, Y_MASK) -
435 GETSCALAR(src_dir, Y_MASK) * GETSCALAR(dest_dir, X_MASK));
438 void calc_snake_metrics(glsnake_configuration * bp)
440 int src_dir, dest_dir;
442 int prev_src_dir = -Y_MASK;
443 int prev_dest_dir = Z_MASK;
444 int grid[25][25][25];
447 memset(&grid, 0, sizeof(int) * 25*25*25);
452 /* trace path of snake and keep record for is_legal */
453 for (i = 0; i < 23; i++) {
454 /* establish new state variables */
455 src_dir = -prev_dest_dir;
456 x += GETSCALAR(prev_dest_dir, X_MASK);
457 y += GETSCALAR(prev_dest_dir, Y_MASK);
458 z += GETSCALAR(prev_dest_dir, Z_MASK);
460 switch ((int) bp->node[i].dest_angle) {
461 case (int) (ZERO * 90.0):
462 dest_dir = -prev_src_dir;
464 case (int) (PIN * 90.0):
465 dest_dir = prev_src_dir;
467 case (int) (RIGHT * 90.):
468 case (int) (LEFT * 90.0):
469 dest_dir = cross_product(prev_src_dir, prev_dest_dir);
470 if (bp->node[i].dest_angle == (int) (RIGHT * 90.0))
471 dest_dir = -dest_dir;
474 /* prevent spurious "might be used uninitialised" warnings */
479 if (grid[x][y][z] == 0)
480 grid[x][y][z] = src_dir + dest_dir;
481 else if (grid[x][y][z] + src_dir + dest_dir == 0)
486 prev_src_dir = src_dir;
487 prev_dest_dir = dest_dir;
490 /* determine if the snake is cyclic */
491 bp->is_cyclic = (dest_dir == Y_MASK && x == 12 && y == 11 && x == 12);
493 /* determine last turn */
498 bp->last_turn = ZERO * 90.0;
501 bp->last_turn = PIN * 90.0;
504 bp->last_turn = LEFT * 90.0;
507 bp->last_turn = RIGHT * 90.0;
513 void set_colours(glsnake_configuration * bp, int immediate)
515 /* set target colour */
517 bp->colour_t[0] = 0.5;
518 bp->colour_t[1] = 0.5;
519 bp->colour_t[2] = 0.5;
520 } else if (bp->is_cyclic) {
521 bp->colour_t[0] = 0.4;
522 bp->colour_t[1] = 0.8;
523 bp->colour_t[2] = 0.2;
525 bp->colour_t[0] = 0.3;
526 bp->colour_t[1] = 0.1;
527 bp->colour_t[2] = 0.9;
530 bp->colour_i[0] = bp->colour_t[0] - bp->colour[0];
531 bp->colour_i[1] = bp->colour_t[1] - bp->colour[1];
532 bp->colour_i[2] = bp->colour_t[2] - bp->colour[2];
534 /* instead of 50.0, I should actually work out how many times this gets
535 * called during a morph */
536 bp->colour_i[0] = (bp->colour_t[0] - bp->colour[0]) / 50.0;
537 bp->colour_i[1] = (bp->colour_t[1] - bp->colour[1]) / 50.0;
538 bp->colour_i[2] = (bp->colour_t[2] - bp->colour[2]) / 50.0;
542 void start_morph(int model_index, int immediate, glsnake_configuration * bp)
546 for (i = 0; i < 23; i++) {
547 bp->node[i].dest_angle = bp->models[model_index].node[i];
549 bp->node[i].cur_angle = bp->models[model_index].node[i];
552 calc_snake_metrics(bp);
554 bp->cur_model = model_index;
561 void draw_label(ModeInfo * mi)
563 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
565 glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT);
566 glDisable(GL_LIGHTING);
567 glDisable(GL_DEPTH_TEST);
568 glMatrixMode(GL_PROJECTION);
571 glMatrixMode(GL_MODELVIEW);
574 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
575 glColor3f(1.0, 1.0, 0.0);
583 s = bp->models[bp->cur_model].name;
588 for (i = 0; i < l; i++) {
589 w += (bp->font->per_char
590 ? bp->font->per_char[((int)s[i]) - bp->font->min_char_or_byte2].rbearing
591 : bp->font->min_bounds.rbearing);
595 glRasterPos2f(10, mi->xgwa.height - 10 - (bp->font->ascent + bp->font->descent));
596 /* mi->xgwa.width - w, bp->font->descent + bp->font->ascent); */
598 /* fprintf(stderr, "afaf.width = %d, w = %d\n", mi->xgwa.width, w); */
600 for (i = 0; i < l; i++)
601 glCallList(bp->font_list + (int)s[i]);
604 glMatrixMode(GL_PROJECTION);
609 /* load the fonts -- this function borrowed from molecule.c */
610 static void load_font(ModeInfo * mi, char * res, XFontStruct ** fontp, GLuint * dlistp)
612 const char * font = get_string_resource(res, "Font");
618 font = "-*-helvetica-medium-r-*-*-*-120-*";
620 f = XLoadQueryFont(mi->dpy, font);
622 f = XLoadQueryFont(mi->dpy, "fixed");
625 first = f->min_char_or_byte2;
626 last = f->max_char_or_byte2;
629 *dlistp = glGenLists((GLuint) last + 1);
630 check_gl_error("glGenLists");
631 glXUseXFont(id, first, last - first + 1, *dlistp + first);
632 check_gl_error("glXUseXFont");
639 /* window management */
640 void glsnake_reshape(ModeInfo *mi, int w, int h)
642 glViewport (0, 0, (GLint) w, (GLint) h);
643 glMatrixMode(GL_PROJECTION);
645 gluPerspective(25.0, w/(GLfloat)h, 1.0, 100.0 );
646 glMatrixMode(GL_MODELVIEW);
650 static void gl_init(ModeInfo *mi)
652 /* glsnake_configuration *bp = &glc[MI_SCREEN(mi)]; */
653 int wire = MI_IS_WIREFRAME(mi);
654 float light_pos[][3] = {{0.0,0.0,20.0},{0.0,20.0,0.0}};
655 float light_dir[][3] = {{0.0,0.0,-20.0},{0.0,-20.0,0.0}};
657 glClearColor(0.0, 0.0, 0.0, 0.0);
658 glEnable(GL_DEPTH_TEST);
659 glShadeModel(GL_SMOOTH);
661 glEnable(GL_CULL_FACE);
662 glEnable(GL_NORMALIZE);
665 glColor3f(1.0, 1.0, 1.0);
666 glLightfv(GL_LIGHT0, GL_POSITION, light_pos[0]);
667 glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_dir[0]);
668 glLightfv(GL_LIGHT1, GL_POSITION, light_pos[1]);
669 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_dir[1]);
670 glEnable(GL_LIGHTING);
673 glEnable(GL_COLOR_MATERIAL);
677 /* lifted from lament.c */
678 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
679 #define RANDSIGN() ((random() & 1) ? 1 : -1)
681 void glsnake_init(ModeInfo *mi)
683 glsnake_configuration * bp;
684 int wire = MI_IS_WIREFRAME(mi);
687 glc = (glsnake_configuration *) calloc(MI_NUM_SCREENS(mi), sizeof(glsnake_configuration));
689 fprintf(stderr, "%s: out of memory\n", progname);
692 bp = &glc[MI_SCREEN(mi)];
695 bp = &glc[MI_SCREEN(mi)];
697 if ((bp->glx_context = init_GL(mi)) != NULL) {
699 glsnake_reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
702 /* initialise config variables */
703 memset(&bp->node, 0, sizeof(nodeang_t) * 24);
704 bp->m_count = sizeof(default_models) / sizeof(model_t); /* overwrite this in a bit */
717 # ifdef GETTIMEOFDAY_TWO_ARGS
719 gettimeofday(&bp->last_iteration, &tzp);
721 gettimeofday(&bp->last_iteration);
725 memcpy(&bp->last_morph, &(bp->last_iteration),
726 sizeof(bp->last_morph));
727 /* srand((unsigned int) bp->last_iteration.time); */
729 /* load the model files */
730 /* first copy the defaults to bp->m_count */
731 bp->models = (model_t *) malloc(sizeof(model_t) * bp->m_count);
732 memcpy(bp->models, default_models, bp->m_count * sizeof(model_t));
733 /* then add on models from the Debian model file location */
734 bp->models = load_models("/usr/share/glsnake", bp->models, &(bp->m_count));
736 bp->m = bp->cur_model = RAND(bp->m_count);
737 start_morph(bp->cur_model, 1, bp);
739 calc_snake_metrics(bp);
742 /* set up a font for the labels */
744 load_font(mi, "labelfont", &bp->font, &bp->font_list);
746 bp->node_list = glGenLists(1);
747 glNewList(bp->node_list, GL_COMPILE);
750 glBegin(GL_TRIANGLES);
751 glNormal3fv(solid_prism_n[0]);
752 glVertex3fv(solid_prism_v[0]);
753 glVertex3fv(solid_prism_v[2]);
754 glVertex3fv(solid_prism_v[1]);
756 glNormal3fv(solid_prism_n[1]);
757 glVertex3fv(solid_prism_v[6]);
758 glVertex3fv(solid_prism_v[7]);
759 glVertex3fv(solid_prism_v[8]);
761 glNormal3fv(solid_prism_n[2]);
762 glVertex3fv(solid_prism_v[12]);
763 glVertex3fv(solid_prism_v[13]);
764 glVertex3fv(solid_prism_v[14]);
766 glNormal3fv(solid_prism_n[3]);
767 glVertex3fv(solid_prism_v[3]);
768 glVertex3fv(solid_prism_v[4]);
769 glVertex3fv(solid_prism_v[5]);
771 glNormal3fv(solid_prism_n[4]);
772 glVertex3fv(solid_prism_v[9]);
773 glVertex3fv(solid_prism_v[11]);
774 glVertex3fv(solid_prism_v[10]);
776 glNormal3fv(solid_prism_n[5]);
777 glVertex3fv(solid_prism_v[16]);
778 glVertex3fv(solid_prism_v[15]);
779 glVertex3fv(solid_prism_v[17]);
784 glNormal3fv(solid_prism_n[6]);
785 glVertex3fv(solid_prism_v[0]);
786 glVertex3fv(solid_prism_v[12]);
787 glVertex3fv(solid_prism_v[14]);
788 glVertex3fv(solid_prism_v[2]);
790 glNormal3fv(solid_prism_n[7]);
791 glVertex3fv(solid_prism_v[0]);
792 glVertex3fv(solid_prism_v[1]);
793 glVertex3fv(solid_prism_v[7]);
794 glVertex3fv(solid_prism_v[6]);
796 glNormal3fv(solid_prism_n[8]);
797 glVertex3fv(solid_prism_v[6]);
798 glVertex3fv(solid_prism_v[8]);
799 glVertex3fv(solid_prism_v[13]);
800 glVertex3fv(solid_prism_v[12]);
802 glNormal3fv(solid_prism_n[9]);
803 glVertex3fv(solid_prism_v[3]);
804 glVertex3fv(solid_prism_v[5]);
805 glVertex3fv(solid_prism_v[17]);
806 glVertex3fv(solid_prism_v[15]);
808 glNormal3fv(solid_prism_n[10]);
809 glVertex3fv(solid_prism_v[3]);
810 glVertex3fv(solid_prism_v[9]);
811 glVertex3fv(solid_prism_v[10]);
812 glVertex3fv(solid_prism_v[4]);
814 glNormal3fv(solid_prism_n[11]);
815 glVertex3fv(solid_prism_v[15]);
816 glVertex3fv(solid_prism_v[16]);
817 glVertex3fv(solid_prism_v[11]);
818 glVertex3fv(solid_prism_v[9]);
820 glNormal3fv(solid_prism_n[12]);
821 glVertex3fv(solid_prism_v[1]);
822 glVertex3fv(solid_prism_v[2]);
823 glVertex3fv(solid_prism_v[5]);
824 glVertex3fv(solid_prism_v[4]);
826 glNormal3fv(solid_prism_n[13]);
827 glVertex3fv(solid_prism_v[8]);
828 glVertex3fv(solid_prism_v[7]);
829 glVertex3fv(solid_prism_v[10]);
830 glVertex3fv(solid_prism_v[11]);
832 glNormal3fv(solid_prism_n[14]);
833 glVertex3fv(solid_prism_v[13]);
834 glVertex3fv(solid_prism_v[16]);
835 glVertex3fv(solid_prism_v[17]);
836 glVertex3fv(solid_prism_v[14]);
840 glBegin(GL_TRIANGLES);
841 glNormal3fv(solid_prism_n[15]);
842 glVertex3fv(solid_prism_v[0]);
843 glVertex3fv(solid_prism_v[6]);
844 glVertex3fv(solid_prism_v[12]);
846 glNormal3fv(solid_prism_n[19]);
847 glVertex3fv(solid_prism_v[3]);
848 glVertex3fv(solid_prism_v[15]);
849 glVertex3fv(solid_prism_v[9]);
853 glNormal3fv(solid_prism_n[16]);
854 glVertex3fv(solid_prism_v[1]);
855 glVertex3fv(solid_prism_v[4]);
856 glVertex3fv(solid_prism_v[10]);
857 glVertex3fv(solid_prism_v[7]);
859 glNormal3fv(solid_prism_n[17]);
860 glVertex3fv(solid_prism_v[8]);
861 glVertex3fv(solid_prism_v[11]);
862 glVertex3fv(solid_prism_v[16]);
863 glVertex3fv(solid_prism_v[13]);
865 glNormal3fv(solid_prism_n[18]);
866 glVertex3fv(solid_prism_v[2]);
867 glVertex3fv(solid_prism_v[14]);
868 glVertex3fv(solid_prism_v[17]);
869 glVertex3fv(solid_prism_v[5]);
872 /* build wire display list */
873 glBegin(GL_LINE_STRIP);
874 glVertex3fv(wire_prism_v[0]);
875 glVertex3fv(wire_prism_v[1]);
876 glVertex3fv(wire_prism_v[2]);
877 glVertex3fv(wire_prism_v[0]);
878 glVertex3fv(wire_prism_v[3]);
879 glVertex3fv(wire_prism_v[4]);
880 glVertex3fv(wire_prism_v[5]);
881 glVertex3fv(wire_prism_v[3]);
885 glVertex3fv(wire_prism_v[1]);
886 glVertex3fv(wire_prism_v[4]);
887 glVertex3fv(wire_prism_v[2]);
888 glVertex3fv(wire_prism_v[5]);
894 /* "jwz? no way man, he's my idle" -- Jaq, 2001.
895 * I forget the context :( */
896 void glsnake_idol(glsnake_configuration * bp)
898 /* time since last iteration */
900 /* time since the beginning of last morph */
902 float iter_angle_max;
904 struct timeval current_time;
907 /* Do nothing to the model if we are paused */
909 /* Avoid busy waiting when nothing is changing */
915 # ifdef GETTIMEOFDAY_TWO_ARGS
917 gettimeofday(¤t_time, &tzp);
919 gettimeofday(¤t_time);
923 /* <spiv> Well, ftime gives time with millisecond resolution.
924 * <Jaq> if current time is exactly equal to last iteration,
925 * then don't do this block
926 * <spiv> (or worse, perhaps... who knows what the OS will do)
927 * <spiv> So if no discernable amount of time has passed:
928 * <spiv> a) There's no point updating the screen, because
929 * it would be the same
930 * <spiv> b) The code will divide by zero
932 iter_msec = ((long) current_time.tv_usec - bp->last_iteration.tv_usec)/1000L +
933 ((long) current_time.tv_sec - bp->last_iteration.tv_sec) * 1000L;
935 /* save the current time */
936 memcpy(&bp->last_iteration, ¤t_time,
937 sizeof(bp->last_iteration));
939 /* work out if we have to switch models */
940 morf_msec = (bp->last_iteration.tv_usec - bp->last_morph.tv_usec)/1000L +
941 ((long) (bp->last_iteration.tv_sec - bp->last_morph.tv_sec) * 1000L);
943 if ((morf_msec > statictime) && !bp->interactive) {
944 memcpy(&bp->last_morph, &(bp->last_iteration),
945 sizeof(bp->last_morph));
946 start_morph(RAND(bp->m_count), 0, bp);
949 if (bp->interactive && !bp->morphing) {
954 if (!bp->dragging && !bp->interactive) {
955 bp->roty += 360/((1000/yspin)/iter_msec);
956 bp->rotz += 360/((1000/zspin)/iter_msec);
959 /* work out the maximum angle for this iteration */
960 iter_angle_max = 90.0 * (velocity/1000.0) * iter_msec;
963 for (i = 0; i < 24; i++) {
964 float cur_angle = bp->node[i].cur_angle;
965 float dest_angle = bp->node[i].dest_angle;
966 if (cur_angle != dest_angle) {
968 if (fabs(cur_angle - dest_angle) <= iter_angle_max)
969 bp->node[i].cur_angle = dest_angle;
970 else if (fmod(cur_angle - dest_angle + 360, 360) > 180)
971 bp->node[i].cur_angle = fmod(cur_angle + iter_angle_max, 360);
973 bp->node[i].cur_angle = fmod(cur_angle + 360 - iter_angle_max, 360);
981 if (fabs(bp->colour[0] - bp->colour_t[0]) <= fabs(bp->colour_i[0]))
982 bp->colour[0] = bp->colour_t[0];
984 bp->colour[0] += bp->colour_i[0];
985 if (fabs(bp->colour[1] - bp->colour_t[1]) <= fabs(bp->colour_i[1]))
986 bp->colour[1] = bp->colour_t[1];
988 bp->colour[1] += bp->colour_i[1];
989 if (fabs(bp->colour[2] - bp->colour_t[2]) <= fabs(bp->colour_i[2]))
990 bp->colour[2] = bp->colour_t[2];
992 bp->colour[2] += bp->colour_i[2];
994 /* We are going too fast, so we may as well let the
995 * cpu relax a little by sleeping for a millisecond. */
1001 snake_bounding_box (ModeInfo *mi,
1002 GLfloat *x1, GLfloat *y1, GLfloat *z1,
1003 GLfloat *x2, GLfloat *y2, GLfloat *z2)
1005 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
1007 GLdouble identity[16] = { 1, 0, 0, 0,
1011 GLint vp[4] = { 0, 0, 1, 1 };
1018 for (i = 0; i < 24; i++)
1022 GLfloat ang = bp->node[i].cur_angle;
1024 glGetDoublev (GL_MODELVIEW_MATRIX, model);
1025 gluProject (0, 0, 0, model, identity, vp, &x, &y, &z);
1026 fprintf (stderr, "%2d: %5.2f %5.2f %5.2f\n", i, (float)x, (float)y, (float)z);
1028 if (x < *x1) *x1 = x;
1029 else if (x > *x2) *x2 = x;
1030 if (y < *y1) *y1 = y;
1031 else if (y > *y2) *y2 = y;
1032 if (z < *z1) *z1 = z;
1033 else if (z > *z2) *z2 = z;
1035 glTranslatef(0.5, 0.5, 0.5);
1036 glRotatef(90, 0.0, 0.0, -1.0);
1037 glTranslatef(1.0 + explode, 0.0, 0.0);
1038 glRotatef(180 + ang, 1.0, 0.0, 0.0);
1039 glTranslatef(-0.5, -0.5, -0.5);
1041 fprintf(stderr, "\n");
1056 draw_bounding_box (ModeInfo *mi)
1058 static GLfloat c1[4] = { 0.4, 0.4, 0.4, 1.0 };
1059 static GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
1060 int wire = MI_IS_WIREFRAME(mi);
1061 GLfloat x1, y1, z1, x2, y2, z2;
1062 snake_bounding_box (mi, &x1, &y1, &z1, &x2, &y2, &z2);
1064 glColor3f (c1[0], c1[1], c1[2]);
1065 /* glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);*/
1066 glFrontFace(GL_CCW);
1068 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1069 glNormal3f(0, 1, 0);
1070 glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
1071 glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
1073 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1074 glNormal3f(0, -1, 0);
1075 glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2);
1076 glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1);
1078 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1079 glNormal3f(0, 0, 1);
1080 glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
1081 glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
1083 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1084 glNormal3f(0, 0, -1);
1085 glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2);
1086 glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
1088 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1089 glNormal3f(1, 0, 0);
1090 glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
1091 glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
1093 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
1094 glNormal3f(-1, 0, 0);
1095 glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2);
1096 glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
1099 glPushAttrib (GL_LIGHTING);
1100 glDisable (GL_LIGHTING);
1102 glColor3f (c2[0], c2[1], c2[2]);
1104 if (x1 > 0) x1 = 0; if (x2 < 0) x2 = 0;
1105 if (y1 > 0) y1 = 0; if (y2 < 0) y2 = 0;
1106 if (z1 > 0) z1 = 0; if (z2 < 0) z2 = 0;
1107 glVertex3f(x1, 0, 0); glVertex3f(x2, 0, 0);
1108 glVertex3f(0 , y1, 0); glVertex3f(0, y2, 0);
1109 glVertex3f(0, 0, z1); glVertex3f(0, 0, z2);
1116 void glsnake_draw(ModeInfo *mi)
1118 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
1119 Display *dpy = MI_DISPLAY(mi);
1120 Window window = MI_WINDOW(mi);
1125 if (!bp->glx_context)
1128 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1130 glMatrixMode(GL_MODELVIEW);
1132 gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
1134 /* rotate and translate into snake space */
1135 glRotatef(45.0, -5.0, 0.0, 1.0);
1136 glTranslatef(-0.5, 0.0, 0.5);
1138 /* rotate the 0th junction */
1139 glTranslatef(0.5, 0.0, 0.5);
1140 /* glMultMatrix(rotation); -- quaternion rotation */
1141 glRotatef(bp->roty, 0.0, 1.0, 0.0);
1142 glRotatef(bp->rotz, 0.0, 0.0, 1.0);
1143 glTranslated(-0.5, 0.0, -0.5);
1145 /* translate middle node to centre */
1146 for (i = 11; i >= 0; i--) {
1147 ang = bp->node[i].cur_angle;
1148 glTranslatef(0.5, 0.5, 0.5);
1149 glRotatef(180+ang, -1.0, 0.0, 0.0);
1150 glTranslatef(-1.0 - explode, 0.0, 0.0);
1151 glRotatef(90, 0.0, 0.0, 1.0);
1152 glTranslatef(-0.5, -0.5, -0.5);
1155 /* now draw each node along the snake */
1157 for (i = 0; i < 24; i++) {
1159 /* choose a colour for this node */
1160 if (bp->interactive && (i == bp->selected || i == bp->selected+1))
1161 glColor3f(1.0, 1.0, 0.0);
1165 glColor3f(0.6, 0.0, 0.9);
1167 glColor3fv(bp->colour);
1170 glColor3f(0.2, 0.9, 1.0);
1172 glColor3f(1.0, 1.0, 1.0);
1177 if (i == 0) glColor3f(0.0, 1.0, 1.0);
1181 glCallList(bp->node_list);
1183 /* now work out where to draw the next one */
1185 /* interpolate between models */
1186 ang = bp->node[i].cur_angle;
1188 glTranslatef(0.5, 0.5, 0.5);
1189 glRotatef(90, 0.0, 0.0, -1.0);
1190 glTranslatef(1.0 + explode, 0.0, 0.0);
1191 glRotatef(180 + ang, 1.0, 0.0, 0.0);
1192 glTranslatef(-0.5, -0.5, -0.5);
1198 draw_bounding_box (mi);
1209 glXSwapBuffers(dpy, window);