Take the 2-minute tour ×

I'm working on a drawing application (similar to a 2d cad app) in Linux and one of the first things I discovered while working with OpenGL is that my Intel I5 Core HD GMA (built in) graphics hardware does not support AA lines or Multisample AA methods. So, I've spent the last week or so researching how to do antialiasing by using textures. I came across the arekkusu Invariance Texture AA article and have picked up quite a bit from it, but the problem I'm having is that when I use a blended circle just like those in many examples, my lines come out as really wide ellipses. It does blend correctly and the ellipse looks great. :) However, this isn't quite what I'm looking for. It appears the texture is not being "smeared" horizontally but is instead being stretched instead. I wind up with an ellipse that is the height of the "width" of my line and an elleptical width about 1/2 the length of my line.

In the mean time, I've tried something slightly different and created a texture that is 1 pixel wide and X pixels in height. As expected, the height and varying alpha values do change the outcome of my lines but I'm actually getting pretty good results except for very thin lines.

I'm including the code for a small test application I'm using (GLUT app) in hopes that someone can point out the bone-headed mistake I'm making. It is using the above 1 pixel wide texture but obviously I want to replace this by a circular texture instead. It isn't intended to be the most efficient code, but is easy to play with until I can get everything worked out.

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>

float centerX = 320.0;
float centerY = 240.0;

GLuint textureId = 0;

static GLuint createTexture(int width, int height)
    GLuint id;
glGenTextures( 1, &id );

glBindTexture( GL_TEXTURE_2D, id );
    int bpp = 4;  // Bytes per pixel

    GLubyte* bitmap = new GLubyte[width * height * bpp];
        printf("%03d: ",y);
            if ((y == 0) || (y == height - 1)) {
                bitmap[y * width * bpp + x + 3] = 21;
            } else if ((y == 1) || (y == height - 2)) {
                bitmap[y * width * bpp + x + 3] = 80;
            } else if ((y == 2) || (y == height - 3)) {
                bitmap[y * width * bpp + x + 3] = 166;
            } else {
                bitmap[y * width * bpp + x + 3] = 255;
            printf("%03d ", bitmap[y * width * bpp + x + 3]);

            // Fill color with white so we can blend in our
            // own color when we draw the line.
            bitmap[y * width * bpp + x + 0] = 255;
            bitmap[y * width * bpp + x + 1] = 255;
            bitmap[y * width * bpp + x + 2] = 255;
    glTexImage2D(GL_TEXTURE_2D, 0, bpp, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, bitmap);


    // Doesn't seem to make much difference for how this is currently  
    // working.
    // gluBuild2DMipmaps( GL_TEXTURE_2D, 4, width, height,
    //                    GL_RGBA, GL_UNSIGNED_BYTE, bitmap);

    delete [] bitmap;

    return id;

static void resize(int width, int height)
    glViewport(0, 0, width, height);

    glLoadIdentity() ;

    centerX = (float)width / 2.0;
    centerY = (float)height / 2.0;


static void drawLine(float x0, float y0, float x1, float y1, float width)
    glBindTexture(GL_TEXTURE_2D, textureId);

    // Would be faster using arrays, but this is easier to tweak for now
        glTexCoord2f(0.0, 0.0); glVertex2f( x0, y0);
        glTexCoord2f(0.0, 1.0); glVertex2f(x0, y0 + width);
        glTexCoord2f(1.0, 1.0); glVertex2f(x1, y1 + width);
        glTexCoord2f(1.0, 0.0); glVertex2f(x1, y1);

static void display(void)

    for(float angle = 0.0; angle < 360.0; angle += 2.0) {
        glTranslatef(centerX, centerY, 0.0);
        glRotatef(angle, 0.0, 0.0, 1.0);
        glColor3f(0.0, 0.3, 0.9);
        drawLine(0.0, 0.0, centerY, 0.0, 5.0);



int main(int argc, char *argv[])
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Texture Antialiasing"); 



    // Create a texture 1 pixel wide by 8 pixels high. This
    // texture will get stretched horizontally when we
    // draw the textured line. Ideally, we would want to use
    // a circlular texture here, but the code currently causes
    // the line to consist of a very wide ellipse with "width"
    // height and a elliptical width of about 1/2 our line length.
    textureId = createTexture(1,8);


    return EXIT_SUCCESS;

I've tried different options for the glTexParameterf calls like trying to use GL_NEAREST for the filters and GL_REPEAT for the wrap, but that didn't work well at all for circle tectures. I've also tried using the GL_MODULATE setting as shown in the OpenGL FAQ for doing this type of AA but that made no difference.

Any help would be much appreciated. Thanks.

share|improve this question
add comment

2 Answers

It is not necessary that you use the entire texture at once. Let us assume that your circle texture has tex vertices from 0 to 1.0 in x axis and in y axis. When you need the curved edge or a round cap, you could map (0,0) (0,0.5) (0.5,0.5) (0.5,0) of the texture to the vertices. Or when you need just the line strip, you could map (0.5,0) (0.5,0) (0,0.5) (0,0.5) to the entire rect.

share|improve this answer
This was indeed the key to my issue. Unfortunately, in the examples I've seen, none actually showed details for the actual rendering sections, just mentioned roughly how to do it. Once I "stretched" just the center of the circle for the non cap length of the line, it works great. –  Russ May 20 '11 at 20:23
add comment

The basic implementation for this is to draw 1 rectangle (your line) and 2 quads (you line extremities).

You put the half-circles textures in the quads, and a simple gradient in your rectangle.

A better solution is to draw a rectangle, and use the length of the segment as your V coordinate.

In your fragment shader,

  • when V € [0,0.5], use your normal circular texture (left extremity)
  • when V € [length-0.5,length], use your normal circular texture, but with v-length+1 (rightextremity)
  • else (v € [0.5, length-0.5]) use v=0.5 (the real line segment)
share|improve this answer
For a while, I was using gradients to solve this. Specifically I would render the "center" section of the line then render gradients on each edge tapering down to 0 alpha. That yielded some good results, but strangely it seems slower than using the texture option. Is this what you would expect? I was rather surprised by this. This method did seem to do a better job on thinner lines, so I may use a hybrid approach. –  Russ May 20 '11 at 20:26
If I understand correctly, you were rendering 3 quads (=6 triangles) for the line itself, extremities not included ? If so, yes, it's slower than just 2 triangles, even with a texture. Texturing is cheap, and with such a small texture, it's almost free. –  Calvin1602 May 20 '11 at 21:09
That's correct, two thin (ie: 1 to 2 pixels) edges on each side of the line, then the middle of the line. By using the suggestions here, I have things working great except that the only way I can get thin (< 3 pixel) lines to look good is if the texture's middle alpha value is lower than 255 (ie: 110 or so). This causes the lines to appear dimmer than those that use a texture with full intensity alpha values. By playing with the edge and middle alpha, I can make the lines look better but it depends on the background color. I hat to have to generate different textures for this. Any ideas? –  Russ May 20 '11 at 22:28
Just realized that I didn't point out that my current code is using the texture shading algorithm and not the simple alpha blended quads. This seems to be the best option in terms of performance, but I need to find a solution to thin lines since my app will use mostly thin lines in it. –  Russ May 20 '11 at 22:30
Try multiplying the rgb component of your texture by the a component. This is known as "premultiplied alpha". If you want to make alpha vary depending on the depth/width, this is possible in the shader too. –  Calvin1602 May 21 '11 at 4:55
show 2 more comments

Your Answer


