Merge commit 'origin/gallium-0.1'
[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/gl.h>
14 #include <GL/glut.h>
15 #include <GL/glext.h>
16 #include "extfuncs.h"
17 #include "shaderutil.h"
18
19
20 static GLuint FragShader;
21 static GLuint VertShader;
22 static GLuint Program;
23
24 static GLint Win = 0;
25 static GLint WinWidth = 500, WinHeight = 200;
26 static GLfloat Xpos = 0.0f, Ypos = 0.0f;
27 static GLint uViewportInv;
28 static 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 */
36 static void
37 PointVertex3f(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
53 static void
54 DrawPoints(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 */
79 static void
80 Redisplay(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
124 static void
125 Reshape(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
139 static void
140 Key(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
163 static void
164 SpecialKey(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
185 static void
186 Init(void)
187 {
188 /* 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)
195 */
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,
211 * texcoords, point size, and inverse viewport scale factor.
212 * Note: should compute point size attenuation here too.
213 */
214 static const char *vertShaderText =
215 "uniform vec2 viewportInv; \n"
216 "void main() {\n"
217 " 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"
221 " gl_TexCoord[0] = gl_MultiTexCoord0; \n"
222 " gl_FrontColor = gl_Color; \n"
223 "}\n";
224
225 if (!ShadersSupported())
226 exit(1);
227
228 GetExtensionFuncs();
229
230 VertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
231 FragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
232 Program = LinkShaders(VertShader, FragShader);
233
234 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
244 int
245 main(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