在查看Ogre例子时,想看材质要里的纹理,着色器代码都需要每个去查找,非常麻烦.也想看更新每个Ogre里的对象后有什么效果.然后看到Compositor组件与粒子组件时,想到能实时编辑着色器代码实时更新渲染.

  开始想着C++做界面麻烦,用C#的winForm做,后面发现首先结合层比较麻烦,然后C#与C++一起调试也会比较麻烦,还有一些比较奇怪的异常也会麻烦.好吧,不如全用C++做,在学习能用在Ogre中的UI时,主要了解了包括Ogre自己的Overlay, CEGUI, MyGUI等等,最终选择MyGUI,因为他小,功能全,代码容易理解,这样拓展起来也方便.因此最终选定Ogre1.9 + MyGUI3.2.2.这二个项目还都是跨平台的,如果有机会,后面可以尝试移值.开发平台暂时选用VS2013.

  首先整合MyGUI到Ogre中,这部分主要是加载MyGUI的资源文件与初始化MyGUI的环境.其中初始化整个函数如下.  

        void initRoot()
{
String pluginsPath = fsLayer->getConfigFilePath("plugins.cfg");
String logPath = fsLayer->getWritablePath("ogre.log");
root = new Root(pluginsPath, fsLayer->getWritablePath("ogre.cfg"), "ogre.log");
//root->showConfigDialog();
bool foundit = false;
for (auto rs : root->getAvailableRenderers())
{
root->setRenderSystem(rs);
String rname = root->getRenderSystem()->getName();
if (rname == "OpenGL Rendering Subsystem")//"OpenGL Rendering Subsystem"
{
foundit = true;
break;
}
}
if (!foundit)
return; //we didn't find it... Raise exception?
//we found it, we might as well use it!
root->getRenderSystem()->setConfigOption("Full Screen", "No");
root->getRenderSystem()->setConfigOption("Video Mode", "1024 x 768 @ 32-bit colour");
window = root->initialise(true, "Ogre3DX");
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps();
allResListener = new AllResourceListener(); this->loadUIResources();
this->loadResources();
this->createSceneManager();
this->createView();
this->createGui();
this->createSceneRoot();
}

InitRoot

  先初始化Root,选择渲染系统,初始化渲染窗口,加载UI资源等.我们单独把UI部分的资源拿出来,这样可以先加快界面出现过程,然后在界面里用进度条等显示加载游戏资源,这是大头部分,后面也会修改成这种,如下是UI资源部分代码.

        void loadUIResources()
{
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Core", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/OgreData", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show/Main", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show/Panel", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show/Other", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show/PanelView", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Show/PropertyField", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/Themes", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().addResourceLocation("../../Media/GUI/TreeControl", "FileSystem", "MyGUI");
ResourceGroupManager::getSingleton().initialiseResourceGroup("MyGUI");
}

Load UI

  其中GUI/Core里放的就是MyGUI中的Media/MyGUI_Media这个目录,这个是必需的,MyGUI下另外的几个文件夹都是非必要的.不过在这里,我设定的是黑色风格,MyGUI_Media默认提供的不是这种,所以把原MyGUI下的Media/Tools/LayoutEditor/Themes放入我们的资源文件GUI/Themes下,另外一些文件夹后面遇到再说.

  在生成viewport与camera后,我们开始加载MyGUI,如下是初始MyGUI环境代码.

