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"
43 #define DEFAULTS "*delay: 30000 \n" \
45 "*showFPS: False \n" \
46 "*wireframe: False \n" \
47 "*speed: " DEF_SPEED " \n" \
48 "*explode: " DEF_EXPLODE " \n" \
49 "*velocity: " DEF_VELOCITY " \n" \
50 /* "*accel: " DEF_ACCEL " \n" */ \
51 "*statictime: " DEF_STATICTIME " \n" \
52 "*yspin: " DEF_YSPIN " \n" \
53 "*zspin: " DEF_ZSPIN " \n" \
54 "*scarycolour:" DEF_SCARYCOLOUR " \n" \
55 "*labels: " DEF_LABELS " \n" \
56 "*labelfont: -*-times-bold-r-normal-*-180-*\n" \
61 #define countof(x) (sizeof((x))/sizeof((*x)))
63 #include "xlockmore.h"
65 #ifdef USE_GL /* whole file */
76 #include <sys/types.h>
83 typedef struct model_s {
88 typedef struct nodeang_s {
94 GLXContext * glx_context;
96 int node_list; /* name of the display list */
101 struct timeval last_iteration;
102 struct timeval last_morph;
120 } glsnake_configuration;
122 static glsnake_configuration *glc = NULL;
124 static GLfloat speed;
125 static GLfloat explode;
126 static GLfloat velocity;
127 /* static GLfloat accel; */
128 static long statictime;
129 static GLfloat yspin;
130 static GLfloat zspin;
131 static Bool scarycolour;
134 static XrmOptionDescRec opts[] = {
135 { "-speed", ".speed", XrmoptionSepArg, 0 },
136 { "-explode", ".explode", XrmoptionSepArg, 0 },
137 { "-velocity", ".velocity", XrmoptionSepArg, 0 },
138 /* { "-accel", ".accel", XrmoptionSepArg, 0 }, */
139 { "-statictime", ".statictime", XrmoptionSepArg, 0 },
140 { "-yspin", ".yspin", XrmoptionSepArg, 0 },
141 { "-zspin", ".zspin", XrmoptionSepArg, 0 },
142 { "-scarycolour", ".scarycolour", XrmoptionNoArg, "True" },
143 { "+scarycolour", ".scarycolour", XrmoptionNoArg, "False" },
144 { "-labels", ".labels", XrmoptionNoArg, "True" },
145 { "+labels", ".labels", XrmoptionNoArg, "False" },
148 static argtype vars[] = {
149 {(caddr_t *) &speed, "speed", "Speed", DEF_SPEED, t_Float},
150 {(caddr_t *) &explode, "explode", "Explode", DEF_EXPLODE, t_Float},
151 {(caddr_t *) &velocity, "velocity", "Velocity", DEF_VELOCITY, t_Float},
152 /* {(caddr_t *) &accel, "accel", "Acceleration", DEF_ACCEL, t_Float}, */
153 {(caddr_t *) &statictime, "statictime", "Static Time", DEF_STATICTIME, t_Int},
154 {(caddr_t *) &yspin, "yspin", "Y Spin", DEF_YSPIN, t_Float},
155 {(caddr_t *) &zspin, "zspin", "Z Spin", DEF_ZSPIN, t_Float},
156 /* {(caddr_t *) &interactive, "interactive", "Interactive", DEF_INTERACTIVE, t_Bool}, */
157 {(caddr_t *) &scarycolour, "scarycolour", "Scary Colour", DEF_SCARYCOLOUR, t_Bool},
158 {(caddr_t *) &labels, "labels", "Labels", DEF_LABELS, t_Bool},
161 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
164 #define VOFFSET 0.045
165 float solid_prism_v[][3] = {
166 /* first corner, bottom left front */
167 { VOFFSET, VOFFSET, 1.0 },
168 { VOFFSET, 0.0, 1.0 - VOFFSET },
169 { 0.0, VOFFSET, 1.0 - VOFFSET },
170 /* second corner, rear */
171 { VOFFSET, VOFFSET, 0.00 },
172 { VOFFSET, 0.0, VOFFSET },
173 { 0.0, VOFFSET, VOFFSET },
174 /* third, right front */
175 { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 1.0 },
176 { 1.0 - VOFFSET / M_SQRT1_2, 0.0, 1.0 - VOFFSET },
177 { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, 1.0 - VOFFSET },
178 /* fourth, right rear */
179 { 1.0 - VOFFSET / M_SQRT1_2, VOFFSET, 0.0 },
180 { 1.0 - VOFFSET / M_SQRT1_2, 0.0, VOFFSET },
181 { 1.0 - VOFFSET * M_SQRT1_2, VOFFSET, VOFFSET },
182 /* fifth, upper front */
183 { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 1.0 },
184 { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, 1.0 - VOFFSET },
185 { 0.0, 1.0 - VOFFSET / M_SQRT1_2, 1.0 - VOFFSET},
186 /* sixth, upper rear */
187 { VOFFSET, 1.0 - VOFFSET / M_SQRT1_2, 0.0 },
188 { VOFFSET / M_SQRT1_2, 1.0 - VOFFSET * M_SQRT1_2, VOFFSET },
189 { 0.0, 1.0 - VOFFSET / M_SQRT1_2, VOFFSET }
193 float solid_prism_n[][3] = {
195 { -VOFFSET, -VOFFSET, VOFFSET },
196 { VOFFSET, -VOFFSET, VOFFSET },
197 { -VOFFSET, VOFFSET, VOFFSET },
198 { -VOFFSET, -VOFFSET, -VOFFSET },
199 { VOFFSET, -VOFFSET, -VOFFSET },
200 { -VOFFSET, VOFFSET, -VOFFSET },
202 { -VOFFSET, 0.0, VOFFSET },
203 { 0.0, -VOFFSET, VOFFSET },
204 { VOFFSET, VOFFSET, VOFFSET },
205 { -VOFFSET, 0.0, -VOFFSET },
206 { 0.0, -VOFFSET, -VOFFSET },
207 { VOFFSET, VOFFSET, -VOFFSET },
208 { -VOFFSET, -VOFFSET, 0.0 },
209 { VOFFSET, -VOFFSET, 0.0 },
210 { -VOFFSET, VOFFSET, 0.0 },
214 { M_SQRT1_2, M_SQRT1_2, 0.0 },
220 float wire_prism_v[][3] = {
230 float wire_prism_n[][3] = {
233 { M_SQRT1_2, M_SQRT1_2, 0.0},
244 static model_t default_models[] = {
246 { R, R, L, L, R, L, R, R, L, R, L, L, R, R, L, L, R, L, R, R, L, R, L }
249 { R, R, R, R, L, L, L, L, R, R, R, R, L, L, L, L, R, R, R, R, L, L, L }
252 { Z, Z, Z, R, L, R, Z, L, Z, Z, Z, R, L, R, Z, L, Z, Z, Z, R, L, R, Z }
255 { Z, P, Z, Z, Z, Z, Z, P, R, R, P, R, L, P, L, R, P, R, R, Z, Z, Z, P }
258 { Z, P, P, Z, P, P, Z, L, Z, P, P, Z, P, P, Z, P, P, Z, Z, Z, Z, Z, Z }
261 { Z, Z, P, P, Z, L, Z, L, R, P, R, Z, P, P, Z, R, P, R, L, Z, L, Z, P }
265 /* add a model to the model list */
266 model_t * add_model(model_t * models, char * name, int * rotations, int * count) {
270 models = realloc(models, sizeof(model_t) * (*count));
271 models[(*count)-1].name = strdup(name);
273 fprintf(stderr, "resized models to %d bytes for model %s\n", sizeof(model_t) * (*count), models[(*count)-1].name);
275 for (i = 0; i < 24; i++) {
276 models[(*count)-1].node[i] = rotations[i] * 90.0;
281 /* filename is the name of the file to load
282 * models is the pointer to where the models will be kept
283 * returns a new pointer to models
284 * count is number of models read
286 model_t * load_modelfile(char * filename, model_t * models, int * count) {
294 f = fopen(filename, "r");
296 int error_msg_len = strlen(filename) + 33 + 1;
297 char * error_msg = (char *) malloc(sizeof(char) * error_msg_len);
298 sprintf(error_msg, "Unable to open model data file \"%s\"", filename);
304 while ((c = getc(f)) != EOF) {
306 /* ignore comments */
312 buffy[name-1] = '\0';
318 /* print out the model we just read in */
320 printf("%s: ", buffy);
321 for (i = 0; i < rots; i++) {
322 switch (rotations[i]) {
339 models = add_model(models, buffy, rotations, count);
349 fprintf(stderr, "buffy overflow warning\n");
354 rotations[rots] = ZERO;
359 rotations[rots] = LEFT;
364 rotations[rots] = PIN;
369 rotations[rots] = RIGHT;
382 model_t * load_models(char * dirpath, model_t * models, int * count) {
387 if ((dfd = opendir(dirpath)) == NULL) {
388 if (strstr(dirpath, "data") == NULL)
389 /* fprintf(stderr, "load_models: can't read %s/\n", dirpath); */
392 while ((dp = readdir(dfd)) != NULL) {
393 if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
395 if (strlen(dirpath) + strlen(dp->d_name) + 2 > sizeof(name))
396 fprintf(stderr, "load_models: name %s/%s too long\n", dirpath, dp->d_name);
398 sprintf(name, "%s/%s", dirpath, dp->d_name);
399 if (strcmp(&name[(int) strlen(name) - 7], "glsnake") == 0) {
401 fprintf(stderr, "load_models: opening %s\n", name);
403 models = load_modelfile(name, models, count);
415 #define GETSCALAR(vec,mask) ((vec)==(mask) ? 1 : ((vec)==-(mask) ? -1 : 0 ))
417 int cross_product(int src_dir, int dest_dir) {
418 return X_MASK * (GETSCALAR(src_dir, Y_MASK) * GETSCALAR(dest_dir, Z_MASK) -
419 GETSCALAR(src_dir, Z_MASK) * GETSCALAR(dest_dir, Y_MASK)) +
420 Y_MASK * (GETSCALAR(src_dir, Z_MASK) * GETSCALAR(dest_dir, X_MASK) -
421 GETSCALAR(src_dir, X_MASK) * GETSCALAR(dest_dir, Z_MASK)) +
422 Z_MASK * (GETSCALAR(src_dir, X_MASK) * GETSCALAR(dest_dir, Y_MASK) -
423 GETSCALAR(src_dir, Y_MASK) * GETSCALAR(dest_dir, X_MASK));
426 void calc_snake_metrics(glsnake_configuration * bp) {
427 int src_dir, dest_dir;
429 int prev_src_dir = -Y_MASK;
430 int prev_dest_dir = Z_MASK;
431 int grid[25][25][25];
434 memset(&grid, 0, sizeof(int) * 25*25*25);
439 /* trace path of snake and keep record for is_legal */
440 for (i = 0; i < 23; i++) {
441 /* establish new state variables */
442 src_dir = -prev_dest_dir;
443 x += GETSCALAR(prev_dest_dir, X_MASK);
444 y += GETSCALAR(prev_dest_dir, Y_MASK);
445 z += GETSCALAR(prev_dest_dir, Z_MASK);
447 switch ((int) bp->node[i].dest_angle) {
448 case (int) (ZERO * 90.0):
449 dest_dir = -prev_src_dir;
451 case (int) (PIN * 90.0):
452 dest_dir = prev_src_dir;
454 case (int) (RIGHT * 90.):
455 case (int) (LEFT * 90.0):
456 dest_dir = cross_product(prev_src_dir, prev_dest_dir);
457 if (bp->node[i].dest_angle == (int) (RIGHT * 90.0))
458 dest_dir = -dest_dir;
461 /* prevent spurious "might be used uninitialised" warnings */
466 if (grid[x][y][z] == 0)
467 grid[x][y][z] = src_dir + dest_dir;
468 else if (grid[x][y][z] + src_dir + dest_dir == 0)
473 prev_src_dir = src_dir;
474 prev_dest_dir = dest_dir;
477 /* determine if the snake is cyclic */
478 bp->is_cyclic = (dest_dir == Y_MASK && x == 12 && y == 11 && x == 12);
480 /* determine last turn */
485 bp->last_turn = ZERO * 90.0;
488 bp->last_turn = PIN * 90.0;
491 bp->last_turn = LEFT * 90.0;
494 bp->last_turn = RIGHT * 90.0;
500 void set_colours(glsnake_configuration * bp, int immediate) {
501 /* set target colour */
503 bp->colour_t[0] = 0.5;
504 bp->colour_t[1] = 0.5;
505 bp->colour_t[2] = 0.5;
506 } else if (bp->is_cyclic) {
507 bp->colour_t[0] = 0.4;
508 bp->colour_t[1] = 0.8;
509 bp->colour_t[2] = 0.2;
511 bp->colour_t[0] = 0.3;
512 bp->colour_t[1] = 0.1;
513 bp->colour_t[2] = 0.9;
516 bp->colour_i[0] = bp->colour_t[0] - bp->colour[0];
517 bp->colour_i[1] = bp->colour_t[1] - bp->colour[1];
518 bp->colour_i[2] = bp->colour_t[2] - bp->colour[2];
520 /* instead of 50.0, I should actually work out how many times this gets
521 * called during a morph */
522 bp->colour_i[0] = (bp->colour_t[0] - bp->colour[0]) / 50.0;
523 bp->colour_i[1] = (bp->colour_t[1] - bp->colour[1]) / 50.0;
524 bp->colour_i[2] = (bp->colour_t[2] - bp->colour[2]) / 50.0;
528 void start_morph(int model_index, int immediate, glsnake_configuration * bp) {
531 for (i = 0; i < 23; i++) {
532 bp->node[i].dest_angle = bp->models[model_index].node[i];
534 bp->node[i].cur_angle = bp->models[model_index].node[i];
537 calc_snake_metrics(bp);
539 bp->cur_model = model_index;
546 void draw_label(ModeInfo * mi) {
547 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
549 glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT);
550 glDisable(GL_LIGHTING);
551 glDisable(GL_DEPTH_TEST);
552 glMatrixMode(GL_PROJECTION);
555 glMatrixMode(GL_MODELVIEW);
558 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
559 glColor3f(1.0, 1.0, 0.0);
567 s = bp->models[bp->cur_model].name;
572 for (i = 0; i < l; i++) {
573 w += (bp->font->per_char
574 ? bp->font->per_char[((int)s[i]) - bp->font->min_char_or_byte2].rbearing
575 : bp->font->min_bounds.rbearing);
579 glRasterPos2f(10, mi->xgwa.height - 10 - (bp->font->ascent + bp->font->descent));
580 /* mi->xgwa.width - w, bp->font->descent + bp->font->ascent); */
582 /* fprintf(stderr, "afaf.width = %d, w = %d\n", mi->xgwa.width, w); */
584 for (i = 0; i < l; i++)
585 glCallList(bp->font_list + (int)s[i]);
588 glMatrixMode(GL_PROJECTION);
593 /* load the fonts -- this function borrowed from molecule.c */
594 static void load_font(ModeInfo * mi, char * res, XFontStruct ** fontp, GLuint * dlistp) {
595 const char * font = get_string_resource(res, "Font");
601 font = "-*-helvetica-medium-r-*-*-*-120-*";
603 f = XLoadQueryFont(mi->dpy, font);
605 f = XLoadQueryFont(mi->dpy, "fixed");
608 first = f->min_char_or_byte2;
609 last = f->max_char_or_byte2;
612 *dlistp = glGenLists((GLuint) last + 1);
613 check_gl_error("glGenLists");
614 glXUseXFont(id, first, last - first + 1, *dlistp + first);
615 check_gl_error("glXUseXFont");
622 /* window management */
623 void glsnake_reshape(ModeInfo *mi, int w, int h) {
624 glViewport (0, 0, (GLint) w, (GLint) h);
625 glMatrixMode(GL_PROJECTION);
627 gluPerspective(25.0, w/(GLfloat)h, 1.0, 100.0 );
628 glMatrixMode(GL_MODELVIEW);
632 static void gl_init(ModeInfo *mi) {
633 /* glsnake_configuration *bp = &glc[MI_SCREEN(mi)]; */
634 int wire = MI_IS_WIREFRAME(mi);
635 float light_pos[][3] = {{0.0,0.0,20.0},{0.0,20.0,0.0}};
636 float light_dir[][3] = {{0.0,0.0,-20.0},{0.0,-20.0,0.0}};
638 glClearColor(0.0, 0.0, 0.0, 0.0);
639 glEnable(GL_DEPTH_TEST);
640 glShadeModel(GL_SMOOTH);
642 glEnable(GL_CULL_FACE);
643 glEnable(GL_NORMALIZE);
646 glColor3f(1.0, 1.0, 1.0);
647 glLightfv(GL_LIGHT0, GL_POSITION, light_pos[0]);
648 glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_dir[0]);
649 glLightfv(GL_LIGHT1, GL_POSITION, light_pos[1]);
650 glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light_dir[1]);
651 glEnable(GL_LIGHTING);
654 glEnable(GL_COLOR_MATERIAL);
658 /* lifted from lament.c */
659 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
660 #define RANDSIGN() ((random() & 1) ? 1 : -1)
662 void glsnake_init(ModeInfo *mi) {
663 glsnake_configuration * bp;
664 int wire = MI_IS_WIREFRAME(mi);
667 glc = (glsnake_configuration *) calloc(MI_NUM_SCREENS(mi), sizeof(glsnake_configuration));
669 fprintf(stderr, "%s: out of memory\n", progname);
672 bp = &glc[MI_SCREEN(mi)];
675 bp = &glc[MI_SCREEN(mi)];
677 if ((bp->glx_context = init_GL(mi)) != NULL) {
679 glsnake_reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
682 /* initialise config variables */
683 memset(&bp->node, 0, sizeof(nodeang_t) * 24);
684 bp->m_count = sizeof(default_models) / sizeof(model_t); /* overwrite this in a bit */
697 # ifdef GETTIMEOFDAY_TWO_ARGS
699 gettimeofday(&bp->last_iteration, &tzp);
701 gettimeofday(&bp->last_iteration);
705 memcpy(&bp->last_morph, &(bp->last_iteration),
706 sizeof(bp->last_morph));
707 /* srand((unsigned int) bp->last_iteration.time); */
709 /* load the model files */
710 /* first copy the defaults to bp->m_count */
711 bp->models = (model_t *) malloc(sizeof(model_t) * bp->m_count);
712 memcpy(bp->models, default_models, bp->m_count * sizeof(model_t));
713 /* then add on models from the Debian model file location */
714 bp->models = load_models("/usr/share/glsnake", bp->models, &(bp->m_count));
716 bp->m = bp->cur_model = RAND(bp->m_count);
717 start_morph(bp->cur_model, 1, bp);
719 calc_snake_metrics(bp);
722 /* set up a font for the labels */
724 load_font(mi, "labelfont", &bp->font, &bp->font_list);
726 bp->node_list = glGenLists(1);
727 glNewList(bp->node_list, GL_COMPILE);
730 glBegin(GL_TRIANGLES);
731 glNormal3fv(solid_prism_n[0]);
732 glVertex3fv(solid_prism_v[0]);
733 glVertex3fv(solid_prism_v[2]);
734 glVertex3fv(solid_prism_v[1]);
736 glNormal3fv(solid_prism_n[1]);
737 glVertex3fv(solid_prism_v[6]);
738 glVertex3fv(solid_prism_v[7]);
739 glVertex3fv(solid_prism_v[8]);
741 glNormal3fv(solid_prism_n[2]);
742 glVertex3fv(solid_prism_v[12]);
743 glVertex3fv(solid_prism_v[13]);
744 glVertex3fv(solid_prism_v[14]);
746 glNormal3fv(solid_prism_n[3]);
747 glVertex3fv(solid_prism_v[3]);
748 glVertex3fv(solid_prism_v[4]);
749 glVertex3fv(solid_prism_v[5]);
751 glNormal3fv(solid_prism_n[4]);
752 glVertex3fv(solid_prism_v[9]);
753 glVertex3fv(solid_prism_v[11]);
754 glVertex3fv(solid_prism_v[10]);
756 glNormal3fv(solid_prism_n[5]);
757 glVertex3fv(solid_prism_v[16]);
758 glVertex3fv(solid_prism_v[15]);
759 glVertex3fv(solid_prism_v[17]);
764 glNormal3fv(solid_prism_n[6]);
765 glVertex3fv(solid_prism_v[0]);
766 glVertex3fv(solid_prism_v[12]);
767 glVertex3fv(solid_prism_v[14]);
768 glVertex3fv(solid_prism_v[2]);
770 glNormal3fv(solid_prism_n[7]);
771 glVertex3fv(solid_prism_v[0]);
772 glVertex3fv(solid_prism_v[1]);
773 glVertex3fv(solid_prism_v[7]);
774 glVertex3fv(solid_prism_v[6]);
776 glNormal3fv(solid_prism_n[8]);
777 glVertex3fv(solid_prism_v[6]);
778 glVertex3fv(solid_prism_v[8]);
779 glVertex3fv(solid_prism_v[13]);
780 glVertex3fv(solid_prism_v[12]);
782 glNormal3fv(solid_prism_n[9]);
783 glVertex3fv(solid_prism_v[3]);
784 glVertex3fv(solid_prism_v[5]);
785 glVertex3fv(solid_prism_v[17]);
786 glVertex3fv(solid_prism_v[15]);
788 glNormal3fv(solid_prism_n[10]);
789 glVertex3fv(solid_prism_v[3]);
790 glVertex3fv(solid_prism_v[9]);
791 glVertex3fv(solid_prism_v[10]);
792 glVertex3fv(solid_prism_v[4]);
794 glNormal3fv(solid_prism_n[11]);
795 glVertex3fv(solid_prism_v[15]);
796 glVertex3fv(solid_prism_v[16]);
797 glVertex3fv(solid_prism_v[11]);
798 glVertex3fv(solid_prism_v[9]);
800 glNormal3fv(solid_prism_n[12]);
801 glVertex3fv(solid_prism_v[1]);
802 glVertex3fv(solid_prism_v[2]);
803 glVertex3fv(solid_prism_v[5]);
804 glVertex3fv(solid_prism_v[4]);
806 glNormal3fv(solid_prism_n[13]);
807 glVertex3fv(solid_prism_v[8]);
808 glVertex3fv(solid_prism_v[7]);
809 glVertex3fv(solid_prism_v[10]);
810 glVertex3fv(solid_prism_v[11]);
812 glNormal3fv(solid_prism_n[14]);
813 glVertex3fv(solid_prism_v[13]);
814 glVertex3fv(solid_prism_v[16]);
815 glVertex3fv(solid_prism_v[17]);
816 glVertex3fv(solid_prism_v[14]);
820 glBegin(GL_TRIANGLES);
821 glNormal3fv(solid_prism_n[15]);
822 glVertex3fv(solid_prism_v[0]);
823 glVertex3fv(solid_prism_v[6]);
824 glVertex3fv(solid_prism_v[12]);
826 glNormal3fv(solid_prism_n[19]);
827 glVertex3fv(solid_prism_v[3]);
828 glVertex3fv(solid_prism_v[15]);
829 glVertex3fv(solid_prism_v[9]);
833 glNormal3fv(solid_prism_n[16]);
834 glVertex3fv(solid_prism_v[1]);
835 glVertex3fv(solid_prism_v[4]);
836 glVertex3fv(solid_prism_v[10]);
837 glVertex3fv(solid_prism_v[7]);
839 glNormal3fv(solid_prism_n[17]);
840 glVertex3fv(solid_prism_v[8]);
841 glVertex3fv(solid_prism_v[11]);
842 glVertex3fv(solid_prism_v[16]);
843 glVertex3fv(solid_prism_v[13]);
845 glNormal3fv(solid_prism_n[18]);
846 glVertex3fv(solid_prism_v[2]);
847 glVertex3fv(solid_prism_v[14]);
848 glVertex3fv(solid_prism_v[17]);
849 glVertex3fv(solid_prism_v[5]);
852 /* build wire display list */
853 glBegin(GL_LINE_STRIP);
854 glVertex3fv(wire_prism_v[0]);
855 glVertex3fv(wire_prism_v[1]);
856 glVertex3fv(wire_prism_v[2]);
857 glVertex3fv(wire_prism_v[0]);
858 glVertex3fv(wire_prism_v[3]);
859 glVertex3fv(wire_prism_v[4]);
860 glVertex3fv(wire_prism_v[5]);
861 glVertex3fv(wire_prism_v[3]);
865 glVertex3fv(wire_prism_v[1]);
866 glVertex3fv(wire_prism_v[4]);
867 glVertex3fv(wire_prism_v[2]);
868 glVertex3fv(wire_prism_v[5]);
874 /* "jwz? no way man, he's my idle" -- Jaq, 2001.
875 * I forget the context :( */
876 void glsnake_idol(glsnake_configuration * bp) {
877 /* time since last iteration */
879 /* time since the beginning of last morph */
881 float iter_angle_max;
883 struct timeval current_time;
886 /* Do nothing to the model if we are paused */
888 /* Avoid busy waiting when nothing is changing */
894 # ifdef GETTIMEOFDAY_TWO_ARGS
896 gettimeofday(¤t_time, &tzp);
898 gettimeofday(¤t_time);
902 /* <spiv> Well, ftime gives time with millisecond resolution.
903 * <Jaq> if current time is exactly equal to last iteration,
904 * then don't do this block
905 * <spiv> (or worse, perhaps... who knows what the OS will do)
906 * <spiv> So if no discernable amount of time has passed:
907 * <spiv> a) There's no point updating the screen, because
908 * it would be the same
909 * <spiv> b) The code will divide by zero
911 iter_msec = ((long) current_time.tv_usec - bp->last_iteration.tv_usec)/1000L +
912 ((long) current_time.tv_sec - bp->last_iteration.tv_sec) * 1000L;
914 /* save the current time */
915 memcpy(&bp->last_iteration, ¤t_time,
916 sizeof(bp->last_iteration));
918 /* work out if we have to switch models */
919 morf_msec = (bp->last_iteration.tv_usec - bp->last_morph.tv_usec)/1000L +
920 ((long) (bp->last_iteration.tv_sec - bp->last_morph.tv_sec) * 1000L);
922 if ((morf_msec > statictime) && !bp->interactive) {
923 memcpy(&bp->last_morph, &(bp->last_iteration),
924 sizeof(bp->last_morph));
925 start_morph(RAND(bp->m_count), 0, bp);
928 if (bp->interactive && !bp->morphing) {
933 if (!bp->dragging && !bp->interactive) {
934 bp->roty += 360/((1000/yspin)/iter_msec);
935 bp->rotz += 360/((1000/zspin)/iter_msec);
938 /* work out the maximum angle for this iteration */
939 iter_angle_max = 90.0 * (velocity/1000.0) * iter_msec;
942 for (i = 0; i < 24; i++) {
943 float cur_angle = bp->node[i].cur_angle;
944 float dest_angle = bp->node[i].dest_angle;
945 if (cur_angle != dest_angle) {
947 if (fabs(cur_angle - dest_angle) <= iter_angle_max)
948 bp->node[i].cur_angle = dest_angle;
949 else if (fmod(cur_angle - dest_angle + 360, 360) > 180)
950 bp->node[i].cur_angle = fmod(cur_angle + iter_angle_max, 360);
952 bp->node[i].cur_angle = fmod(cur_angle + 360 - iter_angle_max, 360);
960 if (fabs(bp->colour[0] - bp->colour_t[0]) <= fabs(bp->colour_i[0]))
961 bp->colour[0] = bp->colour_t[0];
963 bp->colour[0] += bp->colour_i[0];
964 if (fabs(bp->colour[1] - bp->colour_t[1]) <= fabs(bp->colour_i[1]))
965 bp->colour[1] = bp->colour_t[1];
967 bp->colour[1] += bp->colour_i[1];
968 if (fabs(bp->colour[2] - bp->colour_t[2]) <= fabs(bp->colour_i[2]))
969 bp->colour[2] = bp->colour_t[2];
971 bp->colour[2] += bp->colour_i[2];
973 /* We are going too fast, so we may as well let the
974 * cpu relax a little by sleeping for a millisecond. */
979 void glsnake_draw(ModeInfo *mi) {
980 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
981 Display *dpy = MI_DISPLAY(mi);
982 Window window = MI_WINDOW(mi);
987 if (!bp->glx_context)
990 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
992 glMatrixMode(GL_MODELVIEW);
994 gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
996 /* rotate and translate into snake space */
997 glRotatef(45.0, -5.0, 0.0, 1.0);
998 glTranslatef(-0.5, 0.0, 0.5);
1000 /* rotate the 0th junction */
1001 glTranslatef(0.5, 0.0, 0.5);
1002 /* glMultMatrix(rotation); -- quaternion rotation */
1003 glRotatef(bp->roty, 0.0, 1.0, 0.0);
1004 glRotatef(bp->rotz, 0.0, 0.0, 1.0);
1005 glTranslated(-0.5, 0.0, -0.5);
1007 /* translate middle node to centre */
1008 for (i = 11; i >= 0; i--) {
1009 ang = bp->node[i].cur_angle;
1010 glTranslatef(0.5, 0.5, 0.5);
1011 glRotatef(180+ang, -1.0, 0.0, 0.0);
1012 glTranslatef(-1.0 - explode, 0.0, 0.0);
1013 glRotatef(90, 0.0, 0.0, 1.0);
1014 glTranslatef(-0.5, -0.5, -0.5);
1017 /* now draw each node along the snake */
1018 for (i = 0; i < 24; i++) {
1021 /* choose a colour for this node */
1022 if (bp->interactive && (i == bp->selected || i == bp->selected+1))
1023 glColor3f(1.0, 1.0, 0.0);
1027 glColor3f(0.6, 0.0, 0.9);
1029 glColor3fv(bp->colour);
1032 glColor3f(0.2, 0.9, 1.0);
1034 glColor3f(1.0, 1.0, 1.0);
1039 glCallList(bp->node_list);
1041 /* now work out where to draw the next one */
1043 /* interpolate between models */
1044 ang = bp->node[i].cur_angle;
1046 glTranslatef(0.5, 0.5, 0.5);
1047 glRotatef(90, 0.0, 0.0, -1.0);
1048 glTranslatef(1.0 + explode, 0.0, 0.0);
1049 glRotatef(180 + ang, 1.0, 0.0, 0.0);
1050 glTranslatef(-0.5, -0.5, -0.5);
1053 /* clear up the matrix stack */
1054 for (i = 0; i < 24; i++)
1066 glXSwapBuffers(dpy, window);