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: -*-helvetica-medium-r-*-*-*-120-*\n" \
61 #define countof(x) (sizeof((x))/sizeof((*x)))
63 #include "xlockmore.h"
65 #ifdef USE_GL /* whole file */
68 #include <sys/timeb.h>
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 timeb last_iteration;
102 struct timeb 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 */
696 ftime(&(bp->last_iteration));
697 memcpy(&(bp->last_morph), &(bp->last_iteration), sizeof(struct timeb));
698 /* srand((unsigned int) bp->last_iteration.time); */
700 /* load the model files */
701 /* first copy the defaults to bp->m_count */
702 bp->models = (model_t *) malloc(sizeof(model_t) * bp->m_count);
703 memcpy(bp->models, default_models, bp->m_count * sizeof(model_t));
704 /* then add on models from the Debian model file location */
705 bp->models = load_models("/usr/share/glsnake", bp->models, &(bp->m_count));
707 bp->m = bp->cur_model = RAND(bp->m_count);
708 start_morph(bp->cur_model, 1, bp);
710 calc_snake_metrics(bp);
713 /* set up a font for the labels */
715 load_font(mi, "labelfont", &bp->font, &bp->font_list);
717 bp->node_list = glGenLists(1);
718 glNewList(bp->node_list, GL_COMPILE);
721 glBegin(GL_TRIANGLES);
722 glNormal3fv(solid_prism_n[0]);
723 glVertex3fv(solid_prism_v[0]);
724 glVertex3fv(solid_prism_v[2]);
725 glVertex3fv(solid_prism_v[1]);
727 glNormal3fv(solid_prism_n[1]);
728 glVertex3fv(solid_prism_v[6]);
729 glVertex3fv(solid_prism_v[7]);
730 glVertex3fv(solid_prism_v[8]);
732 glNormal3fv(solid_prism_n[2]);
733 glVertex3fv(solid_prism_v[12]);
734 glVertex3fv(solid_prism_v[13]);
735 glVertex3fv(solid_prism_v[14]);
737 glNormal3fv(solid_prism_n[3]);
738 glVertex3fv(solid_prism_v[3]);
739 glVertex3fv(solid_prism_v[4]);
740 glVertex3fv(solid_prism_v[5]);
742 glNormal3fv(solid_prism_n[4]);
743 glVertex3fv(solid_prism_v[9]);
744 glVertex3fv(solid_prism_v[11]);
745 glVertex3fv(solid_prism_v[10]);
747 glNormal3fv(solid_prism_n[5]);
748 glVertex3fv(solid_prism_v[16]);
749 glVertex3fv(solid_prism_v[15]);
750 glVertex3fv(solid_prism_v[17]);
755 glNormal3fv(solid_prism_n[6]);
756 glVertex3fv(solid_prism_v[0]);
757 glVertex3fv(solid_prism_v[12]);
758 glVertex3fv(solid_prism_v[14]);
759 glVertex3fv(solid_prism_v[2]);
761 glNormal3fv(solid_prism_n[7]);
762 glVertex3fv(solid_prism_v[0]);
763 glVertex3fv(solid_prism_v[1]);
764 glVertex3fv(solid_prism_v[7]);
765 glVertex3fv(solid_prism_v[6]);
767 glNormal3fv(solid_prism_n[8]);
768 glVertex3fv(solid_prism_v[6]);
769 glVertex3fv(solid_prism_v[8]);
770 glVertex3fv(solid_prism_v[13]);
771 glVertex3fv(solid_prism_v[12]);
773 glNormal3fv(solid_prism_n[9]);
774 glVertex3fv(solid_prism_v[3]);
775 glVertex3fv(solid_prism_v[5]);
776 glVertex3fv(solid_prism_v[17]);
777 glVertex3fv(solid_prism_v[15]);
779 glNormal3fv(solid_prism_n[10]);
780 glVertex3fv(solid_prism_v[3]);
781 glVertex3fv(solid_prism_v[9]);
782 glVertex3fv(solid_prism_v[10]);
783 glVertex3fv(solid_prism_v[4]);
785 glNormal3fv(solid_prism_n[11]);
786 glVertex3fv(solid_prism_v[15]);
787 glVertex3fv(solid_prism_v[16]);
788 glVertex3fv(solid_prism_v[11]);
789 glVertex3fv(solid_prism_v[9]);
791 glNormal3fv(solid_prism_n[12]);
792 glVertex3fv(solid_prism_v[1]);
793 glVertex3fv(solid_prism_v[2]);
794 glVertex3fv(solid_prism_v[5]);
795 glVertex3fv(solid_prism_v[4]);
797 glNormal3fv(solid_prism_n[13]);
798 glVertex3fv(solid_prism_v[8]);
799 glVertex3fv(solid_prism_v[7]);
800 glVertex3fv(solid_prism_v[10]);
801 glVertex3fv(solid_prism_v[11]);
803 glNormal3fv(solid_prism_n[14]);
804 glVertex3fv(solid_prism_v[13]);
805 glVertex3fv(solid_prism_v[16]);
806 glVertex3fv(solid_prism_v[17]);
807 glVertex3fv(solid_prism_v[14]);
811 glBegin(GL_TRIANGLES);
812 glNormal3fv(solid_prism_n[15]);
813 glVertex3fv(solid_prism_v[0]);
814 glVertex3fv(solid_prism_v[6]);
815 glVertex3fv(solid_prism_v[12]);
817 glNormal3fv(solid_prism_n[19]);
818 glVertex3fv(solid_prism_v[3]);
819 glVertex3fv(solid_prism_v[15]);
820 glVertex3fv(solid_prism_v[9]);
824 glNormal3fv(solid_prism_n[16]);
825 glVertex3fv(solid_prism_v[1]);
826 glVertex3fv(solid_prism_v[4]);
827 glVertex3fv(solid_prism_v[10]);
828 glVertex3fv(solid_prism_v[7]);
830 glNormal3fv(solid_prism_n[17]);
831 glVertex3fv(solid_prism_v[8]);
832 glVertex3fv(solid_prism_v[11]);
833 glVertex3fv(solid_prism_v[16]);
834 glVertex3fv(solid_prism_v[13]);
836 glNormal3fv(solid_prism_n[18]);
837 glVertex3fv(solid_prism_v[2]);
838 glVertex3fv(solid_prism_v[14]);
839 glVertex3fv(solid_prism_v[17]);
840 glVertex3fv(solid_prism_v[5]);
843 /* build wire display list */
844 glBegin(GL_LINE_STRIP);
845 glVertex3fv(wire_prism_v[0]);
846 glVertex3fv(wire_prism_v[1]);
847 glVertex3fv(wire_prism_v[2]);
848 glVertex3fv(wire_prism_v[0]);
849 glVertex3fv(wire_prism_v[3]);
850 glVertex3fv(wire_prism_v[4]);
851 glVertex3fv(wire_prism_v[5]);
852 glVertex3fv(wire_prism_v[3]);
856 glVertex3fv(wire_prism_v[1]);
857 glVertex3fv(wire_prism_v[4]);
858 glVertex3fv(wire_prism_v[2]);
859 glVertex3fv(wire_prism_v[5]);
865 /* "jwz? no way man, he's my idle" -- Jaq, 2001.
866 * I forget the context :( */
867 void glsnake_idol(glsnake_configuration * bp) {
868 /* time since last iteration */
870 /* time since the beginning of last morph */
872 float iter_angle_max;
874 struct timeb current_time;
877 /* Do nothing to the model if we are paused */
879 /* Avoid busy waiting when nothing is changing */
883 /* ftime is winDOS compatible */
884 ftime(¤t_time);
886 /* <spiv> Well, ftime gives time with millisecond resolution.
887 * <Jaq> if current time is exactly equal to last iteration,
888 * then don't do this block
889 * <spiv> (or worse, perhaps... who knows what the OS will do)
890 * <spiv> So if no discernable amount of time has passed:
891 * <spiv> a) There's no point updating the screen, because
892 * it would be the same
893 * <spiv> b) The code will divide by zero
895 iter_msec = (long) current_time.millitm - bp->last_iteration.millitm +
896 ((long) current_time.time - bp->last_iteration.time) * 1000L;
898 /* save the current time */
899 memcpy(&(bp->last_iteration), ¤t_time, sizeof(struct timeb));
901 /* work out if we have to switch models */
902 morf_msec = bp->last_iteration.millitm - bp->last_morph.millitm +
903 ((long) (bp->last_iteration.time - bp->last_morph.time) * 1000L);
905 if ((morf_msec > statictime) && !bp->interactive) {
906 memcpy(&(bp->last_morph), &(bp->last_iteration), sizeof(struct timeb));
907 start_morph(RAND(bp->m_count), 0, bp);
910 if (bp->interactive && !bp->morphing) {
915 if (!bp->dragging && !bp->interactive) {
916 bp->roty += 360/((1000/yspin)/iter_msec);
917 bp->rotz += 360/((1000/zspin)/iter_msec);
920 /* work out the maximum angle for this iteration */
921 iter_angle_max = 90.0 * (velocity/1000.0) * iter_msec;
924 for (i = 0; i < 24; i++) {
925 float cur_angle = bp->node[i].cur_angle;
926 float dest_angle = bp->node[i].dest_angle;
927 if (cur_angle != dest_angle) {
929 if (fabs(cur_angle - dest_angle) <= iter_angle_max)
930 bp->node[i].cur_angle = dest_angle;
931 else if (fmod(cur_angle - dest_angle + 360, 360) > 180)
932 bp->node[i].cur_angle = fmod(cur_angle + iter_angle_max, 360);
934 bp->node[i].cur_angle = fmod(cur_angle + 360 - iter_angle_max, 360);
942 if (fabs(bp->colour[0] - bp->colour_t[0]) <= fabs(bp->colour_i[0]))
943 bp->colour[0] = bp->colour_t[0];
945 bp->colour[0] += bp->colour_i[0];
946 if (fabs(bp->colour[1] - bp->colour_t[1]) <= fabs(bp->colour_i[1]))
947 bp->colour[1] = bp->colour_t[1];
949 bp->colour[1] += bp->colour_i[1];
950 if (fabs(bp->colour[2] - bp->colour_t[2]) <= fabs(bp->colour_i[2]))
951 bp->colour[2] = bp->colour_t[2];
953 bp->colour[2] += bp->colour_i[2];
955 /* We are going too fast, so we may as well let the
956 * cpu relax a little by sleeping for a millisecond. */
961 void glsnake_draw(ModeInfo *mi) {
962 glsnake_configuration *bp = &glc[MI_SCREEN(mi)];
963 Display *dpy = MI_DISPLAY(mi);
964 Window window = MI_WINDOW(mi);
969 if (!bp->glx_context)
972 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
974 glMatrixMode(GL_MODELVIEW);
976 gluLookAt(0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
978 /* rotate and translate into snake space */
979 glRotatef(45.0, -5.0, 0.0, 1.0);
980 glTranslatef(-0.5, 0.0, 0.5);
982 /* rotate the 0th junction */
983 glTranslatef(0.5, 0.0, 0.5);
984 /* glMultMatrix(rotation); -- quaternion rotation */
985 glRotatef(bp->roty, 0.0, 1.0, 0.0);
986 glRotatef(bp->rotz, 0.0, 0.0, 1.0);
987 glTranslated(-0.5, 0.0, -0.5);
989 /* translate middle node to centre */
990 for (i = 11; i >= 0; i--) {
991 ang = bp->node[i].cur_angle;
992 glTranslatef(0.5, 0.5, 0.5);
993 glRotatef(180+ang, -1.0, 0.0, 0.0);
994 glTranslatef(-1.0 - explode, 0.0, 0.0);
995 glRotatef(90, 0.0, 0.0, 1.0);
996 glTranslatef(-0.5, -0.5, -0.5);
999 /* now draw each node along the snake */
1000 for (i = 0; i < 24; i++) {
1003 /* choose a colour for this node */
1004 if (bp->interactive && (i == bp->selected || i == bp->selected+1))
1005 glColor3f(1.0, 1.0, 0.0);
1009 glColor3f(0.6, 0.0, 0.9);
1011 glColor3fv(bp->colour);
1014 glColor3f(0.2, 0.9, 1.0);
1016 glColor3f(1.0, 1.0, 1.0);
1021 glCallList(bp->node_list);
1023 /* now work out where to draw the next one */
1025 /* interpolate between models */
1026 ang = bp->node[i].cur_angle;
1028 glTranslatef(0.5, 0.5, 0.5);
1029 glRotatef(90, 0.0, 0.0, -1.0);
1030 glTranslatef(1.0 + explode, 0.0, 0.0);
1031 glRotatef(180 + ang, 1.0, 0.0, 0.0);
1032 glTranslatef(-0.5, -0.5, -0.5);
1035 /* clear up the matrix stack */
1036 for (i = 0; i < 24; i++)
1048 glXSwapBuffers(dpy, window);