blob: 861b3b72522cb7f3b9603dd9e340c771222c7222 [file] [log] [blame]
Brian Paul24339172003-04-17 19:20:54 +00001/*
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
17static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
18static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
19static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
20static GLfloat Delta = 1.0;
21
22static GLuint FragProg;
23static GLuint VertProg;
24static GLboolean Anim = GL_TRUE;
25static GLboolean Wire = GL_FALSE;
26static GLboolean PixelLight = GL_TRUE;
Brianbc74cb42007-04-20 11:59:18 -060027static GLint Win;
Brian Paul24339172003-04-17 19:20:54 +000028
Keith Whitwell180e28e2004-04-23 14:06:02 +000029static GLint T0 = 0;
30static GLint Frames = 0;
31
Brian Paul24339172003-04-17 19:20:54 +000032static GLfloat Xrot = 0, Yrot = 0;
33
34static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
Brian Paul3ca3ab02003-04-17 21:43:55 +000035static PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB_func;
36static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB_func;
Brian Paul24339172003-04-17 19:20:54 +000037static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
38static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
39static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
40static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
Brian Paula7e6f7b2004-01-13 16:17:21 +000041static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func;
Brian Paul24339172003-04-17 19:20:54 +000042
43/* These must match the indexes used in the fragment program */
Brian Paul24339172003-04-17 19:20:54 +000044#define LIGHTPOS 3
45
Brian Paul9a389d42004-02-17 17:59:59 +000046/* Set to one to test ARB_fog_linear program option */
47#define DO_FRAGMENT_FOG 0
Brian Paul24339172003-04-17 19:20:54 +000048
michal9c22f912007-10-27 18:41:47 +010049static void normalize (GLfloat *dst, const GLfloat *src)
50{
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;
55}
Brian Paul24339172003-04-17 19:20:54 +000056
57static void Redisplay( void )
58{
59 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
60
61 if (PixelLight) {
michal9c22f912007-10-27 18:41:47 +010062 GLfloat pos[4];
63
64 normalize( pos, LightPos );
65 pos[3] = LightPos[3];
Brian Paul3ca3ab02003-04-17 21:43:55 +000066 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB,
michal9c22f912007-10-27 18:41:47 +010067 LIGHTPOS, pos);
Brian Paul24339172003-04-17 19:20:54 +000068 glEnable(GL_FRAGMENT_PROGRAM_ARB);
69 glEnable(GL_VERTEX_PROGRAM_ARB);
70 glDisable(GL_LIGHTING);
71 }
72 else {
73 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
74 glDisable(GL_FRAGMENT_PROGRAM_ARB);
75 glDisable(GL_VERTEX_PROGRAM_ARB);
76 glEnable(GL_LIGHTING);
77 }
78
79 glPushMatrix();
80 glRotatef(Xrot, 1, 0, 0);
81 glRotatef(Yrot, 0, 1, 0);
82 glutSolidSphere(2.0, 10, 5);
83 glPopMatrix();
84
85 glutSwapBuffers();
Keith Whitwell180e28e2004-04-23 14:06:02 +000086
87 Frames++;
88
89 if (Anim) {
90 GLint t = glutGet(GLUT_ELAPSED_TIME);
91 if (t - T0 >= 5000) {
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);
Keith Whitwelle6479c62009-02-24 12:02:24 +000095 fflush(stdout);
Keith Whitwell180e28e2004-04-23 14:06:02 +000096 T0 = t;
97 Frames = 0;
98 }
99 }
Brian Paul24339172003-04-17 19:20:54 +0000100}
101
102
103static void Idle(void)
104{
105 LightPos[0] += Delta;
106 if (LightPos[0] > 25.0)
107 Delta = -1.0;
108 else if (LightPos[0] <- 25.0)
109 Delta = 1.0;
110 glutPostRedisplay();
111}
112
113
114static void Reshape( int width, int height )
115{
116 glViewport( 0, 0, width, height );
117 glMatrixMode( GL_PROJECTION );
118 glLoadIdentity();
119 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
120 glMatrixMode( GL_MODELVIEW );
121 glLoadIdentity();
122 glTranslatef( 0.0, 0.0, -15.0 );
123}
124
125
126static void Key( unsigned char key, int x, int y )
127{
128 (void) x;
129 (void) y;
130 switch (key) {
131 case ' ':
Brian Paul4e41eb12004-02-17 22:00:45 +0000132 case 'a':
Brian Paul24339172003-04-17 19:20:54 +0000133 Anim = !Anim;
134 if (Anim)
135 glutIdleFunc(Idle);
136 else
137 glutIdleFunc(NULL);
138 break;
139 case 'x':
140 LightPos[0] -= 1.0;
141 break;
142 case 'X':
143 LightPos[0] += 1.0;
144 break;
145 case 'w':
146 Wire = !Wire;
147 if (Wire)
148 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
149 else
150 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
151 break;
152 case 'p':
153 PixelLight = !PixelLight;
154 if (PixelLight) {
155 printf("Per-pixel lighting\n");
156 }
157 else {
158 printf("Conventional lighting\n");
159 }
160 break;
161 case 27:
Brian Paula7e6f7b2004-01-13 16:17:21 +0000162 glDeleteProgramsARB_func(1, &VertProg);
163 glDeleteProgramsARB_func(1, &FragProg);
Brianbc74cb42007-04-20 11:59:18 -0600164 glutDestroyWindow(Win);
Brian Paul24339172003-04-17 19:20:54 +0000165 exit(0);
166 break;
167 }
168 glutPostRedisplay();
169}
170
171static void SpecialKey( int key, int x, int y )
172{
173 const GLfloat step = 3.0;
174 (void) x;
175 (void) y;
176 switch (key) {
177 case GLUT_KEY_UP:
178 Xrot -= step;
179 break;
180 case GLUT_KEY_DOWN:
181 Xrot += step;
182 break;
183 case GLUT_KEY_LEFT:
184 Yrot -= step;
185 break;
186 case GLUT_KEY_RIGHT:
187 Yrot += step;
188 break;
189 }
190 glutPostRedisplay();
191}
192
193
194/* A helper for finding errors in program strings */
195static int FindLine( const char *program, int position )
196{
197 int i, line = 1;
198 for (i = 0; i < position; i++) {
199 if (program[i] == '\n')
200 line++;
201 }
202 return line;
203}
204
205
206static void Init( void )
207{
208 GLint errorPos;
209
210 /* Yes, this could be expressed more efficiently */
211 static const char *fragProgramText =
212 "!!ARBfp1.0\n"
Brian Paul9a389d42004-02-17 17:59:59 +0000213#if DO_FRAGMENT_FOG
214 "OPTION ARB_fog_linear; \n"
215#endif
Brian Paulf6a93d32004-03-22 16:27:13 +0000216 "PARAM Diffuse = state.material.diffuse; \n"
217 "PARAM Specular = state.material.specular; \n"
Brian Paul24339172003-04-17 19:20:54 +0000218 "PARAM LightPos = program.local[3]; \n"
michal9c22f912007-10-27 18:41:47 +0100219 "TEMP normal, len; \n"
Brian Paul24339172003-04-17 19:20:54 +0000220 "TEMP dotProd, specAtten; \n"
221 "TEMP diffuseColor, specularColor; \n"
222
Brian Paul24339172003-04-17 19:20:54 +0000223 "# Compute normalized normal \n"
224 "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
225 "RSQ len.y, len.x; \n"
michal9c22f912007-10-27 18:41:47 +0100226 "MUL normal.xyz, fragment.texcoord[0], len.y; \n"
Brian Paul24339172003-04-17 19:20:54 +0000227
228 "# Compute dot product of light direction and normal vector\n"
michal9c22f912007-10-27 18:41:47 +0100229 "DP3_SAT dotProd.x, LightPos, normal; # limited to [0,1]\n"
Brian Paul24339172003-04-17 19:20:54 +0000230
michal9c22f912007-10-27 18:41:47 +0100231 "MUL diffuseColor.xyz, Diffuse, dotProd.x; # diffuse attenuation\n"
Brian Paul24339172003-04-17 19:20:54 +0000232
233 "POW specAtten.x, dotProd.x, {20.0}.x; # specular exponent\n"
234
michal9c22f912007-10-27 18:41:47 +0100235 "MUL specularColor.xyz, Specular, specAtten.x; # specular attenuation\n"
Brian Paul24339172003-04-17 19:20:54 +0000236
michal9c22f912007-10-27 18:41:47 +0100237 "MOV result.color.w, Diffuse; \n"
Brian Paul9a389d42004-02-17 17:59:59 +0000238#if DO_FRAGMENT_FOG
239 "# need to clamp color to [0,1] before fogging \n"
michal9c22f912007-10-27 18:41:47 +0100240 "ADD_SAT result.color.xyz, diffuseColor, specularColor; # add colors\n"
Brian Paul9a389d42004-02-17 17:59:59 +0000241#else
242 "# clamping will be done after program's finished \n"
michal9c22f912007-10-27 18:41:47 +0100243 "ADD result.color.xyz, diffuseColor, specularColor; # add colors\n"
Brian Paul9a389d42004-02-17 17:59:59 +0000244#endif
Brian Paul24339172003-04-17 19:20:54 +0000245 "END \n"
246 ;
247
248 static const char *vertProgramText =
249 "!!ARBvp1.0\n"
250 "ATTRIB pos = vertex.position; \n"
251 "ATTRIB norm = vertex.normal; \n"
Brian Paul4e41eb12004-02-17 22:00:45 +0000252 "PARAM modelview[4] = { state.matrix.modelview }; \n"
Brian Paul24339172003-04-17 19:20:54 +0000253 "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
254 "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
255
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"
261
262 "# transform normal by inv transpose of modelview, put in tex0 \n"
Brian Paulb3680df2003-08-31 19:06:10 +0000263 "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"
Brian Paul24339172003-04-17 19:20:54 +0000267
Brian Paul9a389d42004-02-17 17:59:59 +0000268#if DO_FRAGMENT_FOG
Brian Paul4e41eb12004-02-17 22:00:45 +0000269 "# compute fog coordinate = vertex eye-space Z coord (negated)\n"
270 "DP4 result.fogcoord, -pos, modelview[2]; \n"
Brian Paul9a389d42004-02-17 17:59:59 +0000271#endif
Brian Paul24339172003-04-17 19:20:54 +0000272 "END\n";
273 ;
274
275 if (!glutExtensionSupported("GL_ARB_vertex_program")) {
276 printf("Sorry, this demo requires GL_ARB_vertex_program\n");
277 exit(1);
278 }
279 if (!glutExtensionSupported("GL_ARB_fragment_program")) {
280 printf("Sorry, this demo requires GL_ARB_fragment_program\n");
281 exit(1);
282 }
283
284 /*
285 * Get extension function pointers.
286 */
287 glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
288 assert(glProgramLocalParameter4fvARB_func);
289
Brian Paul3ca3ab02003-04-17 21:43:55 +0000290 glProgramLocalParameter4dARB_func = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
291 assert(glProgramLocalParameter4dARB_func);
292
293 glGetProgramLocalParameterdvARB_func = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
294 assert(glGetProgramLocalParameterdvARB_func);
295
Brian Paul24339172003-04-17 19:20:54 +0000296 glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
297 assert(glGenProgramsARB_func);
298
299 glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
300 assert(glProgramStringARB_func);
301
302 glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
303 assert(glBindProgramARB_func);
304
305 glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
306 assert(glIsProgramARB_func);
307
Brian Paula7e6f7b2004-01-13 16:17:21 +0000308 glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
309 assert(glDeleteProgramsARB_func);
310
Brian Paul24339172003-04-17 19:20:54 +0000311 /*
312 * Fragment program
313 */
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));
326 exit(0);
327 }
328 assert(glIsProgramARB_func(FragProg));
329
Brian Paul24339172003-04-17 19:20:54 +0000330 /*
331 * Do some sanity tests
332 */
333 {
334 GLdouble v[4];
Brian Paul3ca3ab02003-04-17 21:43:55 +0000335 glProgramLocalParameter4dARB_func(GL_FRAGMENT_PROGRAM_ARB, 8,
Brian Paul24339172003-04-17 19:20:54 +0000336 10.0, 20.0, 30.0, 40.0);
Brian Paul3ca3ab02003-04-17 21:43:55 +0000337 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB, 8, v);
Brian Paul24339172003-04-17 19:20:54 +0000338 assert(v[0] == 10.0);
339 assert(v[1] == 20.0);
340 assert(v[2] == 30.0);
341 assert(v[3] == 40.0);
Brian Paul24339172003-04-17 19:20:54 +0000342 }
343
344 /*
345 * Vertex program
346 */
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) {
Brian Paulec83f382006-03-30 14:26:29 +0000356 int l = FindLine(vertProgramText, errorPos);
Brian Paul24339172003-04-17 19:20:54 +0000357 printf("Vertex Program Error (pos=%d line=%d): %s\n", errorPos, l,
358 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
359 exit(0);
360 }
361 assert(glIsProgramARB_func(VertProg));
362
363 /*
364 * Misc init
365 */
366 glClearColor(0.3, 0.3, 0.3, 0.0);
367 glEnable(GL_DEPTH_TEST);
368 glEnable(GL_LIGHT0);
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);
373
Brian Paul9a389d42004-02-17 17:59:59 +0000374#if DO_FRAGMENT_FOG
375 {
376 /* Green-ish fog color */
377 static const GLfloat fogColor[4] = {0.5, 1.0, 0.5, 0};
Brian Paul9a389d42004-02-17 17:59:59 +0000378 glFogfv(GL_FOG_COLOR, fogColor);
379 glFogf(GL_FOG_START, 5.0);
Brian Paul4e41eb12004-02-17 22:00:45 +0000380 glFogf(GL_FOG_END, 25.0);
Brian Paul9a389d42004-02-17 17:59:59 +0000381 }
382#endif
383
Brian Paul24339172003-04-17 19:20:54 +0000384 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
385 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
386}
387
388
389int main( int argc, char *argv[] )
390{
Brian Paul24339172003-04-17 19:20:54 +0000391 glutInitWindowSize( 200, 200 );
Brian Paul263f4322009-12-18 08:12:55 -0700392 glutInit( &argc, argv );
Brian Paul24339172003-04-17 19:20:54 +0000393 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
Brianbc74cb42007-04-20 11:59:18 -0600394 Win = glutCreateWindow(argv[0]);
Brian Paul24339172003-04-17 19:20:54 +0000395 glutReshapeFunc( Reshape );
396 glutKeyboardFunc( Key );
397 glutSpecialFunc( SpecialKey );
398 glutDisplayFunc( Redisplay );
399 if (Anim)
400 glutIdleFunc(Idle);
401 Init();
402 glutMainLoop();
403 return 0;
404}