blob: b03ba2315a4b1b6ce1b28213f53d9303aab0b6ee [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 };
Brian917a5082007-02-21 15:57:55 -070033static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 0.0f };
Brian Paul24ea2c22006-11-03 00:04:06 +000034static GLfloat delta = 1.0f;
35
36static GLuint fragShader;
37static GLuint vertShader;
38static GLuint program;
39
Brian Paul24ea2c22006-11-03 00:04:06 +000040static GLint uDiffuse;
41static GLint uSpecular;
Brian46a92412007-01-17 10:25:44 -070042static GLint uTexture;
Brian Paul24ea2c22006-11-03 00:04:06 +000043
Brian46a92412007-01-17 10:25:44 -070044static GLuint SphereList, RectList, CurList;
Brian Paul24ea2c22006-11-03 00:04:06 +000045static GLint win = 0;
Brianbecb3932006-12-15 09:31:14 -070046static GLboolean anim = GL_FALSE;
Brian Paul24ea2c22006-11-03 00:04:06 +000047static GLboolean wire = GL_FALSE;
48static GLboolean pixelLight = GL_TRUE;
49
50static GLint t0 = 0;
51static GLint frames = 0;
52
Brian46a92412007-01-17 10:25:44 -070053static GLfloat xRot = 90.0f, yRot = 0.0f;
Brian Paul24ea2c22006-11-03 00:04:06 +000054
Brian Paul24ea2c22006-11-03 00:04:06 +000055
56static void
57normalize(GLfloat *dst, const GLfloat *src)
58{
59 GLfloat len = sqrtf(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
60 dst[0] = src[0] / len;
61 dst[1] = src[1] / len;
62 dst[2] = src[2] / len;
Brian917a5082007-02-21 15:57:55 -070063 dst[3] = src[3];
Brian Paul24ea2c22006-11-03 00:04:06 +000064}
65
66
67static void
68Redisplay(void)
69{
Brian917a5082007-02-21 15:57:55 -070070 GLfloat vec[4];
71
Brian Paul24ea2c22006-11-03 00:04:06 +000072 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Brian917a5082007-02-21 15:57:55 -070073
74 /* update light position */
75 normalize(vec, lightPos);
76 glLightfv(GL_LIGHT0, GL_POSITION, vec);
Brian Paul24ea2c22006-11-03 00:04:06 +000077
78 if (pixelLight) {
Brian Paul24ea2c22006-11-03 00:04:06 +000079 glUseProgram_func(program);
Brian Paul24ea2c22006-11-03 00:04:06 +000080 glDisable(GL_LIGHTING);
81 }
82 else {
83 glUseProgram_func(0);
Brian Paul24ea2c22006-11-03 00:04:06 +000084 glEnable(GL_LIGHTING);
85 }
86
87 glPushMatrix();
88 glRotatef(xRot, 1.0f, 0.0f, 0.0f);
89 glRotatef(yRot, 0.0f, 1.0f, 0.0f);
Brian46a92412007-01-17 10:25:44 -070090 /*
Brian Paul24ea2c22006-11-03 00:04:06 +000091 glutSolidSphere(2.0, 10, 5);
Brian46a92412007-01-17 10:25:44 -070092 */
93 glCallList(CurList);
Brian Paul24ea2c22006-11-03 00:04:06 +000094 glPopMatrix();
95
96 glutSwapBuffers();
97 frames++;
98
99 if (anim) {
100 GLint t = glutGet(GLUT_ELAPSED_TIME);
101 if (t - t0 >= 5000) {
102 GLfloat seconds =(GLfloat)(t - t0) / 1000.0f;
103 GLfloat fps = frames / seconds;
104 printf("%d frames in %6.3f seconds = %6.3f FPS\n",
105 frames, seconds, fps);
106 t0 = t;
107 frames = 0;
108 }
109 }
110}
111
112
113static void
114Idle(void)
115{
116 lightPos[0] += delta;
117 if (lightPos[0] > 25.0f || lightPos[0] < -25.0f)
118 delta = -delta;
119 glutPostRedisplay();
120}
121
122
123static void
124Reshape(int width, int height)
125{
126 glViewport(0, 0, width, height);
127 glMatrixMode(GL_PROJECTION);
128 glLoadIdentity();
129 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
130 glMatrixMode(GL_MODELVIEW);
131 glLoadIdentity();
132 glTranslatef(0.0f, 0.0f, -15.0f);
133}
134
135
136static void
137CleanUp(void)
138{
139 glDeleteShader_func(fragShader);
140 glDeleteShader_func(vertShader);
141 glDeleteProgram_func(program);
142 glutDestroyWindow(win);
143}
144
145
146static void
147Key(unsigned char key, int x, int y)
148{
149 (void) x;
150 (void) y;
151
152 switch(key) {
153 case ' ':
154 case 'a':
155 anim = !anim;
156 if (anim)
157 glutIdleFunc(Idle);
158 else
159 glutIdleFunc(NULL);
160 break;
161 case 'x':
162 lightPos[0] -= 1.0f;
163 break;
164 case 'X':
165 lightPos[0] += 1.0f;
166 break;
167 case 'w':
168 wire = !wire;
169 if (wire)
170 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
171 else
172 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
173 break;
Brian46a92412007-01-17 10:25:44 -0700174 case 'o':
175 if (CurList == SphereList)
176 CurList = RectList;
177 else
178 CurList = SphereList;
179 break;
Brian Paul24ea2c22006-11-03 00:04:06 +0000180 case 'p':
181 pixelLight = !pixelLight;
182 if (pixelLight)
183 printf("Per-pixel lighting\n");
184 else
185 printf("Conventional lighting\n");
186 break;
187 case 27:
188 CleanUp();
189 exit(0);
190 break;
191 }
192 glutPostRedisplay();
193}
194
195
196static void
197SpecialKey(int key, int x, int y)
198{
199 const GLfloat step = 3.0f;
200
201 (void) x;
202 (void) y;
203
204 switch(key) {
205 case GLUT_KEY_UP:
206 xRot -= step;
207 break;
208 case GLUT_KEY_DOWN:
209 xRot += step;
210 break;
211 case GLUT_KEY_LEFT:
212 yRot -= step;
213 break;
214 case GLUT_KEY_RIGHT:
215 yRot += step;
216 break;
217 }
218 glutPostRedisplay();
219}
220
221
222static void
Brianbecb3932006-12-15 09:31:14 -0700223TestFunctions(void)
224{
225 printf("Error 0x%x at line %d\n", glGetError(), __LINE__);
226 {
227 GLfloat pos[3];
Brianbecb3932006-12-15 09:31:14 -0700228 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);
Brianf4e345c2007-01-17 16:30:11 -0700405 fprintf(stderr, "fslight: problem compiling shader:\n%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 =
Brian Paul24ea2c22006-11-03 00:04:06 +0000456 "uniform vec4 diffuse;\n"
457 "uniform vec4 specular;\n"
458 "varying vec3 normal;\n"
459 "void main() {\n"
460 " // Compute dot product of light direction and normal vector\n"
Brian917a5082007-02-21 15:57:55 -0700461 " float dotProd = max(dot(gl_LightSource[0].position.xyz, \n"
462 " normalize(normal)), 0.0);\n"
Brian Paul24ea2c22006-11-03 00:04:06 +0000463 " // 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
Brian Paul24ea2c22006-11-03 00:04:06 +0000502 uDiffuse = glGetUniformLocation_func(program, "diffuse");
503 uSpecular = glGetUniformLocation_func(program, "specular");
Brian46a92412007-01-17 10:25:44 -0700504 uTexture = glGetUniformLocation_func(program, "texture");
Brian917a5082007-02-21 15:57:55 -0700505 printf("DiffusePos %d SpecularPos %d TexturePos %d\n",
506 uDiffuse, uSpecular, uTexture);
Brian Paul24ea2c22006-11-03 00:04:06 +0000507
508 glUniform4fv_func(uDiffuse, 1, diffuse);
509 glUniform4fv_func(uSpecular, 1, specular);
Brian180cc2f2007-03-21 11:41:41 -0600510 /* assert(glGetError() == 0);*/
Brian46a92412007-01-17 10:25:44 -0700511 glUniform1i_func(uTexture, 2); /* use texture unit 2 */
Brian917a5082007-02-21 15:57:55 -0700512 /*assert(glGetError() == 0);*/
Brian46a92412007-01-17 10:25:44 -0700513
514 if (CoordAttrib) {
515 int i;
516 glBindAttribLocation_func(program, CoordAttrib, "coord");
517 i = glGetAttribLocation_func(program, "coord");
518 assert(i >= 0);
519 if (i != CoordAttrib) {
520 printf("Hmmm, NVIDIA bug?\n");
521 CoordAttrib = i;
522 }
523 else {
524 printf("Mesa bind attrib: coord = %d\n", i);
525 }
526 }
527
528 /*assert(glGetError() == 0);*/
Brian Paul24ea2c22006-11-03 00:04:06 +0000529
530 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
531 glEnable(GL_DEPTH_TEST);
532 glEnable(GL_LIGHT0);
533 glEnable(GL_LIGHTING);
534 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
535 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
536 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);
537
Brian46a92412007-01-17 10:25:44 -0700538 MakeSphere();
539 MakeRect();
540
541 CurList = SphereList;
542
543 MakeTexture();
544
Brian Paul24ea2c22006-11-03 00:04:06 +0000545 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
546 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
547
548 /* test glGetShaderSource() */
Brianbecb3932006-12-15 09:31:14 -0700549 if (0) {
Brian Paul24ea2c22006-11-03 00:04:06 +0000550 GLsizei len = strlen(fragShaderText) + 1;
551 GLsizei lenOut;
552 GLchar *src =(GLchar *) malloc(len * sizeof(GLchar));
553 glGetShaderSource_func(fragShader, 0, NULL, src);
554 glGetShaderSource_func(fragShader, len, &lenOut, src);
555 assert(len == lenOut + 1);
556 assert(strcmp(src, fragShaderText) == 0);
557 free(src);
558 }
559
560 assert(glIsProgram_func(program));
561 assert(glIsShader_func(fragShader));
562 assert(glIsShader_func(vertShader));
Brianbecb3932006-12-15 09:31:14 -0700563
564 glColor3f(1, 0, 0);
Brian917a5082007-02-21 15:57:55 -0700565
566 /* for testing state vars */
567 {
568 static GLfloat fc[4] = { 1, 1, 0, 0 };
569 static GLfloat amb[4] = { 1, 0, 1, 0 };
570 glFogfv(GL_FOG_COLOR, fc);
571 glLightfv(GL_LIGHT1, GL_AMBIENT, amb);
572 }
573
Brianbecb3932006-12-15 09:31:14 -0700574#if 0
575 TestFunctions();
576#endif
577}
578
579
580static void
581ParseOptions(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+1];
587 }
588 else if (strcmp(argv[i], "-vs") == 0) {
589 VertProgFile = argv[i+1];
590 }
591 }
Brian Paul24ea2c22006-11-03 00:04:06 +0000592}
593
594
595int
596main(int argc, char *argv[])
597{
598 glutInit(&argc, argv);
599 glutInitWindowPosition( 0, 0);
Brianbecb3932006-12-15 09:31:14 -0700600 glutInitWindowSize(100, 100);
Brian Paul24ea2c22006-11-03 00:04:06 +0000601 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
602 win = glutCreateWindow(argv[0]);
603 glutReshapeFunc(Reshape);
604 glutKeyboardFunc(Key);
605 glutSpecialFunc(SpecialKey);
606 glutDisplayFunc(Redisplay);
607 if (anim)
608 glutIdleFunc(Idle);
Brianbecb3932006-12-15 09:31:14 -0700609 ParseOptions(argc, argv);
Brian Paul24ea2c22006-11-03 00:04:06 +0000610 Init();
611 glutMainLoop();
612 return 0;
613}
614
Brian917a5082007-02-21 15:57:55 -0700615