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
11static const char *filename = NULL;
12static GLuint nr_steps = 4;
13static GLuint prim = GL_TRIANGLES;
14static GLfloat psz = 1.0;
15static GLboolean pointsmooth = 0;
16static GLboolean program_point_size = 0;
17
18static GLuint fragShader;
19static GLuint vertShader;
20static GLuint program;
21
22static 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
32static 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
50static 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
72static 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
84static 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
132static 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
163static 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
192union vert {
193   struct {
194      GLfloat color[3];
195      GLfloat pos[3];
196   } v;
197   GLfloat f[6];
198};
199
200static 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
209static 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
236static 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 )  \
246do {                                \
247    V[0] = V0;                      \
248    V[1] = V1;                      \
249    V[2] = V2;                      \
250} while(0)
251
252static 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
285static 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
297static void CleanUp(void)
298{
299   glDeleteShader(fragShader);
300   glDeleteShader(vertShader);
301   glDeleteProgram(program);
302}
303
304static 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
348int 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