Problems with line drawing

Hi,

I’m writing a window manager that uses OpenGL as the rasteriser. Bizarrly, I have a problem with straight lines.

I set the screen up so that the x,y dimensions coorespond to the pixel width / height of the video mode.

int GLRasteriser::Set2DLinearMode()
{
float matrix[16];

int x,y,bpp;
GB_GetScreenDimensions(&x,&y,&bpp);
glDisable(GL_NORMALIZE);
glDisable(GL_LINE_SMOOTH);

glViewport(0,0,x,y);
glMatrixMode(GL_PROJECTION); // set up projection transform
glLoadIdentity();

gluOrtho2D(0,(double)x,(double)y,0); // Top left = 0,0 screen origin

glMatrixMode(GL_MODELVIEW); // now change to modelview
glLoadIdentity();

return TRUE;
}

When I try an draw a line (glBegin(GL_LINES))that is approx. 75% of the screen away from the origin it is draw at 1 pixel less than the specified coordinate. What makes it really strange is that calls to glBegin(GL_QUADS), for filling the windows, and glDrawPixels get the correct coordinate.

Any ideas?

Leo

This is just a guess, but if you have the starting coordinates 0,0 then the ending coordinates should be x-1, y-1.

eg. 0,0-----------
| |
----------x-1,y-1

I’m also using OpenGl as a 2D rasterizer and I also had the same problem. I ended up just using GL_QUADS to draw my lines because GL_LINES seemed inexact. It wasn’t always one pixel off otherwise I would have just added a constant. Instead it was off by one pixel depending on where in the window it was drawing.

I would be very curious for someone to explane this too.

Have a look at the “diamond exit rule” used in OpenGL to decide which pixels are touched while rendering primitives. Pictures are in the OpenGL specs.
Also remember that pixels are not infinitely small points but have an area. If you want to hit a pixel exactly in the center you have to shift all 2D screen coordinates by 0.5.
That is, don’t draw from (0, 0) to (x, y) but from (0.0 + 0.5, 0.0 + 0.5) to (x + 0.5, y + 0.5). This should fulfill the diamond exit rule conditions for both start and end points.

Thanks all,

stumbled across the GL_QUADS method before reading this post. Used a width of 1.1f for the quads as single pixel width was creating new atifacts. Will have a look at the +/-0.5f line method later

cheers

Leo

Tried both methods. QUADS worked nicely until I noticed that very infrequently it would drop pixels in the middle of a line! Some kind of odd sliver problems there.

LINES method didn’t work with an offset of 0.5, (as I’m using straight lines I only added the offset on the princliple axis). Played around with it and used 0.4f offset. That works.

#define USELINES

int GLRasteriser::iDrawVline(int an_XPos, int an_Ypos, int an_Len, COLOUR a_Colour)
{
if ( mn_RasterMode != RM_2DLINEAR ) Set2DLinearMode();

#ifdef USELINES

glBegin(GL_LINES);

  glColor3ub((GLubyte)GETRED(a_Colour),(GLubyte)GETGREEN(a_Colour),(GLubyte)GETBLUE(a_Colour));

  glVertex2f((float)an_XPos+0.4f, an_Ypos);
  glVertex2f((float)an_XPos+0.4f, an_Ypos + an_Len);

glEnd();

#else

glBegin(GL_QUADS);

  glColor3ub((GLubyte)GETRED(a_Colour),(GLubyte)GETGREEN(a_Colour),(GLubyte)GETBLUE(a_Colour));

  glVertex2d((double)an_XPos-0.4f,   (double) (an_Ypos) );
  glVertex2d((double)an_XPos+1.4f, (double) (an_Ypos) );

  glVertex2d((double)an_XPos-0.4f, (double)(an_Ypos + an_Len));
  glVertex2d((double)an_XPos+1.4f, (double)(an_Ypos + an_Len));

glEnd();

#endif

return TRUE;
}

int GLRasteriser::iDrawHline(int an_XPos, int an_Ypos, int an_Len, COLOUR a_Colour)
{
if ( mn_RasterMode != RM_2DLINEAR ) Set2DLinearMode();

#ifdef USELINES

glBegin(GL_LINES);

  glColor3ub((GLubyte)GETRED(a_Colour),(GLubyte)GETGREEN(a_Colour),(GLubyte)GETBLUE(a_Colour));

  glVertex2f((float)an_XPos,             (float)an_Ypos + 0.4f);
  glVertex2f((float)(an_XPos + an_Len),  (float)an_Ypos + 0.4f);

glEnd();

#else

glBegin(GL_QUADS);

  glColor3ub((GLubyte)GETRED(a_Colour),(GLubyte)GETGREEN(a_Colour),(GLubyte)GETBLUE(a_Colour));

  glVertex2d((double)an_XPos, (double)an_Ypos-0.45f);
  glVertex2d((double)(an_XPos + an_Len), (double)an_Ypos-0.45f);

  glVertex2d((double)(an_XPos + an_Len), (double)an_Ypos+1.45f);
  glVertex2d((double)an_XPos, (double)an_Ypos+1.45f);

glEnd();

#endif

return TRUE;
}
#undef USELINES