/** * Test two-sided lighting with shaders. * Both GL_VERTEX_PROGRAM_TWO_SIDE and gl_FrontFacing can be tested * (see keys below). * * Brian Paul * 18 Dec 2007 */ #include #include #include #include #include #include #include #include #include "extfuncs.h" static const char *Prog = "twoside"; static GLint WinWidth = 300, WinHeight = 300; static char *FragProgFile = NULL; static char *VertProgFile = NULL; static GLuint fragShader; static GLuint vertShader; static GLuint program; static GLint win = 0; static GLboolean anim = 0*GL_TRUE; static GLboolean DetermineInFragProg = GL_TRUE; static GLfloat Yrot = 0.0f; static GLint u_fragface; static GLenum FrontWinding = GL_CCW; static int prevTime = 0; static const GLfloat Red[4] = {1, 0, 0, 0}; static const GLfloat Green[4] = {0, 1, 0, 0}; static void Redisplay(void) { float xmin = -1, xmax = 1, ymin = -1, ymax = 1; glFrontFace(FrontWinding); if (DetermineInFragProg) { glUniform1i_func(u_fragface, 1); glDisable(GL_VERTEX_PROGRAM_TWO_SIDE); } else { glUniform1i_func(u_fragface, 0); glEnable(GL_VERTEX_PROGRAM_TWO_SIDE); } glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glRotatef(Yrot, 0, 1, 0); glBegin(GL_POLYGON); glColor4fv(Red); glSecondaryColor3fv_func(Green); glVertex2f(xmin, ymin); glVertex2f(xmax, ymin); glVertex2f(xmax, ymax); glVertex2f(xmin, ymax); glEnd(); glPopMatrix(); glutSwapBuffers(); } static void Idle(void) { int curTime = glutGet(GLUT_ELAPSED_TIME); int dt = curTime - prevTime; if (prevTime == 0) { prevTime = curTime; return; } prevTime = curTime; Yrot += dt * 0.1; glutPostRedisplay(); } static void Reshape(int width, int height) { float ar = (float) width / height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-ar, ar, -1, 1, 5, 15); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -10); } static void CleanUp(void) { glDeleteShader_func(fragShader); glDeleteShader_func(vertShader); glDeleteProgram_func(program); glutDestroyWindow(win); } static void Key(unsigned char key, int x, int y) { (void) x; (void) y; switch(key) { case ' ': case 'a': anim = !anim; if (anim) { prevTime = glutGet(GLUT_ELAPSED_TIME); glutIdleFunc(Idle); } else glutIdleFunc(NULL); break; case 'f': printf("Using frag shader gl_FrontFacing\n"); DetermineInFragProg = GL_TRUE; break; case 'v': printf("Using vert shader Two-sided lighting\n"); DetermineInFragProg = GL_FALSE; break; case 'r': Yrot = 0; anim = 0; glutIdleFunc(NULL); break; case 's': Yrot += 5; break; case 'w': if (FrontWinding == GL_CCW) { FrontWinding = GL_CW; printf("FrontFace = GL_CW\n"); } else { FrontWinding = GL_CCW; printf("FrontFace = GL_CCW\n"); } break; case 27: CleanUp(); exit(0); break; } glutPostRedisplay(); } static void LoadAndCompileShader(GLuint shader, const char *text) { GLint stat; glShaderSource_func(shader, 1, (const GLchar **) &text, NULL); glCompileShader_func(shader); glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat); if (!stat) { GLchar log[1000]; GLsizei len; glGetShaderInfoLog_func(shader, 1000, &len, log); fprintf(stderr, "%s: problem compiling shader:\n%s\n", Prog, log); exit(1); } } /** * Read a shader from a file. */ static void ReadShader(GLuint shader, const char *filename) { const int max = 100*1000; int n; char *buffer = (char*) malloc(max); FILE *f = fopen(filename, "r"); if (!f) { fprintf(stderr, "%s: Unable to open shader file %s\n", Prog, filename); exit(1); } n = fread(buffer, 1, max, f); printf("%s: read %d bytes from shader file %s\n", Prog, n, filename); if (n > 0) { buffer[n] = 0; LoadAndCompileShader(shader, buffer); } fclose(f); free(buffer); } static void CheckLink(GLuint prog) { GLint stat; glGetProgramiv_func(prog, GL_LINK_STATUS, &stat); if (!stat) { GLchar log[1000]; GLsizei len; glGetProgramInfoLog_func(prog, 1000, &len, log); fprintf(stderr, "Linker error:\n%s\n", log); } } static void Init(void) { static const char *fragShaderText = "uniform bool fragface; \n" "void main() { \n" " if (!fragface || gl_FrontFacing) { \n" " gl_FragColor = gl_Color; \n" " } \n" " else { \n" " gl_FragColor = 0.8 * gl_SecondaryColor; \n" " } \n" "} \n"; static const char *vertShaderText = "uniform bool fragface; \n" "void main() { \n" " gl_FrontColor = gl_Color; \n" " if (fragface) { \n" " // front/back chosen in frag prog \n" " gl_FrontSecondaryColor = gl_SecondaryColor; \n" " } \n" " else { \n" " // front/back chosen in prim setup \n" " gl_BackColor = gl_SecondaryColor; \n" " } \n" " gl_Position = ftransform(); \n" "} \n"; const char *version; version = (const char *) glGetString(GL_VERSION); if (version[0] != '2' || version[1] != '.') { printf("This program requires OpenGL 2.x, found %s\n", version); exit(1); } GetExtensionFuncs(); fragShader = glCreateShader_func(GL_FRAGMENT_SHADER); if (FragProgFile) ReadShader(fragShader, FragProgFile); else LoadAndCompileShader(fragShader, fragShaderText); vertShader = glCreateShader_func(GL_VERTEX_SHADER); if (VertProgFile) ReadShader(vertShader, VertProgFile); else LoadAndCompileShader(vertShader, vertShaderText); program = glCreateProgram_func(); glAttachShader_func(program, fragShader); glAttachShader_func(program, vertShader); glLinkProgram_func(program); CheckLink(program); glUseProgram_func(program); u_fragface = glGetUniformLocation_func(program, "fragface"); printf("Uniforms: %d\n", u_fragface); /*assert(glGetError() == 0);*/ glClearColor(0.3f, 0.3f, 0.3f, 0.0f); printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); assert(glIsProgram_func(program)); assert(glIsShader_func(fragShader)); assert(glIsShader_func(vertShader)); } static void ParseOptions(int argc, char *argv[]) { int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-fs") == 0) { FragProgFile = argv[i+1]; } else if (strcmp(argv[i], "-vs") == 0) { VertProgFile = argv[i+1]; } } } static void Usage(void) { printf("Keys:\n"); printf(" f - do front/back determination in fragment shader\n"); printf(" v - do front/back determination in vertex shader\n"); printf(" r - reset, show front\n"); printf(" a - toggle animation\n"); printf(" s - step rotation\n"); printf(" w - toggle CW, CCW front-face winding\n"); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitWindowPosition( 0, 0); glutInitWindowSize(WinWidth, WinHeight); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); win = glutCreateWindow(argv[0]); glutReshapeFunc(Reshape); glutKeyboardFunc(Key); glutDisplayFunc(Redisplay); if (anim) glutIdleFunc(Idle); ParseOptions(argc, argv); Init(); Usage(); glutMainLoop(); return 0; }