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