| 327 | |
| 328 | |
| 329 | == Interactivity == |
| 330 | [[Image(teapot.png,right)]] |
| 331 | |
| 332 | Assemble the following Utah teapot model and attached virtual [attachment:trackball.h] and [attachment:trackball.c] sources from SGI. We use |
| 333 | {{{ |
| 334 | #!c |
| 335 | #include <stdio.h> |
| 336 | #include <stdlib.h> |
| 337 | #include <string.h> |
| 338 | |
| 339 | #include <GL/glew.h> |
| 340 | #include <GL/glut.h> |
| 341 | #include "trackball.h" |
| 342 | |
| 343 | GLuint p; // program needs to be global! |
| 344 | float lpos[4] = {1, 0.5, 1, 0}; |
| 345 | GLfloat m[4][4]; // modelview rotation matrix |
| 346 | float last[4], cur[4]; // rotation tracking quaternions |
| 347 | int width, height, beginx, beginy; |
| 348 | float p1x, p1y, p2x, p2y; |
| 349 | |
| 350 | void display(void) { |
| 351 | GLuint location = glGetUniformLocation(p, "RotationMatrix"); |
| 352 | build_rotmatrix(m, cur); |
| 353 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 354 | glLightfv(GL_LIGHT0, GL_POSITION, lpos); |
| 355 | if( location >= 0 ) |
| 356 | glUniformMatrix4fv(location, 1, GL_FALSE, &m[0][0]); |
| 357 | glutSolidTeapot(0.6); |
| 358 | glutSwapBuffers(); |
| 359 | } |
| 360 | |
| 361 | |
| 362 | void processNormalKeys(unsigned char key, int x, int y) { |
| 363 | if (key == 27) |
| 364 | exit(0); |
| 365 | } |
| 366 | |
| 367 | void mouse(int button,int state, int x, int y) |
| 368 | { |
| 369 | beginx = x; |
| 370 | beginy = y; |
| 371 | } |
| 372 | |
| 373 | void motion(int x,int y) |
| 374 | { |
| 375 | p1x = (2.0*beginx - width)/width; |
| 376 | p1y = (height - 2.0*beginy)/height; |
| 377 | p2x = (2.0 * x - width) / width; |
| 378 | p2y = (height - 2.0 * y) / height; |
| 379 | trackball(last, p1x, p1y, p2x, p2y); |
| 380 | add_quats(last, cur, cur); |
| 381 | beginx = x; |
| 382 | beginy = y; |
| 383 | glutPostRedisplay(); |
| 384 | } |
| 385 | |
| 386 | void reshape (int w, int h) |
| 387 | { |
| 388 | double l = 1; |
| 389 | width=w; height=h; |
| 390 | glViewport (0, 0, w, h); |
| 391 | glMatrixMode (GL_PROJECTION); |
| 392 | glLoadIdentity(); |
| 393 | glOrtho(-l, l, -l, l, -l, l); |
| 394 | glMatrixMode(GL_MODELVIEW); |
| 395 | glLoadIdentity(); |
| 396 | } |
| 397 | |
| 398 | static const GLchar * vertex_shader[] ={"\ |
| 399 | varying vec3 normal, lightDir;\ |
| 400 | uniform mat4 RotationMatrix;\ |
| 401 | void main()\ |
| 402 | { \ |
| 403 | lightDir=normalize(vec3(gl_LightSource[0].position));\ |
| 404 | normal=normalize(gl_NormalMatrix*gl_Normal);\ |
| 405 | gl_Position = gl_ProjectionMatrix * \ |
| 406 | RotationMatrix*gl_ModelViewMatrix*gl_Vertex;\ |
| 407 | }"}; |
| 408 | |
| 409 | static const GLchar * fragment_shader[] ={"\ |
| 410 | /* simple toon fragment shader */\ |
| 411 | /* www.lighthouse3d.com */\ |
| 412 | \ |
| 413 | varying vec3 normal, lightDir;\ |
| 414 | \ |
| 415 | void main()\ |
| 416 | {\ |
| 417 | float intensity;\ |
| 418 | vec3 n;\ |
| 419 | vec4 color;\ |
| 420 | \ |
| 421 | n = normalize(normal);\ |
| 422 | intensity = max(dot(lightDir,n),0.0);\ |
| 423 | if (intensity > 0.98)\ |
| 424 | color = vec4(0.8,0.8,0.8,1.0);\ |
| 425 | else if (intensity > 0.5)\ |
| 426 | color = vec4(0.4,0.4,0.8,1.0);\ |
| 427 | else if (intensity > 0.25)\ |
| 428 | color = vec4(0.2,0.2,0.4,1.0);\ |
| 429 | else\ |
| 430 | color = vec4(0.1,0.1,0.1,1.0);\ |
| 431 | gl_FragColor = color;\ |
| 432 | }"}; |
| 433 | |
| 434 | void setShaders() |
| 435 | { |
| 436 | GLuint v, f; |
| 437 | |
| 438 | v = glCreateShader(GL_VERTEX_SHADER); |
| 439 | f = glCreateShader(GL_FRAGMENT_SHADER); |
| 440 | glShaderSource(v, 1, vertex_shader, NULL); |
| 441 | glShaderSource(f, 1, fragment_shader, NULL); |
| 442 | glCompileShader(v); |
| 443 | glCompileShader(f); |
| 444 | p = glCreateProgram(); |
| 445 | glAttachShader(p,f); |
| 446 | glAttachShader(p,v); |
| 447 | glLinkProgram(p); |
| 448 | glUseProgram(p); |
| 449 | } |
| 450 | |
| 451 | int main(int argc, char **argv) |
| 452 | { |
| 453 | glutInit(&argc, argv); |
| 454 | glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); |
| 455 | glutInitWindowSize(512, 512); |
| 456 | glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-512)/2, |
| 457 | (glutGet(GLUT_SCREEN_HEIGHT)-512)/2); |
| 458 | glutCreateWindow("Use mouse to rotate"); |