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