void createGui()
{
ogrePlatform = new OgrePlatform();
ogrePlatform->initialise(window, sceneMgr, "MyGUI");
gui = new Gui();
gui->initialise(); std::ostringstream handleStr;
long handle = ;
window->getCustomAttribute("WINDOW", &handle); inputMgr = new OgreViewUI::InputManager();
inputMgr->createInput(handle);
pointMgr = new OgreViewUI::PointerManager();
pointMgr->createPointerManager(handle);
pointMgr->loadPointerResources(); MyGUI::ResourceManager::getInstance().load("FrameworkFonts.xml");
MyGUI::ResourceManager::getInstance().load("MyGUI_DarkSkin.xml");
MyGUI::ResourceManager::getInstance().load("MyGUI_DarkTemplate.xml");
MyGUI::ResourceManager::getInstance().load("TreeControlSkin.xml");
MyGUI::ResourceManager::getInstance().load("TreeControlTemplate.xml");
MyGUI::ResourceManager::getInstance().load("AutoComplete.xml"); MyGUI::FactoryManager& factory = MyGUI::FactoryManager::getInstance();
std::string widgetCategory = MyGUI::WidgetManager::getInstance().getCategoryName();
factory.registerFactory<MyGUI::TreeControl>(widgetCategory);
factory.registerFactory<MyGUI::TreeControlItem>(widgetCategory);
factory.registerFactory<MyGUI::AutoComplete>(widgetCategory);
}

MyGUI Initialise

  OgrePlatform的初始化就是把对应MyGUI的RenderManager关联在Ogre的渲染过程中,详细说明请看我上一篇 MyGUI 解析 里有详细介绍这个过程.而gui对象的初始化就是对内部的单例管理类初始化,初始化的过程大部分都在解析上面所说MyGUI中的Media/MyGUI_Media 中的文件.

  然后我们初始化InputManager与PointerManager这二个类,这二个类会在MyGUI下的Common/Input中提供,一个截获鼠标与键盘事件,一个是管理鼠标显示状态.

  前面所说,Media/MyGUI_Media下文件名都是固定的,MyGUI初始化时自动会去加载对应的固定名,而非那个文件夹下的文件,我们需要自己用MyGUI提供的ResourceManger进行load,前面我们用Ogre去load,但是Ogre不能处理这些文件,但是会记录对应文件路径,这样读出对应的文件流给MyGUI去处理.然后我们注册我们自定义的一些UI组件,上面的是树型控件和自动完成控件.

  这样Ogre与MyGUI就整合在一起了.然后就是主界面大致设定,如下图所示.

  

  暂时大致分成五个部分,上面是菜单区,左边是管理区,大致分成场景,资源等,中间上面是显示区域,中间下面暂时空出,右边部分是属性区.

  在这里,我们要先定义一个主界面的Layout文件与菜单的Layout文件如下:

  

  

  注意Align,在这,我们想让主界面占满整个窗口,则定义为Stretch,相当于winForm中的Fill,注意这也是第一层控件,我们需要定义他的name固定为Root或是_Main,因为MyGUI给我们提供的一个基本管理Layout文件类BaseLayout有字段mMainWidget,在初始化时,检测名为Root或_Main的Widget赋给mMainWidget,找不到则给出异常,这样有个好处,mMainWidget能代表当前Layout的大小,如果我们调整大小,修改这个就好,并且根据子Widget的Align来调整子Widget的大小,还有Layer,前文说过,同一层的UI定义的Layer最好在同一层,不然层之间会遮挡.

  在主界面的Layout中定义划二个Widget控件在上面,一个name为MainMenuControl,Align为Top.一个name为MainControl,Align为Stretch.而在菜单界面对应的Layout中放入的是MenuBar控件在上面.

  对于菜单界面,我们直接使用Layout editor生成的代码,如下代码.

    ATTRIBUTE_CLASS_LAYOUT(MainMenu, "MainMenuControl.layout");
class MainMenu :
public wraps::BaseLayout
{
public:
MainMenu(MyGUI::Widget* _parent = nullptr);
virtual ~MainMenu(); private:
void mouseClick(MyGUI::Widget* sender);
private:
//%LE Widget_Declaration list start
ATTRIBUTE_FIELD_WIDGET_NAME(MainMenu, mMenuMenuBar, "Menu");
MyGUI::MenuBar* mMenuMenuBar;
ATTRIBUTE_FIELD_WIDGET_NAME(MainMenu, mLoadMenuItem, "load");
MyGUI::MenuItem* mLoadMenuItem;
//%LE Widget_Declaration list end
}; MainMenu::MainMenu(MyGUI::Widget* _parent)
{
initialiseByAttributes(this, _parent);
mLoadMenuItem->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::mouseClick);
} MainMenu::~MainMenu()
{
} void MainMenu::mouseClick(MyGUI::Widget* sender)
{ }

