132001f49Smrg/** 232001f49Smrg * Test some hacks to approximate wide lines, AA lines and stippled lines 332001f49Smrg * by drawing the lines multiple times at offsets and stippling with a fragment 432001f49Smrg * shader. 532001f49Smrg * 632001f49Smrg * Brian Paul 732001f49Smrg * June 2011 832001f49Smrg */ 932001f49Smrg 1032001f49Smrg 1132001f49Smrg#include <stdio.h> 1232001f49Smrg#include <stdlib.h> 1332001f49Smrg#include <math.h> 1432001f49Smrg#include <GL/glew.h> 1532001f49Smrg#include "glut_wrap.h" 1632001f49Smrg#include "shaderutil.h" 1732001f49Smrg 1832001f49Smrg 1932001f49Smrgstatic int Win; 2032001f49Smrgstatic int WinWidth = 1000, WinHeight = 500; 2132001f49Smrgstatic GLboolean Anti = GL_FALSE, Stipple = GL_FALSE; 2232001f49Smrgstatic GLfloat LineWidth = 1.0, MaxLineWidth = 3.0; 2332001f49Smrgstatic GLuint StippleProgram; 2432001f49Smrg 2532001f49Smrg 2632001f49Smrg/** 2732001f49Smrg * Generate a 2D texture stipple pattern from 1D line stipple pattern. 2832001f49Smrg * Note: the stipple repeat factor could be implemented by scaling the 2932001f49Smrg * texcoords in the frag shader. 3032001f49Smrg */ 3132001f49Smrgstatic GLuint 3232001f49SmrgLineStippleToTexture(GLushort pattern) 3332001f49Smrg{ 3432001f49Smrg GLuint tex, i, j; 3532001f49Smrg GLubyte pattern2d[16][16]; 3632001f49Smrg 3732001f49Smrg glGenTextures(1, &tex); 3832001f49Smrg glBindTexture(GL_TEXTURE_2D, tex); 3932001f49Smrg 4032001f49Smrg for (i = 0; i < 16; i++) { 4132001f49Smrg for (j = 0; j < 16; j++) { 4232001f49Smrg GLuint ibit = (pattern >> i) & 1; 4332001f49Smrg GLuint jbit = (pattern >> j) & 1; 4432001f49Smrg pattern2d[i][j] = (ibit | jbit) * 255; 4532001f49Smrg } 4632001f49Smrg } 4732001f49Smrg 4832001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 4932001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 5032001f49Smrg glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 16, 16, 0, 5132001f49Smrg GL_LUMINANCE, GL_UNSIGNED_BYTE, pattern2d); 5232001f49Smrg 5332001f49Smrg return tex; 5432001f49Smrg} 5532001f49Smrg 5632001f49Smrg 5732001f49Smrg/** Draw some lines */ 5832001f49Smrgstatic void 5932001f49SmrgDrawLines(void) 6032001f49Smrg{ 6132001f49Smrg const float r0 = 0.2, r1 = 0.9; 6232001f49Smrg float a; 6332001f49Smrg 6432001f49Smrg glBegin(GL_LINES); 6532001f49Smrg for (a = 0.0; a < 2.0*M_PI; a += 0.1) { 6632001f49Smrg float x0 = r0 * cos(a), y0 = r0 * sin(a); 6732001f49Smrg float x1 = r1 * cos(a), y1 = r1 * sin(a); 6832001f49Smrg glVertex2f(x0, y0); 6932001f49Smrg glVertex2f(x1, y1); 7032001f49Smrg } 7132001f49Smrg glEnd(); 7232001f49Smrg glBegin(GL_LINE_LOOP); 7332001f49Smrg for (a = 0.0; a <= 2.0*M_PI; a += 0.1) { 7432001f49Smrg float x1 = r1 * cos(a), y1 = r1 * sin(a); 7532001f49Smrg glVertex2f(x1, y1); 7632001f49Smrg } 7732001f49Smrg glEnd(); 7832001f49Smrg glBegin(GL_LINE_LOOP); 7932001f49Smrg for (a = 0.0; a <= 2.0*M_PI; a += 0.1) { 8032001f49Smrg float x0 = r0 * cos(a), y0 = r0 * sin(a); 8132001f49Smrg glVertex2f(x0, y0); 8232001f49Smrg } 8332001f49Smrg glEnd(); 8432001f49Smrg glBegin(GL_LINE_LOOP); 8532001f49Smrg glVertex2f(-r1, -r1); 8632001f49Smrg glVertex2f(+r1, -r1); 8732001f49Smrg glVertex2f(+r1, +r1); 8832001f49Smrg glVertex2f(-r1, +r1); 8932001f49Smrg glEnd(); 9032001f49Smrg} 9132001f49Smrg 9232001f49Smrg 9332001f49Smrgstatic void 9432001f49SmrgDraw(void) 9532001f49Smrg{ 9632001f49Smrg GLint vpWidth = WinWidth / 2; 9732001f49Smrg GLint vpHeight = WinHeight; 9832001f49Smrg 9932001f49Smrg glClear(GL_COLOR_BUFFER_BIT); 10032001f49Smrg 10132001f49Smrg /* draw regular lines */ 10232001f49Smrg { 10332001f49Smrg if (Anti) { 10432001f49Smrg glEnable(GL_LINE_SMOOTH); 10532001f49Smrg glEnable(GL_BLEND); 10632001f49Smrg } 10732001f49Smrg if (Stipple) 10832001f49Smrg glEnable(GL_LINE_STIPPLE); 10932001f49Smrg glLineWidth(LineWidth); 11032001f49Smrg 11132001f49Smrg glViewport(0, 0, vpWidth, vpHeight); 11232001f49Smrg glColor3f(1, 1, 1); 11332001f49Smrg DrawLines(); 11432001f49Smrg 11532001f49Smrg glDisable(GL_LINE_SMOOTH); 11632001f49Smrg glDisable(GL_LINE_STIPPLE); 11732001f49Smrg glDisable(GL_BLEND); 11832001f49Smrg glLineWidth(1.0); 11932001f49Smrg } 12032001f49Smrg 12132001f49Smrg /* draw hacked lines */ 12232001f49Smrg { 12332001f49Smrg#define ALPHA 0.5 12432001f49Smrg static const float offsets_alpha[5][3] = { 12532001f49Smrg { 0.0, 0.0, 1.0 }, 12632001f49Smrg#if 0 12732001f49Smrg { 1.0, 0.5, ALPHA }, 12832001f49Smrg { -1.0, -0.5, ALPHA }, 12932001f49Smrg { -0.5, 1.0, ALPHA }, 13032001f49Smrg { 0.5, -1.0, ALPHA } 13132001f49Smrg#else 13232001f49Smrg { 1.0, 0.0, ALPHA }, 13332001f49Smrg { -1.0, 0.0, ALPHA }, 13432001f49Smrg { 0.0, 1.0, ALPHA }, 13532001f49Smrg { 0.0, -1.0, ALPHA } 13632001f49Smrg#endif 13732001f49Smrg }; 13832001f49Smrg 13932001f49Smrg int passes, pass; 14032001f49Smrg float s; 14132001f49Smrg 14232001f49Smrg glViewport(vpWidth, 0, vpWidth, vpHeight); 14332001f49Smrg 14432001f49Smrg if (Anti || LineWidth > 1.5) { 14532001f49Smrg passes = 5; 14632001f49Smrg } 14732001f49Smrg else { 14832001f49Smrg passes = 1; 14932001f49Smrg } 15032001f49Smrg if (Anti) 15132001f49Smrg s = 2.0 * LineWidth / MaxLineWidth; 15232001f49Smrg else 15332001f49Smrg s = 1.5 * LineWidth / MaxLineWidth; 15432001f49Smrg 15532001f49Smrg if (Stipple) { 15632001f49Smrg glUseProgram(StippleProgram); 15732001f49Smrg } 15832001f49Smrg if (Anti) { 15932001f49Smrg glEnable(GL_BLEND); 16032001f49Smrg } 16132001f49Smrg 16232001f49Smrg for (pass = 0; pass < passes; pass++) { 16332001f49Smrg /* Translate all vertices by small x/y offset */ 16432001f49Smrg float tx = offsets_alpha[pass][0] / vpWidth * s; 16532001f49Smrg float ty = offsets_alpha[pass][1] / vpHeight * s; 16632001f49Smrg /* adjust fragment alpha (this could be done in many ways) */ 16732001f49Smrg glColor4f(1, 1, 1, offsets_alpha[pass][2]); 16832001f49Smrg 16932001f49Smrg glPushMatrix(); 17032001f49Smrg glTranslatef(tx, ty, 0.0); 17132001f49Smrg DrawLines(); 17232001f49Smrg glPopMatrix(); 17332001f49Smrg } 17432001f49Smrg 17532001f49Smrg if (1) { 17632001f49Smrg /* debug: show the 2D texture / stipple pattern */ 17732001f49Smrg GLfloat w = 32.0 / (vpWidth); 17832001f49Smrg GLfloat h = 32.0 / (vpHeight); 17932001f49Smrg 18032001f49Smrg glColor3f(1, 1, 1); 18132001f49Smrg glBegin(GL_QUADS); 18232001f49Smrg glVertex2f(0.0, 0.0); 18332001f49Smrg glVertex2f(w, 0.0); 18432001f49Smrg glVertex2f(w, h); 18532001f49Smrg glVertex2f(0.0, h); 18632001f49Smrg glEnd(); 18732001f49Smrg } 18832001f49Smrg 18932001f49Smrg glUseProgram(0); 19032001f49Smrg glDisable(GL_BLEND); 19132001f49Smrg 19232001f49Smrg } 19332001f49Smrg 19432001f49Smrg glutSwapBuffers(); 19532001f49Smrg} 19632001f49Smrg 19732001f49Smrg 19832001f49Smrgstatic void 19932001f49SmrgReshape(int width, int height) 20032001f49Smrg{ 20132001f49Smrg WinWidth = width; 20232001f49Smrg WinHeight = height; 20332001f49Smrg glViewport(0, 0, width, height); 20432001f49Smrg glMatrixMode(GL_PROJECTION); 20532001f49Smrg glLoadIdentity(); 20632001f49Smrg glMatrixMode(GL_MODELVIEW); 20732001f49Smrg glLoadIdentity(); 20832001f49Smrg} 20932001f49Smrg 21032001f49Smrg 21132001f49Smrgstatic void 21232001f49SmrgKey(unsigned char key, int x, int y) 21332001f49Smrg{ 21432001f49Smrg (void) x; 21532001f49Smrg (void) y; 21632001f49Smrg switch (key) { 21732001f49Smrg case 'a': 21832001f49Smrg Anti = !Anti; 21932001f49Smrg break; 22032001f49Smrg case 's': 22132001f49Smrg Stipple = !Stipple; 22232001f49Smrg break; 22332001f49Smrg case 'w': 22432001f49Smrg LineWidth -= 0.25; 22532001f49Smrg if (LineWidth < 1.0) 22632001f49Smrg LineWidth = 1.0; 22732001f49Smrg break; 22832001f49Smrg case 'W': 22932001f49Smrg LineWidth += 0.25; 23032001f49Smrg if (LineWidth > MaxLineWidth) 23132001f49Smrg LineWidth = MaxLineWidth; 23232001f49Smrg break; 23332001f49Smrg case 27: 23432001f49Smrg glutDestroyWindow(Win); 23532001f49Smrg exit(0); 23632001f49Smrg break; 23732001f49Smrg } 23832001f49Smrg printf("Stipple: %d Antialias: %d LineWidth: %f\n", 23932001f49Smrg Stipple, Anti, LineWidth); 24032001f49Smrg 24132001f49Smrg glutPostRedisplay(); 24232001f49Smrg} 24332001f49Smrg 24432001f49Smrg 24532001f49Smrgstatic void 24632001f49SmrgSpecialKey(int key, int x, int y) 24732001f49Smrg{ 24832001f49Smrg glutPostRedisplay(); 24932001f49Smrg} 25032001f49Smrg 25132001f49Smrg 25232001f49Smrgstatic GLuint 25332001f49SmrgMakeFragmentShader(void) 25432001f49Smrg{ 25532001f49Smrg static const char *fragShaderText = 25632001f49Smrg "uniform sampler2D stippleTex; \n" 25732001f49Smrg "uniform vec2 viewportSize; \n" 25832001f49Smrg "float scale = 1.0 / 16.0; \n" 25932001f49Smrg "void main() \n" 26032001f49Smrg "{ \n" 26132001f49Smrg " vec2 t = gl_FragCoord.xy * scale; \n" 26232001f49Smrg " gl_FragColor = gl_Color * texture2D(stippleTex, t); \n" 26332001f49Smrg "} \n"; 26432001f49Smrg 26532001f49Smrg GLuint fragShader, program; 26632001f49Smrg GLint stippleTex, viewportSize; 26732001f49Smrg 26832001f49Smrg fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 26932001f49Smrg program = LinkShaders(0, fragShader); 27032001f49Smrg glUseProgram(program); 27132001f49Smrg 27232001f49Smrg stippleTex = glGetUniformLocation(program, "stippleTex"); 27332001f49Smrg glUniform1i(stippleTex, 0); /* unit 0 */ 27432001f49Smrg 27532001f49Smrg viewportSize = glGetUniformLocation(program, "viewportSize"); 27632001f49Smrg glUniform2f(viewportSize, WinWidth / 2.0, WinHeight); 27732001f49Smrg 27832001f49Smrg glUseProgram(0); 27932001f49Smrg 28032001f49Smrg return program; 28132001f49Smrg} 28232001f49Smrg 28332001f49Smrg 28432001f49Smrgstatic void 28532001f49SmrgUsage(void) 28632001f49Smrg{ 28732001f49Smrg printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); 28832001f49Smrg printf("Keys:\n"); 28932001f49Smrg printf(" a - toggle antialiasing\n"); 29032001f49Smrg printf(" s - toogle stippling\n"); 29132001f49Smrg printf(" w/W - decrease/increase line width\n"); 29232001f49Smrg} 29332001f49Smrg 29432001f49Smrg 29532001f49Smrgstatic void 29632001f49SmrgInit(void) 29732001f49Smrg{ 29832001f49Smrg GLushort pattern = 0xf2; 29932001f49Smrg GLuint tex; 30032001f49Smrg 30132001f49Smrg if (!ShadersSupported()) 30232001f49Smrg exit(1); 30332001f49Smrg 30432001f49Smrg glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 30532001f49Smrg glLineStipple(1, pattern); 30632001f49Smrg 30732001f49Smrg StippleProgram = MakeFragmentShader(); 30832001f49Smrg 30932001f49Smrg tex = LineStippleToTexture(pattern); 31032001f49Smrg glBindTexture(GL_TEXTURE_2D, tex); 31132001f49Smrg} 31232001f49Smrg 31332001f49Smrg 31432001f49Smrgint 31532001f49Smrgmain(int argc, char *argv[]) 31632001f49Smrg{ 31732001f49Smrg glutInit(&argc, argv); 31832001f49Smrg glutInitWindowSize(WinWidth, WinHeight); 31932001f49Smrg glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 32032001f49Smrg Win = glutCreateWindow(argv[0]); 32132001f49Smrg glutReshapeFunc(Reshape); 32232001f49Smrg glutKeyboardFunc(Key); 32332001f49Smrg glutSpecialFunc(SpecialKey); 32432001f49Smrg glutDisplayFunc(Draw); 32532001f49Smrg glewInit(); 32632001f49Smrg Usage(); 32732001f49Smrg Init(); 32832001f49Smrg glutMainLoop(); 32932001f49Smrg return 0; 33032001f49Smrg} 331