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