Ogre 编辑器一(MyGUI+Ogre配置与主界面)

  在查看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(5);
            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 = 0;
            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 解析 .  

时间: 2024-10-22 12:00:00

Ogre 编辑器一(MyGUI+Ogre配置与主界面)的相关文章

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

主界面如上文设计完成后,场景刚开始添加了是Ogre例子里的,发现场景里实物太少,于是想到直接把天龙的场景拿下来,天龙网上有源码,参考了下,把天龙的地形用Ogre的地形组件完成了下,如下是效果图: 因为主要是加载地形,然后只是简单加载了静态模型,因此场景看着比较简陋,再者因为上传的图片限制,场景复杂后根本传不上来. 天龙的地形还是比较简单的,如下是天龙的pingpan.terrain简化后的内容. <?xml version="1.0" encoding="UTF-8&q

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

最开始设计这个编辑器时,其中一个要求就是能在运行过程中,通过UI来更新各对象,这样我们就能明确每个Ogre对象更新其属性影响的渲染效果.比如点光源,方向光源,聚光灯各属性与效果,深度测试开启与关闭,深度比较方式影响的效果等等.如下先看效果图: 这个位置没有用上一篇天龙的场景,主要是图片大小限制,场景复杂后,生成的gif图片太大. 这个功能当时我主界面完成后,就准备做的,但是当时一时想不到好的方案,如果针对每个Ogre属性来生成UI,然后关联每个对象,再想想后续如果要修改其中的字段属性或是位置,这

Keepalived+MariaDB10配置双主高可用数据库

Keepalived+MariaDB10配置双主高可用数据库 OS RS 子网掩码 路由网关 Centos6.6 MariaDB10 Keepalived Eth0:192.168.26.210 255.255.252.0 192.168.25.3 VIP:192.168.27.210 255.255.255.252 Centos6.6 MariaDB10 Keepalived Eth0:192.168.26.211 255.255.252.0 192.168.25.3 VIP:192.168.

配置域主DNS服务器

一.DNS服务器的类型 ①Primary DNS Server(Master) 一个域的主服务器保存着该域的zone配置文件,该域所有的配置.更改都是在该服务器上进行,本篇随笔要讲解的也是如何配置一个域的主DNS服务器 ②Secondary DNS Server(Slave) 域从服务器一般都是作为冗余负载使用,一个域的从服务器是从该域的主服务器上抓取zone配置文件,从服务器不会进行任何信息的更改,zone配置文件的修改只能在主DNS服务器上进行,所有的修改都有主服务器同步 ③Caching

05-SCVMM2012之认识主界面及配置运行账户

4.配置SCVMM 2012 R24.1.认识SCVMM主界面安装完VMM服务器后,打开VMM控制台,点击"连接" VMM服务器的主界面,分为工作区.导航区和功能区 4.2.配置运行方式账户SCVMM在很多作业上都需要用户权限,因此配置合理的"运行方式账户",会大大简化后续的SCVMM操作,在SCVMM主界面,在工作区选择设置创建运行方式账户 为方便测试,这里只创建一个域管理员的运行防止账户,输入如下信息,点击"确定" 创建完后,刚才创建的账户在

hibernate配置联合主键

配置联合主键有多种方式,这里仅记录我使用的一种. 直接上代码 使用@IdClass,红色标注. package com.szy.operation.stat.model.agent.school; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.IdClass;

MySQL组复制(4):配置多主模型的组复制

在这一篇,我演示的是如何配置MySQL组复制的多主模型(multi-primary).在配置上,多主模型的组复制和单主模型基本没区别. 本文仅为搭建和维护多主模型组复制抛块小砖,若对其间涉及的术语和理论有所疑惑,可参看: 单主模型相关内容的大长文:配置单主模型的组复制. 组复制的理论:MySQL组复制官方手册翻译. 使用组复制技术,必须要了解它的要求和局限性.见:组复制的要求和局限性. 1.组复制:单主和多主模型 MySQL组复制支持单主模型和多主模型,它们都能保证MySQL数据库的高可用. 单

mysql学习-mysql8.0配置双主复制+keepalived实现高可用架构

一般小型公司数据库,使用主从复制即可保证数据库的高可用,但是一旦主数据库故障,切换到从库需要一定的时间,这样就导致了停机时间过长,不能及时恢复业务.使用双主(master)配合keepalived这种mysql高可用架构也是基于主从复制的原理而搭建的.这是一种简单.便捷的解决方案,在高可用集群环境中,keepalived使用vip,利用keepalived自带的服务监控功能和自定义脚本来实现mysql故障时自动切换. 1.mysql双主复制介绍 双主复制,就是相互做主从复制,每个master既是

Ext JS 6开发实例(三) :主界面设计

在上文中,已经将CMD创建的应用程序导入到项目里了,而且也看到默认的主界面了,今天的主要工作就是修改这个主界面,以符合项目的需要.除了设计主界面,还有一些其他的东西需要配置一下. 添加本地化包 打开app.json文件,找到requires,代码如下:     "requires": [      "font-awesome"     ],12341234 以上代码说明项目默认已经引用了Font Awesome的图标,可以在项目中直接使用.这个在项目的后续开发中会经