通过前面3章,我们得到了一个只需要使用微软opengl32.lib和glew32.lib的用于开发OpenGL程序的基本框架。这个框架是基于win32 api的,这样的程序框架好处是它最为简单,只使用尽可能少的第三方库和尽可能少的封装,这样才容易搞明白真正的底层原理。
但一旦开始编写实际有用的程序,我们总是会使用到各种各样的第三方库,对OpenGL来说,需要处理的最重要关系时与第三方界面库的关系。即如果我们使用MFC或者wxWidgets之类的界面库进行开发时,如何让OpenGL在这些界面库的窗口里绘图。
其实如果前3章的代码仔细体会了,就明白这个问题很简单。对OpenGL来说,只要能得到HGLRC句柄,HGLRC句柄与哪个窗口绑定,OpenGL就在哪个窗口上绘图。
所有windows平台上的第三方界面库,都最终用到了windows平台的窗体,有窗体就可以得到HWND,有HWND就可以得到HDC,有HDC就可以创建OpenGL环境,创建了环境就可以得到HGLRC,就可以绑定到HDC,OpenGL就可以在那个窗口上绘图。
本章仅以wxWidgets为例验证该思路的可行性。
4.1 wxWidgets集成OpenGL
虽然wxWidgets可以通过wxUSE_GLCANVAS=1使得编译出来的wxWidgets库支持OpenGL,但知道怎么样自己做到这点可以更灵活。
4.1.1 创建最简单的wxWidgets程序
创建一个App模块,一个Frame模块,两个模块各一个.h文件和一个.cpp文件。wxWidgets版本用的是2.9.4,其它版本原理都是一样的。链接库除了wxWidgets库外,还需要opengl32.lib和glew32.lib。自行添加。
4.2各文件及其内容
4.2.1 aboutApp.h
#ifndef ABOUT_APP_H
#define ABOUT_APP_H
#include <wx/wx.h>
class aboutApp:public wxApp
{
public:
virtual bool OnInit();
};
#endif
4.2.2 aboutApp.cpp
注意该文件中的OnInit函数中初始化OpenGL环境的内容。
#include "aboutApp.h"
#include "aboutFrame.h"
#include "wx/image.h"
#include <Windows.h>
#include <gl/glew.h>
#include <gl/wglew.h>
bool aboutApp::OnInit()
{
wxInitAllImageHandlers();
HWND hWnd;
HGLRC hRC;
HDC hDC;
wxFrame * nullFrame = new wxFrame(NULL,wxID_ANY,wxT("null"));
hWnd = nullFrame->GetHWND();
hDC = GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
SetPixelFormat( hDC, 1,&pfd);
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
//一旦wgl被初始化,可以撤消相关环境
//之后可以利用wgl函数,调用最新版的OpenGL建立真正使用的环境
GLenum ret = glewInit();
if (GLEW_OK != ret)
{
//MessageBox(NULL,(LPCSTR)glewGetErrorString(ret),TEXT("glew初始化"),MB_OK);
MessageBox(NULL,TEXT("OnInit()glewInit错误"),TEXT("glew初始化"),MB_OK);
}
//释放OpenGL环境,wgl函数已经在调用glewInit()时完成了初始化
//释放环境后仍然可以使用
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
hWnd = 0;
nullFrame->Destroy();
aboutFrame * paf = new aboutFrame(_("about"));
hWnd = paf->GetHWND();
hDC = GetDC(hWnd);
int nPixCount = 0;
//利用OpenGL查询函数查找最符合要求的OpenGL环境特性
//需要#include <gl/wglew.h>
int pixAttribs[] = { WGL_SUPPORT_OPENGL_ARB, GL_TRUE, //要求支持OpenGL
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, //可以绘制到某个窗口
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, //必须完全支持硬件加速
WGL_RED_BITS_ARB, 8, //红色为8位精度
WGL_GREEN_BITS_ARB, 8, //绿色为8位精度
WGL_BLUE_BITS_ARB, 8, //蓝色为8位精度
WGL_DEPTH_BITS_ARB, 16, //深度为16位精度
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, //使用RGBA类型的像素
0}; //必须以0结尾
int nPixelFormat = -1;
//查询系统中是否存在满足要求的环境像素格式
wglChoosePixelFormatARB(hDC, &pixAttribs[0], NULL, 1, &nPixelFormat, (UINT*)&nPixCount);
if(nPixelFormat == -1)
{
//不存在满足要求的环境,则释放数据,结束程序
ReleaseDC(hWnd, hDC);
DestroyWindow(hWnd);
MessageBox(NULL,TEXT("OpenGL不支持查询的格式"),TEXT("错误"),MB_OK);
return 1;
}
else
{
//找到满足要求的格式,则设置其为当前像素格式,并创建OpenGL环境
SetPixelFormat( hDC, nPixelFormat, &pfd );
//指定OpenGL版本为3.10
GLint attribs[] = {WGL_CONTEXT_MAJOR_VERSION_ARB, 3,WGL_CONTEXT_MINOR_VERSION_ARB, 1, 0 };
hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
if (hRC == NULL)
{
MessageBox(NULL,TEXT("无法创建OpenGL环境"),TEXT("错误"),MB_OK);
return false;
}
//成功则绑定OpenGL渲染环境(hRC)至窗口设备环境(hDC)
wglMakeCurrent( hDC, hRC );
}
paf->Show(true);
return true;
}
IMPLEMENT_APP(aboutApp);
DECLARE_APP(aboutApp);
4.2.3 aboutFrame.h
#ifndef ABOUT_FRAME_H
#define ABOUT_FRAME_H
#include <wx/wx.h>
class aboutFrame: public wxFrame
{
public:
aboutFrame(const wxString & title);
void OnAbout(wxCommandEvent & event);
void OnExit(wxCommandEvent & event);
void OnPaint(wxPaintEvent& event);
private:
DECLARE_EVENT_TABLE()
};
#endif
4.2.4 aboutFrame.cpp
在OnPaint函数中用旧风格编写了一段显示三角形的代码。
#include "aboutFrame.h"
#include <wx/wxhtml.h>
#include <GL/glew.h>
aboutFrame::aboutFrame(const wxString & title)
:wxFrame(NULL,wxID_ANY,title)
{
//SetIcon(wxICON(sample));
wxMenuBar * menubar = new wxMenuBar();
wxMenu * menu = new wxMenu();
menu->Append(wxID_ABOUT,wxT("关于"));
menu->Append(wxID_EXIT,wxT("退出"));
menubar->Append(menu,wxT("文件"));
SetMenuBar(menubar);
}
void aboutFrame::OnAbout(wxCommandEvent & event)
{
wxBoxSizer *topsizer;
wxHtmlWindow *html;
wxDialog dlg(this, wxID_ANY, wxString(_("About")));
topsizer = new wxBoxSizer(wxVERTICAL);
html = new wxHtmlWindow(&dlg, wxID_ANY, wxDefaultPosition, wxSize(380, 160), wxHW_SCROLLBAR_NEVER);
html -> SetBorders(0);
html -> LoadPage(wxT("data/about.htm"));
html -> SetSize(html -> GetInternalRepresentation() -> GetWidth(),
html -> GetInternalRepresentation() -> GetHeight());
topsizer -> Add(html, 1, wxALL, 10);
wxButton *bu1 = new wxButton(&dlg, wxID_OK, _("OK"));
bu1 -> SetDefault();
topsizer -> Add(bu1, 0, wxALL | wxALIGN_RIGHT, 15);
dlg.SetSizer(topsizer);
topsizer -> Fit(&dlg);
dlg.ShowModal();
}
void aboutFrame::OnExit(wxCommandEvent & event)
{
Close(true);
}
void aboutFrame::OnPaint(wxPaintEvent& event)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
glBegin(GL_TRIANGLES);
glVertex2f(-1.0,0.0);
glVertex2f(1.0,0.0);
glVertex2f(0.0,1.0);
glVertex2f(-0.7,0.5);
glVertex2f(-0.9,-0.1);
glEnd();
glBegin(GL_TRIANGLES);
glVertex2f(0.5,0.8);
glEnd();
glFlush();
}
BEGIN_EVENT_TABLE(aboutFrame,wxFrame)
EVT_MENU(wxID_ABOUT, aboutFrame::OnAbout)
EVT_MENU(wxID_EXIT, aboutFrame::OnExit)
EVT_PAINT(aboutFrame::OnPaint)
END_EVENT_TABLE()
4.3 运行结果
图4-1集成OpenGL的wxFrame