What does GL_FILL mean, -exactly-

Alright, I’m working on a game, and I’m writing an overlay. My overlay loads the identity matrix for projection and modelview, then sets the projection matrix to an Ortho2D mode (0, 0, width, height) where width and height are equal to the pixel size of my viewport.

Now in modelview, logic assumes that:

glBegin(GL_POINTS);
glVertex2i(50, 50);
glend();

will place draw a pixel and coordinate 50, 50. No problem, this works fine.

Now I have a ‘window’. A window is defined as (x1, y1),(x2, y2). No brainer. So I do a

glBegin(GL_POLYGON);
vertexes…
glEnd();

or, better yet, use the glRecti() command.

That’s great. Now here’s my problem. I draw my ‘window’ twice. Once, I draw it filled, and it gets rendered as such:

111111
111111
111111

Then, the second draw, I render it in glPolygonMode(GL_LINE). And now it looks like:

222222
2111112
2111112
2222222

New pixels were drawn above and to the left of the window, and pixels within the window were overwritten on the right and bottom sides. In addition, the top-left pixel is NOT drawn.

So, I guess my question is, is this behavior defined? Where? Am I going about this wrongly? I want pixel-exact drawing, can I do this with OGL? Is this behavior the same on ALL OGL implementations/hardware? If so, that means I can just work around how it is working here, and expect my ‘hacked’ code to work fine on all implementations?

Any help would be appreciated.

Keith Jackson

Crap, my fancy ASCII art did not work right on this board. It should be:

111111
111111
111111

222222
2111112
2111112
2222222

How the actual rasterization is done is implementation specific, and there’s no dictation that any given call MUST produce a given result.

So, maybe on someone else’s system the bottom right pixel will be gone, or there will be no corners, or all corners.

In conclusion, you’ll need to do some code modifications (perhaps drawing four lines, but that still might not be exact in all instances) or live with it.

Can be a pixel center problem. Remember that the lower left corner of the window, coordinate (0, 0), is the corner of the lower left pixel. The center of lower left pixel is located at 0.5 offser along both the X and Y axes. If you want to map integer coordinates to pixel coordinates, you must offset the projection matrix by one half.

glOrtho(-0.5, width-0.5, 0.5, height-0.5, -1, 1);

[This message has been edited by Bob (edited 12-07-2002).]

So then I guess my question is, how can I get pixel-exact results with OpenGL? Can i simply not do it? Are there are libraries or extensions or anything for it? Can I use DirectDraw and OGL together? WHat do I do? I need to draw pixels in exact pixels, and it to be same on all systems.

Keith

Sure you can. Using the projection matrix I gave you, and the modelview matirx set to identity, you can have exact control over which pixels are drawn or not.

So where can I find more information about this 0.5 offset, pixels being defined by their lower left corner, etc? I have the red and blue books but I’m not finding it…

Keith

The Red book (I’m assuming the 1.2 version), appendix G, OpenGL Correcness Tips. It uses 0.375 instead of 0.5 as I did though.

It will help if you take a look at picture 2-1 (p. 37) also. To make it easier to see, forget about the thin lines and imagine the values in the upper right corner says (5, 5) instead. You now have a picture of a 5x5 pixel area with lines (the thick ones) separating each pixel. If you call gluOrtho2D(0, 5, 0, 5), coordinate (0, 0) will map to the lower left corner, and (5, 5) to the upper left corner. Each line has it’s own integer coordinate value.

Now, note than coordinate (1, 1) is in the exact corner of where four pixels meet. If you draw a point there, which pixel is actually drawn? If you want exact control over what pixel is drawn, you have to specify half integers values. (0.5, 0.5) for example is the center of the lower left pixel, and (4.5, 1.5) is the center of the pixel one up from the bottom right corner.

Alright, so, the offset makes sense, but still does not fix my problem.

What I’m trying to do is draw a ‘window’. A rectangle that is alpha blended over whatever is there. Then, if it’s the ‘current’ window, I want it to have a border. So I draw each window with GL_FILL mode, and then draw them with GL_LINE mode. The outline on some edges are ‘inside’ the drawn window, and some edges have a new pixel added.

So, given this problem, needing a window where I can have borders like this, how should I do it? I don’t think it’s this pixel offset thing like we’ve been discussing. It’s always offset on one or more edges, offset by 0.375, 0.5, or whatever.

Keith

Post some code so we can see what you do.

Every Window is an object, with a render method, as follows:

