132001f49Smrg/** 232001f49Smrg * Test using a geometry shader to implement point sprites. 332001f49Smrg * XXX we should also demo point size attenuation. 432001f49Smrg * 532001f49Smrg * Brian Paul 632001f49Smrg * March 2011 732001f49Smrg */ 832001f49Smrg 932001f49Smrg#include <assert.h> 1032001f49Smrg#include <string.h> 1132001f49Smrg#include <stdio.h> 1232001f49Smrg#include <stdlib.h> 1332001f49Smrg#include <math.h> 1432001f49Smrg#include <GL/glew.h> 1532001f49Smrg#include "glut_wrap.h" 1632001f49Smrg#include "shaderutil.h" 1732001f49Smrg 1832001f49Smrgstatic GLint WinWidth = 500, WinHeight = 500; 1932001f49Smrgstatic GLint Win = 0; 2032001f49Smrgstatic GLuint VertShader, GeomShader, FragShader, Program; 2132001f49Smrgstatic GLboolean Anim = GL_TRUE; 2232001f49Smrgstatic GLfloat Xrot = 0, Yrot = 0; 2332001f49Smrgstatic int uPointSize = -1, uInverseViewportSize = -1; 2432001f49Smrg 2532001f49Smrgstatic const int NumPoints = 50; 2632001f49Smrgstatic float Points[100][3]; 2732001f49Smrg 2832001f49Smrgstatic const GLfloat Red[4] = {1, 0, 0, 1}; 2932001f49Smrgstatic const GLfloat Green[4] = {0, 1, 0, 0}; 3032001f49Smrg 3132001f49Smrg 3232001f49Smrgstatic void 3332001f49SmrgCheckError(int line) 3432001f49Smrg{ 3532001f49Smrg GLenum err = glGetError(); 3632001f49Smrg if (err) { 3732001f49Smrg printf("GL Error %s (0x%x) at line %d\n", 3832001f49Smrg gluErrorString(err), (int) err, line); 3932001f49Smrg } 4032001f49Smrg} 4132001f49Smrg 4232001f49Smrg 4332001f49Smrgstatic void 4432001f49SmrgRedisplay(void) 4532001f49Smrg{ 4632001f49Smrg int i; 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 glBegin(GL_POINTS); 5532001f49Smrg for (i = 0; i < NumPoints; i++) { 5632001f49Smrg glVertex3fv(Points[i]); 5732001f49Smrg } 5832001f49Smrg glEnd(); 5932001f49Smrg 6032001f49Smrg glPopMatrix(); 6132001f49Smrg 6232001f49Smrg glutSwapBuffers(); 6332001f49Smrg} 6432001f49Smrg 6532001f49Smrg 6632001f49Smrgstatic void 6732001f49SmrgIdle(void) 6832001f49Smrg{ 6932001f49Smrg int curTime = glutGet(GLUT_ELAPSED_TIME); 7032001f49Smrg Xrot = curTime * 0.02; 7132001f49Smrg Yrot = curTime * 0.05; 7232001f49Smrg glutPostRedisplay(); 7332001f49Smrg} 7432001f49Smrg 7532001f49Smrg 7632001f49Smrgstatic void 7732001f49SmrgReshape(int width, int height) 7832001f49Smrg{ 7932001f49Smrg float ar = (float) width / height; 8032001f49Smrg glViewport(0, 0, width, height); 8132001f49Smrg glMatrixMode(GL_PROJECTION); 8232001f49Smrg glLoadIdentity(); 8332001f49Smrg glFrustum(-ar, ar, -1, 1, 3, 25); 8432001f49Smrg glMatrixMode(GL_MODELVIEW); 8532001f49Smrg glLoadIdentity(); 8632001f49Smrg glTranslatef(0, 0, -10); 8732001f49Smrg 8832001f49Smrg { 8932001f49Smrg GLfloat viewport[4]; 9032001f49Smrg glGetFloatv(GL_VIEWPORT, viewport); 9132001f49Smrg glUniform2f(uInverseViewportSize, 1.0F / viewport[2], 1.0F / viewport[3]); 9232001f49Smrg } 9332001f49Smrg} 9432001f49Smrg 9532001f49Smrg 9632001f49Smrgstatic void 9732001f49SmrgCleanUp(void) 9832001f49Smrg{ 9932001f49Smrg glDeleteShader(FragShader); 10032001f49Smrg glDeleteShader(VertShader); 10132001f49Smrg glDeleteShader(GeomShader); 10232001f49Smrg glDeleteProgram(Program); 10332001f49Smrg glutDestroyWindow(Win); 10432001f49Smrg} 10532001f49Smrg 10632001f49Smrg 10732001f49Smrgstatic void 10832001f49SmrgKey(unsigned char key, int x, int y) 10932001f49Smrg{ 11032001f49Smrg (void) x; 11132001f49Smrg (void) y; 11232001f49Smrg 11332001f49Smrg switch(key) { 11432001f49Smrg case ' ': 11532001f49Smrg case 'a': 11632001f49Smrg Anim = !Anim; 11732001f49Smrg if (Anim) { 11832001f49Smrg glutIdleFunc(Idle); 11932001f49Smrg } 12032001f49Smrg else 12132001f49Smrg glutIdleFunc(NULL); 12232001f49Smrg break; 12332001f49Smrg case 27: 12432001f49Smrg CleanUp(); 12532001f49Smrg exit(0); 12632001f49Smrg break; 12732001f49Smrg } 12832001f49Smrg glutPostRedisplay(); 12932001f49Smrg} 13032001f49Smrg 13132001f49Smrg 13232001f49Smrgstatic GLuint 13332001f49SmrgMakeTexture(void) 13432001f49Smrg{ 13532001f49Smrg#define TEX_SIZE 32 13632001f49Smrg GLubyte image[TEX_SIZE][TEX_SIZE][3]; 13732001f49Smrg GLuint i, j; 13832001f49Smrg GLuint tex; 13932001f49Smrg 14032001f49Smrg glGenTextures(1, &tex); 14132001f49Smrg glBindTexture(GL_TEXTURE_2D, tex); 14232001f49Smrg 14332001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 14432001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 14532001f49Smrg 14632001f49Smrg /* 'X' pattern */ 14732001f49Smrg for (i = 0; i < TEX_SIZE; i++) { 14832001f49Smrg for (j = 0; j < TEX_SIZE; j++) { 14932001f49Smrg int p1 = i - j, p2 = TEX_SIZE - 1 - i - j; 15032001f49Smrg p1 = (p1 >= -2 && p1 <= 2); 15132001f49Smrg p2 = (p2 >= -2 && p2 <= 2); 15232001f49Smrg if (p1 || p2) { 15332001f49Smrg image[i][j][0] = 255; 15432001f49Smrg image[i][j][1] = 255; 15532001f49Smrg image[i][j][2] = 255; 15632001f49Smrg } 15732001f49Smrg else { 15832001f49Smrg image[i][j][0] = 50; 15932001f49Smrg image[i][j][1] = 50; 16032001f49Smrg image[i][j][2] = 50; 16132001f49Smrg } 16232001f49Smrg } 16332001f49Smrg } 16432001f49Smrg 16532001f49Smrg glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_SIZE, TEX_SIZE, 0, 16632001f49Smrg GL_RGB, GL_UNSIGNED_BYTE, image); 16732001f49Smrg 16832001f49Smrg return tex; 16932001f49Smrg} 17032001f49Smrg 17132001f49Smrg 17232001f49Smrgstatic void 17332001f49SmrgMakePoints(void) 17432001f49Smrg{ 17532001f49Smrg int i; 17632001f49Smrg for (i = 0; i < NumPoints; i++) { 17732001f49Smrg Points[i][0] = ((rand() % 2000) - 1000.0) / 500.0; 17832001f49Smrg Points[i][1] = ((rand() % 2000) - 1000.0) / 500.0; 17932001f49Smrg Points[i][2] = ((rand() % 2000) - 1000.0) / 500.0; 18032001f49Smrg } 18132001f49Smrg} 18232001f49Smrg 18332001f49Smrgstatic void 18432001f49SmrgInit(void) 18532001f49Smrg{ 18632001f49Smrg static const char *fragShaderText = 18732001f49Smrg "uniform sampler2D tex; \n" 18832001f49Smrg "void main() \n" 18932001f49Smrg "{ \n" 19032001f49Smrg " gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); \n" 19132001f49Smrg "} \n"; 19232001f49Smrg static const char *vertShaderText = 19332001f49Smrg "void main() \n" 19432001f49Smrg "{ \n" 19532001f49Smrg " gl_FrontColor = gl_Color; \n" 19632001f49Smrg " gl_Position = ftransform(); \n" 19732001f49Smrg "} \n"; 19832001f49Smrg static const char *geomShaderText = 19932001f49Smrg "#version 120 \n" 20032001f49Smrg "#extension GL_ARB_geometry_shader4: enable \n" 20132001f49Smrg "uniform vec2 InverseViewportSize; \n" 20232001f49Smrg "uniform float PointSize; \n" 20332001f49Smrg "void main() \n" 20432001f49Smrg "{ \n" 20532001f49Smrg " vec4 pos = gl_PositionIn[0]; \n" 20632001f49Smrg " vec2 d = vec2(PointSize * pos.w) * InverseViewportSize; \n" 20732001f49Smrg " gl_FrontColor = gl_FrontColorIn[0]; \n" 20832001f49Smrg " gl_TexCoord[0] = vec4(0, 0, 0, 1); \n" 20932001f49Smrg " gl_Position = pos + vec4(-d.x, -d.y, 0, 0); \n" 21032001f49Smrg " EmitVertex(); \n" 21132001f49Smrg " gl_TexCoord[0] = vec4(1, 0, 0, 1); \n" 21232001f49Smrg " gl_Position = pos + vec4( d.x, -d.y, 0, 0); \n" 21332001f49Smrg " EmitVertex(); \n" 21432001f49Smrg " gl_TexCoord[0] = vec4(0, 1, 0, 1); \n" 21532001f49Smrg " gl_Position = pos + vec4(-d.x, d.y, 0, 0); \n" 21632001f49Smrg " EmitVertex(); \n" 21732001f49Smrg " gl_TexCoord[0] = vec4(1, 1, 0, 1); \n" 21832001f49Smrg " gl_Position = pos + vec4( d.x, d.y, 0, 0); \n" 21932001f49Smrg " EmitVertex(); \n" 22032001f49Smrg "} \n"; 22132001f49Smrg 22232001f49Smrg if (!ShadersSupported()) 22332001f49Smrg exit(1); 22432001f49Smrg 22532001f49Smrg if (!glutExtensionSupported("GL_ARB_geometry_shader4")) { 22632001f49Smrg fprintf(stderr, "Sorry, GL_ARB_geometry_shader4 is not supported.\n"); 22732001f49Smrg exit(1); 22832001f49Smrg } 22932001f49Smrg 23032001f49Smrg VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText); 23132001f49Smrg FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 23232001f49Smrg GeomShader = CompileShaderText(GL_GEOMETRY_SHADER_ARB, geomShaderText); 23332001f49Smrg assert(GeomShader); 23432001f49Smrg 23532001f49Smrg Program = LinkShaders3(VertShader, GeomShader, FragShader); 23632001f49Smrg assert(Program); 23732001f49Smrg CheckError(__LINE__); 23832001f49Smrg 23932001f49Smrg /* 24032001f49Smrg * The geometry shader will convert incoming points to quads (4-vertex 24132001f49Smrg * triangle strips). 24232001f49Smrg */ 24332001f49Smrg glProgramParameteriARB(Program, GL_GEOMETRY_INPUT_TYPE_ARB, 24432001f49Smrg GL_POINTS); 24532001f49Smrg glProgramParameteriARB(Program, GL_GEOMETRY_OUTPUT_TYPE_ARB, 24632001f49Smrg GL_TRIANGLE_STRIP); 24732001f49Smrg glProgramParameteriARB(Program,GL_GEOMETRY_VERTICES_OUT_ARB, 4); 24832001f49Smrg CheckError(__LINE__); 24932001f49Smrg 25032001f49Smrg glLinkProgramARB(Program); 25132001f49Smrg 25232001f49Smrg /* check link */ 25332001f49Smrg { 25432001f49Smrg GLint stat; 25532001f49Smrg GetProgramiv(Program, GL_LINK_STATUS, &stat); 25632001f49Smrg if (!stat) { 25732001f49Smrg GLchar log[1000]; 25832001f49Smrg GLsizei len; 25932001f49Smrg GetProgramInfoLog(Program, 1000, &len, log); 26032001f49Smrg fprintf(stderr, "Shader link error:\n%s\n", log); 26132001f49Smrg } 26232001f49Smrg } 26332001f49Smrg 26432001f49Smrg CheckError(__LINE__); 26532001f49Smrg 26632001f49Smrg glUseProgram(Program); 26732001f49Smrg CheckError(__LINE__); 26832001f49Smrg 26932001f49Smrg uInverseViewportSize = glGetUniformLocation(Program, "InverseViewportSize"); 27032001f49Smrg uPointSize = glGetUniformLocation(Program, "PointSize"); 27132001f49Smrg 27232001f49Smrg glUniform1f(uPointSize, 24.0); 27332001f49Smrg 27432001f49Smrg glClearColor(0.3f, 0.3f, 0.3f, 0.0f); 27532001f49Smrg 27632001f49Smrg printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 27732001f49Smrg 27832001f49Smrg assert(glIsProgram(Program)); 27932001f49Smrg assert(glIsShader(FragShader)); 28032001f49Smrg assert(glIsShader(VertShader)); 28132001f49Smrg assert(glIsShader(GeomShader)); 28232001f49Smrg 28332001f49Smrg glEnable(GL_DEPTH_TEST); 28432001f49Smrg 28532001f49Smrg MakeTexture(); 28632001f49Smrg MakePoints(); 28732001f49Smrg} 28832001f49Smrg 28932001f49Smrg 29032001f49Smrgint 29132001f49Smrgmain(int argc, char *argv[]) 29232001f49Smrg{ 29332001f49Smrg glutInit(&argc, argv); 29432001f49Smrg glutInitWindowSize(WinWidth, WinHeight); 29532001f49Smrg glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 29632001f49Smrg Win = glutCreateWindow(argv[0]); 29732001f49Smrg glewInit(); 29832001f49Smrg glutReshapeFunc(Reshape); 29932001f49Smrg glutKeyboardFunc(Key); 30032001f49Smrg glutDisplayFunc(Redisplay); 30132001f49Smrg if (Anim) 30232001f49Smrg glutIdleFunc(Idle); 30332001f49Smrg 30432001f49Smrg Init(); 30532001f49Smrg glutMainLoop(); 30632001f49Smrg return 0; 30732001f49Smrg} 308