132001f49Smrg/** 232001f49Smrg * Test using a geometry shader to implement wide lines. 332001f49Smrg * 432001f49Smrg * Brian Paul 532001f49Smrg * March 2011 632001f49Smrg */ 732001f49Smrg 832001f49Smrg#include <assert.h> 932001f49Smrg#include <string.h> 1032001f49Smrg#include <stdio.h> 1132001f49Smrg#include <stdlib.h> 1232001f49Smrg#include <math.h> 1332001f49Smrg#include <GL/glew.h> 1432001f49Smrg#include "glut_wrap.h" 1532001f49Smrg#include "shaderutil.h" 1632001f49Smrg 1732001f49Smrg 1832001f49Smrgstatic GLint WinWidth = 500, WinHeight = 500; 1932001f49Smrgstatic GLint Win = 0; 2032001f49Smrgstatic GLuint VertShader, GeomShader, FragShader, Program; 2132001f49Smrgstatic GLboolean Anim = GL_TRUE; 2232001f49Smrgstatic GLboolean UseGeomShader = GL_TRUE; 2332001f49Smrgstatic GLfloat LineWidth = 10.0; 2432001f49Smrgstatic GLfloat MaxLineWidth; 2532001f49Smrgstatic GLfloat Xrot = 0, Yrot = 0; 2632001f49Smrgstatic int uLineWidth = -1, uInverseViewportSize = -1; 2732001f49Smrg 287ec3b29aSmrgstatic int NumPoints = 50; 2932001f49Smrg 3032001f49Smrgstatic const GLfloat Red[4] = {1, 0, 0, 1}; 3132001f49Smrgstatic const GLfloat Green[4] = {0, 1, 0, 0}; 3232001f49Smrg 3332001f49Smrg 3432001f49Smrgstatic void 3532001f49SmrgCheckError(int line) 3632001f49Smrg{ 3732001f49Smrg GLenum err = glGetError(); 3832001f49Smrg if (err) { 3932001f49Smrg printf("GL Error %s (0x%x) at line %d\n", 4032001f49Smrg gluErrorString(err), (int) err, line); 4132001f49Smrg } 4232001f49Smrg} 4332001f49Smrg 4432001f49Smrg 4532001f49Smrgstatic void 4632001f49SmrgRedisplay(void) 4732001f49Smrg{ 4832001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 4932001f49Smrg 5032001f49Smrg glPushMatrix(); 5132001f49Smrg glRotatef(Xrot, 1, 0, 0); 5232001f49Smrg glRotatef(Yrot, 0, 0, 1); 5332001f49Smrg 5432001f49Smrg if (UseGeomShader) { 5532001f49Smrg glUseProgram(Program); 5632001f49Smrg glUniform1f(uLineWidth, LineWidth); 5732001f49Smrg } 5832001f49Smrg else { 5932001f49Smrg glUseProgram(0); 6032001f49Smrg glLineWidth(LineWidth); 6132001f49Smrg } 6232001f49Smrg 637ec3b29aSmrg glDrawArrays(GL_LINES, 0, NumPoints / 2); 6432001f49Smrg 6532001f49Smrg glPopMatrix(); 6632001f49Smrg 6732001f49Smrg glutSwapBuffers(); 6832001f49Smrg} 6932001f49Smrg 7032001f49Smrg 7132001f49Smrgstatic void 7232001f49SmrgIdle(void) 7332001f49Smrg{ 7432001f49Smrg int curTime = glutGet(GLUT_ELAPSED_TIME); 7532001f49Smrg Xrot = curTime * 0.02; 7632001f49Smrg Yrot = curTime * 0.05; 7732001f49Smrg glutPostRedisplay(); 7832001f49Smrg} 7932001f49Smrg 8032001f49Smrg 8132001f49Smrgstatic void 8232001f49SmrgReshape(int width, int height) 8332001f49Smrg{ 8432001f49Smrg float ar = (float) width / height; 8532001f49Smrg glViewport(0, 0, width, height); 8632001f49Smrg glMatrixMode(GL_PROJECTION); 8732001f49Smrg glLoadIdentity(); 8832001f49Smrg glFrustum(-ar, ar, -1, 1, 3, 25); 8932001f49Smrg glMatrixMode(GL_MODELVIEW); 9032001f49Smrg glLoadIdentity(); 9132001f49Smrg glTranslatef(0, 0, -10); 9232001f49Smrg 9332001f49Smrg { 9432001f49Smrg GLfloat viewport[4]; 9532001f49Smrg glGetFloatv(GL_VIEWPORT, viewport); 9632001f49Smrg glUniform2f(uInverseViewportSize, 1.0F / viewport[2], 1.0F / viewport[3]); 9732001f49Smrg } 9832001f49Smrg} 9932001f49Smrg 10032001f49Smrg 10132001f49Smrgstatic void 10232001f49SmrgCleanUp(void) 10332001f49Smrg{ 10432001f49Smrg glDeleteShader(FragShader); 10532001f49Smrg glDeleteShader(VertShader); 10632001f49Smrg glDeleteShader(GeomShader); 10732001f49Smrg glDeleteProgram(Program); 10832001f49Smrg glutDestroyWindow(Win); 10932001f49Smrg} 11032001f49Smrg 11132001f49Smrg 11232001f49Smrgstatic void 11332001f49SmrgKey(unsigned char key, int x, int y) 11432001f49Smrg{ 11532001f49Smrg (void) x; 11632001f49Smrg (void) y; 11732001f49Smrg 11832001f49Smrg switch(key) { 11932001f49Smrg case ' ': 12032001f49Smrg case 'a': 12132001f49Smrg Anim = !Anim; 12232001f49Smrg if (Anim) { 12332001f49Smrg glutIdleFunc(Idle); 12432001f49Smrg } 12532001f49Smrg else 12632001f49Smrg glutIdleFunc(NULL); 12732001f49Smrg break; 12832001f49Smrg case 'g': 12932001f49Smrg UseGeomShader = !UseGeomShader; 13032001f49Smrg printf("Use geometry shader? %d\n", UseGeomShader); 13132001f49Smrg break; 13232001f49Smrg case 'w': 13332001f49Smrg LineWidth -= 0.5; 13432001f49Smrg if (LineWidth < 1.0) 13532001f49Smrg LineWidth = 1.0; 13632001f49Smrg printf("Line width: %f\n", LineWidth); 13732001f49Smrg break; 13832001f49Smrg case 'W': 13932001f49Smrg LineWidth += 0.5; 14032001f49Smrg if (LineWidth > MaxLineWidth) 14132001f49Smrg LineWidth = MaxLineWidth; 14232001f49Smrg printf("Line width: %f\n", LineWidth); 14332001f49Smrg break; 14432001f49Smrg 14532001f49Smrg case 27: 14632001f49Smrg CleanUp(); 14732001f49Smrg exit(0); 14832001f49Smrg break; 14932001f49Smrg } 15032001f49Smrg glutPostRedisplay(); 15132001f49Smrg} 15232001f49Smrg 15332001f49Smrg 15432001f49Smrgstatic void 1557ec3b29aSmrgMakePointsVBO(void) 15632001f49Smrg{ 1577ec3b29aSmrg struct vert { 1587ec3b29aSmrg GLfloat pos[3]; 1597ec3b29aSmrg GLfloat color[3]; 1607ec3b29aSmrg }; 1617ec3b29aSmrg struct vert *v; 1627ec3b29aSmrg GLuint vbo; 16332001f49Smrg int i; 1647ec3b29aSmrg 1657ec3b29aSmrg glGenBuffers(1, &vbo); 1667ec3b29aSmrg glBindBuffer(GL_ARRAY_BUFFER, vbo); 1677ec3b29aSmrg glBufferData(GL_ARRAY_BUFFER, NumPoints * sizeof(struct vert), 1687ec3b29aSmrg NULL, GL_STATIC_DRAW); 1697ec3b29aSmrg 1707ec3b29aSmrg v = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); 17132001f49Smrg for (i = 0; i < NumPoints; i++) { 1727ec3b29aSmrg v[i].color[0] = (rand() % 1000) / 1000.0; 1737ec3b29aSmrg v[i].color[1] = (rand() % 1000) / 1000.0; 1747ec3b29aSmrg v[i].color[2] = (rand() % 1000) / 1000.0; 1757ec3b29aSmrg v[i].pos[0] = ((rand() % 2000) - 1000.0) / 500.0; 1767ec3b29aSmrg v[i].pos[1] = ((rand() % 2000) - 1000.0) / 500.0; 1777ec3b29aSmrg v[i].pos[2] = ((rand() % 2000) - 1000.0) / 500.0; 17832001f49Smrg } 1797ec3b29aSmrg glUnmapBuffer(GL_ARRAY_BUFFER); 1807ec3b29aSmrg 1817ec3b29aSmrg glVertexPointer(3, GL_FLOAT, sizeof(struct vert), (void *) 0); 1827ec3b29aSmrg glEnable(GL_VERTEX_ARRAY); 1837ec3b29aSmrg glColorPointer(3, GL_FLOAT, sizeof(struct vert), (void *) sizeof(float[3])); 1847ec3b29aSmrg glEnable(GL_COLOR_ARRAY); 18532001f49Smrg} 18632001f49Smrg 1877ec3b29aSmrg 18832001f49Smrgstatic void 18932001f49SmrgInit(void) 19032001f49Smrg{ 19132001f49Smrg static const char *fragShaderText = 19232001f49Smrg "void main() \n" 19332001f49Smrg "{ \n" 19432001f49Smrg " gl_FragColor = gl_Color; \n" 19532001f49Smrg "} \n"; 19632001f49Smrg static const char *vertShaderText = 19732001f49Smrg "void main() \n" 19832001f49Smrg "{ \n" 19932001f49Smrg " gl_FrontColor = gl_Color; \n" 20032001f49Smrg " gl_Position = ftransform(); \n" 20132001f49Smrg "} \n"; 20232001f49Smrg static const char *geomShaderText = 20332001f49Smrg "#version 120 \n" 20432001f49Smrg "#extension GL_ARB_geometry_shader4: enable \n" 20532001f49Smrg "uniform vec2 InverseViewportSize; \n" 20632001f49Smrg "uniform float LineWidth; \n" 20732001f49Smrg "void main() \n" 20832001f49Smrg "{ \n" 20932001f49Smrg " vec4 pos0 = gl_PositionIn[0]; \n" 21032001f49Smrg " vec4 pos1 = gl_PositionIn[1]; \n" 21132001f49Smrg " vec4 dir = abs(pos1 - pos0); \n" 21232001f49Smrg " vec2 d0 = vec2(LineWidth * pos0.w) * InverseViewportSize; \n" 21332001f49Smrg " vec2 d1 = vec2(LineWidth * pos1.w) * InverseViewportSize; \n" 21432001f49Smrg " // this conditional could be avoided \n" 21532001f49Smrg " if (dir.x > dir.y) { \n" 21632001f49Smrg " // X-major line \n" 21732001f49Smrg " d0.x = 0.0; \n" 21832001f49Smrg " d1.x = 0.0; \n" 21932001f49Smrg " } \n" 22032001f49Smrg " else { \n" 22132001f49Smrg " // Y-major line \n" 22232001f49Smrg " d0.y = 0.0; \n" 22332001f49Smrg " d1.y = 0.0; \n" 22432001f49Smrg " } \n" 22532001f49Smrg " gl_FrontColor = gl_FrontColorIn[0]; \n" 22632001f49Smrg " gl_TexCoord[0] = vec4(0, 0, 0, 1); \n" 22732001f49Smrg " gl_Position = pos0 + vec4( d0.x, -d0.y, 0, 0); \n" 22832001f49Smrg " EmitVertex(); \n" 22932001f49Smrg " gl_FrontColor = gl_FrontColorIn[1]; \n" 23032001f49Smrg " gl_TexCoord[0] = vec4(1, 0, 0, 1); \n" 23132001f49Smrg " gl_Position = pos1 + vec4( d1.x, -d1.y, 0, 0); \n" 23232001f49Smrg " EmitVertex(); \n" 23332001f49Smrg " gl_FrontColor = gl_FrontColorIn[0]; \n" 23432001f49Smrg " gl_TexCoord[0] = vec4(0, 1, 0, 1); \n" 23532001f49Smrg " gl_Position = pos0 + vec4(-d0.x, d0.y, 0, 0); \n" 23632001f49Smrg " EmitVertex(); \n" 23732001f49Smrg " gl_FrontColor = gl_FrontColorIn[1]; \n" 23832001f49Smrg " gl_TexCoord[0] = vec4(1, 1, 0, 1); \n" 23932001f49Smrg " gl_Position = pos1 + vec4(-d1.x, d1.y, 0, 0); \n" 24032001f49Smrg " EmitVertex(); \n" 24132001f49Smrg "} \n"; 24232001f49Smrg 24332001f49Smrg if (!ShadersSupported()) 24432001f49Smrg exit(1); 24532001f49Smrg 24632001f49Smrg if (!glutExtensionSupported("GL_ARB_geometry_shader4")) { 24732001f49Smrg fprintf(stderr, "Sorry, GL_ARB_geometry_shader4 is not supported.\n"); 24832001f49Smrg exit(1); 24932001f49Smrg } 25032001f49Smrg 25132001f49Smrg VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText); 25232001f49Smrg FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 25332001f49Smrg GeomShader = CompileShaderText(GL_GEOMETRY_SHADER_ARB, geomShaderText); 25432001f49Smrg assert(GeomShader); 25532001f49Smrg 25632001f49Smrg Program = LinkShaders3(VertShader, GeomShader, FragShader); 25732001f49Smrg assert(Program); 25832001f49Smrg CheckError(__LINE__); 25932001f49Smrg 26032001f49Smrg /* 26132001f49Smrg * The geometry shader will convert incoming lines to quads (4-vertex 26232001f49Smrg * triangle strips). 26332001f49Smrg */ 26432001f49Smrg glProgramParameteriARB(Program, GL_GEOMETRY_INPUT_TYPE_ARB, 26532001f49Smrg GL_LINES); 26632001f49Smrg glProgramParameteriARB(Program, GL_GEOMETRY_OUTPUT_TYPE_ARB, 26732001f49Smrg GL_TRIANGLE_STRIP); 26832001f49Smrg glProgramParameteriARB(Program,GL_GEOMETRY_VERTICES_OUT_ARB, 4); 26932001f49Smrg CheckError(__LINE__); 27032001f49Smrg 27132001f49Smrg glLinkProgramARB(Program); 27232001f49Smrg 27332001f49Smrg /* check link */ 27432001f49Smrg { 27532001f49Smrg GLint stat; 27632001f49Smrg GetProgramiv(Program, GL_LINK_STATUS, &stat); 27732001f49Smrg if (!stat) { 27832001f49Smrg GLchar log[1000]; 27932001f49Smrg GLsizei len; 28032001f49Smrg GetProgramInfoLog(Program, 1000, &len, log); 28132001f49Smrg fprintf(stderr, "Shader link error:\n%s\n", log); 28232001f49Smrg } 28332001f49Smrg } 28432001f49Smrg 28532001f49Smrg CheckError(__LINE__); 28632001f49Smrg 28732001f49Smrg glUseProgram(Program); 28832001f49Smrg CheckError(__LINE__); 28932001f49Smrg 29032001f49Smrg uInverseViewportSize = glGetUniformLocation(Program, "InverseViewportSize"); 29132001f49Smrg uLineWidth = glGetUniformLocation(Program, "LineWidth"); 29232001f49Smrg 29332001f49Smrg glClearColor(0.3f, 0.3f, 0.3f, 0.0f); 29432001f49Smrg 29532001f49Smrg printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 29632001f49Smrg 29732001f49Smrg assert(glIsProgram(Program)); 29832001f49Smrg assert(glIsShader(FragShader)); 29932001f49Smrg assert(glIsShader(VertShader)); 30032001f49Smrg assert(glIsShader(GeomShader)); 30132001f49Smrg 30232001f49Smrg glEnable(GL_DEPTH_TEST); 30332001f49Smrg 30432001f49Smrg { 30532001f49Smrg GLfloat r[2]; 30632001f49Smrg glGetFloatv(GL_LINE_WIDTH_RANGE, r); 30732001f49Smrg MaxLineWidth = r[1]; 30832001f49Smrg } 30932001f49Smrg 3107ec3b29aSmrg MakePointsVBO(); 31132001f49Smrg} 31232001f49Smrg 31332001f49Smrg 31432001f49Smrgint 31532001f49Smrgmain(int argc, char *argv[]) 31632001f49Smrg{ 31732001f49Smrg glutInit(&argc, argv); 3187ec3b29aSmrg 3197ec3b29aSmrg if (argc > 1) { 3207ec3b29aSmrg int n = atoi(argv[1]); 3217ec3b29aSmrg if (n > 0) { 3227ec3b29aSmrg NumPoints = n; 3237ec3b29aSmrg } 3247ec3b29aSmrg else { 3257ec3b29aSmrg printf("Invalid number of points\n"); 3267ec3b29aSmrg return 1; 3277ec3b29aSmrg } 3287ec3b29aSmrg } 3297ec3b29aSmrg 33032001f49Smrg glutInitWindowSize(WinWidth, WinHeight); 33132001f49Smrg glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 33232001f49Smrg Win = glutCreateWindow(argv[0]); 33332001f49Smrg glewInit(); 33432001f49Smrg glutReshapeFunc(Reshape); 33532001f49Smrg glutKeyboardFunc(Key); 33632001f49Smrg glutDisplayFunc(Redisplay); 33732001f49Smrg if (Anim) 33832001f49Smrg glutIdleFunc(Idle); 33932001f49Smrg 34032001f49Smrg Init(); 34132001f49Smrg glutMainLoop(); 34232001f49Smrg return 0; 34332001f49Smrg} 344