blob: f9112a39f20a01d0c315c57e75800cd0beebb0bb [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
44
45
46static void Redisplay( void )
47{
48 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
49
50 if (PixelLight) {
Brian Paul3ca3ab02003-04-17 21:43:55 +000051 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB,
52 LIGHTPOS, LightPos);
Brian Paul24339172003-04-17 19:20:54 +000053 glEnable(GL_FRAGMENT_PROGRAM_ARB);
54 glEnable(GL_VERTEX_PROGRAM_ARB);
55 glDisable(GL_LIGHTING);
56 }
57 else {
58 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
59 glDisable(GL_FRAGMENT_PROGRAM_ARB);
60 glDisable(GL_VERTEX_PROGRAM_ARB);
61 glEnable(GL_LIGHTING);
62 }
63
64 glPushMatrix();
65 glRotatef(Xrot, 1, 0, 0);
66 glRotatef(Yrot, 0, 1, 0);
67 glutSolidSphere(2.0, 10, 5);
68 glPopMatrix();
69
70 glutSwapBuffers();
71}
72
73
74static void Idle(void)
75{
76 LightPos[0] += Delta;
77 if (LightPos[0] > 25.0)
78 Delta = -1.0;
79 else if (LightPos[0] <- 25.0)
80 Delta = 1.0;
81 glutPostRedisplay();
82}
83
84
85static void Reshape( int width, int height )
86{
87 glViewport( 0, 0, width, height );
88 glMatrixMode( GL_PROJECTION );
89 glLoadIdentity();
90 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
91 glMatrixMode( GL_MODELVIEW );
92 glLoadIdentity();
93 glTranslatef( 0.0, 0.0, -15.0 );
94}
95
96
97static void Key( unsigned char key, int x, int y )
98{
99 (void) x;
100 (void) y;
101 switch (key) {
102 case ' ':
103 Anim = !Anim;
104 if (Anim)
105 glutIdleFunc(Idle);
106 else
107 glutIdleFunc(NULL);
108 break;
109 case 'x':
110 LightPos[0] -= 1.0;
111 break;
112 case 'X':
113 LightPos[0] += 1.0;
114 break;
115 case 'w':
116 Wire = !Wire;
117 if (Wire)
118 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
119 else
120 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
121 break;
122 case 'p':
123 PixelLight = !PixelLight;
124 if (PixelLight) {
125 printf("Per-pixel lighting\n");
126 }
127 else {
128 printf("Conventional lighting\n");
129 }
130 break;
131 case 27:
Brian Paula7e6f7b2004-01-13 16:17:21 +0000132 glDeleteProgramsARB_func(1, &VertProg);
133 glDeleteProgramsARB_func(1, &FragProg);
Brian Paul24339172003-04-17 19:20:54 +0000134 exit(0);
135 break;
136 }
137 glutPostRedisplay();
138}
139
140static void SpecialKey( int key, int x, int y )
141{
142 const GLfloat step = 3.0;
143 (void) x;
144 (void) y;
145 switch (key) {
146 case GLUT_KEY_UP:
147 Xrot -= step;
148 break;
149 case GLUT_KEY_DOWN:
150 Xrot += step;
151 break;
152 case GLUT_KEY_LEFT:
153 Yrot -= step;
154 break;
155 case GLUT_KEY_RIGHT:
156 Yrot += step;
157 break;
158 }
159 glutPostRedisplay();
160}
161
162
163/* A helper for finding errors in program strings */
164static int FindLine( const char *program, int position )
165{
166 int i, line = 1;
167 for (i = 0; i < position; i++) {
168 if (program[i] == '\n')
169 line++;
170 }
171 return line;
172}
173
174
175static void Init( void )
176{
177 GLint errorPos;
178
179 /* Yes, this could be expressed more efficiently */
180 static const char *fragProgramText =
181 "!!ARBfp1.0\n"
182 "PARAM Diffuse = program.local[1]; \n"
183 "PARAM Specular = program.local[2]; \n"
184 "PARAM LightPos = program.local[3]; \n"
185 "TEMP lightDir, normal, len; \n"
186 "TEMP dotProd, specAtten; \n"
187 "TEMP diffuseColor, specularColor; \n"
188
189 "# Compute normalized light direction \n"
190 "DP3 len.x, LightPos, LightPos; \n"
191 "RSQ len.y, len.x; \n"
192 "MUL lightDir, LightPos, len.y; \n"
193
194 "# Compute normalized normal \n"
195 "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
196 "RSQ len.y, len.x; \n"
197 "MUL normal, fragment.texcoord[0], len.y; \n"
198
199 "# Compute dot product of light direction and normal vector\n"
200 "DP3 dotProd, lightDir, normal;"
201
202 "MUL diffuseColor, Diffuse, dotProd; # diffuse attenuation\n"
203
204 "POW specAtten.x, dotProd.x, {20.0}.x; # specular exponent\n"
205
206 "MUL specularColor, Specular, specAtten.x; # specular attenuation\n"
207
208 "ADD result.color, diffuseColor, specularColor; # add colors\n"
209 "END \n"
210 ;
211
212 static const char *vertProgramText =
213 "!!ARBvp1.0\n"
214 "ATTRIB pos = vertex.position; \n"
215 "ATTRIB norm = vertex.normal; \n"
216 "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
217 "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
218
219 "# typical modelview/projection transform \n"
220 "DP4 result.position.x, pos, modelviewProj[0]; \n"
221 "DP4 result.position.y, pos, modelviewProj[1]; \n"
222 "DP4 result.position.z, pos, modelviewProj[2]; \n"
223 "DP4 result.position.w, pos, modelviewProj[3]; \n"
224
225 "# transform normal by inv transpose of modelview, put in tex0 \n"
Brian Paulb3680df2003-08-31 19:06:10 +0000226 "DP3 result.texcoord[0].x, norm, invModelview[0]; \n"
227 "DP3 result.texcoord[0].y, norm, invModelview[1]; \n"
228 "DP3 result.texcoord[0].z, norm, invModelview[2]; \n"
229 "DP3 result.texcoord[0].w, norm, invModelview[3]; \n"
Brian Paul24339172003-04-17 19:20:54 +0000230
231 "END\n";
232 ;
233
234 if (!glutExtensionSupported("GL_ARB_vertex_program")) {
235 printf("Sorry, this demo requires GL_ARB_vertex_program\n");
236 exit(1);
237 }
238 if (!glutExtensionSupported("GL_ARB_fragment_program")) {
239 printf("Sorry, this demo requires GL_ARB_fragment_program\n");
240 exit(1);
241 }
242
243 /*
244 * Get extension function pointers.
245 */
246 glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
247 assert(glProgramLocalParameter4fvARB_func);
248
Brian Paul3ca3ab02003-04-17 21:43:55 +0000249 glProgramLocalParameter4dARB_func = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
250 assert(glProgramLocalParameter4dARB_func);
251
252 glGetProgramLocalParameterdvARB_func = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
253 assert(glGetProgramLocalParameterdvARB_func);
254
Brian Paul24339172003-04-17 19:20:54 +0000255 glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
256 assert(glGenProgramsARB_func);
257
258 glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
259 assert(glProgramStringARB_func);
260
261 glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
262 assert(glBindProgramARB_func);
263
264 glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
265 assert(glIsProgramARB_func);
266
Brian Paula7e6f7b2004-01-13 16:17:21 +0000267 glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
268 assert(glDeleteProgramsARB_func);
269
Brian Paul24339172003-04-17 19:20:54 +0000270 /*
271 * Fragment program
272 */
273 glGenProgramsARB_func(1, &FragProg);
274 assert(FragProg > 0);
275 glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, FragProg);
276 glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
277 GL_PROGRAM_FORMAT_ASCII_ARB,
278 strlen(fragProgramText),
279 (const GLubyte *) fragProgramText);
280 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
281 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
282 int l = FindLine(fragProgramText, errorPos);
283 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
284 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
285 exit(0);
286 }
287 assert(glIsProgramARB_func(FragProg));
288
Brian Paul3ca3ab02003-04-17 21:43:55 +0000289 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, DIFFUSE, Diffuse);
290 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB, SPECULAR, Specular);
Brian Paul24339172003-04-17 19:20:54 +0000291
292 /*
293 * Do some sanity tests
294 */
295 {
296 GLdouble v[4];
Brian Paul3ca3ab02003-04-17 21:43:55 +0000297 glProgramLocalParameter4dARB_func(GL_FRAGMENT_PROGRAM_ARB, 8,
Brian Paul24339172003-04-17 19:20:54 +0000298 10.0, 20.0, 30.0, 40.0);
Brian Paul3ca3ab02003-04-17 21:43:55 +0000299 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB, 8, v);
Brian Paul24339172003-04-17 19:20:54 +0000300 assert(v[0] == 10.0);
301 assert(v[1] == 20.0);
302 assert(v[2] == 30.0);
303 assert(v[3] == 40.0);
Brian Paul3ca3ab02003-04-17 21:43:55 +0000304 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB, DIFFUSE, v);
Brian Paul24339172003-04-17 19:20:54 +0000305 assert(v[0] == Diffuse[0]);
306 assert(v[1] == Diffuse[1]);
307 assert(v[2] == Diffuse[2]);
308 assert(v[3] == Diffuse[3]);
309 }
310
311 /*
312 * Vertex program
313 */
314 glGenProgramsARB_func(1, &VertProg);
315 assert(VertProg > 0);
316 glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB, VertProg);
317 glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB,
318 GL_PROGRAM_FORMAT_ASCII_ARB,
319 strlen(vertProgramText),
320 (const GLubyte *) vertProgramText);
321 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
322 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
323 int l = FindLine(fragProgramText, errorPos);
324 printf("Vertex 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(VertProg));
329
330 /*
331 * Misc init
332 */
333 glClearColor(0.3, 0.3, 0.3, 0.0);
334 glEnable(GL_DEPTH_TEST);
335 glEnable(GL_LIGHT0);
336 glEnable(GL_LIGHTING);
337 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
338 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
339 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
340
341 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
342 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
343}
344
345
346int main( int argc, char *argv[] )
347{
348 glutInit( &argc, argv );
349 glutInitWindowPosition( 0, 0 );
350 glutInitWindowSize( 200, 200 );
351 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
352 glutCreateWindow(argv[0]);
353 glutReshapeFunc( Reshape );
354 glutKeyboardFunc( Key );
355 glutSpecialFunc( SpecialKey );
356 glutDisplayFunc( Redisplay );
357 if (Anim)
358 glutIdleFunc(Idle);
359 Init();
360 glutMainLoop();
361 return 0;
362}