132001f49Smrg
232001f49Smrg#include <assert.h>
332001f49Smrg#include <string.h>
432001f49Smrg#include <stdio.h>
532001f49Smrg#include <stdlib.h>
632001f49Smrg#include <math.h>
732001f49Smrg
832001f49Smrg#include <GL/glew.h>
932001f49Smrg#include "glut_wrap.h"
1032001f49Smrg
1132001f49Smrgstatic const char *filename = NULL;
1232001f49Smrgstatic GLuint nr_steps = 4;
1332001f49Smrgstatic GLuint prim = GL_TRIANGLES;
1432001f49Smrgstatic GLfloat psz = 1.0;
1532001f49Smrgstatic GLboolean pointsmooth = 0;
1632001f49Smrgstatic GLboolean program_point_size = 0;
1732001f49Smrg
1832001f49Smrgstatic GLuint fragShader;
1932001f49Smrgstatic GLuint vertShader;
2032001f49Smrgstatic GLuint program;
2132001f49Smrg
2232001f49Smrgstatic void usage( char *name )
2332001f49Smrg{
2432001f49Smrg   fprintf( stderr, "usage: %s [ options ] shader_filename\n", name );
2532001f49Smrg   fprintf( stderr, "\n" );
2632001f49Smrg   fprintf( stderr, "options:\n" );
2732001f49Smrg   fprintf( stderr, "    -f     flat shaded\n" );
2832001f49Smrg   fprintf( stderr, "    -nNr  subdivision steps\n" );
2932001f49Smrg}
3032001f49Smrg
3132001f49Smrg
3232001f49Smrgstatic void load_and_compile_shader(GLuint shader, const char *text)
3332001f49Smrg{
3432001f49Smrg   GLint stat;
3532001f49Smrg
3632001f49Smrg   glShaderSource(shader, 1, (const GLchar **) &text, NULL);
3732001f49Smrg
3832001f49Smrg   glCompileShader(shader);
3932001f49Smrg
4032001f49Smrg   glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
4132001f49Smrg   if (!stat) {
4232001f49Smrg      GLchar log[1000];
4332001f49Smrg      GLsizei len;
4432001f49Smrg      glGetShaderInfoLog(shader, 1000, &len, log);
4532001f49Smrg      fprintf(stderr, "vp-tris: problem compiling shader:\n%s\n", log);
4632001f49Smrg      exit(1);
4732001f49Smrg   }
4832001f49Smrg}
4932001f49Smrg
5032001f49Smrgstatic void read_shader(GLuint shader, const char *filename)
5132001f49Smrg{
5232001f49Smrg   const int max = 100*1000;
5332001f49Smrg   int n;
5432001f49Smrg   char *buffer = (char*) malloc(max);
5532001f49Smrg   FILE *f = fopen(filename, "r");
5632001f49Smrg   if (!f) {
5732001f49Smrg      fprintf(stderr, "vp-tris: Unable to open shader file %s\n", filename);
5832001f49Smrg      exit(1);
5932001f49Smrg   }
6032001f49Smrg
6132001f49Smrg   n = fread(buffer, 1, max, f);
6232001f49Smrg   printf("vp-tris: read %d bytes from shader file %s\n", n, filename);
6332001f49Smrg   if (n > 0) {
6432001f49Smrg      buffer[n] = 0;
6532001f49Smrg      load_and_compile_shader(shader, buffer);
6632001f49Smrg   }
6732001f49Smrg
6832001f49Smrg   fclose(f);
6932001f49Smrg   free(buffer);
7032001f49Smrg}
7132001f49Smrg
7232001f49Smrgstatic void check_link(GLuint prog)
7332001f49Smrg{
7432001f49Smrg   GLint stat;
7532001f49Smrg   glGetProgramiv(prog, GL_LINK_STATUS, &stat);
7632001f49Smrg   if (!stat) {
7732001f49Smrg      GLchar log[1000];
7832001f49Smrg      GLsizei len;
7932001f49Smrg      glGetProgramInfoLog(prog, 1000, &len, log);
8032001f49Smrg      fprintf(stderr, "Linker error:\n%s\n", log);
8132001f49Smrg   }
8232001f49Smrg}
8332001f49Smrg
8432001f49Smrgstatic void setup_uniforms(void)
8532001f49Smrg{
8632001f49Smrg   {
8732001f49Smrg      GLint loc1f = glGetUniformLocationARB(program, "Offset1f");
8832001f49Smrg      GLint loc2f = glGetUniformLocationARB(program, "Offset2f");
8932001f49Smrg      GLint loc4f = glGetUniformLocationARB(program, "Offset4f");
9032001f49Smrg      GLfloat vecKer[] =
9132001f49Smrg         { 1.0, 0.0, 0.0,  1.0,
9232001f49Smrg           0.0, 1.0, 0.0,  1.0,
9332001f49Smrg           1.0, 0.0, 0.0,  1.0,
9432001f49Smrg           0.0, 0.0, 0.0,  1.0
9532001f49Smrg         };
9632001f49Smrg      if (loc1f >= 0)
9732001f49Smrg         glUniform1fv(loc1f, 16, vecKer);
9832001f49Smrg
9932001f49Smrg      if (loc2f >= 0)
10032001f49Smrg         glUniform2fv(loc2f, 8, vecKer);
10132001f49Smrg
10232001f49Smrg      if (loc4f >= 0)
10332001f49Smrg         glUniform4fv(loc4f, 4, vecKer);
10432001f49Smrg
10532001f49Smrg   }
10632001f49Smrg
10732001f49Smrg   {
10832001f49Smrg      GLint loc1f = glGetUniformLocationARB(program, "KernelValue1f");
10932001f49Smrg      GLint loc2f = glGetUniformLocationARB(program, "KernelValue2f");
11032001f49Smrg      GLint loc4f = glGetUniformLocationARB(program, "KernelValue4f");
11132001f49Smrg      GLfloat vecKer[] =
11232001f49Smrg         { 1.0, 0.0, 0.0,  0.25,
11332001f49Smrg           0.0, 1.0, 0.0,  0.25,
11432001f49Smrg           0.0, 0.0, 1.0,  0.25,
11532001f49Smrg           0.0, 0.0, 0.0,  0.25,
11632001f49Smrg           0.5, 0.0, 0.0,  0.35,
11732001f49Smrg           0.0, 0.5, 0.0,  0.35,
11832001f49Smrg           0.0, 0.0, 0.5,  0.35,
11932001f49Smrg           0.0, 0.0, 0.0,  0.35
12032001f49Smrg         };
12132001f49Smrg      if (loc1f >= 0)
12232001f49Smrg         glUniform1fv(loc1f, 16, vecKer);
12332001f49Smrg
12432001f49Smrg      if (loc2f >= 0)
12532001f49Smrg         glUniform2fv(loc2f, 8, vecKer);
12632001f49Smrg
12732001f49Smrg      if (loc4f >= 0)
12832001f49Smrg         glUniform4fv(loc4f, 4, vecKer);
12932001f49Smrg   }
13032001f49Smrg}
13132001f49Smrg
13232001f49Smrgstatic void prepare_shaders(void)
13332001f49Smrg{
13432001f49Smrg   static const char *fragShaderText =
13532001f49Smrg      "void main() {\n"
13632001f49Smrg      "    gl_FragColor = gl_Color;\n"
13732001f49Smrg      "}\n";
13832001f49Smrg   static const char *vertShaderText =
13932001f49Smrg      "void main() {\n"
14032001f49Smrg      "   gl_FrontColor = gl_Color;\n"
14132001f49Smrg      "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
14232001f49Smrg      "}\n";
14332001f49Smrg   fragShader = glCreateShader(GL_FRAGMENT_SHADER);
14432001f49Smrg   load_and_compile_shader(fragShader, fragShaderText);
14532001f49Smrg
14632001f49Smrg
14732001f49Smrg   vertShader = glCreateShader(GL_VERTEX_SHADER);
14832001f49Smrg   if (filename)
14932001f49Smrg      read_shader(vertShader, filename);
15032001f49Smrg   else
15132001f49Smrg      load_and_compile_shader(vertShader, vertShaderText);
15232001f49Smrg
15332001f49Smrg   program = glCreateProgram();
15432001f49Smrg   glAttachShader(program, fragShader);
15532001f49Smrg   glAttachShader(program, vertShader);
15632001f49Smrg   glLinkProgram(program);
15732001f49Smrg   check_link(program);
15832001f49Smrg   glUseProgram(program);
15932001f49Smrg
16032001f49Smrg   setup_uniforms();
16132001f49Smrg}
16232001f49Smrg
16332001f49Smrgstatic void args(int argc, char *argv[])
16432001f49Smrg{
16532001f49Smrg   GLint i;
16632001f49Smrg
16732001f49Smrg   for (i = 1; i < argc; i++) {
16832001f49Smrg      if (strncmp(argv[i], "-n", 2) == 0) {
16932001f49Smrg	 nr_steps = atoi((argv[i]) + 2);
17032001f49Smrg      }
17132001f49Smrg      else if (strcmp(argv[i], "-f") == 0) {
17232001f49Smrg	 glShadeModel(GL_FLAT);
17332001f49Smrg      }
17432001f49Smrg      else if (i == argc - 1) {
17532001f49Smrg	 filename = argv[i];
17632001f49Smrg      }
17732001f49Smrg      else {
17832001f49Smrg	 usage(argv[0]);
17932001f49Smrg	 exit(1);
18032001f49Smrg      }
18132001f49Smrg   }
18232001f49Smrg
18332001f49Smrg   if (!filename) {
18432001f49Smrg      usage(argv[0]);
18532001f49Smrg      exit(1);
18632001f49Smrg   }
18732001f49Smrg}
18832001f49Smrg
18932001f49Smrg
19032001f49Smrg
19132001f49Smrg
19232001f49Smrgunion vert {
19332001f49Smrg   struct {
19432001f49Smrg      GLfloat color[3];
19532001f49Smrg      GLfloat pos[3];
19632001f49Smrg   } v;
19732001f49Smrg   GLfloat f[6];
19832001f49Smrg};
19932001f49Smrg
20032001f49Smrgstatic void make_midpoint( union vert *out,
20132001f49Smrg			   const union vert *v0,
20232001f49Smrg			   const union vert *v1)
20332001f49Smrg{
20432001f49Smrg   int i;
20532001f49Smrg   for (i = 0; i < 6; i++)
20632001f49Smrg      out->f[i] = v0->f[i] + .5 * (v1->f[i] - v0->f[i]);
20732001f49Smrg}
20832001f49Smrg
20932001f49Smrgstatic void subdiv( union vert *v0,
21032001f49Smrg		    union vert *v1,
21132001f49Smrg		    union vert *v2,
21232001f49Smrg		    GLuint depth )
21332001f49Smrg{
21432001f49Smrg   if (depth == 0) {
21532001f49Smrg      glColor3fv(v0->v.color);
21632001f49Smrg      glVertex3fv(v0->v.pos);
21732001f49Smrg      glColor3fv(v1->v.color);
21832001f49Smrg      glVertex3fv(v1->v.pos);
21932001f49Smrg      glColor3fv(v2->v.color);
22032001f49Smrg      glVertex3fv(v2->v.pos);
22132001f49Smrg   }
22232001f49Smrg   else {
22332001f49Smrg      union vert m[3];
22432001f49Smrg
22532001f49Smrg      make_midpoint(&m[0], v0, v1);
22632001f49Smrg      make_midpoint(&m[1], v1, v2);
22732001f49Smrg      make_midpoint(&m[2], v2, v0);
22832001f49Smrg
22932001f49Smrg      subdiv(&m[0], &m[2], v0, depth-1);
23032001f49Smrg      subdiv(&m[1], &m[0], v1, depth-1);
23132001f49Smrg      subdiv(&m[2], &m[1], v2, depth-1);
23232001f49Smrg      subdiv(&m[0], &m[1], &m[2], depth-1);
23332001f49Smrg   }
23432001f49Smrg}
23532001f49Smrg
23632001f49Smrgstatic void enable( GLenum value, GLboolean flag )
23732001f49Smrg{
23832001f49Smrg   if (flag)
23932001f49Smrg      glEnable(value);
24032001f49Smrg   else
24132001f49Smrg      glDisable(value);
24232001f49Smrg}
24332001f49Smrg
24432001f49Smrg/** Assignment */
24532001f49Smrg#define ASSIGN_3V( V, V0, V1, V2 )  \
24632001f49Smrgdo {                                \
24732001f49Smrg    V[0] = V0;                      \
24832001f49Smrg    V[1] = V1;                      \
24932001f49Smrg    V[2] = V2;                      \
25032001f49Smrg} while(0)
25132001f49Smrg
25232001f49Smrgstatic void Display( void )
25332001f49Smrg{
25432001f49Smrg   glClearColor(0.3, 0.3, 0.3, 1);
25532001f49Smrg   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
25632001f49Smrg   glPointSize(psz);
25732001f49Smrg
25832001f49Smrg   glUseProgram(program);
25932001f49Smrg   enable( GL_POINT_SMOOTH, pointsmooth );
26032001f49Smrg   enable( GL_VERTEX_PROGRAM_POINT_SIZE_ARB, program_point_size );
26132001f49Smrg
26232001f49Smrg   glBegin(prim);
26332001f49Smrg
26432001f49Smrg
26532001f49Smrg   {
26632001f49Smrg      union vert v[3];
26732001f49Smrg
26832001f49Smrg      ASSIGN_3V(v[0].v.color, 0,0,1);
26932001f49Smrg      ASSIGN_3V(v[0].v.pos,  0.9, -0.9, 0.0);
27032001f49Smrg      ASSIGN_3V(v[1].v.color, 1,0,0);
27132001f49Smrg      ASSIGN_3V(v[1].v.pos, 0.9, 0.9, 0.0);
27232001f49Smrg      ASSIGN_3V(v[2].v.color, 0,1,0);
27332001f49Smrg      ASSIGN_3V(v[2].v.pos, -0.9, 0, 0.0);
27432001f49Smrg
27532001f49Smrg      subdiv(&v[0], &v[1], &v[2], nr_steps);
27632001f49Smrg   }
27732001f49Smrg
27832001f49Smrg   glEnd();
27932001f49Smrg
28032001f49Smrg
28132001f49Smrg   glFlush();
28232001f49Smrg}
28332001f49Smrg
28432001f49Smrg
28532001f49Smrgstatic void Reshape( int width, int height )
28632001f49Smrg{
28732001f49Smrg   glViewport( 0, 0, width, height );
28832001f49Smrg   glMatrixMode( GL_PROJECTION );
28932001f49Smrg   glLoadIdentity();
29032001f49Smrg   glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
29132001f49Smrg   glMatrixMode( GL_MODELVIEW );
29232001f49Smrg   glLoadIdentity();
29332001f49Smrg   /*glTranslatef( 0.0, 0.0, -15.0 );*/
29432001f49Smrg}
29532001f49Smrg
29632001f49Smrg
29732001f49Smrgstatic void CleanUp(void)
29832001f49Smrg{
29932001f49Smrg   glDeleteShader(fragShader);
30032001f49Smrg   glDeleteShader(vertShader);
30132001f49Smrg   glDeleteProgram(program);
30232001f49Smrg}
30332001f49Smrg
30432001f49Smrgstatic void Key( unsigned char key, int x, int y )
30532001f49Smrg{
30632001f49Smrg   (void) x;
30732001f49Smrg   (void) y;
30832001f49Smrg   switch (key) {
30932001f49Smrg   case 'p':
31032001f49Smrg      prim = GL_POINTS;
31132001f49Smrg      break;
31232001f49Smrg   case 't':
31332001f49Smrg      prim = GL_TRIANGLES;
31432001f49Smrg      break;
31532001f49Smrg   case 's':
31632001f49Smrg      psz += .5;
31732001f49Smrg      break;
31832001f49Smrg   case 'S':
31932001f49Smrg      if (psz > .5)
32032001f49Smrg         psz -= .5;
32132001f49Smrg      break;
32232001f49Smrg   case 'm':
32332001f49Smrg      pointsmooth = !pointsmooth;
32432001f49Smrg      break;
32532001f49Smrg   case 'z':
32632001f49Smrg      program_point_size = !program_point_size;
32732001f49Smrg      break;
32832001f49Smrg   case '+':
32932001f49Smrg      nr_steps++;
33032001f49Smrg      break;
33132001f49Smrg   case '-':
33232001f49Smrg      if (nr_steps)
33332001f49Smrg         nr_steps--;
33432001f49Smrg      break;
33532001f49Smrg   case ' ':
33632001f49Smrg      psz = 1.0;
33732001f49Smrg      prim = GL_TRIANGLES;
33832001f49Smrg      nr_steps = 4;
33932001f49Smrg      break;
34032001f49Smrg   case 27:
34132001f49Smrg      CleanUp();
34232001f49Smrg      exit(0);
34332001f49Smrg      break;
34432001f49Smrg   }
34532001f49Smrg   glutPostRedisplay();
34632001f49Smrg}
34732001f49Smrg
34832001f49Smrgint main( int argc, char *argv[] )
34932001f49Smrg{
35032001f49Smrg   glutInit( &argc, argv );
35132001f49Smrg   glutInitWindowPosition( 0, 0 );
35232001f49Smrg   glutInitWindowSize( 250, 250 );
35332001f49Smrg   glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
35432001f49Smrg   glutCreateWindow(argv[argc-1]);
35532001f49Smrg   glewInit();
35632001f49Smrg   glutReshapeFunc( Reshape );
35732001f49Smrg   glutKeyboardFunc( Key );
35832001f49Smrg   glutDisplayFunc( Display );
35932001f49Smrg   args( argc, argv );
36032001f49Smrg   prepare_shaders();
36132001f49Smrg   glutMainLoop();
36232001f49Smrg   return 0;
36332001f49Smrg}
364