texaaline.c revision 32001f49
1/**
2 * AA lines with texture mapped quads
3 *
4 * Brian Paul
5 * 9 Feb 2008
6 */
7
8
9#include <assert.h>
10#include <string.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <math.h>
14#include <GL/glew.h>
15#include "glut_wrap.h"
16
17#ifndef M_PI
18#define M_PI 3.1415926535
19#endif
20
21static GLint WinWidth = 300, WinHeight = 300;
22static GLint win = 0;
23static GLfloat Width = 8.;
24
25/*
26 * Quad strip for line from v0 to v1:
27 *
28 1   3                     5   7
29 +---+---------------------+---+
30 |                             |
31 |   *v0                 v1*   |
32 |                             |
33 +---+---------------------+---+
34 0   2                     4   6
35 */
36static void
37QuadLine(const GLfloat *v0, const GLfloat *v1, GLfloat width)
38{
39   GLfloat dx = v1[0] - v0[0];
40   GLfloat dy = v1[1] - v0[1];
41   GLfloat len = sqrt(dx*dx + dy*dy);
42   float dx0, dx1, dx2, dx3, dx4, dx5, dx6, dx7;
43   float dy0, dy1, dy2, dy3, dy4, dy5, dy6, dy7;
44
45   dx /= len;
46   dy /= len;
47
48   width *= 0.5;  /* half width */
49   dx = dx * (width + 0.0);
50   dy = dy * (width + 0.0);
51
52   dx0 = -dx+dy;  dy0 = -dy-dx;
53   dx1 = -dx-dy;  dy1 = -dy+dx;
54
55   dx2 =   0+dy;  dy2 = -dx+0;
56   dx3 =   0-dy;  dy3 = +dx+0;
57
58   dx4 =   0+dy;  dy4 = -dx+0;
59   dx5 =   0-dy;  dy5 = +dx+0;
60
61   dx6 =  dx+dy;  dy6 =  dy-dx;
62   dx7 =  dx-dy;  dy7 =  dy+dx;
63
64   /*
65   printf("dx, dy = %g, %g\n", dx, dy);
66   printf("  dx0, dy0: %g, %g\n", dx0, dy0);
67   printf("  dx1, dy1: %g, %g\n", dx1, dy1);
68   printf("  dx2, dy2: %g, %g\n", dx2, dy2);
69   printf("  dx3, dy3: %g, %g\n", dx3, dy3);
70   */
71
72   glBegin(GL_QUAD_STRIP);
73   glTexCoord2f(0, 0);
74   glVertex2f(v0[0] + dx0, v0[1] + dy0);
75   glTexCoord2f(0, 1);
76   glVertex2f(v0[0] + dx1, v0[1] + dy1);
77
78   glTexCoord2f(0.5, 0);
79   glVertex2f(v0[0] + dx2, v0[1] + dy2);
80   glTexCoord2f(0.5, 1);
81   glVertex2f(v0[0] + dx3, v0[1] + dy3);
82
83   glTexCoord2f(0.5, 0);
84   glVertex2f(v1[0] + dx2, v1[1] + dy2);
85   glTexCoord2f(0.5, 1);
86   glVertex2f(v1[0] + dx3, v1[1] + dy3);
87
88   glTexCoord2f(1, 0);
89   glVertex2f(v1[0] + dx6, v1[1] + dy6);
90   glTexCoord2f(1, 1);
91   glVertex2f(v1[0] + dx7, v1[1] + dy7);
92   glEnd();
93}
94
95
96static float Cos(float a)
97{
98   return cos(a * M_PI / 180.);
99}
100
101static float Sin(float a)
102{
103   return sin(a * M_PI / 180.);
104}
105
106static void
107Redisplay(void)
108{
109   float cx = 0.5 * WinWidth, cy = 0.5 * WinHeight;
110   float len = 0.5 * WinWidth - 20.0;
111   int i;
112
113   glClear(GL_COLOR_BUFFER_BIT);
114
115   glColor3f(1, 1, 1);
116
117   glEnable(GL_BLEND);
118   glEnable(GL_TEXTURE_2D);
119
120   for (i = 0; i < 360; i+=5) {
121      float v0[2], v1[2];
122      v0[0] = cx + 40 * Cos(i);
123      v0[1] = cy + 40 * Sin(i);
124      v1[0] = cx + len * Cos(i);
125      v1[1] = cy + len * Sin(i);
126      QuadLine(v0, v1, Width);
127   }
128
129   {
130      float v0[2], v1[2], x;
131      for (x = 0; x < 1.0; x += 0.2) {
132         v0[0] = cx + x;
133         v0[1] = cy + x * 40 - 20;
134         v1[0] = cx + x + 5.0;
135         v1[1] = cy + x * 40 - 20;
136         QuadLine(v0, v1, Width);
137      }
138   }
139
140   glDisable(GL_BLEND);
141   glDisable(GL_TEXTURE_2D);
142
143   glutSwapBuffers();
144}
145
146
147static void
148Reshape(int width, int height)
149{
150   WinWidth = width;
151   WinHeight = height;
152   glViewport(0, 0, width, height);
153   glMatrixMode(GL_PROJECTION);
154   glLoadIdentity();
155   glOrtho(0, width, 0, height, -1, 1);
156   glMatrixMode(GL_MODELVIEW);
157   glLoadIdentity();
158}
159
160
161static void
162CleanUp(void)
163{
164   glutDestroyWindow(win);
165}
166
167
168static void
169Key(unsigned char key, int x, int y)
170{
171  (void) x;
172  (void) y;
173
174   switch(key) {
175   case 'w':
176      Width -= 0.5;
177      break;
178   case 'W':
179      Width += 0.5;
180      break;
181   case 27:
182      CleanUp();
183      exit(0);
184      break;
185   }
186#if 0
187   if (Width < 3)
188      Width = 3;
189#endif
190   printf("Width = %g\n", Width);
191   glutPostRedisplay();
192}
193
194
195static float
196ramp4(GLint i, GLint size)
197{
198   float d;
199   if (i < 4 ) {
200      d = i / 4.0;
201   }
202   else if (i >= size - 5) {
203      d = 1.0 - (i - (size - 5)) / 4.0;
204   }
205   else {
206      d = 1.0;
207   }
208   return d;
209}
210
211static float
212ramp2(GLint i, GLint size)
213{
214   float d;
215   if (i < 2 ) {
216      d = i / 2.0;
217   }
218   else if (i >= size - 3) {
219      d = 1.0 - (i - (size - 3)) / 2.0;
220   }
221   else {
222      d = 1.0;
223   }
224   return d;
225}
226
227static float
228ramp1(GLint i, GLint size)
229{
230   float d;
231   if (i == 0 || i == size-1) {
232      d = 0.0;
233   }
234   else {
235      d = 1.0;
236   }
237   return d;
238}
239
240
241/**
242 * Make an alpha texture for antialiasing lines.
243 * Just a linear fall-off ramp for now.
244 * Should have a number of different textures for different line widths.
245 * Could try a bell-like-curve....
246 */
247static void
248MakeTexture(void)
249{
250#define SZ 8
251   GLfloat tex[SZ][SZ];  /* alpha tex */
252   int i, j;
253   for (i = 0; i < SZ; i++) {
254      for (j = 0; j < SZ; j++) {
255#if 0
256         float k = (SZ-1) / 2.0;
257         float dx = fabs(i - k) / k;
258         float dy = fabs(j - k) / k;
259         float d;
260
261         dx = 1.0 - dx;
262         dy = 1.0 - dy;
263         d = dx * dy;
264
265#else
266         float d = ramp1(i, SZ) * ramp1(j, SZ);
267         printf("%d, %d: %g\n", i, j, d);
268#endif
269         tex[i][j] = d;
270      }
271   }
272
273   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, SZ, SZ, 0, GL_ALPHA, GL_FLOAT, tex);
274   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
275   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
276   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
277   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
278   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
279#undef SZ
280}
281
282
283static void
284MakeMipmap(void)
285{
286#define SZ 64
287   GLfloat tex[SZ][SZ];  /* alpha tex */
288   int level;
289
290   glPixelStorei(GL_UNPACK_ROW_LENGTH, SZ);
291   for (level = 0; level < 7; level++) {
292      int sz = 1 << (6 - level);
293      int i, j;
294      for (i = 0; i < sz; i++) {
295         for (j = 0; j < sz; j++) {
296            if (level == 6)
297               tex[i][j] = 1.0;
298            else if (level == 5)
299               tex[i][j] = 0.5;
300            else
301               tex[i][j] = ramp1(i, sz) * ramp1(j, sz);
302         }
303      }
304
305      glTexImage2D(GL_TEXTURE_2D, level, GL_ALPHA,
306                   sz, sz, 0, GL_ALPHA, GL_FLOAT, tex);
307   }
308
309   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
310   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
311   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
312   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
313   /* glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); */
314   /* glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); */
315
316   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
317#undef SZ
318}
319
320
321static void
322Init(void)
323{
324   (void) MakeTexture;
325   (void) ramp4;
326   (void) ramp2;
327
328   if (!GLEW_VERSION_2_0) {
329      printf("This program requires OpenGL 2.x\n");
330      exit(1);
331   }
332
333   glClearColor(0.3f, 0.3f, 0.3f, 0.0f);
334
335   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
336
337   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
338#if 0
339   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
340#elif 0
341   MakeTexture();
342#else
343   MakeMipmap();
344#endif
345}
346
347
348static void
349ParseOptions(int argc, char *argv[])
350{
351}
352
353
354int
355main(int argc, char *argv[])
356{
357   glutInit(&argc, argv);
358   glutInitWindowSize(WinWidth, WinHeight);
359   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
360   win = glutCreateWindow(argv[0]);
361   glewInit();
362   glutReshapeFunc(Reshape);
363   glutKeyboardFunc(Key);
364   glutDisplayFunc(Redisplay);
365   ParseOptions(argc, argv);
366   Init();
367   glutMainLoop();
368   return 0;
369}
370