C++教程:DirectX11Frame

  C++教程:DirectX11Frame

  前面几讲的内容过于难了一些,当然看不懂没关系,因为在整个框架里面他们只是作为底层应用来使用,而最终暴露的接口都相当的易于使用,那么,对于拿来主义这就足够了,因为接下来的内容都注定会是一马平川。

  回顾我们前面说过的内容:一套反射机制(对于这种非主流的GUI库来说没有反射靠硬编码来实现界面配置的话那么结果会是有些吃力不讨好),一套事件系统(新的事件机制没有推送,以前我们使用的事件响应是依赖于boost的signal,不过boost的signal后来被我废弃了,所以现在的事件响应是一套全新的方案,当然也不算是全新的了,因为大致结构是模仿C#的事件),一套完备的属性系统(微信里面推送的是当初设计这个属性的一个版本,它的缺点我们已经说过,至于第二个版本没有在微信里进行推送,第二个版本不但支持多槽函数进行绑定还支持同步和异步两种连接方式,当然最重要的还实现了对象有效性的追踪),一个基础对象MObject(该对象继承至属性和反射,所以凡是MObject的子类都可以实现动态创建对象以及除了使用新的事件机制向外部发送事件外还能够使用属性的操作方式和一些需要接收事件的槽函数进行同步)。

  好吧,简单的总结了一些我们前面说过的一些东西后下面我们继续向前,如同前面我们说过,DirectX本身并没有窗口的概念,他需要依附在特定的窗口上面才能够进行可视化的绘制,而标识这个窗口的东西就是HWND。虽然当初这个Frame使用win32来实现的,但后来被应用在Qt里面(公司使用的是Qt)进行项目开发,所以该Frame的设计就是支持跨平台的(不是指操作系统,而是指在Windows下面的开发平台),只要能够获取到HWND就能够使用这套Frame。

  为了达到上面的效果,我们有必要来设计一个基础窗口类,它提供了一些必须的接口以及一些共有的实现,这个类就是MAppWindow.

  //===============================

  #pragma once

  #include "MDx11Comm.h"

  #include "MObject.h"

  class MAppWindow : public MObject

  {

  public:

  //

  // 鼠标消息函数

  // 鼠标按键,鼠标动作,x,y,是否为全局坐标

  //

  //

  typedef std::function MouseFunType;

  typedef std::function ADD_INIT; // 附加初始化函数

  typedef std::function RECALL_INIT; // 初始化函数

  typedef std::function RECALL_DRAW; // 绘图函数

  typedef std::function RECALL_CLEAR; // 清理资源函数

  typedef std::function RECALL_RESHAPE; // 更改尺寸处理函数

  typedef std::function RECALL_WNDPROC; // 底层消息回调处理函数

  typedef std::function RECALL_IDLE; // 空闲处理函数

  typedef std::function RECALL_UPDATA; // 动画更新函数

  typedef std::function InputFunType; // 输入回掉函数

  typedef std::function KeyEventFunType; // 键盘状态回调函数

  typedef std::function KeyInputCharFunType;// 处理输入字符函数

  public:

  MAppWindow();

  virtual ~MAppWindow();

  //

  // 获取窗口句柄

  //

  virtual HWND WindHwnd(){ return nullptr; }

  //

  // 移除窗口边框

  //

  virtual void RemoveBorder(){}

  //

  // 注册函数

  //

  void RegisterFunInitD3D(RECALL_INIT initGLfun);

  void RegisterDrawScreen(RECALL_DRAW drawFun); // 注册显示函数,很重要,没他,就显示不出3D画面

  void RegisterReShape(RECALL_RESHAPE reshapeFun); // 移动窗口会被调用

  void RegisterWndProc(RECALL_WNDPROC WndProc); // 注册事件回调函数,该函数将会相应窗口消息

  void RegisterAddProcFun(RECALL_WNDPROC WndProc);

  void RegisterOnIdleFun(RECALL_IDLE idlefun); // 注册系统闲时处理函数

  void RegisterClearFun(RECALL_CLEAR clearFun); // 注册清除资源函数

  void RegisterUpdataFun(RECALL_UPDATA updatafun) // 注册更新界面函数

  void RegisterMouseEnventFun(MouseFunType fun); // 注册鼠标事件函数

  protected:

  MouseFunType mMouseEventFun{ nullptr };

  RECALL_INIT mInitD3d;

  RECALL_DRAW mDrawScreen;

  RECALL_RESHAPE mReshape;

  RECALL_CLEAR mClearFun;

  RECALL_IDLE mIdleFun;

  RECALL_UPDATA mUpdateFun;

  };

  //==========================================

  注册系列函数我们已经实现,唯一需要用户自行实现的就只有WindHwnd和RemoveBorder这两个函数,对于使用Win32或者MFC的同学来说获取这个HWND实在是太简单了,对于使用Qt的同学来说这两个函数的实现依然很简单,对了,为什么我们要实现RemoveBorder呢?看看我们文章开头的图片,整个窗口全都是使用DirectX绘制出来的,包括标题栏和边框,这样我们就可以实现我们想要的任意风格了,否则就算你把Client区域做得多华丽但是一看窗口边框和标题栏就会不自觉的认为这不是一个风格的。

  由于我们现在是在win32下,所以这里我们可以使用MAppWindow来作为我们真正的窗口基类。真正的win32窗口类MWindow:

  //==================================

  #pragma once

  #include "MDx11String.h"

  #include

  #include "MNoCopy.h"

  #include

  #include "MAppWindow.h"

  using namespace MDx11;

  class MWindow;

  class MEventFun;

  //

  // 消息回调函数

  //

  HRESULT __stdcall WndProc(HWND, UINT, WPARAM, LPARAM);

  class MWindow : public MAppWindow, public MNoCopy

  {

  DECLARE_CLASS(MWindow)

  public:

  explicit MWindow(MWindow* parent = nullptr);

  virtual ~MWindow();

  public:

  unsigned Width() const{ return mWidth; }

  unsigned Height() const{ return mHeight; }

  void SetTitle(const MDx11String& Title);

  //

  // 重写继承而来的两个虚函数

  //

  void RemoveBorder();

  virtual HWND WindHwnd(){ return mHwnd; }

  //

  // 开启消息循环

  //

  int Run() const;

  //

  // 显示窗口

  //

  void Show();

  virtual void SetExStyle(DWORD dwExStyle);

  virtual void SetStyle(DWORD dwStyle);

  virtual void SetIsFullScreen(bool fullscreen);

  virtual void Update(){ InvalidateRect(*this, nullptr, false); }

  virtual operator HWND() const{ return mHwnd; }

  virtual LRESULT __stdcall MemWndProc(HWND, UINT, WPARAM, LPARAM);

  bool IsFullScreen(){ return bIsFullscreen; }

  bool IsActive(){ return bIsActive; }

  void CalculateFrameStats();

  //

  // 事件

  //

  public:

  friend LRESULT __stdcall WndProc(HWND, UINT, WPARAM, LPARAM); // 窗口回调函数

  //

  // 定义几个事件属性

  //

  static MDx11String MouseClickedEvent;

  static MDx11String MouseMoveEvent;

  static MDx11String MouseEnterEvent;

  static MDx11String MouseLeverEvent;

  static MDx11String ContentChangedEvent;

  static MDx11String SelectedChangedEvent;

  void RegisterEventFun(const MDx11String& EventDesc, MEventFun* SlotFun);

  protected:

  virtual bool InitWindow();

  bool RegisterWndClass(); // 注册窗口类

  bool GenWindow(); // 创建窗口

  virtual int Msgloop() const; // 消息循环

  virtual void MouseEnterWindow();

  virtual void MouseLeavesWindow();

  //

  // 窗口消息经回调函数转而进相关的成员函数,方便操作成员数据

  //

  LRESULT __stdcall BaseWndProc(HWND, UINT, WPARAM, LPARAM);

  RECALL_WNDPROC mAddFun; // 消息回调附加函数

  private:

  MDx11String mTitle;

  HWND mHwnd;

  unsigned mWidth;

  unsigned mHeight;

  DWORD mDwExStyle; // 窗口风格

  DWORD mDwStyle; // 窗口风格

  bool* bIsKeys; //监控键状态

  bool bIsInited;

  volatile bool bIsDone;

  bool bIsFullscreen;

  bool bIsActive;

  bool bIsAppPaused;

  bool bIsMinimized;

  bool bIsMaximized;

  bool bIsResizing;

  WNDCLASS mWndclass;

  MDx11String mWndClassName;

  //

  // 一个计时器,凡是以I开头的东西都是从com组件中导出来的

  //

  ITimer* pTimer{ nullptr };

  //

  // 记录鼠标是否进入窗口

  //

  bool bIsEnter{ false };

  //

  // 保存消息响应函数

  //

  std::unordered_map mEventFunMap;

  };

  //=====================================

  这个类没啥多说的,唯一的技巧性操作是将回调函数过程转发指成员函数身上,要解决这个问题很简单,正cpp文件中创建一个全局窗口对象,在类的构造函数中将this直接赋给该全局指针,然后在回掉函数中根据HWND来检查出对应的窗口,从而将事件转发指相应的成员函数身上(其实如果只是简单的实现一个窗口大不必要这么麻烦,之所以这么干是考虑到以后该窗口类的扩展性)。

  现在只需要下面的代码窗口就出来了:

  //=====================================

  MWindow w; //创建一个对象

  w.SetTitle("Hello World"); // 设置窗口标题

  w.Show(); // 显示窗口

  w.Run(); // 开启消息循环

  //=======================================

  ok,今天的就到这里吧,具体实现因为比较简单就比贴出来了,只需要知道这些类有这些接口以及相关成员就足够了,接下来我们开始真正的进入DirectX,下一讲我们来说说该类的渲染核心——DirectX11的初始化。

时间: 2024-10-17 09:13:19

C++教程:DirectX11Frame的相关文章

C++教程 DirectX11Frame属性

原本打算先和大家说怎么在C++里面操作的lua的,毕竟这个Frame的主要功能便是靠lua实现的,但是想想可能有些朋友对lua不甚了解所以在说怎么和lua通信之前那么大家可以先了解lua是个什么鬼,哦,对了,我用的是5.3版本的,虽然这个版本没什么第三方库,但是现在很多常用的东西我自己已经添加好,所以顺手了也就无所谓了. 那么今天我们从什么地方入手呢?嗯,好吧,就从"属性"这玩意而已开始吧,属性这个东西可能不是大家想想的属性,我取名字这事已经被同事吐槽了不下10次了,总觉得我名字莫名其

Windows Git+TortoiseGit简易使用教程

转载自 http://blog.csdn.net/jarelzhou/article/details/8256139 官方教程:http://tortoisegit.org/docs/tortoisegit/(英文版) 为什么选择Git 效率 很多人有一种习惯吧,什么软件都要最新的,最好的.其实吧,软件就是工具,生产力工具,为的是提高我们的生产力.如果现有的工具已经可以满足生产力要求了,就没有必要换了.生产效率高低应当是选择工具的第一位. 历史 开源世界的版本控制系统,经历了这么几代: 第一代,

微信公众号中添加外部链接地址的图文教程

2017-9-18,长沙,有点闷,有点热. 本教程教大家如何在微信公众号中,添加外部的链接,网络有很多教程,但由于表述不太清楚,出个教程吧.最终实现在微信后台管理平台"原文链接"处插入外部链接,用户点击发布好的图文文章底部左下角的"阅读原文",就可以跳转到您添加的外部链接页面中去. 第1步. 使用微信公众管理帐号登陆微信管理后台 > 素材管理 > 图文消息 >  新建图文消息或者编辑文章都可以,如下图所示: 第2步. 之后,将页面向下拉,看到底部&

win2003从组策略关闭端口(445/135/137/138/139/3389等)教程

一些恶劣的病毒会从某些端口入侵计算机,因此关闭某些用不到的而又具有高风险的端口就显得很有必要,是服务器管理员要做的基本的安全防范.本文将介绍win2003系统在组策略关闭某一个端口的教程,文章以关闭445端口为例. 首先要说明的是,此方法不仅仅适用于win2003,也适用于win7,且操作方法完全相同,所以win7用户也可以按照本文教程操作. 1.打开组策略编辑器 按组合键WIN+R打开运行窗口,然后输入gpedit.msc,按回车键,即可进入组策略编辑器. 2.创建 IP 安全策略 展开选项"

微信小程序实例教程(一)

序言 开始开发应用号之前,先看看官方公布的「小程序」教程吧!(以下内容来自微信官方公布的「小程序」开发指南) 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果.这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志. 1. 获取微信小程序的 AppID 首先,我们需要拥有一个帐号,如果你能看到该文档,我们应当已经邀请并为你创建好一个帐号.注意不可直接使用服务号或订阅号的 AppID. 利用提供的帐号,登录https

SQL Server2005安装材料及教程编制

首发:https://www.douban.com/note/579628972/ 系统为 win10SQL Server 安装材料下载 链接:http://p删除an.baidu.com/s/1中文miQ1ZQg 密码:pszf挂不补,可到bdsola.com搜索下载 1.安装教程(幸运E版):http://jingyan.baidu.com/article/acf728fd1a30d0f8e510a380.html 注意:当你的电脑是多核的时候可能会出现安装错误   2.此时推荐教程:htt

mac数据恢复软件EasyRecovery使用教程

mac数据恢复软件EasyRecovery使用教程 文件丢失是非常让人郁闷的!因为没有备份所以很多重要的东西都没有办法找回!小编为大家准备了EasyRecovery,这款数据恢复软件费非常好用,可以将您丢失的数据找回.小编还特意为大家准备了数据恢复软件EasyRecovery使用教程,下面就和小编一起来看看具体如何使用吧! <ignore_js_op> 数据恢复软件EasyRecovery使用教程介绍:第一步:我们需要在Mac中安装好EasyRecovery for Mac,然后启动EasyR

mac苹果电脑上Mathtype软件的安装教程

对于数学学习来将,Mathtype是一款非常不错的工具,在这里您可以方便快捷的计算出公式的结果,只需要将方程式填写进去就能出来结果.小编为大家准备了Mathtype安装教程,安装的过程是非常简单的,安装好了之后会让您的工作变得更加轻松,还能提升工作的效率哦! Mathtype安装教程介绍:第一步:打开下载的Mathtype文件 第二步:点击左边的安装文件,会得到提示,下图所示: 第三步:选择好,然后会在弹出提示窗口,点击继续,如下图所示: 第四步:因为暂时只有英文版的,所以选择英文版,点击继续安

JavaWeb之Java Servlet完全教程(转)

Servlet 是一些遵从Java Servlet API的Java类,这些Java类可以响应请求.尽管Servlet可以响应任意类型的请求,但是它们使用最广泛的是响应web方面的请求. Servlet必须部署在Java servlet容器才能使用.虽然很多开发者都使用Java Server Pages(JSP)和Java Server Faces(JSF)等Servlet框架,但是这些技术都要在幕后通过Servlet容器把页面编译为Java Servlet.也就是说,了解Java Servle