blob: 3c2830773a3d6998c7ba633807691bfcd1257fc0 [file] [log] [blame]
Zack Rusine842b5e2007-10-25 07:19:02 -04001
2#include <assert.h>
3#include <string.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <math.h>
7#define GL_GLEXT_PROTOTYPES
8#include <GL/glut.h>
9
10static const char *filename = NULL;
11static GLuint nr_steps = 4;
12
13static GLuint fragShader;
14static GLuint vertShader;
15static GLuint program;
16
17static void usage( char *name )
18{
19 fprintf( stderr, "usage: %s [ options ] shader_filename\n", name );
20 fprintf( stderr, "\n" );
21 fprintf( stderr, "options:\n" );
22 fprintf( stderr, " -f flat shaded\n" );
23 fprintf( stderr, " -nNr subdivision steps\n" );
24}
25
26
27static void load_and_compile_shader(GLuint shader, const char *text)
28{
29 GLint stat;
30
31 glShaderSource(shader, 1, (const GLchar **) &text, NULL);
32
33 glCompileShader(shader);
34
35 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
36 if (!stat) {
37 GLchar log[1000];
38 GLsizei len;
39 glGetShaderInfoLog(shader, 1000, &len, log);
40 fprintf(stderr, "vp-tris: problem compiling shader:\n%s\n", log);
41 exit(1);
42 }
43}
44
45static void read_shader(GLuint shader, const char *filename)
46{
47 const int max = 100*1000;
48 int n;
49 char *buffer = (char*) malloc(max);
50 FILE *f = fopen(filename, "r");
51 if (!f) {
52 fprintf(stderr, "vp-tris: Unable to open shader file %s\n", filename);
53 exit(1);
54 }
55
56 n = fread(buffer, 1, max, f);
Zack Rusin1d26e9c2007-10-25 07:52:59 -040057 printf("vp-tris: read %d bytes from shader file %s\n", n, filename);
Zack Rusine842b5e2007-10-25 07:19:02 -040058 if (n > 0) {
59 buffer[n] = 0;
60 load_and_compile_shader(shader, buffer);
61 }
62
63 fclose(f);
64 free(buffer);
65}
66
67static void check_link(GLuint prog)
68{
69 GLint stat;
70 glGetProgramiv(prog, GL_LINK_STATUS, &stat);
71 if (!stat) {
72 GLchar log[1000];
73 GLsizei len;
74 glGetProgramInfoLog(prog, 1000, &len, log);
75 fprintf(stderr, "Linker error:\n%s\n", log);
76 }
77}
78
79static void prepare_shaders()
80{
81 static const char *fragShaderText =
82 "void main() {\n"
83 " gl_FragColor = gl_Color;\n"
84 "}\n";
85 static const char *vertShaderText =
86 "void main() {\n"
87 " gl_FrontColor = gl_Color;\n"
88 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
89 "}\n";
90 fragShader = glCreateShader(GL_FRAGMENT_SHADER);
91 load_and_compile_shader(fragShader, fragShaderText);
92
93
94 vertShader = glCreateShader(GL_VERTEX_SHADER);
95 if (filename)
96 read_shader(vertShader, filename);
97 else
98 load_and_compile_shader(vertShader, vertShaderText);
99
100 program = glCreateProgram();
101 glAttachShader(program, fragShader);
102 glAttachShader(program, vertShader);
103 glLinkProgram(program);
104 check_link(program);
105 glUseProgram(program);
106}
107
108static void args(int argc, char *argv[])
109{
110 GLint i;
111
112 for (i = 1; i < argc; i++) {
113 if (strncmp(argv[i], "-n", 2) == 0) {
114 nr_steps = atoi((argv[i]) + 2);
115 }
116 else if (strcmp(argv[i], "-f") == 0) {
117 glShadeModel(GL_FLAT);
118 }
119 else if (i == argc - 1) {
120 filename = argv[i];
121 }
122 else {
123 usage(argv[0]);
124 exit(1);
125 }
126 }
127
128 if (!filename) {
129 usage(argv[0]);
130 exit(1);
131 }
132}
133
134
135
136
137union vert {
138 struct {
139 GLfloat color[3];
140 GLfloat pos[3];
141 } v;
142 GLfloat f[6];
143};
144
145static void make_midpoint( union vert *out,
146 const union vert *v0,
147 const union vert *v1)
148{
149 int i;
150 for (i = 0; i < 6; i++)
151 out->f[i] = v0->f[i] + .5 * (v1->f[i] - v0->f[i]);
152}
153
154static void subdiv( union vert *v0,
155 union vert *v1,
156 union vert *v2,
157 GLuint depth )
158{
159 if (depth == 0) {
160 glColor3fv(v0->v.color);
161 glVertex3fv(v0->v.pos);
162 glColor3fv(v1->v.color);
163 glVertex3fv(v1->v.pos);
164 glColor3fv(v2->v.color);
165 glVertex3fv(v2->v.pos);
166 }
167 else {
168 union vert m[3];
169
170 make_midpoint(&m[0], v0, v1);
171 make_midpoint(&m[1], v1, v2);
172 make_midpoint(&m[2], v2, v0);
173
174 subdiv(&m[0], &m[2], v0, depth-1);
175 subdiv(&m[1], &m[0], v1, depth-1);
176 subdiv(&m[2], &m[1], v2, depth-1);
177 subdiv(&m[0], &m[1], &m[2], depth-1);
178 }
179}
180
181/** Assignment */
182#define ASSIGN_3V( V, V0, V1, V2 ) \
183do { \
184 V[0] = V0; \
185 V[1] = V1; \
186 V[2] = V2; \
187} while(0)
188
189static void Display( void )
190{
191 glClearColor(0.3, 0.3, 0.3, 1);
192 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
193
194 glUseProgram(program);
195
196 glBegin(GL_TRIANGLES);
197
198
199 {
200 union vert v[3];
201
202 ASSIGN_3V(v[0].v.color, 0,0,1);
203 ASSIGN_3V(v[0].v.pos, 0.9, -0.9, 0.0);
204 ASSIGN_3V(v[1].v.color, 1,0,0);
205 ASSIGN_3V(v[1].v.pos, 0.9, 0.9, 0.0);
206 ASSIGN_3V(v[2].v.color, 0,1,0);
207 ASSIGN_3V(v[2].v.pos, -0.9, 0, 0.0);
208
209 subdiv(&v[0], &v[1], &v[2], nr_steps);
210 }
211
212 glEnd();
213
214
215 glFlush();
216}
217
218
219static void Reshape( int width, int height )
220{
221 glViewport( 0, 0, width, height );
222 glMatrixMode( GL_PROJECTION );
223 glLoadIdentity();
224 glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
225 glMatrixMode( GL_MODELVIEW );
226 glLoadIdentity();
227 /*glTranslatef( 0.0, 0.0, -15.0 );*/
228}
229
230
231static void CleanUp(void)
232{
233 glDeleteShader(fragShader);
234 glDeleteShader(vertShader);
235 glDeleteProgram(program);
236}
237
238static void Key( unsigned char key, int x, int y )
239{
240 (void) x;
241 (void) y;
242 switch (key) {
243 case 27:
244 CleanUp();
245 exit(0);
246 break;
247 }
248 glutPostRedisplay();
249}
250
251int main( int argc, char *argv[] )
252{
253 glutInit( &argc, argv );
254 glutInitWindowPosition( 0, 0 );
255 glutInitWindowSize( 250, 250 );
256 glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
257 glutCreateWindow(argv[0]);
258 glutReshapeFunc( Reshape );
259 glutKeyboardFunc( Key );
260 glutDisplayFunc( Display );
261 args( argc, argv );
262 prepare_shaders();
263 glutMainLoop();
264 return 0;
265}