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