#include #include #include #include #ifndef WIN32 #include #endif /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265 #endif #include #include /* For portability... */ #undef fcos #undef fsin #undef fsqrt #ifdef MGL_HAS_NO_SPE_NEWLIB #define fcos spe_cos #define fsin spe_sin #define fsqrt spe_sqrt #else #define fcos cos #define fsin sin #define fsqrt sqrt #endif /* Minimum stack space */ static USED const char *stack = "$STACK:65535"; static double d_near = 1.0; static double d_far = 2000; static int poo = 0; int spinning = 1; typedef struct { float rad, wid; } Profile; void flat_face(float ir, float or, float wd); void draw_inside(float w1, float w2, float rad); void draw_outside(float w1, float w2, float rad); void tooth_side(int nt, float ir, float or, float tp, float tip, float wd); int circle_subdiv; int width, height; char *buffer = NULL; int showPic = 0; void screenshot(void) { glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadBuffer(GL_FRONT); if (buffer) free(buffer); buffer = malloc(width * height * 4); if (buffer) glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); } void gear(int nt, float wd, float ir, float or, float tp, float tip, int ns, Profile * ip) { /** * nt - number of teeth * wd - width of gear at teeth * ir - inside radius absolute scale * or - radius at outside of wheel (tip of tooth) ratio of ir * tp - ratio of tooth in slice of circle (0..1] (1 = teeth are touching at base) * tip - ratio of tip of tooth (0..tp] (cant be wider that base of tooth) * ns - number of elements in wheel width profile * *ip - list of float pairs {start radius, width, ...} (width is ratio to wd) * */ /* gear lying on xy plane, z for width. all normals calulated (normalized) */ float prev; int k, t; /* estimat # times to divide circle */ if (nt <= 0) circle_subdiv = 64; else { /* lowest multiple of number of teeth */ circle_subdiv = nt; while (circle_subdiv < 64) circle_subdiv += nt; } /* --- draw wheel face --- */ /* draw horzontal, vertical faces for each section. if first section radius not zero, use wd for 0.. first if ns == 0 use wd for whole face. last width used to edge. */ if (ns <= 0) { flat_face(0.0, ir, wd); } else { /* draw first flat_face, then continue in loop */ if (ip[0].rad > 0.0) { flat_face(0.0, ip[0].rad * ir, wd); prev = wd; t = 0; } else { flat_face(0.0, ip[1].rad * ir, ip[0].wid * wd); prev = ip[0].wid; t = 1; } for (k = t; k < ns; k++) { if (prev < ip[k].wid) { draw_inside(prev * wd, ip[k].wid * wd, ip[k].rad * ir); } else { draw_outside(prev * wd, ip[k].wid * wd, ip[k].rad * ir); } prev = ip[k].wid; /* - draw to edge of wheel, add final face if needed - */ if (k == ns - 1) { flat_face(ip[k].rad * ir, ir, ip[k].wid * wd); /* now draw side to match tooth rim */ if (ip[k].wid < 1.0) { draw_inside(ip[k].wid * wd, wd, ir); } else { draw_outside(ip[k].wid * wd, wd, ir); } } else { flat_face(ip[k].rad * ir, ip[k + 1].rad * ir, ip[k].wid * wd); } } } /* --- tooth side faces --- */ tooth_side(nt, ir, or, tp, tip, wd); /* --- tooth hill surface --- */ } void tooth_side(int nt, float ir, float or, float tp, float tip, float wd) { float i; float end = 2.0 * M_PI / nt; float x[6], y[6]; float s[3], c[3]; or = or * ir; /* or is really a ratio of ir */ for (i = 0; i < 2.0 * M_PI - end / 4.0; i += end) { c[0] = fcos(i); s[0] = fsin(i); c[1] = fcos(i + end * (0.5 - tip / 2)); s[1] = fsin(i + end * (0.5 - tip / 2)); c[2] = fcos(i + end * (0.5 + tp / 2)); s[2] = fsin(i + end * (0.5 + tp / 2)); x[0] = ir * c[0]; y[0] = ir * s[0]; x[5] = ir * fcos(i + end); y[5] = ir * fsin(i + end); /* ---treat veritices 1,4 special to match strait edge of face */ x[1] = x[0] + (x[5] - x[0]) * (0.5 - tp / 2); y[1] = y[0] + (y[5] - y[0]) * (0.5 - tp / 2); x[4] = x[0] + (x[5] - x[0]) * (0.5 + tp / 2); y[4] = y[0] + (y[5] - y[0]) * (0.5 + tp / 2); x[2] = or * fcos(i + end * (0.5 - tip / 2)); y[2] = or * fsin(i + end * (0.5 - tip / 2)); x[3] = or * fcos(i + end * (0.5 + tip / 2)); y[3] = or * fsin(i + end * (0.5 + tip / 2)); /* draw face trapezoids as 2 tmesh */ glNormal3f(0.0, 0.0, 1.0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[2], y[2], wd / 2); glVertex3f(x[1], y[1], wd / 2); glVertex3f(x[3], y[3], wd / 2); glVertex3f(x[4], y[4], wd / 2); glEnd(); glNormal3f(0.0, 0.0, -1.0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[2], y[2], -wd / 2); glVertex3f(x[1], y[1], -wd / 2); glVertex3f(x[3], y[3], -wd / 2); glVertex3f(x[4], y[4], -wd / 2); glEnd(); /* draw inside rim pieces */ glNormal3f(c[0], s[0], 0.0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[0], y[0], -wd / 2); glVertex3f(x[1], y[1], -wd / 2); glVertex3f(x[0], y[0], wd / 2); glVertex3f(x[1], y[1], wd / 2); glEnd(); /* draw up hill side */ { float a, b, n; /* calculate normal of face */ a = x[2] - x[1]; b = y[2] - y[1]; n = 1.0 / fsqrt(a * a + b * b); a = a * n; b = b * n; glNormal3f(b, -a, 0.0); } glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[1], y[1], -wd / 2); glVertex3f(x[2], y[2], -wd / 2); glVertex3f(x[1], y[1], wd / 2); glVertex3f(x[2], y[2], wd / 2); glEnd(); /* draw top of hill */ glNormal3f(c[1], s[1], 0.0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[2], y[2], -wd / 2); glVertex3f(x[3], y[3], -wd / 2); glVertex3f(x[2], y[2], wd / 2); glVertex3f(x[3], y[3], wd / 2); glEnd(); /* draw down hill side */ { float a, b, c; /* calculate normal of face */ a = x[4] - x[3]; b = y[4] - y[3]; c = 1.0 / fsqrt(a * a + b * b); a = a * c; b = b * c; glNormal3f(b, -a, 0.0); } glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[3], y[3], -wd / 2); glVertex3f(x[4], y[4], -wd / 2); glVertex3f(x[3], y[3], wd / 2); glVertex3f(x[4], y[4], wd / 2); glEnd(); /* inside rim part */ glNormal3f(c[2], s[2], 0.0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(x[4], y[4], -wd / 2); glVertex3f(x[5], y[5], -wd / 2); glVertex3f(x[4], y[4], wd / 2); glVertex3f(x[5], y[5], wd / 2); glEnd(); } } void flat_face(float ir, float or, float wd) { int i; float w; /* draw each face (top & bottom ) * */ if (poo) #ifdef MGL_HAS_NO_SPE_NEWLIB printf("Face : %d..%d wid=%d\n", (int)ir, (int)or, (int)wd); #else printf("Face : %f..%f wid=%f\n", ir, or, wd); #endif if (wd == 0.0) return; for (w = wd / 2; w > -wd; w -= wd) { if (w > 0.0) glNormal3f(0.0, 0.0, 1.0); else glNormal3f(0.0, 0.0, -1.0); if (ir == 0.0) { /* draw as t-fan */ glBegin(GL_TRIANGLE_FAN); glVertex3f(0.0, 0.0, w); /* center */ glVertex3f(or, 0.0, w); for (i = 1; i < circle_subdiv; i++) { glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * or, fsin(2.0 * M_PI * i / circle_subdiv) * or, w); } glVertex3f(or, 0.0, w); glEnd(); } else { /* draw as tmesh */ glBegin(GL_TRIANGLE_STRIP); glVertex3f(or, 0.0, w); glVertex3f(ir, 0.0, w); for (i = 1; i < circle_subdiv; i++) { glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * or, fsin(2.0 * M_PI * i / circle_subdiv) * or, w); glVertex3f(fcos(2.0 * M_PI * i / circle_subdiv) * ir, fsin(2.0 * M_PI * i / circle_subdiv) * ir, w); } glVertex3f(or, 0.0, w); glVertex3f(ir, 0.0, w); glEnd(); } } } void draw_inside(float w1, float w2, float rad) { int i, j; float c, s; if (poo) #ifdef MGL_HAS_NO_SPE_NEWLIB printf("Inside: wid=%d..%d rad=%d\n", (int)w1, (int)w2, (int)rad); #else printf("Inside: wid=%f..%f rad=%f\n", w1, w2, rad); #endif if (w1 == w2) return; w1 = w1 / 2; w2 = w2 / 2; for (j = 0; j < 2; j++) { if (j == 1) { w1 = -w1; w2 = -w2; } glBegin(GL_TRIANGLE_STRIP); glNormal3f(-1.0, 0.0, 0.0); glVertex3f(rad, 0.0, w1); glVertex3f(rad, 0.0, w2); for (i = 1; i < circle_subdiv; i++) { c = fcos(2.0 * M_PI * i / circle_subdiv); s = fsin(2.0 * M_PI * i / circle_subdiv); glNormal3f(-c, -s, 0.0); glVertex3f(c * rad, s * rad, w1); glVertex3f(c * rad, s * rad, w2); } glNormal3f(-1.0, 0.0, 0.0); glVertex3f(rad, 0.0, w1); glVertex3f(rad, 0.0, w2); glEnd(); } } void draw_outside(float w1, float w2, float rad) { int i, j; float c, s; if (poo) #ifdef MGL_HAS_NO_SPE_NEWLIB printf("Outsid: wid=%d..%d rad=%d\n", (int)w1, (int)w2, (int)rad); #else printf("Outsid: wid=%f..%f rad=%f\n", w1, w2, rad); #endif if (w1 == w2) return; w1 = w1 / 2; w2 = w2 / 2; for (j = 0; j < 2; j++) { if (j == 1) { w1 = -w1; w2 = -w2; } glBegin(GL_TRIANGLE_STRIP); glNormal3f(1.0, 0.0, 0.0); glVertex3f(rad, 0.0, w1); glVertex3f(rad, 0.0, w2); for (i = 1; i < circle_subdiv; i++) { c = fcos(2.0 * M_PI * i / circle_subdiv); s = fsin(2.0 * M_PI * i / circle_subdiv); glNormal3f(c, s, 0.0); glVertex3f(c * rad, s * rad, w1); glVertex3f(c * rad, s * rad, w2); } glNormal3f(1.0, 0.0, 0.0); glVertex3f(rad, 0.0, w1); glVertex3f(rad, 0.0, w2); glEnd(); } } Profile gear_profile[] = { {0.000, 0.0}, {0.300, 7.0}, {0.340, 0.4}, {0.550, 0.64}, {0.600, 0.4}, {0.950, 1.0} }; float a1 = 27.0; float a2 = 67.0; float a3 = 47.0; float a4 = 87.0; float i1 = 1.2; float i2 = 3.1; float i3 = 2.3; float i4 = 1.1; void oneFrame(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(0.0, 0.0, -4.0); glRotatef(a3, 1.0, 1.0, 1.0); glRotatef(a4, 0.0, 0.0, -1.0); glTranslatef(0.14, 0.2, 0.0); gear(76, 0.4, 2.0, 1.1, 0.4, 0.04, sizeof(gear_profile) / sizeof(Profile), gear_profile); glPopMatrix(); #if 0 glPushMatrix(); glTranslatef(0.1, 0.2, -3.8); glRotatef(a2, -4.0, 2.0, -1.0); glRotatef(a1, 1.0, -3.0, 1.0); glTranslatef(0.0, -0.2, 0.0); gear(36, 0.4, 2.0, 1.1, 0.7, 0.2, sizeof(gear_profile) / sizeof(Profile), gear_profile); glPopMatrix(); #endif if (spinning) { a1 += i1; if (a1 > 360.0) a1 -= 360.0; if (a1 < 0.0) a1 -= 360.0; a2 += i2; if (a2 > 360.0) a2 -= 360.0; if (a2 < 0.0) a2 -= 360.0; a3 += i3; if (a3 > 360.0) a3 -= 360.0; if (a3 < 0.0) a3 -= 360.0; a4 += i4; if (a4 > 360.0) a4 -= 360.0; if (a4 < 0.0) a4 -= 360.0; } if (showPic && buffer) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0.0, width, 0.0, height, 0.0, 2.0); glRasterPos2i(10, 10); glPixelZoom(0.4, 0.4); glDrawPixels(width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer); glPixelZoom(1.0, 1.0); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } glutSwapBuffers(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -1.0, 1.0, d_near, d_far); /** use perspective instead: if (w <= h){ glOrtho( 0.0, 1.0, 0.0, 1.0 * (GLfloat) h / (GLfloat) w, -16.0, 4.0); }else{ glOrtho( 0.0, 1.0 * (GLfloat) w / (GLfloat) h, 0.0, 1.0, -16.0, 4.0); } */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); width = w; height = h; } void visibility(int status) { if (status == GLUT_VISIBLE) { glutIdleFunc(oneFrame); } else { glutIdleFunc(NULL); } } void myinit(void) { float f[20]; glClearColor(0.5, 0.5, 0.5, 1.0); glColor3f(0.3, 0.3, 0.3); myReshape(640, 480); /* glShadeModel(GL_FLAT); */ glEnable(GL_DEPTH_TEST); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_LIGHTING); glLightf(GL_LIGHT0, GL_SHININESS, 1.0); f[0] = 1.3; f[1] = 1.3; f[2] = -3.3; f[3] = 1.0; glLightfv(GL_LIGHT0, GL_POSITION, f); f[0] = 0.8; f[1] = 1.0; f[2] = 0.83; f[3] = 1.0; glLightfv(GL_LIGHT0, GL_SPECULAR, f); glLightfv(GL_LIGHT0, GL_DIFFUSE, f); glEnable(GL_LIGHT0); glLightf(GL_LIGHT1, GL_SHININESS, 1.0); f[0] = -2.3; f[1] = 0.3; f[2] = -7.3; f[3] = 1.0; glLightfv(GL_LIGHT1, GL_POSITION, f); f[0] = 1.0; f[1] = 0.8; f[2] = 0.93; f[3] = 1.0; glLightfv(GL_LIGHT1, GL_SPECULAR, f); glLightfv(GL_LIGHT1, GL_DIFFUSE, f); glEnable(GL_LIGHT1); /* gear material */ f[0] = 0.1; f[1] = 0.15; f[2] = 0.2; f[3] = 1.0; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, f); f[0] = 0.9; f[1] = 0.3; f[2] = 0.3; f[3] = 1.0; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, f); f[0] = 0.4; f[1] = 0.9; f[2] = 0.6; f[3] = 1.0; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, f); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 4); } /* ARGSUSED1 */ void keys(unsigned char c, int x, int y) { if (c == 'e') glEnable(GL_LIGHTING); if (c == 'n') glDisable(GL_LIGHTING); if (c == 's') spinning = !spinning; if (c == 'c') screenshot(); if (c == 'w') showPic = !showPic; if (c == 0x1b) exit(0); /* escape */ } int main(int argc, char **argv) { int mode = GLUT_DOUBLE; width = 640; height = 480; glutInit(&argc, argv); if (argc > 1) mode = GLUT_SINGLE; glutInitDisplayMode(mode | GLUT_RGB | GLUT_DEPTH); glutInitWindowPosition(100, 100); glutInitWindowSize(width, height); glutCreateWindow(argv[0]); myinit(); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutKeyboardFunc(keys); glutVisibilityFunc(visibility); glutPostRedisplay(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ }