linehacks.c revision 32001f49
1/** 2 * Test some hacks to approximate wide lines, AA lines and stippled lines 3 * by drawing the lines multiple times at offsets and stippling with a fragment 4 * shader. 5 * 6 * Brian Paul 7 * June 2011 8 */ 9 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <math.h> 14#include <GL/glew.h> 15#include "glut_wrap.h" 16#include "shaderutil.h" 17 18 19static int Win; 20static int WinWidth = 1000, WinHeight = 500; 21static GLboolean Anti = GL_FALSE, Stipple = GL_FALSE; 22static GLfloat LineWidth = 1.0, MaxLineWidth = 3.0; 23static GLuint StippleProgram; 24 25 26/** 27 * Generate a 2D texture stipple pattern from 1D line stipple pattern. 28 * Note: the stipple repeat factor could be implemented by scaling the 29 * texcoords in the frag shader. 30 */ 31static GLuint 32LineStippleToTexture(GLushort pattern) 33{ 34 GLuint tex, i, j; 35 GLubyte pattern2d[16][16]; 36 37 glGenTextures(1, &tex); 38 glBindTexture(GL_TEXTURE_2D, tex); 39 40 for (i = 0; i < 16; i++) { 41 for (j = 0; j < 16; j++) { 42 GLuint ibit = (pattern >> i) & 1; 43 GLuint jbit = (pattern >> j) & 1; 44 pattern2d[i][j] = (ibit | jbit) * 255; 45 } 46 } 47 48 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 49 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 50 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 16, 0, 51 GL_LUMINANCE, GL_UNSIGNED_BYTE, pattern2d); 52 53 return tex; 54} 55 56 57/** Draw some lines */ 58static void 59DrawLines(void) 60{ 61 const float r0 = 0.2, r1 = 0.9; 62 float a; 63 64 glBegin(GL_LINES); 65 for (a = 0.0; a < 2.0*M_PI; a += 0.1) { 66 float x0 = r0 * cos(a), y0 = r0 * sin(a); 67 float x1 = r1 * cos(a), y1 = r1 * sin(a); 68 glVertex2f(x0, y0); 69 glVertex2f(x1, y1); 70 } 71 glEnd(); 72 glBegin(GL_LINE_LOOP); 73 for (a = 0.0; a <= 2.0*M_PI; a += 0.1) { 74 float x1 = r1 * cos(a), y1 = r1 * sin(a); 75 glVertex2f(x1, y1); 76 } 77 glEnd(); 78 glBegin(GL_LINE_LOOP); 79 for (a = 0.0; a <= 2.0*M_PI; a += 0.1) { 80 float x0 = r0 * cos(a), y0 = r0 * sin(a); 81 glVertex2f(x0, y0); 82 } 83 glEnd(); 84 glBegin(GL_LINE_LOOP); 85 glVertex2f(-r1, -r1); 86 glVertex2f(+r1, -r1); 87 glVertex2f(+r1, +r1); 88 glVertex2f(-r1, +r1); 89 glEnd(); 90} 91 92 93static void 94Draw(void) 95{ 96 GLint vpWidth = WinWidth / 2; 97 GLint vpHeight = WinHeight; 98 99 glClear(GL_COLOR_BUFFER_BIT); 100 101 /* draw regular lines */ 102 { 103 if (Anti) { 104 glEnable(GL_LINE_SMOOTH); 105 glEnable(GL_BLEND); 106 } 107 if (Stipple) 108 glEnable(GL_LINE_STIPPLE); 109 glLineWidth(LineWidth); 110 111 glViewport(0, 0, vpWidth, vpHeight); 112 glColor3f(1, 1, 1); 113 DrawLines(); 114 115 glDisable(GL_LINE_SMOOTH); 116 glDisable(GL_LINE_STIPPLE); 117 glDisable(GL_BLEND); 118 glLineWidth(1.0); 119 } 120 121 /* draw hacked lines */ 122 { 123#define ALPHA 0.5 124 static const float offsets_alpha[5][3] = { 125 { 0.0, 0.0, 1.0 }, 126#if 0 127 { 1.0, 0.5, ALPHA }, 128 { -1.0, -0.5, ALPHA }, 129 { -0.5, 1.0, ALPHA }, 130 { 0.5, -1.0, ALPHA } 131#else 132 { 1.0, 0.0, ALPHA }, 133 { -1.0, 0.0, ALPHA }, 134 { 0.0, 1.0, ALPHA }, 135 { 0.0, -1.0, ALPHA } 136#endif 137 }; 138 139 int passes, pass; 140 float s; 141 142 glViewport(vpWidth, 0, vpWidth, vpHeight); 143 144 if (Anti || LineWidth > 1.5) { 145 passes = 5; 146 } 147 else { 148 passes = 1; 149 } 150 if (Anti) 151 s = 2.0 * LineWidth / MaxLineWidth; 152 else 153 s = 1.5 * LineWidth / MaxLineWidth; 154 155 if (Stipple) { 156 glUseProgram(StippleProgram); 157 } 158 if (Anti) { 159 glEnable(GL_BLEND); 160 } 161 162 for (pass = 0; pass < passes; pass++) { 163 /* Translate all vertices by small x/y offset */ 164 float tx = offsets_alpha[pass][0] / vpWidth * s; 165 float ty = offsets_alpha[pass][1] / vpHeight * s; 166 /* adjust fragment alpha (this could be done in many ways) */ 167 glColor4f(1, 1, 1, offsets_alpha[pass][2]); 168 169 glPushMatrix(); 170 glTranslatef(tx, ty, 0.0); 171 DrawLines(); 172 glPopMatrix(); 173 } 174 175 if (1) { 176 /* debug: show the 2D texture / stipple pattern */ 177 GLfloat w = 32.0 / (vpWidth); 178 GLfloat h = 32.0 / (vpHeight); 179 180 glColor3f(1, 1, 1); 181 glBegin(GL_QUADS); 182 glVertex2f(0.0, 0.0); 183 glVertex2f(w, 0.0); 184 glVertex2f(w, h); 185 glVertex2f(0.0, h); 186 glEnd(); 187 } 188 189 glUseProgram(0); 190 glDisable(GL_BLEND); 191 192 } 193 194 glutSwapBuffers(); 195} 196 197 198static void 199Reshape(int width, int height) 200{ 201 WinWidth = width; 202 WinHeight = height; 203 glViewport(0, 0, width, height); 204 glMatrixMode(GL_PROJECTION); 205 glLoadIdentity(); 206 glMatrixMode(GL_MODELVIEW); 207 glLoadIdentity(); 208} 209 210 211static void 212Key(unsigned char key, int x, int y) 213{ 214 (void) x; 215 (void) y; 216 switch (key) { 217 case 'a': 218 Anti = !Anti; 219 break; 220 case 's': 221 Stipple = !Stipple; 222 break; 223 case 'w': 224 LineWidth -= 0.25; 225 if (LineWidth < 1.0) 226 LineWidth = 1.0; 227 break; 228 case 'W': 229 LineWidth += 0.25; 230 if (LineWidth > MaxLineWidth) 231 LineWidth = MaxLineWidth; 232 break; 233 case 27: 234 glutDestroyWindow(Win); 235 exit(0); 236 break; 237 } 238 printf("Stipple: %d Antialias: %d LineWidth: %f\n", 239 Stipple, Anti, LineWidth); 240 241 glutPostRedisplay(); 242} 243 244 245static void 246SpecialKey(int key, int x, int y) 247{ 248 glutPostRedisplay(); 249} 250 251 252static GLuint 253MakeFragmentShader(void) 254{ 255 static const char *fragShaderText = 256 "uniform sampler2D stippleTex; \n" 257 "uniform vec2 viewportSize; \n" 258 "float scale = 1.0 / 16.0; \n" 259 "void main() \n" 260 "{ \n" 261 " vec2 t = gl_FragCoord.xy * scale; \n" 262 " gl_FragColor = gl_Color * texture2D(stippleTex, t); \n" 263 "} \n"; 264 265 GLuint fragShader, program; 266 GLint stippleTex, viewportSize; 267 268 fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 269 program = LinkShaders(0, fragShader); 270 glUseProgram(program); 271 272 stippleTex = glGetUniformLocation(program, "stippleTex"); 273 glUniform1i(stippleTex, 0); /* unit 0 */ 274 275 viewportSize = glGetUniformLocation(program, "viewportSize"); 276 glUniform2f(viewportSize, WinWidth / 2.0, WinHeight); 277 278 glUseProgram(0); 279 280 return program; 281} 282 283 284static void 285Usage(void) 286{ 287 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 288 printf("Keys:\n"); 289 printf(" a - toggle antialiasing\n"); 290 printf(" s - toogle stippling\n"); 291 printf(" w/W - decrease/increase line width\n"); 292} 293 294 295static void 296Init(void) 297{ 298 GLushort pattern = 0xf2; 299 GLuint tex; 300 301 if (!ShadersSupported()) 302 exit(1); 303 304 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 305 glLineStipple(1, pattern); 306 307 StippleProgram = MakeFragmentShader(); 308 309 tex = LineStippleToTexture(pattern); 310 glBindTexture(GL_TEXTURE_2D, tex); 311} 312 313 314int 315main(int argc, char *argv[]) 316{ 317 glutInit(&argc, argv); 318 glutInitWindowSize(WinWidth, WinHeight); 319 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 320 Win = glutCreateWindow(argv[0]); 321 glutReshapeFunc(Reshape); 322 glutKeyboardFunc(Key); 323 glutSpecialFunc(SpecialKey); 324 glutDisplayFunc(Draw); 325 glewInit(); 326 Usage(); 327 Init(); 328 glutMainLoop(); 329 return 0; 330} 331