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