Ignore more demo programs
[mesa.git] / progs / demos / arbfplight.c
1 /*
2 * Use GL_ARB_fragment_program and GL_ARB_vertex_program to implement
3 * simple per-pixel lighting.
4 *
5 * Brian Paul
6 * 17 April 2003
7 */
8
9 #include <assert.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <math.h>
14 #include <GL/glut.h>
15
16
17 static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
18 static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
19 static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
20 static GLfloat Delta = 1.0;
21
22 static GLuint FragProg;
23 static GLuint VertProg;
24 static GLboolean Anim = GL_TRUE;
25 static GLboolean Wire = GL_FALSE;
26 static GLboolean PixelLight = GL_TRUE;
27 static GLint Win;
28
29 static GLint T0 = 0;
30 static GLint Frames = 0;
31
32 static GLfloat Xrot = 0, Yrot = 0;
33
34 static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
35 static PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB_func;
36 static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB_func;
37 static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
38 static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
39 static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
40 static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
41 static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func;
42
43 /* These must match the indexes used in the fragment program */
44 #define LIGHTPOS 3
45
46 /* Set to one to test ARB_fog_linear program option */
47 #define DO_FRAGMENT_FOG 0
48
49
50 static void Redisplay( void )
51 {
52 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
53
54 if (PixelLight) {
55 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB,
56 LIGHTPOS, LightPos);
57 glEnable(GL_FRAGMENT_PROGRAM_ARB);
58 glEnable(GL_VERTEX_PROGRAM_ARB);
59 glDisable(GL_LIGHTING);
60 }
61 else {
62 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
63 glDisable(GL_FRAGMENT_PROGRAM_ARB);
64 glDisable(GL_VERTEX_PROGRAM_ARB);
65 glEnable(GL_LIGHTING);
66 }
67
68 glPushMatrix();
69 glRotatef(Xrot, 1, 0, 0);
70 glRotatef(Yrot, 0, 1, 0);
71 glutSolidSphere(2.0, 10, 5);
72 glPopMatrix();
73
74 glutSwapBuffers();
75
76 Frames++;
77
78 if (Anim) {
79 GLint t = glutGet(GLUT_ELAPSED_TIME);
80 if (t - T0 >= 5000) {
81 GLfloat seconds = (t - T0) / 1000.0;
82 GLfloat fps = Frames / seconds;
83 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
84 T0 = t;
85 Frames = 0;
86 }
87 }
88 }
89
90
91 static void Idle(void)
92 {
93 LightPos[0] += Delta;
94 if (LightPos[0] > 25.0)
95 Delta = -1.0;
96 else if (LightPos[0] <- 25.0)
97 Delta = 1.0;
98 glutPostRedisplay();
99 }
100
101
102 static void Reshape( int width, int height )
103 {
104 glViewport( 0, 0, width, height );
105 glMatrixMode( GL_PROJECTION );
106 glLoadIdentity();
107 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
108 glMatrixMode( GL_MODELVIEW );
109 glLoadIdentity();
110 glTranslatef( 0.0, 0.0, -15.0 );
111 }
112
113
114 static void Key( unsigned char key, int x, int y )
115 {
116 (void) x;
117 (void) y;
118 switch (key) {
119 case ' ':
120 case 'a':
121 Anim = !Anim;
122 if (Anim)
123 glutIdleFunc(Idle);
124 else
125 glutIdleFunc(NULL);
126 break;
127 case 'x':
128 LightPos[0] -= 1.0;
129 break;
130 case 'X':
131 LightPos[0] += 1.0;
132 break;
133 case 'w':
134 Wire = !Wire;
135 if (Wire)
136 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
137 else
138 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
139 break;
140 case 'p':
141 PixelLight = !PixelLight;
142 if (PixelLight) {
143 printf("Per-pixel lighting\n");
144 }
145 else {
146 printf("Conventional lighting\n");
147 }
148 break;
149 case 27:
150 glDeleteProgramsARB_func(1, &VertProg);
151 glDeleteProgramsARB_func(1, &FragProg);
152 glutDestroyWindow(Win);
153 exit(0);
154 break;
155 }
156 glutPostRedisplay();
157 }
158
159 static void SpecialKey( int key, int x, int y )
160 {
161 const GLfloat step = 3.0;
162 (void) x;
163 (void) y;
164 switch (key) {
165 case GLUT_KEY_UP:
166 Xrot -= step;
167 break;
168 case GLUT_KEY_DOWN:
169 Xrot += step;
170 break;
171 case GLUT_KEY_LEFT:
172 Yrot -= step;
173 break;
174 case GLUT_KEY_RIGHT:
175 Yrot += step;
176 break;
177 }
178 glutPostRedisplay();
179 }
180
181
182 /* A helper for finding errors in program strings */
183 static int FindLine( const char *program, int position )
184 {
185 int i, line = 1;
186 for (i = 0; i < position; i++) {
187 if (program[i] == '\n')
188 line++;
189 }
190 return line;
191 }
192
193
194 static void Init( void )
195 {
196 GLint errorPos;
197
198 /* Yes, this could be expressed more efficiently */
199 static const char *fragProgramText =
200 "!!ARBfp1.0\n"
201 #if DO_FRAGMENT_FOG
202 "OPTION ARB_fog_linear; \n"
203 #endif
204 "PARAM Diffuse = state.material.diffuse; \n"
205 "PARAM Specular = state.material.specular; \n"
206 "PARAM LightPos = program.local[3]; \n"
207 "TEMP lightDir, normal, len; \n"
208 "TEMP dotProd, specAtten; \n"
209 "TEMP diffuseColor, specularColor; \n"
210
211 "# Compute normalized light direction \n"
212 "DP3 len.x, LightPos, LightPos; \n"
213 "RSQ len.y, len.x; \n"
214 "MUL lightDir, LightPos, len.y; \n"
215
216 "# Compute normalized normal \n"
217 "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
218 "RSQ len.y, len.x; \n"
219 "MUL normal, fragment.texcoord[0], len.y; \n"
220
221 "# Compute dot product of light direction and normal vector\n"
222 "DP3_SAT dotProd, lightDir, normal; # limited to [0,1]\n"
223
224 "MUL diffuseColor, Diffuse, dotProd; # diffuse attenuation\n"
225
226 "POW specAtten.x, dotProd.x, {20.0}.x; # specular exponent\n"
227
228 "MUL specularColor, Specular, specAtten.x; # specular attenuation\n"
229
230 #if DO_FRAGMENT_FOG
231 "# need to clamp color to [0,1] before fogging \n"
232 "ADD_SAT result.color, diffuseColor, specularColor; # add colors\n"
233 #else
234 "# clamping will be done after program's finished \n"
235 "ADD result.color, diffuseColor, specularColor; # add colors\n"
236 #endif
237 "END \n"
238 ;
239
240 static const char *vertProgramText =
241 "!!ARBvp1.0\n"
242 "ATTRIB pos = vertex.position; \n"
243 "ATTRIB norm = vertex.normal; \n"
244 "PARAM modelview[4] = { state.matrix.modelview }; \n"
245 "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
246 "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
247
248 "# typical modelview/projection transform \n"
249 "DP4 result.position.x, pos, modelviewProj[0]; \n"
250 "DP4 result.position.y, pos, modelviewProj[1]; \n"
251 "DP4 result.position.z, pos, modelviewProj[2]; \n"
252 "DP4 result.position.w, pos, modelviewProj[3]; \n"
253
254 "# transform normal by inv transpose of modelview, put in tex0 \n"
255 "DP3 result.texcoord[0].x, norm, invModelview[0]; \n"
256 "DP3 result.texcoord[0].y, norm, invModelview[1]; \n"
257 "DP3 result.texcoord[0].z, norm, invModelview[2]; \n"
258 "DP3 result.texcoord[0].w, norm, invModelview[3]; \n"
259
260 #if DO_FRAGMENT_FOG
261 "# compute fog coordinate = vertex eye-space Z coord (negated)\n"
262 "DP4 result.fogcoord, -pos, modelview[2]; \n"
263 #endif
264 "END\n";
265 ;
266
267 if (!glutExtensionSupported("GL_ARB_vertex_program")) {
268 printf("Sorry, this demo requires GL_ARB_vertex_program\n");
269 exit(1);
270 }
271 if (!glutExtensionSupported("GL_ARB_fragment_program")) {
272 printf("Sorry, this demo requires GL_ARB_fragment_program\n");
273 exit(1);
274 }
275
276 /*
277 * Get extension function pointers.
278 */
279 glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
280 assert(glProgramLocalParameter4fvARB_func);
281
282 glProgramLocalParameter4dARB_func = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
283 assert(glProgramLocalParameter4dARB_func);
284
285 glGetProgramLocalParameterdvARB_func = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
286 assert(glGetProgramLocalParameterdvARB_func);
287
288 glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
289 assert(glGenProgramsARB_func);
290
291 glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
292 assert(glProgramStringARB_func);
293
294 glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
295 assert(glBindProgramARB_func);
296
297 glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
298 assert(glIsProgramARB_func);
299
300 glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
301 assert(glDeleteProgramsARB_func);
302
303 /*
304 * Fragment program
305 */
306 glGenProgramsARB_func(1, &FragProg);
307 assert(FragProg > 0);
308 glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, FragProg);
309 glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
310 GL_PROGRAM_FORMAT_ASCII_ARB,
311 strlen(fragProgramText),
312 (const GLubyte *) fragProgramText);
313 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
314 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
315 int l = FindLine(fragProgramText, errorPos);
316 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
317 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
318 exit(0);
319 }
320 assert(glIsProgramARB_func(FragProg));
321
322 /*
323 * Do some sanity tests
324 */
325 {
326 GLdouble v[4];
327 glProgramLocalParameter4dARB_func(GL_FRAGMENT_PROGRAM_ARB, 8,
328 10.0, 20.0, 30.0, 40.0);
329 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB, 8, v);
330 assert(v[0] == 10.0);
331 assert(v[1] == 20.0);
332 assert(v[2] == 30.0);
333 assert(v[3] == 40.0);
334 }
335
336 /*
337 * Vertex program
338 */
339 glGenProgramsARB_func(1, &VertProg);
340 assert(VertProg > 0);
341 glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB, VertProg);
342 glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB,
343 GL_PROGRAM_FORMAT_ASCII_ARB,
344 strlen(vertProgramText),
345 (const GLubyte *) vertProgramText);
346 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
347 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
348 int l = FindLine(vertProgramText, errorPos);
349 printf("Vertex Program Error (pos=%d line=%d): %s\n", errorPos, l,
350 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
351 exit(0);
352 }
353 assert(glIsProgramARB_func(VertProg));
354
355 /*
356 * Misc init
357 */
358 glClearColor(0.3, 0.3, 0.3, 0.0);
359 glEnable(GL_DEPTH_TEST);
360 glEnable(GL_LIGHT0);
361 glEnable(GL_LIGHTING);
362 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
363 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
364 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
365
366 #if DO_FRAGMENT_FOG
367 {
368 /* Green-ish fog color */
369 static const GLfloat fogColor[4] = {0.5, 1.0, 0.5, 0};
370 glFogfv(GL_FOG_COLOR, fogColor);
371 glFogf(GL_FOG_START, 5.0);
372 glFogf(GL_FOG_END, 25.0);
373 }
374 #endif
375
376 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
377 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
378 }
379
380
381 int main( int argc, char *argv[] )
382 {
383 glutInit( &argc, argv );
384 glutInitWindowPosition( 0, 0 );
385 glutInitWindowSize( 200, 200 );
386 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
387 Win = glutCreateWindow(argv[0]);
388 glutReshapeFunc( Reshape );
389 glutKeyboardFunc( Key );
390 glutSpecialFunc( SpecialKey );
391 glutDisplayFunc( Redisplay );
392 if (Anim)
393 glutIdleFunc(Idle);
394 Init();
395 glutMainLoop();
396 return 0;
397 }