gs-tri.c revision 32001f49
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 <GL/glew.h>
12#include "glut_wrap.h"
13
14static const char *filename = NULL;
15static GLuint nr_steps = 0;
16
17static GLuint fragShader;
18static GLuint vertShader;
19static GLuint geoShader;
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   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
48static 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
70static 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
82static 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
144static 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
173union vert {
174   struct {
175      GLfloat color[3];
176      GLfloat pos[3];
177   } v;
178   GLfloat f[6];
179};
180
181static 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
190static 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 )  \
219do {                                \
220    V[0] = V0;                      \
221    V[1] = V1;                      \
222    V[2] = V2;                      \
223} while(0)
224
225static 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
255static 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
267static void CleanUp(void)
268{
269   glDeleteShader(fragShader);
270   glDeleteShader(vertShader);
271   glDeleteProgram(program);
272}
273
274static 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
287int 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   glewInit();
295   glutReshapeFunc( Reshape );
296   glutKeyboardFunc( Key );
297   glutDisplayFunc( Display );
298   args( argc, argv );
299   prepare_shaders();
300   glutMainLoop();
301   return 0;
302}
303