« 自剖一下自己用的NEHE OpenGL框架(上篇)自剖一下自己用的NEHE OpenGL框架(下篇) »

自剖一下自己用的NEHE OpenGL框架(中篇)

接着上一篇日志,再接再厉~~本篇是:自剖一下自己用的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类。

  1. class CMainFrame : public CFrameWnd
  2. {
  3.     DECLARE_DYNAMIC(CMainFrame)
这里有一个DECLARE_DYNAMIC宏,把它展开,有
#define DECLARE_DYNAMIC(class_name) \
protected: \
 static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
 static const AFX_DATA CRuntimeClass class##class_name; \
 virtual CRuntimeClass* GetRuntimeClass() const; \ //
 
      第一个(保护函数)明显是为了获得基类。(第二个成员变量)中##是连接符,所以说这里定义了一个CRuntimeClass类型的静态变量classCMainFrame。第三个(虚成员函数)返回这个class##class_name类名。
 
      另外既然名中有类CRuntimeClass,那它必然与运行时识别RTTI有关。好,我先来看看什么是CRuntimeClass:“每个从CObject中派生的类都有有一个CRuntimeClass对象同它关联以完成在运行时得到类实例的信息或者是它的基类。”因此按我的理解, DECLARE_DYNAMIC的作用主要是获得当前这个类(CMainFrame)的信息,包括基类,并交给CRuntimeClass类实现对它的动态创建,管理等等(RTTI)。如果有错请各看官指出恩。
      得到这些信息就能实现吗?其实还需要其兄弟IMPLEMENT_DYNAMIC(放在实现文件中)帮忙。很快我们就能遇到了。
       CMainframe类(头文件部分):
  1. public:
  2.     CMainFrame(); //构造函数
  3. //Attributes
  4. protected:
  5.  //设备描述句柄DC(Device Context)和渲染描述句柄RC(Render Contex),
  6. //它们是OPENGL与操作系统,设备间交互所必不可少的。我将在下篇日志详细介绍
  7.     HDC m_hDC;                              
  8.     HGLRC m_hRC;
  9.                             
  10. //客户区长宽,我们平时不是可以手动调节渲染窗口的窗口大小吗?这种调节行为其实就是给程序发消息(还记得上篇日志中的PeekMessage么?)这两个参数会在OnSize()中保存调节后实际窗口的长宽,通过对应的消息响应ON_WM_SIZE()上交到消息队列,故暂停渲染来响应PeekMessage处理。
  11. //所以平时我们调节窗口大小时可以看到渲染进程是暂停了的。
  12.     UINT m_cxClient;
  13.     UINT m_cyClient;
  14.  
  15. //调色板?貌似GDI+上见过类似类型名称的,不知道在这里用来干什么。搜索代码也只见在这里定义和初始化出现,实在迷糊。
  16.     HPALETTE m_hPal;
  17.  
  18. //这个是我们屏幕大小 1024*768 起码最大化的时候要知道吧.
  19.     int VB_WIDTH;
  20.     int VB_HEIGHT;
  21. //绘图深度
  22.     int VB_DEPTH;
  23.  
  24. //DEVMODE的数据结构描述了要设定的显示器的各类属性值,刷新率啦分辨率啦
  25. //OpenGL作图过程中有需要先保存起渲染前的这些屏幕数据,渲染完后返还
  26.     DEVMODE m_DMsaved;
  27. //是否全屏幕                   
  28.     BOOL m_bFullScreen;
  29.  
  30. // Operations
  31. public:
  32.     void RenderGLScene();//渲染函数
  33.     BOOL m_bAppIsActive;//上篇日志提过,控制是否渲染
  34.     GLvoid ReSizeGLScene(GLsizei width, GLsizei height);//重置窗口大小
  35.     int InitGL(GLvoid); //初始化
  36.     GLvoid KillGLWindow(GLvoid);//关闭程序窗口
  37.     void calculateFramesPerSec ();//计算FPS,非必要
  38.  
  39. // 重载来自父类的两个函数:
  40.     virtual BOOL PreCreateWindow(CREATESTRUCT& cs); //初始化屏幕
  41.  
  42. //初始化像素设置,绘图设备(上面提到的DC,RC)等等
  43.     virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
  44. public:
  45.     virtual ~CMainFrame();//析构
  46.  
  47. //同样重载(其实是调用父类的),用于DEBUG的函数
  48. #ifdef _DEBUG       
  49.  //AssertValid提供对对象内部状态的运行时检查,可用于验证成员函数有效值
  50.     virtual void AssertValid() const;
  51.  
  52. //Dump函数将对象的成员变量的文本化表示形式写入转储上下文(CDumpContext,类似I/O流)
  53.     virtual void Dump(CDumpContext& dc) const;
  54. #endif
  55.  
  56. protected:
  57. //{     又来了,消息映射表(MESSAGE_MAP,告诉MFC你要处理什么消息,在哪里),不过这次是“真”的了。
  58. afx_msg void OnPaint();//对应消息ON_WM_PAINT()(以下类似)告诉窗口绘制自己
  59. afx_msg void OnSize(UINT nType, int cx, int cy);//告诉窗口改变大小
  60. afx_msg void OnSetFocus(CWnd *pOldWnd);//告诉窗口设立焦点
  61.  
  62. //当某一窗口即将激活时,主框架窗口将收到WM_QUERYNEWPALETTE消息,通知该窗口将要收到输入焦点,给它一次机会实现其自身的逻辑调色板; 
  63. //当系统调色板改变后,主框架窗口将收到WM_PALETTECHANGED消息,通知其它窗口系统调色板已经改变,此时每一窗口都应该实现其逻辑调色板,重画客户区。
  64.     afx_msg BOOL OnQueryNewPalette();
  65.     afx_msg void OnPaletteChanged(CWnd* pFocusWnd);//告诉窗口绘制自己
  66.  
  67. //窗口被激活的时候触发,譬如你用另一个应用的窗口掩盖渲染穿口了
  68.     afx_msg void OnActivateApp(BOOL bActive, HTASK hTask);
  69. //按键消息
  70.     afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
  71.     //}}AFX_MSG
  72.     DECLARE_MESSAGE_MAP()//(通过它程序找到以上对应的消息响应函数)
  73. };

