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