tutorial: motorbike.c

File motorbike.c, 8.0 KB (added by leon, 6 years ago)

Final motorbike source

Line 
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
14float       vertex[MaxVertices*3];
15float       normal[MaxVertices*3];
16unsigned int  face[MaxFaces*3];
17char    group_name[MaxGroups][80];
18int     start_face[MaxGroups];
19
20int vertices = 0;
21int faces    = 0;
22int groups   = 0;
23
24
25GLuint program;
26
27static const GLchar * vertex_shader[] ={"\
28varying vec3 normal, lightDir;\
29uniform mat4 RotationMatrix;  \
30uniform float Zoom;\
31void 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
41static const GLchar * fragment_shader[] ={"\
42/* simple toon fragment shader */\
43/* www.lighthouse3d.com        */\
44\
45varying vec3 normal, lightDir;\
46\
47void 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
67void 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
90void 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
137float lpos[4] = {0.5, 0.5, 1, 0};
138GLfloat m[4][4]; // modelview rotation matrix
139float last[4], cur[4]; // rotation tracking quaternions
140int width, height, beginx, beginy;
141float p1x, p1y, p2x, p2y;
142float zoom = 1.0;
143
144void 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
167void 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
179void keys(unsigned char key, int x, int y)
180{
181   if (key == 27 || key == 'q') 
182         exit(0);
183}
184
185void 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
195void 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
209void 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
242void 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
271int 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}