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