triangle rasterization with frag shader
[mesa.git] / progs / glsl / trirast.c
1 /**
2 * Demonstration of doing triangle rasterization with a fragment program.
3 * Basic idea:
4 * 1. Draw screen-aligned quad / bounding box around the triangle verts.
5 * 2. For each pixel in the quad, determine if pixel is inside/outside
6 * the triangle edges.
7 *
8 * Brian Paul
9 * 1 Aug 2007
10 */
11
12
13 #include <assert.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <math.h>
18 #include <GL/gl.h>
19 #include <GL/glut.h>
20 #include <GL/glext.h>
21 #include "extfuncs.h"
22
23
24 static GLint WinWidth = 300, WinHeight = 300;
25 static char *FragProgFile = NULL;
26 static char *VertProgFile = NULL;
27 static GLuint fragShader;
28 static GLuint vertShader;
29 static GLuint program;
30 static GLint win = 0;
31 static GLboolean anim = GL_TRUE;
32 static GLfloat Zrot = 0.0f;
33 static GLint uv0, uv1, uv2;
34
35
36 static const GLfloat TriVerts[3][2] = {
37 { 50, 50 },
38 { 250, 50 },
39 { 150, 250 }
40 };
41
42
43 static void
44 RotateVerts(GLfloat a,
45 GLuint n, const GLfloat vertsIn[][2], GLfloat vertsOut[][2])
46 {
47 GLuint i;
48 GLfloat cx = WinWidth / 2, cy = WinHeight / 2;
49 for (i = 0; i < n; i++) {
50 float x = vertsIn[i][0] - cx;
51 float y = vertsIn[i][1] - cy;
52
53 vertsOut[i][0] = x * cos(a) + y * sin(a) + cx;
54 vertsOut[i][1] = -x * sin(a) + y * cos(a) + cy;
55 }
56 }
57
58 static void
59 ComputeBounds(GLuint n, GLfloat vertsIn[][2],
60 GLfloat *xmin, GLfloat *ymin,
61 GLfloat *xmax, GLfloat *ymax)
62 {
63 GLuint i;
64 *xmin = *xmax = vertsIn[0][0];
65 *ymin = *ymax = vertsIn[0][1];
66 for (i = 1; i < n; i++) {
67 if (vertsIn[i][0] < *xmin)
68 *xmin = vertsIn[i][0];
69 else if (vertsIn[i][0] > *xmax)
70 *xmax = vertsIn[i][0];
71 if (vertsIn[i][1] < *ymin)
72 *ymin = vertsIn[i][1];
73 else if (vertsIn[i][1] > *ymax)
74 *ymax = vertsIn[i][1];
75 }
76 }
77
78
79 static void
80 Redisplay(void)
81 {
82 GLfloat v[3][2], xmin, ymin, xmax, ymax;
83
84 RotateVerts(Zrot, 3, TriVerts, v);
85 ComputeBounds(3, v, &xmin, &ymin, &xmax, &ymax);
86
87 glUniform2fv_func(uv0, 1, v[0]);
88 glUniform2fv_func(uv1, 1, v[1]);
89 glUniform2fv_func(uv2, 1, v[2]);
90
91 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
92
93 glPushMatrix();
94 glBegin(GL_POLYGON);
95 glVertex2f(xmin, ymin);
96 glVertex2f(xmax, ymin);
97 glVertex2f(xmax, ymax);
98 glVertex2f(xmin, ymax);
99 glEnd();
100 glPopMatrix();
101
102 glutSwapBuffers();
103 }
104
105
106 static void
107 Idle(void)
108 {
109 Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.0005;
110 glutPostRedisplay();
111 }
112
113
114 static void
115 Reshape(int width, int height)
116 {
117 glViewport(0, 0, width, height);
118 glMatrixMode(GL_PROJECTION);
119 glLoadIdentity();
120 glOrtho(0, width, 0, height, -1, 1);
121
122 glMatrixMode(GL_MODELVIEW);
123 glLoadIdentity();
124 }
125
126
127 static void
128 CleanUp(void)
129 {
130 glDeleteShader_func(fragShader);
131 glDeleteShader_func(vertShader);
132 glDeleteProgram_func(program);
133 glutDestroyWindow(win);
134 }
135
136
137 static void
138 Key(unsigned char key, int x, int y)
139 {
140 (void) x;
141 (void) y;
142
143 switch(key) {
144 case ' ':
145 case 'a':
146 anim = !anim;
147 if (anim)
148 glutIdleFunc(Idle);
149 else
150 glutIdleFunc(NULL);
151 break;
152 case 27:
153 CleanUp();
154 exit(0);
155 break;
156 }
157 glutPostRedisplay();
158 }
159
160
161 static void
162 LoadAndCompileShader(GLuint shader, const char *text)
163 {
164 GLint stat;
165
166 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
167
168 glCompileShader_func(shader);
169
170 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
171 if (!stat) {
172 GLchar log[1000];
173 GLsizei len;
174 glGetShaderInfoLog_func(shader, 1000, &len, log);
175 fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
176 exit(1);
177 }
178 }
179
180
181 /**
182 * Read a shader from a file.
183 */
184 static void
185 ReadShader(GLuint shader, const char *filename)
186 {
187 const int max = 100*1000;
188 int n;
189 char *buffer = (char*) malloc(max);
190 FILE *f = fopen(filename, "r");
191 if (!f) {
192 fprintf(stderr, "fslight: Unable to open shader file %s\n", filename);
193 exit(1);
194 }
195
196 n = fread(buffer, 1, max, f);
197 printf("fslight: read %d bytes from shader file %s\n", n, filename);
198 if (n > 0) {
199 buffer[n] = 0;
200 LoadAndCompileShader(shader, buffer);
201 }
202
203 fclose(f);
204 free(buffer);
205 }
206
207
208 static void
209 CheckLink(GLuint prog)
210 {
211 GLint stat;
212 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
213 if (!stat) {
214 GLchar log[1000];
215 GLsizei len;
216 glGetProgramInfoLog_func(prog, 1000, &len, log);
217 fprintf(stderr, "Linker error:\n%s\n", log);
218 }
219 }
220
221
222 static void
223 Init(void)
224 {
225 static const char *fragShaderText =
226 "uniform vec2 v0, v1, v2; \n"
227 "float crs(const vec2 u, const vec2 v) \n"
228 "{ \n"
229 " return u.x * v.y - u.y * v.x; \n"
230 "} \n"
231 "\n"
232 "void main() {\n"
233 " vec2 p = gl_FragCoord.xy; \n"
234 " if (crs(v1 - v0, p - v0) >= 0 && \n"
235 " crs(v2 - v1, p - v1) >= 0 && \n"
236 " crs(v0 - v2, p - v2) >= 0) \n"
237 " gl_FragColor = vec4(1.0); \n"
238 " else \n"
239 " gl_FragColor = vec4(0.5); \n"
240 "}\n";
241 static const char *vertShaderText =
242 "void main() {\n"
243 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
244 "}\n";
245 const char *version;
246
247 version = (const char *) glGetString(GL_VERSION);
248 if (version[0] != '2' || version[1] != '.') {
249 printf("This program requires OpenGL 2.x, found %s\n", version);
250 exit(1);
251 }
252
253 GetExtensionFuncs();
254
255 fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
256 if (FragProgFile)
257 ReadShader(fragShader, FragProgFile);
258 else
259 LoadAndCompileShader(fragShader, fragShaderText);
260
261 vertShader = glCreateShader_func(GL_VERTEX_SHADER);
262 if (VertProgFile)
263 ReadShader(vertShader, VertProgFile);
264 else
265 LoadAndCompileShader(vertShader, vertShaderText);
266
267 program = glCreateProgram_func();
268 glAttachShader_func(program, fragShader);
269 glAttachShader_func(program, vertShader);
270 glLinkProgram_func(program);
271 CheckLink(program);
272 glUseProgram_func(program);
273
274 uv0 = glGetUniformLocation_func(program, "v0");
275 uv1 = glGetUniformLocation_func(program, "v1");
276 uv2 = glGetUniformLocation_func(program, "v2");
277 printf("Uniforms: %d %d %d\n", uv0, uv1, uv2);
278
279 /*assert(glGetError() == 0);*/
280
281 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
282 glEnable(GL_DEPTH_TEST);
283
284 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
285
286 assert(glIsProgram_func(program));
287 assert(glIsShader_func(fragShader));
288 assert(glIsShader_func(vertShader));
289
290 glColor3f(1, 0, 0);
291 }
292
293
294 static void
295 ParseOptions(int argc, char *argv[])
296 {
297 int i;
298 for (i = 1; i < argc; i++) {
299 if (strcmp(argv[i], "-fs") == 0) {
300 FragProgFile = argv[i+1];
301 }
302 else if (strcmp(argv[i], "-vs") == 0) {
303 VertProgFile = argv[i+1];
304 }
305 }
306 }
307
308
309 int
310 main(int argc, char *argv[])
311 {
312 glutInit(&argc, argv);
313 glutInitWindowPosition( 0, 0);
314 glutInitWindowSize(WinWidth, WinHeight);
315 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
316 win = glutCreateWindow(argv[0]);
317 glutReshapeFunc(Reshape);
318 glutKeyboardFunc(Key);
319 glutDisplayFunc(Redisplay);
320 if (anim)
321 glutIdleFunc(Idle);
322 ParseOptions(argc, argv);
323 Init();
324 glutMainLoop();
325 return 0;
326 }