2842755447e5da00a4665eea84260c516261f8f7
[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 if (anim) {
110 Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.0005;
111 glutPostRedisplay();
112 }
113 else
114 abort();
115 }
116
117
118 static void
119 Reshape(int width, int height)
120 {
121 glViewport(0, 0, width, height);
122 glMatrixMode(GL_PROJECTION);
123 glLoadIdentity();
124 glOrtho(0, width, 0, height, -1, 1);
125
126 glMatrixMode(GL_MODELVIEW);
127 glLoadIdentity();
128 }
129
130
131 static void
132 CleanUp(void)
133 {
134 glDeleteShader_func(fragShader);
135 glDeleteShader_func(vertShader);
136 glDeleteProgram_func(program);
137 glutDestroyWindow(win);
138 }
139
140
141 static void
142 Key(unsigned char key, int x, int y)
143 {
144 (void) x;
145 (void) y;
146
147 switch(key) {
148 case ' ':
149 case 'a':
150 anim = !anim;
151 if (anim)
152 glutIdleFunc(Idle);
153 else
154 glutIdleFunc(NULL);
155 break;
156 case 'z':
157 Zrot = 0;
158 break;
159 case 's':
160 Zrot += 0.05;
161 break;
162 case 27:
163 CleanUp();
164 exit(0);
165 break;
166 }
167 glutPostRedisplay();
168 }
169
170
171 static void
172 LoadAndCompileShader(GLuint shader, const char *text)
173 {
174 GLint stat;
175
176 glShaderSource_func(shader, 1, (const GLchar **) &text, NULL);
177
178 glCompileShader_func(shader);
179
180 glGetShaderiv_func(shader, GL_COMPILE_STATUS, &stat);
181 if (!stat) {
182 GLchar log[1000];
183 GLsizei len;
184 glGetShaderInfoLog_func(shader, 1000, &len, log);
185 fprintf(stderr, "fslight: problem compiling shader:\n%s\n", log);
186 exit(1);
187 }
188 }
189
190
191 /**
192 * Read a shader from a file.
193 */
194 static void
195 ReadShader(GLuint shader, const char *filename)
196 {
197 const int max = 100*1000;
198 int n;
199 char *buffer = (char*) malloc(max);
200 FILE *f = fopen(filename, "r");
201 if (!f) {
202 fprintf(stderr, "fslight: Unable to open shader file %s\n", filename);
203 exit(1);
204 }
205
206 n = fread(buffer, 1, max, f);
207 printf("fslight: read %d bytes from shader file %s\n", n, filename);
208 if (n > 0) {
209 buffer[n] = 0;
210 LoadAndCompileShader(shader, buffer);
211 }
212
213 fclose(f);
214 free(buffer);
215 }
216
217
218 static void
219 CheckLink(GLuint prog)
220 {
221 GLint stat;
222 glGetProgramiv_func(prog, GL_LINK_STATUS, &stat);
223 if (!stat) {
224 GLchar log[1000];
225 GLsizei len;
226 glGetProgramInfoLog_func(prog, 1000, &len, log);
227 fprintf(stderr, "Linker error:\n%s\n", log);
228 }
229 }
230
231
232 static void
233 Init(void)
234 {
235 static const char *fragShaderText =
236 "uniform vec2 v0, v1, v2; \n"
237 "float crs(const vec2 u, const vec2 v) \n"
238 "{ \n"
239 " return u.x * v.y - u.y * v.x; \n"
240 "} \n"
241 "\n"
242 "void main() {\n"
243 " vec2 p = gl_FragCoord.xy; \n"
244 " if (crs(v1 - v0, p - v0) >= 0 && \n"
245 " crs(v2 - v1, p - v1) >= 0 && \n"
246 " crs(v0 - v2, p - v2) >= 0) \n"
247 " gl_FragColor = vec4(1.0); \n"
248 " else \n"
249 " gl_FragColor = vec4(0.5); \n"
250 "}\n";
251 static const char *vertShaderText =
252 "void main() {\n"
253 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
254 "}\n";
255 const char *version;
256
257 version = (const char *) glGetString(GL_VERSION);
258 if (version[0] != '2' || version[1] != '.') {
259 printf("This program requires OpenGL 2.x, found %s\n", version);
260 exit(1);
261 }
262
263 GetExtensionFuncs();
264
265 fragShader = glCreateShader_func(GL_FRAGMENT_SHADER);
266 if (FragProgFile)
267 ReadShader(fragShader, FragProgFile);
268 else
269 LoadAndCompileShader(fragShader, fragShaderText);
270
271 vertShader = glCreateShader_func(GL_VERTEX_SHADER);
272 if (VertProgFile)
273 ReadShader(vertShader, VertProgFile);
274 else
275 LoadAndCompileShader(vertShader, vertShaderText);
276
277 program = glCreateProgram_func();
278 glAttachShader_func(program, fragShader);
279 glAttachShader_func(program, vertShader);
280 glLinkProgram_func(program);
281 CheckLink(program);
282 glUseProgram_func(program);
283
284 uv0 = glGetUniformLocation_func(program, "v0");
285 uv1 = glGetUniformLocation_func(program, "v1");
286 uv2 = glGetUniformLocation_func(program, "v2");
287 printf("Uniforms: %d %d %d\n", uv0, uv1, uv2);
288
289 /*assert(glGetError() == 0);*/
290
291 glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
292 glEnable(GL_DEPTH_TEST);
293
294 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
295
296 assert(glIsProgram_func(program));
297 assert(glIsShader_func(fragShader));
298 assert(glIsShader_func(vertShader));
299
300 glColor3f(1, 0, 0);
301 }
302
303
304 static void
305 ParseOptions(int argc, char *argv[])
306 {
307 int i;
308 for (i = 1; i < argc; i++) {
309 if (strcmp(argv[i], "-fs") == 0) {
310 FragProgFile = argv[i+1];
311 }
312 else if (strcmp(argv[i], "-vs") == 0) {
313 VertProgFile = argv[i+1];
314 }
315 }
316 }
317
318
319 int
320 main(int argc, char *argv[])
321 {
322 glutInit(&argc, argv);
323 glutInitWindowPosition( 0, 0);
324 glutInitWindowSize(WinWidth, WinHeight);
325 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
326 win = glutCreateWindow(argv[0]);
327 glutReshapeFunc(Reshape);
328 glutKeyboardFunc(Key);
329 glutDisplayFunc(Redisplay);
330 if (anim)
331 glutIdleFunc(Idle);
332 ParseOptions(argc, argv);
333 Init();
334 glutMainLoop();
335 return 0;
336 }