#include #include #include #include #include #include #include "trackball.h" #define MaxVertices 400000 #define MaxFaces 400000 #define MaxGroups 100 float vertex[MaxVertices*3]; float normal[MaxVertices*3]; unsigned int face[MaxFaces*3]; char group_name[MaxGroups][80]; int start_face[MaxGroups]; int vertices = 0; int faces = 0; int groups = 0; GLuint program; static const GLchar * vertex_shader[] ={"\ varying vec3 normal, lightDir;\ uniform mat4 RotationMatrix; \ uniform float Zoom;\ void main()\ { \ lightDir=normalize(vec3(gl_LightSource[0].position));\ vec4 n = RotationMatrix*vec4(gl_NormalMatrix*gl_Normal, 1);\ normal = normalize(n.xyz); \ vec3 position = gl_Vertex.xyz+vec3(-0.75, 0, -0.7); \ gl_Position = gl_ProjectionMatrix * RotationMatrix \ * gl_ModelViewMatrix*vec4(Zoom*position, 1.0); \ }"}; static const GLchar * fragment_shader[] ={"\ /* simple toon fragment shader */\ /* www.lighthouse3d.com */\ \ varying vec3 normal, lightDir;\ \ void main()\ {\ float intensity;\ vec3 n;\ vec4 color;\ \ n = normalize(normal);\ intensity = abs(dot(lightDir,n)); \ if (intensity > 0.98)\ color = vec4(0.8,0.8,0.8,1.0);\ else if (intensity > 0.5)\ color = vec4(0.4,0.4,0.8,1.0);\ else if (intensity > 0.25)\ color = vec4(0.2,0.2,0.4,1.0);\ else\ color = vec4(0.1,0.1,0.1,1.0);\ gl_FragColor = color; \ }"}; void active_vertex_shader_inputs(GLuint prog) { char *name; GLint active_attribs, max_length; unsigned i; glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &active_attribs); glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_length); name = malloc(max_length + 1); printf("Active vertex shader inputs:\n"); for (i = 0; i < active_attribs; i++) { GLint size; GLenum type; glGetActiveAttrib(prog, i, max_length + 1, NULL, &size, &type, name); printf("Vertex input attribute %s of type %d is at location %d\n", name, type, glGetAttribLocation(prog, name)); } free(name); } void create_shaders() { GLuint v, f; v = glCreateShader(GL_VERTEX_SHADER); f = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(v, 1, vertex_shader, NULL); glShaderSource(f, 1, fragment_shader, NULL); glCompileShader(v); GLint compiled; glGetShaderiv(v, GL_COMPILE_STATUS, &compiled ); if ( !compiled ) { GLsizei maxLength, length; glGetShaderiv( v, GL_INFO_LOG_LENGTH, &maxLength ); GLchar* log = malloc(sizeof(GLchar)*(maxLength+1)); glGetShaderInfoLog(v, maxLength, &length, log); printf("Vertex Shader compilation failed: %s\n", log); free(log); } glCompileShader(f); glGetShaderiv(f, GL_COMPILE_STATUS, &compiled ); if ( !compiled ) { GLsizei maxLength, length; glGetShaderiv( f, GL_INFO_LOG_LENGTH, &maxLength ); GLchar* log = malloc(sizeof(GLchar)*(maxLength+1)); glGetShaderInfoLog(f, maxLength, &length, log); printf("Fragment Shader compilation failed: %s\n", log); free(log); } program = glCreateProgram(); glAttachShader(program, f); glAttachShader(program, v); glLinkProgram(program); GLint linked; glGetProgramiv(program, GL_LINK_STATUS, &linked ); if ( !linked ) { GLsizei len; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len ); GLchar* log = malloc(sizeof(GLchar)*(len+1)); glGetProgramInfoLog(program, len, &len, log ); printf("Shader linking failed: %s\n", log); free(log); } glUseProgram(program); active_vertex_shader_inputs(program); } float lpos[4] = {0.5, 0.5, 1, 0}; GLfloat m[4][4]; // modelview rotation matrix float last[4], cur[4]; // rotation tracking quaternions int width, height, beginx, beginy; float p1x, p1y, p2x, p2y; float zoom = 1.0; void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0, GL_POSITION, lpos); GLuint location = glGetUniformLocation(program, "RotationMatrix"); build_rotmatrix(m, cur); if( location >= 0 ) glUniformMatrix4fv(location, 1, GL_FALSE, &m[0][0]); location = glGetUniformLocation(program, "Zoom"); if (location >= 0) glUniform1f(location, zoom); //glutSolidTeapot(0.6); glNormalPointer(GL_FLOAT, 0, normal); glVertexPointer(3, GL_FLOAT, 0, vertex); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glDrawElements(GL_TRIANGLES, faces*3, GL_UNSIGNED_INT, face); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glutSwapBuffers(); } void reshape (int w, int h) { double l = 1; width=w; height=h; glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); glOrtho(-l, l, -l, l, -l, l); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keys(unsigned char key, int x, int y) { if (key == 27 || key == 'q') exit(0); } void mouse(int button,int state, int x, int y) { beginx = x; beginy = y; if (button == 3 && state == GLUT_DOWN) { zoom *= 1.1; glutPostRedisplay(); } else if (button == 4 && state == GLUT_DOWN) { zoom /= 1.1; glutPostRedisplay(); } } void motion(int x,int y) { p1x = (2.0*beginx - width)/width; p1y = (height - 2.0*beginy)/height; p2x = (2.0 * x - width) / width; p2y = (height - 2.0 * y) / height; trackball(last, p1x, p1y, p2x, p2y); add_quats(last, cur, cur); beginx = x; beginy = y; glutPostRedisplay(); } // http://www.opengl.org/wiki/Calculating_a_Surface_Normal void calculate_normals() { int i, j; for(i = 0; i < vertices*3; ++i) normal[i] = 0.0; for(j = 0; j < groups; ++j) if(!strstr(group_name[j], "shadow")) for(i = start_face[j]; i < start_face[j+1]; ++i) { int p1 = face[i*3]*3; int p2 = face[i*3+1]*3; int p3 = face[i*3+2]*3; float ux = vertex[p3]-vertex[p1]; float uy = vertex[p3+1]-vertex[p1+1]; float uz = vertex[p3+2]-vertex[p1+2]; float vx = vertex[p2]-vertex[p1]; float vy = vertex[p2+1]-vertex[p1+1]; float vz = vertex[p2+2]-vertex[p1+2]; float nx = uy*vz - uz*vy; float ny = uz*vx - ux*vz; float nz = ux*vy - uy*vx; float length = sqrt(nx*nx+ny*ny+nz*nz); normal[p1] += nx/length; normal[p1+1] += ny/length; normal[p1+2] += nz/length; normal[p2] += nx/length; normal[p2+1] += ny/length; normal[p2+2] += nz/length; normal[p3] += nx/length; normal[p3+1] += ny/length; normal[p3+2] += nz/length; } } void read_wavefront(const char *filename) { char line[80]; FILE *f = fopen(filename, "r"); while(fgets(line, sizeof(line), f)) switch(line[0]) { case 'v': sscanf(&line[1], "%f %f %f", &vertex[vertices*3], &vertex[vertices*3+1], &vertex[vertices*3+2]); ++vertices; break; case 'g': sscanf(&line[1], "%s", group_name[groups]); start_face[groups++] = faces; break; case 'f': sscanf(&line[1], "%d %d %d", &face[faces*3], &face[faces*3+1], &face[faces*3+2]); --face[faces*3]; --face[faces*3+1]; --face[faces*3+2]; ++faces; break; } fclose(f); start_face[groups] = faces; printf("Read %d vertices and %d faces within %d groups from %s\n", vertices, faces, groups, filename); } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(512, 512); glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-512)/2, (glutGet(GLUT_SCREEN_HEIGHT)-512)/2); glutCreateWindow("Use mouse to rotate"); trackball(cur, 0.0, 0.0, 0.0, 0.0); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(keys); glEnable(GL_DEPTH_TEST); glClearColor(1.0,1.0,1.0,1.0); glewInit(); if (!glewIsSupported("GL_VERSION_2_0")) { printf("GLSL not supported\n"); exit(EXIT_FAILURE); } read_wavefront("motorBike.obj"); calculate_normals(); create_shaders(); glutMainLoop(); return EXIT_SUCCESS; }