1 | #include <stdio.h> |
---|
2 | #include <stdlib.h> |
---|
3 | #include <string.h> |
---|
4 | #include <math.h> |
---|
5 | |
---|
6 | #include <GL/glew.h> |
---|
7 | #include <GL/glut.h> |
---|
8 | #include "trackball.h" |
---|
9 | |
---|
10 | #define MaxVertices 400000 |
---|
11 | #define MaxFaces 400000 |
---|
12 | #define MaxGroups 100 |
---|
13 | |
---|
14 | float vertex[MaxVertices*3]; |
---|
15 | float normal[MaxVertices*3]; |
---|
16 | unsigned int face[MaxFaces*3]; |
---|
17 | char group_name[MaxGroups][80]; |
---|
18 | int start_face[MaxGroups]; |
---|
19 | |
---|
20 | int vertices = 0; |
---|
21 | int faces = 0; |
---|
22 | int groups = 0; |
---|
23 | |
---|
24 | |
---|
25 | GLuint program; |
---|
26 | |
---|
27 | static const GLchar * vertex_shader[] ={"\ |
---|
28 | varying vec3 normal, lightDir;\ |
---|
29 | uniform mat4 RotationMatrix; \ |
---|
30 | uniform float Zoom;\ |
---|
31 | void main()\ |
---|
32 | { \ |
---|
33 | lightDir=normalize(vec3(gl_LightSource[0].position));\ |
---|
34 | vec4 n = RotationMatrix*vec4(gl_NormalMatrix*gl_Normal, 1);\ |
---|
35 | normal = normalize(n.xyz); \ |
---|
36 | vec3 position = gl_Vertex.xyz+vec3(-0.75, 0, -0.7); \ |
---|
37 | gl_Position = gl_ProjectionMatrix * RotationMatrix \ |
---|
38 | * gl_ModelViewMatrix*vec4(Zoom*position, 1.0); \ |
---|
39 | }"}; |
---|
40 | |
---|
41 | static const GLchar * fragment_shader[] ={"\ |
---|
42 | /* simple toon fragment shader */\ |
---|
43 | /* www.lighthouse3d.com */\ |
---|
44 | \ |
---|
45 | varying vec3 normal, lightDir;\ |
---|
46 | \ |
---|
47 | void main()\ |
---|
48 | {\ |
---|
49 | float intensity;\ |
---|
50 | vec3 n;\ |
---|
51 | vec4 color;\ |
---|
52 | \ |
---|
53 | n = normalize(normal);\ |
---|
54 | intensity = abs(dot(lightDir,n)); \ |
---|
55 | if (intensity > 0.98)\ |
---|
56 | color = vec4(0.8,0.8,0.8,1.0);\ |
---|
57 | else if (intensity > 0.5)\ |
---|
58 | color = vec4(0.4,0.4,0.8,1.0);\ |
---|
59 | else if (intensity > 0.25)\ |
---|
60 | color = vec4(0.2,0.2,0.4,1.0);\ |
---|
61 | else\ |
---|
62 | color = vec4(0.1,0.1,0.1,1.0);\ |
---|
63 | gl_FragColor = color; \ |
---|
64 | }"}; |
---|
65 | |
---|
66 | |
---|
67 | void active_vertex_shader_inputs(GLuint prog) |
---|
68 | { |
---|
69 | char *name; |
---|
70 | GLint active_attribs, max_length; |
---|
71 | unsigned i; |
---|
72 | |
---|
73 | glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &active_attribs); |
---|
74 | glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_length); |
---|
75 | |
---|
76 | name = malloc(max_length + 1); |
---|
77 | printf("Active vertex shader inputs:\n"); |
---|
78 | for (i = 0; i < active_attribs; i++) { |
---|
79 | GLint size; |
---|
80 | GLenum type; |
---|
81 | |
---|
82 | glGetActiveAttrib(prog, i, max_length + 1, NULL, |
---|
83 | &size, &type, name); |
---|
84 | printf("Vertex input attribute %s of type %d is at location %d\n", |
---|
85 | name, type, glGetAttribLocation(prog, name)); |
---|
86 | } |
---|
87 | free(name); |
---|
88 | } |
---|
89 | |
---|
90 | void create_shaders() |
---|
91 | { |
---|
92 | GLuint v, f; |
---|
93 | |
---|
94 | v = glCreateShader(GL_VERTEX_SHADER); |
---|
95 | f = glCreateShader(GL_FRAGMENT_SHADER); |
---|
96 | glShaderSource(v, 1, vertex_shader, NULL); |
---|
97 | glShaderSource(f, 1, fragment_shader, NULL); |
---|
98 | glCompileShader(v); |
---|
99 | GLint compiled; |
---|
100 | glGetShaderiv(v, GL_COMPILE_STATUS, &compiled ); |
---|
101 | if ( !compiled ) { |
---|
102 | GLsizei maxLength, length; |
---|
103 | glGetShaderiv( v, GL_INFO_LOG_LENGTH, &maxLength ); |
---|
104 | GLchar* log = malloc(sizeof(GLchar)*(maxLength+1)); |
---|
105 | glGetShaderInfoLog(v, maxLength, &length, log); |
---|
106 | printf("Vertex Shader compilation failed: %s\n", log); |
---|
107 | free(log); |
---|
108 | } |
---|
109 | glCompileShader(f); |
---|
110 | glGetShaderiv(f, GL_COMPILE_STATUS, &compiled ); |
---|
111 | if ( !compiled ) { |
---|
112 | GLsizei maxLength, length; |
---|
113 | glGetShaderiv( f, GL_INFO_LOG_LENGTH, &maxLength ); |
---|
114 | GLchar* log = malloc(sizeof(GLchar)*(maxLength+1)); |
---|
115 | glGetShaderInfoLog(f, maxLength, &length, log); |
---|
116 | printf("Fragment Shader compilation failed: %s\n", log); |
---|
117 | free(log); |
---|
118 | } |
---|
119 | program = glCreateProgram(); |
---|
120 | glAttachShader(program, f); |
---|
121 | glAttachShader(program, v); |
---|
122 | glLinkProgram(program); |
---|
123 | GLint linked; |
---|
124 | glGetProgramiv(program, GL_LINK_STATUS, &linked ); |
---|
125 | if ( !linked ) { |
---|
126 | GLsizei len; |
---|
127 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len ); |
---|
128 | GLchar* log = malloc(sizeof(GLchar)*(len+1)); |
---|
129 | glGetProgramInfoLog(program, len, &len, log ); |
---|
130 | printf("Shader linking failed: %s\n", log); |
---|
131 | free(log); |
---|
132 | } |
---|
133 | glUseProgram(program); |
---|
134 | active_vertex_shader_inputs(program); |
---|
135 | } |
---|
136 | |
---|
137 | float lpos[4] = {0.5, 0.5, 1, 0}; |
---|
138 | GLfloat m[4][4]; // modelview rotation matrix |
---|
139 | float last[4], cur[4]; // rotation tracking quaternions |
---|
140 | int width, height, beginx, beginy; |
---|
141 | float p1x, p1y, p2x, p2y; |
---|
142 | float zoom = 1.0; |
---|
143 | |
---|
144 | void display(void) |
---|
145 | { |
---|
146 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
---|
147 | glLightfv(GL_LIGHT0, GL_POSITION, lpos); |
---|
148 | GLuint location = glGetUniformLocation(program, "RotationMatrix"); |
---|
149 | build_rotmatrix(m, cur); |
---|
150 | if( location >= 0 ) |
---|
151 | glUniformMatrix4fv(location, 1, GL_FALSE, &m[0][0]); |
---|
152 | location = glGetUniformLocation(program, "Zoom"); |
---|
153 | if (location >= 0) glUniform1f(location, zoom); |
---|
154 | |
---|
155 | //glutSolidTeapot(0.6); |
---|
156 | glNormalPointer(GL_FLOAT, 0, normal); |
---|
157 | glVertexPointer(3, GL_FLOAT, 0, vertex); |
---|
158 | glEnableClientState(GL_VERTEX_ARRAY); |
---|
159 | glEnableClientState(GL_NORMAL_ARRAY); |
---|
160 | glDrawElements(GL_TRIANGLES, faces*3, GL_UNSIGNED_INT, face); |
---|
161 | glDisableClientState(GL_VERTEX_ARRAY); |
---|
162 | glDisableClientState(GL_NORMAL_ARRAY); |
---|
163 | |
---|
164 | glutSwapBuffers(); |
---|
165 | } |
---|
166 | |
---|
167 | void reshape (int w, int h) |
---|
168 | { |
---|
169 | double l = 1; |
---|
170 | width=w; height=h; |
---|
171 | glViewport (0, 0, w, h); |
---|
172 | glMatrixMode (GL_PROJECTION); |
---|
173 | glLoadIdentity(); |
---|
174 | glOrtho(-l, l, -l, l, -l, l); |
---|
175 | glMatrixMode(GL_MODELVIEW); |
---|
176 | glLoadIdentity(); |
---|
177 | } |
---|
178 | |
---|
179 | void keys(unsigned char key, int x, int y) |
---|
180 | { |
---|
181 | if (key == 27 || key == 'q') |
---|
182 | exit(0); |
---|
183 | } |
---|
184 | |
---|
185 | void mouse(int button,int state, int x, int y) |
---|
186 | { |
---|
187 | beginx = x; |
---|
188 | beginy = y; |
---|
189 | if (button == 3 && state == GLUT_DOWN) |
---|
190 | { zoom *= 1.1; glutPostRedisplay(); } |
---|
191 | else if (button == 4 && state == GLUT_DOWN) |
---|
192 | { zoom /= 1.1; glutPostRedisplay(); } |
---|
193 | } |
---|
194 | |
---|
195 | void motion(int x,int y) |
---|
196 | { |
---|
197 | p1x = (2.0*beginx - width)/width; |
---|
198 | p1y = (height - 2.0*beginy)/height; |
---|
199 | p2x = (2.0 * x - width) / width; |
---|
200 | p2y = (height - 2.0 * y) / height; |
---|
201 | trackball(last, p1x, p1y, p2x, p2y); |
---|
202 | add_quats(last, cur, cur); |
---|
203 | beginx = x; |
---|
204 | beginy = y; |
---|
205 | glutPostRedisplay(); |
---|
206 | } |
---|
207 | |
---|
208 | // http://www.opengl.org/wiki/Calculating_a_Surface_Normal |
---|
209 | void calculate_normals() |
---|
210 | { |
---|
211 | int i, j; |
---|
212 | for(i = 0; i < vertices*3; ++i) |
---|
213 | normal[i] = 0.0; |
---|
214 | for(j = 0; j < groups; ++j) if(!strstr(group_name[j], "shadow")) |
---|
215 | for(i = start_face[j]; i < start_face[j+1]; ++i) |
---|
216 | { |
---|
217 | int p1 = face[i*3]*3; |
---|
218 | int p2 = face[i*3+1]*3; |
---|
219 | int p3 = face[i*3+2]*3; |
---|
220 | float ux = vertex[p3]-vertex[p1]; |
---|
221 | float uy = vertex[p3+1]-vertex[p1+1]; |
---|
222 | float uz = vertex[p3+2]-vertex[p1+2]; |
---|
223 | float vx = vertex[p2]-vertex[p1]; |
---|
224 | float vy = vertex[p2+1]-vertex[p1+1]; |
---|
225 | float vz = vertex[p2+2]-vertex[p1+2]; |
---|
226 | float nx = uy*vz - uz*vy; |
---|
227 | float ny = uz*vx - ux*vz; |
---|
228 | float nz = ux*vy - uy*vx; |
---|
229 | float length = sqrt(nx*nx+ny*ny+nz*nz); |
---|
230 | normal[p1] += nx/length; |
---|
231 | normal[p1+1] += ny/length; |
---|
232 | normal[p1+2] += nz/length; |
---|
233 | normal[p2] += nx/length; |
---|
234 | normal[p2+1] += ny/length; |
---|
235 | normal[p2+2] += nz/length; |
---|
236 | normal[p3] += nx/length; |
---|
237 | normal[p3+1] += ny/length; |
---|
238 | normal[p3+2] += nz/length; |
---|
239 | } |
---|
240 | } |
---|
241 | |
---|
242 | void read_wavefront(const char *filename) |
---|
243 | { |
---|
244 | char line[80]; |
---|
245 | FILE *f = fopen(filename, "r"); |
---|
246 | while(fgets(line, sizeof(line), f)) |
---|
247 | switch(line[0]) |
---|
248 | { |
---|
249 | case 'v': |
---|
250 | sscanf(&line[1], "%f %f %f", &vertex[vertices*3], |
---|
251 | &vertex[vertices*3+1], &vertex[vertices*3+2]); |
---|
252 | ++vertices; |
---|
253 | break; |
---|
254 | case 'g': |
---|
255 | sscanf(&line[1], "%s", group_name[groups]); |
---|
256 | start_face[groups++] = faces; |
---|
257 | break; |
---|
258 | case 'f': |
---|
259 | sscanf(&line[1], "%d %d %d", &face[faces*3], |
---|
260 | &face[faces*3+1], &face[faces*3+2]); |
---|
261 | --face[faces*3]; --face[faces*3+1]; |
---|
262 | --face[faces*3+2]; ++faces; |
---|
263 | break; |
---|
264 | } |
---|
265 | fclose(f); |
---|
266 | start_face[groups] = faces; |
---|
267 | printf("Read %d vertices and %d faces within %d groups from %s\n", |
---|
268 | vertices, faces, groups, filename); |
---|
269 | } |
---|
270 | |
---|
271 | int main(int argc, char **argv) |
---|
272 | { |
---|
273 | glutInit(&argc, argv); |
---|
274 | glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); |
---|
275 | glutInitWindowSize(512, 512); |
---|
276 | glutInitWindowPosition((glutGet(GLUT_SCREEN_WIDTH)-512)/2, |
---|
277 | (glutGet(GLUT_SCREEN_HEIGHT)-512)/2); |
---|
278 | glutCreateWindow("Use mouse to rotate"); |
---|
279 | |
---|
280 | trackball(cur, 0.0, 0.0, 0.0, 0.0); |
---|
281 | |
---|
282 | glutDisplayFunc(display); |
---|
283 | glutReshapeFunc(reshape); |
---|
284 | glutMouseFunc(mouse); |
---|
285 | glutMotionFunc(motion); |
---|
286 | glutKeyboardFunc(keys); |
---|
287 | |
---|
288 | glEnable(GL_DEPTH_TEST); |
---|
289 | glClearColor(1.0,1.0,1.0,1.0); |
---|
290 | glewInit(); |
---|
291 | if (!glewIsSupported("GL_VERSION_2_0")) |
---|
292 | { |
---|
293 | printf("GLSL not supported\n"); |
---|
294 | exit(EXIT_FAILURE); |
---|
295 | } |
---|
296 | read_wavefront("motorBike.obj"); |
---|
297 | calculate_normals(); |
---|
298 | create_shaders(); |
---|
299 | glutMainLoop(); |
---|
300 | return EXIT_SUCCESS; |
---|
301 | } |
---|