MainMenu

  每个类名前面一个宏,控件字段上带一个宏,这样在初始化,调用initialiseByAttributes时,其实就是分析相应宏设置,类宏提供对应的Layout文件(需要注意放入Ogre加载的文件夹下,否则找不到), 控件字段提供控件对象与Layout中的子Widget对应.其实我们不要上面的宏,在初始化调用如下语句,是一个意思.

    MainMenu::MainMenu(MyGUI::Widget* _parent)
{
initialise("MainPane.layout");
assignWidget(mMenuMenuBar, "Menu");
assignWidget(mLoadMenuItem, "load"); //initialiseByAttributes(this, _parent);
mLoadMenuItem->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::mouseClick);
}

MainMenu

  我们还记的主控件里放入的是二个Widget,并没有实际对应某种控件,一般控件里放入Widget,表示实际对应是另一个我们自己定义的Layout,如这里,上面的Widget明显对应的是我们上面所说的MainMenu.我们看下,如下把这二者关联起来.

    class MainPane :
public wraps::BaseLayout
{
public:
MainPane(MyGUI::Widget* _parent = nullptr);
virtual ~MainPane();
private:
MainMenu* mMainMenuControl = nullptr; tools::PropertiesPanelView* properyPanel2 = nullptr;
}; MainPane::MainPane(MyGUI::Widget* _parent)
{
initialise("MainPane.layout");
assignBase(mMainMenuControl, "MainMenuControl");
assignBase(properyPanel2 , "MainControl");
}

MainPane

  在MainPane里,我们自己来写,没用生成的代码,我们也就不用那些宏了,自己来初始化,和前面一样,先initialise对应的layout文件,然后把layout对应控件名给某控件,和前面用assignWidget不同,这里我们用的是assignBase.assignWidget一般用于指定layout的template控件(也就是系统内定的控件),而assignBase一般用于把layout中的Type为Widget的控件定义成我们自定义的Layout对应类.

  MyGUI说大了,再复杂的界面都是于assignWidget与assignBase来构成,对于其内部具体实现,请看相关代码与于我前篇 MyGUI 解析 .  

