zoukankan      html  css  js  c++  java
  • Ogre 编辑器三(自动生成与更新Ogre对象编辑界面)

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

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

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

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

    XML文件与基本类

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

     

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

    namespace Ogre3DX
    {
        typedef std::vector<string> VectorString;
        class OgreStyle;
        typedef std::vector<OgreStyle*> OgreStyleVector;
    
        class OgreStyle
        {
        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::string getText()
            {
                if (ogreText.empty())
                    return ogreName;
                return ogreText;
            }
    
            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);
            }
    
            void removeAll()
            {
                //删除所有子节点
                while (!childs.empty())
                {
                    auto child = childs.back();
                    childs.pop_back();
                    //这句 避免递归时重复delete
                    child->parent = nullptr;
                    if (child != nullptr)
                    {
                        delete child;
                        child = nullptr;
                    }
                }
            }
    
            OgreStyle* findChild(int type)
            {
                if (childs.empty())
                    return nullptr;
                for (auto child : this->childs)
                {
                    if (child->type == type)
                        return child;
                }
                return nullptr;
            }
    
            OgreStyle* findChild(std::string name)
            {
                if (childs.empty())
                    return nullptr;
                for (auto child : this->childs)
                {
                    if (child->ogreName == name)
                        return child;
                }
                return nullptr;
            }
    
            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)
                    {
                        delete child;
                        child = nullptr;
                    }
    
                }
            }
    
        private:
            void remove(OgreStyle* child, bool bDelete)
            {
                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)
                {
                    delete child;
                    child = nullptr;
                }
            }
        };
    }
    OgreStyle

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

    namespace ResourceEnum
    {
        //对应Ogre资源类型
        enum ResourceType
        {
            Resource = 100,
            Material,
            Technique,
            Pass,
            Mesh,
            SubMesh,
            TextureUnit,
            Texture,
            Particle,
            Compositor,
            Program,
            Shader_Cg,
            Shader_hlsl,
            Shader_glsl,
        };
    
        //对应Ogre场景
        enum SceneType
        {
            Scene = 200,
            SceneNode,
            Viewport,
            Camera,
            RenderSystem,
            RenderTarget,
            MovableObject,
            Renderable
        };
    
        enum MovableType
        {
            MovableOther = 300,
            BillboardChain,
            BillboardSet,
            Entity,
            Light,
            ManualObject,
            ParticleSystem,
            RibbonTrail,
        };
    
        enum RenderType
        {
            RenderOther = 400,
            RenderSubEntity
        };
    
        enum FileType
        {
            FL_Materials = 500,
            FL_Material,
            FL_Group,
        };
    }
    ResourceType

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

    namespace Ogre3DX
    {
        struct NodeStyle
        {
            std::string nodeName;
            std::string nodeText;
            NodeStyle(){};
            NodeStyle(std::string name, std::string text)
                :nodeName(name), nodeText(text){}
    
            string getText()
            {
                if (nodeText.empty())
                {
                    string result;
                    for (auto ch = nodeName.begin(); ch != nodeName.end(); ++ch)
                    {
                        if (ch != nodeName.begin() && isupper(*ch))
                        {
                            result.push_back(' ');
                        }
                        result.push_back(*ch);
                    }
                    return result;
                }
                return nodeText;
            }
        };
    
        struct OgreField
        {
            string fieldName;
            string fieldType;
            string fieldKey;
            string fieldText;
            bool fieldManual = false;
            OgreField(){};
            OgreField(std::string name, std::string type, std::string key)
                :fieldName(name), fieldType(type), fieldKey(key){}
    
            string getText()
            {
                if (fieldText.empty())
                {
                    string result;
                    for (auto ch = fieldName.begin(); ch != fieldName.end(); ++ch)
                    {
                        if (ch != fieldName.begin() && isupper(*ch))
                        {
                            result.push_back(' ');
                        }
                        result.push_back(*ch);
                    }
                    return result;
                }
                return fieldText;
            }
        };
    
        struct RelationVisible
        {
            string name;
            string relationName;
            string relationValue;
            bool relationVisible;
            string nodeName;
            RelationVisible(std::string name, std::string dName, std::string value, bool visible, string node)
                :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;
    }
    
    namespace Ogre3DX
    {
        class OgreStyleManager :
            public tools::Singleton<OgreStyleManager>
        {
        public:
            OgreStyleManager();
            ~OgreStyleManager();
    
            void initialise();
    
            int getOgreStyleType(const string& name, int deault = 0)
            {
                for (auto kv : ogreStyles)
                {
                    if (kv.second == name)
                        return kv.first;
                }
                return deault;
            }
    
            std::string getOgreStyleName(int type, const string& name = "")
            {
                if (ogreStyles.find(type) != ogreStyles.end())
                {
                    return ogreStyles[type];
                }
                return name;
            }
    
            NodeStyleVector getNodeStyles(int type)
            {
                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);
                        }
                    }
                }
                return result;
            }
    
            FieldVector getFieldVector(const string& nodeName)
            {
                if (nodeFields.find(nodeName) != nodeFields.end())
                {
                    return nodeFields[nodeName];
                }
                return FieldVector();
            }
    
            VectorString getKeyItems(const string& key)
            {
                if (keyItems.find(key) != keyItems.end())
                {
                    return keyItems[key];
                }
                return VectorString();
            }
    
            RelationVector getRelationFields(const string& nodeName)
            {
                RelationVector result;
                for (auto rf : relationFields)
                {
                    if (rf->nodeName == nodeName)
                        result.push_back(rf);
                }
                return result;
            }
    
            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::string xmlName, ptrFun func);
    
            void initOgreStyles();
            void initStyleNodes(xml::ElementPtr root);
            void initNodeFields(xml::ElementPtr root);
            void initKeyItems(xml::ElementPtr root);
            void initRelationFields();
            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;
    
    namespace Ogre3DX
    {
        OgreStyleManager::OgreStyleManager()
        {
    
        }
    
        OgreStyleManager::~OgreStyleManager()
        {
    
        }
    
        void OgreStyleManager::initialise()
        {
            initOgreStyles();
            initXML("StyleNode.xml", &OgreStyleManager::initStyleNodes);
            initXML("NodeField.xml", &OgreStyleManager::initNodeFields);
            initXML("KeyItem.xml", &OgreStyleManager::initKeyItems);
            initRelationFields();
        }
    
        void OgreStyleManager::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::string xmlName, 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);
        }
    
        void OgreStyleManager::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);
                }
            }
        }
    
        void OgreStyleManager::initNodeFields(xml::ElementPtr root)
        {
            auto node = root->getElementEnumerator();
            while (node.next("OgreNode"))
            {
                auto name = node->findAttribute("name");
                auto text = node->findAttribute("text");
                NodeStyle* nodeStyle = new NodeStyle(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 = new OgreField(fieldName, fieldType, fieldKey);
                    field->fieldText = fieldText;
                    if (fieldManual.size() > 0)
                    {
                        field->fieldManual = Ogre::StringConverter::parseBool(fieldManual);
                    }
                    nodeFields[name].push_back(field);
                }
            }
        }
    
        void OgreStyleManager::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);
                }
            }
        }
    
        void OgreStyleManager::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("");
            }
            return root;
        }
    }
    OgreStyleManager

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

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

        OgreStyle* OgreQuery::getTLRoot()
        {
            ogreRoot = shared_ptr<OgreStyle>(new OgreStyle());
            auto ogreSceneRoot = new OgreStyle();
    
            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 = new OgreStyle();
                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 = new OgreStyle();
                    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 = new OgreStyle();
                            movable->add(subStyle);
                            getRenderable(subEntity, subStyle, ResourceEnum::RenderType::RenderSubEntity, i);
                        }
                    }
                }
            }
            auto ogreRenderRoot = new OgreStyle();
            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用于管理这些类,我们先看这个类的实现.

    namespace tools
    {
    
        class PropertyFieldManager :
            public MyGUI::Singleton<PropertyFieldManager>
        {
        public:
            PropertyFieldManager();
            virtual ~PropertyFieldManager();
    
            void initialise();
            void shutdown();
    
            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";
    
    namespace tools
    {
    
        template <typename Type>
        class GenericFactory
        {
        public:
            typedef MyGUI::delegates::CDelegate2<IPropertyField*&, MyGUI::Widget*> Delegate;
            static typename Delegate::IDelegate* getFactory()
            {
                return MyGUI::newDelegate(createFromFactory);
            }
    
        private:
            static void createFromFactory(IPropertyField*& _instance, MyGUI::Widget* _parent)
            {
                _instance = new Type(_parent);
            }
        };
    
        PropertyFieldManager::PropertyFieldManager()
        {
        }
    
        PropertyFieldManager::~PropertyFieldManager()
        {
        }
    
        void PropertyFieldManager::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();
        }
    
        void PropertyFieldManager::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);
    
            return result;
        }
    
    }
    PropertyFieldManager

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

    using namespace Ogre3DX;
    namespace tools
    {
        typedef MyGUI::delegates::CDelegate3<const std::string&, const std::string&, bool> PropertyFieldActionDelegate;
    
        class IPropertyField
        {
        public:
            virtual ~IPropertyField();
    
            virtual void initialise(const std::string& _type);
    
            virtual void setValue(const std::string& _value) = 0;
            //Relation Field
            virtual string getValue();
            virtual void onFillValues();
    
            virtual void setField(OgreField* _field);
            virtual OgreField* getField();
            //Update Field
            virtual bool getFocus();
    
            virtual void setName(const std::string& _value);
            virtual void setVisible(bool _value);
            virtual bool getVisible();
    
            virtual void onAction(const std::string& _value, bool _final);
            virtual bool onCheckValue();
    
            virtual MyGUI::IntSize getContentSize();
            virtual void setCoord(const MyGUI::IntCoord& _coord);
            virtual bool checkFocus(MyGUI::Widget* widget);
    
            PropertyFieldActionDelegate eventAction;
        protected:
            MyGUI::TextBox* mText = nullptr;
            std::string mType;
            std::string mName;
    
            OgreField* field = nullptr;
    
            MyGUI::Widget* mainWidget = nullptr;
        };
    }
    namespace tools
    {
        IPropertyField::~IPropertyField()
        {
        }
    
        void IPropertyField::initialise(const std::string& _type)
        {
            mType = _type;
        }
    
        string IPropertyField::getValue()
        {
            return "";
        }
    
        void IPropertyField::onFillValues()
        {
        }
    
        void IPropertyField::setField(OgreField* _field)
        {
            field = _field;
            onFillValues();
        }
    
        OgreField* IPropertyField::getField()
        {
            return field;
        }
    
        bool IPropertyField::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);
        }
    
        bool IPropertyField::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);
        }
    
        bool IPropertyField::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的具体实现,这个类可以让我们更好理解相关方法需要如何实现.

    namespace tools
    {
        class PropertyFieldComboBox :
            public wraps::BaseLayout,
            public IPropertyField
        {
        public:
            PropertyFieldComboBox(MyGUI::Widget* _parent);
            virtual ~PropertyFieldComboBox();
    
            virtual void setValue(const std::string& _value);
            virtual string getValue();
        protected:
            virtual void onFillValues();
    
        private:
            void notifyApplyProperties(MyGUI::Widget* _sender);
            void notifyForceApplyProperties2(MyGUI::ComboBox* _widget, size_t _index);
    
        protected:
            MyGUI::ComboBox* mField;
    
        };
    }
    namespace tools
    {
        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()
        {
        }
    
        void PropertyFieldComboBox::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);
        }
    
        string PropertyFieldComboBox::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代码.

    namespace tools
    {
        class PropertiesPanelView :
            public wraps::BaseLayout
        {
        public:
            PropertiesPanelView(MyGUI::Widget* _parent = nullptr);
            virtual ~PropertiesPanelView();
            void notifyChangeSelectedWidget(OgreStyle* data);
            void hideAllPanel();
        private:
            void notifyWindowChangeCoord(MyGUI::Window* _sender);
    
            std::vector<PanelProperties*> getPropertyWindow(OgreStyle* _style);
            size_t getIndexPanel(PanelProperties* _panel);
    
            void onRefleshFiled(float time);
        private:
            MyGUI::IntSize mOldSize;
            PanelView* mPanelView;
    
            typedef std::map<string, PanelProperties*> MapPropertyWindow;
            MapPropertyWindow mMapPropertyWindow;
    
            OgreStyle* currentStyle;
        };
    }
    namespace tools
    {
    
        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();
            }
        }
    
        void PropertiesPanelView::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 = new PanelProperties();
                    mPanelView->addItem(panel);// insertItem(getIndexByDepth(_depth), result);
                    mMapPropertyWindow[key] = panel;
                }
                mMapPropertyWindow[key]->setStyle(_style, nodeStyle);
                result.push_back(mMapPropertyWindow[key]);
            }
            return result;
        }
    
        size_t PropertiesPanelView::getIndexPanel(PanelProperties* _panel)
        {
            for (size_t index = 0; index < mPanelView->getItemCount(); ++index)
            {
                if (mPanelView->getItem(index) == _panel)
                    return index;
            }
            return MyGUI::ITEM_NONE;
        }
    
        void PropertiesPanelView::onRefleshFiled(float time)
        {
            for (auto item = mMapPropertyWindow.begin(); item != mMapPropertyWindow.end(); ++item)
            {
                if ((*item).second->getVisible())
                {
                    (*item).second->onReflesh();
                }
            }
        }
    }
    PropertiesPanelView
    using namespace Ogre3DX;
    namespace tools
    {
        typedef std::vector<std::pair<std::string, IPropertyField*>> MapPropertyField;
        typedef MapPropertyField::iterator FieldIter;
    
        class PanelProperties :
            public wraps::BasePanelViewItem
        {
        public:
    
            PanelProperties();
    
            virtual void initialise();
            virtual void shutdown();
    
            void setStyle(OgreStyle* ogreStyle, NodeStyle* nodeStyle);
            void update();
    
            void onReflesh();
        private:
            void notifyAction(const std::string& _name, const std::string& _value, bool _final);
    
            size_t addParametrs();
            void destroyPropertyFields();
            void hidePropertyFields();
            void updateSize();
            void updateRelationFields();
    
            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;
        };
    
    }
    namespace tools
    {
    
        PanelProperties::PanelProperties() :
            BasePanelViewItem("PanelProperties.layout")
        {
        }
    
        void PanelProperties::initialise()
        {
        }
    
        void PanelProperties::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++;
                }
            }
            return result;
        }
    
        void PanelProperties::setStyle(OgreStyle* ogreStyle, NodeStyle* nodeStyle)
        {
            currentOgreStyle = ogreStyle;
            currentNodeStyle = nodeStyle;
        }
    
        void PanelProperties::update()
        {
            hidePropertyFields();
    
            if (currentNodeStyle != nullptr)
                mPanelCell->setCaption(currentNodeStyle->getText());
    
            size_t count = addParametrs();
    
            setVisible(count > 0);
            onReflesh();
            updateSize();
            updateRelationFields();
        }
    
        void PanelProperties::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);
                        }
                    }
                }
            }
        }
    
        void PanelProperties::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);
        }
    
        void PanelProperties::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();
            }
        }
    
        void PanelProperties::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();
        }
    
        void PanelProperties::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)
                    return i;
            }
            return mFields.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));
            return result;
        }
    }
    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找到对象.如下是代码:

    namespace Ogre3DX
    {
        class OgreManager :
            public tools::Singleton<OgreManager>
        {
        public:
            OgreManager()
            {
                mapObject[ResourceEnum::ResourceType::Resource] = new OgreResource();
                mapObject[ResourceEnum::ResourceType::Material] = new OgreMaterial();
                mapObject[ResourceEnum::ResourceType::Technique] = new OgreTechnique();
                mapObject[ResourceEnum::ResourceType::Pass] = new OgrePass();
                mapObject[ResourceEnum::SceneType::Viewport] = new OgreViewport();
    
                mapObject[ResourceEnum::SceneType::SceneNode] = new OgreSceneNode();
                mapObject[ResourceEnum::SceneType::MovableObject] = new OgreMovableObject();
                mapObject[ResourceEnum::SceneType::RenderTarget] = new OgreRenderTarget();
                mapObject[ResourceEnum::SceneType::Camera] = new OgreCamera();
                mapObject[ResourceEnum::SceneType::Renderable] = new OgreRenderable();
                mapObject[ResourceEnum::SceneType::Scene] = new OgreSceneManager();
    
                mapObject[ResourceEnum::MovableType::Entity] = new OgreEntity();
                mapObject[ResourceEnum::MovableType::Light] = new OgreLight();
                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, int type)
            {
                auto object = getType(type);
                if (object == nullptr)
                    return nullptr;
                //重新设置ogre值.
                if (style != preStyle || type != preType)
                {
                    fillStyleObject(style, type);
                    preStyle = style;
                    preType = type;
                }
                return object;
            }
    
            OgreBasic* getType(int type)
            {
                if (mapObject.find(type) != mapObject.end())
                {
                    return mapObject[type];
                }
                return nullptr;
            }
    
    
            void fillStyleObject(OgreStyle* style, int type)
            {
                auto object = getType(type);
                if (object == nullptr)
                    return;
    
                switch (style->type)
                {
                case ResourceEnum::SceneType::Scene:
                    if (true)
                    {
                        if (type == ResourceEnum::SceneType::Scene)
                        {
                            object->setObject(scene);
                        }
                        else if (type == ResourceEnum::SceneType::Viewport)
                        {
                            object->setObject(scene->getCurrentViewport());
                        }
                    }
                    break;
                case ResourceEnum::MovableType::Entity:
                    if (true)
                    {
                        auto entity = scene->getEntity(style->ogreName);
                        if (type == ResourceEnum::MovableType::Entity)
                        {
                            object->setObject(entity);
                        }
                        fillMovableable(object, entity, type);
                    }
                    break;
                case ResourceEnum::ResourceType::Material:
                    if (true)
                    {
                        auto mat = MaterialManager::getSingleton().getByName(style->ogreName);
                        fillMaterial(object, mat, type);
                    }
                    break;
                case ResourceEnum::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;
                case ResourceEnum::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;
                case ResourceEnum::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;
                case ResourceEnum::SceneType::Camera:
                    if (true)
                    {
                        auto camera = scene->getCamera(style->ogreName);
                        if (camera != nullptr)
                        {
                            fillCamera(object, camera, type);
                        }
                    }
                    break;
                case ResourceEnum::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, int type)
            {
                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, int type)
            {
                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, int type)
            {
                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, int type)
            {
                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是一个泛型类,提供一些方便.如下代码:

    using namespace Ogre;
    
    typedef Ogre::StringConverter format;
    namespace Ogre3DX
    {
        class OgreBasic
        {
        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(){ return nullptr; }
        };
    
        template<typename T>
        class OgreTemplate
            : public OgreBasic
        {
        public:
            OgreTemplate()
            {
            }
    
            virtual ~OgreTemplate(){};
    
            virtual std::string getValue(std::string field)
            {
                return "";
            }
    
            virtual bool setValue(std::string field, std::string value)
            {
                return false;
            }
    
            virtual void setObject(T* object)
            {
                ogreObject = object;
            }
    
            virtual T* getOgreObject()
            {
                return ogreObject;
            }
        protected:
            virtual void setObject(void* object)
            {
                return setObject((T*)object);
            }
            virtual void* getObject()
            {
                if (ogreObject == nullptr)
                    return nullptr;
                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泛型具体化实现.

    namespace Ogre3DX
    {
        class OgreSceneManager :
            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)
                {
                    delete plane;
                    plane = nullptr;
                }
            }
    
            virtual std::string getValue(std::string field)
            {
                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());
                }
                return result;
            }
    
            virtual bool setValue(std::string field, std::string value)
            {
                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新手参考.

  • 相关阅读:
    Spring Boot 2.0 + zipkin 分布式跟踪系统快速入门
    在线yaml转Properties
    Spring Boot 配置优先级顺序
    集群服务器下使用SpringBoot @Scheduled注解定时任务
    spring-boot项目在eclipse中指定配置文件启动
    org.hibernate.TransientObjectException异常
    Servlet、ServletConfig、ServletContext深入学习
    Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别、SSH线程安全问题
    nested exception is com.svorx.core.dao.PersistenceException
    yui压缩JS和CSS文件
  • 原文地址:https://www.cnblogs.com/zhouxin/p/4743685.html
Copyright © 2011-2022 走看看