blob: 39c9226b3d95483d889a5cb6417b78d79834a019 [file] [log] [blame]
Michal Krol36997512006-02-15 10:58:52 +00001/*
2 * Use GL_ARB_fragment_shader and GL_ARB_vertex_shader to implement
Michal Krol6acf1e92006-04-25 10:11:59 +00003 * simple per-pixel lighting.
4 *
5 * Michal Krol
Michal Krolcc159162006-02-21 12:35:06 +00006 * 20 February 2006
Michal Krol6acf1e92006-04-25 10:11:59 +00007 *
Michal Krol36997512006-02-15 10:58:52 +00008 * Based on the original demo by:
9 * Brian Paul
10 * 17 April 2003
Michal Krol6acf1e92006-04-25 10:11:59 +000011 */
12
13#ifdef WIN32
14#include <windows.h>
Michal Krol36541932006-02-18 15:11:18 +000015#endif
Michal Krol36997512006-02-15 10:58:52 +000016
17#include <stdio.h>
Michal Krol6acf1e92006-04-25 10:11:59 +000018#include <stdlib.h>
Michal Krol1616f5b2006-08-02 14:46:50 +000019#include <math.h>
Michal Krol36541932006-02-18 15:11:18 +000020#include <GL/gl.h>
Michal Krol6acf1e92006-04-25 10:11:59 +000021#include <GL/glut.h>
22#include <GL/glext.h>
23
24#ifdef WIN32
25#define GETPROCADDRESS wglGetProcAddress
26#else
27#define GETPROCADDRESS glutGetProcAddress
28#endif
Michal Krol36997512006-02-15 10:58:52 +000029
30static GLfloat diffuse[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
31static GLfloat specular[4] = { 0.8f, 0.8f, 0.8f, 1.0f };
32static GLfloat lightPos[4] = { 0.0f, 10.0f, 20.0f, 1.0f };
33static GLfloat delta = 1.0f;
34
35static GLhandleARB fragShader;
Michal Krol6acf1e92006-04-25 10:11:59 +000036static GLhandleARB vertShader;
37static GLhandleARB program;
38
39static GLint uLightPos;
40static GLint uDiffuse;
41static GLint uSpecular;
Michal Krol36997512006-02-15 10:58:52 +000042
43static GLboolean anim = GL_TRUE;
44static GLboolean wire = GL_FALSE;
45static GLboolean pixelLight = GL_TRUE;
46
47static GLint t0 = 0;
48static GLint frames = 0;
49
Michal Krol6acf1e92006-04-25 10:11:59 +000050static GLfloat xRot = 0.0f, yRot = 0.0f;
51
52static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
53static PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
54static PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
55static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
56static PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
57static PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
58static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
59static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
Michal Krol1616f5b2006-08-02 14:46:50 +000060static PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
61static PFNGLUNIFORM3FVARBPROC glUniform4fvARB = NULL;
62
63static void normalize (GLfloat *dst, const GLfloat *src)
64{
Brian4a285482007-04-26 07:46:38 -060065 GLfloat len = sqrt (src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
Michal Krol1616f5b2006-08-02 14:46:50 +000066 dst[0] = src[0] / len;
67 dst[1] = src[1] / len;
68 dst[2] = src[2] / len;
69}
Michal Krol36997512006-02-15 10:58:52 +000070
71static void Redisplay (void)
72{
73 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
74
Michal Krol6acf1e92006-04-25 10:11:59 +000075 if (pixelLight)
76 {
Michal Krol1616f5b2006-08-02 14:46:50 +000077 GLfloat vec[3];
78
Michal Krol6acf1e92006-04-25 10:11:59 +000079 glUseProgramObjectARB (program);
Michal Krol1616f5b2006-08-02 14:46:50 +000080 normalize (vec, lightPos);
81 glUniform3fvARB (uLightPos, 1, vec);
Michal Krol36997512006-02-15 10:58:52 +000082 glDisable(GL_LIGHTING);
83 }
Michal Krol6acf1e92006-04-25 10:11:59 +000084 else
85 {
Michal Krol36997512006-02-15 10:58:52 +000086 glUseProgramObjectARB (0);
87 glLightfv (GL_LIGHT0, GL_POSITION, lightPos);
88 glEnable(GL_LIGHTING);
89 }
90
91 glPushMatrix ();
92 glRotatef (xRot, 1.0f, 0.0f, 0.0f);
93 glRotatef (yRot, 0.0f, 1.0f, 0.0f);
Michal Krol6acf1e92006-04-25 10:11:59 +000094 glutSolidSphere (2.0, 10, 5);
Michal Krol36997512006-02-15 10:58:52 +000095 glPopMatrix ();
96
97 glutSwapBuffers();
98 frames++;
99
Michal Krol6acf1e92006-04-25 10:11:59 +0000100 if (anim)
Michal Krol36997512006-02-15 10:58:52 +0000101 {
102 GLint t = glutGet (GLUT_ELAPSED_TIME);
Michal Krol6acf1e92006-04-25 10:11:59 +0000103 if (t - t0 >= 5000)
Michal Krol36997512006-02-15 10:58:52 +0000104 {
105 GLfloat seconds = (GLfloat) (t - t0) / 1000.0f;
106 GLfloat fps = frames / seconds;
107 printf ("%d frames in %6.3f seconds = %6.3f FPS\n", frames, seconds, fps);
108 t0 = t;
109 frames = 0;
110 }
111 }
112}
113
114static void Idle (void)
115{
116 lightPos[0] += delta;
117 if (lightPos[0] > 25.0f || lightPos[0] < -25.0f)
118 delta = -delta;
119 glutPostRedisplay ();
120}
121
122static void Reshape (int width, int height)
123{
124 glViewport (0, 0, width, height);
125 glMatrixMode (GL_PROJECTION);
126 glLoadIdentity ();
127 glFrustum (-1.0, 1.0, -1.0, 1.0, 5.0, 25.0);
128 glMatrixMode (GL_MODELVIEW);
129 glLoadIdentity ();
130 glTranslatef (0.0f, 0.0f, -15.0f);
131}
132
133static void Key (unsigned char key, int x, int y)
134{
135 (void) x;
Michal Krol6acf1e92006-04-25 10:11:59 +0000136 (void) y;
Michal Krol36997512006-02-15 10:58:52 +0000137
Michal Krol6acf1e92006-04-25 10:11:59 +0000138 switch (key)
Michal Krol36997512006-02-15 10:58:52 +0000139 {
140 case ' ':
141 case 'a':
142 anim = !anim;
143 if (anim)
144 glutIdleFunc (Idle);
145 else
146 glutIdleFunc (NULL);
147 break;
148 case 'x':
149 lightPos[0] -= 1.0f;
150 break;
151 case 'X':
152 lightPos[0] += 1.0f;
153 break;
154 case 'w':
155 wire = !wire;
156 if (wire)
157 glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
158 else
159 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
160 break;
161 case 'p':
162 pixelLight = !pixelLight;
163 if (pixelLight)
164 printf ("Per-pixel lighting\n");
165 else
166 printf ("Conventional lighting\n");
167 break;
168 case 27:
169 exit(0);
170 break;
171 }
172 glutPostRedisplay ();
173}
174
175static void SpecialKey (int key, int x, int y)
176{
Michal Krol6acf1e92006-04-25 10:11:59 +0000177 const GLfloat step = 3.0f;
Michal Krol36997512006-02-15 10:58:52 +0000178
179 (void) x;
Michal Krol6acf1e92006-04-25 10:11:59 +0000180 (void) y;
Michal Krol36997512006-02-15 10:58:52 +0000181
Michal Krol6acf1e92006-04-25 10:11:59 +0000182 switch (key)
Michal Krol36997512006-02-15 10:58:52 +0000183 {
184 case GLUT_KEY_UP:
185 xRot -= step;
186 break;
187 case GLUT_KEY_DOWN:
188 xRot += step;
189 break;
190 case GLUT_KEY_LEFT:
191 yRot -= step;
192 break;
193 case GLUT_KEY_RIGHT:
194 yRot += step;
195 break;
196 }
197 glutPostRedisplay ();
198}
199
200static void Init (void)
201{
Michal Krol1616f5b2006-08-02 14:46:50 +0000202 static const char *fragShaderText =
203 "uniform vec3 lightPos;\n"
204 "uniform vec4 diffuse;\n"
205 "uniform vec4 specular;\n"
206 "varying vec3 normal;\n"
207 "void main () {\n"
208 " // Compute dot product of light direction and normal vector\n"
209 " float dotProd = max (dot (lightPos, normalize (normal)), 0.0);\n"
210 " // Compute diffuse and specular contributions\n"
Brian9405ec62007-09-28 21:04:56 -0600211#if 0
Michal Krol1616f5b2006-08-02 14:46:50 +0000212 " gl_FragColor = diffuse * dotProd + specular * pow (dotProd, 20.0);\n"
Brian9405ec62007-09-28 21:04:56 -0600213#else
214 " if (normal.y > 0.0) { \n"
215 " gl_FragColor = diffuse * dotProd + specular * pow (dotProd, 20.0);\n"
216 " } \n"
217 " else { \n"
218 " if (normal.x < 0.0) { \n"
219 " gl_FragColor = vec4(1, 0, 0, 0); \n"
220 " } \n"
221 " else { \n"
222 " gl_FragColor = vec4(1, 1, 0, 0); \n"
223 " } \n"
224 " } \n"
225#endif
Michal Krol1616f5b2006-08-02 14:46:50 +0000226 "}\n"
227 ;
228 static const char *vertShaderText =
229 "varying vec3 normal;\n"
230 "void main () {\n"
231 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
232 " normal = gl_NormalMatrix * gl_Normal;\n"
233 "}\n"
234 ;
Michal Krol6acf1e92006-04-25 10:11:59 +0000235
236 if (!glutExtensionSupported ("GL_ARB_fragment_shader"))
Michal Krol36997512006-02-15 10:58:52 +0000237 {
238 printf ("Sorry, this demo requires GL_ARB_fragment_shader\n");
239 exit(1);
Michal Krol6acf1e92006-04-25 10:11:59 +0000240 }
241 if (!glutExtensionSupported ("GL_ARB_shader_objects"))
242 {
243 printf ("Sorry, this demo requires GL_ARB_shader_objects\n");
244 exit(1);
245 }
246 if (!glutExtensionSupported ("GL_ARB_shading_language_100"))
247 {
248 printf ("Sorry, this demo requires GL_ARB_shading_language_100\n");
249 exit(1);
250 }
251 if (!glutExtensionSupported ("GL_ARB_vertex_shader"))
252 {
253 printf ("Sorry, this demo requires GL_ARB_vertex_shader\n");
254 exit(1);
Michal Krol36997512006-02-15 10:58:52 +0000255 }
256
Michal Krol6acf1e92006-04-25 10:11:59 +0000257 glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GETPROCADDRESS ("glCreateShaderObjectARB");
258 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GETPROCADDRESS ("glShaderSourceARB");
259 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GETPROCADDRESS ("glCompileShaderARB");
260 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GETPROCADDRESS ("glCreateProgramObjectARB");
261 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GETPROCADDRESS ("glAttachObjectARB");
262 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GETPROCADDRESS ("glLinkProgramARB");
263 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GETPROCADDRESS ("glUseProgramObjectARB");
264 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GETPROCADDRESS ("glGetUniformLocationARB");
Michal Krol1616f5b2006-08-02 14:46:50 +0000265 glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GETPROCADDRESS ("glUniform3fvARB");
266 glUniform4fvARB = (PFNGLUNIFORM3FVARBPROC) GETPROCADDRESS ("glUniform4fvARB");
Michal Krol6acf1e92006-04-25 10:11:59 +0000267
268 fragShader = glCreateShaderObjectARB (GL_FRAGMENT_SHADER_ARB);
269 glShaderSourceARB (fragShader, 1, &fragShaderText, NULL);
Michal Krol36997512006-02-15 10:58:52 +0000270 glCompileShaderARB (fragShader);
Michal Krol6acf1e92006-04-25 10:11:59 +0000271
272 vertShader = glCreateShaderObjectARB (GL_VERTEX_SHADER_ARB);
273 glShaderSourceARB (vertShader, 1, &vertShaderText, NULL);
274 glCompileShaderARB (vertShader);
275
276 program = glCreateProgramObjectARB ();
277 glAttachObjectARB (program, fragShader);
278 glAttachObjectARB (program, vertShader);
279 glLinkProgramARB (program);
280 glUseProgramObjectARB (program);
281
282 uLightPos = glGetUniformLocationARB (program, "lightPos");
283 uDiffuse = glGetUniformLocationARB (program, "diffuse");
284 uSpecular = glGetUniformLocationARB (program, "specular");
285
Michal Krol1616f5b2006-08-02 14:46:50 +0000286 glUniform4fvARB (uDiffuse, 1, diffuse);
287 glUniform4fvARB (uSpecular, 1, specular);
Michal Krol36997512006-02-15 10:58:52 +0000288
289 glClearColor (0.3f, 0.3f, 0.3f, 0.0f);
290 glEnable (GL_DEPTH_TEST);
Michal Krol6acf1e92006-04-25 10:11:59 +0000291 glEnable (GL_LIGHT0);
Michal Krol36997512006-02-15 10:58:52 +0000292 glEnable (GL_LIGHTING);
293 glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
294 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
295 glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 20.0f);
296
297 printf ("GL_RENDERER = %s\n", (const char *) glGetString (GL_RENDERER));
298 printf ("Press p to toggle between per-pixel and per-vertex lighting\n");
299}
300
301int main (int argc, char *argv[])
302{
303 glutInit (&argc, argv);
304 glutInitWindowPosition ( 0, 0);
305 glutInitWindowSize (200, 200);
306 glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
307 glutCreateWindow (argv[0]);
308 glutReshapeFunc (Reshape);
309 glutKeyboardFunc (Key);
310 glutSpecialFunc (SpecialKey);
311 glutDisplayFunc (Redisplay);
312 if (anim)
313 glutIdleFunc (Idle);
314 Init ();
315 glutMainLoop ();
316 return 0;
317}
Michal Krol6acf1e92006-04-25 10:11:59 +0000318