我在一个包含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渲染暂停时调整窗口大小时才能看到它。
答案 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操作。