Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 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> |
Keith Whitwell | b799af9 | 2009-06-29 14:13:58 +0100 | [diff] [blame] | 14 | #include <GL/glew.h> |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 15 | #include <GL/glut.h> |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 16 | |
Jon TURNEY | a15d9ca | 2009-07-24 20:33:25 +0100 | [diff] [blame] | 17 | #ifndef M_PI |
| 18 | #define M_PI 3.1415926535 |
| 19 | #endif |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 20 | |
| 21 | static GLint WinWidth = 300, WinHeight = 300; |
| 22 | static GLint win = 0; |
| 23 | static 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 | */ |
| 36 | static void |
| 37 | QuadLine(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 | |
| 96 | static float Cos(float a) |
| 97 | { |
| 98 | return cos(a * M_PI / 180.); |
| 99 | } |
| 100 | |
| 101 | static float Sin(float a) |
| 102 | { |
| 103 | return sin(a * M_PI / 180.); |
| 104 | } |
| 105 | |
| 106 | static void |
| 107 | Redisplay(void) |
| 108 | { |
Brian Paul | 2bcf787 | 2009-08-26 11:56:19 -0600 | [diff] [blame] | 109 | float cx = 0.5 * WinWidth, cy = 0.5 * WinHeight; |
| 110 | float len = 0.5 * WinWidth - 20.0; |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 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]; |
Brian Paul | 2bcf787 | 2009-08-26 11:56:19 -0600 | [diff] [blame] | 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); |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 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) { |
Brian Paul | 2bcf787 | 2009-08-26 11:56:19 -0600 | [diff] [blame] | 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; |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 136 | QuadLine(v0, v1, Width); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | glDisable(GL_BLEND); |
| 141 | glDisable(GL_TEXTURE_2D); |
| 142 | |
| 143 | glutSwapBuffers(); |
| 144 | } |
| 145 | |
| 146 | |
| 147 | static void |
| 148 | Reshape(int width, int height) |
| 149 | { |
Brian Paul | 2bcf787 | 2009-08-26 11:56:19 -0600 | [diff] [blame] | 150 | WinWidth = width; |
| 151 | WinHeight = height; |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 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 | |
| 161 | static void |
| 162 | CleanUp(void) |
| 163 | { |
| 164 | glutDestroyWindow(win); |
| 165 | } |
| 166 | |
| 167 | |
| 168 | static void |
| 169 | Key(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 | |
| 195 | static float |
| 196 | ramp4(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 | |
| 211 | static float |
| 212 | ramp2(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 | |
| 227 | static float |
| 228 | ramp1(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 | */ |
| 247 | static void |
| 248 | MakeTexture(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 | |
| 283 | static void |
| 284 | MakeMipmap(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); |
Brian Paul | b08f447 | 2009-11-17 16:14:09 -0700 | [diff] [blame] | 313 | /* |
| 314 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 4); |
| 315 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); |
| 316 | */ |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 317 | |
| 318 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
| 319 | #undef SZ |
| 320 | } |
| 321 | |
| 322 | |
| 323 | static void |
| 324 | Init(void) |
| 325 | { |
| 326 | const char *version; |
| 327 | |
| 328 | (void) MakeTexture; |
| 329 | (void) ramp4; |
| 330 | (void) ramp2; |
| 331 | |
| 332 | version = (const char *) glGetString(GL_VERSION); |
| 333 | if (version[0] != '2' || version[1] != '.') { |
| 334 | printf("This program requires OpenGL 2.x, found %s\n", version); |
| 335 | exit(1); |
| 336 | } |
| 337 | |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 338 | glClearColor(0.3f, 0.3f, 0.3f, 0.0f); |
| 339 | |
| 340 | printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); |
| 341 | |
| 342 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| 343 | #if 0 |
| 344 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); |
| 345 | #elif 0 |
| 346 | MakeTexture(); |
| 347 | #else |
| 348 | MakeMipmap(); |
| 349 | #endif |
| 350 | } |
| 351 | |
| 352 | |
| 353 | static void |
| 354 | ParseOptions(int argc, char *argv[]) |
| 355 | { |
| 356 | } |
| 357 | |
| 358 | |
| 359 | int |
| 360 | main(int argc, char *argv[]) |
| 361 | { |
| 362 | glutInit(&argc, argv); |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 363 | glutInitWindowSize(WinWidth, WinHeight); |
| 364 | glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); |
| 365 | win = glutCreateWindow(argv[0]); |
Keith Whitwell | b799af9 | 2009-06-29 14:13:58 +0100 | [diff] [blame] | 366 | glewInit(); |
Brian Paul | c0565e8 | 2009-04-18 14:18:59 -0600 | [diff] [blame] | 367 | glutReshapeFunc(Reshape); |
| 368 | glutKeyboardFunc(Key); |
| 369 | glutDisplayFunc(Redisplay); |
| 370 | ParseOptions(argc, argv); |
| 371 | Init(); |
| 372 | glutMainLoop(); |
| 373 | return 0; |
| 374 | } |