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