在MFC中的OpenGL上下文上方绘制文本 [英] Painting Text above OpenGL context in MFC

查看:80
本文介绍了在MFC中的OpenGL上下文上方绘制文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在包含OpenGL上下文的MFC应用程序上工作.我是MFC的新手,这就是为什么我问它.OpenGL可以正常工作,但是当我想在WindowProc中使用以下代码在3D窗口上方绘制文本时:

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;

它显示在OpenGL上下文下方.我只能在调整窗口大小时看到它,因为OpenGL渲染会暂停.

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

推荐答案

您正在做的事情是错误的,而且比在OpenGL中做的还要困难.要解决将文本添加到OpenGL绘制的窗口的问题,最好只使OpenGL绘制文本.您甚至可以使用与MFC中使用的字体完全相同的字体,方法是在处理WM_CREATE时创建CFont实例,将字体选择到DC中,然后调用wglUseFontBitmaps,这将生成一系列可与glCallLists一起使用的光栅化位图. (同时,调用GetCharABCWidths和GetTextMetrics分别确定每个字形的宽度和高度.)

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

然后,当您处理WM_PAINT时,重置矩阵并使用glRasterPos2d将文本放在需要的地方.如果您希望将字符串水平居中,建议使用与以下代码相似的代码来计算字符串的确切宽度.

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

虽然设置很烦人,但您只需要执行一次,而且我认为与处理GDI相比,它没有那么令人沮丧.混合使用GDI和OpenGL确实会带来麻烦,并且OpenGL在显示文本方面做得非常好-您可以免费获得亚像素精度,还有其他好处.

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.

编辑:针对您要求包含GUI元素的要求,我假设您的意思是既要拥有OpenGL绘制的窗口,又要拥有标准Windows控件(编辑框,复选框,按钮,列表控件等).我还将假设您打算OpenGL仅绘制窗口的一部分,而不绘制窗口的背景.

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.

由于您说过使用的是MFC,因此建议您创建一个对话框窗口,将所有标准Windows控件添加到其中,然后添加一个处理WM_PAINT的CWnd派生类.使用资源编辑器将控件移至所需位置.实际上,您是在OpenGL进行绘制的地方制作了一个所有者绘制的自定义控件.因此,OpenGL将绘制该窗口,而标准的MFC类(CEdit,CButton等)将绘制它们自己.以我的经验来看,这种方法效果很好,而且与GDI在所有者绘图控件中所做的没有太大区别.

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.

相反,如果您希望OpenGL绘制窗口背景,并且希望标准Windows控件出现在窗口顶部怎么办?我认为这不是一个好主意,但是您可以为CDialog派生的类处理WM_PAINT和WM_ERASE.在WM_ERASE中,调用OpenGL绘制您的3D内容,当调用WM_PAINT时,它将被标准Windows控件覆盖.另外,在WM_PAINT中,您可以在调用CDialog :: OnDraw之前先调用OpenGL,这是类似的.

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.

如果您要我写更多的内容,请澄清您的声明我要添加一些2s图形叠加层(如标签,gui元素)".

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

这篇关于在MFC中的OpenGL上下文上方绘制文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