1 /*
2 * Simple example for testing basic features of
3 * geometry shaders
4 */
5
6 #include <assert.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <math.h>
11 #include <glad/glad.h>
12 #include "glut_wrap.h"
13
14 static const char *filename = NULL;
15 static GLuint nr_steps = 0;
16
17 static GLuint fragShader;
18 static GLuint vertShader;
19 static GLuint geoShader;
20 static GLuint program;
21
usage(char * name)22 static void usage( char *name )
23 {
24 fprintf(stderr, "usage: %s [ options ] shader_filename\n", name);
25 fprintf(stderr, "\n" );
26 fprintf(stderr, "options:\n" );
27 fprintf(stderr, " -f flat shaded\n" );
28 fprintf(stderr, " -nNr subdivision steps\n" );
29 }
30
31
load_and_compile_shader(GLuint shader,const char * text)32 static void load_and_compile_shader(GLuint shader, const char *text)
33 {
34 GLint stat;
35
36 glShaderSource(shader, 1, (const GLchar **) &text, NULL);
37 glCompileShader(shader);
38 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
39 if (!stat) {
40 GLchar log[1000];
41 GLsizei len;
42 glGetShaderInfoLog(shader, 1000, &len, log);
43 fprintf(stderr, "gp: problem compiling shader:\n%s\n", log);
44 exit(1);
45 }
46 }
47
read_shader(GLuint shader,const char * filename)48 static void read_shader(GLuint shader, const char *filename)
49 {
50 const int max = 100*1000;
51 int n;
52 char *buffer = (char*) malloc(max);
53 FILE *f = fopen(filename, "r");
54 if (!f) {
55 fprintf(stderr, "gp: Unable to open shader file %s\n", filename);
56 exit(1);
57 }
58
59 n = fread(buffer, 1, max, f);
60 printf("gp: read %d bytes from shader file %s\n", n, filename);
61 if (n > 0) {
62 buffer[n] = 0;
63 load_and_compile_shader(shader, buffer);
64 }
65
66 fclose(f);
67 free(buffer);
68 }
69
check_link(GLuint prog)70 static void check_link(GLuint prog)
71 {
72 GLint stat;
73 glGetProgramiv(prog, GL_LINK_STATUS, &stat);
74 if (!stat) {
75 GLchar log[1000];
76 GLsizei len;
77 glGetProgramInfoLog(prog, 1000, &len, log);
78 fprintf(stderr, "Linker error:\n%s\n", log);
79 }
80 }
81
prepare_shaders(void)82 static void prepare_shaders(void)
83 {
84 static const char *fragShaderText =
85 "void main() {\n"
86 " gl_FragColor = gl_Color;\n"
87 "}\n";
88 static const char *vertShaderText =
89 "void main() {\n"
90 " gl_FrontColor = gl_Color;\n"
91 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
92 "}\n";
93 static const char *geoShaderText =
94 "#version 120\n"
95 "#extension GL_ARB_geometry_shader4 : enable\n"
96 "void main()\n"
97 "{\n"
98 " for(int i = 0; i < gl_VerticesIn; ++i)\n"
99 " {\n"
100 " gl_FrontColor = gl_FrontColorIn[i];\n"
101 " gl_Position = gl_PositionIn[i];\n"
102 " EmitVertex();\n"
103 " }\n"
104 "}\n";
105
106 if (!glutExtensionSupported("GL_ARB_geometry_shader4")) {
107 fprintf(stderr, "needs GL_ARB_geometry_shader4 extension\n");
108 exit(1);
109 }
110
111 fragShader = glCreateShader(GL_FRAGMENT_SHADER);
112 load_and_compile_shader(fragShader, fragShaderText);
113
114 vertShader = glCreateShader(GL_VERTEX_SHADER);
115 load_and_compile_shader(vertShader, vertShaderText);
116
117 geoShader = glCreateShader(GL_GEOMETRY_SHADER_ARB);
118 if (filename)
119 read_shader(geoShader, filename);
120 else
121 load_and_compile_shader(geoShader,
122 geoShaderText);
123
124 program = glCreateProgram();
125 glAttachShader(program, vertShader);
126 glAttachShader(program, geoShader);
127 glAttachShader(program, fragShader);
128
129 glProgramParameteriARB(program, GL_GEOMETRY_INPUT_TYPE_ARB, GL_TRIANGLES);
130 glProgramParameteriARB(program, GL_GEOMETRY_OUTPUT_TYPE_ARB,
131 GL_TRIANGLE_STRIP);
132
133 {
134 int temp;
135 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB,&temp);
136 glProgramParameteriARB(program,GL_GEOMETRY_VERTICES_OUT_ARB,temp);
137 }
138
139 glLinkProgram(program);
140 check_link(program);
141 glUseProgram(program);
142 }
143
args(int argc,char * argv[])144 static void args(int argc, char *argv[])
145 {
146 GLint i;
147
148 for (i = 1; i < argc; i++) {
149 if (strncmp(argv[i], "-n", 2) == 0) {
150 nr_steps = atoi((argv[i]) + 2);
151 }
152 else if (strcmp(argv[i], "-f") == 0) {
153 glShadeModel(GL_FLAT);
154 }
155 else if (i == argc - 1) {
156 filename = argv[i];
157 }
158 else {
159 usage(argv[0]);
160 exit(1);
161 }
162 }
163
164 if (!filename) {
165 usage(argv[0]);
166 exit(1);
167 }
168 }
169
170
171
172
173 union vert {
174 struct {
175 GLfloat color[3];
176 GLfloat pos[3];
177 } v;
178 GLfloat f[6];
179 };
180
make_midpoint(union vert * out,const union vert * v0,const union vert * v1)181 static void make_midpoint( union vert *out,
182 const union vert *v0,
183 const union vert *v1)
184 {
185 int i;
186 for (i = 0; i < 6; i++)
187 out->f[i] = v0->f[i] + .5 * (v1->f[i] - v0->f[i]);
188 }
189
subdiv(union vert * v0,union vert * v1,union vert * v2,GLuint depth)190 static void subdiv( union vert *v0,
191 union vert *v1,
192 union vert *v2,
193 GLuint depth )
194 {
195 if (depth == 0) {
196 glColor3fv(v0->v.color);
197 glVertex3fv(v0->v.pos);
198 glColor3fv(v1->v.color);
199 glVertex3fv(v1->v.pos);
200 glColor3fv(v2->v.color);
201 glVertex3fv(v2->v.pos);
202 }
203 else {
204 union vert m[3];
205
206 make_midpoint(&m[0], v0, v1);
207 make_midpoint(&m[1], v1, v2);
208 make_midpoint(&m[2], v2, v0);
209
210 subdiv(&m[0], &m[2], v0, depth-1);
211 subdiv(&m[1], &m[0], v1, depth-1);
212 subdiv(&m[2], &m[1], v2, depth-1);
213 subdiv(&m[0], &m[1], &m[2], depth-1);
214 }
215 }
216
217 /** Assignment */
218 #define ASSIGN_3V( V, V0, V1, V2 ) \
219 do { \
220 V[0] = V0; \
221 V[1] = V1; \
222 V[2] = V2; \
223 } while(0)
224
Display(void)225 static void Display( void )
226 {
227 glClearColor(0.3, 0.3, 0.3, 1);
228 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
229
230 glUseProgram(program);
231
232 glBegin(GL_TRIANGLES);
233
234
235 {
236 union vert v[3];
237
238 ASSIGN_3V(v[0].v.color, 0,0,1);
239 ASSIGN_3V(v[0].v.pos, 0.9, -0.9, 0.0);
240 ASSIGN_3V(v[1].v.color, 1,0,0);
241 ASSIGN_3V(v[1].v.pos, 0.9, 0.9, 0.0);
242 ASSIGN_3V(v[2].v.color, 0,1,0);
243 ASSIGN_3V(v[2].v.pos, -0.9, 0, 0.0);
244
245 subdiv(&v[0], &v[1], &v[2], nr_steps);
246 }
247
248 glEnd();
249
250
251 glFlush();
252 }
253
254
Reshape(int width,int height)255 static void Reshape( int width, int height )
256 {
257 glViewport( 0, 0, width, height );
258 glMatrixMode( GL_PROJECTION );
259 glLoadIdentity();
260 glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
261 glMatrixMode( GL_MODELVIEW );
262 glLoadIdentity();
263 /*glTranslatef( 0.0, 0.0, -15.0 );*/
264 }
265
266
CleanUp(void)267 static void CleanUp(void)
268 {
269 glDeleteShader(fragShader);
270 glDeleteShader(vertShader);
271 glDeleteProgram(program);
272 }
273
Key(unsigned char key,int x,int y)274 static void Key( unsigned char key, int x, int y )
275 {
276 (void) x;
277 (void) y;
278 switch (key) {
279 case 27:
280 CleanUp();
281 exit(0);
282 break;
283 }
284 glutPostRedisplay();
285 }
286
main(int argc,char * argv[])287 int main( int argc, char *argv[] )
288 {
289 glutInit( &argc, argv );
290 glutInitWindowPosition( 0, 0 );
291 glutInitWindowSize( 250, 250 );
292 glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
293 glutCreateWindow(argv[0]);
294 gladLoadGL();
295 glutReshapeFunc( Reshape );
296 glutKeyboardFunc( Key );
297 glutDisplayFunc( Display );
298 args( argc, argv );
299 prepare_shaders();
300 glutMainLoop();
301 return 0;
302 }
303