Reputation: 3234
I have an old application written in Visual C++ 6. Part of this app is drawing text into a bitmap. This works fine on Windows XP but when the same code is run on Windows 7 all the text is shifted by one place in the ASCII table.
For example, "Category"
becomes "B'sdfnqx"
.
Any ideas what is causing this and how to fix it?
Edit: Sorry but the above is slightly incorrect. When I saw the DrawText function in the code I assumed it was the GDI function. When I step into it, it turns out that the author has created their own DrawText
function which is using OpenGL
. I don't know any OpenGL
so this has now got out of hand. It calls glCallLists
which passes the text (stored in a CString
) into this function.
Full class code below. Note: it is the glCallLists function in the DrawText function causing the problem.
OGLFontClass::OGLFontClass()
{
m_id = -1;
}
OGLFontClass::~OGLFontClass()
{
Clear();
}
void OGLFontClass::Clear()
{
if( m_id != -1 )
{
glDeleteLists(m_id,255);
m_id = -1;
}
}
void OGLFontClass::Initialise(CString fontname, int size, HDC hDC)
{
m_HDC = hDC;
m_id = glGenLists(255);
::DeleteObject( m_FONT );
m_FONT = CreateFont( -size, // Height Of Font ( NEW )
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
FW_NORMAL, // Font Weight
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout
ANSI_CHARSET, // Character Set Identifier
OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
fontname); // Font Name
HFONT oldfont = (HFONT)SelectObject(hDC, m_FONT); // Selects The Font We Want
wglUseFontBitmaps(hDC, 0, 255, m_id ); // Builds 96 Characters Starting At Character 32
::SelectObject( hDC, oldfont );
}
void OGLFontClass::DrawText( float x, float y, CString str )
{
glRasterPos3f(x,y, 0);
glPushAttrib(GL_LIST_BIT);
glListBase(m_id);
glCallLists(str.GetLength(), GL_UNSIGNED_BYTE, str.GetBuffer(0));
glPopAttrib();
}
void OGLFontClass::DrawText(int x, int y, int r, int g, int b, CString text)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();// Reset The View
HWND hWnd = ::WindowFromDC(wglGetCurrentDC() );
RECT rc;
::GetClientRect( hWnd, &rc );
int CX = rc.right;//::GetSystemMetrics( SM_CXSCREEN );
int CY = rc.bottom;//::GetSystemMetrics( SM_CYSCREEN );
gluOrtho2D (0,::GetSystemMetrics(SM_CXSCREEN),::GetSystemMetrics(SM_CYSCREEN), 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3ub(r,g,b);
glRasterPos2d( x, y ); // had to do this to get the text to line up where i want it
//glDisable(GL_TEXTURE_2D);
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits ( NEW )
glListBase(m_id); // Sets The Base Character to 32 ( NEW )
unsigned char* szTemp = new unsigned char[text.GetLength()+1];
strcpy((char*)szTemp, text);
glCallLists(strlen((char*)szTemp), GL_UNSIGNED_BYTE, szTemp); // Draws The Display List Text ( NEW )
delete[] szTemp;
glPopAttrib(); // Pops The Display List Bits ( NEW )
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
void OGLFontClass::DrawRightText( int x, int y, int r, int g, int b, CString text )
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();// Reset The View
HWND hWnd = ::WindowFromDC(wglGetCurrentDC() );
RECT rc;
::GetClientRect( hWnd, &rc );
float CX = (float)::GetSystemMetrics( SM_CXSCREEN );
float CY = (float)::GetSystemMetrics( SM_CYSCREEN );
float fMultiplier = CX / CY;
gluOrtho2D (0,::GetSystemMetrics(SM_CXSCREEN),::GetSystemMetrics(SM_CYSCREEN), 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
int nPos = x;
glColor3ub(r,g,b);
//glDisable(GL_TEXTURE_2D);
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits ( NEW )
glListBase(m_id); // Sets The Base Character to 32 ( NEW )
for( int i = text.GetLength() - 1; i >= 0; i-- )
{
CString sChar = text.GetAt(i);
glRasterPos2d(nPos,y); // had to do this to get the text to line up where i want it
glCallLists(1, GL_UNSIGNED_BYTE, sChar); // Draws The Display List Text ( NEW )
if ( i > 0 )
{
CString sNextChar = text.GetAt(i-1);
SIZE szWidth = GetTextExtent(sNextChar);
szWidth.cx += 1;
szWidth.cx *= fMultiplier;
szWidth.cx += 1;
nPos -= szWidth.cx;
}
}
//glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text ( NEW )
glPopAttrib(); // Pops The Display List Bits ( NEW )
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
CSize OGLFontClass::GetTextExtent(CString text, float fFactor)
{
SIZE sz;
HFONT oldfont = (HFONT) SelectObject(m_HDC, m_FONT);
GetTextExtentPoint32(m_HDC,text,strlen(text),&sz);
SelectObject(m_HDC, oldfont);
sz.cx *= 0.2;
sz.cy *= 0.2;
return sz;
}
Now I don't know openGL at all but I'm assuming that as glCallLists
just reinterprets the string as a byte array there is something going wrong in this between Windows XP and Windows 7. Perhaps a unicode issue or something? 32-bit Windows OS versus 64-bit OS maybe?
Does this now show up a more obvious problem?
Upvotes: 6
Views: 4124
Reputation: 9
This works fine on Windows XP but when the same code is run on Windows 7 all the text is shifted by one place in the ASCII table.
the opengl32.dll from windows 7 and windows 8 have trouble with a display list call between glNewList/glEndList
see answer with sample "glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);"
my solution:
simple copy the "old" opengl32.dll from XP (windows\system32) to your program folder
Upvotes: 0
Reputation: 1
I can confirm this bug after changing from XP to Windows 7. If you use the native opengl32.dll driver from windows (without drivers from your grahpicscard, like under RDP) then you have a problem with glCallLists() between glNewList/glEndList.
see Lession 13 von NeHe http://nehe.gamedev.net/tutorial/bitmap_fonts/17002 and change glPrint() to write a line shifted by one place in the ASCII table and a second correct line. (use Windows 7 with RDP Screen)
GLvoid glPrint(const char *fmt, ...) // Custom GL "Print" Routine
{
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) // If There's No Text
return; // Do Nothing
va_start(ap, fmt); // Parses The String For Variables
vsprintf_s(text, fmt, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
//first text line
glRasterPos2f(-0.8f, 0);
GLuint List1 = glGenLists (1);
glNewList(List1, GL_COMPILE);
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits
glListBase(base1); // Sets The Base Character to 32
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
glPopAttrib(); // Pops The Display List Bits
glEndList();
glCallList(List1);
//second text line
glRasterPos2f(-0.8f, -0.2f);
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits
glListBase(base1); // Sets The Base Character
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
glPopAttrib(); // Pops The Display List Bits
}
An indication of this trouble: http://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml glCallList and glCallLists can be entered into display lists. Commands in the display list or lists executed by glCallList or glCallLists are not included in the display list being created, even if the list creation mode is GL_COMPILE_AND_EXECUTE.
Upvotes: 0
Reputation: 283733
This line clearly doesn't do what its comment says:
wglUseFontBitmaps(hDC, 0, 255, m_id ); // Builds 96 Characters Starting At Character 32
Nor does this:
glListBase(m_id); // Sets The Base Character to 32 ( NEW )
Somehow, your m_id
variable is off by one from what it should be. Replace this line by
glListBase(m_id+1);
both places it occurs, and all should be well on Windows 7. But XP will break.
A better fix would be to actually generate only the printable characters, as the accompanying comments suggest. Then you'll not have issues if one of the computers is missing a non-printing character.
Upvotes: 1
Reputation: 7065
I found this, as this is what I was suspecting. I actually suspect that it is a UNICODE thing. I noticed this years ago when I tried to move to a later version fo Visual C++. Problem is most likely that the compiler beyond 2003 automatically typedefs CStrings to wchar_t. Take a look at the linked item below.
http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/fa43f4aa-1822-405e-a95f-9b6377b64352
Upvotes: 0