diff options
Diffstat (limited to 'progs/glsl/twoside.c')
-rw-r--r-- | progs/glsl/twoside.c | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/progs/glsl/twoside.c b/progs/glsl/twoside.c new file mode 100644 index 00000000000..1db92b5512a --- /dev/null +++ b/progs/glsl/twoside.c @@ -0,0 +1,348 @@ +/** + * 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 <assert.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <GL/gl.h> +#include <GL/glut.h> +#include <GL/glext.h> +#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; +} |