blob: 392dc4db8534a59e5d3e3732abf25a60c19cbc3c [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"
Brian2dca3372008-04-09 22:28:23 -060017#include "shaderutil.h"
Brianaa71b882007-07-29 18:04:23 -060018
19
20static GLuint FragShader;
21static GLuint VertShader;
22static GLuint Program;
23
24static GLint Win = 0;
25static GLint WinWidth = 500, WinHeight = 200;
26static GLfloat Xpos = 0.0f, Ypos = 0.0f;
27static GLint uViewportInv;
28static GLboolean Smooth = GL_TRUE, Blend = GL_TRUE;
29
30
31/**
32 * Issue vertices for a "shader point".
33 * The position is duplicated, only texcoords (or other vertex attrib) change.
34 * The vertex program will compute the "real" quad corners.
35 */
36static void
37PointVertex3f(GLfloat x, GLfloat y, GLfloat z)
38{
39 glTexCoord2f(-1, -1);
40 glVertex3f(x, y, z);
41
42 glTexCoord2f( 1, -1);
43 glVertex3f(x, y, z);
44
45 glTexCoord2f( 1, 1);
46 glVertex3f(x, y, z);
47
48 glTexCoord2f(-1, 1);
49 glVertex3f(x, y, z);
50}
51
52
53static void
54DrawPoints(GLboolean shaderPoints)
55{
56 int i;
57 for (i = 0; i < 9; i++) {
58 GLfloat x = i - 4, y = 0, z = 0;
59 /* note: can't call glPointSize inside Begin/End :( */
60 glPointSize( 2 + i * 5 );
61 if (shaderPoints) {
62 glBegin(GL_QUADS);
63 PointVertex3f(x, y, z);
64 glEnd();
65 }
66 else {
67 glBegin(GL_POINTS);
68 glVertex3f(x, y, z);
69 glEnd();
70 }
71 }
72}
73
74
75/**
76 * Top row of points rendered convetionally,
77 * bottom row rendered with shaders.
78 */
79static void
80Redisplay(void)
81{
82 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
83
84 if (Smooth)
85 glEnable(GL_POINT_SMOOTH);
86 else
87 glDisable(GL_POINT_SMOOTH);
88
89 if (Blend)
90 glEnable(GL_BLEND);
91 else
92 glDisable(GL_BLEND);
93
94 glPushMatrix();
95 glTranslatef(Xpos, Ypos, 0);
96
97 /*
98 * regular points
99 */
100 glPushMatrix();
101 glTranslatef(0, 1.2, 0);
102 glUseProgram_func(0);
103 DrawPoints(GL_FALSE);
104 glPopMatrix();
105
106 /*
107 * shader points
108 */
109 glPushMatrix();
110 glTranslatef(0, -1.2, 0);
111 glUseProgram_func(Program);
112 if (uViewportInv != -1) {
113 glUniform2f_func(uViewportInv, 1.0 / WinWidth, 1.0 / WinHeight);
114 }
115 DrawPoints(GL_TRUE);
116 glPopMatrix();
117
118 glPopMatrix();
119
120 glutSwapBuffers();
121}
122
123
124static void
125Reshape(int width, int height)
126{
127 WinWidth = width;
128 WinHeight = height;
129 glViewport(0, 0, width, height);
130 glMatrixMode(GL_PROJECTION);
131 glLoadIdentity();
132 glFrustum(-1.0, 1.0, -1.0, 1.0, 4.0, 30.0);
133 glMatrixMode(GL_MODELVIEW);
134 glLoadIdentity();
135 glTranslatef(0.0f, 0.0f, -20.0f);
136}
137
138
139static void
140Key(unsigned char key, int x, int y)
141{
142 (void) x;
143 (void) y;
144
145 switch(key) {
146 case 'b':
147 Blend = !Blend;
148 break;
149 case 's':
150 Smooth = !Smooth;
151 break;
152 case 27:
153 glDeleteShader_func(FragShader);
154 glDeleteShader_func(VertShader);
155 glDeleteProgram_func(Program);
156 glutDestroyWindow(Win);
157 exit(0);
158 }
159 glutPostRedisplay();
160}
161
162
163static void
164SpecialKey(int key, int x, int y)
165{
166 const GLfloat step = 1/100.0;
167 switch(key) {
168 case GLUT_KEY_UP:
169 Ypos += step;
170 break;
171 case GLUT_KEY_DOWN:
172 Ypos -= step;
173 break;
174 case GLUT_KEY_LEFT:
175 Xpos -= step;
176 break;
177 case GLUT_KEY_RIGHT:
178 Xpos += step;
179 break;
180 }
181 glutPostRedisplay();
182}
183
184
185static void
Brianaa71b882007-07-29 18:04:23 -0600186Init(void)
187{
Brian5c6f1f52007-07-30 08:52:57 -0600188 /* Fragment shader: compute distance of fragment from center of point
189 * (we're using texcoords but another varying could be used).
190 * if dist > 1, discard (coverage==0)
191 * if dist < k, coverage = 1
192 * else, coverage = func(dist)
193 * Note: length() uses sqrt() and may be expensive. The distance could
194 * be squared instead (with adjustments to the threshold (k) test)
Brianaa71b882007-07-29 18:04:23 -0600195 */
196 static const char *fragShaderText =
197 "void main() {\n"
198 " float cover; \n"
199 " float k = 2.0 / gl_Point.size; \n"
200 " float d = length(gl_TexCoord[0].xy); \n"
201 " if (d >= 1.0) \n"
202 " discard; \n"
203 " if (d < 1.0 - k) \n"
204 " cover = 1.0; \n"
205 " else \n"
206 " cover = (1.0 - d) * 0.5 * gl_Point.size; \n"
207 " gl_FragColor.rgb = gl_Color.rgb; \n"
208 " gl_FragColor.a = cover; \n"
209 "}\n";
210 /* Vertex shader: compute new vertex position based on incoming vertex pos,
Brian5c6f1f52007-07-30 08:52:57 -0600211 * texcoords, point size, and inverse viewport scale factor.
212 * Note: should compute point size attenuation here too.
Brianaa71b882007-07-29 18:04:23 -0600213 */
214 static const char *vertShaderText =
215 "uniform vec2 viewportInv; \n"
216 "void main() {\n"
Brian5c6f1f52007-07-30 08:52:57 -0600217 " vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
218 " gl_Position.xy = pos.xy + gl_MultiTexCoord0.xy * viewportInv \n"
219 " * gl_Point.size * pos.w; \n"
220 " gl_Position.zw = pos.zw; \n"
Brianaa71b882007-07-29 18:04:23 -0600221 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
222 " gl_FrontColor = gl_Color; \n"
223 "}\n";
Brianaa71b882007-07-29 18:04:23 -0600224
Brian2dca3372008-04-09 22:28:23 -0600225 if (!ShadersSupported())
Brianaa71b882007-07-29 18:04:23 -0600226 exit(1);
Brianaa71b882007-07-29 18:04:23 -0600227
228 GetExtensionFuncs();
229
Brian2dca3372008-04-09 22:28:23 -0600230 VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
231 FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
232 Program = LinkShaders(VertShader, FragShader);
Brianaa71b882007-07-29 18:04:23 -0600233
Brianaa71b882007-07-29 18:04:23 -0600234 glUseProgram_func(Program);
235
236 uViewportInv = glGetUniformLocation_func(Program, "viewportInv");
237
238 glUseProgram_func(0);
239
240 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
241}
242
243
244int
245main(int argc, char *argv[])
246{
247 glutInit(&argc, argv);
248 glutInitWindowSize(WinWidth, WinHeight);
249 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
250 Win = glutCreateWindow(argv[0]);
251 glutReshapeFunc(Reshape);
252 glutKeyboardFunc(Key);
253 glutSpecialFunc(SpecialKey);
254 glutDisplayFunc(Redisplay);
255 Init();
256 glutMainLoop();
257 return 0;
258}
259
260