2011-07-06 70 views
2

我在一個包含OpenGL上下文的MFC應用程序上工作。我是MFC的新手,這就是爲什麼我問它.OpenGL工作正常,但是當我想在3D窗口上方使用此代碼內的WindowProc:調整窗口的大小,只有當作爲OpenGL渲染停頓比在MFC上面繪製OpenGL上下文的文本

 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 context.I下方可以看到它。

+0

哪裏是opengl渲染代碼?應該在WM_PAINT,但我不能在你的代碼摘錄中看到它... –

+0

@Felice Pollano:我想它是從空閒循環中調用的。 – datenwolf

回答

4

你在做什麼是錯誤的,並且比在OpenGL中做這些都難。爲了解決向OpenGL繪製的窗口添加文本的問題,最好讓OpenGL繪製文本。當你處理WM_CREATE,在DC中選擇字體並調用wglUseFontBitmaps時,甚至可以使用與MFC中使用的字體完全相同的字體,這將創建一系列可與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控件添加到它,然後添加一個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元素)」如果你想我寫更多。

+0

Hi @ user244795雖然我同意你的答案解決了這個問題,因爲我已經在我的原始目標之前嘗試過了,它能夠在OpenGL上繪製Windows內容。在這裏我只是嘗試了文本示例。但是如果我想添加一些2s圖形覆蓋(如標籤,gui元素),我是否也應該在OpenGL中完成所有這些工作?對於這些基本問題抱歉,但我試圖讓我的NOOB解決所有這些問題。 –

2

查看你的代碼我假設OpenGL渲染是從計時器或作爲idel循環動作調用的。自然OpenGL執行可能會包含一些清除,從而採取任何其他繪製。

不推薦使用OpenGL混合GDI文本繪圖,但可以完成。但是,當然,您還需要將該代碼包含到OpenGL繪圖函數中,將所有GDI操作放在緩衝區交換後。

+0

不僅僅是緩衝區交換,還需要'glFlush'或'glFinish'來同步。否則,GPU可能仍然在處理命令並在未來某個點執行交換,仍然覆蓋GUI輸出。 –

+0

wglSwapBuffers隱含glFinish();想想看,如果OpenGL已經完成渲染,緩衝區交換纔有意義。 – datenwolf

+0

然後,混合的OpenGL/GDI方案需要'glFlush'。 'wglSwapBuffers'與所有其他的OpenGL命令在同一個流水線中,它在緩衝區交換髮生之前返回,在wglSwapBuffers之後發出的GDI命令仍然可以在緩衝區交換之前執行。 –