Ogre 编辑器一(MyGUI+Ogre整合与主界面)的更多相关文章

  1. Ogre 编辑器二(用Ogre的地形组件加载天龙八部地形)

    主界面如上文设计完成后,场景刚开始添加了是Ogre例子里的,发现场景里实物太少,于是想到直接把天龙的场景拿下来,天龙网上有源码,参考了下,把天龙的地形用Ogre的地形组件完成了下,如下是效果图: 因为 ...

  2. Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)

    最开始设计这个编辑器时,其中一个要求就是能在运行过程中,通过UI来更新各对象,这样我们就能明确每个Ogre对象更新其属性影响的渲染效果.比如点光源,方向光源,聚光灯各属性与效果,深度测试开启与关闭,深 ...

  3. Winform开发主界面菜单的动态树形列表展示

    我在之前很多文章里面,介绍过Winform主界面的开发,基本上都是标准的界面,在顶部放置工具栏,中间区域则放置多文档的内容,但是在顶部菜单比较多的时候,就需要把菜单分为几级处理,如可以在顶部菜单放置一 ...

  4. Winform开发框架主界面设计展示

    做了好多年Winform的程序的开发,主窗口的界面设计一般都要求做的更好一些,可以根据不同的系统功能模块进行归类整合,能使客户迅速寻找到相关功能的同时,也能感觉到整体性的美观大方,因此主窗口的界面设计 ...

  5. android布局实践——模仿微信主界面

    这是目前微信6.0版本的主界面 先来分析一波: 1.(top.xml)界面头部有一个微信(6)消息提醒    一个搜索图标   一个更多的的图标+,中间还有一段空白,我们可以弄两个textView(其 ...

  6. 使用DotNetBar制作漂亮的WinFrom界面,自定义AgileEAS.NET SOA平台WinClient主界面

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  7. delphi 一个线程和主界面的交互的演示代码

    求一个线程和主界面的交互的演示代码求一个线程和主界面的交互的演示代码.线程和主界面处于两个Unit.线程中的user中不能引用主窗口.我只是想学习一下,线程和主界面交互的方法.去网上查了好几天资料,能 ...

  8. 安卓开发_慕课网_Fragment实现Tab(App主界面)

    学习内容来自“慕课网” 这里用Fragment来实现APP主界面 思路: 底部横向排列4个LinearLayout,每个LinearLayout包含一个图片按钮和一个文字 1.默认显示第一个功能(微信 ...

  9. 关于VS打包程序无法弹出主界面的问题

    代码中的程序很正常,VS打包之后,无法弹出主界面的问题. 这种问题,一般是缺少程序加载所必须的东西,包括dll,配置文件等. (1)程序主界面使用的是DevExpress,DevExpress的相关类 ...

随机推荐

  1. 【Unity】8.5 扩展编辑器

    分类:Unity.C#.VS2015 创建日期:2016-04-27 一.简介 可以通过编辑器窗口 (Editor Windows) 创建自己在 Unity 中的自定义设计工具.来自EditorWin ...

  2. C++11 constexpr使用

    C++11为了提高代码执行效率做了一些改善.这种改善之一就是:生成常量表达式,允许程序利用编译时的计算能力.假如你熟悉模板元编程,你将发现constexpr使这一切变得更加简单.constexpr使我 ...

  3. linux Ctrl+z和Ctrl+c的区别

    1.Ctrl+z 挂起进程,并不会结束,执行fg命令可以重新启动这个被挂起的命令. 2.Ctrl+c 终止进程

  4. raise EnvironmentError("%s not found" % (mysql_config.path,)) EnvironmentError: mysql_config not found 解决办法

    报错信息如下: Downloading https://pypi.tuna.tsinghua.edu.cn/packages/a5/e9/51b544da85a36a68debe7a7091f068d ...

  5. c与c++相互调用机制分析与实现

    c++通常被称为Better c,多数是因为c++程序可以很简单的调用c函数,语法上基本实现兼容.最常用的调用方式就是c++模块调用c实现的dll导出函数,很简单的用法,使用extern " ...

  6. 线程安全的无锁RingBuffer的实现【一个读线程,一个写线程】

    在程序设计中,我们有时会遇到这样的情况,一个线程将数据写到一个buffer中,另外一个线程从中读数据.所以这里就有多线程竞争的问题.通常的解决办法是对竞争资源加锁.但是,一般加锁的损耗较高.其实,对于 ...

  7. QT-提示“database not open”

    问题现象: 要用QT开发"SQLite"时出现如下提示: QSqlQuery::exec: database not open QSqlDatabase: QSQLITE driv ...

  8. Android 后台发送邮件 (收集应用异常信息+Demo代码)

    上一次说了如何收集我们已经发布的应用程序的错误信息,方便我们调试完善程序.上次说的收集方法主要是把收集的信息通过Http的post请求把相关的异常信息变成请求参数发送到服务器.这个对做过web开发的人 ...

  9. laravel服务l队列资料整理

    Laravel 队列系列 —— 基于 Redis 实现任务队列的基本配置和使用 1.概述 在Web开发中,我们经常会遇到需要批量处理任务的场景,比如群发邮件.秒杀资格获取等,我们将这些耗时或者高并发的 ...

  10. Chrome 插件编写日记

    Chrome 插件,你可以理解为打开了一个网页,但是里面只有前端语言,JavaScript, HTML + css 但是有一点区别的是,它是有一个名字为 manifest.json 的配置文件的,里面 ...