void UIWindow::Render(bool mouse_focus)
{
int x;
GLint mousepos[2];

g_UI->GetMousePos(mousepos);

if (m_theight && mouse_focus &&
mousepos >= m_pos && mousepos <= m_pos + m_width &&
mousepos[Y] <= m_pos[Y] && mousepos[Y] >= m_pos[Y] - m_theight + 1)
{
GLfloat ifactor = 1.0f / m_theight;

for (x = 1; x <= m_theight; x++)
{
  glColor3f(ifactor * (m_theight - x), ifactor * (m_theight - x), 1);
  glRasterPos2i(0, 0);
  glBitmap(0, 0, 0, 0, m_pos[X], m_pos[Y], NULL);
  glBitmap(0, 0, 0, 0, 0, -(x-1), NULL);
  glBitmap(m_width, 1, 0, 0, 0, 0, g_bits);
}

}

glPushAttrib(GL_COLOR_BUFFER_BIT);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glColor4fv(m_bgcolor);
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, m_pos, m_pos[Y], NULL);
glBitmap( 0, 0, 0, 0, 0, 1 - m_theight - m_height, NULL);
glBitmap(m_width, m_height, 0, 0, 0, 0, g_bits);

if (m_border)
{
glColor4fv(m_bordercolor);
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, m_pos, m_pos[Y], NULL);
glBitmap( 0, 0, 0, 0, 0, 0 - m_theight, NULL);

glBitmap(m_width,            1, 0, 0,           0,  1 - m_height, g_bits);
glBitmap(m_width,            1, 0, 0,           0,             1, g_bits);
glBitmap(      1, m_height - 2, 0, 0, m_width - 1,             0, g_bits);
glBitmap(      1, m_height - 2, 0, 0,           0,             0, g_bits);

}

glPopAttrib();

glColor3f(0.5f, 0.5f, 1.0f);
glRasterPos2i(0, 0);
glBitmap(0, 0, 0, 0, m_pos, m_pos[Y], NULL);

glBitmap(0, 0, 0, 0, 2, 1 - m_theight - g_UI->GetFontHeight(), NULL);
for (x = 0; x < m_cheight; x++)
{
glCallLists(m_cwidth, GL_UNSIGNED_BYTE, &m_screenbuf[x * m_cwidth]);
glBitmap(0, 0, 0, 0, -m_cwidth * g_UI->GetFontWidth(), -g_UI->GetFontHeight(), NULL);
}
}

UIWindow::Render is called from UI::Render() as follows:

bool UI::Render(void)
{
list<UIWindow *>::iterator it;
list<UIWindow *>::reverse_iterator rit;
UIWindow *focuswin;
char txt[1024];

if (m_framesec != g_cursec)
{
m_framesec = g_cursec;
m_fps = m_frames;
m_frames = 0;
}
else
m_frames++;

ProcessKB();
ProcessMouse();

glListBase(m_fontoffset);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, g_OGLWin->GetWidth(), 0, g_OGLWin->GetHeight(), -1, 1);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375, 0.375, 0.0);

focuswin = NULL;
for (rit = m_windowlist.rbegin(); rit != m_windowlist.rend(); rit++)
{
if ((*rit)->IsWithin(m_mousepos, m_mousepos[Y], false))
{
focuswin = *rit;
break;
}
}
for (it = m_windowlist.begin(); it != m_windowlist.end(); it++)
(*it)->Render((*it) == focuswin);

glColor3f(1, 1, 1);
glRasterPos2i(1, g_OGLWin->GetHeight() - m_fheight);
sprintf(txt, “FPS: %2d, Mouse: %d, %d (%ld %ld)”, m_fps, m_mousepos, m_mousepos[Y], g_curtick, g_cursec);
glCallLists(strlen(txt), GL_UNSIGNED_BYTE, txt);

if (g_mode & MODE_LOGIN)
{
glRasterPos2i(100, 200);
m_loginimg->Render();
glRasterPos2i(100, 100);
m_passwordimg->Render();
}

glRasterPos2i(m_mousepos, m_mousepos[Y]);
glBitmap(0, 0, 0, 0, 0, -m_cursor->GetHeight() + 1, NULL);
m_cursor->Render();

return true;
}

Anyway, that’s the basics of my UI. I’ve abandoned the idea of using any of the vertex data for User Interface stuff. As you can see, I’m doing it all with glBitmap() now. I cannot get reliability with polygons. Lines and points I can get where I want, but polygons are being a pain. If I draw my window as a polygon, it may or may not fill the edge pixels. I can’t cope with that ‘inexactness’. However, since I’m using bitmaps, I lose the ability to do nice things like smooth shading. Do I need that in the user interface, anyway? Probably not. Though, I am worried… Transfering a completely filled 100*100 bitmap as a window MUST be slower than transfering vertex data. That sucks. Until I can figure out other ways, this is the only way I can get these windows to have edges defined EXACTLY how I want them in pixel space.

Any suggestions/optimizations/etc are welcome.

Keith

P.S. Yeah, I pasted too much code. Was easier to just post the two methods than pick through them for the ‘important’ stuff.

[This message has been edited by kjackson (edited 12-08-2002).]