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