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

摘要:
=nullptr){autoindex=find;child-˃parent-˃childs.erase;}child-˃parent=this;childs.push_back;}voidremove{remove;}voidremoveAll(){//删除所有子节点while(!=nullptr)parent-˃remove;//删除所有子节点while(!childs.empty()){autochild=childs.back();childs.pop_back();//这句避免递归时重复deletechild-˃parent=nullptr;if(child!

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

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

这个位置没有用上一篇天龙的场景,主要是图片大小限制,场景复杂后,生成的gif图片太大.

这个功能当时我主界面完成后,就准备做的,但是当时一时想不到好的方案,如果针对每个Ogre属性来生成UI,然后关联每个对象,再想想后续如果要修改其中的字段属性或是位置,这个工作量让我不得不先想一个方案能够避免这些问题.在完成第二篇天龙场景的加载时,顺便在空闲时间想出现在的这种解决方法,不说这方法好,但是工作量少,简洁,易修改,避免很多BUG.灵活性高,只有二个Ogre之间有关联,就可以显示在一起.如上面的Entity,他显示出他父节点SceneNode,以及他的父类MovableObject的各属性.

这个方案简单来说,分成三个部分,一个部分主要是XML文件,XML文件包含每个Ogre对象要关联的对象,字段,关联字段等.第二个部分是自动生成控件界面,根据第一部分的信息来生成各个界面.第三部分是根据Ogre对象更新各个控件,以及更新控件上的值更新后反馈给对应Ogre对象.如下是三个部分代码图,VS中C++代码生成的代码关联图中,聚合关系不能显示出来,所以一些聚合信息在上面没有显示出来.

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

XML文件与基本类

这个部分主要有二方面,一方面是XML文件保存的信息,包含每个Ogre对象关联的对象,每个对象更新的字段,字段的项选择,如下图:

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

然后就是如第一张图中的类OgreStyle,我们可以看到,这个类三个部分都有引用到,也是我们的这解决方法的核心类,这个类是一个树型结构,这个结构在这主要有二个好处,一是容易添加在树型控件里.二是可以得到父节点信息与子节点信息.其中我们设计在删除节点时,所有子节点全删除.如下是OgreStyle代码.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第5张
namespaceOgre3DX
{
    typedef std::vector<string>VectorString;
    classOgreStyle;
    typedef std::vector<OgreStyle*>OgreStyleVector;
    classOgreStyle
    {
    public:
        //ResourceType,SceneType
        int type = 0;
        std::string ogreName = "";
        std::string ogreSecond = "";
        std::string ogreText = "";
        OgreStyle* parent =nullptr;
        OgreStyleVector childs;        
    public:
        OgreStyle()
        {
            childs.clear();
        }
        std::stringgetText()
        {
            if(ogreText.empty())
                returnogreName;
            returnogreText;
        }
        void add(OgreStyle*child)
        {
            if (!check(child))
            {
                throw exception("child is parent.");
            }
            if (child->parent !=nullptr)
            {
                auto index = find(child->parent->childs.begin(), child->parent->childs.end(), child);
                child->parent->childs.erase(index);
            }
            child->parent = this;
            childs.push_back(child);
        }
        void remove(OgreStyle*child)
        {
            remove(child, true);
        }
        voidremoveAll()
        {
            //删除所有子节点
            while (!childs.empty())
            {
                auto child =childs.back();
                childs.pop_back();
                //这句 避免递归时重复delete
                child->parent =nullptr;
                if (child !=nullptr)
                {
                    deletechild;
                    child =nullptr;
                }
            }
        }
        OgreStyle* findChild(inttype)
        {
            if(childs.empty())
                returnnullptr;
            for (auto child : this->childs)
            {
                if (child->type ==type)
                    returnchild;
            }
            returnnullptr;
        }
        OgreStyle* findChild(std::stringname)
        {
            if(childs.empty())
                returnnullptr;
            for (auto child : this->childs)
            {
                if (child->ogreName ==name)
                    returnchild;
            }
            returnnullptr;
        }
        bool check(OgreStyle*style)
        {
            OgreStyle* parent = this->parent;
            while (parent !=nullptr)
            {
                if (parent ==style)
                    return false;
                parent = parent->parent;
            }
            return true;
        }
        ~OgreStyle()
        {
            if (parent !=nullptr)
                parent->remove(this, false);
            //删除所有子节点
            while (!childs.empty())
            {
                auto child =childs.back();
                childs.pop_back();
                //这句 避免递归时重复delete
                child->parent =nullptr;
                if (child !=nullptr)
                {
                    deletechild;
                    child =nullptr;
                }
            }
        }
    private:
        void remove(OgreStyle* child, boolbDelete)
        {
            if (child->parent !=nullptr)
            {
                auto index = find(child->parent->childs.begin(), child->parent->childs.end(), child);
                child->parent->childs.erase(index);
            }
            child->parent =nullptr;
            if(bDelete)
            {
                deletechild;
                child =nullptr;
            }
        }
    };
}
OgreStyle

其中OgreStyle中的Type就是对应的Ogre中的对象类型,而ogreName是对应Ogre对象的标识,parent与childs树结构.type对应的值在如下类中:

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第7张
namespaceResourceEnum
{
    //对应Ogre资源类型
    enumResourceType
    {
        Resource = 100,
        Material,
        Technique,
        Pass,
        Mesh,
        SubMesh,
        TextureUnit,
        Texture,
        Particle,
        Compositor,
        Program,
        Shader_Cg,
        Shader_hlsl,
        Shader_glsl,
    };
    //对应Ogre场景
    enumSceneType
    {
        Scene = 200,
        SceneNode,
        Viewport,
        Camera,
        RenderSystem,
        RenderTarget,
        MovableObject,
        Renderable
    };
    enumMovableType
    {
        MovableOther = 300,
        BillboardChain,
        BillboardSet,
        Entity,
        Light,
        ManualObject,
        ParticleSystem,
        RibbonTrail,
    };
    enumRenderType
    {
        RenderOther = 400,
        RenderSubEntity
    };
    enumFileType
    {
        FL_Materials = 500,
        FL_Material,
        FL_Group,
    };
}
ResourceType

先暂时列这么多,其中上面第一份XML文件就是每个type关联那些type,第二份文件就是每个type对应的字段,第三个type就是其中Ogre中的一些enum.下面这个类把type与三份三XML文件关联起来.其中方法initXML不是有意要使用这种比较难理解的方式,主要是因为DataStreamHolder里面的数据是shared_ptr智能指针类型,最后得到的root只有在函数initXML内才有效,传出这个值无效,而针对XML文件有效性检查的代码是一样,这样只有把方法传过来.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第9张
namespaceOgre3DX
{
    structNodeStyle
    {
        std::stringnodeName;
        std::stringnodeText;
        NodeStyle(){};
        NodeStyle(std::string name, std::stringtext)
            :nodeName(name), nodeText(text){}
        stringgetText()
        {
            if(nodeText.empty())
            {
                stringresult;
                for (auto ch = nodeName.begin(); ch != nodeName.end(); ++ch)
                {
                    if (ch != nodeName.begin() && isupper(*ch))
                    {
                        result.push_back(' ');
                    }
                    result.push_back(*ch);
                }
                returnresult;
            }
            returnnodeText;
        }
    };
    structOgreField
    {
        stringfieldName;
        stringfieldType;
        stringfieldKey;
        stringfieldText;
        bool fieldManual = false;
        OgreField(){};
        OgreField(std::string name, std::string type, std::stringkey)
            :fieldName(name), fieldType(type), fieldKey(key){}
        stringgetText()
        {
            if(fieldText.empty())
            {
                stringresult;
                for (auto ch = fieldName.begin(); ch != fieldName.end(); ++ch)
                {
                    if (ch != fieldName.begin() && isupper(*ch))
                    {
                        result.push_back(' ');
                    }
                    result.push_back(*ch);
                }
                returnresult;
            }
            returnfieldText;
        }
    };
    structRelationVisible
    {
        stringname;
        stringrelationName;
        stringrelationValue;
        boolrelationVisible;
        stringnodeName;
        RelationVisible(std::string name, std::string dName, std::string value, bool visible, stringnode)
            :name(name), relationName(dName), relationValue(value), relationVisible(visible), nodeName(node){}
    };
    typedef std::vector<OgreField*>FieldVector;
    typedef std::vector<NodeStyle*>NodeStyleVector;
    typedef std::vector<RelationVisible*>RelationVector;
}
namespaceOgre3DX
{
    classOgreStyleManager :
        public tools::Singleton<OgreStyleManager>
    {
    public:
        OgreStyleManager();
        ~OgreStyleManager();
        voidinitialise();
        int getOgreStyleType(const string& name, int deault = 0)
        {
            for(auto kv : ogreStyles)
            {
                if (kv.second ==name)
                    returnkv.first;
            }
            returndeault;
        }
        std::string getOgreStyleName(int type, const string& name = "")
        {
            if (ogreStyles.find(type) !=ogreStyles.end())
            {
                returnogreStyles[type];
            }
            returnname;
        }
        NodeStyleVector getNodeStyles(inttype)
        {
            NodeStyleVector result;
            if (ogreStyles.find(type) !=ogreStyles.end())
            {
                auto styleName =ogreStyles[type];
                if (ogreNodes.find(styleName) !=ogreNodes.end())
                {
                    auto nodeNames =ogreNodes[styleName];
                    int size =nodeNames.size();
                    for (int i = 0; i < size; i++)
                    {
                        auto name =nodeNames[i];
                        auto nodeStyle =nodeStyles[name];
                        auto text =ogreTexts[styleName][i];
                        if (!text.empty())
                            nodeStyle->nodeText =text;
                        result.push_back(nodeStyle);
                    }
                }
            }
            returnresult;
        }
        FieldVector getFieldVector(const string&nodeName)
        {
            if (nodeFields.find(nodeName) !=nodeFields.end())
            {
                returnnodeFields[nodeName];
            }
            returnFieldVector();
        }
        VectorString getKeyItems(const string&key)
        {
            if (keyItems.find(key) !=keyItems.end())
            {
                returnkeyItems[key];
            }
            returnVectorString();
        }
        RelationVector getRelationFields(const string&nodeName)
        {
            RelationVector result;
            for(auto rf : relationFields)
            {
                if (rf->nodeName ==nodeName)
                    result.push_back(rf);
            }
            returnresult;
        }
        bool getRelation(const string&fieldName)
        {
            for(auto rf : relationFields)
            {
                if (rf->name == fieldName || rf->relationName ==fieldName)
                    return true;
            }
            return false;
        }
    private:
        typedef void(OgreStyleManager::*ptrFun)(xml::ElementPtr root);
        void initXML(std::stringxmlName, ptrFun func);
        voidinitOgreStyles();
        voidinitStyleNodes(xml::ElementPtr root);
        voidinitNodeFields(xml::ElementPtr root);
        voidinitKeyItems(xml::ElementPtr root);
        voidinitRelationFields();
        xml::ElementPtr getRoot(DataStreamHolder data);
    private:
        //OgreResource int -> OgreStyleName
        std::map<int, string>ogreStyles;
        //NodeName -> NodeStyle
        std::map<string, NodeStyle*>nodeStyles;
        //OgreStyleName -> Vector NodeName (StyleNode.xml)
        std::map<string, VectorString>ogreNodes;
        std::map<string, VectorString>ogreTexts;
        //NodeName -> Vector NodeField (NodeField.xml)
        std::map<string, FieldVector>nodeFields;
        //key - items (KeyItem.xml)
        std::map<string, VectorString>keyItems;
        RelationVector relationFields;
    };
}
template <> OgreStyleManager* tools::Singleton<OgreStyleManager>::msInstance =nullptr;
namespaceOgre3DX
{
    OgreStyleManager::OgreStyleManager()
    {
    }
    OgreStyleManager::~OgreStyleManager()
    {
    }
    voidOgreStyleManager::initialise()
    {
        initOgreStyles();
        initXML("StyleNode.xml", &OgreStyleManager::initStyleNodes);
        initXML("NodeField.xml", &OgreStyleManager::initNodeFields);
        initXML("KeyItem.xml", &OgreStyleManager::initKeyItems);
        initRelationFields();
    }
    voidOgreStyleManager::initOgreStyles()
    {
        ogreStyles[ResourceEnum::ResourceType::Resource] = "Resource";
        ogreStyles[ResourceEnum::ResourceType::Material] = "Material";
        ogreStyles[ResourceEnum::ResourceType::Technique] = "Technique";
        ogreStyles[ResourceEnum::ResourceType::Mesh] = "Mesh";
        ogreStyles[ResourceEnum::ResourceType::Texture] = "Texture";
        ogreStyles[ResourceEnum::ResourceType::Particle] = "Particle";
        ogreStyles[ResourceEnum::ResourceType::Compositor] = "Compositor";
        ogreStyles[ResourceEnum::ResourceType::Program] = "Program";
        ogreStyles[ResourceEnum::ResourceType::SubMesh] = "SubMesh";
        ogreStyles[ResourceEnum::ResourceType::Pass] = "Pass";
        ogreStyles[ResourceEnum::SceneType::Scene] = "SceneManager";
        ogreStyles[ResourceEnum::SceneType::SceneNode] = "SceneNode";
        ogreStyles[ResourceEnum::SceneType::Viewport] = "Viewport";
        ogreStyles[ResourceEnum::SceneType::Camera] = "Camera";
        ogreStyles[ResourceEnum::SceneType::RenderSystem] = "RenderSystem";
        ogreStyles[ResourceEnum::SceneType::RenderTarget] = "RenderTarget";
        ogreStyles[ResourceEnum::SceneType::MovableObject] = "MovableObject";
        ogreStyles[ResourceEnum::SceneType::Renderable] = "Renderable";
        ogreStyles[ResourceEnum::MovableType::MovableOther] = "MovableOther";
        ogreStyles[ResourceEnum::MovableType::BillboardChain] = "BillboardChain";
        ogreStyles[ResourceEnum::MovableType::BillboardSet] = "BillboardSet";
        ogreStyles[ResourceEnum::MovableType::Entity] = "Entity";
        ogreStyles[ResourceEnum::MovableType::Light] = "Light";
        ogreStyles[ResourceEnum::MovableType::ManualObject] = "ManualObject";
        ogreStyles[ResourceEnum::MovableType::ParticleSystem] = "ParticleSystem";
        ogreStyles[ResourceEnum::MovableType::RibbonTrail] = "RibbonTrail";
        ogreStyles[ResourceEnum::RenderType::RenderSubEntity] = "SubEntity";
    }
    void OgreStyleManager::initXML(std::stringxmlName, ptrFun initFunc)
    {
        DataStreamHolder data =MyGUI::DataManager::getInstance().getData(xmlName);
        if (data.getData() ==nullptr)
        {
            throw exception("");
        }
        xml::Document doc;
        if (!doc.open(data.getData()))
        {
            throw exception("");
        }
        xml::ElementPtr root =doc.getRoot();
        if ((nullptr == root) || (root->getName() != "OgreResource"))
        {
            throw exception("");
        }
        (this->*initFunc)(root);
    }
    voidOgreStyleManager::initStyleNodes(xml::ElementPtr root)
    {
        auto node = root->getElementEnumerator();
        while (node.next("OgreStyle"))
        {
            auto name = node->findAttribute("name");
            auto field = node->getElementEnumerator();
            while(field.next())
            {
                auto nodeName = field->findAttribute("name");
                auto text = field->findAttribute("text");
                ogreNodes[name].push_back(nodeName);
                ogreTexts[name].push_back(text);
            }
        }
    }
    voidOgreStyleManager::initNodeFields(xml::ElementPtr root)
    {
        auto node = root->getElementEnumerator();
        while (node.next("OgreNode"))
        {
            auto name = node->findAttribute("name");
            auto text = node->findAttribute("text");
            NodeStyle* nodeStyle = newNodeStyle(name, text);
            nodeStyles[name] =nodeStyle;
            auto field = node->getElementEnumerator();
            while(field.next())
            {
                auto fieldName = field->findAttribute("name");
                auto fieldType = field->findAttribute("type");
                auto fieldKey = field->findAttribute("key");
                auto fieldText = field->findAttribute("text");
                auto fieldManual = field->findAttribute("manual");
                OgreField* field = newOgreField(fieldName, fieldType, fieldKey);
                field->fieldText =fieldText;
                if (fieldManual.size() > 0)
                {
                    field->fieldManual =Ogre::StringConverter::parseBool(fieldManual);
                }
                nodeFields[name].push_back(field);
            }
        }
    }
    voidOgreStyleManager::initKeyItems(xml::ElementPtr root)
    {
        auto node = root->getElementEnumerator();
        while (node.next("Key"))
        {
            auto name = node->findAttribute("name");
            auto field = node->getElementEnumerator();
            while(field.next())
            {
                auto nodeName = field->findAttribute("name");
                keyItems[name].push_back(nodeName);
            }
        }
    }
    voidOgreStyleManager::initRelationFields()
    {
        RelationVisible* entitySkeleton = new RelationVisible("DisplaySkeleton", "HaveSkeleton", "false", false, "Entity");
        RelationVisible* targetPrimary0 = new RelationVisible("Update", "Primary", "true", false, "RenderTarget");
        RelationVisible* targetPrimary1 = new RelationVisible("Active", "Primary", "true", false, "RenderTarget");
        RelationVisible* targetPrimary2 = new RelationVisible("AutoUpdated", "Primary", "true", false, "RenderTarget");
        RelationVisible* spot = new RelationVisible("Spotlight", "Type", "SPOTLIGHT", true, "Light");
        RelationVisible* spotInner = new RelationVisible("SpotlightInner", "Type", "SPOTLIGHT", true, "Light");
        RelationVisible* spotOuter = new RelationVisible("SpotlightOuter", "Type", "SPOTLIGHT", true, "Light");
        RelationVisible* spotFalloff = new RelationVisible("SpotlightFalloff", "Type", "SPOTLIGHT", true, "Light");
        relationFields.push_back(entitySkeleton);
        relationFields.push_back(targetPrimary0);
        relationFields.push_back(targetPrimary1);
        relationFields.push_back(targetPrimary2);
        relationFields.push_back(spot);
        relationFields.push_back(spotInner);
        relationFields.push_back(spotOuter);
        relationFields.push_back(spotFalloff);
    }
    xml::ElementPtr OgreStyleManager::getRoot(DataStreamHolder data)
    {
        //Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(_name, mGroup, true);
        //MyGUI::OgreDataStream* data = new MyGUI::OgreDataStream(stream);
        //"OgreNodes.xml");
        if (data.getData() ==nullptr)
        {
            throw exception("");
        }
        xml::Document doc;
        if (!doc.open(data.getData()))
        {
            throw exception("");
        }
        xml::ElementPtr root =doc.getRoot();
        if ((nullptr == root) || (root->getName() != "OgreResource"))
        {
            throw exception("");
        }
        returnroot;
    }
}
OgreStyleManager

通过这个类,我们知道,一个OgreStyle对应多个NodeStyle,就如Entity分别显示Entiy, SceneNode, MovableObject 这三个节点,每个节点NodeStyle又包含多个OgreField,就如SceneManager包含name,typename,ambientLight等字段.上面的RelationVisible主要是指二个字段有主从关系的那种,如上面是聚光灯才显示一些聚光灯的信息,后面也会放入XML文件中.

然后就是OgreQuery,这个类比较复杂,在这我们只列出一个方法,就是得到我们现在树型控件上的数据.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第11张
    OgreStyle*OgreQuery::getTLRoot()
    {
        ogreRoot = shared_ptr<OgreStyle>(newOgreStyle());
        auto ogreSceneRoot = newOgreStyle();
        auto scene =Ogre::Root::getSingleton().getSceneManager(DSceneName);
        ogreSceneRoot->type =ResourceEnum::SceneType::Scene;
        ogreSceneRoot->ogreName = scene->getName();
        ogreRoot->add(ogreSceneRoot);
        auto factorys =Ogre::Root::getSingleton().getMovableObjectFactoryIterator();
        while(factorys.hasMoreElements())
        {
            auto currentFactory =factorys.getNext();
            OgreStyle* factory = newOgreStyle();
            factory->ogreName = currentFactory->getType();
            factory->type =ResourceEnum::SceneType::MovableObject;
            ogreSceneRoot->add(factory);
            auto movables = scene->getMovableObjectIterator(factory->ogreName);
            while(movables.hasMoreElements())
            {
                auto currentMovable =movables.getNext();
                OgreStyle* movable = newOgreStyle();
                movable->ogreName = currentMovable->getName();
                int type = OgreStyleManager::getInstance().getOgreStyleType(currentMovable->getMovableType(),
                    ResourceEnum::MovableType::MovableOther);
                movable->type =type;
                factory->add(movable);
                if (type ==ResourceEnum::MovableType::Entity)
                {
                    Ogre::Entity* entity = dynamic_cast<Ogre::Entity*>(currentMovable);
                    if (MyGUI::utility::startWith(movable->ogreName, "Unnamed"))
                    {
                        movable->ogreText = entity->getMesh()->getName();
                    }
                    int subCount = entity->getNumSubEntities();
                    for (int i = 0; i < subCount; i++)
                    {
                        auto subEntity = entity->getSubEntity(i);
                        OgreStyle* subStyle = newOgreStyle();
                        movable->add(subStyle);
                        getRenderable(subEntity, subStyle, ResourceEnum::RenderType::RenderSubEntity, i);
                    }
                }
            }
        }
        auto ogreRenderRoot = newOgreStyle();
        ogreRoot->add(ogreRenderRoot);
        auto render =Ogre::Root::getSingleton().getRenderSystem();
        getRenderSystem(render, ogreRenderRoot);
        return ogreRoot.get();
    }
getTLRoot

这个类现在设计了二种显示方式,一种是上面的这种,不显示SceneNode,还有一种是显示SceneNode,这里就不放出来了,和上面这个方法差不多.

自动生成界面

第二部分全是UI显示部分,主要是控件显示分类,控件创建,显示,更新.

我们把我们要的控件分成如下几种显示方式,大部分是从MyGUI中的LayoutEditor中修改后直接使用.

1.PropertyFieldLabel:主要是显示一个文本,主要用于表示分组.

2.PropertyFieldEditBox:显示一个文本与一个值,一般用来设定字符串,如Technique象的名称.

3.PropertyFieldColour:颜色选择.对应对象的颜色.

4.PropertyFieldCheckBox:对应Bool类型,是或否.

5.PropertyFieldComboBox:对应多项选择,如Ogre常见的Enum,对光源类型,对应NodeField.xml文件中的type="ComboBox",这种type一般后面会有一个key的属性,用于去KeyItem.xml查找对应的多项显示,如光源类型对应的点光源,方向光源,聚光灯这些.

6.PropertyFieldAutoComplete:自定义MyGUI控件AutoComplete的包装,用于项非常多的时候,如天龙中,一个场景中Mesh与Material,一般成百上千的,下拉框根本显示不过来,AutoComplete能根据输入给出最适合的选择.后面会专门写一篇针对MyGUI各控件的扩展.

7.PropertyFieldNumeric:对应各type有n int,n float,用于检查输入是否合法.

其中PropertyFieldManager用于管理这些类,我们先看这个类的实现.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第13张
namespacetools
{
    classPropertyFieldManager :
        public MyGUI::Singleton<PropertyFieldManager>
    {
    public:
        PropertyFieldManager();
        virtual ~PropertyFieldManager();
        voidinitialise();
        voidshutdown();
        IPropertyField* createPropertyField(MyGUI::Widget* _window, const std::string&_type);
    private:
        typedef MyGUI::delegates::CDelegate2<IPropertyField*&, MyGUI::Widget*>Delegate;
        typedef std::map<std::string, Delegate>MapFactoryItem;
        MapFactoryItem mFactories;
    };
}
template <> tools::PropertyFieldManager* MyGUI::Singleton<tools::PropertyFieldManager>::msInstance =nullptr;
template <> const char* MyGUI::Singleton<tools::PropertyFieldManager>::mClassTypeName = "PropertyFieldManager";
namespacetools
{
    template <typename Type>
    classGenericFactory
    {
    public:
        typedef MyGUI::delegates::CDelegate2<IPropertyField*&, MyGUI::Widget*>Delegate;
        static typename Delegate::IDelegate*getFactory()
        {
            returnMyGUI::newDelegate(createFromFactory);
        }
    private:
        static void createFromFactory(IPropertyField*& _instance, MyGUI::Widget*_parent)
        {
            _instance = newType(_parent);
        }
    };
    PropertyFieldManager::PropertyFieldManager()
    {
    }
    PropertyFieldManager::~PropertyFieldManager()
    {
    }
    voidPropertyFieldManager::initialise()
    {
        mFactories["EditBox"] = GenericFactory<PropertyFieldEditBox>::getFactory();
        mFactories["Label"] = GenericFactory<PropertyFieldLabel>::getFactory();
        mFactories["Colour"] = GenericFactory<PropertyFieldColour>::getFactory();
        mFactories["Bool"] = GenericFactory<PropertyFieldCheckBox>::getFactory();
        mFactories["ComboBox"] = GenericFactory<PropertyFieldComboBox>::getFactory();
        mFactories["Auto"] = GenericFactory<PropertyFieldAutoComplete>::getFactory();
        mFactories["StaticEditBox"] = GenericFactory<PropertyFieldStaticEditBox>::getFactory();
        mFactories["1 int"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["2 int"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["4 int"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["1 float"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["2 float"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["3 float"] = GenericFactory<PropertyFieldNumeric>::getFactory();
        mFactories["4 float"] = GenericFactory<PropertyFieldNumeric>::getFactory();
    }
    voidPropertyFieldManager::shutdown()
    {
    }
    IPropertyField* PropertyFieldManager::createPropertyField(MyGUI::Widget* _window, const std::string&_type)
    {
        IPropertyField* result =nullptr;
        MapFactoryItem::iterator item =mFactories.find(_type);
        MYGUI_ASSERT(item != mFactories.end(), "Factory PropertyField '" << _type << "' not found.");
        (*item).second(result, _window);
        result->initialise(_type);
        returnresult;
    }
}
PropertyFieldManager

PropertyFieldManager主要是根据不同的NodeField.xml中NodeField中的Type来生成对应IPropertyField.IPropertyField是上面各字段控件的基类,我们来看下他的实现,了解所有字段控件实现能那些功能.对比Mygui中的LayoutEditor中的IPropertyField有些改动主要一是为了让IPropertyField承载更多公共实现,免的子类型的各部分代码差不多.二是更好的适合我们自己的项目,针对Ogre的各属性更改.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第15张
using namespaceOgre3DX;
namespacetools
{
    typedef MyGUI::delegates::CDelegate3<const std::string&, const std::string&, bool>PropertyFieldActionDelegate;
    classIPropertyField
    {
    public:
        virtual ~IPropertyField();
        virtual void initialise(const std::string&_type);
        virtual void setValue(const std::string& _value) = 0;
        //Relation Field
        virtual stringgetValue();
        virtual voidonFillValues();
        virtual void setField(OgreField*_field);
        virtual OgreField*getField();
        //Update Field
        virtual boolgetFocus();
        virtual void setName(const std::string&_value);
        virtual void setVisible(bool_value);
        virtual boolgetVisible();
        virtual void onAction(const std::string& _value, bool_final);
        virtual boolonCheckValue();
        virtualMyGUI::IntSize getContentSize();
        virtual void setCoord(const MyGUI::IntCoord&_coord);
        virtual bool checkFocus(MyGUI::Widget*widget);
        PropertyFieldActionDelegate eventAction;
    protected:
        MyGUI::TextBox* mText =nullptr;
        std::stringmType;
        std::stringmName;
        OgreField* field =nullptr;
        MyGUI::Widget* mainWidget =nullptr;
    };
}
namespacetools
{
    IPropertyField::~IPropertyField()
    {
    }
    void IPropertyField::initialise(const std::string&_type)
    {
        mType =_type;
    }
    stringIPropertyField::getValue()
    {
        return "";
    }
    voidIPropertyField::onFillValues()
    {
    }
    void IPropertyField::setField(OgreField*_field)
    {
        field =_field;
        onFillValues();
    }
    OgreField*IPropertyField::getField()
    {
        returnfield;
    }
    boolIPropertyField::getFocus()
    {
        //InputManager::getInstance().getKeyFocusWidget();
        return false;
    }
    bool IPropertyField::checkFocus(MyGUI::Widget*widget)
    {
        auto mouseF =MyGUI::InputManager::getInstance().getMouseFocusWidget();
        if (mouseF ==widget)
            return true;
        auto keyF =MyGUI::InputManager::getInstance().getKeyFocusWidget();
        if (keyF ==widget)
            return true;
        return false;
    }
    void IPropertyField::onAction(const std::string& _value, bool_final)
    {
        eventAction(field->fieldName, _value, _final);
    }
    boolIPropertyField::onCheckValue()
    {
        return true;
    }
    MyGUI::IntSize IPropertyField::getContentSize()
    {
        return MyGUI::IntSize(0, mainWidget->getHeight());
    }
    void IPropertyField::setCoord(const MyGUI::IntCoord&_coord)
    {
        mainWidget->setCoord(_coord);
    }
    void IPropertyField::setName(const std::string&_value)
    {
        mName =_value;
        mText->setCaption(_value);
    }
    void IPropertyField::setVisible(bool_value)
    {
        mainWidget->setVisible(_value);
    }
    boolIPropertyField::getVisible()
    {
        return mainWidget->getVisible();
    }
}
IPropertyField

可以看到IPropertyField与第一部分中的OgreField是一一对应的,拿一些方法说下.

1.initialise():子类主要根据对应的Layout文件生成各个控件.在这主要把BaseLayout中的mMainWidget给IPropertyField中的mainWidget,这样子类就不需要每个来实现getVisible,setVisible,getContentSize,setCoord就不需要子类型去实现了.

2.setValue,getValue:设置和得到IPropertyField控件中的值.

3.setField,getField:设置和得到对应的OgreField.

4.getFocus:检查当前IPropertyField是否在得到鼠标或键盘的焦点.如果是,我们不去更新上面的值.

5.onAction:当我们更新IPropertyField中的值后,我们需要通知事件上的各个方法.

如下是PropertyFieldComboBox的具体实现,这个类可以让我们更好理解相关方法需要如何实现.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第17张
namespacetools
{
    classPropertyFieldComboBox :
        publicwraps::BaseLayout,
        publicIPropertyField
    {
    public:
        PropertyFieldComboBox(MyGUI::Widget*_parent);
        virtual ~PropertyFieldComboBox();
        virtual void setValue(const std::string&_value);
        virtual stringgetValue();
    protected:
        virtual voidonFillValues();
    private:
        void notifyApplyProperties(MyGUI::Widget*_sender);
        void notifyForceApplyProperties2(MyGUI::ComboBox*_widget, size_t _index);
    protected:
        MyGUI::ComboBox*mField;
    };
}
namespacetools
{
    PropertyFieldComboBox::PropertyFieldComboBox(MyGUI::Widget*_parent) :
        BaseLayout("PropertyFieldComboBox.layout", _parent),
        mField(nullptr)
    {
        assignWidget(mText, "Text");
        assignWidget(mField, "Field");
        mainWidget =mMainWidget;
        mField->eventComboAccept += newDelegate(this, &PropertyFieldComboBox::notifyForceApplyProperties2);
    }
    PropertyFieldComboBox::~PropertyFieldComboBox()
    {
    }
    voidPropertyFieldComboBox::onFillValues()
    {
        if (field == nullptr || field->fieldKey.empty())
            return;
        mField->removeAllItems();
        auto items = OgreStyleManager::getInstance().getKeyItems(field->fieldKey);
        for(auto item : items)
        {
            mField->addItem(item);
        }
    }
    void PropertyFieldComboBox::notifyApplyProperties(MyGUI::Widget*_sender)
    {
        std::string value = MyGUI::utility::toString(mField->getIndexSelected());//mField->getOnlyText();
        onAction(value, true);
    }
    void PropertyFieldComboBox::notifyForceApplyProperties2(MyGUI::ComboBox*_sender, size_t _index)
    {
        notifyApplyProperties(_sender);
    }
    void PropertyFieldComboBox::setValue(const std::string&_value)
    {
        int index =MyGUI::utility::parseInt(_value);
        if (index >= 0 && index < mField->getItemCount())
            mField->setItemSelect(index);
        //mField->setOnlyText(_value);
}
    stringPropertyFieldComboBox::getValue()
    {
        return mField->getOnlyText();
    }
}
PropertyFieldComboBox

当我们知道如何根据OgreField生成IPropertyField后,如前面一个OgreStyle对应多个NodeStyle,每个节点NodeStyle又包含多个OgreField.对应PropertiesPanelView包含多个PanelProperties.每个PanelProperties又包含多个IPropertyField.

当PropertiesPanelView得到OgreStyle后,根据OgreStyle的NodeStyle生成PanelProperties,然后PanelProperties根据对应的NodeStyle中的OgreField 生成IPropertyField.这样OgreStyle需要的各个控件显示出来了,如下是相关PropertiesPanelView与PanelProperties代码.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第19张
namespacetools
{
    classPropertiesPanelView :
        publicwraps::BaseLayout
    {
    public:
        PropertiesPanelView(MyGUI::Widget* _parent =nullptr);
        virtual ~PropertiesPanelView();
        void notifyChangeSelectedWidget(OgreStyle*data);
        voidhideAllPanel();
    private:
        void notifyWindowChangeCoord(MyGUI::Window*_sender);
        std::vector<PanelProperties*> getPropertyWindow(OgreStyle*_style);
        size_t getIndexPanel(PanelProperties*_panel);
        void onRefleshFiled(floattime);
    private:
        MyGUI::IntSize mOldSize;
        PanelView*mPanelView;
        typedef std::map<string, PanelProperties*>MapPropertyWindow;
        MapPropertyWindow mMapPropertyWindow;
        OgreStyle*currentStyle;
    };
}
namespacetools
{
    PropertiesPanelView::PropertiesPanelView(MyGUI::Widget*_parent) :
        BaseLayout("PropertiesPanelView.layout", _parent),
        mPanelView(nullptr),
        currentStyle(nullptr)
    {
        assignBase(mPanelView, "scroll_View");
        MyGUI::Window* window = mMainWidget->castType<MyGUI::Window>(false);
        if (window !=nullptr)
        {
            window->eventWindowChangeCoord += MyGUI::newDelegate(this, &PropertiesPanelView::notifyWindowChangeCoord);
            mOldSize = window->getSize();
        }
        notifyChangeSelectedWidget(nullptr);
        Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &PropertiesPanelView::onRefleshFiled);
    }
    PropertiesPanelView::~PropertiesPanelView()
    {
        mPanelView->removeAllItems();
        for (MapPropertyWindow::iterator item = mMapPropertyWindow.begin(); item != mMapPropertyWindow.end(); ++item)
            delete (*item).second;
        mMapPropertyWindow.clear();
    }
    void PropertiesPanelView::notifyWindowChangeCoord(MyGUI::Window*_sender)
    {
        const MyGUI::IntSize& size = _sender->getSize();
        if (size !=mOldSize)
        {
            mOldSize =size;
            mPanelView->setNeedUpdate();
        }
    }
    void PropertiesPanelView::notifyChangeSelectedWidget(OgreStyle*_currentStyle)
    {
        currentStyle =_currentStyle;
        for (MapPropertyWindow::iterator item = mMapPropertyWindow.begin(); item != mMapPropertyWindow.end(); ++item)
        {
            (*item).second->setVisible(false);
            (*item).second->setStyle(nullptr, nullptr);
            (*item).second->update();
        }
        if (currentStyle ==nullptr)
            return;
        auto panels =getPropertyWindow(currentStyle);
        for(auto panel : panels)
        {
            panel->setVisible(true);
            panel->update();
        }
    }
    voidPropertiesPanelView::hideAllPanel()
    {
        for (MapPropertyWindow::iterator item = mMapPropertyWindow.begin(); item != mMapPropertyWindow.end(); ++item)
        {
            (*item).second->setVisible(false);
            (*item).second->setStyle(nullptr, nullptr);
            (*item).second->update();
        }
    }
    std::vector<PanelProperties*> PropertiesPanelView::getPropertyWindow(OgreStyle*_style)
    {
        std::vector<PanelProperties*>result;
        auto nodeStyles = OgreStyleManager::getInstance().getNodeStyles(_style->type);
        for(auto nodeStyle : nodeStyles)
        {
            if (nodeStyle == nullptr || nodeStyle->nodeName.empty())
                continue;
            std::string key = MyGUI::utility::toString(_style->type) + nodeStyle->nodeName;
            MapPropertyWindow::iterator item =mMapPropertyWindow.find(key);
            if (item ==mMapPropertyWindow.end())
            {
                PanelProperties* panel = newPanelProperties();
                mPanelView->addItem(panel);//insertItem(getIndexByDepth(_depth), result);
                mMapPropertyWindow[key] =panel;
            }
            mMapPropertyWindow[key]->setStyle(_style, nodeStyle);
            result.push_back(mMapPropertyWindow[key]);
        }
        returnresult;
    }
    size_t PropertiesPanelView::getIndexPanel(PanelProperties*_panel)
    {
        for (size_t index = 0; index < mPanelView->getItemCount(); ++index)
        {
            if (mPanelView->getItem(index) ==_panel)
                returnindex;
        }
        returnMyGUI::ITEM_NONE;
    }
    void PropertiesPanelView::onRefleshFiled(floattime)
    {
        for (auto item = mMapPropertyWindow.begin(); item != mMapPropertyWindow.end(); ++item)
        {
            if ((*item).second->getVisible())
            {
                (*item).second->onReflesh();
            }
        }
    }
}
PropertiesPanelView
Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第21张
using namespaceOgre3DX;
namespacetools
{
    typedef std::vector<std::pair<std::string, IPropertyField*>>MapPropertyField;
    typedef MapPropertyField::iterator FieldIter;
    classPanelProperties :
        publicwraps::BasePanelViewItem
    {
    public:
        PanelProperties();
        virtual voidinitialise();
        virtual voidshutdown();
        void setStyle(OgreStyle* ogreStyle, NodeStyle*nodeStyle);
        voidupdate();
        voidonReflesh();
    private:
        void notifyAction(const std::string& _name, const std::string& _value, bool_final);
        size_t addParametrs();
        voiddestroyPropertyFields();
        voidhidePropertyFields();
        voidupdateSize();
        voidupdateRelationFields();
        IPropertyField* getPropertyField(MyGUI::Widget* _client, OgreField*field);
        FieldIter getField(const std::string&name);
    private:
        //typedef std::map<std::string, IPropertyField*> MapPropertyField;
MapPropertyField mFields;
        OgreStyle* currentOgreStyle =nullptr;
        NodeStyle* currentNodeStyle =nullptr;
    };
}
namespacetools
{
    PanelProperties::PanelProperties() :
        BasePanelViewItem("PanelProperties.layout")
    {
    }
    voidPanelProperties::initialise()
    {
    }
    voidPanelProperties::shutdown()
    {
        destroyPropertyFields();
    }
    size_t PanelProperties::addParametrs()
    {
        size_t result = 0;
        if (currentNodeStyle !=nullptr)
        {
            auto fields = OgreStyleManager::getInstance().getFieldVector(currentNodeStyle->nodeName);
            for (auto iter = fields.begin(); iter != fields.end(); ++iter)
            {
                IPropertyField* field = getPropertyField(mWidgetClient, (*iter));
                field->setField(*iter);
                field->setValue("");
                result++;
            }
        }
        returnresult;
    }
    void PanelProperties::setStyle(OgreStyle* ogreStyle, NodeStyle*nodeStyle)
    {
        currentOgreStyle =ogreStyle;
        currentNodeStyle =nodeStyle;
    }
    voidPanelProperties::update()
    {
        hidePropertyFields();
        if (currentNodeStyle !=nullptr)
            mPanelCell->setCaption(currentNodeStyle->getText());
        size_t count =addParametrs();
        setVisible(count > 0);
        onReflesh();
        updateSize();
        updateRelationFields();
    }
    voidPanelProperties::onReflesh()
    {
        for (MapPropertyField::iterator item = mFields.begin(); item != mFields.end(); ++item)
        {
            auto fieldLayout = (*item).second;
            if (fieldLayout->getVisible() && !fieldLayout->getFocus())
            {
                auto field = fieldLayout->getField();
                if (field->fieldManual)
                    continue;
                if (currentOgreStyle != nullptr && currentNodeStyle != nullptr && field !=nullptr)
                {
                    int type = OgreStyleManager::getInstance().getOgreStyleType(currentNodeStyle->nodeName);
                    if (type != 0)
                    {
                        auto text = OgreManager::getInstance().getValue(currentOgreStyle, type, field->fieldName);
                        fieldLayout->setValue(text);
                    }
                }
            }
        }
    }
    voidPanelProperties::updateSize()
    {
        int height = 0;
        for (MapPropertyField::iterator item = mFields.begin(); item != mFields.end(); ++item)
        {
            if ((*item).second->getVisible())
            {
                MyGUI::IntSize size = (*item).second->getContentSize();
                (*item).second->setCoord(MyGUI::IntCoord(0, height, mMainWidget->getWidth(), size.height));
                height +=size.height;
            }
        }
        mPanelCell->setClientHeight(height);
    }
    voidPanelProperties::updateRelationFields()
    {
        if (currentNodeStyle ==nullptr)
            return;
        RelationVector rfs = OgreStyleManager::getInstance().getRelationFields(currentNodeStyle->nodeName);
        if (rfs.size() == 0)
            return;
        bool change = false;
        for(auto rf : rfs)
        {
            auto source = getField(rf->name);
            auto dest = getField(rf->relationName);
            if (source != mFields.end() && dest !=mFields.end())
            {
                auto nowValue = (*dest).second->getValue();
                bool nowVisable = (*source).second->getVisible();
                if ((nowValue == rf->relationValue) != (nowVisable == rf->relationVisible))
                {
                    change = true;
                    (*source).second->setVisible(!nowVisable);
                }
            }
        }
        if(change)
        {
            updateSize();
        }
    }
    voidPanelProperties::destroyPropertyFields()
    {
        for (MapPropertyField::iterator item = mFields.begin(); item != mFields.end(); ++item)
            delete (*item).second;
        mFields.clear();
    }
    void PanelProperties::notifyAction(const std::string& _name, const std::string& _value, bool_final)
    {
        //if (currentOgreStyle != nullptr)
        //{
        //currentOgreStyle->setValue(_name, _value);
        //}
        if (currentOgreStyle != nullptr && currentNodeStyle !=nullptr)
        {
            int type = OgreStyleManager::getInstance().getOgreStyleType(currentNodeStyle->nodeName);
            if (type != 0)
            {
                OgreManager::getInstance().setValue(currentOgreStyle, type, _name, _value);
            }
        }
        updateRelationFields();
    }
    voidPanelProperties::hidePropertyFields()
    {
        for (MapPropertyField::iterator item = mFields.begin(); item != mFields.end(); ++item)
            (*item).second->setVisible(false);
    }
    FieldIter PanelProperties::getField(const std::string&name)
    {
        for (auto i = mFields.begin(); i != mFields.end(); ++i)
        {
            if ((*i).first ==name)
                returni;
        }
        returnmFields.end();
    }
    IPropertyField* PanelProperties::getPropertyField(MyGUI::Widget* _client, OgreField*field)
    {
        MapPropertyField::iterator item = getField(field->fieldName);
        if (item !=mFields.end())
        {
            (*item).second->setVisible(true);
            return (*item).second;
        }
        IPropertyField* result = PropertyFieldManager::getInstance().createPropertyField(_client, field->fieldType);
        result->setName(field->getText());
        result->eventAction = MyGUI::newDelegate(this, &PanelProperties::notifyAction);
        //mFields[_name] = result;
        mFields.push_back(std::make_pair(field->fieldName, result));
        returnresult;
    }
}
PanelProperties

这样第二部分就把XML与控件生成关联起来了,下面是第三部分,主要管理控件更新.

Oger对象驱动更新界面

最开始我这边的处理是OgreStyle里关联一个Ogre对象,如OgreStyle中的type是Camera,就关联一个Ogre中的Camera对象,这样相应更新就直接根据这个对象来处理,不过后面没有这样处理,主要是如下考虑,一是OgreStyle被太多类引用,最好不要过于复杂,首先更新必然会修改到更多类,其次在C++中更新这种很多类引用的文件编译都要等死个人.二是我们的需求,如前面所说Entity类型的OgreStyle需要更新Entity的属性,也可能是MovableObject或SceneNode,这样绑定OgreStyle与Ogre对象后,并不好处理这种情况,因为并不是一对一,根据修改的Field的名字来查找对应的NodeStyle并不是一个好的选择.基于上面考虑,放弃这种想法.

我们仔细想一下,应该是每一种type一种更新方式,并不和OgreStyle有关,而是和OgreStyle中的type有关,如OgreStyle为Entity,但是type可能是Entiyt,MovableObject,SceneNode这三种,我们可以根据type查找如何更新Ogre对象各字段的方法,然后根据OgreStyle的Ogrename找到对象.如下是代码:

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第23张
namespaceOgre3DX
{
    classOgreManager :
        public tools::Singleton<OgreManager>
    {
    public:
        OgreManager()
        {
            mapObject[ResourceEnum::ResourceType::Resource] = newOgreResource();
            mapObject[ResourceEnum::ResourceType::Material] = newOgreMaterial();
            mapObject[ResourceEnum::ResourceType::Technique] = newOgreTechnique();
            mapObject[ResourceEnum::ResourceType::Pass] = newOgrePass();
            mapObject[ResourceEnum::SceneType::Viewport] = newOgreViewport();
            mapObject[ResourceEnum::SceneType::SceneNode] = newOgreSceneNode();
            mapObject[ResourceEnum::SceneType::MovableObject] = newOgreMovableObject();
            mapObject[ResourceEnum::SceneType::RenderTarget] = newOgreRenderTarget();
            mapObject[ResourceEnum::SceneType::Camera] = newOgreCamera();
            mapObject[ResourceEnum::SceneType::Renderable] = newOgreRenderable();
            mapObject[ResourceEnum::SceneType::Scene] = newOgreSceneManager();
            mapObject[ResourceEnum::MovableType::Entity] = newOgreEntity();
            mapObject[ResourceEnum::MovableType::Light] = newOgreLight();
            scene =Ogre::Root::getSingleton().getSceneManager(DSceneName);
        }
        std::string OgreManager::getValue(OgreStyle* style, int type, const string&field)
        {
            OgreBasic* basic =getObject(style, type);
            if (basic != nullptr && basic->getObject() !=nullptr)
            {
                return basic->getValue(field);
            }
            return "";
        }
        bool OgreManager::setValue(OgreStyle* style, int type, const string& field, const string&value)
        {
            OgreBasic* basic =getObject(style, type);
            if (basic != nullptr && basic->getObject() !=nullptr)
            {
                return basic->setValue(field, value);
            }
            return false;
        }
        OgreBasic* getObject(OgreStyle* style, inttype)
        {
            auto object =getType(type);
            if (object ==nullptr)
                returnnullptr;
            //重新设置ogre值.
            if (style != preStyle || type !=preType)
            {
                fillStyleObject(style, type);
                preStyle =style;
                preType =type;
            }
            return object;
        }
        OgreBasic* getType(inttype)
        {
            if (mapObject.find(type) !=mapObject.end())
            {
                returnmapObject[type];
            }
            returnnullptr;
        }
        void fillStyleObject(OgreStyle* style, inttype)
        {
            auto object =getType(type);
            if (object ==nullptr)
                return;
            switch (style->type)
            {
            caseResourceEnum::SceneType::Scene:
                if (true)
                {
                    if (type ==ResourceEnum::SceneType::Scene)
                    {
                        object->setObject(scene);
                    }
                    else if (type ==ResourceEnum::SceneType::Viewport)
                    {
                        object->setObject(scene->getCurrentViewport());
                    }
                }
                break;
            caseResourceEnum::MovableType::Entity:
                if (true)
                {
                    auto entity = scene->getEntity(style->ogreName);
                    if (type ==ResourceEnum::MovableType::Entity)
                    {
                        object->setObject(entity);
                    }
                    fillMovableable(object, entity, type);
                }
                break;
            caseResourceEnum::ResourceType::Material:
                if (true)
                {
                    auto mat = MaterialManager::getSingleton().getByName(style->ogreName);
                    fillMaterial(object, mat, type);
                }
                break;
            caseResourceEnum::RenderType::RenderSubEntity:
                if (style->parent != nullptr && style->parent->type ==ResourceEnum::MovableType::Entity)
                {
                    auto entity = scene->getEntity(style->parent->ogreName);
                    int index = Ogre::StringConverter::parseInt(style->ogreName);
                    auto subEntity = entity->getSubEntity(index);
                    fillRenderable(object, subEntity, type);
                }
                break;
            caseResourceEnum::SceneType::RenderTarget:
                if (true)
                {
                    auto render =Ogre::Root::getSingleton().getRenderSystem();
                    auto target = render->getRenderTarget(style->ogreName);
                    if (type ==ResourceEnum::SceneType::RenderTarget)
                    {
                        object->setObject(target);
                    }
                }
                break;
            caseResourceEnum::SceneType::Viewport:
                if (true)
                {
                    RenderSystem* render =Ogre::Root::getSingleton().getRenderSystem();
                    if (style->parent != nullptr && style->parent->type ==ResourceEnum::SceneType::RenderTarget)
                    {
                        auto target = render->getRenderTarget(style->parent->ogreName);
                        int index = Ogre::StringConverter::parseInt(style->ogreName);
                        auto viewport = target->getViewport(index);
                        auto camera = viewport->getCamera();
                        if (type ==ResourceEnum::SceneType::Viewport)
                        {
                            object->setObject(viewport);
                        }
                        else if (camera !=nullptr)
                        {
                            fillCamera(object, camera, type);
                        }
                    }
                }
                break;
            caseResourceEnum::SceneType::Camera:
                if (true)
                {
                    auto camera = scene->getCamera(style->ogreName);
                    if (camera !=nullptr)
                    {
                        fillCamera(object, camera, type);
                    }
                }
                break;
            caseResourceEnum::MovableType::Light:
                if (true)
                {
                    auto light = scene->getLight(style->ogreName);
                    if (type ==ResourceEnum::MovableType::Light)
                    {
                        object->setObject(light);
                    }
                    fillMovableable(object, light, type);
                }
                break;
            default:
                break;
            }
        }
        void fillCamera(OgreBasic* object, Camera* camera, inttype)
        {
            if (type ==ResourceEnum::SceneType::Camera)
            {
                object->setObject(camera);
            }
            else if (type ==ResourceEnum::SceneType::MovableObject)
            {
                object->setObject(camera);
            }
            else if (type ==ResourceEnum::SceneType::Renderable)
            {
                object->setObject(camera);
            }
        }
        void fillRenderable(OgreBasic* object, Renderable* render, inttype)
        {
            if (type ==ResourceEnum::SceneType::Renderable)
            {
                object->setObject(render);
            }
            else if (type ==ResourceEnum::ResourceType::Material)
            {
                object->setObject(render->getMaterial().get());
            }
            else if (type ==ResourceEnum::ResourceType::Technique)
            {
                auto tech = render->getTechnique();
                object->setObject(tech);
            }
            else if (type ==ResourceEnum::ResourceType::Pass)
            {
                auto pass = render->getTechnique()->getPass(0);
                object->setObject(pass);
            }
        }
        void fillMaterial(OgreBasic* object, MaterialPtr material, inttype)
        {
            if (type ==ResourceEnum::ResourceType::Material)
            {
                object->setObject(material.get());
            }
            else if (type ==ResourceEnum::ResourceType::Resource)
            {
                object->setObject(material.get());
            }
            else if (type ==ResourceEnum::ResourceType::Technique)
            {
                auto tech = material->getBestTechnique();
                if (tech ==nullptr)
                {
                    tech = material->getTechnique(0);
                }
                object->setObject(tech);
            }
            else if (type ==ResourceEnum::ResourceType::Pass)
            {
                auto tech = material->getBestTechnique();
                if (tech ==nullptr)
                {
                    tech = material->getTechnique(0);
                }
                object->setObject(tech->getPass(0));
            }
        }
        void fillMovableable(OgreBasic* object, MovableObject* movable, inttype)
        {
            if (type ==ResourceEnum::SceneType::MovableObject)
            {
                object->setObject(movable);
            }
            else if (type ==ResourceEnum::SceneType::SceneNode)
            {
                object->setObject(movable->getParentSceneNode());
            }
        }
        ~OgreManager()
        {
        }
    private:
        std::map<int, OgreBasic*>mapObject;
        //OgreBasic* pre
        OgreStyle* preStyle =nullptr;
        int preType = 0;
        SceneManager* scene =nullptr;
    };
}
OgreManager

其中OgreBasic是所有ogre对象更新类的基类,OgreTemplate是一个泛型类,提供一些方便.如下代码:

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第25张
using namespaceOgre;
typedef Ogre::StringConverter format;
namespaceOgre3DX
{
    classOgreBasic
    {
    public:
        virtual std::string getValue(std::string field) = 0;
        virtual bool setValue(std::string field, std::string value) = 0;
        virtual void setObject(void* object){};
        virtual void* getObject(){ returnnullptr; }
    };
    template<typename T>
    classOgreTemplate
        : publicOgreBasic
    {
    public:
        OgreTemplate()
        {
        }
        virtual ~OgreTemplate(){};
        virtual std::string getValue(std::stringfield)
        {
            return "";
        }
        virtual bool setValue(std::string field, std::stringvalue)
        {
            return false;
        }
        virtual void setObject(T* object)
        {
            ogreObject = object;
        }
        virtual T*getOgreObject()
        {
            returnogreObject;
        }
    protected:
        virtual void setObject(void* object)
        {
            return setObject((T*)object);
        }
        virtual void*getObject()
        {
            if (ogreObject ==nullptr)
                returnnullptr;
            return (void*)ogreObject;
        }
    protected:
        T* ogreObject =nullptr;
    };
}
OgreBasic OgreTemplate

其中OgreBasic是根据字段名得到对应Ogre属性的值,setValue是对某个字段赋值,setObject是传入相关Ogre对象指针,getObject是返回某对象指针,而OgreTemplate主要给我们提供一些方便,如上面都是void*指针,在C#中相当于object一样,需要强制转化后才能用,这个OgreTemplate自动帮我们做这些事件,基于最少可见原则,在OgreTemplate我们把父类中的setObject与getObject隐藏,我们并不希望用OgreTemplate泛型类后还在使用对应void*指针,这样可以避免很多不安全的问题.而OgreBasic本身是给OgreManager使用,在这个类中,会保证生成正确的OgreTemplate,传入正确的Ogre对象指针.

在这我们给出OgreSceneManager的一个OgreTemplate泛型具体化实现.

Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第4张Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)第27张
namespaceOgre3DX
{
    classOgreSceneManager :
        public OgreTemplate<Ogre::SceneManager>
    {
    private:
        Plane* plane =nullptr;
        std::string planeMaterial = "";
        FogMode fogMode =FogMode::FOG_NONE;
        ColourValue fogColor =ColourValue::White;
        Real fogDensity = 0.001;
        Real fogStart = 0.0;
        Real fogEnd = 1.0;
    public:
        OgreSceneManager()
        {
            plane = new Plane(0, -1, 0, 5000);
        }
        ~OgreSceneManager()
        {
            if (plane !=nullptr)
            {
                deleteplane;
                plane =nullptr;
            }
        }
        virtual std::string getValue(std::stringfield)
        {
            std::string result = "";
            if (field == "Name")
            {
                result = ogreObject->getName();
            }
            else if (field == "TypeName")
            {
                result = ogreObject->getTypeName();
            }
            else if (field == "AmbientLight")
            {
                result = format::toString(ogreObject->getAmbientLight());
            }
            else if (field == "PlaneEnable")
            {
                result = format::toString(ogreObject->isSkyPlaneEnabled());
            }
            else if (field == "Plane")
            {
                Vector4 vp(plane->normal.x, plane->normal.y, plane->normal.z, plane->d);
                result =format::toString(vp);
            }
            else if (field == "BoxEnable")
            {
                result = format::toString(ogreObject->isSkyBoxEnabled());
            }
            else if (field == "DomeEnable")
            {
                result = format::toString(ogreObject->isSkyDomeEnabled());
            }
            else if (field == "FogMode")
            {
                result = format::toString(ogreObject->getFogMode());
            }
            else if (field == "FogColour")
            {
                result = format::toString(ogreObject->getFogColour());
            }
            else if (field == "FogStart")
            {
                result = format::toString(ogreObject->getFogStart());
            }
            else if (field == "FogEnd")
            {
                result = format::toString(ogreObject->getFogEnd());
            }
            else if (field == "FogDensity")
            {
                result = format::toString(ogreObject->getFogDensity());
            }
            else if (field == "ShadowTechnique")
            {
                int index = 0;
                auto st = ogreObject->getShadowTechnique();
                if (st == 0x12)
                {
                    index = 1;
                }
                else if (st == 0x11)
                {
                    index = 2;
                }
                else if (st == 0x22)
                {
                    index = 3;
                }
                else if (st == 0x21)
                {
                    index = 4;
                }
                else if (st == 0x25)
                {
                    index = 5;
                }
                else if (st == 0x26)
                {
                    index = 6;
                }
                result =format::toString(index);
            }
            else if (field == "ShadowColour")
            {
                result = format::toString(ogreObject->getShadowColour());
            }
            else if (field == "ShadowFarDistance")
            {
                result = format::toString(ogreObject->getShadowFarDistance());
            }
            returnresult;
        }
        virtual bool setValue(std::string field, std::stringvalue)
        {
            if (field == "AmbientLight")
            {
                auto ambient =format::parseColourValue(value);
                ogreObject->setAmbientLight(ambient);
            }
            else if (field == "PlaneEnable")
            {
                auto check =format::parseBool(value);
                ogreObject->setSkyPlaneEnabled(check);
            }
            else if (field == "Plane" || field == "PlaneMaterial")
            {
                if (field == "Plane")
                {
                    auto v4 =format::parseVector4(value);
                    plane->normal.x =v4.x;
                    plane->normal.y =v4.y;
                    plane->normal.z =v4.z;
                    plane->d =v4.w;
                }
                else if (field == "PlaneMaterial")
                {
                    planeMaterial =value;
                }
                if (!planeMaterial.empty())
                {
                    ogreObject->setSkyPlane(true, *plane, planeMaterial);
                }
            }
            else if (field == "BoxEnable")
            {
                auto check =format::parseBool(value);
                ogreObject->setSkyBoxEnabled(check);
            }
            else if (field == "DomeEnable")
            {
                auto check =format::parseBool(value);
                ogreObject->setSkyDomeEnabled(check);
            }
            else if (field == "BoxMaterial")
            {
                if (!value.empty())
                {
                    ogreObject->setSkyBox(true, value);
                }
            }
            else if (field == "DomeMaterial")
            {
                if (!value.empty())
                {
                    ogreObject->setSkyDome(true, value);
                }
            }
            if (field == "FogMode" || field == "FogColour" || field == "FogStart" || field == "FogEnd" || field == "FogDensity")
            {
                if (field == "FogMode")
                {
                    fogMode =(FogMode)format::parseInt(value);
                }
                else if (field == "FogColour")
                {
                    fogColor =format::parseColourValue(value);
                }
                else if (field == "FogStart")
                {
                    fogStart =format::parseReal(value);
                }
                else if (field == "FogEnd")
                {
                    fogEnd =format::parseReal(value);
                }
                else if (field == "FogDensity")
                {
                    fogDensity =format::parseReal(value);
                }
                ogreObject->setFog(fogMode, fogColor, fogDensity, fogStart, fogEnd);
            }
            else if (field == "ShadowTechnique")
            {
                int index =format::parseInt(value);
                ShadowTechnique st =(ShadowTechnique)index;
                if (index == 1)
                {
                    st =ShadowTechnique::SHADOWTYPE_STENCIL_MODULATIVE;
                }
                else if (index == 2)
                {
                    st =ShadowTechnique::SHADOWTYPE_STENCIL_ADDITIVE;
                }
                else if (index == 3)
                {
                    st =ShadowTechnique::SHADOWTYPE_TEXTURE_MODULATIVE;
                }
                else if (index == 4)
                {
                    st =ShadowTechnique::SHADOWTYPE_TEXTURE_ADDITIVE;
                }
                else if (index == 5)
                {
                    st =ShadowTechnique::SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED;
                }
                else if (index == 6)
                {
                    st =ShadowTechnique::SHADOWTYPE_TEXTURE_MODULATIVE_INTEGRATED;
                }
                ogreObject->setShadowTechnique(st);
            }
            else if (field == "ShadowColour")
            {
                auto color =format::parseColourValue(value);
                ogreObject->setShadowColour(color);
            }
            else if (field == "ShadowFarDistance")
            {
                auto dist =format::parseReal(value);
                ogreObject->setShadowFarDistance(dist);
            }
            return true;
        }
    };
}
OgreSceneManager

需要注意的是ShadowTechnique里我们KeyItem.xml文件里列出的项并没与Ogre本身的对应,所以需要在这处理一下,如果是正常一一对应的,直接tostring与parseInt后就行. 然后别的Ogre对象分别实现的OgreTemplate泛型具体化类都差不多是这种处理.

回头我们再看PanelProperties中updateRelationFields与notifyAction的处理,前者是每桢根据当前NodeStyle的对应type找到对应的OgreTemplate泛型具体化子类.然后根据当前OgreStyle的OgreName找到对应Ogre对应,然后根据字段,或是更新,更新得到对应OgreTemplate泛型具体化子类中的值.

至于为什么要每桢更新,而不是根据UI操作更新,简单来说,是为了避免BUG产生,如上面我们点击SceneNode的visible为flase后,对应节点下的MovableObject的visible也变成false,如果你不设置对应UI更新,对应的MovableObject上的visible还是显示为true,如果你去更新UI,可以说这样工作量又变大了,有一些你也想不到的关联,这样就等着更新大量的BUG去吧.其实这二种更新方式,对应我们官方的话来说:一个是事件驱动,一个是数据驱动.所以我们也不要以为WPF中的数据驱动是什么高大上的概念,就是因为如这里样WPF关联了控件与对应数据,数据更新后,每桢渲染时,根据数据显示对应UI状态.

如上通过这三个部分,我们实现了控件根据XML自动生成,控件根据Ogre对象自动更新.

当这个方案完成后,我只花了二个晚上的时间就完成了如上图中的Ogre对象的各个UI界面更新,完成不需要更新任何有关UI控件的代码,只要三个步骤就行,一是更新XML文件,二是具体化对应泛型OgreTemplate的实现,三是在OgreManager关联Ogre对象与泛型OgreTemplate就行,在可见的将来,对应的粒子,地形,合成器的编辑都可以用这种方式.

PS 2016.1.12 因为现在这个设计不满足Ogre2.1,暂时没有继续完成下去的欲望,代码放git上免的让别人认为是搞笑,就直接放http://pan.baidu.com/s/1kTWdqnl 这里,vs2013,相应DLL已经组织好,给mygui与ogre新手参考.

免责声明:文章转载自《Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇PPT2010制作充电动画mui 注意事项下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

WinRAR 激活的小办法

WinRAR是一个强大的压缩文件管理工具。它可以备份数据,减少电子邮件附件的大小,解压缩从Internet下载的RAR、ZIP和其他压缩文件,并以RAR和ZIP格式创建压缩文件。如果您使用的正版WinRAR未激活,请将以下注册代码复制到新文档并将其重命名为rarreg。键,然后复制rarreg。键到WinRAR根目录以激活它。...

简谈docker-compose内存控制Java问题

最近,我正在整理docker合成内存的问题,并编写了一个模板供您参考。命令:/ceshi/start。Sh#在启动时重新启动脚本:始终#--cpu共享:当cpu资源充足时,设置cpu权重没有意义。只有当容器竞争CPU资源时,#CPU的权重才能使不同容器使用不同数量的CPU。我们可以将其设置为2以获得非常低的权重,但将其设置成0以获得默认值1024。上面写了相...

HTTP请求报文

不仅报表样式可以传递请求参数,请求url也可以以类似于键值对的方式传递数据...

Delete from join 用法

delete(别名)fromtblA(别名)leftjointblb(别名)on。。。...

USBWriter之后恢复磁盘大小

USBWriter之后恢复磁盘大小的方法:1,cmd2,diskpart3,listdisk4,selectdisk*5,clean6、在我的电脑点右键,管理,然后选磁盘管理,选择USB后,右键,然后再新建卷就可以了。...

wifi密码暴力破解

转自:Python最新暴力破解WiFi,攻破所有密码限制,最强破解!...