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

发布于 2024-11-18 23:23:25 字数 494 浏览 1 评论 0原文

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

I work on an MFC app containing OpenGL context.I am new to MFC that is why I am asking it.OpenGL works fine ,but when I want to draw a text above the 3D window using this code inside WindowProc:

        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;

it is shown beneath the OpenGL context.I can see it only when resizing the window as the OpenGL rendering pauses than.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哆啦不做梦 2024-11-25 23:23:25

你所做的事情是错误的,而且比在 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(); 

然后,当您处理 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 控件,然后添加一个处理 WM_PAINT 的 CWnd 派生类。使用资源编辑器将控件移动到您想要的位置。实际上,您正在创建一个所有者绘制的自定义控件,其中 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 元素)”。

What you're doing is wrong and also harder than doing it all in OpenGL. To solve the problem of adding text to an OpenGL-drawn window, it's better to just make OpenGL draw the text. You can even use the exact same font you were using in MFC by creating a CFont instance when you handle WM_CREATE, selecting the font into the DC, and calling wglUseFontBitmaps, which will make a series of rasterized bitmaps that you can use with glCallLists. (While you're at it, call GetCharABCWidths and GetTextMetrics to determine the width and height of each glyph, respectively.)

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(); 

Then when you handle WM_PAINT, reset your matrices and use glRasterPos2d to put the text where you need it to go. I suggest calculating the exact width of your string using code similar to the one below if you want it to be horizontally centered.

// 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();

While the setup is annoying, you only have to do it once, and I think it's less frustrating than dealing with GDI. Mixing GDI and OpenGL is really asking for trouble, and OpenGL does a very good job of displaying text -- you get sub-pixel accuracy for free, among other benefits.

Edit: In response to your request for including GUI elements, I will assume that you meant that you want to have both OpenGL-drawn windows and also standard Windows controls (edit boxes, check boxes, buttons, list controls, etc.) inside the same parent window. I will also assume that you intend OpenGL to draw only part of the window, not the background of the window.

Since you said you're using MFC, I suggest that you create a dialog window, add all of your standard Windows controls to it, and then add in a CWnd-derived class where you handle WM_PAINT. Use the resource editor to move the control to where you want it. Effectively, you're making an owner-draw custom control where OpenGL is doing the drawing. So OpenGL will draw that window, and the standard MFC classes (CEdit, CButton, etc.) will draw themselves. This works well in my experience, and it's really not much different from what GDI does in an owner-draw control.

What if instead you want OpenGL to draw the background of the window, and you want standard Windows controls to appear on top of it? I don't think this is a great idea, but you can handle WM_PAINT and WM_ERASE for your CDialog-derived class. In WM_ERASE, call OpenGL to draw your 3D content, which will be overwritten by the standard Windows controls when WM_PAINT is called. Alternatively in WM_PAINT you could call OpenGL before calling CDialog::OnDraw, which would be similar.

Please clarify your statement "I want to add some 2s graphics overlay (like labels ,gui elements)" if you want me to write more.

久夏青 2024-11-25 23:23:25

查看您的代码,我假设 OpenGL 渲染是从计时器调用的或作为 idel 循环操作调用的。自然地,OpenGL 执行可能会包含一些清除,从而获取用它绘制的任何其他内容。

不建议将 GDI 文本绘制与 OpenGL 混合使用,但可以这样做。当然,您还需要将该代码包含到 OpenGL 绘图函数中,将所有 GDI 操作放在缓冲区交换之后。

Looking at your code I assume the OpenGL rendering is called from a timer or as idel loop action. Naturally OpenGL execution will probably contain some clearing, thus taking anything else drawn with it.

Mixing GDI text drawing with OpenGL is not recommended, but can be done. But of course you then need to include that code into the OpenGL drawing function, too, placing all GDI operations after the buffer swap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文