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#define GL_GLEXT_PROTOTYPES
12#include <GL/glew.h>
13#include "glut_wrap.h"
14#include "shaderutil.h"
15
16static const char *filename = "bezier.geom";
17
18static GLuint fragShader;
19static GLuint vertShader;
20static GLuint geoShader;
21static GLuint program;
22
23#define QUIT 9999
24
25GLfloat vertices[][3] =
26   { {  -0.9, -0.9, 0.0 },
27     {  -0.5,  0.9, 0.0 },
28     {   0.5,  0.9, 0.0 },
29     {   0.9, -0.9, 0.0 } };
30
31GLfloat color[][4] =
32{ { 1, 1, 1, 1 },
33  { 1, 1, 1, 1 },
34  { 1, 1, 1, 1 },
35  { 1, 1, 1, 1 } };
36
37
38static struct uniform_info Uniforms[] = {
39   { "NumSubdivisions", 1, GL_INT, { 50, 0, 0, 0 }, -1 },
40   END_OF_UNIFORMS
41};
42
43static void usage( char *name )
44{
45   fprintf(stderr, "usage: %s\n", name);
46   fprintf(stderr, "\n" );
47}
48
49
50static void load_and_compile_shader(GLuint shader, const char *text)
51{
52   GLint stat;
53
54   glShaderSource(shader, 1, (const GLchar **) &text, NULL);
55   glCompileShader(shader);
56   glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
57   if (!stat) {
58      GLchar log[1000];
59      GLsizei len;
60      glGetShaderInfoLog(shader, 1000, &len, log);
61      fprintf(stderr, "bezier: problem compiling shader:\n%s\n", log);
62      exit(1);
63   }
64}
65
66static void read_shader(GLuint shader, const char *filename)
67{
68   const int max = 100*1000;
69   int n;
70   char *buffer = (char*) malloc(max);
71   FILE *f = fopen(filename, "r");
72   if (!f) {
73      fprintf(stderr, "bezier: Unable to open shader file %s\n", filename);
74      exit(1);
75   }
76
77   n = fread(buffer, 1, max, f);
78   printf("bezier: read %d bytes from shader file %s\n", n, filename);
79   if (n > 0) {
80      buffer[n] = 0;
81      load_and_compile_shader(shader, buffer);
82   }
83
84   fclose(f);
85   free(buffer);
86}
87
88static void check_link(GLuint prog)
89{
90   GLint stat;
91   glGetProgramiv(prog, GL_LINK_STATUS, &stat);
92   if (!stat) {
93      GLchar log[1000];
94      GLsizei len;
95      glGetProgramInfoLog(prog, 1000, &len, log);
96      fprintf(stderr, "Linker error:\n%s\n", log);
97   }
98}
99
100static void menu_selected(int entry)
101{
102   switch (entry) {
103   case QUIT:
104      exit(0);
105      break;
106   default:
107      Uniforms[0].value[0] = entry;
108   }
109
110   SetUniformValues(program, Uniforms);
111   glutPostRedisplay();
112}
113
114
115static void menu_init(void)
116{
117   glutCreateMenu(menu_selected);
118
119   glutAddMenuEntry("1 Subdivision",  1);
120   glutAddMenuEntry("2 Subdivisions", 2);
121   glutAddMenuEntry("3 Subdivisions", 3);
122   glutAddMenuEntry("4 Subdivisions", 4);
123   glutAddMenuEntry("5 Subdivisions", 5);
124   glutAddMenuEntry("6 Subdivisions", 6);
125   glutAddMenuEntry("7 Subdivisions", 7);
126   glutAddMenuEntry("10 Subdivisions", 10);
127   glutAddMenuEntry("50 Subdivisions", 50);
128   glutAddMenuEntry("100 Subdivisions", 100);
129   glutAddMenuEntry("500 Subdivisions", 500);
130
131   glutAddMenuEntry("Quit", QUIT);
132
133   glutAttachMenu(GLUT_RIGHT_BUTTON);
134}
135
136static void init(void)
137{
138   static const char *fragShaderText =
139      "void main() {\n"
140      "    gl_FragColor = gl_Color;\n"
141      "}\n";
142   static const char *vertShaderText =
143      "void main() {\n"
144      "   gl_FrontColor = gl_Color;\n"
145      "   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
146      "}\n";
147   static const char *geoShaderText =
148      "#version 120\n"
149      "#extension GL_ARB_geometry_shader4 : enable\n"
150      "void main()\n"
151      "{\n"
152      "  for(int i = 0; i < gl_VerticesIn; ++i)\n"
153      "  {\n"
154      "    gl_FrontColor = gl_FrontColorIn[i];\n"
155      "    gl_Position = gl_PositionIn[i];\n"
156      "    EmitVertex();\n"
157      "  }\n"
158      "}\n";
159
160
161   if (!ShadersSupported())
162      exit(1);
163
164   if (!glutExtensionSupported("GL_ARB_geometry_shader4")) {
165      printf("This demo requires GL_ARB_geometry_shader4\n");
166      exit(1);
167   }
168
169   menu_init();
170
171   fragShader = glCreateShader(GL_FRAGMENT_SHADER);
172   load_and_compile_shader(fragShader, fragShaderText);
173
174   vertShader = glCreateShader(GL_VERTEX_SHADER);
175   load_and_compile_shader(vertShader, vertShaderText);
176
177   geoShader = glCreateShader(GL_GEOMETRY_SHADER_ARB);
178   if (filename)
179      read_shader(geoShader, filename);
180   else
181      load_and_compile_shader(geoShader,
182                              geoShaderText);
183
184   program = glCreateProgram();
185   glAttachShader(program, vertShader);
186   glAttachShader(program, geoShader);
187   glAttachShader(program, fragShader);
188
189   glProgramParameteriARB(program, GL_GEOMETRY_INPUT_TYPE_ARB,
190                          GL_LINES_ADJACENCY_ARB);
191   glProgramParameteriARB(program, GL_GEOMETRY_OUTPUT_TYPE_ARB,
192                          GL_LINE_STRIP);
193
194   {
195      int temp;
196      glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB,&temp);
197      glProgramParameteriARB(program,GL_GEOMETRY_VERTICES_OUT_ARB,temp);
198   }
199
200   glLinkProgram(program);
201   check_link(program);
202   glUseProgram(program);
203
204   SetUniformValues(program, Uniforms);
205   PrintUniforms(Uniforms);
206
207   assert(glGetError() == 0);
208
209   glEnableClientState( GL_VERTEX_ARRAY );
210   glEnableClientState( GL_COLOR_ARRAY );
211
212   glVertexPointer( 3, GL_FLOAT, sizeof(vertices[0]), vertices );
213   glColorPointer( 4, GL_FLOAT, sizeof(color[0]), color );
214}
215
216static void args(int argc, char *argv[])
217{
218   if (argc != 1) {
219      usage(argv[0]);
220      exit(1);
221   }
222}
223
224static void Display( void )
225{
226   glClearColor(0, 0, 0, 1);
227   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
228
229   glUseProgram(program);
230
231   glEnable(GL_VERTEX_PROGRAM_ARB);
232
233   glDrawArrays(GL_LINES_ADJACENCY_ARB, 0, 4);
234
235   glFlush();
236}
237
238
239static void Reshape( int width, int height )
240{
241   glViewport( 0, 0, width, height );
242   glMatrixMode( GL_PROJECTION );
243   glLoadIdentity();
244   glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
245   glMatrixMode( GL_MODELVIEW );
246   glLoadIdentity();
247   /*glTranslatef( 0.0, 0.0, -15.0 );*/
248}
249
250
251static void CleanUp(void)
252{
253   glDeleteShader(fragShader);
254   glDeleteShader(vertShader);
255   glDeleteProgram(program);
256}
257
258static void Key( unsigned char key, int x, int y )
259{
260   (void) x;
261   (void) y;
262   switch (key) {
263      case 27:
264         CleanUp();
265         exit(0);
266         break;
267   }
268   glutPostRedisplay();
269}
270
271int main( int argc, char *argv[] )
272{
273   glutInit( &argc, argv );
274   glutInitWindowPosition( 0, 0 );
275   glutInitWindowSize( 250, 250 );
276   glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
277   glutCreateWindow(argv[0]);
278   glewInit();
279   glutReshapeFunc( Reshape );
280   glutKeyboardFunc( Key );
281   glutDisplayFunc( Display );
282   args(argc, argv);
283   init();
284   glutMainLoop();
285   return 0;
286}
287