1 
2 #include <assert.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <math.h>
7 
8 #include <GL/glew.h>
9 #include "glut_wrap.h"
10 
11 static const char *filename = NULL;
12 static GLuint nr_steps = 4;
13 static GLuint prim = GL_TRIANGLES;
14 static GLfloat psz = 1.0;
15 static GLboolean pointsmooth = 0;
16 static GLboolean program_point_size = 0;
17 
18 static GLuint fragShader;
19 static GLuint vertShader;
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 
38    glCompileShader(shader);
39 
40    glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
41    if (!stat) {
42       GLchar log[1000];
43       GLsizei len;
44       glGetShaderInfoLog(shader, 1000, &len, log);
45       fprintf(stderr, "vp-tris: problem compiling shader:\n%s\n", log);
46       exit(1);
47    }
48 }
49 
read_shader(GLuint shader,const char * filename)50 static void read_shader(GLuint shader, const char *filename)
51 {
52    const int max = 100*1000;
53    int n;
54    char *buffer = (char*) malloc(max);
55    FILE *f = fopen(filename, "r");
56    if (!f) {
57       fprintf(stderr, "vp-tris: Unable to open shader file %s\n", filename);
58       exit(1);
59    }
60 
61    n = fread(buffer, 1, max, f);
62    printf("vp-tris: read %d bytes from shader file %s\n", n, filename);
63    if (n > 0) {
64       buffer[n] = 0;
65       load_and_compile_shader(shader, buffer);
66    }
67 
68    fclose(f);
69    free(buffer);
70 }
71 
check_link(GLuint prog)72 static void check_link(GLuint prog)
73 {
74    GLint stat;
75    glGetProgramiv(prog, GL_LINK_STATUS, &stat);
76    if (!stat) {
77       GLchar log[1000];
78       GLsizei len;
79       glGetProgramInfoLog(prog, 1000, &len, log);
80       fprintf(stderr, "Linker error:\n%s\n", log);
81    }
82 }
83 
setup_uniforms(void)84 static void setup_uniforms(void)
85 {
86    {
87       GLint loc1f = glGetUniformLocationARB(program, "Offset1f");
88       GLint loc2f = glGetUniformLocationARB(program, "Offset2f");
89       GLint loc4f = glGetUniformLocationARB(program, "Offset4f");
90       GLfloat vecKer[] =
91          { 1.0, 0.0, 0.0,  1.0,
92            0.0, 1.0, 0.0,  1.0,
93            1.0, 0.0, 0.0,  1.0,
94            0.0, 0.0, 0.0,  1.0
95          };
96       if (loc1f >= 0)
97          glUniform1fv(loc1f, 16, vecKer);
98 
99       if (loc2f >= 0)
100          glUniform2fv(loc2f, 8, vecKer);
101 
102       if (loc4f >= 0)
103          glUniform4fv(loc4f, 4, vecKer);
104 
105    }
106 
107    {
108       GLint loc1f = glGetUniformLocationARB(program, "KernelValue1f");
109       GLint loc2f = glGetUniformLocationARB(program, "KernelValue2f");
110       GLint loc4f = glGetUniformLocationARB(program, "KernelValue4f");
111       GLfloat vecKer[] =
112          { 1.0, 0.0, 0.0,  0.25,
113            0.0, 1.0, 0.0,  0.25,
114            0.0, 0.0, 1.0,  0.25,
115            0.0, 0.0, 0.0,  0.25,
116            0.5, 0.0, 0.0,  0.35,
117            0.0, 0.5, 0.0,  0.35,
118            0.0, 0.0, 0.5,  0.35,
119            0.0, 0.0, 0.0,  0.35
120          };
121       if (loc1f >= 0)
122          glUniform1fv(loc1f, 16, vecKer);
123 
124       if (loc2f >= 0)
125          glUniform2fv(loc2f, 8, vecKer);
126 
127       if (loc4f >= 0)
128          glUniform4fv(loc4f, 4, vecKer);
129    }
130 }
131 
prepare_shaders(void)132 static void prepare_shaders(void)
133 {
134    static const char *fragShaderText =
135       "void main() {\n"
136       "    gl_FragColor = gl_Color;\n"
137       "}\n";
138    static const char *vertShaderText =
139       "void main() {\n"
140       "   gl_FrontColor = gl_Color;\n"
141       "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
142       "}\n";
143    fragShader = glCreateShader(GL_FRAGMENT_SHADER);
144    load_and_compile_shader(fragShader, fragShaderText);
145 
146 
147    vertShader = glCreateShader(GL_VERTEX_SHADER);
148    if (filename)
149       read_shader(vertShader, filename);
150    else
151       load_and_compile_shader(vertShader, vertShaderText);
152 
153    program = glCreateProgram();
154    glAttachShader(program, fragShader);
155    glAttachShader(program, vertShader);
156    glLinkProgram(program);
157    check_link(program);
158    glUseProgram(program);
159 
160    setup_uniforms();
161 }
162 
args(int argc,char * argv[])163 static void args(int argc, char *argv[])
164 {
165    GLint i;
166 
167    for (i = 1; i < argc; i++) {
168       if (strncmp(argv[i], "-n", 2) == 0) {
169 	 nr_steps = atoi((argv[i]) + 2);
170       }
171       else if (strcmp(argv[i], "-f") == 0) {
172 	 glShadeModel(GL_FLAT);
173       }
174       else if (i == argc - 1) {
175 	 filename = argv[i];
176       }
177       else {
178 	 usage(argv[0]);
179 	 exit(1);
180       }
181    }
182 
183    if (!filename) {
184       usage(argv[0]);
185       exit(1);
186    }
187 }
188 
189 
190 
191 
192 union vert {
193    struct {
194       GLfloat color[3];
195       GLfloat pos[3];
196    } v;
197    GLfloat f[6];
198 };
199 
make_midpoint(union vert * out,const union vert * v0,const union vert * v1)200 static void make_midpoint( union vert *out,
201 			   const union vert *v0,
202 			   const union vert *v1)
203 {
204    int i;
205    for (i = 0; i < 6; i++)
206       out->f[i] = v0->f[i] + .5 * (v1->f[i] - v0->f[i]);
207 }
208 
subdiv(union vert * v0,union vert * v1,union vert * v2,GLuint depth)209 static void subdiv( union vert *v0,
210 		    union vert *v1,
211 		    union vert *v2,
212 		    GLuint depth )
213 {
214    if (depth == 0) {
215       glColor3fv(v0->v.color);
216       glVertex3fv(v0->v.pos);
217       glColor3fv(v1->v.color);
218       glVertex3fv(v1->v.pos);
219       glColor3fv(v2->v.color);
220       glVertex3fv(v2->v.pos);
221    }
222    else {
223       union vert m[3];
224 
225       make_midpoint(&m[0], v0, v1);
226       make_midpoint(&m[1], v1, v2);
227       make_midpoint(&m[2], v2, v0);
228 
229       subdiv(&m[0], &m[2], v0, depth-1);
230       subdiv(&m[1], &m[0], v1, depth-1);
231       subdiv(&m[2], &m[1], v2, depth-1);
232       subdiv(&m[0], &m[1], &m[2], depth-1);
233    }
234 }
235 
enable(GLenum value,GLboolean flag)236 static void enable( GLenum value, GLboolean flag )
237 {
238    if (flag)
239       glEnable(value);
240    else
241       glDisable(value);
242 }
243 
244 /** Assignment */
245 #define ASSIGN_3V( V, V0, V1, V2 )  \
246 do {                                \
247     V[0] = V0;                      \
248     V[1] = V1;                      \
249     V[2] = V2;                      \
250 } while(0)
251 
Display(void)252 static void Display( void )
253 {
254    glClearColor(0.3, 0.3, 0.3, 1);
255    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
256    glPointSize(psz);
257 
258    glUseProgram(program);
259    enable( GL_POINT_SMOOTH, pointsmooth );
260    enable( GL_VERTEX_PROGRAM_POINT_SIZE_ARB, program_point_size );
261 
262    glBegin(prim);
263 
264 
265    {
266       union vert v[3];
267 
268       ASSIGN_3V(v[0].v.color, 0,0,1);
269       ASSIGN_3V(v[0].v.pos,  0.9, -0.9, 0.0);
270       ASSIGN_3V(v[1].v.color, 1,0,0);
271       ASSIGN_3V(v[1].v.pos, 0.9, 0.9, 0.0);
272       ASSIGN_3V(v[2].v.color, 0,1,0);
273       ASSIGN_3V(v[2].v.pos, -0.9, 0, 0.0);
274 
275       subdiv(&v[0], &v[1], &v[2], nr_steps);
276    }
277 
278    glEnd();
279 
280 
281    glFlush();
282 }
283 
284 
Reshape(int width,int height)285 static void Reshape( int width, int height )
286 {
287    glViewport( 0, 0, width, height );
288    glMatrixMode( GL_PROJECTION );
289    glLoadIdentity();
290    glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
291    glMatrixMode( GL_MODELVIEW );
292    glLoadIdentity();
293    /*glTranslatef( 0.0, 0.0, -15.0 );*/
294 }
295 
296 
CleanUp(void)297 static void CleanUp(void)
298 {
299    glDeleteShader(fragShader);
300    glDeleteShader(vertShader);
301    glDeleteProgram(program);
302 }
303 
Key(unsigned char key,int x,int y)304 static void Key( unsigned char key, int x, int y )
305 {
306    (void) x;
307    (void) y;
308    switch (key) {
309    case 'p':
310       prim = GL_POINTS;
311       break;
312    case 't':
313       prim = GL_TRIANGLES;
314       break;
315    case 's':
316       psz += .5;
317       break;
318    case 'S':
319       if (psz > .5)
320          psz -= .5;
321       break;
322    case 'm':
323       pointsmooth = !pointsmooth;
324       break;
325    case 'z':
326       program_point_size = !program_point_size;
327       break;
328    case '+':
329       nr_steps++;
330       break;
331    case '-':
332       if (nr_steps)
333          nr_steps--;
334       break;
335    case ' ':
336       psz = 1.0;
337       prim = GL_TRIANGLES;
338       nr_steps = 4;
339       break;
340    case 27:
341       CleanUp();
342       exit(0);
343       break;
344    }
345    glutPostRedisplay();
346 }
347 
main(int argc,char * argv[])348 int main( int argc, char *argv[] )
349 {
350    glutInit( &argc, argv );
351    glutInitWindowPosition( 0, 0 );
352    glutInitWindowSize( 250, 250 );
353    glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
354    glutCreateWindow(argv[argc-1]);
355    glewInit();
356    glutReshapeFunc( Reshape );
357    glutKeyboardFunc( Key );
358    glutDisplayFunc( Display );
359    args( argc, argv );
360    prepare_shaders();
361    glutMainLoop();
362    return 0;
363 }
364