nv50: any cpu access to a texture is done on its backing images
[mesa.git] / progs / demos / arbfplight.c
1 /*
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
17 static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
18 static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
19 static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
20 static GLfloat Delta = 1.0;
21
22 static GLuint FragProg;
23 static GLuint VertProg;
24 static GLboolean Anim = GL_TRUE;
25 static GLboolean Wire = GL_FALSE;
26 static GLboolean PixelLight = GL_TRUE;
27 static GLint Win;
28
29 static GLint T0 = 0;
30 static GLint Frames = 0;
31
32 static GLfloat Xrot = 0, Yrot = 0;
33
34 static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
35 static PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB_func;
36 static PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB_func;
37 static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
38 static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
39 static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
40 static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
41 static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func;
42
43 /* These must match the indexes used in the fragment program */
44 #define LIGHTPOS 3
45
46 /* Set to one to test ARB_fog_linear program option */
47 #define DO_FRAGMENT_FOG 0
48
49 static 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 }
56
57 static void Redisplay( void )
58 {
59 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
60
61 if (PixelLight) {
62 GLfloat pos[4];
63
64 normalize( pos, LightPos );
65 pos[3] = LightPos[3];
66 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB,
67 LIGHTPOS, pos);
68 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();
86
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);
95 T0 = t;
96 Frames = 0;
97 }
98 }
99 }
100
101
102 static void Idle(void)
103 {
104 LightPos[0] += Delta;
105 if (LightPos[0] > 25.0)
106 Delta = -1.0;
107 else if (LightPos[0] <- 25.0)
108 Delta = 1.0;
109 glutPostRedisplay();
110 }
111
112
113 static void Reshape( int width, int height )
114 {
115 glViewport( 0, 0, width, height );
116 glMatrixMode( GL_PROJECTION );
117 glLoadIdentity();
118 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
119 glMatrixMode( GL_MODELVIEW );
120 glLoadIdentity();
121 glTranslatef( 0.0, 0.0, -15.0 );
122 }
123
124
125 static void Key( unsigned char key, int x, int y )
126 {
127 (void) x;
128 (void) y;
129 switch (key) {
130 case ' ':
131 case 'a':
132 Anim = !Anim;
133 if (Anim)
134 glutIdleFunc(Idle);
135 else
136 glutIdleFunc(NULL);
137 break;
138 case 'x':
139 LightPos[0] -= 1.0;
140 break;
141 case 'X':
142 LightPos[0] += 1.0;
143 break;
144 case 'w':
145 Wire = !Wire;
146 if (Wire)
147 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
148 else
149 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
150 break;
151 case 'p':
152 PixelLight = !PixelLight;
153 if (PixelLight) {
154 printf("Per-pixel lighting\n");
155 }
156 else {
157 printf("Conventional lighting\n");
158 }
159 break;
160 case 27:
161 glDeleteProgramsARB_func(1, &VertProg);
162 glDeleteProgramsARB_func(1, &FragProg);
163 glutDestroyWindow(Win);
164 exit(0);
165 break;
166 }
167 glutPostRedisplay();
168 }
169
170 static void SpecialKey( int key, int x, int y )
171 {
172 const GLfloat step = 3.0;
173 (void) x;
174 (void) y;
175 switch (key) {
176 case GLUT_KEY_UP:
177 Xrot -= step;
178 break;
179 case GLUT_KEY_DOWN:
180 Xrot += step;
181 break;
182 case GLUT_KEY_LEFT:
183 Yrot -= step;
184 break;
185 case GLUT_KEY_RIGHT:
186 Yrot += step;
187 break;
188 }
189 glutPostRedisplay();
190 }
191
192
193 /* A helper for finding errors in program strings */
194 static int FindLine( const char *program, int position )
195 {
196 int i, line = 1;
197 for (i = 0; i < position; i++) {
198 if (program[i] == '\n')
199 line++;
200 }
201 return line;
202 }
203
204
205 static void Init( void )
206 {
207 GLint errorPos;
208
209 /* Yes, this could be expressed more efficiently */
210 static const char *fragProgramText =
211 "!!ARBfp1.0\n"
212 #if DO_FRAGMENT_FOG
213 "OPTION ARB_fog_linear; \n"
214 #endif
215 "PARAM Diffuse = state.material.diffuse; \n"
216 "PARAM Specular = state.material.specular; \n"
217 "PARAM LightPos = program.local[3]; \n"
218 "TEMP normal, len; \n"
219 "TEMP dotProd, specAtten; \n"
220 "TEMP diffuseColor, specularColor; \n"
221
222 "# Compute normalized normal \n"
223 "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
224 "RSQ len.y, len.x; \n"
225 "MUL normal.xyz, fragment.texcoord[0], len.y; \n"
226
227 "# Compute dot product of light direction and normal vector\n"
228 "DP3_SAT dotProd.x, LightPos, normal; # limited to [0,1]\n"
229
230 "MUL diffuseColor.xyz, Diffuse, dotProd.x; # diffuse attenuation\n"
231
232 "POW specAtten.x, dotProd.x, {20.0}.x; # specular exponent\n"
233
234 "MUL specularColor.xyz, Specular, specAtten.x; # specular attenuation\n"
235
236 "MOV result.color.w, Diffuse; \n"
237 #if DO_FRAGMENT_FOG
238 "# need to clamp color to [0,1] before fogging \n"
239 "ADD_SAT result.color.xyz, diffuseColor, specularColor; # add colors\n"
240 #else
241 "# clamping will be done after program's finished \n"
242 "ADD result.color.xyz, diffuseColor, specularColor; # add colors\n"
243 #endif
244 "END \n"
245 ;
246
247 static const char *vertProgramText =
248 "!!ARBvp1.0\n"
249 "ATTRIB pos = vertex.position; \n"
250 "ATTRIB norm = vertex.normal; \n"
251 "PARAM modelview[4] = { state.matrix.modelview }; \n"
252 "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
253 "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
254
255 "# typical modelview/projection transform \n"
256 "DP4 result.position.x, pos, modelviewProj[0]; \n"
257 "DP4 result.position.y, pos, modelviewProj[1]; \n"
258 "DP4 result.position.z, pos, modelviewProj[2]; \n"
259 "DP4 result.position.w, pos, modelviewProj[3]; \n"
260
261 "# transform normal by inv transpose of modelview, put in tex0 \n"
262 "DP3 result.texcoord[0].x, norm, invModelview[0]; \n"
263 "DP3 result.texcoord[0].y, norm, invModelview[1]; \n"
264 "DP3 result.texcoord[0].z, norm, invModelview[2]; \n"
265 "DP3 result.texcoord[0].w, norm, invModelview[3]; \n"
266
267 #if DO_FRAGMENT_FOG
268 "# compute fog coordinate = vertex eye-space Z coord (negated)\n"
269 "DP4 result.fogcoord, -pos, modelview[2]; \n"
270 #endif
271 "END\n";
272 ;
273
274 if (!glutExtensionSupported("GL_ARB_vertex_program")) {
275 printf("Sorry, this demo requires GL_ARB_vertex_program\n");
276 exit(1);
277 }
278 if (!glutExtensionSupported("GL_ARB_fragment_program")) {
279 printf("Sorry, this demo requires GL_ARB_fragment_program\n");
280 exit(1);
281 }
282
283 /*
284 * Get extension function pointers.
285 */
286 glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
287 assert(glProgramLocalParameter4fvARB_func);
288
289 glProgramLocalParameter4dARB_func = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) glutGetProcAddress("glProgramLocalParameter4dARB");
290 assert(glProgramLocalParameter4dARB_func);
291
292 glGetProgramLocalParameterdvARB_func = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) glutGetProcAddress("glGetProgramLocalParameterdvARB");
293 assert(glGetProgramLocalParameterdvARB_func);
294
295 glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
296 assert(glGenProgramsARB_func);
297
298 glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
299 assert(glProgramStringARB_func);
300
301 glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
302 assert(glBindProgramARB_func);
303
304 glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
305 assert(glIsProgramARB_func);
306
307 glDeleteProgramsARB_func = (PFNGLDELETEPROGRAMSARBPROC) glutGetProcAddress("glDeleteProgramsARB");
308 assert(glDeleteProgramsARB_func);
309
310 /*
311 * Fragment program
312 */
313 glGenProgramsARB_func(1, &FragProg);
314 assert(FragProg > 0);
315 glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, FragProg);
316 glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
317 GL_PROGRAM_FORMAT_ASCII_ARB,
318 strlen(fragProgramText),
319 (const GLubyte *) fragProgramText);
320 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
321 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
322 int l = FindLine(fragProgramText, errorPos);
323 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
324 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
325 exit(0);
326 }
327 assert(glIsProgramARB_func(FragProg));
328
329 /*
330 * Do some sanity tests
331 */
332 {
333 GLdouble v[4];
334 glProgramLocalParameter4dARB_func(GL_FRAGMENT_PROGRAM_ARB, 8,
335 10.0, 20.0, 30.0, 40.0);
336 glGetProgramLocalParameterdvARB_func(GL_FRAGMENT_PROGRAM_ARB, 8, v);
337 assert(v[0] == 10.0);
338 assert(v[1] == 20.0);
339 assert(v[2] == 30.0);
340 assert(v[3] == 40.0);
341 }
342
343 /*
344 * Vertex program
345 */
346 glGenProgramsARB_func(1, &VertProg);
347 assert(VertProg > 0);
348 glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB, VertProg);
349 glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB,
350 GL_PROGRAM_FORMAT_ASCII_ARB,
351 strlen(vertProgramText),
352 (const GLubyte *) vertProgramText);
353 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
354 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
355 int l = FindLine(vertProgramText, errorPos);
356 printf("Vertex Program Error (pos=%d line=%d): %s\n", errorPos, l,
357 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
358 exit(0);
359 }
360 assert(glIsProgramARB_func(VertProg));
361
362 /*
363 * Misc init
364 */
365 glClearColor(0.3, 0.3, 0.3, 0.0);
366 glEnable(GL_DEPTH_TEST);
367 glEnable(GL_LIGHT0);
368 glEnable(GL_LIGHTING);
369 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
370 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
371 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
372
373 #if DO_FRAGMENT_FOG
374 {
375 /* Green-ish fog color */
376 static const GLfloat fogColor[4] = {0.5, 1.0, 0.5, 0};
377 glFogfv(GL_FOG_COLOR, fogColor);
378 glFogf(GL_FOG_START, 5.0);
379 glFogf(GL_FOG_END, 25.0);
380 }
381 #endif
382
383 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
384 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
385 }
386
387
388 int main( int argc, char *argv[] )
389 {
390 glutInit( &argc, argv );
391 glutInitWindowPosition( 0, 0 );
392 glutInitWindowSize( 200, 200 );
393 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
394 Win = glutCreateWindow(argv[0]);
395 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 }