progs/demos: add fps output to cubemap
[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
26 #define TEXTURE 0
27
28 static GLint CoordAttrib = 0;
29
30 static char *FragProgFile = NULL;
31 static char *VertProgFile = NULL;
32
33 static GLfloat diffuse[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
34 static GLfloat specular[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
35 static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 0.0f };
36 static GLfloat delta = 1.0f;
37
38 static GLuint fragShader;
39 static GLuint vertShader;
40 static GLuint program;
41
42 static GLint uDiffuse;
43 static GLint uSpecular;
44 static GLint uTexture;
45
46 static GLuint SphereList, RectList, CurList;
47 static GLint win = 0;
48 static GLboolean anim = GL_TRUE;
49 static GLboolean wire = GL_FALSE;
50 static GLboolean pixelLight = GL_TRUE;
51
52 static GLint t0 = 0;
53 static GLint frames = 0;
54
55 static GLfloat xRot = 90.0f, yRot = 0.0f;
56
57
58 static void
59 normalize(GLfloat *dst, const GLfloat *src)
60 {
61 GLfloat len = sqrt(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
62 dst[0] = src[0] / len;
63 dst[1] = src[1] / len;
64 dst[2] = src[2] / len;
65 dst[3] = src[3];
66 }
67
68
69 static void
70 Redisplay(void)
71 {
72 GLfloat vec[4];
73
74 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
75
76 /* update light position */
77 normalize(vec, lightPos);
78 glLightfv(GL_LIGHT0, GL_POSITION, vec);
79
80 if (pixelLight) {
81 glUseProgram_func(program);
82 glDisable(GL_LIGHTING);
83 }
84 else {
85 glUseProgram_func(0);
86 glEnable(GL_LIGHTING);
87 }
88
89 glPushMatrix();
90 glRotatef(xRot, 1.0f, 0.0f, 0.0f);
91 glRotatef(yRot, 0.0f, 1.0f, 0.0f);
92 /*
93 glutSolidSphere(2.0, 10, 5);
94 */
95 glCallList(CurList);
96 glPopMatrix();
97
98 glutSwapBuffers();
99 frames++;
100
101 if (anim) {
102 GLint t = glutGet(GLUT_ELAPSED_TIME);
103 if (t - t0 >= 5000) {
104 GLfloat seconds =(GLfloat)(t - t0) / 1000.0f;
105 GLfloat fps = frames / seconds;
106 printf("%d frames in %6.3f seconds = %6.3f FPS\n",
107 frames, seconds, fps);
108 fflush(stdout);
109 t0 = t;
110 frames = 0;
111 }
112 }
113 }
114
115
116 static void
117 Idle(void)
118 {
119 lightPos[0] += delta;
120 if (lightPos[0] > 25.0f || lightPos[0] < -25.0f)
121 delta = -delta;
122 glutPostRedisplay();
123 }
124
125
126 static void
127 Reshape(int width, int height)
128 {
129 glViewport(0, 0, width, height);
130 glMatrixMode(GL_PROJECTION);
131 glLoadIdentity();
132 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
133 glMatrixMode(GL_MODELVIEW);
134 glLoadIdentity();
135 glTranslatef(0.0f, 0.0f, -15.0f);
136 }
137
138
139 static void
140 CleanUp(void)
141 {
142 glDeleteShader_func(fragShader);
143 glDeleteShader_func(vertShader);
144 glDeleteProgram_func(program);
145 glutDestroyWindow(win);
146 }
147
148
149 static void
150 Key(unsigned char key, int x, int y)
151 {
152 (void) x;
153 (void) y;
154
155 switch(key) {
156 case ' ':
157 case 'a':
158 anim = !anim;
159 if (anim)
160 glutIdleFunc(Idle);
161 else
162 glutIdleFunc(NULL);
163 break;
164 case 'x':
165 lightPos[0] -= 1.0f;
166 break;
167 case 'X':
168 lightPos[0] += 1.0f;
169 break;
170 case 'w':
171 wire = !wire;
172 if (wire)
173 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
174 else
175 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
176 break;
177 case 'o':
178 if (CurList == SphereList)
179 CurList = RectList;
180 else
181 CurList = SphereList;
182 break;
183 case 'p':
184 pixelLight = !pixelLight;
185 if (pixelLight)
186 printf("Per-pixel lighting\n");
187 else
188 printf("Conventional lighting\n");
189 break;
190 case 27:
191 CleanUp();
192 exit(0);
193 break;
194 }
195 glutPostRedisplay();
196 }
197
198
199 static void
200 SpecialKey(int key, int x, int y)
201 {
202 const GLfloat step = 3.0f;
203
204 (void) x;
205 (void) y;
206
207 switch(key) {
208 case GLUT_KEY_UP:
209 xRot -= step;
210 break;
211 case GLUT_KEY_DOWN:
212 xRot += step;
213 break;
214 case GLUT_KEY_LEFT:
215 yRot -= step;
216 break;
217 case GLUT_KEY_RIGHT:
218 yRot += step;
219 break;
220 }
221 glutPostRedisplay();
222 }
223
224
225 static void
226 TestFunctions(void)
227 {
228 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
229
230 assert(glIsProgram_func(program));
231 assert(glIsShader_func(fragShader));
232 assert(glIsShader_func(vertShader));
233
234 /* attached shaders */
235 {
236 GLuint shaders[20];
237 GLsizei count;
238 int i;
239 glGetAttachedShaders_func(program, 20, &count, shaders);
240 for (i = 0; i < count; i++) {
241 printf("Attached: %u\n", shaders[i]);
242 assert(shaders[i] == fragShader ||
243 shaders[i] == vertShader);
244 }
245 }
246
247 {
248 GLchar log[1000];
249 GLsizei len;
250 glGetShaderInfoLog_func(vertShader, 1000, &len, log);
251 printf("Vert Shader Info Log: %s\n", log);
252 glGetShaderInfoLog_func(fragShader, 1000, &len, log);
253 printf("Frag Shader Info Log: %s\n", log);
254 glGetProgramInfoLog_func(program, 1000, &len, log);
255 printf("Program Info Log: %s\n", log);
256 }
257
258 /* active uniforms */
259 {
260 GLint n, max, i;
261 glGetProgramiv_func(program, GL_ACTIVE_UNIFORMS, &n);
262 glGetProgramiv_func(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max);
263 printf("Num uniforms: %d Max name length: %d\n", n, max);
264 for (i = 0; i < n; i++) {
265 GLint size, len;
266 GLenum type;
267 char name[100];
268 glGetActiveUniform_func(program, i, 100, &len, &size, &type, name);
269 printf(" %d: %s nameLen=%d size=%d type=0x%x\n",
270 i, name, len, size, type);
271 }
272 }
273 }
274
275
276 #if TEXTURE
277 static void
278 MakeTexture(void)
279 {
280 #define SZ0 64
281 #define SZ1 32
282 GLubyte image0[SZ0][SZ0][SZ0][4];
283 GLubyte image1[SZ1][SZ1][SZ1][4];
284 GLuint i, j, k;
285
286 /* level 0: two-tone gray checkboard */
287 for (i = 0; i < SZ0; i++) {
288 for (j = 0; j < SZ0; j++) {
289 for (k = 0; k < SZ0; k++) {
290 if ((i/8 + j/8 + k/8) & 1) {
291 image0[i][j][k][0] =
292 image0[i][j][k][1] =
293 image0[i][j][k][2] = 200;
294 }
295 else {
296 image0[i][j][k][0] =
297 image0[i][j][k][1] =
298 image0[i][j][k][2] = 100;
299 }
300 image0[i][j][k][3] = 255;
301 }
302 }
303 }
304
305 /* level 1: two-tone green checkboard */
306 for (i = 0; i < SZ1; i++) {
307 for (j = 0; j < SZ1; j++) {
308 for (k = 0; k < SZ1; k++) {
309 if ((i/8 + j/8 + k/8) & 1) {
310 image1[i][j][k][0] = 0;
311 image1[i][j][k][1] = 250;
312 image1[i][j][k][2] = 0;
313 }
314 else {
315 image1[i][j][k][0] = 0;
316 image1[i][j][k][1] = 200;
317 image1[i][j][k][2] = 0;
318 }
319 image1[i][j][k][3] = 255;
320 }
321 }
322 }
323
324 glActiveTexture(GL_TEXTURE2); /* unit 2 */
325 glBindTexture(GL_TEXTURE_2D, 42);
326 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SZ0, SZ0, 0,
327 GL_RGBA, GL_UNSIGNED_BYTE, image0);
328 glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, SZ1, SZ1, 0,
329 GL_RGBA, GL_UNSIGNED_BYTE, image1);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
331 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
332 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
333
334 glActiveTexture(GL_TEXTURE4); /* unit 4 */
335 glBindTexture(GL_TEXTURE_3D, 43);
336 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, SZ0, SZ0, SZ0, 0,
337 GL_RGBA, GL_UNSIGNED_BYTE, image0);
338 glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA, SZ1, SZ1, SZ1, 0,
339 GL_RGBA, GL_UNSIGNED_BYTE, image1);
340 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 1);
341 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
342 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
343 }
344 #endif
345
346
347 static void
348 MakeSphere(void)
349 {
350 GLUquadricObj *obj = gluNewQuadric();
351 SphereList = glGenLists(1);
352 gluQuadricTexture(obj, GL_TRUE);
353 glNewList(SphereList, GL_COMPILE);
354 gluSphere(obj, 2.0f, 10, 5);
355 glEndList();
356 }
357
358 static void
359 VertAttrib(GLint index, float x, float y)
360 {
361 #if 1
362 glVertexAttrib2f_func(index, x, y);
363 #else
364 glTexCoord2f(x, y);
365 #endif
366 }
367
368 static void
369 MakeRect(void)
370 {
371 RectList = glGenLists(1);
372 glNewList(RectList, GL_COMPILE);
373 glNormal3f(0, 0, 1);
374 glBegin(GL_POLYGON);
375 VertAttrib(CoordAttrib, 0, 0); glVertex2f(-2, -2);
376 VertAttrib(CoordAttrib, 1, 0); glVertex2f( 2, -2);
377 VertAttrib(CoordAttrib, 1, 1); glVertex2f( 2, 2);
378 VertAttrib(CoordAttrib, 0, 1); glVertex2f(-2, 2);
379 glEnd(); /* XXX omit this and crash! */
380 glEndList();
381 }
382
383
384
385 static void
386 LoadAndCompileShader(GLuint shader, const char *text)
387 {
388 GLint stat;
389
390 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
391
392 glCompileShader_func(shader);
393
394 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
395 if (!stat) {
396 GLchar log[1000];
397 GLsizei len;
398 glGetShaderInfoLog_func(shader, 1000, &len, log);
399 fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
400 exit(1);
401 }
402 }
403
404
405 /**
406 * Read a shader from a file.
407 */
408 static void
409 ReadShader(GLuint shader, const char *filename)
410 {
411 const int max = 100*1000;
412 int n;
413 char *buffer = (char*) malloc(max);
414 FILE *f = fopen(filename, "r");
415 if (!f) {
416 fprintf(stderr, "fslight: Unable to open shader file %s\n", filename);
417 exit(1);
418 }
419
420 n = fread(buffer, 1, max, f);
421 printf("fslight: read %d bytes from shader file %s\n", n, filename);
422 if (n > 0) {
423 buffer[n] = 0;
424 LoadAndCompileShader(shader, buffer);
425 }
426
427 fclose(f);
428 free(buffer);
429 }
430
431
432 static void
433 CheckLink(GLuint prog)
434 {
435 GLint stat;
436 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
437 if (!stat) {
438 GLchar log[1000];
439 GLsizei len;
440 glGetProgramInfoLog_func(prog, 1000, &len, log);
441 fprintf(stderr, "Linker error:\n%s\n", log);
442 }
443 }
444
445
446 static void
447 Init(void)
448 {
449 static const char *fragShaderText =
450 "uniform vec4 diffuse;\n"
451 "uniform vec4 specular;\n"
452 "varying vec3 normal;\n"
453 "void main() {\n"
454 " // Compute dot product of light direction and normal vector\n"
455 " float dotProd = max(dot(gl_LightSource[0].position.xyz, \n"
456 " normalize(normal)), 0.0);\n"
457 " // Compute diffuse and specular contributions\n"
458 " gl_FragColor = diffuse * dotProd + specular * pow(dotProd, 20.0);\n"
459 "}\n";
460 static const char *vertShaderText =
461 "varying vec3 normal;\n"
462 "void main() {\n"
463 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
464 " normal = gl_NormalMatrix * gl_Normal;\n"
465 "}\n";
466 const char *version;
467
468 version = (const char *) glGetString(GL_VERSION);
469 if (version[0] != '2' || version[1] != '.') {
470 printf("This program requires OpenGL 2.x, found %s\n", version);
471 exit(1);
472 }
473
474 GetExtensionFuncs();
475
476 fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
477 if (FragProgFile)
478 ReadShader(fragShader, FragProgFile);
479 else
480 LoadAndCompileShader(fragShader, fragShaderText);
481
482
483 vertShader = glCreateShader_func(GL_VERTEX_SHADER);
484 if (VertProgFile)
485 ReadShader(vertShader, VertProgFile);
486 else
487 LoadAndCompileShader(vertShader, vertShaderText);
488
489 program = glCreateProgram_func();
490 glAttachShader_func(program, fragShader);
491 glAttachShader_func(program, vertShader);
492 glLinkProgram_func(program);
493 CheckLink(program);
494 glUseProgram_func(program);
495
496 uDiffuse = glGetUniformLocation_func(program, "diffuse");
497 uSpecular = glGetUniformLocation_func(program, "specular");
498 uTexture = glGetUniformLocation_func(program, "texture");
499 printf("DiffusePos %d SpecularPos %d TexturePos %d\n",
500 uDiffuse, uSpecular, uTexture);
501
502 glUniform4fv_func(uDiffuse, 1, diffuse);
503 glUniform4fv_func(uSpecular, 1, specular);
504 /* assert(glGetError() == 0);*/
505 #if TEXTURE
506 glUniform1i_func(uTexture, 2); /* use texture unit 2 */
507 #endif
508 /*assert(glGetError() == 0);*/
509
510 if (CoordAttrib) {
511 int i;
512 glBindAttribLocation_func(program, CoordAttrib, "coord");
513 i = glGetAttribLocation_func(program, "coord");
514 assert(i >= 0);
515 if (i != CoordAttrib) {
516 printf("Hmmm, NVIDIA bug?\n");
517 CoordAttrib = i;
518 }
519 else {
520 printf("Mesa bind attrib: coord = %d\n", i);
521 }
522 }
523
524 /*assert(glGetError() == 0);*/
525
526 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
527 glEnable(GL_DEPTH_TEST);
528 glEnable(GL_LIGHT0);
529 glEnable(GL_LIGHTING);
530 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
531 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
532 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);
533
534 MakeSphere();
535 MakeRect();
536
537 CurList = SphereList;
538
539 #if TEXTURE
540 MakeTexture();
541 #endif
542
543 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
544 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
545
546 /* test glGetShaderSource() */
547 if (0) {
548 GLsizei len = strlen(fragShaderText) + 1;
549 GLsizei lenOut;
550 GLchar *src =(GLchar *) malloc(len * sizeof(GLchar));
551 glGetShaderSource_func(fragShader, 0, NULL, src);
552 glGetShaderSource_func(fragShader, len, &lenOut, src);
553 assert(len == lenOut + 1);
554 assert(strcmp(src, fragShaderText) == 0);
555 free(src);
556 }
557
558 assert(glIsProgram_func(program));
559 assert(glIsShader_func(fragShader));
560 assert(glIsShader_func(vertShader));
561
562 glColor3f(1, 0, 0);
563
564 /* for testing state vars */
565 {
566 static GLfloat fc[4] = { 1, 1, 0, 0 };
567 static GLfloat amb[4] = { 1, 0, 1, 0 };
568 glFogfv(GL_FOG_COLOR, fc);
569 glLightfv(GL_LIGHT1, GL_AMBIENT, amb);
570 }
571
572 #if 0
573 TestFunctions();
574 #else
575 (void) TestFunctions;
576 #endif
577 }
578
579
580 static void
581 ParseOptions(int argc, char *argv[])
582 {
583 int i;
584 for (i = 1; i < argc; i++) {
585 if (strcmp(argv[i], "-fs") == 0) {
586 FragProgFile = argv[++i];
587 }
588 else if (strcmp(argv[i], "-vs") == 0) {
589 VertProgFile = argv[++i];
590 }
591 else {
592 fprintf(stderr, "unknown option %s\n", argv[i]);
593 break;
594 }
595 }
596 }
597
598
599 int
600 main(int argc, char *argv[])
601 {
602 glutInit(&argc, argv);
603 glutInitWindowPosition( 0, 0);
604 glutInitWindowSize(200, 200);
605 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
606 win = glutCreateWindow(argv[0]);
607 glutReshapeFunc(Reshape);
608 glutKeyboardFunc(Key);
609 glutSpecialFunc(SpecialKey);
610 glutDisplayFunc(Redisplay);
611 if (anim)
612 glutIdleFunc(Idle);
613 ParseOptions(argc, argv);
614 Init();
615 glutMainLoop();
616 return 0;
617 }
618
619