diff options
-rw-r--r-- | progs/demos/Makefile | 1 | ||||
-rw-r--r-- | progs/demos/gearbox.c | 486 |
2 files changed, 487 insertions, 0 deletions
diff --git a/progs/demos/Makefile b/progs/demos/Makefile index 1f796424c02..2009c42c69d 100644 --- a/progs/demos/Makefile +++ b/progs/demos/Makefile @@ -24,6 +24,7 @@ PROGS = \ fogcoord \ fplight \ gamma \ + gearbox \ gears \ geartrain \ glinfo \ diff --git a/progs/demos/gearbox.c b/progs/demos/gearbox.c new file mode 100644 index 00000000000..fa4cbe726fc --- /dev/null +++ b/progs/demos/gearbox.c @@ -0,0 +1,486 @@ +/* + * Use glCopyTexSubImage2D to draw animated gears on the sides of a box. + * + * Brian Paul + * 27 January 2006 + */ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <GL/glut.h> + +#ifndef M_PI +#define M_PI 3.14159265 +#endif + +static GLint WinWidth = 800, WinHeight = 500; +static GLint TexWidth, TexHeight; +static GLuint TexObj = 1; +static GLenum IntFormat = GL_RGB; + +static GLboolean WireFrame = GL_FALSE; + +static GLint T0 = 0; +static GLint Frames = 0; +static GLint Win = 0; + +static GLfloat ViewRotX = 20.0, ViewRotY = 30.0, ViewRotZ = 0.0; +static GLint Gear1, Gear2, Gear3; +static GLfloat GearRot = 0.0; +static GLfloat CubeRot = 0.0; + + +/** + Draw a gear wheel. You'll probably want to call this function when + building a display list since we do a lot of trig here. + + Input: inner_radius - radius of hole at center + outer_radius - radius at center of teeth + width - width of gear + teeth - number of teeth + tooth_depth - depth of tooth + **/ +static void +gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLint i; + GLfloat r0, r1, r2; + GLfloat angle, da; + GLfloat u, v, len; + + r0 = inner_radius; + r1 = outer_radius - tooth_depth / 2.0; + r2 = outer_radius + tooth_depth / 2.0; + + da = 2.0 * M_PI / teeth / 4.0; + + glShadeModel(GL_FLAT); + + glNormal3f(0.0, 0.0, 1.0); + + /* draw front face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + if (i < teeth) { + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + } + } + glEnd(); + + /* draw front sides of teeth */ + glBegin(GL_QUADS); + da = 2.0 * M_PI / teeth / 4.0; + for (i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + } + glEnd(); + + glNormal3f(0.0, 0.0, -1.0); + + /* draw back face */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + if (i < teeth) { + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + } + } + glEnd(); + + /* draw back sides of teeth */ + glBegin(GL_QUADS); + da = 2.0 * M_PI / teeth / 4.0; + for (i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + } + glEnd(); + + /* draw outward faces of teeth */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + + glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); + glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); + u = r2 * cos(angle + da) - r1 * cos(angle); + v = r2 * sin(angle + da) - r1 * sin(angle); + len = sqrt(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); + glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); + glNormal3f(cos(angle), sin(angle), 0.0); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); + glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); + u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); + v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); + glNormal3f(v, -u, 0.0); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); + glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); + glNormal3f(cos(angle), sin(angle), 0.0); + } + + glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); + glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); + + glEnd(); + + glShadeModel(GL_SMOOTH); + + /* draw inside radius cylinder */ + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) { + angle = i * 2.0 * M_PI / teeth; + glNormal3f(-cos(angle), -sin(angle), 0.0); + glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); + glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); + } + glEnd(); + +} + +static void +cleanup(void) +{ + glDeleteTextures(1, &TexObj); + glDeleteLists(Gear1, 1); + glDeleteLists(Gear2, 1); + glDeleteLists(Gear3, 1); + glutDestroyWindow(Win); +} + + +static void +DrawGears(void) +{ + if (WireFrame) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + + glPushMatrix(); + glRotatef(20/*ViewRotX*/, 1.0, 0.0, 0.0); + glRotatef(ViewRotY, 0.0, 1.0, 0.0); + glRotatef(ViewRotZ, 0.0, 0.0, 1.0); + + glPushMatrix(); + glTranslatef(-3.0, -2.0, 0.0); + glRotatef(GearRot, 0.0, 0.0, 1.0); + glCallList(Gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1, -2.0, 0.0); + glRotatef(-2.0 * GearRot - 9.0, 0.0, 0.0, 1.0); + glCallList(Gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1, 4.2, 0.0); + glRotatef(-2.0 * GearRot - 25.0, 0.0, 0.0, 1.0); + glCallList(Gear3); + glPopMatrix(); + + glPopMatrix(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +} + + +static void +DrawCube(void) +{ + static const GLfloat texcoords[4][2] = { + { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } + }; + static const GLfloat vertices[4][2] = { + { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } + }; + static const GLfloat xforms[6][4] = { + { 0, 0, 1, 0 }, + { 90, 0, 1, 0 }, + { 180, 0, 1, 0 }, + { 270, 0, 1, 0 }, + { 90, 1, 0, 0 }, + { -90, 1, 0, 0 } + }; + static const GLfloat mat[4] = { 1.0, 1.0, 0.5, 1.0 }; + GLint i, j; + + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat); + glEnable(GL_TEXTURE_2D); + + glPushMatrix(); + glRotatef(ViewRotX, 1.0, 0.0, 0.0); + glRotatef(15, 1, 0, 0); + glRotatef(CubeRot, 0, 1, 0); + glScalef(4, 4, 4); + + for (i = 0; i < 6; i++) { + glPushMatrix(); + glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]); + glTranslatef(0, 0, 1.1); + glBegin(GL_POLYGON); + glNormal3f(0, 0, 1); + for (j = 0; j < 4; j++) { + glTexCoord2fv(texcoords[j]); + glVertex2fv(vertices[j]); + } + glEnd(); + glPopMatrix(); + } + glPopMatrix(); + + glDisable(GL_TEXTURE_2D); +} + + +static void +draw(void) +{ + float ar; + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -40.0); + + glDisable(GL_SCISSOR_TEST); + glClear(GL_DEPTH_BUFFER_BIT); + glEnable(GL_SCISSOR_TEST); + + /* draw gears */ + glViewport(0, 0, TexWidth, TexHeight); + glScissor(0, 0, TexWidth, TexHeight); + glClearColor(0.5, 0.5, 0.8, 0.0); + glClearColor(1, 1, 1, 0); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + + DrawGears(); + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TexWidth, TexHeight); + + /* draw textured cube */ + glViewport(TexWidth, 0, WinWidth - TexWidth, WinHeight); + glScissor(TexWidth, 0, WinWidth - TexWidth, WinHeight); + glClearColor(0.5, 0.5, 0.8, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + ar = (float) (WinWidth - TexWidth) / WinHeight; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + + DrawCube(); + + /* finish up */ + glutSwapBuffers(); + + Frames++; + { + GLint t = glutGet(GLUT_ELAPSED_TIME); + if (t - T0 >= 5000) { + GLfloat seconds = (t - T0) / 1000.0; + GLfloat fps = Frames / seconds; + printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps); + T0 = t; + Frames = 0; + } + } +} + + +static void +idle(void) +{ + static double t0 = -1.; + double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; + if (t0 < 0.0) + t0 = t; + dt = t - t0; + t0 = t; + + GearRot += 70.0 * dt; /* 70 degrees per second */ + GearRot = fmod(GearRot, 360.0); /* prevents eventual overflow */ + + CubeRot += 15.0 * dt; + + glutPostRedisplay(); +} + + +/* change view angle, exit upon ESC */ +static void +key(unsigned char k, int x, int y) +{ + (void) x; + (void) y; + switch (k) { + case 'w': + WireFrame = !WireFrame; + break; + case 'z': + ViewRotZ += 5.0; + break; + case 'Z': + ViewRotZ -= 5.0; + break; + case 27: /* Escape */ + cleanup(); + exit(0); + break; + default: + return; + } + glutPostRedisplay(); +} + +/* change view angle */ +static void +special(int k, int x, int y) +{ + (void) x; + (void) y; + switch (k) { + case GLUT_KEY_UP: + ViewRotX += 5.0; + break; + case GLUT_KEY_DOWN: + ViewRotX -= 5.0; + break; + case GLUT_KEY_LEFT: + ViewRotY += 5.0; + break; + case GLUT_KEY_RIGHT: + ViewRotY -= 5.0; + break; + default: + return; + } + glutPostRedisplay(); +} + + +/* new window size or exposure */ +static void +reshape(int width, int height) +{ + WinWidth = width; + WinHeight = height; +} + + +static void +init(int argc, char *argv[]) +{ + static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0}; + static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0}; + static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0}; + static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0}; + GLint i; + + glLightfv(GL_LIGHT0, GL_POSITION, pos); +#if 0 + glEnable(GL_CULL_FACE); +#endif + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + /* make the gears */ + Gear1 = glGenLists(1); + glNewList(Gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); + gear(1.0, 4.0, 1.0, 20, 0.7); + glEndList(); + + Gear2 = glGenLists(1); + glNewList(Gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); + gear(0.5, 2.0, 2.0, 10, 0.7); + glEndList(); + + Gear3 = glGenLists(1); + glNewList(Gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); + gear(1.3, 2.0, 0.5, 10, 0.7); + glEndList(); + + glEnable(GL_NORMALIZE); + + /* xxx make size dynamic */ + TexWidth = 256; + TexHeight = 256; + + glBindTexture(GL_TEXTURE_2D, TexObj); + glTexImage2D(GL_TEXTURE_2D, 0, IntFormat, TexWidth, TexHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + for ( i=1; i<argc; i++ ) { + if (strcmp(argv[i], "-info")==0) { + printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); + printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); + printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); + printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); + } + } +} + + +static void +visible(int vis) +{ + if (vis == GLUT_VISIBLE) + glutIdleFunc(idle); + else + glutIdleFunc(NULL); +} + + +int +main(int argc, char *argv[]) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + + glutInitWindowSize(WinWidth, WinHeight); + Win = glutCreateWindow("gearbox"); + init(argc, argv); + + glutDisplayFunc(draw); + glutReshapeFunc(reshape); + glutKeyboardFunc(key); + glutSpecialFunc(special); + glutVisibilityFunc(visible); + + glutMainLoop(); + return 0; /* ANSI C requires main to return int. */ +} |