2 * Use GL_ARB_fragment_program and GL_ARB_vertex_program to implement
3 * simple per-pixel lighting.
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;
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
;
30 static GLint Frames
= 0;
32 static GLfloat Xrot
= 0, Yrot
= 0;
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
;
43 /* These must match the indexes used in the fragment program */
46 /* Set to one to test ARB_fog_linear program option */
47 #define DO_FRAGMENT_FOG 0
49 static void normalize (GLfloat
*dst
, const GLfloat
*src
)
51 GLfloat len
= sqrt (src
[0] * src
[0] + src
[1] * src
[1] + src
[2] * src
[2]);
52 dst
[0] = src
[0] / len
;
53 dst
[1] = src
[1] / len
;
54 dst
[2] = src
[2] / len
;
57 static void Redisplay( void )
59 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
64 normalize( pos
, LightPos
);
66 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB
,
68 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
69 glEnable(GL_VERTEX_PROGRAM_ARB
);
70 glDisable(GL_LIGHTING
);
73 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
74 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
75 glDisable(GL_VERTEX_PROGRAM_ARB
);
76 glEnable(GL_LIGHTING
);
80 glRotatef(Xrot
, 1, 0, 0);
81 glRotatef(Yrot
, 0, 1, 0);
82 glutSolidSphere(2.0, 10, 5);
90 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
92 GLfloat seconds
= (t
- T0
) / 1000.0;
93 GLfloat fps
= Frames
/ seconds
;
94 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames
, seconds
, fps
);
103 static void Idle(void)
105 LightPos
[0] += Delta
;
106 if (LightPos
[0] > 25.0)
108 else if (LightPos
[0] <- 25.0)
114 static void Reshape( int width
, int height
)
116 glViewport( 0, 0, width
, height
);
117 glMatrixMode( GL_PROJECTION
);
119 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
120 glMatrixMode( GL_MODELVIEW
);
122 glTranslatef( 0.0, 0.0, -15.0 );
126 static void Key( unsigned char key
, int x
, int y
)
148 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
150 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
153 PixelLight
= !PixelLight
;
155 printf("Per-pixel lighting\n");
158 printf("Conventional lighting\n");
162 glDeleteProgramsARB_func(1, &VertProg
);
163 glDeleteProgramsARB_func(1, &FragProg
);
164 glutDestroyWindow(Win
);
171 static void SpecialKey( int key
, int x
, int y
)
173 const GLfloat step
= 3.0;
194 /* A helper for finding errors in program strings */
195 static int FindLine( const char *program
, int position
)
198 for (i
= 0; i
< position
; i
++) {
199 if (program
[i
] == '\n')
206 static void Init( void )
210 /* Yes, this could be expressed more efficiently */
211 static const char *fragProgramText
=
214 "OPTION ARB_fog_linear; \n"
216 "PARAM Diffuse = state.material.diffuse; \n"
217 "PARAM Specular = state.material.specular; \n"
218 "PARAM LightPos = program.local[3]; \n"
219 "TEMP normal, len; \n"
220 "TEMP dotProd, specAtten; \n"
221 "TEMP diffuseColor, specularColor; \n"
223 "# Compute normalized normal \n"
224 "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
225 "RSQ len.y, len.x; \n"
226 "MUL normal.xyz, fragment.texcoord[0], len.y; \n"
228 "# Compute dot product of light direction and normal vector\n"
229 "DP3_SAT dotProd.x, LightPos, normal; # limited to [0,1]\n"
231 "MUL diffuseColor.xyz, Diffuse, dotProd.x; # diffuse attenuation\n"
233 "POW specAtten.x, dotProd.x, {20.0}.x; # specular exponent\n"
235 "MUL specularColor.xyz, Specular, specAtten.x; # specular attenuation\n"
237 "MOV result.color.w, Diffuse; \n"
239 "# need to clamp color to [0,1] before fogging \n"
240 "ADD_SAT result.color.xyz, diffuseColor, specularColor; # add colors\n"
242 "# clamping will be done after program's finished \n"
243 "ADD result.color.xyz, diffuseColor, specularColor; # add colors\n"
248 static const char *vertProgramText
=
250 "ATTRIB pos = vertex.position; \n"
251 "ATTRIB norm = vertex.normal; \n"
252 "PARAM modelview[4] = { state.matrix.modelview }; \n"
253 "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
254 "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
256 "# typical modelview/projection transform \n"
257 "DP4 result.position.x, pos, modelviewProj[0]; \n"
258 "DP4 result.position.y, pos, modelviewProj[1]; \n"
259 "DP4 result.position.z, pos, modelviewProj[2]; \n"
260 "DP4 result.position.w, pos, modelviewProj[3]; \n"
262 "# transform normal by inv transpose of modelview, put in tex0 \n"
263 "DP3 result.texcoord[0].x, norm, invModelview[0]; \n"
264 "DP3 result.texcoord[0].y, norm, invModelview[1]; \n"
265 "DP3 result.texcoord[0].z, norm, invModelview[2]; \n"
266 "DP3 result.texcoord[0].w, norm, invModelview[3]; \n"
269 "# compute fog coordinate = vertex eye-space Z coord (negated)\n"
270 "DP4 result.fogcoord, -pos, modelview[2]; \n"
275 if (!glutExtensionSupported("GL_ARB_vertex_program")) {
276 printf("Sorry, this demo requires GL_ARB_vertex_program\n");
279 if (!glutExtensionSupported("GL_ARB_fragment_program")) {
280 printf("Sorry, this demo requires GL_ARB_fragment_program\n");
285 * Get extension function pointers.
287 glProgramLocalParameter4fvARB_func
= (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC
) glutGetProcAddress("glProgramLocalParameter4fvARB");
288 assert(glProgramLocalParameter4fvARB_func
);
290 glProgramLocalParameter4dARB_func
= (PFNGLPROGRAMLOCALPARAMETER4DARBPROC
) glutGetProcAddress("glProgramLocalParameter4dARB");
291 assert(glProgramLocalParameter4dARB_func
);
293 glGetProgramLocalParameterdvARB_func
= (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC
) glutGetProcAddress("glGetProgramLocalParameterdvARB");
294 assert(glGetProgramLocalParameterdvARB_func
);
296 glGenProgramsARB_func
= (PFNGLGENPROGRAMSARBPROC
) glutGetProcAddress("glGenProgramsARB");
297 assert(glGenProgramsARB_func
);
299 glProgramStringARB_func
= (PFNGLPROGRAMSTRINGARBPROC
) glutGetProcAddress("glProgramStringARB");
300 assert(glProgramStringARB_func
);
302 glBindProgramARB_func
= (PFNGLBINDPROGRAMARBPROC
) glutGetProcAddress("glBindProgramARB");
303 assert(glBindProgramARB_func
);
305 glIsProgramARB_func
= (PFNGLISPROGRAMARBPROC
) glutGetProcAddress("glIsProgramARB");
306 assert(glIsProgramARB_func
);
308 glDeleteProgramsARB_func
= (PFNGLDELETEPROGRAMSARBPROC
) glutGetProcAddress("glDeleteProgramsARB");
309 assert(glDeleteProgramsARB_func
);
314 glGenProgramsARB_func(1, &FragProg
);
315 assert(FragProg
> 0);
316 glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB
, FragProg
);
317 glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB
,
318 GL_PROGRAM_FORMAT_ASCII_ARB
,
319 strlen(fragProgramText
),
320 (const GLubyte
*) fragProgramText
);
321 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errorPos
);
322 if (glGetError() != GL_NO_ERROR
|| errorPos
!= -1) {
323 int l
= FindLine(fragProgramText
, errorPos
);
324 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos
, l
,
325 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB
));
328 assert(glIsProgramARB_func(FragProg
));
331 * Do some sanity tests
335 glProgramLocalParameter4dARB_func(GL_FRAGMENT_PROGRAM_ARB
, 8,
336 10.0, 20.0, 30.0, 40.0);
337 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB
, 8, v
);
338 assert(v
[0] == 10.0);
339 assert(v
[1] == 20.0);
340 assert(v
[2] == 30.0);
341 assert(v
[3] == 40.0);
347 glGenProgramsARB_func(1, &VertProg
);
348 assert(VertProg
> 0);
349 glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB
, VertProg
);
350 glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB
,
351 GL_PROGRAM_FORMAT_ASCII_ARB
,
352 strlen(vertProgramText
),
353 (const GLubyte
*) vertProgramText
);
354 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB
, &errorPos
);
355 if (glGetError() != GL_NO_ERROR
|| errorPos
!= -1) {
356 int l
= FindLine(vertProgramText
, errorPos
);
357 printf("Vertex Program Error (pos=%d line=%d): %s\n", errorPos
, l
,
358 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB
));
361 assert(glIsProgramARB_func(VertProg
));
366 glClearColor(0.3, 0.3, 0.3, 0.0);
367 glEnable(GL_DEPTH_TEST
);
369 glEnable(GL_LIGHTING
);
370 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, Diffuse
);
371 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, Specular
);
372 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, 20.0);
376 /* Green-ish fog color */
377 static const GLfloat fogColor
[4] = {0.5, 1.0, 0.5, 0};
378 glFogfv(GL_FOG_COLOR
, fogColor
);
379 glFogf(GL_FOG_START
, 5.0);
380 glFogf(GL_FOG_END
, 25.0);
384 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
385 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
389 int main( int argc
, char *argv
[] )
391 glutInit( &argc
, argv
);
392 glutInitWindowPosition( 0, 0 );
393 glutInitWindowSize( 200, 200 );
394 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
395 Win
= glutCreateWindow(argv
[0]);
396 glutReshapeFunc( Reshape
);
397 glutKeyboardFunc( Key
);
398 glutSpecialFunc( SpecialKey
);
399 glutDisplayFunc( Redisplay
);