1/* 2 * Use GL_NV_fragment_program to implement per-pixel lighting. 3 * 4 * Brian Paul 5 * 7 April 2003 6 */ 7 8#include <assert.h> 9#include <string.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <math.h> 13#include <GL/glew.h> 14#include "glut_wrap.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; 27static GLint Win; 28static GLfloat Xrot = 0, Yrot = 0; 29 30 31#define NAMED_PARAMETER4FV(prog, name, v) \ 32 glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v) 33 34 35static void Display( void ) 36{ 37 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 38 39 if (PixelLight) { 40#if defined(GL_NV_fragment_program) 41 NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos); 42 glEnable(GL_FRAGMENT_PROGRAM_NV); 43 glEnable(GL_VERTEX_PROGRAM_NV); 44#endif 45 glDisable(GL_LIGHTING); 46 } 47 else { 48 glLightfv(GL_LIGHT0, GL_POSITION, LightPos); 49#if defined(GL_NV_fragment_program) 50 glDisable(GL_FRAGMENT_PROGRAM_NV); 51 glDisable(GL_VERTEX_PROGRAM_NV); 52#endif 53 glEnable(GL_LIGHTING); 54 } 55 56 glPushMatrix(); 57 glRotatef(Xrot, 1, 0, 0); 58 glRotatef(Yrot, 0, 1, 0); 59 60#if 1 61 glutSolidSphere(2.0, 10, 5); 62#else 63 { 64 GLUquadricObj *q = gluNewQuadric(); 65 gluQuadricNormals(q, GL_SMOOTH); 66 gluQuadricTexture(q, GL_TRUE); 67 glRotatef(90, 1, 0, 0); 68 glTranslatef(0, 0, -1); 69 gluCylinder(q, 1.0, 1.0, 2.0, 24, 1); 70 gluDeleteQuadric(q); 71 } 72#endif 73 74 glPopMatrix(); 75 76 glutSwapBuffers(); 77} 78 79 80static void Idle(void) 81{ 82 LightPos[0] += Delta; 83 if (LightPos[0] > 25.0) 84 Delta = -1.0; 85 else if (LightPos[0] <- 25.0) 86 Delta = 1.0; 87 glutPostRedisplay(); 88} 89 90 91static void Reshape( int width, int height ) 92{ 93 glViewport( 0, 0, width, height ); 94 glMatrixMode( GL_PROJECTION ); 95 glLoadIdentity(); 96 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); 97 /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/ 98 glMatrixMode( GL_MODELVIEW ); 99 glLoadIdentity(); 100 glTranslatef( 0.0, 0.0, -15.0 ); 101} 102 103 104static void Key( unsigned char key, int x, int y ) 105{ 106 (void) x; 107 (void) y; 108 switch (key) { 109 case ' ': 110 Anim = !Anim; 111 if (Anim) 112 glutIdleFunc(Idle); 113 else 114 glutIdleFunc(NULL); 115 break; 116 case 'x': 117 LightPos[0] -= 1.0; 118 break; 119 case 'X': 120 LightPos[0] += 1.0; 121 break; 122 case 'w': 123 Wire = !Wire; 124 if (Wire) 125 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 126 else 127 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 128 break; 129 case 'p': 130 PixelLight = !PixelLight; 131 if (PixelLight) { 132 printf("Per-pixel lighting\n"); 133 } 134 else { 135 printf("Conventional lighting\n"); 136 } 137 break; 138 case 27: 139 glutDestroyWindow(Win); 140 exit(0); 141 } 142 glutPostRedisplay(); 143} 144 145static void SpecialKey( int key, int x, int y ) 146{ 147 const GLfloat step = 3.0; 148 (void) x; 149 (void) y; 150 switch (key) { 151 case GLUT_KEY_UP: 152 Xrot -= step; 153 break; 154 case GLUT_KEY_DOWN: 155 Xrot += step; 156 break; 157 case GLUT_KEY_LEFT: 158 Yrot -= step; 159 break; 160 case GLUT_KEY_RIGHT: 161 Yrot += step; 162 break; 163 } 164 glutPostRedisplay(); 165} 166 167 168static void Init( void ) 169{ 170 static const char *fragProgramText = 171 "!!FP1.0\n" 172 "DECLARE Diffuse; \n" 173 "DECLARE Specular; \n" 174 "DECLARE LightPos; \n" 175 176 "# Compute normalized LightPos, put it in R0\n" 177 "DP3 R0.x, LightPos, LightPos;\n" 178 "RSQ R0.y, R0.x;\n" 179 "MUL R0, LightPos, R0.y;\n" 180 181 "# Compute normalized normal, put it in R1\n" 182 "DP3 R1, f[TEX0], f[TEX0]; \n" 183 "RSQ R1.y, R1.x;\n" 184 "MUL R1, f[TEX0], R1.y;\n" 185 186 "# Compute dot product of light direction and normal vector\n" 187 "DP3_SAT R2, R0, R1;" 188 189 "MUL R3, Diffuse, R2; # diffuse attenuation\n" 190 191 "POW R4, R2.x, {20.0}.x; # specular exponent\n" 192 193 "MUL R5, Specular, R4; # specular attenuation\n" 194 195 "ADD o[COLR], R3, R5; # add diffuse and specular colors\n" 196 "END \n" 197 ; 198 199 static const char *vertProgramText = 200 "!!VP1.0\n" 201 "# typical modelview/projection transform\n" 202 "DP4 o[HPOS].x, c[0], v[OPOS] ;\n" 203 "DP4 o[HPOS].y, c[1], v[OPOS] ;\n" 204 "DP4 o[HPOS].z, c[2], v[OPOS] ;\n" 205 "DP4 o[HPOS].w, c[3], v[OPOS] ;\n" 206 "# transform normal by inv transpose of modelview, put in tex0\n" 207 "DP3 o[TEX0].x, c[4], v[NRML] ;\n" 208 "DP3 o[TEX0].y, c[5], v[NRML] ;\n" 209 "DP3 o[TEX0].z, c[6], v[NRML] ;\n" 210 "DP3 o[TEX0].w, c[7], v[NRML] ;\n" 211 "END\n"; 212 ; 213 214 if (!glutExtensionSupported("GL_NV_vertex_program")) { 215 printf("Sorry, this demo requires GL_NV_vertex_program\n"); 216 exit(1); 217 } 218 if (!glutExtensionSupported("GL_NV_fragment_program")) { 219 printf("Sorry, this demo requires GL_NV_fragment_program\n"); 220 exit(1); 221 } 222 223#if defined(GL_NV_fragment_program) 224 glGenProgramsNV(1, &FragProg); 225 assert(FragProg > 0); 226 glGenProgramsNV(1, &VertProg); 227 assert(VertProg > 0); 228 229 /* 230 * Fragment program 231 */ 232 glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg, 233 strlen(fragProgramText), 234 (const GLubyte *) fragProgramText); 235 assert(glIsProgramNV(FragProg)); 236 glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg); 237 238 NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse); 239 NAMED_PARAMETER4FV(FragProg, "Specular", Specular); 240 241 /* 242 * Vertex program 243 */ 244 glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg, 245 strlen(vertProgramText), 246 (const GLubyte *) vertProgramText); 247 assert(glIsProgramNV(VertProg)); 248 glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg); 249 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV); 250 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV); 251#endif 252 253 /* 254 * Misc init 255 */ 256 glClearColor(0.3, 0.3, 0.3, 0.0); 257 glEnable(GL_DEPTH_TEST); 258 glEnable(GL_LIGHT0); 259 glEnable(GL_LIGHTING); 260 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse); 261 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular); 262 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0); 263 264 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 265 printf("Press p to toggle between per-pixel and per-vertex lighting\n"); 266} 267 268 269int main( int argc, char *argv[] ) 270{ 271 glutInitWindowSize( 200, 200 ); 272 glutInit( &argc, argv ); 273 glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); 274 Win = glutCreateWindow(argv[0]); 275 glewInit(); 276 glutReshapeFunc( Reshape ); 277 glutKeyboardFunc( Key ); 278 glutSpecialFunc( SpecialKey ); 279 glutDisplayFunc( Display ); 280 if (Anim) 281 glutIdleFunc(Idle); 282 Init(); 283 glutMainLoop(); 284 return 0; 285} 286