接着上一篇日志,再接再厉~~本篇是:自剖一下自己用的NEHE OpenGL框架(中篇), 更好地了解NEHE OpenGL框架,同时学习一下MFC咯,自我修炼。(友情提醒:如果你只为OPENGL初学者之初学者,而不懂MFC也不想懂MFC,建议碰到类似的文章先别看[包括本文],更有益的是先关注渲染部分^^)。——ZwqXin.com
上篇日志请看:自剖一下自己用的NEHE OpenGL框架(上篇)
此日志自我学习用。
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/MFC/2-nehe-frame-vc6.html
还记得向导生成了一个 CMainframe类和一个C***App类。上篇日志讲了C***App类,现在来看看重要的CMainframe类。
- class CMainFrame : public CFrameWnd
- {
- DECLARE_DYNAMIC(CMainFrame)
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \ //
CMainframe类(头文件部分):
- public:
- CMainFrame(); //构造函数
- //Attributes
- protected:
- //设备描述句柄DC(Device Context)和渲染描述句柄RC(Render Contex),
- //它们是OPENGL与操作系统,设备间交互所必不可少的。我将在下篇日志详细介绍
- HDC m_hDC;
- HGLRC m_hRC;
- //客户区长宽,我们平时不是可以手动调节渲染窗口的窗口大小吗?这种调节行为其实就是给程序发消息(还记得上篇日志中的PeekMessage么?)这两个参数会在OnSize()中保存调节后实际窗口的长宽,通过对应的消息响应ON_WM_SIZE()上交到消息队列,故暂停渲染来响应PeekMessage处理。
- //所以平时我们调节窗口大小时可以看到渲染进程是暂停了的。
- UINT m_cxClient;
- UINT m_cyClient;
- //调色板?貌似GDI+上见过类似类型名称的,不知道在这里用来干什么。搜索代码也只见在这里定义和初始化出现,实在迷糊。
- HPALETTE m_hPal;
- //这个是我们屏幕大小 1024*768 起码最大化的时候要知道吧.
- int VB_WIDTH;
- int VB_HEIGHT;
- //绘图深度
- int VB_DEPTH;
- //DEVMODE的数据结构描述了要设定的显示器的各类属性值,刷新率啦分辨率啦
- //OpenGL作图过程中有需要先保存起渲染前的这些屏幕数据,渲染完后返还
- DEVMODE m_DMsaved;
- //是否全屏幕
- BOOL m_bFullScreen;
- // Operations
- public:
- void RenderGLScene();//渲染函数
- BOOL m_bAppIsActive;//上篇日志提过,控制是否渲染
- GLvoid ReSizeGLScene(GLsizei width, GLsizei height);//重置窗口大小
- int InitGL(GLvoid); //初始化
- GLvoid KillGLWindow(GLvoid);//关闭程序窗口
- void calculateFramesPerSec ();//计算FPS,非必要
- // 重载来自父类的两个函数:
- virtual BOOL PreCreateWindow(CREATESTRUCT& cs); //初始化屏幕
- //初始化像素设置,绘图设备(上面提到的DC,RC)等等
- virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
- public:
- virtual ~CMainFrame();//析构
- //同样重载(其实是调用父类的),用于DEBUG的函数
- #ifdef _DEBUG
- //AssertValid提供对对象内部状态的运行时检查,可用于验证成员函数有效值
- virtual void AssertValid() const;
- //Dump函数将对象的成员变量的文本化表示形式写入转储上下文(CDumpContext,类似I/O流)
- virtual void Dump(CDumpContext& dc) const;
- #endif
- protected:
- //{ 又来了,消息映射表(MESSAGE_MAP,告诉MFC你要处理什么消息,在哪里),不过这次是“真”的了。
- afx_msg void OnPaint();//对应消息ON_WM_PAINT()(以下类似)告诉窗口绘制自己
- afx_msg void OnSize(UINT nType, int cx, int cy);//告诉窗口改变大小
- afx_msg void OnSetFocus(CWnd *pOldWnd);//告诉窗口设立焦点
- //当某一窗口即将激活时,主框架窗口将收到WM_QUERYNEWPALETTE消息,通知该窗口将要收到输入焦点,给它一次机会实现其自身的逻辑调色板;
- //当系统调色板改变后,主框架窗口将收到WM_PALETTECHANGED消息,通知其它窗口系统调色板已经改变,此时每一窗口都应该实现其逻辑调色板,重画客户区。
- afx_msg BOOL OnQueryNewPalette();
- afx_msg void OnPaletteChanged(CWnd* pFocusWnd);//告诉窗口绘制自己
- //窗口被激活的时候触发,譬如你用另一个应用的窗口掩盖渲染穿口了
- afx_msg void OnActivateApp(BOOL bActive, HTASK hTask);
- //按键消息
- afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()//(通过它程序找到以上对应的消息响应函数)
- };
当然了,还可以在编程过程中加入更多事件(譬如鼠标行为) vc6中在工作空间右键点击CMainframe类----ADD WINDOWS HANDLER,下面再看看实现中开头那段代码:
- IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
- //IMPLEMENT_DYNAMIC(参数为本类,本类的父类)与上面的DECLARE_DYNAMIC是两兄弟,不过它位于实现文件,打开:
- //#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
- // IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
- //就不再继续打开了,简单说明其作用:通过运行时在串行结构中为动态CObject派生类访问类名和位置来产生必要的C++代码(RTTI)。这就用到DECLARE_DYNAMIC获得的东西了
- //其实一言毙之:就是在程序里搞RTTI的,MFC加了它们俩,没错的~(误)
- BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //开始消息影射
- //{{ //这些就是窗口消息。与上面消息响应处理函数一一对应
- ON_WM_PAINT()
- ON_WM_SIZE()
- ON_WM_SETFOCUS()
- ON_WM_QUERYNEWPALETTE()
- ON_WM_PALETTECHANGED()
- ON_WM_ACTIVATEAPP()
- ON_WM_KEYDOWN()
- //}}
- END_MESSAGE_MAP()//结束消息映射
现在我们先跳过实现的其他部分(放在下篇介绍),看看实现里面相应的消息处理函数:
- //前面带空洪afx_msg的消息处理函数基本其实也是来自CWnd的,只是没有virtual符号而已(我不知道这算重写不,还是掩盖了,以后了解多点MFC再说).
- void CMainFrame::OnPaint()//告诉窗口重绘自己
- {
- CPaintDC dc(this); //得到一个绘图用的DC
- // 加自己的东西(其实我都没加过 - -)
- //以下是CWnd的函数,用处是使窗口有效,并 清除消息队列中的WM_PAINT消息
- ::ValidateRect ( m_hWnd, NULL );
- }
- void CMainFrame::OnSize(UINT, int cx, int cy)
- { //重新调整客户区域(窗口大小)时启动,ReSizeGLScene就是调整函数(见下篇)
- m_cxClient = cx;
- m_cyClient = cy;
- ReSizeGLScene( cx, cy );
- }
- //其实下面两个处理函数功用上面着重说过了,这里说说实现的问题
- BOOL CMainFrame::OnQueryNewPalette()
- { //判断窗口是否即将要重绘(其实根本没判断,直接TRUE并重绘了 - -)
- Invalidate();
- return TRUE;
- }
- void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
- { //注意只对主(顶)框架(top-level and overlapped windows)有效
- if ((pFocusWnd != this) && (!IsChild(pFocusWnd)))
- OnQueryNewPalette(); //重绘
- }
- void CMainFrame::OnSetFocus(CWnd* pOldWnd)
- { //窗口即将获得焦点时,重绘
- OnQueryNewPalette();
- }
- void CMainFrame::OnActivateApp(BOOL bActive, HTASK hTask)
- {//调用上层OnActivateApp,bActive判断遮掩情况,然后赋予本地的判断变量m_bAppIsActive,m_bAppIsActive控制是否渲染
- CFrameWnd::OnActivateApp(bActive, hTask);
- m_bAppIsActive = bActive;
- }
- void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
- {//同样调用上层函数,这里用switch控制按键
- CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- switch ( nChar ) {
- case VK_ESCAPE:
- PostMessage ( WM_CLOSE );
- break;
- }
- }
不知不绝就那么长了,接下来还有其他实现部分,惟有多开一篇日志来剖了~~
自剖一下自己用的NEHE OpenGL框架(下篇)
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/MFC/2-nehe-frame-vc6.html