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