【问题标题】:OpenGL glCallLists Drawing Incorrect Characters On Windows 7OpenGL glCallLists 在 Windows 7 上绘制不正确的字符
【发布时间】:2012-05-28 09:11:10
【问题描述】:

我有一个用 Visual C++ 6 编写的旧应用程序。这个应用程序的一部分是将文本绘制到位图中。这在 Windows XP 上运行良好,但是当在 Windows 7 上运行相同的代码时,所有文本都会在 ASCII 表中移动一个位置。

例如,"Category" 变为 "B'sdfnqx"

任何想法是什么导致了这个问题以及如何解决它?

编辑:抱歉,以上内容略有不正确。当我在代码中看到 DrawText 函数时,我认为它是 GDI 函数。当我踏入其中时,发现作者创建了自己的DrawText 函数,该函数使用OpenGL。我不知道任何OpenGL,所以现在这已经失控了。它调用glCallLists 将文本(存储在CString 中)传递给这个函数。

完整的课程代码如下。注意:是 DrawText 函数中的 glCallLists 函数导致问题。

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;
}

现在我根本不知道 openGL,但我假设 glCallLists 只是将字符串重新解释为字节数组,在 Windows XP 和 Windows 7 之间出现了问题。也许是 unicode 问题或什么的?可能是 32 位 Windows 操作系统与 64 位操作系统?

现在这是否显示出更明显的问题?

【问题讨论】:

  • 真是个大问题。我想自己知道答案,即使它不会影响到我:-)。
  • 谢谢。希望我能得到一个很好的答案;)
  • 当然,这个问题与使用的字体无关。
  • @Sachin:不,最低级别的问题似乎是对字体字形的错误索引(减一),因此字体技术很可能是相关的。一个完整的例子比知道哪种字体更好。
  • 我猜想传递给 glCallLists 的基本列表编号是硬编码的,而不是使用从 glGenLists 返回的值。并且 glGenLists 在您的不同 PC 上返回不同的值。你可能想检查一下。

标签: c++ opengl windows-7


【解决方案1】:

这行显然没有按照它的评论所说的那样做:

wglUseFontBitmaps(hDC, 0, 255, m_id );          // Builds 96 Characters Starting At Character 32

这也不是:

glListBase(m_id);               // Sets The Base Character to 32    ( NEW )

不知何故,您的 m_id 变量与应有的值相差 1。将此行替换为

glListBase(m_id+1);

这两个地方都发生了,在 Windows 7 上应该一切正常。但 XP 会坏。

如随附的 cmets 建议的那样,更好的解决方法是实际仅生成可打印字符。如果其中一台计算机缺少非打印字符,您将不会遇到问题。

【讨论】:

  • 我知道。我认为编写此代码的人将其从互联网上下载下来,并在不更改 cmets 的情况下更改了值。正如我所说,这不是我的代码。身份证很好。它们是正确的值。我检查并仔细检查了这个。
  • @Jonnster:如果您在现有的wglUseFontBitmaps 之后执行wglUseFontBitmaps(hDC, 'a', 26, m_id+'a' ); 会发生什么?您是否尝试过在每次使用时将m_id 打印到控制台?也许您有一个无效的this 指针,导致使用了一个损坏的m_id 副本。
  • m_id 始终有效且始终是正确的值。我尝试将其更改为 m_id+1 并打印完全相同的字符。这很奇怪,但是我不知道 OpenGL,所以没什么应该让我感到惊讶的 ;)
  • @Jonnster:首先,DrawText 的两个函数中哪一个表现不好?
  • 更长的 DrawText 函数。我添加了 wglUseFontBitmaps(hDC, 'a', 26, m_id+'a' );代码,它仍然打印与以前相同的字符。
【解决方案2】:

我发现了这个,因为这是我所怀疑的。我实际上怀疑这是一个 UNICODE 的东西。几年前,当我尝试迁移到 Visual C++ 的更高版本时,我注意到了这一点。问题很可能是 2003 年以后的编译器自动将 CStrings 类型定义为 wchar_t。看看下面的链接项目。

http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/fa43f4aa-1822-405e-a95f-9b6377b64352

【讨论】:

  • 代码没有在较新的编译器中重新编译。它与在 XP 上运行良好但在 Win7 上运行良好的可执行文件相同。它似乎与unicode无关。不过还是谢谢。
  • 实际上仍然可以,考虑到所有底层 DLL 很可能在 XP 和 7 之间发生了变化。考虑到输出功能仅通过更改您正在运行的操作系统而发生变化,这一点相当明显无需重新编译。在您的 DrawText 例程中有一个字符串复制。
  • 强制相同的 DLL 没有区别。实际上原始代码没有那个字符串副本。只是我在弄乱代码,在我发布到这里之前我忘了把它放回去。所以没有字符串副本与问题无关。
  • 只是出于好奇,DrawText 例程的较短版本(没有 r、g、b)是否正常运行?
【解决方案3】:

从 XP 切换到 Windows 7 后,我可以确认这个错误。 如果您使用 Windows 中的本机 opengl32.dll 驱动程序(没有图形卡中的驱动程序,例如在 RDP 下),那么 glNewList/glEndList 之间的 glCallLists() 会出现问题。

见第 13 课冯尼赫http://nehe.gamedev.net/tutorial/bitmap_fonts/17002 并更改 glPrint() 以写入在 ASCII 表中移动了一个位置的行和第二个正确的行。 (使用带有 RDP 屏幕的 Windows 7)

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

}

这个问题的迹象: http://www.opengl.org/sdk/docs/man2/xhtml/glNewList.xml glCallList 和 glCallLists 可以输入到显示列表中。 显示列表中的命令或由 glCallList 或 glCallLists 执行的列表不包含在正在创建的显示列表中,即使列表创建模式为 GL_COMPILE_AND_EXECUTE。

【讨论】:

    【解决方案4】:

    这在 Windows XP 上运行良好,但在运行相同的代码时 Windows 7 所有文本在 ASCII 表中移动了一个位置。

    windows 7 和 windows 8 中的 opengl32.dll 在 glNewList/glEndList 之间调用显示列表时遇到问题

    查看示例“glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);”的答案

    我的解决方案:

    简单地将“旧”opengl32.dll 从 XP (windows\system32) 复制到您的程序文件夹

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-12
      • 1970-01-01
      • 1970-01-01
      • 2021-08-16
      相关资源
      最近更新 更多