1/* 2 * Use glCopyTexSubImage2D to draw animated gears on the sides of a box. 3 * 4 * Brian Paul 5 * 27 January 2006 6 */ 7 8#include <math.h> 9#include <stdlib.h> 10#include <stdio.h> 11#include <string.h> 12#include "glut_wrap.h" 13 14#ifndef M_PI 15#define M_PI 3.14159265 16#endif 17 18static GLint WinWidth = 800, WinHeight = 500; 19static GLint TexWidth, TexHeight; 20static GLuint TexObj = 1; 21static GLenum IntFormat = GL_RGB; 22 23static GLboolean WireFrame = GL_FALSE; 24 25static GLint T0 = 0; 26static GLint Frames = 0; 27static GLint Win = 0; 28 29static GLfloat ViewRotX = 20.0, ViewRotY = 30.0, ViewRotZ = 0.0; 30static GLint Gear1, Gear2, Gear3; 31static GLfloat GearRot = 0.0; 32static GLfloat CubeRot = 0.0; 33 34 35/** 36 Draw a gear wheel. You'll probably want to call this function when 37 building a display list since we do a lot of trig here. 38 39 Input: inner_radius - radius of hole at center 40 outer_radius - radius at center of teeth 41 width - width of gear 42 teeth - number of teeth 43 tooth_depth - depth of tooth 44 **/ 45static void 46gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, 47 GLint teeth, GLfloat tooth_depth) 48{ 49 GLint i; 50 GLfloat r0, r1, r2; 51 GLfloat angle, da; 52 GLfloat u, v, len; 53 54 r0 = inner_radius; 55 r1 = outer_radius - tooth_depth / 2.0; 56 r2 = outer_radius + tooth_depth / 2.0; 57 58 da = 2.0 * M_PI / teeth / 4.0; 59 60 glShadeModel(GL_FLAT); 61 62 glNormal3f(0.0, 0.0, 1.0); 63 64 /* draw front face */ 65 glBegin(GL_QUAD_STRIP); 66 for (i = 0; i <= teeth; i++) { 67 angle = i * 2.0 * M_PI / teeth; 68 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 69 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 70 if (i < teeth) { 71 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 72 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); 73 } 74 } 75 glEnd(); 76 77 /* draw front sides of teeth */ 78 glBegin(GL_QUADS); 79 da = 2.0 * M_PI / teeth / 4.0; 80 for (i = 0; i < teeth; i++) { 81 angle = i * 2.0 * M_PI / teeth; 82 83 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 84 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); 85 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); 86 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); 87 } 88 glEnd(); 89 90 glNormal3f(0.0, 0.0, -1.0); 91 92 /* draw back face */ 93 glBegin(GL_QUAD_STRIP); 94 for (i = 0; i <= teeth; i++) { 95 angle = i * 2.0 * M_PI / teeth; 96 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 97 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 98 if (i < teeth) { 99 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); 100 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 101 } 102 } 103 glEnd(); 104 105 /* draw back sides of teeth */ 106 glBegin(GL_QUADS); 107 da = 2.0 * M_PI / teeth / 4.0; 108 for (i = 0; i < teeth; i++) { 109 angle = i * 2.0 * M_PI / teeth; 110 111 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); 112 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); 113 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); 114 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 115 } 116 glEnd(); 117 118 /* draw outward faces of teeth */ 119 glBegin(GL_QUAD_STRIP); 120 for (i = 0; i < teeth; i++) { 121 angle = i * 2.0 * M_PI / teeth; 122 123 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); 124 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); 125 u = r2 * cos(angle + da) - r1 * cos(angle); 126 v = r2 * sin(angle + da) - r1 * sin(angle); 127 len = sqrt(u * u + v * v); 128 u /= len; 129 v /= len; 130 glNormal3f(v, -u, 0.0); 131 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); 132 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); 133 glNormal3f(cos(angle), sin(angle), 0.0); 134 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); 135 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); 136 u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); 137 v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); 138 glNormal3f(v, -u, 0.0); 139 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); 140 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); 141 glNormal3f(cos(angle), sin(angle), 0.0); 142 } 143 144 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); 145 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); 146 147 glEnd(); 148 149 glShadeModel(GL_SMOOTH); 150 151 /* draw inside radius cylinder */ 152 glBegin(GL_QUAD_STRIP); 153 for (i = 0; i <= teeth; i++) { 154 angle = i * 2.0 * M_PI / teeth; 155 glNormal3f(-cos(angle), -sin(angle), 0.0); 156 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); 157 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); 158 } 159 glEnd(); 160 161} 162 163static void 164cleanup(void) 165{ 166 glDeleteTextures(1, &TexObj); 167 glDeleteLists(Gear1, 1); 168 glDeleteLists(Gear2, 1); 169 glDeleteLists(Gear3, 1); 170 glutDestroyWindow(Win); 171} 172 173 174static void 175DrawGears(void) 176{ 177 if (WireFrame) { 178 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 179 } 180 181 glPushMatrix(); 182 glRotatef(20/*ViewRotX*/, 1.0, 0.0, 0.0); 183 glRotatef(ViewRotY, 0.0, 1.0, 0.0); 184 glRotatef(ViewRotZ, 0.0, 0.0, 1.0); 185 186 glPushMatrix(); 187 glTranslatef(-3.0, -2.0, 0.0); 188 glRotatef(GearRot, 0.0, 0.0, 1.0); 189 glCallList(Gear1); 190 glPopMatrix(); 191 192 glPushMatrix(); 193 glTranslatef(3.1, -2.0, 0.0); 194 glRotatef(-2.0 * GearRot - 9.0, 0.0, 0.0, 1.0); 195 glCallList(Gear2); 196 glPopMatrix(); 197 198 glPushMatrix(); 199 glTranslatef(-3.1, 4.2, 0.0); 200 glRotatef(-2.0 * GearRot - 25.0, 0.0, 0.0, 1.0); 201 glCallList(Gear3); 202 glPopMatrix(); 203 204 glPopMatrix(); 205 206 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 207} 208 209 210static void 211DrawCube(void) 212{ 213 static const GLfloat texcoords[4][2] = { 214 { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } 215 }; 216 static const GLfloat vertices[4][2] = { 217 { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } 218 }; 219 static const GLfloat xforms[6][4] = { 220 { 0, 0, 1, 0 }, 221 { 90, 0, 1, 0 }, 222 { 180, 0, 1, 0 }, 223 { 270, 0, 1, 0 }, 224 { 90, 1, 0, 0 }, 225 { -90, 1, 0, 0 } 226 }; 227 static const GLfloat mat[4] = { 1.0, 1.0, 0.5, 1.0 }; 228 GLint i, j; 229 230 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat); 231 glEnable(GL_TEXTURE_2D); 232 233 glPushMatrix(); 234 glRotatef(ViewRotX, 1.0, 0.0, 0.0); 235 glRotatef(15, 1, 0, 0); 236 glRotatef(CubeRot, 0, 1, 0); 237 glScalef(4, 4, 4); 238 239 for (i = 0; i < 6; i++) { 240 glPushMatrix(); 241 glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]); 242 glTranslatef(0, 0, 1.1); 243 glBegin(GL_POLYGON); 244 glNormal3f(0, 0, 1); 245 for (j = 0; j < 4; j++) { 246 glTexCoord2fv(texcoords[j]); 247 glVertex2fv(vertices[j]); 248 } 249 glEnd(); 250 glPopMatrix(); 251 } 252 glPopMatrix(); 253 254 glDisable(GL_TEXTURE_2D); 255} 256 257 258static void 259draw(void) 260{ 261 float ar; 262 263 glMatrixMode(GL_MODELVIEW); 264 glLoadIdentity(); 265 glTranslatef(0.0, 0.0, -40.0); 266 267 /* clear whole depth buffer */ 268 glDisable(GL_SCISSOR_TEST); 269 glClear(GL_DEPTH_BUFFER_BIT); 270 glEnable(GL_SCISSOR_TEST); 271 272 /* clear upper-left corner of color buffer (unused space) */ 273 glScissor(0, TexHeight, TexWidth, WinHeight - TexHeight); 274 glClearColor(0.0, 0.0, 0.0, 0.0); 275 glClear(GL_COLOR_BUFFER_BIT); 276 277 /* clear lower-left corner of color buffer */ 278 glViewport(0, 0, TexWidth, TexHeight); 279 glScissor(0, 0, TexWidth, TexHeight); 280 glClearColor(1, 1, 1, 0); 281 glClear(GL_COLOR_BUFFER_BIT); 282 283 /* draw gears in lower-left corner */ 284 glMatrixMode(GL_PROJECTION); 285 glLoadIdentity(); 286 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 60.0); 287 glMatrixMode(GL_MODELVIEW); 288 DrawGears(); 289 290 /* copy color buffer to texture */ 291 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, TexWidth, TexHeight); 292 293 /* clear right half of color buffer */ 294 glViewport(TexWidth, 0, WinWidth - TexWidth, WinHeight); 295 glScissor(TexWidth, 0, WinWidth - TexWidth, WinHeight); 296 glClearColor(0.5, 0.5, 0.8, 0.0); 297 glClear(GL_COLOR_BUFFER_BIT); 298 299 /* draw textured cube in right half of window */ 300 ar = (float) (WinWidth - TexWidth) / WinHeight; 301 glMatrixMode(GL_PROJECTION); 302 glLoadIdentity(); 303 glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0); 304 glMatrixMode(GL_MODELVIEW); 305 DrawCube(); 306 307 /* finish up */ 308 glutSwapBuffers(); 309 310 Frames++; 311 { 312 GLint t = glutGet(GLUT_ELAPSED_TIME); 313 if (t - T0 >= 5000) { 314 GLfloat seconds = (t - T0) / 1000.0; 315 GLfloat fps = Frames / seconds; 316 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps); 317 fflush(stdout); 318 T0 = t; 319 Frames = 0; 320 } 321 } 322} 323 324 325static void 326idle(void) 327{ 328 static double t0 = -1.; 329 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; 330 if (t0 < 0.0) 331 t0 = t; 332 dt = t - t0; 333 t0 = t; 334 335 /* fmod to prevent overflow */ 336 GearRot = fmod(GearRot + 70.0 * dt, 360.0); /* 70 deg/sec */ 337 CubeRot = fmod(CubeRot + 15.0 * dt, 360.0); /* 15 deg/sec */ 338 339 glutPostRedisplay(); 340} 341 342 343/* change view angle, exit upon ESC */ 344static void 345key(unsigned char k, int x, int y) 346{ 347 (void) x; 348 (void) y; 349 switch (k) { 350 case 'w': 351 WireFrame = !WireFrame; 352 break; 353 case 'z': 354 ViewRotZ += 5.0; 355 break; 356 case 'Z': 357 ViewRotZ -= 5.0; 358 break; 359 case 27: /* Escape */ 360 cleanup(); 361 exit(0); 362 break; 363 default: 364 return; 365 } 366 glutPostRedisplay(); 367} 368 369/* change view angle */ 370static void 371special(int k, int x, int y) 372{ 373 (void) x; 374 (void) y; 375 switch (k) { 376 case GLUT_KEY_UP: 377 ViewRotX += 5.0; 378 break; 379 case GLUT_KEY_DOWN: 380 ViewRotX -= 5.0; 381 break; 382 case GLUT_KEY_LEFT: 383 ViewRotY += 5.0; 384 break; 385 case GLUT_KEY_RIGHT: 386 ViewRotY -= 5.0; 387 break; 388 default: 389 return; 390 } 391 glutPostRedisplay(); 392} 393 394 395/* new window size or exposure */ 396static void 397reshape(int width, int height) 398{ 399 WinWidth = width; 400 WinHeight = height; 401} 402 403 404static void 405init(int argc, char *argv[]) 406{ 407 static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0}; 408 static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0}; 409 static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0}; 410 static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0}; 411 GLint i; 412 413 glLightfv(GL_LIGHT0, GL_POSITION, pos); 414#if 0 415 glEnable(GL_CULL_FACE); 416#endif 417 glEnable(GL_LIGHTING); 418 glEnable(GL_LIGHT0); 419 glEnable(GL_DEPTH_TEST); 420 421 /* make the gears */ 422 Gear1 = glGenLists(1); 423 glNewList(Gear1, GL_COMPILE); 424 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); 425 gear(1.0, 4.0, 1.0, 20, 0.7); 426 glEndList(); 427 428 Gear2 = glGenLists(1); 429 glNewList(Gear2, GL_COMPILE); 430 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); 431 gear(0.5, 2.0, 2.0, 10, 0.7); 432 glEndList(); 433 434 Gear3 = glGenLists(1); 435 glNewList(Gear3, GL_COMPILE); 436 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); 437 gear(1.3, 2.0, 0.5, 10, 0.7); 438 glEndList(); 439 440 glEnable(GL_NORMALIZE); 441 442 /* xxx make size dynamic */ 443 TexWidth = 256; 444 TexHeight = 256; 445 446 glBindTexture(GL_TEXTURE_2D, TexObj); 447 glTexImage2D(GL_TEXTURE_2D, 0, IntFormat, TexWidth, TexHeight, 0, 448 GL_RGBA, GL_UNSIGNED_BYTE, NULL); 449 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 450 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 451 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 452 453 for ( i=1; i<argc; i++ ) { 454 if (strcmp(argv[i], "-info")==0) { 455 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 456 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION)); 457 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR)); 458 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS)); 459 } 460 } 461} 462 463 464static void 465visible(int vis) 466{ 467 if (vis == GLUT_VISIBLE) 468 glutIdleFunc(idle); 469 else 470 glutIdleFunc(NULL); 471} 472 473 474int 475main(int argc, char *argv[]) 476{ 477 glutInitWindowSize(WinWidth, WinHeight); 478 glutInit(&argc, argv); 479 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 480 481 Win = glutCreateWindow("gearbox"); 482 init(argc, argv); 483 484 glutDisplayFunc(draw); 485 glutReshapeFunc(reshape); 486 glutKeyboardFunc(key); 487 glutSpecialFunc(special); 488 glutVisibilityFunc(visible); 489 490 glutMainLoop(); 491 return 0; /* ANSI C requires main to return int. */ 492} 493