2 * Test using a geometry and fragment shaders to implement stippled lines.
14 #include "glut_wrap.h"
15 #include "shaderutil.h"
17 static GLint WinWidth
= 500, WinHeight
= 500;
19 static GLuint VertShader
, GeomShader
, FragShader
, Program
;
20 static GLboolean Anim
= GL_TRUE
;
21 static GLboolean UseGeomShader
= GL_TRUE
;
22 static GLfloat Xrot
= 0, Yrot
= 0;
23 static int uViewportSize
= -1, uStippleFactor
= -1, uStipplePattern
= -1;
24 static const int NumPoints
= 50;
25 static float Points
[100][3], Colors
[100][3];
27 static const GLushort StipplePattern
= 0x10ff;
28 static GLuint StippleFactor
= 2;
34 GLenum err
= glGetError();
36 printf("GL Error %s (0x%x) at line %d\n",
37 gluErrorString(err
), (int) err
, line
);
43 * Set stipple factor and pattern for geometry shader.
45 * We convert the 16-bit stipple pattern into an array of 16 float values
46 * then pass the array as a uniform variable.
48 * Note: With GLSL 1.30 or later the stipple pattern could be implemented
49 * as an ordinary integer since GLSL 1.30 has true integer types and bit
50 * shifts and bit masks.
54 SetStippleUniform(GLint factor
, GLushort pattern
)
58 for (i
= 0; i
< 16; i
++) {
59 p
[i
] = (pattern
& (1 << i
)) ? 1.0f
: 0.0f
;
61 glUniform1fv(uStipplePattern
, 16, p
);
62 glUniform1f(uStippleFactor
, factor
);
71 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
74 glRotatef(Xrot
, 1, 0, 0);
75 glRotatef(Yrot
, 0, 0, 1);
78 glUseProgram(Program
);
79 glDisable(GL_LINE_STIPPLE
);
83 glEnable(GL_LINE_STIPPLE
);
87 for (i
= 0; i
< NumPoints
; i
++) {
88 glColor3fv(Colors
[i
]);
89 glVertex3fv(Points
[i
]);
102 int curTime
= glutGet(GLUT_ELAPSED_TIME
);
103 Xrot
= curTime
* 0.02;
104 Yrot
= curTime
* 0.05;
110 Reshape(int width
, int height
)
112 float ar
= (float) width
/ height
;
113 glViewport(0, 0, width
, height
);
114 glMatrixMode(GL_PROJECTION
);
117 glFrustum(-ar
, ar
, -1, 1, 3, 25);
119 glOrtho(-3.0*ar
, 3.0*ar
, -3.0, 3.0, 3, 25);
121 glMatrixMode(GL_MODELVIEW
);
123 glTranslatef(0, 0, -10);
127 glGetFloatv(GL_VIEWPORT
, viewport
);
128 glUniform2f(uViewportSize
, viewport
[2], viewport
[3]);
136 glDeleteShader(FragShader
);
137 glDeleteShader(VertShader
);
138 glDeleteShader(GeomShader
);
139 glDeleteProgram(Program
);
140 glutDestroyWindow(Win
);
145 Key(unsigned char key
, int x
, int y
)
161 UseGeomShader
= !UseGeomShader
;
162 printf("Use geometry shader? %d\n", UseGeomShader
);
180 for (i
= 0; i
< NumPoints
; i
++) {
181 Colors
[i
][0] = (rand() % 1000) / 1000.0;
182 Colors
[i
][1] = (rand() % 1000) / 1000.0;
183 Colors
[i
][2] = (rand() % 1000) / 1000.0;
184 Points
[i
][0] = ((rand() % 2000) - 1000.0) / 500.0;
185 Points
[i
][1] = ((rand() % 2000) - 1000.0) / 500.0;
186 Points
[i
][2] = ((rand() % 2000) - 1000.0) / 500.0;
194 static const char *fragShaderText
=
195 "uniform float StipplePattern[16]; \n"
196 "varying float stippleCoord; \n"
199 " // check the stipple pattern and discard if value is zero \n"
200 " // TODO: we should really undo the perspective interpolation here \n"
201 " // so that it's linear. \n"
202 " float stip = StipplePattern[int(fract(stippleCoord) * 16.0)]; \n"
203 " if (stip == 0.0) \n"
205 " gl_FragColor = gl_Color; \n"
207 static const char *vertShaderText
=
210 " gl_FrontColor = gl_Color; \n"
211 " gl_Position = ftransform(); \n"
213 static const char *geomShaderText
=
215 "#extension GL_ARB_geometry_shader4: enable \n"
216 "uniform vec2 ViewportSize; \n"
217 "uniform float StippleFactor; \n"
218 "varying float stippleCoord; \n"
221 " vec4 pos0 = gl_PositionIn[0]; \n"
222 " vec4 pos1 = gl_PositionIn[1]; \n"
223 " // Convert eye coords to window coords \n"
224 " // Note: we're off by a factor of two here, make up for that below \n"
225 " vec2 p0 = pos0.xy / pos0.w * ViewportSize; \n"
226 " vec2 p1 = pos1.xy / pos1.w * ViewportSize; \n"
227 " float len = length(p0.xy - p1.xy); \n"
228 " // Emit first vertex \n"
229 " gl_FrontColor = gl_FrontColorIn[0]; \n"
230 " gl_Position = pos0; \n"
231 " stippleCoord = 0.0; \n"
233 " // Emit second vertex \n"
234 " gl_FrontColor = gl_FrontColorIn[1]; \n"
235 " gl_Position = pos1; \n"
236 " stippleCoord = len / StippleFactor / 32.0; // Note: not 16, see above \n"
240 if (!ShadersSupported())
243 if (!glutExtensionSupported("GL_ARB_geometry_shader4")) {
244 fprintf(stderr
, "Sorry, GL_ARB_geometry_shader4 is not supported.\n");
248 VertShader
= CompileShaderText(GL_VERTEX_SHADER
, vertShaderText
);
249 FragShader
= CompileShaderText(GL_FRAGMENT_SHADER
, fragShaderText
);
250 GeomShader
= CompileShaderText(GL_GEOMETRY_SHADER_ARB
, geomShaderText
);
253 Program
= LinkShaders3(VertShader
, GeomShader
, FragShader
);
255 CheckError(__LINE__
);
258 * The geometry shader accepts lines and produces lines.
260 glProgramParameteriARB(Program
, GL_GEOMETRY_INPUT_TYPE_ARB
,
262 glProgramParameteriARB(Program
, GL_GEOMETRY_OUTPUT_TYPE_ARB
,
264 glProgramParameteriARB(Program
, GL_GEOMETRY_VERTICES_OUT_ARB
, 4);
265 CheckError(__LINE__
);
267 glLinkProgramARB(Program
);
272 GetProgramiv(Program
, GL_LINK_STATUS
, &stat
);
276 GetProgramInfoLog(Program
, 1000, &len
, log
);
277 fprintf(stderr
, "Shader link error:\n%s\n", log
);
281 glUseProgram(Program
);
283 uViewportSize
= glGetUniformLocation(Program
, "ViewportSize");
284 uStippleFactor
= glGetUniformLocation(Program
, "StippleFactor");
285 uStipplePattern
= glGetUniformLocation(Program
, "StipplePattern");
287 glUniform1f(uStippleFactor
, StippleFactor
);
289 glClearColor(0.3f
, 0.3f
, 0.3f
, 0.0f
);
291 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER
));
293 assert(glIsProgram(Program
));
294 assert(glIsShader(FragShader
));
295 assert(glIsShader(VertShader
));
296 assert(glIsShader(GeomShader
));
299 glLineStipple(StippleFactor
, StipplePattern
);
300 SetStippleUniform(StippleFactor
, StipplePattern
);
307 main(int argc
, char *argv
[])
309 glutInit(&argc
, argv
);
310 glutInitWindowSize(WinWidth
, WinHeight
);
311 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
312 Win
= glutCreateWindow(argv
[0]);
314 glutReshapeFunc(Reshape
);
315 glutKeyboardFunc(Key
);
316 glutDisplayFunc(Redisplay
);