2 * Test using a geometry shader to implement polygon outlining.
4 * Based on the technique "Single-Pass Wireframe Rendering" by Andreas
5 * Bærentzen, Steen Lund Nielsen, Mikkel Gjael, Bent D. Larsen & Niels
6 * Jaergen Christensen, SIGGRAPH 2006
18 #include "glut_wrap.h"
19 #include "shaderutil.h"
20 #include "trackball.h"
22 static GLint WinWidth
= 500, WinHeight
= 500;
24 static GLuint VertShader
, GeomShader
, FragShader
, Program
;
25 static GLboolean Anim
= GL_TRUE
;
26 static int uViewportSize
= -1;
28 static const GLfloat Orange
[4] = {1.0, 0.6, 0.0, 1};
30 static float CurQuat
[4] = { 0, 0, 0, 1 };
31 static GLboolean ButtonDown
= GL_FALSE
;
32 static GLint ButtonX
, ButtonY
;
38 GLenum err
= glGetError();
40 printf("GL Error %s (0x%x) at line %d\n",
41 gluErrorString(err
), (int) err
, line
);
51 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
56 build_rotmatrix(rot
, CurQuat
);
57 glMultMatrixf(&rot
[0][0]);
60 glutSolidDodecahedron();
62 glutSolidSphere(2, 30, 20);
73 static const float yAxis
[3] = {0, 1, 0};
74 static double t0
= -1.;
76 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 2000.0;
82 axis_to_quat(yAxis
, 2.0 * dt
, quat
);
83 add_quats(quat
, CurQuat
, CurQuat
);
90 Reshape(int width
, int height
)
92 float ar
= (float) width
/ height
;
95 glViewport(0, 0, width
, height
);
96 glMatrixMode(GL_PROJECTION
);
98 glFrustum(-ar
, ar
, -1, 1, 3, 25);
99 glMatrixMode(GL_MODELVIEW
);
101 glTranslatef(0, 0, -10);
103 /* pass viewport dims to the shader */
106 glGetFloatv(GL_VIEWPORT
, viewport
);
107 glUniform2f(uViewportSize
, viewport
[2], viewport
[3]);
113 MouseMotion(int x
, int y
)
116 float x0
= (2.0 * ButtonX
- WinWidth
) / WinWidth
;
117 float y0
= (WinHeight
- 2.0 * ButtonY
) / WinHeight
;
118 float x1
= (2.0 * x
- WinWidth
) / WinWidth
;
119 float y1
= (WinHeight
- 2.0 * y
) / WinHeight
;
122 trackball(q
, x0
, y0
, x1
, y1
);
125 add_quats(q
, CurQuat
, CurQuat
);
133 MouseButton(int button
, int state
, int x
, int y
)
135 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
136 ButtonDown
= GL_TRUE
;
140 else if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
141 ButtonDown
= GL_FALSE
;
149 glDeleteShader(FragShader
);
150 glDeleteShader(VertShader
);
151 glDeleteShader(GeomShader
);
152 glDeleteProgram(Program
);
153 glutDestroyWindow(Win
);
158 Key(unsigned char key
, int x
, int y
)
185 static const char *vertShaderText
=
189 " gl_FrontColor = gl_Color; \n"
190 " gl_Position = ftransform(); \n"
192 static const char *geomShaderText
=
194 "#extension GL_ARB_geometry_shader4: enable \n"
195 "uniform vec2 ViewportSize; \n"
196 "varying vec2 Vert0, Vert1, Vert2; \n"
198 "// Transform NDC coord to window coord \n"
199 "vec2 vpxform(vec4 p) \n"
201 " return (p.xy / p.w + 1.0) * 0.5 * ViewportSize; \n"
206 " gl_FrontColor = gl_FrontColorIn[0]; \n"
207 " Vert0 = vpxform(gl_PositionIn[0]); \n"
208 " Vert1 = vpxform(gl_PositionIn[1]); \n"
209 " Vert2 = vpxform(gl_PositionIn[2]); \n"
210 " gl_Position = gl_PositionIn[0]; \n"
212 " gl_Position = gl_PositionIn[1]; \n"
214 " gl_Position = gl_PositionIn[2]; \n"
217 static const char *fragShaderText
=
219 "#define LINE_WIDTH 2.5 \n"
220 "varying vec2 Vert0, Vert1, Vert2; \n"
221 "// Compute distance from a point to a line \n"
222 "float point_line_dist(vec2 p, vec2 v1, vec2 v2) \n"
224 " float s = (v2.x - v1.x) * (v1.y - p.y) - (v1.x - p.x) * (v2.y - v1.y); \n"
225 " float t = length(v2 - v1); \n"
226 " return abs(s) / t; \n"
231 " float d0 = point_line_dist(gl_FragCoord.xy, Vert0, Vert1); \n"
232 " float d1 = point_line_dist(gl_FragCoord.xy, Vert1, Vert2); \n"
233 " float d2 = point_line_dist(gl_FragCoord.xy, Vert2, Vert0); \n"
234 " float m = min(d0, min(d1, d2)); \n"
235 " gl_FragColor = gl_Color * smoothstep(0.0, LINE_WIDTH, m); \n"
238 if (!ShadersSupported())
241 if (!glutExtensionSupported("GL_ARB_geometry_shader4")) {
242 fprintf(stderr
, "Sorry, GL_ARB_geometry_shader4 is not supported.\n");
246 VertShader
= CompileShaderText(GL_VERTEX_SHADER
, vertShaderText
);
247 FragShader
= CompileShaderText(GL_FRAGMENT_SHADER
, fragShaderText
);
248 GeomShader
= CompileShaderText(GL_GEOMETRY_SHADER_ARB
, geomShaderText
);
250 Program
= LinkShaders3(VertShader
, GeomShader
, FragShader
);
252 CheckError(__LINE__
);
255 * The geometry shader will receive and emit triangles.
257 glProgramParameteriARB(Program
, GL_GEOMETRY_INPUT_TYPE_ARB
,
259 glProgramParameteriARB(Program
, GL_GEOMETRY_OUTPUT_TYPE_ARB
,
261 glProgramParameteriARB(Program
,GL_GEOMETRY_VERTICES_OUT_ARB
, 3);
262 CheckError(__LINE__
);
265 glLinkProgramARB(Program
);
267 assert(glIsProgram(Program
));
268 assert(glIsShader(FragShader
));
269 assert(glIsShader(VertShader
));
270 assert(glIsShader(GeomShader
));
272 glUseProgram(Program
);
274 uViewportSize
= glGetUniformLocation(Program
, "ViewportSize");
276 glClearColor(0.3f
, 0.3f
, 0.3f
, 0.0f
);
277 glEnable(GL_DEPTH_TEST
);
279 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER
));
284 main(int argc
, char *argv
[])
286 glutInit(&argc
, argv
);
287 glutInitWindowSize(WinWidth
, WinHeight
);
288 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
289 Win
= glutCreateWindow(argv
[0]);
291 glutReshapeFunc(Reshape
);
292 glutKeyboardFunc(Key
);
293 glutDisplayFunc(Redisplay
);
294 glutMotionFunc(MouseMotion
);
295 glutMouseFunc(MouseButton
);