1/* 2 * Use GL_ARB_fragment_shader and GL_ARB_vertex_shader to implement 3 * simple per-pixel lighting. 4 * 5 * Michal Krol 6 * 20 February 2006 7 * 8 * Based on the original demo by: 9 * Brian Paul 10 * 17 April 2003 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <math.h> 16#include <GL/glew.h> 17#include "glut_wrap.h" 18 19static GLfloat diffuse[4] = { 0.5f, 0.5f, 1.0f, 1.0f }; 20static GLfloat specular[4] = { 0.8f, 0.8f, 0.8f, 1.0f }; 21static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 1.0f }; 22 23static GLfloat delta = 1.0f; 24 25static GLhandleARB fragShader; 26static GLhandleARB vertShader; 27static GLhandleARB program; 28 29static GLint uLightPos; 30static GLint uDiffuse; 31static GLint uSpecular; 32 33static GLboolean anim = GL_TRUE; 34static GLboolean wire = GL_FALSE; 35static GLboolean pixelLight = GL_TRUE; 36 37static GLint t0 = 0; 38static GLint frames = 0; 39 40static GLfloat xRot = 0.0f, yRot = 0.0f; 41 42static void 43normalize(GLfloat * dst, const GLfloat * src) 44{ 45 GLfloat len = sqrt(src[0] * src[0] + src[1] * src[1] + src[2] * src[2]); 46 dst[0] = src[0] / len; 47 dst[1] = src[1] / len; 48 dst[2] = src[2] / len; 49} 50 51static void 52Redisplay(void) 53{ 54 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 55 56 if (pixelLight) { 57 GLfloat vec[3]; 58 59 glUseProgramObjectARB(program); 60 normalize(vec, lightPos); 61 glUniform3fvARB(uLightPos, 1, vec); 62 glDisable(GL_LIGHTING); 63 } 64 else { 65 glUseProgramObjectARB(0); 66 glLightfv(GL_LIGHT0, GL_POSITION, lightPos); 67 glEnable(GL_LIGHTING); 68 } 69 70 glPushMatrix(); 71 glRotatef(xRot, 1.0f, 0.0f, 0.0f); 72 glRotatef(yRot, 0.0f, 1.0f, 0.0f); 73 glutSolidSphere(2.0, 10, 5); 74 glPopMatrix(); 75 76 glutSwapBuffers(); 77 frames++; 78 79 if (anim) { 80 GLint t = glutGet(GLUT_ELAPSED_TIME); 81 if (t - t0 >= 5000) { 82 GLfloat seconds = (GLfloat) (t - t0) / 1000.0f; 83 GLfloat fps = frames / seconds; 84 printf("%d frames in %6.3f seconds = %6.3f FPS\n", frames, seconds, 85 fps); 86 fflush(stdout); 87 t0 = t; 88 frames = 0; 89 } 90 } 91} 92 93static void 94Idle(void) 95{ 96 lightPos[0] += delta; 97 if (lightPos[0] > 25.0f || lightPos[0] < -25.0f) 98 delta = -delta; 99 glutPostRedisplay(); 100} 101 102static void 103Reshape(int width, int height) 104{ 105 glViewport(0, 0, width, height); 106 glMatrixMode(GL_PROJECTION); 107 glLoadIdentity(); 108 glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 25.0); 109 glMatrixMode(GL_MODELVIEW); 110 glLoadIdentity(); 111 glTranslatef(0.0f, 0.0f, -15.0f); 112} 113 114static void 115Key(unsigned char key, int x, int y) 116{ 117 (void) x; 118 (void) y; 119 120 switch (key) { 121 case ' ': 122 case 'a': 123 anim = !anim; 124 if (anim) 125 glutIdleFunc(Idle); 126 else 127 glutIdleFunc(NULL); 128 break; 129 case 'x': 130 lightPos[0] -= 1.0f; 131 break; 132 case 'X': 133 lightPos[0] += 1.0f; 134 break; 135 case 'w': 136 wire = !wire; 137 if (wire) 138 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 139 else 140 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 141 break; 142 case 'p': 143 pixelLight = !pixelLight; 144 if (pixelLight) 145 printf("Per-pixel lighting\n"); 146 else 147 printf("Conventional lighting\n"); 148 break; 149 case 27: 150 exit(0); 151 break; 152 } 153 glutPostRedisplay(); 154} 155 156static void 157SpecialKey(int key, int x, int y) 158{ 159 const GLfloat step = 3.0f; 160 161 (void) x; 162 (void) y; 163 164 switch (key) { 165 case GLUT_KEY_UP: 166 xRot -= step; 167 break; 168 case GLUT_KEY_DOWN: 169 xRot += step; 170 break; 171 case GLUT_KEY_LEFT: 172 yRot -= step; 173 break; 174 case GLUT_KEY_RIGHT: 175 yRot += step; 176 break; 177 } 178 glutPostRedisplay(); 179} 180 181static void 182Init(void) 183{ 184 static const char *fragShaderText = 185 "uniform vec3 lightPos;\n" 186 "uniform vec4 diffuse;\n" 187 "uniform vec4 specular;\n" 188 "varying vec3 normal;\n" 189 "void main () {\n" 190 " // Compute dot product of light direction and normal vector\n" 191 " float dotProd = max(dot(lightPos, normalize(normal)), 0.0);\n" 192 " // Compute diffuse and specular contributions\n" 193 " gl_FragColor = diffuse * dotProd + specular * pow(dotProd, 20.0);\n" 194 "}\n"; 195 static const char *vertShaderText = 196 "varying vec3 normal;\n" 197 "void main () {\n" 198 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" 199 " normal = gl_NormalMatrix * gl_Normal;\n" 200 "}\n"; 201 202 if (!glutExtensionSupported("GL_ARB_fragment_shader")) { 203 printf("Sorry, this demo requires GL_ARB_fragment_shader\n"); 204 exit(1); 205 } 206 if (!glutExtensionSupported("GL_ARB_shader_objects")) { 207 printf("Sorry, this demo requires GL_ARB_shader_objects\n"); 208 exit(1); 209 } 210 if (!glutExtensionSupported("GL_ARB_shading_language_100")) { 211 printf("Sorry, this demo requires GL_ARB_shading_language_100\n"); 212 exit(1); 213 } 214 if (!glutExtensionSupported("GL_ARB_vertex_shader")) { 215 printf("Sorry, this demo requires GL_ARB_vertex_shader\n"); 216 exit(1); 217 } 218 219 fragShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 220 glShaderSourceARB(fragShader, 1, &fragShaderText, NULL); 221 glCompileShaderARB(fragShader); 222 223 vertShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); 224 glShaderSourceARB(vertShader, 1, &vertShaderText, NULL); 225 glCompileShaderARB(vertShader); 226 227 program = glCreateProgramObjectARB(); 228 glAttachObjectARB(program, fragShader); 229 glAttachObjectARB(program, vertShader); 230 glLinkProgramARB(program); 231 glUseProgramObjectARB(program); 232 233 uLightPos = glGetUniformLocationARB(program, "lightPos"); 234 uDiffuse = glGetUniformLocationARB(program, "diffuse"); 235 uSpecular = glGetUniformLocationARB(program, "specular"); 236 237 glUniform4fvARB(uDiffuse, 1, diffuse); 238 glUniform4fvARB(uSpecular, 1, specular); 239 240 glClearColor(0.3f, 0.3f, 0.3f, 0.0f); 241 glEnable(GL_DEPTH_TEST); 242 glEnable(GL_LIGHT0); 243 glEnable(GL_LIGHTING); 244 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse); 245 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); 246 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0f); 247 248 printf("GL_RENDERER = %s\n", (const char *) glGetString(GL_RENDERER)); 249 printf("Press p to toggle between per-pixel and per-vertex lighting\n"); 250} 251 252int 253main(int argc, char *argv[]) 254{ 255 glutInitWindowSize(200, 200); 256 glutInit(&argc, argv); 257 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); 258 glutCreateWindow(argv[0]); 259 glewInit(); 260 glutReshapeFunc(Reshape); 261 glutKeyboardFunc(Key); 262 glutSpecialFunc(SpecialKey); 263 glutDisplayFunc(Redisplay); 264 if (anim) 265 glutIdleFunc(Idle); 266 Init(); 267 glutMainLoop(); 268 return 0; 269} 270