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