关闭

关闭

关闭

封号提示

内容

首页 OGRE分析之设计模式.pdf

OGRE分析之设计模式.pdf

OGRE分析之设计模式.pdf

上传者: kankanxingxi 2011-09-19 评分 0 0 0 0 0 0 暂无简介 简介 举报

简介:本文档为《OGRE分析之设计模式pdf》,可适用于IT/计算机领域,主题内容包含OGRE分析之设计模式MythmaOGRE分析之设计模式(一)Mythmahttp:wwwcppblogcommythmaEmail:mythmac符等。

OGRE分析之设计模式MythmaOGRE分析之设计模式(一)Mythmahttp:wwwcppblogcommythmaEmail:mythmacomOGRE的设计结构十分清晰这得归功于设计模式的成功运用。一、SingletonSingleton模式是OGRE中用的最广泛的设计模式若干类都使用了该模式。Singleton模式本身很简单实现方式多种多样简单的如GoF提到的实现方式复杂的有Loki库中解决方案而OGRE的实现方法也是十分简单。OGRE提供了一个模板类Ogre::Singleton<T>作为所有singleton类的基类:template<typenameT>classSingleton{protected:staticT*msSingletonpublic:Singleton(void){assert(!msSingleton)msSingleton=staticcast<T*>(this)}~Singleton(void){assert(msSingleton)msSingleton=}staticTgetSingleton(void){assert(msSingleton)return(*msSingleton)}staticT*getSingletonPtr(void){returnmsSingleton}}需要使用Singleton的类只需要从它继承即可:classMyClass:publicSingleton<MyClass>{}但在OGRE的源码中我们可以发现从Singleton继承的类都Override了Singleton的成员getSingleton和getSingletonPtr。OGRE中是这样解释的:Singleton的实现都在OgreSingletonh文件中这意味着任何包含OgreSingletonh头文件的文件编译后都有Singleton的一份实现这符合模板机制。但是从别的dll中使用基于Singleton的类时就会产生连接错误。子类Override一下把实现放在cpp中就会避免该问题。第页共页OGRE分析之设计模式Mythma二、FactoryMethodFactoryMethod本质上代理某个类的实例化过程封装了一个new的语句而已。C中new和delete通常都要成对出现因此FactoryMethod也应该负责一个对象的delete(GoF没有提到由FactoryMethod构造的对象的析构问题)。另外当一个类的构造函数的参数很多其中有可以提供默认值的时候用FactoryMethod还可以简化对象的创建。OGRE中用到的FactoryMethod的地方很多。为满足最普遍的情况OGRE有一个模板化的FactoryMethodOgre::FactoryObj<T>。因为具体类的构造函数的参数并不都相同因此Ogre::FactoryObj<T>并不是OGRE所有工厂方法的基类。template<typenameT>classFactoryObj{public:virtual~FactoryObj(){}virtualconstStringgetType()const=virtualT*createInstance(constStringname)=virtualvoiddestroyInstance(T*)=}OGRE大部分FactoryMethod的使用效果都是连接平行的类层次如:不使用Ogre::FactoryObj<T>的FactoryMethod很多如:还有ParticleEmitter和ParticleEmitterFactory两个比较大的类层次等。第页共页OGRE分析之设计模式Mythma三、AbstractFactoryAbstractFactory提供了用来创建一系列相关或相互依赖对象的接口。对使用者而言无需关心使用的是何种具体的对象。OGRE中该模式体现在它的Plugin机制。OGRE提供了Plugin机制。利用Plugin一方面把与平台相关的部分和与平台无关的部分分离开来如底层渲染系统既可以使用OpenGL又可以使用DirectX另一方面便于系统功能的扩充如场景既可以使用BSP方式管理又可以用Octree管理。OGRE的Plugin实现方式有两种自此只讨论一下用AbstractFactory模式实现的Plugin。以此方式实现的主要有两大类Plugin:RenderSystemx和PluginxSceneManager。、RenderSystemRenderSystem是与渲染引擎相关的部分如RenderSystemDirectDdll、RenderSystemDirectDdll、RenderSystemGLdll:与渲染相关的对象都是通过具体的子RenderSystem创建的这样就形成了不同类别的Render产品。在使用OGRE的时候只需关心RenderSystem而无需关心究竟是那种具体的RenderSystem。RenderSystem创建的产品主要有:)RenderWindow)RenderTexture)HardwareOcclusionQuery第页共页OGRE分析之设计模式Mythma、SceneManagerSceneManager是与场景内数据的组织方式相关的部分如:PluginOctreeSceneManagerdll、PluginBSPSceneManagerdll等:同样SceneManager只是个接口具体的场景管理是由子类完成的。它的产品系主要有:)SceneNode)RaySceneQuerySceneManager中的很多Products是相同的因此由SceneManager就完成创建过程。所以说SceneManager不是个纯粹的AbstractFactory。第页共页OGRE分析之设计模式MythmaOGRE分析之设计模式(二)Mythmahttp:wwwcppblogcommythmaEmail:mythmacomOGRE的设计结构十分清晰这得归功于设计模式的成功运用。四、AdapterApdater模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。当使用第三方工具包时候这种模式经常用到。OGRE使用了其他的几个开源项目如Cg、freetype、ode、zzip等与其他接口肯定会有不兼容的情况这就需要Adapter。看一下OGRE的文件系统与zzip:OGRE是面向对象的zzip提供的都是结构体和函数。为了处理压缩文件和普通文件使用相同的接口就需要Adapter。OGRE中处理文件目录使用Ogre::Archivezzip用ZZIPDIR来表示压缩文件目录。因此在Ogre::ZipArchive中加入一个ZZIPDIR对象以使zzip的接口适应Archive的接口使用的是对象适配器。文件的处理OGRE使用Ogre::DataStream接口对应zzip的ZZIPFILE。同样OGRE使用的是对象适配器。可以看出Adapter模式与AbstractFactory模式可以实现相同的效果让别的接口兼容(回顾一下用AbstractFactory“适配”不同的RenderSystem),但是两者的区别在于AbstractFactory是用于创建不同类别的对象而Adapter没有创建别的对象的功能。所以GoF把AbstractFactory分在创建型模式类别中而Adapter在结构型模式中。可以发现这两种模式OGRE的文件系统都使用了。五、BridgeBridge的意图是使得抽象部分与它的实现部分分离这样就使得两部分都可以独立变化提高可扩充性。该模式可以在多种情况下使用如实现跨平台、程序换肤、文件版本演化等。当然实现这些功能也可以使用别的设计模式同一个问题有不同的解决方案模式的使用也是仁者见仁智者见智。在分析OGRE二进制文件的序列化时提到了Ogre::Serializer类层次如下图。第页共页OGRE分析之设计模式Mythma可以看到序列化Mesh文件的Serializer既有Ogre::MeshSerializer又有Ogre::MeshSerializerImpl。OGRE在读写Mesh文件的时候使用的是Ogre::MeshSerializerImpl以及它的子类而Ogre::MeshSerializer是Ogre::MeshSerializerImpl系列对外的“接口”但二者是平辈关系。再看一下MeshSerializer的实现一切将会真相大白:MeshSerializer::MeshSerializer(){SetupmapmImplementationsinsert(MeshSerializerImplMap::valuetype("MeshSerializerv",newMeshSerializerImplv()))mImplementationsinsert(MeshSerializerImplMap::valuetype("MeshSerializerv",newMeshSerializerImplv()))mImplementationsinsert(MeshSerializerImplMap::valuetype(msCurrentVersion,newMeshSerializerImpl()))}voidMeshSerializer::exportMesh(constMesh*pMesh,constStringfilename){MeshSerializerImplMap::iteratorimpl=mImplementationsfind(msCurrentVersion)if(impl==mImplementationsend()){OGREEXCEPT(…)}impl>second>exportMesh(pMesh,filename)}可见具体的Mesh文件读取MeshSerializer并未实现而是由合适的Implementor实现的其他组件若要使用序列化功能只需调用MeshSerializer即可。从实现上还可以发现与GoF提到的实现有很大的差别这说明模式不是“死的”同一模式的实现也多种多样只要能满足需求就可以了。第页共页OGRE分析之设计模式Mythma六、ProxyProxy为其他对象提供一种代理以控制对该对象的访问。GoF提到四种常见的情况:RomoteProxyVirtualProxy、ProtectionProxy以及SmartReference。在这里我只分析一下SmartReference。SmartPointer在STL中有std::autoptr在BOOST中有boost::sharedptr、boost::sharedarray、boost::scopedptr、boost::scopedarray、boost::weakptr、boost::intrusiveptr在Loki中则有Loki::SmartPtr。各种SmartPointer都有不同的功能适用的地方又各不相同。加上有的SmartPointer的行为又有点诡异尤其是std::autoptr所以实际应用中一向对之退而却步。OGRE虽不是模板库却也有个SmartPointerOgre::SharedPtr。SharedPtr是一个引用计数的共享指针。下面是OGRE对SharedPtr作的使用说明:ThisisastandardsharedpointerimplementationwhichusesareferencecounttoworkoutwhentodeletetheobjectOGREdoesnotusethisclassveryoften,becauseitisusuallymoreefficienttomakethedestructionofobjectsmoreintentional(inblocks,say)Howeverinsomecasesyoureallycannottellhowmanypeopleareusinganobject,andthisapproachisworthwhile(egControllerValue)除了加上mutex外其实现手法没有什么特别之处。附上Ogre::SharedPtr的实现:template<classT>classSharedPtr{protected:T*pRepunsignedint*pUseCountpublic:OGREAUTOSHAREDMUTEXpublictoallowexternallocking**Constructor,doesnotinitialisetheSharedPtrremarks<b>Dangerous!<b>Youhavetocallbind()beforeusingtheSharedPtr*SharedPtr():pRep(),pUseCount(){}explicitSharedPtr(T*rep):pRep(rep),pUseCount(newunsignedint()){OGRENEWAUTOSHAREDMUTEX}SharedPtr(constSharedPtrr){lockcopyothermutexpointerOGRELOCKMUTEX(*rOGREAUTOMUTEXNAME)OGRECOPYAUTOSHAREDMUTEX(rOGREAUTOMUTEXNAME)pRep=rpReppUseCount=rpUseCount第页共页OGRE分析之设计模式MythmaHandlezeropointergracefullytomanageSTLcontainersif(pUseCount){(*pUseCount)}}SharedPtroperator=(constSharedPtrr){if(pRep==rpRep)return*thisrelease()lockcopyothermutexpointerOGRELOCKMUTEX(*rOGREAUTOMUTEXNAME)OGRECOPYAUTOSHAREDMUTEX(rOGREAUTOMUTEXNAME)pRep=rpReppUseCount=rpUseCountif(pUseCount){(*pUseCount)}return*this}virtual~SharedPtr(){release()}inlineToperator*()const{assert(pRep)return*pRep}inlineT*operator>()const{assert(pRep)returnpRep}inlineT*get()const{returnpRep}**BindsreptotheSharedPtrremarksAssumesthattheSharedPtrisuninitialised!*voidbind(T*rep){assert(!pRep!pUseCount)OGRENEWAUTOSHAREDMUTEXOGRELOCKAUTOSHAREDMUTEXpUseCount=newunsignedint()pRep=rep}inlineboolunique()const{assert(pUseCount)OGRELOCKAUTOSHAREDMUTEXreturn*pUseCount==}第页共页OGRE分析之设计模式MythmainlineunsignedintuseCount()const{assert(pUseCount)OGRELOCKAUTOSHAREDMUTEXreturn*pUseCount}inlineunsignedint*useCountPointer()const{returnpUseCount}inlineT*getPointer()const{returnpRep}inlineboolis(void)const{returnpRep==}inlinevoidset(void){if(pRep){can'tscopelockmutexbeforereleaseincasedeletedrelease()pRep=pUseCount=OGRECOPYAUTOSHAREDMUTEX()}}protected:inlinevoidrelease(void){booldestroyThis=false{lockownmutexinlimitedscope(mustunlockbeforedestroy)OGRELOCKAUTOSHAREDMUTEXif(pUseCount){if((*pUseCount)==){destroyThis=true}}}if(destroyThis)destroy()}virtualvoiddestroy(void){IFYOUGETACRASHHERE,YOUFORGOTTOFREEUPPOINTERSBEFORESHUTTINGOGREDOWNUseset()beforeshutdownormakesureyourpointergoesoutofscopebeforeOGREshutsdowntoavoidthis第页共页OGRE分析之设计模式MythmadeletepRepdeletepUseCountOGREDELETEAUTOSHAREDMUTEX}}template<classT,classU>inlinebooloperator==(SharedPtr<T>consta,SharedPtr<U>constb){returnaget()==bget()}template<classT,classU>inlinebooloperator!=(SharedPtr<T>consta,SharedPtr<U>constb){returnaget()!=bget()}第页共页OGRE分析之设计模式MythmaOGRE分析之设计模式(三)Mythmahttp:wwwcppblogcommythmaEmail:mythmacomOGRE的设计结构十分清晰这得归功于设计模式的成功运用。七、ChainofResponsibilityChainofResponsibility是对象行为型模式它把请求或消息以链的方式传送给对象处理者避免了请求的发送者和接收者之间的耦合关系。该模式普遍用于处理用户事件和处理图形的更新。OGRE的消息传递也是使用ChainofResponsibility模式体现在处理用户事件(鼠标消息和键盘消息)和图形的更新。首先看OGRE是如何传递处理用户事件的消息。、用户事件的消息在《OGRE分析之消息机制》中分析了OGRE中消息的产生、处理和传递得到如下的传递顺序:InputReaderÆEventProcessorÆEventDispatcherÆEventTargetÆEventListener这只是一个总体的过程现在从代码上看一下是如何使用ChainofResponsibility的。)消息的获取InputReader产生的用户消息是如何进入消息传递链的?从代码上分析:OGRE的入口是Root::startRendering然后进入系统循环:voidRoot::startRendering(void){…mQueuedEnd=falsewhile(!mQueuedEnd){MSGmsgwhile(PeekMessage(msg,,U,U,PMREMOVE)){TranslateMessage(msg)DispatchMessage(msg)}if(!renderOneFrame())break}}然后进入Root::renderOneFrame():boolRoot::renderOneFrame(void){第页共页OGRE分析之设计模式Mythmaif(!fireFrameStarted())returnfalseupdateAllRenderTargets()进行图形重画returnfireFrameEnded()}boolRoot::fireFrameStarted(){unsignedlongnow=mTimer>getMilliseconds()FrameEventevtevttimeSinceLastEvent=calculateEventTime(now,FETTANY)evttimeSinceLastFrame=calculateEventTime(now,FETTSTARTED)returnfireFrameStarted(evt)}从上面可以看出构造出了FrameEvent消息并传递但这并不是我们需要的InputEvent继续:boolRoot::fireFrameStarted(FrameEventevt){……略Tellalllistenersfor(i=mFrameListenersbegin()i!=mFrameListenersend()i){if(!(*i)>frameStarted(evt))FrameListener::frameStated(evt)returnfalse}returntrue}可见FrameEvent消息被送往FrameListener去了。在初始化OGRE的时候都需要创建一个EventProcessor并自动注册到Root::mFrameListeners中而EventProcessor属于FrameLIstener的子类所以消息必定会传递给EventProcessor:boolEventProcessor::frameStarted(constFrameEventevt){mInputDevice>capture()while(mEventQueue>getSize()>){InputEvent*e=mEventQueue>pop()processEvent(e)deletee}returntrue}第页共页OGRE分析之设计模式Mythma现在终于出现InputEvent(OGRE中的鼠标消息封装在MouseEvent键盘消息封装在KeyEvent中它们都是InputEvent的子类)。开始进入消息的传递阶段。)消息的传递voidEventProcessor::processEvent(InputEvent*e){trytheeventdispatcherlistfor(DispatcherList::iteratori=mDispatcherListbegin()i!=mDispatcherListend()i){(*i)>dispatchEvent(e)EventDispatcher::dispatchEvent(e)}trytheeventtargetlistif(!e>isConsumed()){自己处理略}}可见InputEvent先传递给EventDispatcher处理若仍未被处理就由EventProcessor自己处理(EventProcessor本身也是个Target有处理用户消息的能力)。看消息在EventDispatcher中是如何处理的:boolEventDispatcher::dispatchEvent(InputEvent*e){boolret=falseif(e>isEventBetween(MouseEvent::MEFIRSTEVENT,MouseEvent::MELASTEVENT)){MouseEvent*me=staticcast<MouseEvent*>(e)ret=processMouseEvent(me)}elseif(e>isEventBetween(KeyEvent::KEFIRSTEVENT,KeyEvent::KELASTEVENT)){KeyEvent*ke=staticcast<KeyEvent*>(e)ret=processKeyEvent(ke)}returnret}至此EventDispatcher把InputEvent消息分成MouseEvent和KeyEvent分别处理。第页共页OGRE分析之设计模式Mythma先看键盘消息:boolEventDispatcher::processKeyEvent(KeyEvent*e){if(mKeyCursorOn!=){mKeyCursorOn>processEvent(e)PositionTarget::processEvent(e)}returne>isConsumed()}键盘消息被分发给Cursor当前所在的PositionTarget由PositionTarget处理。而PositionTarget是个抽象类需要其子类才能处理消息:再看鼠标消息:boolEventDispatcher::processMouseEvent(MouseEvent*e){PositionTarget*targetOvermMouseX=e>getX()mMouseY=e>getY()targetOver=mTargetManager>getPositionTargetAt(e>getX(),e>getY())trackMouseEnterExit(targetOver,e)switch(e>getID()){caseMouseEvent::MEMOUSEPRESSED:mDragging=trueif(mDragDropOn)mDragDropActive=truemMouseDragSource=targetOverretargetMouseEvent(targetOver,e)trackKeyEnterExit(targetOver,e)breakcaseMouseEvent::MEMOUSERELEASED:第页共页OGRE分析之设计模式Mythmaif(targetOver!=){if(targetOver==mMouseDragSource){retargetMouseEvent(mMouseDragSource,MouseEvent::MEMOUSECLICKED,e)retargetMouseEvent(mMouseDragSource,e)}elseietargetOver!=mMouseDragSource{if(mDragDropActive)retargetMouseEvent(targetOver,MouseEvent::MEMOUSEDRAGDROPPED,e)retargetMouseEvent(mMouseDragSource,e)retargetMouseEvent(targetOver,MouseEvent::MEMOUSEENTERED,e)}}elseretargetMouseEvent(mMouseDragSource,e)mDragging=falsemDragDropActive=falsemMouseDragSource=breakcaseMouseEvent::MEMOUSEMOVED:caseMouseEvent::MEMOUSEDRAGGED:if(!mDragging||targetOver==mMouseDragSource){retargetMouseEvent(targetOver,e)}elseiemDraggingtargetOver!=mMouseDragSource{retargetMouseEvent(mMouseDragSource,MouseEvent::MEMOUSEDRAGGED,e,true)if(mDragDropActive)retargetMouseEvent(targetOver,MouseEvent::MEMOUSEDRAGMOVED,e)}break}returne>isConsumed()}第页共页OGRE分析之设计模式MythmavoidEventDispatcher::retargetMouseEvent(PositionTarget*target,MouseEvent*e){if(target==){return}MouseEvent*retargeted=newMouseEvent(target,e>getID(),e>getButtonID(),e>getWhen(),e>getModifiers(),e>getX(),e>getY(),e>getZ(),e>getClickCount())target>processEvent(retargeted)deleteretargetede>consume()}可见所有的消息经过EventDispatcher分发后都是由各种target处理的。若target处理不了则由EvenetProcessor自行处理。而EvenetProcessor本身是也是Target的一种:所有用户消息默认的情况下(在没有其他的Target的时候)是由EvenetProcessor处理的再看EventProcessor::processEvent(InputEvent*e):voidEventProcessor::processEvent(InputEvent*e){trytheeventdispatcherlistfor(DispatcherList::iteratori=mDispatcherListbegin()i!=mDispatcherListend()i){(*i)>dispatchEvent(e)}第页共页OGRE分析之设计模式Mythmatrytheeventtargetlistif(!e>isConsumed()){EventTargetList::iteratori,iEndiEnd=mEventTargetListend()for(i=mEventTargetListbegin()i!=iEndi){(*i)>processEvent(e)}}if(!e>isConsumed()){sw

用户评论(0)

0/200

精彩专题

上传我的资料

每篇奖励 +2积分

资料评价:

/22
1下载券 下载 加入VIP, 送下载券

意见
反馈

立即扫码关注

爱问共享资料微信公众号

返回
顶部