132001f49Smrg/**
232001f49Smrg * Test two-sided lighting with shaders.
332001f49Smrg * Both GL_VERTEX_PROGRAM_TWO_SIDE and gl_FrontFacing can be tested
432001f49Smrg * (see keys below).
532001f49Smrg *
632001f49Smrg * Brian Paul
732001f49Smrg * 18 Dec 2007
832001f49Smrg */
932001f49Smrg
1032001f49Smrg#include <assert.h>
1132001f49Smrg#include <string.h>
1232001f49Smrg#include <stdio.h>
1332001f49Smrg#include <stdlib.h>
1432001f49Smrg#include <math.h>
1532001f49Smrg#include <GL/glew.h>
1632001f49Smrg#include "glut_wrap.h"
1732001f49Smrg#include "shaderutil.h"
1832001f49Smrg
1932001f49Smrg#ifndef M_PI
2032001f49Smrg#define M_PI 3.1415926535
2132001f49Smrg#endif
2232001f49Smrg
2332001f49Smrgstatic GLint WinWidth = 300, WinHeight = 300;
2432001f49Smrgstatic char *FragProgFile = NULL;
2532001f49Smrgstatic char *VertProgFile = NULL;
2632001f49Smrgstatic GLuint fragShader;
2732001f49Smrgstatic GLuint vertShader;
2832001f49Smrgstatic GLuint program;
2932001f49Smrgstatic GLint win = 0;
3032001f49Smrgstatic GLboolean anim;
3132001f49Smrgstatic GLboolean DetermineFacingInFragProg;
3232001f49Smrgstatic GLfloat Xrot;
3332001f49Smrgstatic GLint u_fragface;
3432001f49Smrgstatic GLenum FrontWinding;
3532001f49Smrgstatic int prevTime = 0;
3632001f49Smrg
3732001f49Smrg
3832001f49Smrgstatic const GLfloat Red[4] = {1, 0, 0, 1};
3932001f49Smrgstatic const GLfloat Green[4] = {0, 1, 0, 0};
4032001f49Smrg
4132001f49Smrg
4232001f49Smrgstatic void
4332001f49SmrgSetDefaults(void)
4432001f49Smrg{
4532001f49Smrg   DetermineFacingInFragProg = GL_TRUE;
4632001f49Smrg   FrontWinding = GL_CCW;
4732001f49Smrg   Xrot = 30;
4832001f49Smrg   anim = 0;
4932001f49Smrg   glutIdleFunc(NULL);
5032001f49Smrg}
5132001f49Smrg
5232001f49Smrg
5332001f49Smrgstatic void
5432001f49SmrgRedisplay(void)
5532001f49Smrg{
5632001f49Smrg   const int sections = 20;
5732001f49Smrg   int i;
5832001f49Smrg   float radius = 2;
5932001f49Smrg
6032001f49Smrg   glFrontFace(FrontWinding);
6132001f49Smrg
6232001f49Smrg   if (DetermineFacingInFragProg) {
6332001f49Smrg      glUniform1i(u_fragface, 1);
6432001f49Smrg      glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
6532001f49Smrg   }
6632001f49Smrg   else {
6732001f49Smrg      glUniform1i(u_fragface, 0);
6832001f49Smrg      glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
6932001f49Smrg   }
7032001f49Smrg
7132001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
7232001f49Smrg
7332001f49Smrg   glPushMatrix();
7432001f49Smrg   glRotatef(Xrot, 1, 0, 0);
7532001f49Smrg
7632001f49Smrg   /* Draw a tristrip ring */
7732001f49Smrg   glBegin(GL_TRIANGLE_STRIP);
7832001f49Smrg   glColor4fv(Red);
7932001f49Smrg   glSecondaryColor3fv(Green);
8032001f49Smrg   for (i = 0; i <= sections; i++) {
8132001f49Smrg      float a = (float) i / (sections) * M_PI * 2.0;
8232001f49Smrg      float x = radius * cos(a);
8332001f49Smrg      float y = radius * sin(a);
8432001f49Smrg      glVertex3f(x, -1, y);
8532001f49Smrg      glVertex3f(x, +1, y);
8632001f49Smrg   }
8732001f49Smrg   glEnd();
8832001f49Smrg
8932001f49Smrg   glPopMatrix();
9032001f49Smrg
9132001f49Smrg   glutSwapBuffers();
9232001f49Smrg}
9332001f49Smrg
9432001f49Smrg
9532001f49Smrgstatic void
9632001f49SmrgIdle(void)
9732001f49Smrg{
9832001f49Smrg   int curTime = glutGet(GLUT_ELAPSED_TIME);
9932001f49Smrg   int dt = curTime - prevTime;
10032001f49Smrg
10132001f49Smrg   if (prevTime == 0) {
10232001f49Smrg      prevTime = curTime;
10332001f49Smrg      return;
10432001f49Smrg   }
10532001f49Smrg   prevTime = curTime;
10632001f49Smrg
10732001f49Smrg   Xrot += dt * 0.1;
10832001f49Smrg   glutPostRedisplay();
10932001f49Smrg}
11032001f49Smrg
11132001f49Smrg
11232001f49Smrgstatic void
11332001f49SmrgReshape(int width, int height)
11432001f49Smrg{
11532001f49Smrg   float ar = (float) width / height;
11632001f49Smrg   glViewport(0, 0, width, height);
11732001f49Smrg   glMatrixMode(GL_PROJECTION);
11832001f49Smrg   glLoadIdentity();
11932001f49Smrg   glFrustum(-ar, ar, -1, 1, 3, 25);
12032001f49Smrg   glMatrixMode(GL_MODELVIEW);
12132001f49Smrg   glLoadIdentity();
12232001f49Smrg   glTranslatef(0, 0, -10);
12332001f49Smrg}
12432001f49Smrg
12532001f49Smrg
12632001f49Smrgstatic void
12732001f49SmrgCleanUp(void)
12832001f49Smrg{
12932001f49Smrg   glDeleteShader(fragShader);
13032001f49Smrg   glDeleteShader(vertShader);
13132001f49Smrg   glDeleteProgram(program);
13232001f49Smrg   glutDestroyWindow(win);
13332001f49Smrg}
13432001f49Smrg
13532001f49Smrg
13632001f49Smrgstatic void
13732001f49SmrgKey(unsigned char key, int x, int y)
13832001f49Smrg{
13932001f49Smrg  (void) x;
14032001f49Smrg  (void) y;
14132001f49Smrg
14232001f49Smrg   switch(key) {
14332001f49Smrg   case ' ':
14432001f49Smrg   case 'a':
14532001f49Smrg      anim = !anim;
14632001f49Smrg      if (anim) {
14732001f49Smrg         prevTime = glutGet(GLUT_ELAPSED_TIME);
14832001f49Smrg         glutIdleFunc(Idle);
14932001f49Smrg      }
15032001f49Smrg      else
15132001f49Smrg         glutIdleFunc(NULL);
15232001f49Smrg      break;
15332001f49Smrg   case 'f':
15432001f49Smrg      printf("Using frag shader gl_FrontFacing\n");
15532001f49Smrg      DetermineFacingInFragProg = GL_TRUE;
15632001f49Smrg      break;
15732001f49Smrg   case 'v':
15832001f49Smrg      printf("Using vert shader Two-sided lighting\n");
15932001f49Smrg      DetermineFacingInFragProg = GL_FALSE;
16032001f49Smrg      break;
16132001f49Smrg   case 'r':
16232001f49Smrg      /* reset */
16332001f49Smrg      SetDefaults();
16432001f49Smrg      break;
16532001f49Smrg   case 's':
16632001f49Smrg      Xrot += 5;
16732001f49Smrg      break;
16832001f49Smrg   case 'S':
16932001f49Smrg      Xrot -= 5;
17032001f49Smrg      break;
17132001f49Smrg   case 'w':
17232001f49Smrg      if (FrontWinding == GL_CCW) {
17332001f49Smrg         FrontWinding = GL_CW;
17432001f49Smrg         printf("FrontFace = GL_CW\n");
17532001f49Smrg      }
17632001f49Smrg      else {
17732001f49Smrg         FrontWinding = GL_CCW;
17832001f49Smrg         printf("FrontFace = GL_CCW\n");
17932001f49Smrg      }
18032001f49Smrg      break;
18132001f49Smrg   case 27:
18232001f49Smrg      CleanUp();
18332001f49Smrg      exit(0);
18432001f49Smrg      break;
18532001f49Smrg   }
18632001f49Smrg   glutPostRedisplay();
18732001f49Smrg}
18832001f49Smrg
18932001f49Smrg
19032001f49Smrgstatic void
19132001f49SmrgInit(void)
19232001f49Smrg{
19332001f49Smrg   static const char *fragShaderText =
19432001f49Smrg      "uniform bool fragface; \n"
19532001f49Smrg      "void main() { \n"
19632001f49Smrg#if 1
19732001f49Smrg      "   if (!fragface || gl_FrontFacing) { \n"
19832001f49Smrg      "      gl_FragColor = gl_Color; \n"
19932001f49Smrg      "   } \n"
20032001f49Smrg      "   else { \n"
20132001f49Smrg      "      // note: dim green to help debug \n"
20232001f49Smrg      "      gl_FragColor = 0.8 * gl_SecondaryColor; \n"
20332001f49Smrg      "   } \n"
20432001f49Smrg#else
20532001f49Smrg      /* DEBUG CODE */
20632001f49Smrg      "   bool f = gl_FrontFacing; \n"
20732001f49Smrg      "   if (f) { \n"
20832001f49Smrg      "      gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0); \n"
20932001f49Smrg      "   } \n"
21032001f49Smrg      "   else { \n"
21132001f49Smrg      "      gl_FragColor = vec4(0.0, 1.0, 0.0, 0.0); \n"
21232001f49Smrg      "   } \n"
21332001f49Smrg#endif
21432001f49Smrg      "} \n";
21532001f49Smrg   static const char *vertShaderText =
21632001f49Smrg      "uniform bool fragface; \n"
21732001f49Smrg      "void main() { \n"
21832001f49Smrg      "   gl_FrontColor = gl_Color; \n"
21932001f49Smrg      "   if (fragface) { \n"
22032001f49Smrg      "      // front/back chosen in frag prog \n"
22132001f49Smrg      "      gl_FrontSecondaryColor = gl_SecondaryColor; \n"
22232001f49Smrg      "   } \n"
22332001f49Smrg      "   else { \n"
22432001f49Smrg      "      // front/back chosen in prim setup \n"
22532001f49Smrg      "      gl_BackColor = gl_SecondaryColor; \n"
22632001f49Smrg      "   } \n"
22732001f49Smrg      "   gl_Position = ftransform(); \n"
22832001f49Smrg      "} \n";
22932001f49Smrg
23032001f49Smrg   if (!ShadersSupported())
23132001f49Smrg      exit(1);
23232001f49Smrg
23332001f49Smrg   vertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
23432001f49Smrg   fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
23532001f49Smrg   program = LinkShaders(vertShader, fragShader);
23632001f49Smrg
23732001f49Smrg   glUseProgram(program);
23832001f49Smrg
23932001f49Smrg   u_fragface = glGetUniformLocation(program, "fragface");
24032001f49Smrg   printf("Uniforms: %d\n", u_fragface);
24132001f49Smrg
24232001f49Smrg   /*assert(glGetError() == 0);*/
24332001f49Smrg
24432001f49Smrg   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
24532001f49Smrg
24632001f49Smrg   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
24732001f49Smrg
24832001f49Smrg   assert(glIsProgram(program));
24932001f49Smrg   assert(glIsShader(fragShader));
25032001f49Smrg   assert(glIsShader(vertShader));
25132001f49Smrg
25232001f49Smrg   glEnable(GL_DEPTH_TEST);
25332001f49Smrg
25432001f49Smrg   SetDefaults();
25532001f49Smrg}
25632001f49Smrg
25732001f49Smrg
25832001f49Smrgstatic void
25932001f49SmrgParseOptions(int argc, char *argv[])
26032001f49Smrg{
26132001f49Smrg   int i;
26232001f49Smrg   for (i = 1; i < argc; i++) {
26332001f49Smrg      if (strcmp(argv[i], "-fs") == 0) {
26432001f49Smrg         FragProgFile = argv[i+1];
26532001f49Smrg      }
26632001f49Smrg      else if (strcmp(argv[i], "-vs") == 0) {
26732001f49Smrg         VertProgFile = argv[i+1];
26832001f49Smrg      }
26932001f49Smrg   }
27032001f49Smrg}
27132001f49Smrg
27232001f49Smrg
27332001f49Smrgstatic void
27432001f49SmrgUsage(void)
27532001f49Smrg{
27632001f49Smrg   printf("Keys:\n");
27732001f49Smrg   printf("   f - do front/back determination in fragment shader\n");
27832001f49Smrg   printf("   v - do front/back determination in vertex shader\n");
27932001f49Smrg   printf("   r - reset, show front\n");
28032001f49Smrg   printf("   a - toggle animation\n");
28132001f49Smrg   printf("   s - step rotation\n");
28232001f49Smrg   printf("   w - toggle CW, CCW front-face winding\n");
28332001f49Smrg   printf("NOTE: red = front face, green = back face.\n");
28432001f49Smrg}
28532001f49Smrg
28632001f49Smrg
28732001f49Smrgint
28832001f49Smrgmain(int argc, char *argv[])
28932001f49Smrg{
29032001f49Smrg   glutInit(&argc, argv);
29132001f49Smrg   glutInitWindowSize(WinWidth, WinHeight);
29232001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
29332001f49Smrg   win = glutCreateWindow(argv[0]);
29432001f49Smrg   glewInit();
29532001f49Smrg   glutReshapeFunc(Reshape);
29632001f49Smrg   glutKeyboardFunc(Key);
29732001f49Smrg   glutDisplayFunc(Redisplay);
29832001f49Smrg   if (anim)
29932001f49Smrg      glutIdleFunc(Idle);
30032001f49Smrg   ParseOptions(argc, argv);
30132001f49Smrg   Init();
30232001f49Smrg   Usage();
30332001f49Smrg   glutMainLoop();
30432001f49Smrg   return 0;
30532001f49Smrg}
306