blob: 85115de504a2739410779b7ac4496020e6b90bf0 [file] [log] [blame]
Brianaa71b882007-07-29 18:04:23 -06001/**
2 * Implement smooth (AA) points with shaders.
3 * A simple variation could be used for sprite points.
4 * Brian Paul
5 * 29 July 2007
6 */
7
8#include <assert.h>
9#include <string.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <math.h>
13#include <GL/gl.h>
14#include <GL/glut.h>
15#include <GL/glext.h>
16#include "extfuncs.h"
17
18
19static GLuint FragShader;
20static GLuint VertShader;
21static GLuint Program;
22
23static GLint Win = 0;
24static GLint WinWidth = 500, WinHeight = 200;
25static GLfloat Xpos = 0.0f, Ypos = 0.0f;
26static GLint uViewportInv;
27static GLboolean Smooth = GL_TRUE, Blend = GL_TRUE;
28
29
30/**
31 * Issue vertices for a "shader point".
32 * The position is duplicated, only texcoords (or other vertex attrib) change.
33 * The vertex program will compute the "real" quad corners.
34 */
35static void
36PointVertex3f(GLfloat x, GLfloat y, GLfloat z)
37{
38 glTexCoord2f(-1, -1);
39 glVertex3f(x, y, z);
40
41 glTexCoord2f( 1, -1);
42 glVertex3f(x, y, z);
43
44 glTexCoord2f( 1, 1);
45 glVertex3f(x, y, z);
46
47 glTexCoord2f(-1, 1);
48 glVertex3f(x, y, z);
49}
50
51
52static void
53DrawPoints(GLboolean shaderPoints)
54{
55 int i;
56 for (i = 0; i < 9; i++) {
57 GLfloat x = i - 4, y = 0, z = 0;
58 /* note: can't call glPointSize inside Begin/End :( */
59 glPointSize( 2 + i * 5 );
60 if (shaderPoints) {
61 glBegin(GL_QUADS);
62 PointVertex3f(x, y, z);
63 glEnd();
64 }
65 else {
66 glBegin(GL_POINTS);
67 glVertex3f(x, y, z);
68 glEnd();
69 }
70 }
71}
72
73
74/**
75 * Top row of points rendered convetionally,
76 * bottom row rendered with shaders.
77 */
78static void
79Redisplay(void)
80{
81 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
82
83 if (Smooth)
84 glEnable(GL_POINT_SMOOTH);
85 else
86 glDisable(GL_POINT_SMOOTH);
87
88 if (Blend)
89 glEnable(GL_BLEND);
90 else
91 glDisable(GL_BLEND);
92
93 glPushMatrix();
94 glTranslatef(Xpos, Ypos, 0);
95
96 /*
97 * regular points
98 */
99 glPushMatrix();
100 glTranslatef(0, 1.2, 0);
101 glUseProgram_func(0);
102 DrawPoints(GL_FALSE);
103 glPopMatrix();
104
105 /*
106 * shader points
107 */
108 glPushMatrix();
109 glTranslatef(0, -1.2, 0);
110 glUseProgram_func(Program);
111 if (uViewportInv != -1) {
112 glUniform2f_func(uViewportInv, 1.0 / WinWidth, 1.0 / WinHeight);
113 }
114 DrawPoints(GL_TRUE);
115 glPopMatrix();
116
117 glPopMatrix();
118
119 glutSwapBuffers();
120}
121
122
123static void
124Reshape(int width, int height)
125{
126 WinWidth = width;
127 WinHeight = height;
128 glViewport(0, 0, width, height);
129 glMatrixMode(GL_PROJECTION);
130 glLoadIdentity();
131 glFrustum(-1.0, 1.0, -1.0, 1.0, 4.0, 30.0);
132 glMatrixMode(GL_MODELVIEW);
133 glLoadIdentity();
134 glTranslatef(0.0f, 0.0f, -20.0f);
135}
136
137
138static void
139Key(unsigned char key, int x, int y)
140{
141 (void) x;
142 (void) y;
143
144 switch(key) {
145 case 'b':
146 Blend = !Blend;
147 break;
148 case 's':
149 Smooth = !Smooth;
150 break;
151 case 27:
152 glDeleteShader_func(FragShader);
153 glDeleteShader_func(VertShader);
154 glDeleteProgram_func(Program);
155 glutDestroyWindow(Win);
156 exit(0);
157 }
158 glutPostRedisplay();
159}
160
161
162static void
163SpecialKey(int key, int x, int y)
164{
165 const GLfloat step = 1/100.0;
166 switch(key) {
167 case GLUT_KEY_UP:
168 Ypos += step;
169 break;
170 case GLUT_KEY_DOWN:
171 Ypos -= step;
172 break;
173 case GLUT_KEY_LEFT:
174 Xpos -= step;
175 break;
176 case GLUT_KEY_RIGHT:
177 Xpos += step;
178 break;
179 }
180 glutPostRedisplay();
181}
182
183
184static void
185LoadAndCompileShader(GLuint shader, const char *text)
186{
187 GLint stat;
188
189 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
190
191 glCompileShader_func(shader);
192
193 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
194 if (!stat) {
195 GLchar log[1000];
196 GLsizei len;
197 glGetShaderInfoLog_func(shader, 1000, &len, log);
198 fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
199 exit(1);
200 }
201}
202
203
204static void
205CheckLink(GLuint prog)
206{
207 GLint stat;
208 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
209 if (!stat) {
210 GLchar log[1000];
211 GLsizei len;
212 glGetProgramInfoLog_func(prog, 1000, &len, log);
213 fprintf(stderr, "Linker error:\n%s\n", log);
214 }
215}
216
217
218static void
219Init(void)
220{
Brian5c6f1f52007-07-30 08:52:57 -0600221 /* Fragment shader: compute distance of fragment from center of point
222 * (we're using texcoords but another varying could be used).
223 * if dist > 1, discard (coverage==0)
224 * if dist < k, coverage = 1
225 * else, coverage = func(dist)
226 * Note: length() uses sqrt() and may be expensive. The distance could
227 * be squared instead (with adjustments to the threshold (k) test)
Brianaa71b882007-07-29 18:04:23 -0600228 */
229 static const char *fragShaderText =
230 "void main() {\n"
231 " float cover; \n"
232 " float k = 2.0 / gl_Point.size; \n"
233 " float d = length(gl_TexCoord[0].xy); \n"
234 " if (d >= 1.0) \n"
235 " discard; \n"
236 " if (d < 1.0 - k) \n"
237 " cover = 1.0; \n"
238 " else \n"
239 " cover = (1.0 - d) * 0.5 * gl_Point.size; \n"
240 " gl_FragColor.rgb = gl_Color.rgb; \n"
241 " gl_FragColor.a = cover; \n"
242 "}\n";
243 /* Vertex shader: compute new vertex position based on incoming vertex pos,
Brian5c6f1f52007-07-30 08:52:57 -0600244 * texcoords, point size, and inverse viewport scale factor.
245 * Note: should compute point size attenuation here too.
Brianaa71b882007-07-29 18:04:23 -0600246 */
247 static const char *vertShaderText =
248 "uniform vec2 viewportInv; \n"
249 "void main() {\n"
Brian5c6f1f52007-07-30 08:52:57 -0600250 " vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
251 " gl_Position.xy = pos.xy + gl_MultiTexCoord0.xy * viewportInv \n"
252 " * gl_Point.size * pos.w; \n"
253 " gl_Position.zw = pos.zw; \n"
Brianaa71b882007-07-29 18:04:23 -0600254 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
255 " gl_FrontColor = gl_Color; \n"
256 "}\n";
257 const char *version;
258
259 version = (const char *) glGetString(GL_VERSION);
260 if (version[0] != '2' || version[1] != '.') {
261 printf("This program requires OpenGL 2.x, found %s\n", version);
262 exit(1);
263 }
264 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
265
266 GetExtensionFuncs();
267
268 FragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
269 LoadAndCompileShader(FragShader, fragShaderText);
270
271 VertShader = glCreateShader_func(GL_VERTEX_SHADER);
272 LoadAndCompileShader(VertShader, vertShaderText);
273
274 Program = glCreateProgram_func();
275 glAttachShader_func(Program, FragShader);
276 glAttachShader_func(Program, VertShader);
277 glLinkProgram_func(Program);
278 CheckLink(Program);
279 glUseProgram_func(Program);
280
281 uViewportInv = glGetUniformLocation_func(Program, "viewportInv");
282
283 glUseProgram_func(0);
284
285 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
286}
287
288
289int
290main(int argc, char *argv[])
291{
292 glutInit(&argc, argv);
293 glutInitWindowSize(WinWidth, WinHeight);
294 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
295 Win = glutCreateWindow(argv[0]);
296 glutReshapeFunc(Reshape);
297 glutKeyboardFunc(Key);
298 glutSpecialFunc(SpecialKey);
299 glutDisplayFunc(Redisplay);
300 Init();
301 glutMainLoop();
302 return 0;
303}
304
305