trirast.c revision 32001f49
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/glew.h>
19#include "glut_wrap.h"
20#include "shaderutil.h"
21
22
23static GLint WinWidth = 300, WinHeight = 300;
24static char *FragProgFile = NULL;
25static char *VertProgFile = NULL;
26static GLuint fragShader;
27static GLuint vertShader;
28static GLuint program;
29static GLint win = 0;
30static GLboolean anim = GL_TRUE;
31static GLfloat Zrot = 0.0f;
32static GLint uv0, uv1, uv2;
33
34
35static const GLfloat TriVerts[3][2] = {
36   { 50,  50 },
37   { 250, 50 },
38   { 150, 250 }
39};
40
41
42static void
43RotateVerts(GLfloat a,
44            GLuint n, const GLfloat vertsIn[][2], GLfloat vertsOut[][2])
45{
46   GLuint i;
47   GLfloat cx = WinWidth / 2, cy = WinHeight / 2;
48   for (i = 0; i < n; i++) {
49      float x = vertsIn[i][0] - cx;
50      float y = vertsIn[i][1] - cy;
51
52      vertsOut[i][0] =  x * cos(a) + y * sin(a)  + cx;
53      vertsOut[i][1] = -x * sin(a) + y * cos(a)  + cy;
54   }
55}
56
57static void
58ComputeBounds(GLuint n, GLfloat vertsIn[][2],
59              GLfloat *xmin, GLfloat *ymin,
60              GLfloat *xmax, GLfloat *ymax)
61{
62   GLuint i;
63   *xmin = *xmax = vertsIn[0][0];
64   *ymin = *ymax = vertsIn[0][1];
65   for (i = 1; i < n; i++) {
66      if (vertsIn[i][0] < *xmin)
67         *xmin = vertsIn[i][0];
68      else if (vertsIn[i][0] > *xmax)
69         *xmax = vertsIn[i][0];
70      if (vertsIn[i][1] < *ymin)
71         *ymin = vertsIn[i][1];
72      else if (vertsIn[i][1] > *ymax)
73         *ymax = vertsIn[i][1];
74   }
75}
76
77
78static void
79Redisplay(void)
80{
81   GLfloat v[3][2], xmin, ymin, xmax, ymax;
82
83   RotateVerts(Zrot, 3, TriVerts, v);
84   ComputeBounds(3, v, &xmin, &ymin, &xmax, &ymax);
85
86   glUniform2fv(uv0, 1, v[0]);
87   glUniform2fv(uv1, 1, v[1]);
88   glUniform2fv(uv2, 1, v[2]);
89
90   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
91
92   glPushMatrix();
93   glBegin(GL_POLYGON);
94   glVertex2f(xmin, ymin);
95   glVertex2f(xmax, ymin);
96   glVertex2f(xmax, ymax);
97   glVertex2f(xmin, ymax);
98   glEnd();
99   glPopMatrix();
100
101   glutSwapBuffers();
102}
103
104
105static void
106Idle(void)
107{
108   if (anim) {
109      Zrot = glutGet(GLUT_ELAPSED_TIME) * 0.0005;
110      glutPostRedisplay();
111   }
112   else
113      abort();
114}
115
116
117static void
118Reshape(int width, int height)
119{
120   glViewport(0, 0, width, height);
121   glMatrixMode(GL_PROJECTION);
122   glLoadIdentity();
123   glOrtho(0, width, 0, height, -1, 1);
124
125   glMatrixMode(GL_MODELVIEW);
126   glLoadIdentity();
127}
128
129
130static void
131CleanUp(void)
132{
133   glDeleteShader(fragShader);
134   glDeleteShader(vertShader);
135   glDeleteProgram(program);
136   glutDestroyWindow(win);
137}
138
139
140static void
141Key(unsigned char key, int x, int y)
142{
143  (void) x;
144  (void) y;
145
146   switch(key) {
147   case ' ':
148   case 'a':
149      anim = !anim;
150      if (anim)
151         glutIdleFunc(Idle);
152      else
153         glutIdleFunc(NULL);
154      break;
155   case 'z':
156      Zrot = 0;
157      break;
158   case 's':
159      Zrot += 0.05;
160      break;
161   case 27:
162      CleanUp();
163      exit(0);
164      break;
165   }
166   glutPostRedisplay();
167}
168
169
170static void
171Init(void)
172{
173   static const char *fragShaderText =
174      "uniform vec2 v0, v1, v2; \n"
175      "float crs(const vec2 u, const vec2 v) \n"
176      "{ \n"
177      "   return u.x * v.y - u.y * v.x; \n"
178      "} \n"
179      "\n"
180      "void main() {\n"
181      "   vec2 p = gl_FragCoord.xy; \n"
182      "   if (crs(v1 - v0, p - v0) >= 0.0 && \n"
183      "       crs(v2 - v1, p - v1) >= 0.0 && \n"
184      "       crs(v0 - v2, p - v2) >= 0.0) \n"
185      "      gl_FragColor = vec4(1.0); \n"
186      "   else \n"
187      "      gl_FragColor = vec4(0.5); \n"
188      "}\n";
189   static const char *vertShaderText =
190      "void main() {\n"
191      "   gl_Position = ftransform(); \n"
192      "}\n";
193
194   if (!ShadersSupported())
195      exit(1);
196
197   vertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText);
198   fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText);
199   program = LinkShaders(vertShader, fragShader);
200
201   glUseProgram(program);
202
203   uv0 = glGetUniformLocation(program, "v0");
204   uv1 = glGetUniformLocation(program, "v1");
205   uv2 = glGetUniformLocation(program, "v2");
206
207   /*assert(glGetError() == 0);*/
208
209   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
210   glEnable(GL_DEPTH_TEST);
211
212   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
213
214   assert(glIsProgram(program));
215   assert(glIsShader(fragShader));
216   assert(glIsShader(vertShader));
217
218   glColor3f(1, 0, 0);
219}
220
221
222static void
223ParseOptions(int argc, char *argv[])
224{
225   int i;
226   for (i = 1; i < argc; i++) {
227      if (strcmp(argv[i], "-fs") == 0) {
228         FragProgFile = argv[i+1];
229      }
230      else if (strcmp(argv[i], "-vs") == 0) {
231         VertProgFile = argv[i+1];
232      }
233   }
234}
235
236
237int
238main(int argc, char *argv[])
239{
240   glutInit(&argc, argv);
241   glutInitWindowSize(WinWidth, WinHeight);
242   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
243   win = glutCreateWindow(argv[0]);
244   glewInit();
245   glutReshapeFunc(Reshape);
246   glutKeyboardFunc(Key);
247   glutDisplayFunc(Redisplay);
248   if (anim)
249      glutIdleFunc(Idle);
250   ParseOptions(argc, argv);
251   Init();
252   glutMainLoop();
253   return 0;
254}
255