1/** 2 * Test using a geometry shader to implement point sprites. 3 * XXX we should also demo point size attenuation. 4 * 5 * Brian Paul 6 * March 2011 7 */ 8 9#include <assert.h> 10#include <string.h> 11#include <stdio.h> 12#include <stdlib.h> 13#include <math.h> 14#include <GL/glew.h> 15#include "glut_wrap.h" 16#include "shaderutil.h" 17 18static GLint WinWidth = 500, WinHeight = 500; 19static GLint Win = 0; 20static GLuint VertShader, GeomShader, FragShader, Program; 21static GLboolean Anim = GL_TRUE; 22static GLfloat Xrot = 0, Yrot = 0; 23static int uPointSize = -1, uInverseViewportSize = -1; 24 25static const int NumPoints = 50; 26static float Points[100][3]; 27 28static const GLfloat Red[4] = {1, 0, 0, 1}; 29static const GLfloat Green[4] = {0, 1, 0, 0}; 30 31 32static void 33CheckError(int line) 34{ 35 GLenum err = glGetError(); 36 if (err) { 37 printf("GL Error %s (0x%x) at line %d\n", 38 gluErrorString(err), (int) err, line); 39 } 40} 41 42 43static void 44Redisplay(void) 45{ 46 int i; 47 48 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 49 50 glPushMatrix(); 51 glRotatef(Xrot, 1, 0, 0); 52 glRotatef(Yrot, 0, 0, 1); 53 54 glBegin(GL_POINTS); 55 for (i = 0; i < NumPoints; i++) { 56 glVertex3fv(Points[i]); 57 } 58 glEnd(); 59 60 glPopMatrix(); 61 62 glutSwapBuffers(); 63} 64 65 66static void 67Idle(void) 68{ 69 int curTime = glutGet(GLUT_ELAPSED_TIME); 70 Xrot = curTime * 0.02; 71 Yrot = curTime * 0.05; 72 glutPostRedisplay(); 73} 74 75 76static void 77Reshape(int width, int height) 78{ 79 float ar = (float) width / height; 80 glViewport(0, 0, width, height); 81 glMatrixMode(GL_PROJECTION); 82 glLoadIdentity(); 83 glFrustum(-ar, ar, -1, 1, 3, 25); 84 glMatrixMode(GL_MODELVIEW); 85 glLoadIdentity(); 86 glTranslatef(0, 0, -10); 87 88 { 89 GLfloat viewport[4]; 90 glGetFloatv(GL_VIEWPORT, viewport); 91 glUniform2f(uInverseViewportSize, 1.0F / viewport[2], 1.0F / viewport[3]); 92 } 93} 94 95 96static void 97CleanUp(void) 98{ 99 glDeleteShader(FragShader); 100 glDeleteShader(VertShader); 101 glDeleteShader(GeomShader); 102 glDeleteProgram(Program); 103 glutDestroyWindow(Win); 104} 105 106 107static void 108Key(unsigned char key, int x, int y) 109{ 110 (void) x; 111 (void) y; 112 113 switch(key) { 114 case ' ': 115 case 'a': 116 Anim = !Anim; 117 if (Anim) { 118 glutIdleFunc(Idle); 119 } 120 else 121 glutIdleFunc(NULL); 122 break; 123 case 27: 124 CleanUp(); 125 exit(0); 126 break; 127 } 128 glutPostRedisplay(); 129} 130 131 132static GLuint 133MakeTexture(void) 134{ 135#define TEX_SIZE 32 136 GLubyte image[TEX_SIZE][TEX_SIZE][3]; 137 GLuint i, j; 138 GLuint tex; 139 140 glGenTextures(1, &tex); 141 glBindTexture(GL_TEXTURE_2D, tex); 142 143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 145 146 /* 'X' pattern */ 147 for (i = 0; i < TEX_SIZE; i++) { 148 for (j = 0; j < TEX_SIZE; j++) { 149 int p1 = i - j, p2 = TEX_SIZE - 1 - i - j; 150 p1 = (p1 >= -2 && p1 <= 2); 151 p2 = (p2 >= -2 && p2 <= 2); 152 if (p1 || p2) { 153 image[i][j][0] = 255; 154 image[i][j][1] = 255; 155 image[i][j][2] = 255; 156 } 157 else { 158 image[i][j][0] = 50; 159 image[i][j][1] = 50; 160 image[i][j][2] = 50; 161 } 162 } 163 } 164 165 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_SIZE, TEX_SIZE, 0, 166 GL_RGB, GL_UNSIGNED_BYTE, image); 167 168 return tex; 169} 170 171 172static void 173MakePoints(void) 174{ 175 int i; 176 for (i = 0; i < NumPoints; i++) { 177 Points[i][0] = ((rand() % 2000) - 1000.0) / 500.0; 178 Points[i][1] = ((rand() % 2000) - 1000.0) / 500.0; 179 Points[i][2] = ((rand() % 2000) - 1000.0) / 500.0; 180 } 181} 182 183static void 184Init(void) 185{ 186 static const char *fragShaderText = 187 "uniform sampler2D tex; \n" 188 "void main() \n" 189 "{ \n" 190 " gl_FragColor = texture2D(tex, gl_TexCoord[0].xy); \n" 191 "} \n"; 192 static const char *vertShaderText = 193 "void main() \n" 194 "{ \n" 195 " gl_FrontColor = gl_Color; \n" 196 " gl_Position = ftransform(); \n" 197 "} \n"; 198 static const char *geomShaderText = 199 "#version 120 \n" 200 "#extension GL_ARB_geometry_shader4: enable \n" 201 "uniform vec2 InverseViewportSize; \n" 202 "uniform float PointSize; \n" 203 "void main() \n" 204 "{ \n" 205 " vec4 pos = gl_PositionIn[0]; \n" 206 " vec2 d = vec2(PointSize * pos.w) * InverseViewportSize; \n" 207 " gl_FrontColor = gl_FrontColorIn[0]; \n" 208 " gl_TexCoord[0] = vec4(0, 0, 0, 1); \n" 209 " gl_Position = pos + vec4(-d.x, -d.y, 0, 0); \n" 210 " EmitVertex(); \n" 211 " gl_TexCoord[0] = vec4(1, 0, 0, 1); \n" 212 " gl_Position = pos + vec4( d.x, -d.y, 0, 0); \n" 213 " EmitVertex(); \n" 214 " gl_TexCoord[0] = vec4(0, 1, 0, 1); \n" 215 " gl_Position = pos + vec4(-d.x, d.y, 0, 0); \n" 216 " EmitVertex(); \n" 217 " gl_TexCoord[0] = vec4(1, 1, 0, 1); \n" 218 " gl_Position = pos + vec4( d.x, d.y, 0, 0); \n" 219 " EmitVertex(); \n" 220 "} \n"; 221 222 if (!ShadersSupported()) 223 exit(1); 224 225 if (!glutExtensionSupported("GL_ARB_geometry_shader4")) { 226 fprintf(stderr, "Sorry, GL_ARB_geometry_shader4 is not supported.\n"); 227 exit(1); 228 } 229 230 VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText); 231 FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 232 GeomShader = CompileShaderText(GL_GEOMETRY_SHADER_ARB, geomShaderText); 233 assert(GeomShader); 234 235 Program = LinkShaders3(VertShader, GeomShader, FragShader); 236 assert(Program); 237 CheckError(__LINE__); 238 239 /* 240 * The geometry shader will convert incoming points to quads (4-vertex 241 * triangle strips). 242 */ 243 glProgramParameteriARB(Program, GL_GEOMETRY_INPUT_TYPE_ARB, 244 GL_POINTS); 245 glProgramParameteriARB(Program, GL_GEOMETRY_OUTPUT_TYPE_ARB, 246 GL_TRIANGLE_STRIP); 247 glProgramParameteriARB(Program,GL_GEOMETRY_VERTICES_OUT_ARB, 4); 248 CheckError(__LINE__); 249 250 glLinkProgramARB(Program); 251 252 /* check link */ 253 { 254 GLint stat; 255 GetProgramiv(Program, GL_LINK_STATUS, &stat); 256 if (!stat) { 257 GLchar log[1000]; 258 GLsizei len; 259 GetProgramInfoLog(Program, 1000, &len, log); 260 fprintf(stderr, "Shader link error:\n%s\n", log); 261 } 262 } 263 264 CheckError(__LINE__); 265 266 glUseProgram(Program); 267 CheckError(__LINE__); 268 269 uInverseViewportSize = glGetUniformLocation(Program, "InverseViewportSize"); 270 uPointSize = glGetUniformLocation(Program, "PointSize"); 271 272 glUniform1f(uPointSize, 24.0); 273 274 glClearColor(0.3f, 0.3f, 0.3f, 0.0f); 275 276 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 277 278 assert(glIsProgram(Program)); 279 assert(glIsShader(FragShader)); 280 assert(glIsShader(VertShader)); 281 assert(glIsShader(GeomShader)); 282 283 glEnable(GL_DEPTH_TEST); 284 285 MakeTexture(); 286 MakePoints(); 287} 288 289 290int 291main(int argc, char *argv[]) 292{ 293 glutInit(&argc, argv); 294 glutInitWindowSize(WinWidth, WinHeight); 295 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 296 Win = glutCreateWindow(argv[0]); 297 glewInit(); 298 glutReshapeFunc(Reshape); 299 glutKeyboardFunc(Key); 300 glutDisplayFunc(Redisplay); 301 if (Anim) 302 glutIdleFunc(Idle); 303 304 Init(); 305 glutMainLoop(); 306 return 0; 307} 308