没有用过cegui0.7.7以前的版本,所以不是很清楚它之前的版本是怎么初始化的,这里只是说一下bootstrapSystem的这种方式。
cegui作为一个ui框架,它的底层是直接采用低级图形渲染API实现的(d3d或opengl),它的大致思路是这样的。1.通过配置的方式加载样式和资源。2.在渲染的时候调用底层渲染API。3.针对自己定义的控件实现了一套事件机制,用这套机制相应事件。图形界面相关的永远都是怎么显示怎么交互之类的问题。
在cegui0.7.7版本配合ogre的时候,初始化很简单,只需要调用CEGUI::OgreRenderer::bootstrapSystem();方法就行了。挺好用的也不要参数,但是不好理解,尤其是它是怎么获取ogre相关的对象来渲染自己的,都没有体现出来,为此简单的看了一下这个方法相关的代码。
bootstrapSystem:
OgreRenderer& OgreRenderer::bootstrapSystem() { if (System::getSingletonPtr()) CEGUI_THROW(InvalidRequestException("OgreRenderer::bootstrapSystem: " "CEGUI::System object is already initialised.")); OgreRenderer& renderer = create(); OgreResourceProvider& rp = createOgreResourceProvider(); OgreImageCodec& ic = createOgreImageCodec(); System::create(renderer, &rp, static_cast<XMLParser*>(0), &ic); return renderer; }
这个方法有两个比较重要地方,创建了一个OgreRenderer对象和一个System对象。其中OgreRenderer对象用来渲染所有界面上的元素。System是cegui的根与ogre的root类型,说到这里必须说一下的是,ogre的代码写的真心烂,什么都放在头文件里,我还以为这个是行业规范呢,看了cegui才找到了回归标准的感觉。
1.OgreRenderer:
OgreRenderer::OgreRenderer() : d_pimpl(new OgreRenderer_impl()) { checkOgreInitialised(); // get auto created window Ogre::RenderWindow* rwnd = d_pimpl->d_ogreRoot->getAutoCreatedWindow(); if (!rwnd) CEGUI_THROW(RendererException( "Ogre was not initialised to automatically create a window, you " "should therefore be explicitly specifying a Ogre::RenderTarget in " "the OgreRenderer::create function.")); constructor_impl(*rwnd); } OgreRenderer_impl() :d_displayDPI(96, 96),d_maxTextureSize(2048), d_ogreRoot(Ogre::Root::getSingletonPtr()),d_previousVP(0), d_activeBlendMode(BM_INVALID),d_makeFrameControlCalls(true) {}
1. 这里需要关注的第一个是d_pimpl对象,它是一个结构体,里面是一些常用对象,其中一个成员是ogreRoot。这个地方默认对其进行初始化d_pimpl(new OgreRenderer_impl(),从下面的OgreRenderer_impl构造可以看出,默认对ogreRoot进行获取了。Ogre::Root::getSingletonPtr() 这表示在对OgreRenderer初始化前必须先new出root。
2. getAutoCreatedWindow 是获取RenderWindow而不是重新new,所以在此之前也必须new出RenderWindow。
3.最后看看constructor_impl这个方法,构造的实现名字取的真不俗,其实主要是对d_pimpl结构体的填充。
constructor_impl :
void OgreRenderer::constructor_impl(Ogre::RenderTarget& target) { d_pimpl->d_renderSystem = d_pimpl->d_ogreRoot->getRenderSystem(); d_pimpl->d_displaySize.d_width = target.getWidth(); d_pimpl->d_displaySize.d_height = target.getHeight(); // create default target & rendering root (surface) that uses it d_pimpl->d_defaultTarget = new OgreWindowTarget(*this, *d_pimpl->d_renderSystem, target); d_pimpl->d_defaultRoot = new RenderingRoot(*d_pimpl->d_defaultTarget); // hook into the rendering process d_pimpl->d_ogreRoot->addFrameListener(&S_frameListener); }
能从ogreRoot获取的坚决不自己new,反正OgreRenderer的初始化就这么些东西了。渲染对象的根也是在这个时候添加的,我们自己new出来的组件都是挂接在这个根上的。渲染对象的关系虽然是个tree但是是以list的形势存储的,父在前子在后,所以查询当前鼠标选中的组件的时候,都是从后面向前面查找的,因为子比父的优先级高。如果要实现点击后子和其父都要进行响应,做法应该是子响应后继续向前找下一个选中的渲染对象。
2.System :
System 的构造看起来比OgreRenderer的更复杂,但它只是履行了它作为这个cegui的入口的责任,大量的创建和初始化。System 的构造看起来比较长,里面主要涉及两个内容:
1.Config_xmlHandler:这个对象里面封装着各种xml配置,在System 构造里会加载这些配置。
2.createSingletons和addStandardWindowFactories的调用。
createSingletons:
void System::createSingletons() { // cause creation of other singleton objects new ImagesetManager(); new FontManager(); new WindowFactoryManager(); new WindowManager(); new SchemeManager(); new MouseCursor(); new GlobalEventSet(); new AnimationManager(); new WidgetLookManager(); new WindowRendererManager(); new RenderEffectManager(); }
addStandardWindowFactories:
void System::addStandardWindowFactories() { // Add factories for types all base elements WindowFactoryManager::addFactory< TplWindowFactory<GUISheet> >(); WindowFactoryManager::addFactory< TplWindowFactory<DragContainer> >(); WindowFactoryManager::addFactory< TplWindowFactory<ScrolledContainer> >(); WindowFactoryManager::addFactory< TplWindowFactory<ClippedContainer> >(); WindowFactoryManager::addFactory< TplWindowFactory<Checkbox> >(); WindowFactoryManager::addFactory< TplWindowFactory<PushButton> >(); WindowFactoryManager::addFactory< TplWindowFactory<RadioButton> >(); WindowFactoryManager::addFactory< TplWindowFactory<Combobox> >(); WindowFactoryManager::addFactory< TplWindowFactory<ComboDropList> >(); WindowFactoryManager::addFactory< TplWindowFactory<Editbox> >(); WindowFactoryManager::addFactory< TplWindowFactory<FrameWindow> >(); WindowFactoryManager::addFactory< TplWindowFactory<ItemEntry> >(); WindowFactoryManager::addFactory< TplWindowFactory<Listbox> >(); WindowFactoryManager::addFactory< TplWindowFactory<ListHeader> >(); WindowFactoryManager::addFactory< TplWindowFactory<ListHeaderSegment> >(); WindowFactoryManager::addFactory< TplWindowFactory<Menubar> >(); WindowFactoryManager::addFactory< TplWindowFactory<PopupMenu> >(); WindowFactoryManager::addFactory< TplWindowFactory<MenuItem> >(); WindowFactoryManager::addFactory< TplWindowFactory<MultiColumnList> >(); WindowFactoryManager::addFactory< TplWindowFactory<MultiLineEditbox> >(); WindowFactoryManager::addFactory< TplWindowFactory<ProgressBar> >(); WindowFactoryManager::addFactory< TplWindowFactory<ScrollablePane> >(); WindowFactoryManager::addFactory< TplWindowFactory<Scrollbar> >(); WindowFactoryManager::addFactory< TplWindowFactory<Slider> >(); WindowFactoryManager::addFactory< TplWindowFactory<Spinner> >(); WindowFactoryManager::addFactory< TplWindowFactory<TabButton> >(); WindowFactoryManager::addFactory< TplWindowFactory<TabControl> >(); WindowFactoryManager::addFactory< TplWindowFactory<Thumb> >(); WindowFactoryManager::addFactory< TplWindowFactory<Titlebar> >(); WindowFactoryManager::addFactory< TplWindowFactory<Tooltip> >(); WindowFactoryManager::addFactory< TplWindowFactory<ItemListbox> >(); WindowFactoryManager::addFactory< TplWindowFactory<GroupBox> >(); WindowFactoryManager::addFactory< TplWindowFactory<Tree> >(); WindowFactoryManager::addFactory< TplWindowFactory<HorizontalLayoutContainer> >(); WindowFactoryManager::addFactory< TplWindowFactory<VerticalLayoutContainer> >(); WindowFactoryManager::addFactory< TplWindowFactory<GridLayoutContainer> >(); }
System 作为cegui的入口,初始化的时候为我们new出了所需要使用的所有对象,这些对象都是以单例的形势存在的,这也是为什么初始化的时候没有赋值给某个引用。当然了,这里的单例模式没有java里面实现的严格,严格意义上讲,为保证单例必须使构造私有化。
总结:一般一个开源的框架,为了使用者的方便,会对初始化部分进行统一的内部处理,以简化使用者的使用。这样的结果是我们很难理解它到底做了些什么,所以在使用前有必要点进去看一下。整个cegui的初始化过程,强调了两个东西。
OgreRenderer :它集中的处理了界面的渲染,使用者不需要自己关注界面元素是如何渲染的,你只需要为界面上的组件设置相应的样式,然后把样式涉及到的资源加载到资源管理器中即可。
System :它管理了cegui里面的所有管理对象包括OgreRenderer ,在构造的时候会对xml配置进行加载,获取初始化的参数。
此文,尽管不涉及细节,但是对cegui整体的了解还是有所帮助的。