没什么和大家说的了,ok,现在我们来聊聊怎么搭建一个自己的3D框架,当然,一个框架可能没什么,网上有不少,但是大多都是win32的框架,而且C++的win32框架好像不多,所以我们现在来聊一聊怎么用C++来搭建一个win32的3D框架,当然如果我们再用心一点,他不只是个3D框架,他可以拿来做很多事,好吧,说了这么多,我们直接来切入主题。
通常在win32编程里,我们可能不会在意鼠标和键盘事件的问题,可能我说得不是太清楚,但是凡事接触过win32编程的人都会明白我说的是什么,因为关于消息循环的问题都在回调里得到处理,那么如果我们打算用C++来搭建这个框架,那么我们要做的第一件事是将鼠标键盘抽象出来,怎么抽象出来呢?在决定抽象设备之前我们得考虑一个问题——数据怎么办,因为如果我们把设备(鼠标键盘)抽象出来,那也就意味数据也成了问题,ok,我们再把数据抽象出来,现在我们来盘点一下我们可能会用到的头文件。
//============================
//MFrameH.h
#pragma once
/**************************
*
*
公用头文件
*
***************************/
#include <Windows.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <GL/GLU.h>
#include <GL/glut.h>
#include <string>
#include <random>
#include <time.h>
#include <math.h>
#include <memory>
#include <map>
#include <stdarg.h>
#include <
functional>
#include <vector>
#include <deque>
#include <
fstream>
#include <algorithm>
#include <FTGL/ftgl.h>
#include <FTGL/FTGLPixmapFont.h>
#pragma comment(lib,"
freetype.lib"
)
#pragma comment(lib,"
FTGL.lib"
)
#pragma comment(lib,"
glew32.lib"
)
namespace Mengjin{
const double PI = 3.1415926;
typedef std::function<void(void)> ADD_INIT;
typedef std::function<void(void)> RECALL_DRAW;
typedef std::function<void(int, int)> RECALL_RESHAPE;
typedef std::function<LRESULT(HWND, UINT, WPARAM, LPARAM)> RECALL_WNDPROC;
typedef std::function<void()>
RECALL_IDLE;
}
//===================================
上面是一个公用头文件,前面四个是我们在windows下面编写opengl必备的几个头文件,接下来的几个我想大家一定很熟悉了,这些东西因为都是我们说过的标准库,ftgl.h,FTGLPixmapFont.h这两个库可以不用在意,当然如果我们不打算在屏幕上写字的话,接下来的几个typedef是这个框架的核心,ADD_INIT用来作为附加初始化使用,为什么会有一个附加初始化呢?因为为了免去使用者的负担,所以我在框架中将大部分经常会用到的东西给封装进去了。所以如果使用者有特殊要求而需要额外的东西外,而又不想重写初始化函数,这时这就派上了用场,我们只需要将额外的附加初始化信息注册进去,就会达到我们想要的结果,RECALL_DRAW这个是相当重要的类型了,我们知道不管我们要在屏幕上显示什么东西都要我们去画是吧,画好后就交给程序处理最终才会出现,而这个就是帮我们完成这个功能的,要不就算我们重写DrawGLScreen也不会得到执行,RECALL_RESHAPE这个和上面的RECALL_DRAW一样重要,当我们改变窗口大小时,就会重画窗口,这个回调就是执行这个功能的,RECALL_WNDPROC消息回调函数,他就是我们实现我们所要抽象的一个重要类型,RECALL_IDLE可以用于注册idle函数,也就是说在空闲时间执行的函数,ok,这个公用头文件暂且就这么多吧,经这一解释,我们是不是该明白这个头文件里面的东西有多重要了吧。
解释完上面的东西,我们现在来看看第一个类,如其名,这是一个数据中心,如果我们有什么数据都会从这个类派生出自己的类,将自己的数据添加进去,这里大家可能有些不好理解,没关系,等到我们以后实战的时候大家就明白了。
//========================
//MDataBase.h
/**************************
*
*
数据中心
*
***************************/
#pragma once
#include "
MFrameH.h"
namespace Mengjin{
class MDataBase
{
public:
MDataBase():b_IsModify(false){ }
virtual ~MDataBase();
virtual
void updata() = 0;
void IsModify(bool modify){b_IsModify = modify;
}
bool IsModify(){
return b_IsModify;
}
private:
bool
b_IsModify;
};
}
//====================================
从上面我们看出,这里有一个函数必须得重写——updata(),其实原本打算让框架来调用这个函数的,但是经过一番细想后还是让用户自己来调用它吧。
有了数据这个数据类,我们就可以完成我们的鼠标和键盘的抽象了:
//=======================================
//MKeyEvent.h
/**************************
*
*
键盘事件
*
***************************/
#pragma once
#include "
MFrameH.h"
#include "
MDataBase.h"
namespace Mengjin{
class MWindowBase;
class MKeyEvent
{
friend class MWindowBase;
public:
MKeyEvent(void);
virtual ~MKeyEvent(void);
virtual
void run() = 0;
bool Keydown(unsigned char index){
return b_IsKey[index];
} //返回真,表示键盘按下,返回FALSE表示键盘松开
bool WindowIsActive()
{
return b_IsActive;
}
void bindData(MDataBase* data)
{ if(data) m_Data = data;
}
protected:
virtual
void processEvent(unsigned char index,bool status);
virtual
void WindowIsActive(bool active){ b_IsActive = active;
}
private:
unsigned char m_index;
bool
b_IsKey[256];
//监控键盘
bool
b_IsActive;
// 窗口状态
protected:
MDataBase*
m_Data;
// 数据中心
};
}
//==============================
这是键盘操作的一个基类,大家也看到了我们前置声明了一个MWindowBase的类,并且让他成为MKeyEvent的友元类,大家可能想起些什么来了吧…………..
//=============================
//MMouseEvent.h
/**************************
*
*
鼠标事件
*
***************************/
#pragma once
#include "
MFrameH.h"
#include "
MDataBase.h"
namespace Mengjin{
class MWindowBase;
enum MouseButton{
LButton = 0, //鼠标左键
MButton,
// 鼠标中键
RButton,
// 鼠标右键
NoButton
// 没动作
};
enum MouseAction{
Down = 0,
Move,
Up,
DoubleClick,
Hover
};
struct Point2D{
float x;
float y;
Point2D(){
x = 0.0;
y =0.0;
}
};
class MMouseEvent
{
friend class MWindowBase;
public:
MMouseEvent(void);
virtual ~MMouseEvent(void);
virtual
void run(){ }
Point2D pos(){
return m_point;
}
MouseButton button(){
return m_button;
}
MouseAction status()
{
return m_status;
}
void bindData(MDataBase* data)
{ if(data) m_Data = data;
}
protected:
virtual
void processEvent(MouseButton button,MouseAction action,float x,float y);
private:
Point2D
m_point;
MouseButton m_button;
MouseAction m_action;
protected:
MDataBase* m_Data;
//数据中心
};
}
//=================================
到这里,大家看到了无论是键盘还是鼠标事件中我们都保存了一个数据指针,这就是互动,但是大家可能还不明白这鼠标和键盘是怎么和我们的鼠标和键盘连接起来的,ok,今天先到这里,这事我们接下来再说吧。
封面就是用这个框架移植出来的一个小游戏,说来遗憾,我自己把他移植过来,自己却玩不通关……….
===========================
回复D&
d直接查看目录,回复相应数字查看相应章节。
原文始发于微信公众号(
C/C++的编程教室
):第九十五讲 MFrame3D框架(1)
|