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
18 static GLint WinWidth = 500, WinHeight = 500;
19 static GLint Win = 0;
20 static GLuint VertShader, GeomShader, FragShader, Program;
21 static GLboolean Anim = GL_TRUE;
22 static GLfloat Xrot = 0, Yrot = 0;
23 static int uPointSize = -1, uInverseViewportSize = -1;
24
25 static const int NumPoints = 50;
26 static float Points[100][3];
27
28 static const GLfloat Red[4] = {1, 0, 0, 1};
29 static const GLfloat Green[4] = {0, 1, 0, 0};
30
31
32 static void
CheckError(int line)33 CheckError(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
43 static void
Redisplay(void)44 Redisplay(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
66 static void
Idle(void)67 Idle(void)
68 {
69 int curTime = glutGet(GLUT_ELAPSED_TIME);
70 Xrot = curTime * 0.02;
71 Yrot = curTime * 0.05;
72 glutPostRedisplay();
73 }
74
75
76 static void
Reshape(int width,int height)77 Reshape(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
96 static void
CleanUp(void)97 CleanUp(void)
98 {
99 glDeleteShader(FragShader);
100 glDeleteShader(VertShader);
101 glDeleteShader(GeomShader);
102 glDeleteProgram(Program);
103 glutDestroyWindow(Win);
104 }
105
106
107 static void
Key(unsigned char key,int x,int y)108 Key(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
132 static GLuint
MakeTexture(void)133 MakeTexture(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
172 static void
MakePoints(void)173 MakePoints(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
183 static void
Init(void)184 Init(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
290 int
main(int argc,char * argv[])291 main(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