在MFC中的OpenGL上下文上绘制文本

时间:2011-07-06 11:40:48

标签: opengl mfc

我在一个包含OpenGL上下文的MFC应用程序上工作。我是MFC的新手,这就是我要问它的原因.OpenGL工作正常,但是当我想在WindowProc中使用此代码在3D窗口上方绘制文本时:

        case WM_PAINT:

      hDC=BeginPaint(window,&paintStr);
      GetClientRect(window,&aRect);
      SetBkMode(hDC,TRANSPARENT);
      DrawText(hDC,L"He He I am a text on top of OpenGL",-1,&aRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
      EndPaint(window,&paintStr);

      return 0;

它显示在OpenGL上下文中。我只能在OpenGL渲染暂停时调整窗口大小时才能看到它。

2 个答案:

答案 0 :(得分:4)

你在做什么是错误的,也比在OpenGL中做的更难。要解决向OpenGL绘制的窗口添加文本的问题,最好让OpenGL绘制文本。您甚至可以使用与MFC中使用的完全相同的字体,方法是在处理WM_CREATE时创建一个CFont实例,在DC中选择字体,然后调用wglUseFontBitmaps,这将生成一系列可以与glCallLists一起使用的栅格化位图。 (当你在它的时候,分别调用GetCharABCWidths和GetTextMetrics来确定每个字形的宽度和高度。)

ABC glyphInfo[256]; // for font widths
TEXTMETRIC tm;  // for font heights

// create a bitmap font
CFont myFont;
myFont.CreateFont(
    16,                        // nHeight
    0,                         // nWidth
    0,                         // nEscapement
    0,                         // nOrientation
    FW_NORMAL,                 // nWeight
    FALSE,                     // bItalic
    FALSE,                     // bUnderline
    0,                         // cStrikeOut
    ANSI_CHARSET,              // nCharSet
    OUT_DEFAULT_PRECIS,        // nOutPrecision
    CLIP_DEFAULT_PRECIS,       // nClipPrecision
    DEFAULT_QUALITY,           // nQuality
    DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
    _T("Arial")                // lpszFacename
);

// change the current font in the DC
CDC* pDC = CDC::FromHandle(hdc);

// make the system font the device context's selected font  
CFont *pOldFont = (CFont *)pDC->SelectObject (&myFont); 

// the display list numbering starts at 1000, an arbitrary choice  
wglUseFontBitmaps (hdc, 0, 255, 1000); 
VERIFY( GetCharABCWidths (hdc, 0, 255, &glyphInfo[0]) );
pDC->GetTextMetrics(&tm);

if(pOldFont)
    pDC->SelectObject(pOldFont);

myFont.DeleteObject(); 

ABC glyphInfo[256]; // for font widths TEXTMETRIC tm; // for font heights // create a bitmap font CFont myFont; myFont.CreateFont( 16, // nHeight 0, // nWidth 0, // nEscapement 0, // nOrientation FW_NORMAL, // nWeight FALSE, // bItalic FALSE, // bUnderline 0, // cStrikeOut ANSI_CHARSET, // nCharSet OUT_DEFAULT_PRECIS, // nOutPrecision CLIP_DEFAULT_PRECIS, // nClipPrecision DEFAULT_QUALITY, // nQuality DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily _T("Arial") // lpszFacename ); // change the current font in the DC CDC* pDC = CDC::FromHandle(hdc); // make the system font the device context's selected font CFont *pOldFont = (CFont *)pDC->SelectObject (&myFont); // the display list numbering starts at 1000, an arbitrary choice wglUseFontBitmaps (hdc, 0, 255, 1000); VERIFY( GetCharABCWidths (hdc, 0, 255, &glyphInfo[0]) ); pDC->GetTextMetrics(&tm); if(pOldFont) pDC->SelectObject(pOldFont); myFont.DeleteObject();

然后当您处理WM_PAINT时,重置您的矩阵并使用glRasterPos2d将文本放在您需要的位置。我建议使用类似下面的代码来计算字符串的确切宽度,如果你想让它水平居中的话。

// indicate start of glyph display lists  
glListBase (1000); 

CRect r;
GetWindowRect(r);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, r.Width(), 0, r.Height());

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();

CString formattedString;
formattedString.Format("Pi is about %1.2f", 3.1415);

int stringWidth=0; // pixels
for(int j=0; j < formattedString.GetLength(); ++j)
    stringWidth += glyphInfo[ formattedString.GetAt(j) ].abcA + glyphInfo[ formattedString.GetAt(j) ].abcB + glyphInfo[ formattedString.GetAt(j) ].abcC;

double textXPosition, textYPosition;
textXPosition = r.Width()/2-stringWidth/2; // horizontally centered
textYPosition = r.Height()/2-tm.tmHeight/2; // vertically centered

glRasterPos2d(textXPosition,textYPosition);

// this is what actually draws the text (as a series of rasterized bitmaps)
glCallLists (formattedString.GetLength(), GL_UNSIGNED_BYTE, (LPCSTR)formattedString);

glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();

虽然设置很烦人,但你只需要做一次,而且我认为它比处理GDI更不令人沮丧。混合GDI和OpenGL确实是在寻找麻烦,OpenGL在显示文本方面表现非常出色 - 您可以免费获得亚像素精度,以及其他好处。

编辑:为了回应您对包含GUI元素的请求,我假设您想要同时拥有OpenGL绘制的窗口以及标准的Windows控件(编辑框,复选框,按钮,列表控件等)在同一父窗口内。我还假设你打算让OpenGL只绘制窗口的一部分,而不是窗口的背景。

由于您说您正在使用MFC,我建议您创建一个对话框窗口,将所有标准Windows控件添加到其中,然后添加一个CWnd派生类来处理WM_PAINT。使用资源编辑器将控件移动到所需位置。实际上,您正在制作一个自主绘制自定义控件,OpenGL正在进行绘图。因此OpenGL将绘制该窗口,标准MFC类(CEdit,CButton等)将自行绘制。这在我的经验中效果很好,并且与GDI在所有者绘制控件中的作用相差无几。

如果您希望OpenGL绘制窗口的背景,并且您希望标准Windows控件显示在其上,该怎么办?我认为这不是一个好主意,但你可以为你的CDialog派生类处理WM_PAINT和WM_ERASE。在WM_ERASE中,调用OpenGL来绘制3D内容,当调用WM_PAINT时,将由标准Windows控件覆盖。或者在WM_PAINT中,您可以在调用CDialog :: OnDraw之前调用OpenGL,这类似。

请澄清你的陈述“我想添加一些2s图形叠加(如标签,gui元素)”如果你想让我写更多。

答案 1 :(得分:2)

查看代码我假设从计时器或idel循环操作调用OpenGL渲染。自然地,OpenGL执行可能包含一些清除,因此可以使用它绘制任何其他内容。

不建议将GDI文本绘图与OpenGL混合,但可以完成。但是,当然您需要将该代码包含在OpenGL绘图函数中,在缓冲区交换之后放置所有GDI操作。