Рисование текста над контекстом OpenGL в MFC - PullRequest
2 голосов
/ 06 июля 2011

Я работаю над приложением MFC, содержащим контекст OpenGL. Я новичок в MFC, поэтому я его и спрашиваю. OpenGL работает нормально, но когда я хочу нарисовать текст над 3D-окном, используя этот код внутри 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 делает паузу, чем.

Ответы [ 2 ]

4 голосов
/ 08 июля 2011

То, что вы делаете, неправильно и также сложнее, чем делать все это в OpenGL. Чтобы решить проблему добавления текста в нарисованное OpenGL окно , лучше просто заставить OpenGL рисовать текст. Вы даже можете использовать тот же шрифт, который вы использовали в MFC, создав экземпляр CFont при обработке WM_CREATE, выбрав шрифт в DC и вызвав wglUseFontBitmaps, который создаст серию растровых растровых изображений, которые вы можете использовать с glCallLists. (Пока вы это делаете, вызовите GetCharABCWidths и GetTextMetrics, чтобы определить ширину и высоту каждого глифа соответственно.)

</p> <pre class="lang-cpp prettyprint-override"><code>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, чтобы поместить текст туда, куда вам нужно. Я предлагаю рассчитать точную ширину вашей строки, используя код, подобный приведенному ниже, если вы хотите, чтобы он был горизонтально центрирован. </p> <pre class="lang-cpp prettyprint-override"><code>// 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 отлично справляется с отображением текста - вы получаете бесплатную субпиксельную точность, помимо других преимуществ.

Редактировать: В ответ на ваш запрос о включении элементов графического интерфейса, я предполагаю, что вы имели в виду, что вы хотите иметь как нарисованные OpenGL окна, так и стандартные элементы управления Windows (поля редактирования, флажки, кнопки , список элементов управления и т. д.) в том же родительском окне. Я также предполагаю, что вы намерены OpenGL нарисовать только часть окна, а не фон окна.

Поскольку вы сказали, что используете MFC, я предлагаю создать диалоговое окно, добавить в него все свои стандартные элементы управления Windows, а затем добавить класс, производный от CWnd, где вы обрабатываете WM_PAINT. Используйте редактор ресурсов, чтобы переместить элемент управления туда, куда вы хотите. По сути, вы создаете пользовательский элемент управления для рисования, где OpenGL выполняет рисование. Таким образом, OpenGL нарисует это окно, и стандартные классы MFC (CEdit, CButton и т. Д.) Начнут рисовать сами. По моему опыту, это хорошо работает и на самом деле мало чем отличается от того, что GDI делает в элементе управления для рисования владельцем.

Что если вместо этого вы хотите, чтобы OpenGL рисовал фон окна, и чтобы стандартные элементы управления Windows отображались поверх него? Я не думаю, что это отличная идея, но вы можете обрабатывать WM_PAINT и WM_ERASE для своего класса, производного от CDialog. В WM_ERASE вызовите OpenGL, чтобы нарисовать ваш 3D-контент, который будет перезаписан стандартными элементами управления Windows при вызове WM_PAINT. В качестве альтернативы в WM_PAINT вы можете вызвать OpenGL перед вызовом CDialog :: OnDraw, что будет аналогично.

Пожалуйста, уточните ваше утверждение «Я хочу добавить несколько оверлеев графики 2s (например, метки, элементы графического интерфейса)», если вы хотите, чтобы я написал больше.

2 голосов
/ 06 июля 2011

Глядя на ваш код, я предполагаю, что рендеринг OpenGL вызывается из таймера или как действие цикла idel. Естественно, выполнение OpenGL, вероятно, будет содержать некоторую очистку, таким образом, беря все остальное, нарисованное с ним.

Смешивать рисование текста GDI с OpenGL не рекомендуется, но это можно сделать. Но, конечно же, вам необходимо включить этот код в функцию рисования OpenGL, поместив все операции GDI после замены буфера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...