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