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