Use extfuncs.h helper. Added command line options for loading
[mesa.git] / progs / demos / fslight.c
1 /**
2 * Test OpenGL 2.0 vertex/fragment shaders.
3 * Brian Paul
4 * 1 November 2006
5 *
6 * Based on ARB version by:
7 * Michal Krol
8 * 20 February 2006
9 *
10 * Based on the original demo by:
11 * Brian Paul
12 * 17 April 2003
13 */
14
15 #include <assert.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <math.h>
20 #include <GL/gl.h>
21 #include <GL/glut.h>
22 #include <GL/glext.h>
23 #include "extfuncs.h"
24
25 static char *FragProgFile = NULL;
26 static char *VertProgFile = NULL;
27
28 static GLfloat diffuse[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
29 static GLfloat specular[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
30 static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 1.0f };
31 static GLfloat delta = 1.0f;
32
33 static GLuint fragShader;
34 static GLuint vertShader;
35 static GLuint program;
36
37 static GLint uLightPos;
38 static GLint uDiffuse;
39 static GLint uSpecular;
40
41 static GLint win = 0;
42 static GLboolean anim = GL_FALSE;
43 static GLboolean wire = GL_FALSE;
44 static GLboolean pixelLight = GL_TRUE;
45
46 static GLint t0 = 0;
47 static GLint frames = 0;
48
49 static GLfloat xRot = 0.0f, yRot = 0.0f;
50
51
52 static void
53 normalize(GLfloat *dst, const GLfloat *src)
54 {
55 GLfloat len = sqrtf(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
56 dst[0] = src[0] / len;
57 dst[1] = src[1] / len;
58 dst[2] = src[2] / len;
59 }
60
61
62 static void
63 Redisplay(void)
64 {
65 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
66
67 if (pixelLight) {
68 GLfloat vec[3];
69 glUseProgram_func(program);
70 normalize(vec, lightPos);
71 glUniform3fv_func(uLightPos, 1, vec);
72 glDisable(GL_LIGHTING);
73 }
74 else {
75 glUseProgram_func(0);
76 glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
77 glEnable(GL_LIGHTING);
78 }
79
80 glPushMatrix();
81 glRotatef(xRot, 1.0f, 0.0f, 0.0f);
82 glRotatef(yRot, 0.0f, 1.0f, 0.0f);
83 glutSolidSphere(2.0, 10, 5);
84 glPopMatrix();
85
86 glutSwapBuffers();
87 frames++;
88
89 if (anim) {
90 GLint t = glutGet(GLUT_ELAPSED_TIME);
91 if (t - t0 >= 5000) {
92 GLfloat seconds =(GLfloat)(t - t0) / 1000.0f;
93 GLfloat fps = frames / seconds;
94 printf("%d frames in %6.3f seconds = %6.3f FPS\n",
95 frames, seconds, fps);
96 t0 = t;
97 frames = 0;
98 }
99 }
100 }
101
102
103 static void
104 Idle(void)
105 {
106 lightPos[0] += delta;
107 if (lightPos[0] > 25.0f || lightPos[0] < -25.0f)
108 delta = -delta;
109 glutPostRedisplay();
110 }
111
112
113 static void
114 Reshape(int width, int height)
115 {
116 glViewport(0, 0, width, height);
117 glMatrixMode(GL_PROJECTION);
118 glLoadIdentity();
119 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
120 glMatrixMode(GL_MODELVIEW);
121 glLoadIdentity();
122 glTranslatef(0.0f, 0.0f, -15.0f);
123 }
124
125
126 static void
127 CleanUp(void)
128 {
129 glDeleteShader_func(fragShader);
130 glDeleteShader_func(vertShader);
131 glDeleteProgram_func(program);
132 glutDestroyWindow(win);
133 }
134
135
136 static void
137 Key(unsigned char key, int x, int y)
138 {
139 (void) x;
140 (void) y;
141
142 switch(key) {
143 case ' ':
144 case 'a':
145 anim = !anim;
146 if (anim)
147 glutIdleFunc(Idle);
148 else
149 glutIdleFunc(NULL);
150 break;
151 case 'x':
152 lightPos[0] -= 1.0f;
153 break;
154 case 'X':
155 lightPos[0] += 1.0f;
156 break;
157 case 'w':
158 wire = !wire;
159 if (wire)
160 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
161 else
162 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
163 break;
164 case 'p':
165 pixelLight = !pixelLight;
166 if (pixelLight)
167 printf("Per-pixel lighting\n");
168 else
169 printf("Conventional lighting\n");
170 break;
171 case 27:
172 CleanUp();
173 exit(0);
174 break;
175 }
176 glutPostRedisplay();
177 }
178
179
180 static void
181 SpecialKey(int key, int x, int y)
182 {
183 const GLfloat step = 3.0f;
184
185 (void) x;
186 (void) y;
187
188 switch(key) {
189 case GLUT_KEY_UP:
190 xRot -= step;
191 break;
192 case GLUT_KEY_DOWN:
193 xRot += step;
194 break;
195 case GLUT_KEY_LEFT:
196 yRot -= step;
197 break;
198 case GLUT_KEY_RIGHT:
199 yRot += step;
200 break;
201 }
202 glutPostRedisplay();
203 }
204
205
206 static void
207 TestFunctions(void)
208 {
209 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
210 {
211 GLfloat pos[3];
212 glUniform3fv_func(uLightPos, 1, lightPos);
213 glGetUniformfv_func(program, uLightPos, pos);
214 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
215 printf("Light pos %g %g %g\n", pos[0], pos[1], pos[2]);
216 }
217
218
219 {
220 GLfloat m[16], result[16];
221 GLint mPos;
222 int i;
223
224 for (i = 0; i < 16; i++)
225 m[i] = (float) i;
226
227 mPos = glGetUniformLocation_func(program, "m");
228 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
229 glUniformMatrix4fv_func(mPos, 1, GL_FALSE, m);
230 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
231
232 glGetUniformfv_func(program, mPos, result);
233 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
234
235 for (i = 0; i < 16; i++) {
236 printf("%8g %8g\n", m[i], result[i]);
237 }
238 }
239
240 assert(glIsProgram_func(program));
241 assert(glIsShader_func(fragShader));
242 assert(glIsShader_func(vertShader));
243
244 /* attached shaders */
245 {
246 GLuint shaders[20];
247 GLsizei count;
248 int i;
249 glGetAttachedShaders_func(program, 20, &count, shaders);
250 for (i = 0; i < count; i++) {
251 printf("Attached: %u\n", shaders[i]);
252 assert(shaders[i] == fragShader ||
253 shaders[i] == vertShader);
254 }
255 }
256
257 {
258 GLchar log[1000];
259 GLsizei len;
260 glGetShaderInfoLog_func(vertShader, 1000, &len, log);
261 printf("Vert Shader Info Log: %s\n", log);
262 glGetShaderInfoLog_func(fragShader, 1000, &len, log);
263 printf("Frag Shader Info Log: %s\n", log);
264 glGetProgramInfoLog_func(program, 1000, &len, log);
265 printf("Program Info Log: %s\n", log);
266 }
267 }
268
269
270 static void
271 LoadAndCompileShader(GLuint shader, const char *text)
272 {
273 GLint stat;
274
275 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
276
277 glCompileShader_func(shader);
278
279 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
280 if (!stat) {
281 GLchar log[1000];
282 GLsizei len;
283 glGetShaderInfoLog_func(shader, 1000, &len, log);
284 fprintf(stderr, "Problem compiling shader: %s\n", log);
285 exit(1);
286 }
287 }
288
289
290 /**
291 * Read a shader from a file.
292 */
293 static void
294 ReadShader(GLuint shader, const char *filename)
295 {
296 const int max = 100*1000;
297 int n;
298 char *buffer = (char*) malloc(max);
299 FILE *f = fopen(filename, "r");
300 if (!f) {
301 fprintf(stderr, "Unable to open shader file %s\n", filename);
302 exit(1);
303 }
304
305 n = fread(buffer, 1, max, f);
306 printf("Read %d bytes from shader file %s\n", n, filename);
307 if (n > 0) {
308 buffer[n] = 0;
309 LoadAndCompileShader(shader, buffer);
310 }
311
312 fclose(f);
313 free(buffer);
314 }
315
316
317 static void
318 CheckLink(GLuint prog)
319 {
320 GLint stat;
321 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
322 if (!stat) {
323 GLchar log[1000];
324 GLsizei len;
325 glGetProgramInfoLog_func(prog, 1000, &len, log);
326 fprintf(stderr, "Linker error:\n%s\n", log);
327 }
328 }
329
330
331 static void
332 Init(void)
333 {
334 static const char *fragShaderText =
335 "uniform vec3 lightPos;\n"
336 "uniform vec4 diffuse;\n"
337 "uniform vec4 specular;\n"
338 "varying vec3 normal;\n"
339 "void main() {\n"
340 " // Compute dot product of light direction and normal vector\n"
341 " float dotProd = max(dot(lightPos, normalize(normal)), 0.0);\n"
342 " // Compute diffuse and specular contributions\n"
343 " gl_FragColor = diffuse * dotProd + specular * pow(dotProd, 20.0);\n"
344 "}\n";
345 static const char *vertShaderText =
346 "varying vec3 normal;\n"
347 "void main() {\n"
348 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
349 " normal = gl_NormalMatrix * gl_Normal;\n"
350 "}\n";
351 const char *version;
352
353 version = (const char *) glGetString(GL_VERSION);
354 if (version[0] != '2' || version[1] != '.') {
355 printf("Warning: this program expects OpenGL 2.0\n");
356 /*exit(1);*/
357 }
358
359 GetExtensionFuncs();
360
361 fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
362 if (FragProgFile)
363 ReadShader(fragShader, FragProgFile);
364 else
365 LoadAndCompileShader(fragShader, fragShaderText);
366
367
368 vertShader = glCreateShader_func(GL_VERTEX_SHADER);
369 if (VertProgFile)
370 ReadShader(vertShader, VertProgFile);
371 else
372 LoadAndCompileShader(vertShader, vertShaderText);
373
374 program = glCreateProgram_func();
375 glAttachShader_func(program, fragShader);
376 glAttachShader_func(program, vertShader);
377 glLinkProgram_func(program);
378 CheckLink(program);
379 glUseProgram_func(program);
380
381 uLightPos = glGetUniformLocation_func(program, "lightPos");
382 uDiffuse = glGetUniformLocation_func(program, "diffuse");
383 uSpecular = glGetUniformLocation_func(program, "specular");
384 printf("LightPos %d DiffusePos %d SpecularPos %d\n",
385 uLightPos, uDiffuse, uSpecular);
386
387 glUniform4fv_func(uDiffuse, 1, diffuse);
388 glUniform4fv_func(uSpecular, 1, specular);
389
390 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
391 glEnable(GL_DEPTH_TEST);
392 glEnable(GL_LIGHT0);
393 glEnable(GL_LIGHTING);
394 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
395 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
396 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);
397
398 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
399 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
400
401 /* test glGetShaderSource() */
402 if (0) {
403 GLsizei len = strlen(fragShaderText) + 1;
404 GLsizei lenOut;
405 GLchar *src =(GLchar *) malloc(len * sizeof(GLchar));
406 glGetShaderSource_func(fragShader, 0, NULL, src);
407 glGetShaderSource_func(fragShader, len, &lenOut, src);
408 assert(len == lenOut + 1);
409 assert(strcmp(src, fragShaderText) == 0);
410 free(src);
411 }
412
413 assert(glIsProgram_func(program));
414 assert(glIsShader_func(fragShader));
415 assert(glIsShader_func(vertShader));
416
417 glColor3f(1, 0, 0);
418 #if 0
419 TestFunctions();
420 #endif
421 }
422
423
424 static void
425 ParseOptions(int argc, char *argv[])
426 {
427 int i;
428 for (i = 1; i < argc; i++) {
429 if (strcmp(argv[i], "-fs") == 0) {
430 FragProgFile = argv[i+1];
431 }
432 else if (strcmp(argv[i], "-vs") == 0) {
433 VertProgFile = argv[i+1];
434 }
435 }
436 }
437
438
439 int
440 main(int argc, char *argv[])
441 {
442 glutInit(&argc, argv);
443 glutInitWindowPosition( 0, 0);
444 glutInitWindowSize(100, 100);
445 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
446 win = glutCreateWindow(argv[0]);
447 glutReshapeFunc(Reshape);
448 glutKeyboardFunc(Key);
449 glutSpecialFunc(SpecialKey);
450 glutDisplayFunc(Redisplay);
451 if (anim)
452 glutIdleFunc(Idle);
453 ParseOptions(argc, argv);
454 Init();
455 glutMainLoop();
456 return 0;
457 }
458