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