最开始设计这个编辑器时,其中一个要求就是能在运行过程中,通过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; } } }; }