根据我对msvc系列和mingw编译器的了解
具体差异如下:
1.在编译源文件过程中,2者对涉及的相关头文件有所不同
比如:
#ifdef G_MSVC
#include <GEngine/Template/Vector.hpp>
#endif
这是盖莫引擎中math.hpp包含的头文件
其中有一个函数:
////////////////////////////////////////////////////////
/// 给定差量t(0<=t<=1)获取线性插值点p(0) = p1,p(1) = p2
////////////////////////////////////////////////////////
template<class T>
static Vector3<T> GetPoint(const Vector3<T> &from,const Vector3<T> &to,float t);
在编译的Math的时候MinGW需要先"编译"Vector文件
2.2者在处理函数返回值上的不同
比如:
int GetValue()
{
}
msvc需要显式的给定函数返回值
而mingw不需要(具有默认值)
3.对待函数参数的不同
比如
template<class T>
void Add(T a,T a);
4.基本数据结构类型有所不同
5.在获取原始数据上的区别如下:
const int MAXINT = std::numeric_limits<int>::max;
const double MAXDOUBLE = (std::numeric_limits<double>::max)();
6.其他请大家补充吧
摘要: 这是最新设计的盖莫音频音频(API)(c++)(1.5.5)当前提供一个简易版本的播放器(使用了Skinse界面库)界面如下:当前提供的功能如下:盖莫音频API1.5.5 功能更为强劲盖莫音频引擎(API) 是使用标准c++写的音频播放软件支持devc++,codeblock,vc6,vc7.1,vc8.,vc9编译器平台支持xp,vista,win7 当前支持ogg,mp3,wav,au,aif...
阅读全文
这是刚改动的盖莫游戏引擎-UI小图
可以看出
好看了很多
具体的做法就是每一个控件对象都有一个对于的渲染描述符
包含控件边框和控件背景
当然只有改动控件的描述配置就可以改变控件的外观了(典型的装饰器啊)
具体小图如下:
1.
下一步我并不打算加入更多的控件(控件很多?)
还是先做做UI编辑器吧
提高一下生产率吧
本着简单,易用的设计原则
我给盖莫引擎加入了一个简单的插件系统
插件基类如下:
class Plugin : public virtual RefCount
{
public:
virtual ~Plugin(){}
virtual PLUGIN_FORMAT GetFormat()const = 0;
virtual engine_string GetMaker()const = 0;
virtual engine_string GetDescription()const = 0;
virtual void GetVersion(int &main,int &sub,int &pitch) = 0;
private:
virtual bool Init(void* data) = 0;
virtual void Deinit(void* data) = 0;
friend class PluginFactory;
};
可以看出基本的插件方法有获取插件格式,插件作者,插件描述,插件版本等
下面的是简单的插件工厂
////////////////////////////////////////////////////////////
/// 定义引擎插件工厂(管理器)
////////////////////////////////////////////////////////////
class GAPI PluginFactory : public Singleton<PluginFactory>
{
public:
bool RegisterPlugin(Plugin* plugin);
void UnRegisterPlugin(Plugin* plugin);
};
这是一个简单的单件
它只有2个函数注册和反注册插件
使用的时候只要获取插件指针
然后传入插件工厂注册之后即可使用
(注册的本质就是根据插件类型设置必要的插件上下文数据)
这种插件方法有它的弊端 不过在我看来最大的好处就是简单咯
下面是简单的视频播放插件咯
////////////////////////////////////////////////////////////
/// 定义引擎视频播放器(全局唯一)
////////////////////////////////////////////////////////////
class VideoPlayer : public Plugin
{
public:
///////////////////////////////////////////////////////
/// 构造,析构视频播放器
///////////////////////////////////////////////////////
VideoPlayer(){}
virtual ~VideoPlayer(){}
///////////////////////////////////////////////////////
/// 播放指定视频
///////////////////////////////////////////////////////
virtual bool Play(const engine_string& video) = 0;
///////////////////////////////////////////////////////
/// 视频更新每帧调用
///////////////////////////////////////////////////////
virtual bool Update() = 0;
///////////////////////////////////////////////////////
/// 停止并卸载视频
///////////////////////////////////////////////////////
virtual void Stop() = 0;
///////////////////////////////////////////////////////
/// 获取,设置视频当前音量(0-1)
///////////////////////////////////////////////////////
virtual float GetVolume()const = 0;
virtual void SetVolume(float volume) = 0;
};
1.先说下Ui的input部分
在GUI部分输入输出通常是需要采用回调函数来处理的
比如:
void G_CALL MousePosCallBack(int x,int y)
{
UIWidgetManager::Instance().OnMouseMove(x, y);
}
所以我就先给引擎的Input部分加入了几个输入输出回调函数以方便使用
2.然后上几个UI小图
当鼠标划过按钮时:
.
相关的代码:
void RenderGUI();
RefPtr<Device> device;
RefPtr<Input> input;
Panel *panel = NULL;
ProgressBar *progressbar = NULL;
Button *button1 = NULL;
Button *button2 = NULL;
Button *button3 = NULL;
Button *button4 = NULL;
void G_CALL MouseStateCallBack(int mouse,int action)
{
int x,y;
input->GetMousePosition(x,y);
if(action == KEY_PRESS && mouse == MOUSE_BUTTON_LEFT)
{
UIWidgetManager::Instance().OnLeftButtonDown(x,y);
}
else if(action == KEY_PRESS && mouse == MOUSE_BUTTON_RIGHT)
{
UIWidgetManager::Instance().OnRightButtonDown(x,y);
}
else if(action == KEY_RELEASE && mouse == MOUSE_BUTTON_LEFT)
{
UIWidgetManager::Instance().OnLeftButtonUp(x,y);
}
else if(action == KEY_RELEASE && mouse == MOUSE_BUTTON_RIGHT)
{
UIWidgetManager::Instance().OnRightButtonUp(x,y);
}
}
void G_CALL MousePosCallBack(int x,int y)
{
UIWidgetManager::Instance().OnMouseMove(x, y);
}
bool G_CALL IsShiftPressed()
{
return false;
}
bool G_CALL IsAltPressed()
{
return false;
}
bool G_CALL IsCtrlPressed()
{
return false;
}
void SettingPanel();
int main()
{
device = InitDevice("UI测试1");
input = device->GetInput();
input->AttachMouseState(&MouseStateCallBack);
input->AttachMousePos(&MousePosCallBack);
core::TextDesc::SetDefaultFont(engine_string("simhei.ttf"));
UIWidgetManager::Instance().Initialize(&IsShiftPressed,&IsAltPressed,&IsCtrlPressed);
UIWidgetManager::Instance().AppResized(640,480);
SettingPanel();
BEGIN_LOOP(device)
glClearColor(0.1,0.1,0.2,1.0f);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderGUI();
END_LOOP(device)
return 0;
}
void SettingPanel()
{
panel = new Panel(Rectf(10,75,180,180),NULL);
button1 = new Button(panel,L"寮€濮嬫父鎴?);
button2 = new Button(panel,L"淇濆瓨娓告垙");
button3 = new Button(panel,L"杞藉叆娓告垙");
button4 = new Button(panel,L"閫€鍑烘父鎴?);
progressbar = new ProgressBar(panel,Rectf(150,90,40,220),UI_DIRECTION_VERTICAL);
progressbar->SetPercentage(65.0f);
panel->AddChildWidget(button1);
panel->AddChildWidget(button2);
panel->AddChildWidget(button3);
panel->AddChildWidget(button4);
panel->AddChildWidget(progressbar);
button1->SetSize(Vector2f(120,40));
button2->SetSize(Vector2f(120,40));
button3->SetSize(Vector2f(120,40));
button4->SetSize(Vector2f(120,40));
button1->SetPosition(Vector2f(20,90));
button2->SetPosition(Vector2f(20,150));
button3->SetPosition(Vector2f(20,210));
button4->SetPosition(Vector2f(20,270));
UIWidgetManager::Instance().AddWidget(panel);
}
void RenderGUI()
{
float precent = progressbar->GetPercentage();
precent += 1.0f;
if(precent >= 100.0f)
precent = 0.0f;
progressbar->SetPercentage(precent);
UIWidgetManager::Instance().Update();
}
对于UI部分基本上所有的常见器件都需要一个一个设计
一次性做完太难了
而且设计的不好就需要重新设计
所以我决定先设计以下几个器件 Widget,Panel,StaticText,SliderBar
其余的等把基本框架做成熟了再做吧
当前引擎基本框架功能都已经完备了
接下来的开发将不再强调功能上的大而全
想强调精致,易用性
将优先考虑虚拟仿真上的易用喔
当前在做引擎的GUI部分
设计的的首要原则是先做出来,如果有什么问题以后再改
当然GUI消息事件是这样设计的
事件和听者是2个模板
///////////////////////////////////////////////////////////
/// 定义引擎事件基类模板
///////////////////////////////////////////////////////////
template<class EventType = int>
class Event : NonCopyable
{
public:
///////////////////////////////////////////////////////
/// 事件基类构造函数
///////////////////////////////////////////////////////
Event(const EventType& type):type_(type){}
////////////////////////////////////////////////////////
/// 事件基类析构函数
////////////////////////////////////////////////////////
virtual ~Event(){}
////////////////////////////////////////////////////////
/// 获取事件类型
////////////////////////////////////////////////////////
EventType GetEventType()const{return type_;}
private:
////////////////////////////////////////////////////////
/// 数据成员变量
////////////////////////////////////////////////////////
EventType type_;
};
////////////////////////////////////////////////////////////
/// 定义事件听者基类
////////////////////////////////////////////////////////////
template<class Event,class Object>
class EventListener
{
public:
////////////////////////////////////////////////////////
/// 事件听者虚析构函数
////////////////////////////////////////////////////////
virtual ~EventListener(){}
////////////////////////////////////////////////////////
/// 消息派送
////////////////////////////////////////////////////////
virtual bool Dispatch(const Event& message,Object* object) = 0;
};
可以看出这并不属于GUI部分
在GUI中有
typedef Event<UI_EVENT> UIEvent;
typedef EventListener<UIEvent,Widget> UIEventListener;
每一个控件可能都需要处理消息
所以控件有一个函数
////////////////////////////////////////////////////////
/// 消息处理
////////////////////////////////////////////////////////
virtual bool Process(const UIEvent& event);
来响应消息事件
基本的GUI事件有2类 一个是鼠标事件 一个是按键事件
所有有2个对象
class KeyEvent
class MouseEvent
对于鼠标还有几个派生的对象比如双击事件等
控件需要处理UI事件那么在GUI的某个部分需要生成UI事件
当然事件的生产在UIWidgetManager中
启用管理器的事件载入Input指针参数
然后不断检查鼠标和按键状态生成相关事件然后传递给相关控件
我认为GUI设计有点难度
但是相对来说GUI编辑器应该更难
小注:理想的编辑器应该是这样
通过编辑器生成控件配置文件(比如xml)
使用的时候只需要调用配置文件动态生成对等的控件,当然包含事件处理喽
最后上一个半成品的图图
(cppblog似乎对firefox兼容不好?)
下一篇说控件Surface和Border部分
也许你在使用c++的时候会出现问题:has no member named '...'
意思就是类没有成员变量XXA
实际上类是具有成员变量XX的
问题的原因在于工程中定义的变量和系统头文件定义的宏冲突所致
解决方案有2个
1.
#ifdef XXX
#undef XXX
#endif
2.包含对象定义所在头文件于调用系统头文件之前.
这里的XXX在具体情况中可能为GetObject,LoadImage等等
GUI系统 布局管理器
1.布局管理器存在的理由:可以避免手动或者逐个调整控件位置
2.布局管理器的基本功能:调整同一容器下同一层次下各个控件的位置
3.布局管理器的基本接口:
A.控件加入
B.控件移除
C.控件排列
4.布局管理器和控件的关系
A.一个布局管理器负责1个或则多个控件的排列
B.具有控件容器语义的控件(例如面板)持有一个布局管理器
5.合适调用布局管理之布局?
A.持有的控件尺寸变化,移动或者用户显示的调用之时
6.可能的布局管理器类型
A>流式,中央布局,盒子,复杂类型,...
7.简单的布局管理器接口
///////////////////////////////////////////////////////////
/// UI布局信息基类
///////////////////////////////////////////////////////////
class UILayoutInfo
{
public:
UILayoutInfo(){}
virtual ~UILayoutInfo(){}
public:
virtual engine_string GetLayouttType()const = 0;
};
///////////////////////////////////////////////////////////
/// 定义UI布局管理器基类
///////////////////////////////////////////////////////////
class UILayouter
{
public:
UILayouter(){}
virtual ~UILayouter(){}
public:
////////////////////////////////////////////////////////
/// 增加一个窗体到布局管理区
////////////////////////////////////////////////////////
virtual UILayouter& AddWidget(Widget* widget) = 0;
virtual UILayouter& AddWidget(Widget* widget,const UILayoutInfo&)
{
AddWidget(widget);
return *this;
}
////////////////////////////////////////////////////////
/// 控件移除和重新排列
////////////////////////////////////////////////////////
virtual UILayouter& RemoveWidget(Widget* widget) = 0;
virtual UILayouter& Arrange(Widget* parent) = 0;
};
所有类型的布局管理器都需要继承于UILayouter
其成员函数Arrange负责调配parent控件下的所有控件单元.
需要说明的是当容器控件加入一个新的控件的时候,其布局管理器就会调用AddWidget负责把新的控件加入布局管理器对象
举一个UI面板的例子:
////////////////////////////////////////////////////////////
/// UI面板(容器)
////////////////////////////////////////////////////////////
class G_DLL_API Panel : public Widget
{
public:
Panel(const Rectf& rect,Widget* parent,const engine_string& text = "Panel");
virtual ~Panel();
public:
////////////////////////////////////////////////////////
/// 加入一个子窗体
////////////////////////////////////////////////////////
Panel& AddChildWidget(Widget* widget)
{
windows_.push_back(widget);
layouter_->AddWidget(widget);
return *this;
}
Panel& AddChildWidget(Widget* widget,const UILayoutInfo& info)
{
windows_.push_back(widget);
layouter_->AddWidget(widget,info);
return *this;
}
////////////////////////////////////////////////////////
/// 控件移除
////////////////////////////////////////////////////////
Panel& RemoveChildWidget(Widget* widget)
{
windows_.remove(widget);
layouter_->RemoveWidget(widget);
return *this;
}
////////////////////////////////////////////////////////
/// 控件排列
////////////////////////////////////////////////////////
Panel& ArrangeChildren()
{
layouter_->Arrange(this);
return *this;
}
////////////////////////////////////////////////////////
/// 加载布局管理器
////////////////////////////////////////////////////////
Panel& SetLayouter(UILayouter* layouter);
在我设计的时候主要参考了2个GUI库,glooey,opengl gui lib
目前商业上使用的开源CEGUI过于复杂 比很多游戏引擎都大 让人难以容忍
引擎之GUI将会是当前引擎开发的当务之急(做完这个我想使用引擎做游戏)
那么GUI届时将提供那里功能和特点呢?
如下:
1.可以使用脚本(当前为xml配置GUI属性)
2.统一的GUI画面风格
3.配备专有的GUI编辑器
4.尽可能的和引擎保持独立以便让第三方使用和学习
5.必要的控件装饰器和布局管理器设计以增强UI设计的便利
6.使用信号插槽处理消息(似乎都是这样做的)
7.应该最少支持vc9,devc++2个编译器
7.做完之后的风格表现应该不逊于下图:
使用xml配置之后变成了;
另外一组图面:
2.
GUI库网上很多
但是我觉得还是自己弄一个比较好
附注L:去年我设计了半个GUI库后面放弃了问题太多喽