当然了,还可以在编程过程中加入更多事件(譬如鼠标行为) vc6中在工作空间右键点击CMainframe类----ADD WINDOWS HANDLER,下面再看看实现中开头那段代码:

  1. IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
  2. //IMPLEMENT_DYNAMIC(参数为本类,本类的父类)与上面的DECLARE_DYNAMIC是两兄弟,不过它位于实现文件,打开:
  3.  
  4. //#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
  5. //    IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
  6.  
  7. //就不再继续打开了,简单说明其作用:通过运行时在串行结构中为动态CObject派生类访问类名和位置来产生必要的C++代码(RTTI)。这就用到DECLARE_DYNAMIC获得的东西了
  8. //其实一言毙之:就是在程序里搞RTTI的,MFC加了它们俩,没错的~(误)
  9.  
  10. BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //开始消息影射
  11.     //{{       //这些就是窗口消息。与上面消息响应处理函数一一对应
  12.     ON_WM_PAINT()
  13.     ON_WM_SIZE()
  14.     ON_WM_SETFOCUS()
  15.     ON_WM_QUERYNEWPALETTE()
  16.     ON_WM_PALETTECHANGED()
  17.     ON_WM_ACTIVATEAPP()
  18.     ON_WM_KEYDOWN()
  19.     //}}
  20. END_MESSAGE_MAP()//结束消息映射

现在我们先跳过实现的其他部分(放在下篇介绍),看看实现里面相应的消息处理函数:

  1. //前面带空洪afx_msg的消息处理函数基本其实也是来自CWnd的,只是没有virtual符号而已(我不知道这算重写不,还是掩盖了,以后了解多点MFC再说).
  2. void CMainFrame::OnPaint()//告诉窗口重绘自己
  3. {
  4.     CPaintDC dc(this);   //得到一个绘图用的DC
  5.     // 加自己的东西(其实我都没加过 - -)  
  6. //以下是CWnd的函数,用处是使窗口有效,并 清除消息队列中的WM_PAINT消息
  7.     ::ValidateRect ( m_hWnd, NULL );
  8. }
  9. void CMainFrame::OnSize(UINT, int cx, int cy)
  10. {   //重新调整客户区域(窗口大小)时启动,ReSizeGLScene就是调整函数(见下篇)
  11.     m_cxClient = cx;
  12.     m_cyClient = cy;
  13.     ReSizeGLScene( cx, cy );
  14. }
  15. //其实下面两个处理函数功用上面着重说过了,这里说说实现的问题
  16. BOOL CMainFrame::OnQueryNewPalette()
  17. { //判断窗口是否即将要重绘(其实根本没判断,直接TRUE并重绘了 - -)
  18.     Invalidate();
  19.     return TRUE;
  20. }
  21. void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
  22. { //注意只对主(顶)框架(top-level and overlapped windows)有效  
  23. if ((pFocusWnd != this) && (!IsChild(pFocusWnd)))
  24.         OnQueryNewPalette(); //重绘
  25. }
  26. void CMainFrame::OnSetFocus(CWnd* pOldWnd)
  27. {  //窗口即将获得焦点时,重绘
  28.     OnQueryNewPalette();
  29. }
  30. void CMainFrame::OnActivateApp(BOOL bActive, HTASK hTask)
  31. {//调用上层OnActivateApp,bActive判断遮掩情况,然后赋予本地的判断变量m_bAppIsActive,m_bAppIsActive控制是否渲染
  32.     CFrameWnd::OnActivateApp(bActive, hTask);
  33.     m_bAppIsActive = bActive;
  34. }
  35. void CMainFrame::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
  36. {//同样调用上层函数,这里用switch控制按键
  37.      CFrameWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  38.     switch ( nChar ) {
  39.     case VK_ESCAPE: 
  40.         PostMessage ( WM_CLOSE );
  41.         break;
  42.     }   
  43. }

不知不绝就那么长了,接下来还有其他实现部分,惟有多开一篇日志来剖了~~
自剖一下自己用的NEHE OpenGL框架(下篇) 

本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
      原文地址:http://www.zwqxin.cn/archives/MFC/2-nehe-frame-vc6.html

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2024 ZwqXin. All Rights Reserved. Theme edited from ipati.