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