1/**
2 * Test two-sided lighting with shaders.
3 * Both GL_VERTEX_PROGRAM_TWO_SIDE and gl_FrontFacing can be tested
4 * (see keys below).
5 *
6 * Brian Paul
7 * 18 Dec 2007
8 */
9
10#include <assert.h>
11#include <string.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <math.h>
15#include <GL/glew.h>
16#include "glut_wrap.h"
17#include "shaderutil.h"
18
19#ifndef M_PI
20#define M_PI 3.1415926535
21#endif
22
23static GLint WinWidth = 300, WinHeight = 300;
24static char *FragProgFile = NULL;
25static char *VertProgFile = NULL;
26static GLuint fragShader;
27static GLuint vertShader;
28static GLuint program;
29static GLint win = 0;
30static GLboolean anim;
31static GLboolean DetermineFacingInFragProg;
32static GLfloat Xrot;
33static GLint u_fragface;
34static GLenum FrontWinding;
35static int prevTime = 0;
36
37
38static const GLfloat Red[4] = {1, 0, 0, 1};
39static const GLfloat Green[4] = {0, 1, 0, 0};
40
41
42static void
43SetDefaults(void)
44{
45   DetermineFacingInFragProg = GL_TRUE;
46   FrontWinding = GL_CCW;
47   Xrot = 30;
48   anim = 0;
49   glutIdleFunc(NULL);
50}
51
52
53static void
54Redisplay(void)
55{
56   const int sections = 20;
57   int i;
58   float radius = 2;
59
60   glFrontFace(FrontWinding);
61
62   if (DetermineFacingInFragProg) {
63      glUniform1i(u_fragface, 1);
64      glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
65   }
66   else {
67      glUniform1i(u_fragface, 0);
68      glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
69   }
70
71   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
72
73   glPushMatrix();
74   glRotatef(Xrot, 1, 0, 0);
75
76   /* Draw a tristrip ring */
77   glBegin(GL_TRIANGLE_STRIP);
78   glColor4fv(Red);
79   glSecondaryColor3fv(Green);
80   for (i = 0; i <= sections; i++) {
81      float a = (float) i / (sections) * M_PI * 2.0;
82      float x = radius * cos(a);
83      float y = radius * sin(a);
84      glVertex3f(x, -1, y);
85      glVertex3f(x, +1, y);
86   }
87   glEnd();
88
89   glPopMatrix();
90
91   glutSwapBuffers();
92}
93
94
95static void
96Idle(void)
97{
98   int curTime = glutGet(GLUT_ELAPSED_TIME);
99   int dt = curTime - prevTime;
100
101   if (prevTime == 0) {
102      prevTime = curTime;
103      return;
104   }
105   prevTime = curTime;
106
107   Xrot += dt * 0.1;
108   glutPostRedisplay();
109}
110
111
112static void
113Reshape(int width, int height)
114{
115   float ar = (float) width / height;
116   glViewport(0, 0, width, height);
117   glMatrixMode(GL_PROJECTION);
118   glLoadIdentity();
119   glFrustum(-ar, ar, -1, 1, 3, 25);
120   glMatrixMode(GL_MODELVIEW);
121   glLoadIdentity();
122   glTranslatef(0, 0, -10);
123}
124
125
126static void
127CleanUp(void)
128{
129   glDeleteShader(fragShader);
130   glDeleteShader(vertShader);
131   glDeleteProgram(program);
132   glutDestroyWindow(win);
133}
134
135
136static void
137Key(unsigned char key, int x, int y)
138{
139  (void) x;
140  (void) y;
141
142   switch(key) {
143   case ' ':
144   case 'a':
145      anim = !anim;
146      if (anim) {
147         prevTime = glutGet(GLUT_ELAPSED_TIME);
148         glutIdleFunc(Idle);
149      }
150      else
151         glutIdleFunc(NULL);
152      break;
153   case 'f':
154      printf("Using frag shader gl_FrontFacing\n");
155      DetermineFacingInFragProg = GL_TRUE;
156      break;
157   case 'v':
158      printf("Using vert shader Two-sided lighting\n");
159      DetermineFacingInFragProg = GL_FALSE;
160      break;
161   case 'r':
162      /* reset */
163      SetDefaults();
164      break;
165   case 's':
166      Xrot += 5;
167      break;
168   case 'S':
169      Xrot -= 5;
170      break;
171   case 'w':
172      if (FrontWinding == GL_CCW) {
173         FrontWinding = GL_CW;
174         printf("FrontFace = GL_CW\n");
175      }
176      else {
177         FrontWinding = GL_CCW;
178         printf("FrontFace = GL_CCW\n");
179      }
180      break;
181   case 27:
182      CleanUp();
183      exit(0);
184      break;
185   }
186   glutPostRedisplay();
187}
188
189
190static void
191Init(void)
192{
193   static const char *fragShaderText =
194      "uniform bool fragface; \n"
195      "void main() { \n"
196#if 1
197      "   if (!fragface || gl_FrontFacing) { \n"
198      "      gl_FragColor = gl_Color; \n"
199      "   } \n"
200      "   else { \n"
201      "      // note: dim green to help debug \n"
202      "      gl_FragColor = 0.8 * gl_SecondaryColor; \n"
203      "   } \n"
204#else
205      /* DEBUG CODE */
206      "   bool f = gl_FrontFacing; \n"
207      "   if (f) { \n"
208      "      gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0); \n"
209      "   } \n"
210      "   else { \n"
211      "      gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0); \n"
212      "   } \n"
213#endif
214      "} \n";
215   static const char *vertShaderText =
216      "uniform bool fragface; \n"
217      "void main() { \n"
218      "   gl_FrontColor = gl_Color; \n"
219      "   if (fragface) { \n"
220      "      // front/back chosen in frag prog \n"
221      "      gl_FrontSecondaryColor = gl_SecondaryColor; \n"
222      "   } \n"
223      "   else { \n"
224      "      // front/back chosen in prim setup \n"
225      "      gl_BackColor = gl_SecondaryColor; \n"
226      "   } \n"
227      "   gl_Position = ftransform(); \n"
228      "} \n";
229
230   if (!ShadersSupported())
231      exit(1);
232
233   vertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
234   fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
235   program = LinkShaders(vertShader, fragShader);
236
237   glUseProgram(program);
238
239   u_fragface = glGetUniformLocation(program, "fragface");
240   printf("Uniforms: %d\n", u_fragface);
241
242   /*assert(glGetError() == 0);*/
243
244   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
245
246   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
247
248   assert(glIsProgram(program));
249   assert(glIsShader(fragShader));
250   assert(glIsShader(vertShader));
251
252   glEnable(GL_DEPTH_TEST);
253
254   SetDefaults();
255}
256
257
258static void
259ParseOptions(int argc, char *argv[])
260{
261   int i;
262   for (i = 1; i < argc; i++) {
263      if (strcmp(argv[i], "-fs") == 0) {
264         FragProgFile = argv[i+1];
265      }
266      else if (strcmp(argv[i], "-vs") == 0) {
267         VertProgFile = argv[i+1];
268      }
269   }
270}
271
272
273static void
274Usage(void)
275{
276   printf("Keys:\n");
277   printf("   f - do front/back determination in fragment shader\n");
278   printf("   v - do front/back determination in vertex shader\n");
279   printf("   r - reset, show front\n");
280   printf("   a - toggle animation\n");
281   printf("   s - step rotation\n");
282   printf("   w - toggle CW, CCW front-face winding\n");
283   printf("NOTE: red = front face, green = back face.\n");
284}
285
286
287int
288main(int argc, char *argv[])
289{
290   glutInit(&argc, argv);
291   glutInitWindowSize(WinWidth, WinHeight);
292   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
293   win = glutCreateWindow(argv[0]);
294   glewInit();
295   glutReshapeFunc(Reshape);
296   glutKeyboardFunc(Key);
297   glutDisplayFunc(Redisplay);
298   if (anim)
299      glutIdleFunc(Idle);
300   ParseOptions(argc, argv);
301   Init();
302   Usage();
303   glutMainLoop();
304   return 0;
305}
306