#undef FLAT_SHADING #include #include #include #include #include #include "gl42ogl.h" #include "tk.h" #include "insect.h" #include "insectco.h" GLushort ls = 0xaaaa; unsigned char halftone[] = { 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, }; GLfloat sdepth = 10.; float light[3], phi = PI / 4.0, theta = PI / 4.0; GLfloat ctheta = -900, cphi, cvtheta, cvphi; float fabso (float a ); /* Changes for ECLIPSE 8 bit machine */ /* don't use 7 and 8 for appearances. These are the text standards */ unsigned short ECLIPSE8_RAMP[10] = {4, 5, 6, 8, 9, 10, 11, 12, 13, 14}; GLboolean is_8bit; short savearray[384]; /** change for new window control */ float halfwinx, halfwiny; long worgx, worgy; long wsizex, wsizey; long pikx, piky; GLboolean follow; float px, py; float light[3]; float cx, cy, cz, cvx, cvy, cvz; float dmr[6], fr[6]; GLfloat knee[6]; GLfloat hip_phi[6]; GLfloat hip_theta[6]; GLboolean legup[6]; float legx[6], legy[6]; enum { NOTHING, FORWARD, BACKWARD, LEFT, MIDDLE }; short function; /* mymakerange -- color ramp utilities */ void mymakerange (unsigned short a, unsigned short b, GLubyte red1, GLubyte red2, GLubyte green1, GLubyte green2, GLubyte blue1, GLubyte blue2) { float i; int j; float dr, dg, db; i = (float) (b - a); dr = (float) (red2 - red1) / i; dg = (float) (green2 - green1) / i; db = (float) (blue2 - blue1) / i; for (j = 0; j <= (int) i; j++) mapcolor ((unsigned short) j + a, (short) (dr * (float) j + red1), (short) (dg * (float) j + green1), (short) (db * (float) j + blue1)); /* mapcolor ((unsigned short) j + a, (GLubyte) (dr * (float) j + red1), (GLubyte) (dg * (float) j + green1), (GLubyte) (db * (float) j + blue1)); */ } /* Set up Eclipse 8 bit color ramp */ void make_eclipse8_range(unsigned short e_ramp[], int red1, int red2, int green1, int green2, int blue1, int blue2) { int i; float rinc, ginc, binc; rinc = (float)(red2 - red1) / (float)ECLIPSE8_NCOLORS; ginc = (float)(green2 - green1) / (float)ECLIPSE8_NCOLORS; binc = (float)(blue2 - blue1) / (float)ECLIPSE8_NCOLORS; for (i = 0; i < ECLIPSE8_NCOLORS; i++) { mapcolor(e_ramp[i], (short)(i * rinc + red1), (short)(i * ginc + green1), (short)(i * binc + blue1)); } } /* setupcolors -- load color map */ /* Changed for ECLIPSE 8 bit machine */ void setupcolors (void) { if (!is_8bit) { mapcolor (GRAY, 128, 128, 128); mapcolor (GRID, 128, 200, 250); mapcolor (SKYBLUE, 50, 50, 150); mymakerange (RAMPB5, RAMPE5, 125, 250, 125, 250, 0, 0); mymakerange (RAMPB4, RAMPE4, 100, 200, 125, 250, 0, 0); mymakerange (RAMPB3, RAMPE3, 75, 150, 125, 250, 0, 0); mymakerange (RAMPB2, RAMPE2, 50, 100, 125, 250, 0, 0); mymakerange (RAMPB, RAMPE, 25, 50, 125, 250, 0, 0); } else { mapcolor (ECLIPSE8_GRAY, 128, 128, 128); mapcolor (ECLIPSE8_GRID, 128, 200, 250); mapcolor (ECLIPSE8_SKYBLUE, 50, 50, 150); /* mapcolor (BLACK, 0, 0, 0); mapcolor (COLORS, 255, 0, 0); mapcolor (COLOR1, 0, 255, 0); mapcolor (COLOR2, 255, 255, 0); */ make_eclipse8_range(ECLIPSE8_RAMP, 25, 250, 125, 250, 0, 0); } } /**** New routines for ECLIPSE 8 bit machine */ /* reduces color index value to the lower 16 indices in the color table see ECLIPSE8_RAMP[] for which entries are used for ramp */ short reduce_index (short c) { c = c - RAMPB + 4; while (c > 13) c -= 10; if (c > 6) c++; return(c); } void getcoords (void) { pikx = getvaluator(MOUSEX); piky = getvaluator(MOUSEY); if (pikx <= worgx || pikx >= worgx + wsizex || piky <= worgy || piky >= worgy + wsizey) { pikx = worgx + wsizex / 2 + 1; piky = worgy + wsizey / 2 + 1; } } static void getMouseCoords (void) { int x, y; tkGetMouseLoc (&x, &y); pikx = x; piky = wsizey - y; if ( (pikx < 0) || (pikx > wsizex) || (piky < 0) || (piky > wsizey) ) { pikx = wsizex / 2 + 1; piky = wsizey / 2 + 1; } } int l05 (int i) { if (i < 0) return (i + 6); if (i > 5) return (i - 6); return (i); } int sgn (float i) { if (i < 0) return (-1); if (i > 0) return (1); return (0); } static void fixWindow (void) { halfwinx = (float)wsizex / 2.0; halfwiny = (float)wsizey / 2.0; glViewport (0, 0, wsizex, wsizey); glPopMatrix(); glPushMatrix(); gluPerspective (80, wsizex / (float) wsizey, 0.01, 131072); } /* draw_shadow -- draw halftone shape of insect onto the floor */ void draw_shadow (void) { int leg; glPushMatrix (); glCallList (shadow); glEnable (GL_POLYGON_STIPPLE); glTranslatef (px, py, 1.0); glCallList (body_shadow); for (leg = 0; leg < 6; leg++) { glPushMatrix (); /* glRotatef ((GLfloat) (-leg * 600), 0, 0, 1); */ glRotatef ((GLfloat) (-leg * 60), 0, 0, 1); glTranslatef (0.0, 0.5, 0.0); glCallList (hip_shadow); /* glRotatef (hip_phi[leg], 0, 0, 1); glRotatef (hip_theta[leg], 1, 0, 0); */ glRotatef (hip_phi[leg] / 10, 0, 0, 1); glRotatef (hip_theta[leg]/10, 1, 0, 0); glCallList (thigh_shadow); glCallList (kneeball_shadow); glTranslatef (0.0, 1.0, 0.0); /* glRotatef (knee[leg], 1, 0, 0); */ glRotatef (knee[leg]/10, 1, 0, 0); glCallList (shin_shadow); glPopMatrix (); } glDisable (GL_POLYGON_STIPPLE); glPopMatrix (); } /* draw_hind -- draw a rear leg. First draw hip, then shin, then thigh and knee joint */ void draw_hind (int leg) { glPushMatrix (); /* glRotatef ((GLfloat) (-leg * 600), 0, 0, 1); */ glRotatef ((GLfloat) (-leg * 60), 0, 0, 1); glTranslatef (0.0, 0.5, 0.0); glCallList (hip[leg]); /* glRotatef (hip_phi[leg], 0, 0, 1); glRotatef (hip_theta[leg], 1, 0, 0); */ glRotatef (hip_phi[leg]/10, 0, 0, 1); glRotatef (hip_theta[leg]/10, 1, 0, 0); glPushMatrix (); /* draw thigh */ glTranslatef (0.0, 1.0, 0.0); /* glRotatef (knee[leg], 1, 0, 0); */ glRotatef (knee[leg]/10, 1, 0, 0); glCallList (shin[leg]); glPopMatrix (); if (cz < -5.0) { glCallList (kneeball[leg]); glCallList (thigh[leg]); } else { glCallList (kneeball[leg]); glCallList (thigh[leg]); } glPopMatrix (); } /* draw_fore -- draw a front leg. First draw hip, then thigh, knee joint and finally shin */ void draw_fore (int leg) { glPushMatrix (); /* glRotatef ((GLfloat) (-leg * 600), 0, 0, 1); */ glRotatef ((GLfloat) (-leg * 60), 0, 0, 1); glTranslatef (0.0, 0.5, 0.0); glCallList (hip[leg]); /* glRotatef (hip_phi[leg], 0, 0, 1); glRotatef (hip_theta[leg], 1, 0, 0); */ glRotatef (hip_phi[leg]/10, 0, 0, 1); glRotatef (hip_theta[leg]/10, 1, 0, 0); glCallList (thigh[leg]); glCallList (kneeball[leg]); glTranslatef (0.0, 1.0, 0.0); /* glRotatef (knee[leg], 1, 0, 0); */ glRotatef (knee[leg]/10, 1, 0, 0); glCallList (shin[leg]); glPopMatrix (); } /* draw_insect -- draw rear legs, body and forelegs of insect the order of drawing the objects is important to insure proper hidden surface elimination -- painter's algorithm */ void draw_insect (void) { GLfloat a; float o; int order; o = atan2 (cy + py, cx + px) + PI - (PI / 3.0); order = l05 ((int) integer (o / (PI / 3.0))); glPushMatrix (); /* world */ glTranslatef (px, py, 1.0); draw_hind (l05 (3 - order)); draw_hind (l05 (4 - order)); draw_hind (l05 (2 - order)); glCallList (body); draw_fore (l05 (5 - order)); draw_fore (l05 (1 - order)); draw_fore (l05 (0 - order)); glPopMatrix (); } /* spin_scene -- poll input devices, keyboard and mouse move eye position based upon user input */ void spin_scene (void) { float sin1, cos1, sin2, cos2, t; int mx, my; /* big change to keep movement relative to window */ /* check if still in window x and y are globals - see getcoords */ /* getcoords (); mx = 64 * ((pikx - worgx) - (wsizex / 2)) / wsizex; my = 64 * ((piky - worgy) - (wsizey / 2)) / wsizey; */ getMouseCoords(); mx = 64 * (pikx - (wsizex/2)) / wsizex; my = 64 * (piky - (wsizey/2)) / wsizey; /* mx = (getvaluator (MOUSEX) - 640) / 16; my = (getvaluator (MOUSEY) - 512) / 16; */ switch (function) { case BACKWARD: gl_sincos (ctheta, &sin1, &cos1); gl_sincos (cphi, &sin2, &cos2); cvz -= cos1; cvx -= sin2 * sin1; cvy -= cos2 * sin1; function = NOTHING; break; case FORWARD: gl_sincos (ctheta, &sin1, &cos1); gl_sincos (cphi, &sin2, &cos2); cvz += cos1; cvx += sin2 * sin1; cvy += cos2 * sin1; function = NOTHING; break; case LEFT: cvz = (float) - my; gl_sincos (cphi, &sin1, &cos1); cvx = cos1 * (float) (-mx); cvy = -sin1 * (float) (-mx); break; default: cvx = cvx * 0.7; cvy = cvy * 0.7; cvz = cvz * 0.7; break; } if (function == MIDDLE) { cvtheta = my; cvphi = mx; } else { cvtheta += -cvtheta / 4; if ((cvtheta < 4) && (cvtheta > -4)) cvtheta = 0; cvphi += -cvphi / 4; if ((cvphi < 4) && (cvphi > -4)) cvphi = 0; if (function != LEFT) function = NOTHING; } cx += cvx * 0.0078125; cy += cvy * 0.0078125; if (cz > 0.0) { cz = 0.0; cvz = 0.0; } else cz += cvz * 0.0078125; ctheta += cvtheta; cphi += cvphi; } GLfloat degrees (float a) { return ((GLfloat) (a * 1800.0 / PI)); } void getstuff (void) { int x, y, i; int tr; legup[0] = GL_FALSE; legup[2] = GL_FALSE; legup[4] = GL_FALSE; legup[1] = GL_TRUE; legup[3] = GL_TRUE; legup[5] = GL_TRUE; px = 0.0; py = 0.0; for (i = 0; i < 6; i++) { legx[i] = 30.0 / 2.0 + (float) i; legy[i] = 30.0 / 2.0 + (float) i; } } void dolegs (void) { int i; float r, l, gx, gy, k, t, a, ux, uy; int leg, tr; for (leg = 0; leg < 6; leg++) { gx = legx[leg] - 30.0 / 2.0; gy = legy[leg] - 30.0 / 2.0; ux = gx / (30.0 / 2.0); uy = gy / (30.0 / 2.0); switch (leg) { case 0: gx += 0.0; gy += 30.0; break; case 1: gx += (30.0 * 0.8660254); gy += (30.0 * 0.5); break; case 2: gx += (30.0 * 0.8660254); gy += (30.0 * -0.5); break; case 3: gx += 0.0; gy += -30.0; break; case 4: gx += (30.0 * -0.8660254); gy += (30.0 * -0.5);; break; case 5: gx += (30.0 * -0.8660254); gy += (30.0 * 0.5); break; } r = sqrt ((gx * gx) + (gy * gy)) / 30.0; l = sqrt (1.0 + (r * r)); k = acos ((5.0 - (l * l)) / 4.0); knee[leg] = (GLfloat) degrees (k); t = (2.0 * sin (k)) / l; if (t > 1.0) t = 1.0; a = asin (t); if (l < 1.7320508) a = PI - a; hip_theta[leg] = (GLfloat) (degrees (a - atan2 (1.0, r))); if (gx == 0.0) { hip_phi[leg] = (GLfloat) (900 * sgn (gy)); } else { hip_phi[leg] = (GLfloat) (degrees (atan2 (gy, gx))); } hip_phi[leg] += (-900 + 600 * leg); if (legup[leg]) { hip_theta[leg] += (GLfloat) (200.0 * ((fr[leg] / 2.0) - fabso (dmr[leg] - (fr[leg] / 2.0)))); } } } void move_insect (void) { register int i; register float mx, my, vx, vy, dx, dy, dr, lx, ly, lr, dmx, dmy; float s, c; /* mx = (float) getvaluator (MOUSEX) / 640.0 - 1.0; my = (float) getvaluator (MOUSEY) / 512.0 - 1.0; */ /* changed to keep input within the window. x and y are globals - see getcoords */ /* getcoords (); mx = ((float)pikx - (float)worgx) / halfwinx - 1.0; my = ((float)piky - (float)worgy) / halfwiny - 1.0; */ getMouseCoords(); mx = pikx / halfwinx - 1.0; my = piky / halfwiny - 1.0; gl_sincos (cphi, &s, &c); dx = mx * c + my * s; dy = -mx * s + my * c; mx = dx; my = dy; px += mx / (float) (RES); py += my / (float) (RES); if (follow) { cx -= mx / (float) (RES); cy -= my / (float) (RES); } dr = sqrt (mx * mx + my * my); dx = mx / dr; dy = my / dr; for (i = 0; i < 6; i++) { lx = legx[i] - (float) (RES / 2); ly = legy[i] - (float) (RES / 2); lr = (float) (RES / 2); lx = lx / lr; ly = ly / lr; dmx = (dx - lx); dmy = (dy - ly); dmr[i] = sqrt (dmx * dmx + dmy * dmy); if (legup[i]) { dmx = 3 * dr * dmx / dmr[i]; dmy = 3 * dr * dmy / dmr[i]; legx[i] += dmx; legy[i] += dmy; if ((dmr[i]) < 0.15) { legup[i] = GL_FALSE; } } else { legx[i] -= mx; legy[i] -= my; if (!legup[l05 (i - 1)] && !legup[l05 (i + 1)] && (dmr[i] > REACH) && ((lx * dx + ly * dy) < 0.0)) { legup[i] = GL_TRUE; fr[i] = dmr[i]; legx[i] += dmx; legy[i] += dmy; } } } } void rotate60 (char c, int n, GLfloat a[][3]) { int i, j, l; float nx, ny; switch (c) { case 'z': i = 0; j = 1; break; case 'y': i = 2; j = 0; break; case 'x': i = 1; j = 2; break; }; for (l = 0; l < n; l++) { nx = a[l][i] * COS60 - a[l][j] * SIN60; ny = a[l][i] * SIN60 + a[l][j] * COS60; a[l][i] = nx; a[l][j] = ny; } } void getpolycolor (int p, float pts[][3]) { float norm[3]; float v1[3], v2[3], cons; int i, get; float c; for (i = 0; i < 3; i++) norm[i] = 0.0; i = 0; get = 1; i = 1; v1[0] = pts[1][0] - pts[0][0]; v1[1] = pts[1][1] - pts[0][1]; v1[2] = pts[1][2] - pts[0][2]; v2[0] = pts[2][0] - pts[0][0]; v2[1] = pts[2][1] - pts[0][1]; v2[2] = pts[2][2] - pts[0][2]; norm[0] = v1[1] * v2[2] - v1[2] * v2[1]; norm[1] = v1[2] * v2[0] - v1[0] * v2[2]; norm[2] = v1[0] * v2[1] - v1[1] * v2[0]; cons = sqrt ((norm[0] * norm[0]) + (norm[1] * norm[1]) + (norm[2] * norm[2])); for (i = 0; i < 3; i++) norm[i] = norm[i] / cons; c = dot (norm, light); if (c < 0.0) c = 0.0; if (c > 1.0) c = 1.0; switch (p) { case 0: c = (float) (RAMPE - RAMPB) * c + (float) (RAMPB); if (((unsigned short) c) > RAMPE) c = (float) RAMPE; #ifdef FLAT_SHADING c = COLOR1; #endif break; case 1: c = (float) (RAMPE2 - RAMPB2) * c + (float) (RAMPB2); if (((unsigned short) c) > RAMPE2) c = (float) RAMPE2; #ifdef FLAT_SHADING c = COLOR2; #endif break; case 2: c = (float) (RAMPE3 - RAMPB3) * c + (float) (RAMPB3); if (((unsigned short) c) > RAMPE3) c = (float) RAMPE3; #ifdef FLAT_SHADING c = COLOR2; #endif break; case 3: c = (float) (RAMPE4 - RAMPB4) * c + (float) (RAMPB4); if (((unsigned short) c) > RAMPE4) c = (float) RAMPE4; #ifdef FLAT_SHADING c = COLOR2; #endif break; case 4: c = (float) (RAMPE5 - RAMPB5) * c + (float) (RAMPB5); if (((unsigned short) c) > RAMPE5) c = (float) RAMPE5; #ifdef FLAT_SHADING c = COLOR2; #endif break; } /* Changed for 8 bit ECLIPSE machine */ if (is_8bit) c = (float)reduce_index((int)c); glIndexi (c); } GLboolean lit (int p, float pts[][3]) { float norm[3]; float v1[3], v2[3], cons; int i, get; float c; for (i = 0; i < 3; i++) norm[i] = 0.0; i = 0; get = 1; i = 1; v1[0] = pts[1][0] - pts[0][0]; v1[1] = pts[1][1] - pts[0][1]; v1[2] = pts[1][2] - pts[0][2]; v2[0] = pts[2][0] - pts[0][0]; v2[1] = pts[2][1] - pts[0][1]; v2[2] = pts[2][2] - pts[0][2]; norm[0] = v1[1] * v2[2] - v1[2] * v2[1]; norm[1] = v1[2] * v2[0] - v1[0] * v2[2]; norm[2] = v1[0] * v2[1] - v1[1] * v2[0]; cons = sqrt ((norm[0] * norm[0]) + (norm[1] * norm[1]) + (norm[2] * norm[2])); for (i = 0; i < 3; i++) norm[i] = norm[i] / cons; c = dot (norm, light); return (c > 0.0); } float dot (float vec1[3], float vec2[3]) { float xx; xx = (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]) + (vec1[0] * vec2[0]); return ((float) xx); } void getlightvector (void) { float f; light[2] = cos (theta); f = sin (theta); light[1] = -sin (phi) * f; light[0] = -cos (phi) * f; } float integer (float x) { if (x < 0.0) x -= 1.0; x = (float) (int) x; return (x); } float frac (float x) { return (x - integer (x)); } float fabso (float x) { if (x < 0.0) return (-x); else return (x); } void drawAll (void) { /* new for ECLIPSE 8 bit version */ if (is_8bit) glClearIndex (ECLIPSE8_SKYBLUE); else glClearIndex (SKYBLUE); glClear (GL_COLOR_BUFFER_BIT); glPushMatrix(); doViewit(); glCallList (screen); draw_shadow(); draw_insect(); glPopMatrix(); } static void Reshape(int width, int height) { wsizex = width; wsizey = height; fixWindow(); } static GLenum Key(int key, GLenum mask) { switch (key) { case TK_ESCAPE: tkQuit(); break; case TK_A: case TK_a: function = FORWARD; break; case TK_Z: case TK_z: function = BACKWARD; break; case TK_F: case TK_f: follow = !follow; break; default: return GL_FALSE; } return GL_TRUE; } static GLenum MouseUp(int mouseX, int mouseY, GLenum button) { switch (button) { case TK_LEFTBUTTON: function = NOTHING; break; case TK_MIDDLEBUTTON: function = NOTHING; break; default: return GL_FALSE; } return GL_TRUE; } static GLenum MouseDown(int mouseX, int mouseY, GLenum button) { switch (button) { case TK_LEFTBUTTON: function = LEFT; break; case TK_MIDDLEBUTTON: function = MIDDLE; break; default: return GL_FALSE; } return GL_TRUE; } static void animate (void) { spin_scene(); move_insect(); dolegs(); drawAll(); tkSwapBuffers(); } /* main routine -- handle tokens of window manager -- display shadow and insect */ void main (int argc, char *argv[]) { int i, j, k; short dev, val; long nplanes; GLboolean attached; follow = GL_TRUE; wsizex = 500; wsizey = 400; worgx = 252; worgy = 184; tkInitPosition(0, 0, wsizex, wsizey); tkInitDisplayMode(TK_INDEX|TK_DOUBLE|TK_DIRECT|TK_DEPTH16); if (tkInitWindow("Insect") == GL_FALSE) { tkQuit(); } glPolygonStipple ((unsigned char *) halftone); glShadeModel(GL_FLAT); getlightvector (); /* Changes for ECLIPSE 8 bit machine */ /* * Machines with enough bitplanes will use colormap entries CMAPSTART * to CMAPSTART+127. If the machine doesn't have enough bitplanes, * only colors 0 to 15 will be used (it is assumed that all machines * have at least 4 bitplanes in colormap double-buffered mode). */ #ifdef ECLIPSE nplanes = glGetI(GD_BITS_NORM_DBL_CMODE); /* save color map in savearray */ if ((1< (CMAPSTART+127)) { is_8bit = GL_FALSE; } else { is_8bit = GL_TRUE; } #else nplanes = 4; is_8bit = GL_TRUE; #endif setupcolors (); /* initialize transformation stuff */ cx = 0.0; cy = 10.0; cz = -2.0; cvx = cvy = cvz = 0.0; ctheta = -900; cphi = 0; cvtheta = cvphi = 0.0; function = NOTHING; glPushMatrix(); fixWindow(); createobjects (); getstuff (); spin_scene (); move_insect (); dolegs (); tkExposeFunc(Reshape); tkReshapeFunc(Reshape); tkKeyDownFunc(Key); tkMouseDownFunc(MouseDown); tkMouseUpFunc(MouseUp); tkIdleFunc(animate); tkExec(); glPopMatrix(); }