Ogre引擎由多個模塊組成,從不同角度來劃分可以得到不同的結果,從功能上看Ogre可大致分為資源管理、場景管理和渲染管理三大模塊;而從可執行部分的組織方式看,Ogre引擎則是由多個dll元件組合而成的,
組成Ogre的各動態庫基本上可以分為以下幾部分:核心庫、渲染層、場景管理邏輯層,核心庫(OgreMain.dll,一般debug版會生成OgreMain_d.dll檔案)負責資源加載和管理,并根據實際情況選擇和加載對應的渲染層模塊及場景管理層模塊,同時調度協調各模塊共同對場景進行渲染操作,渲染層主要是對不同的底層渲染引擎進行封裝,使不同的底層渲染引擎如:DirectX、OpenGL、OpenGLES等能夠支持相同的渲染介面,以實作核心層用統一的方式對不同底層渲染引擎的呼叫,這種技術有點類似《設計模式》中提到的Adapter模式,為了支持不同的底層渲染引擎,Ogre要有針對性地生成不同的元件如:RenderSystem_Direct3D9.dll、RenderSystem_Direct3D11.dll、RenderSystem_GL.dll、 RenderSystem_GLES.dll等,場景管理層則主要根據實際需要,采用不同的演算法來實作對場景物件的快速裁剪,比如若要用八叉樹對場景進行管理時一般要生成并呼叫Plugin_OctreeSceneManager.dll庫,而要用BSP演算法則需要生成并呼叫Plugin_BSPSceneManager.dll庫等,
以上所說的這些動態庫要能協調一致地作業,需要首先解決以下兩個問題:1. 如果不考慮跨平臺并假設是在Windows平臺上運行,如何實作各動態庫與核心庫的銜接?Ogre是用面向物件的技術開發的,Windows平臺只提供了動態加載元件及呼叫其中庫函式的相關技術,并沒有現成的對動態加載的動態庫函式中物件的訪問方法,2. 如果考慮跨平臺的問題,那么該如何對動態庫的動態加載程序作進一步的抽象?(另外,如果要考慮將渲染引擎引入到IOS平臺上,那么除了要對加載程序進行適當抽象外,還要考慮到IOS并不支持元件的實際情況,而只能采用靜態庫的使用方法,此問題不在本文的討論范圍之內)
對于以上問題,Ogre采用了稱之為插件(Plugin)的技術來加以解決,這種方法本身比較巧妙,而且對模塊化編程有一定的借鑒意義,所以值得詳細分析一下,
首先Ogre對要加載的動態庫作了一個抽象,用DynLib類來表示,一個動態庫就是一個DynLib類物件,同時Ogre又定義了一個DynLibManager類,用來管理所有加載的DynLib類物件,它負責根據動態庫檔案名對相應的庫進行加載,并保存加載后的DynLib物件指標,
此處采用的是Ogre1.8的相關代碼,
void Root::loadPlugin(const String& pluginName)
{
#if OGRE_PLATFORM != OGRE_PLATFORM_NACL
// Load plugin library
DynLib* lib = DynLibManager::getSingleton().load( pluginName );
// Store for later unload
// Check for existence, because if called 2+ times DynLibManager returns existing entry<br>
if (std::find(mPluginLibs.begin(), mPluginLibs.end(), lib) == mPluginLibs.end())
{
mPluginLibs.push_back(lib);
// Call startup function
DLL_START_PLUGIN pFunc =
(DLL_START_PLUGIN)lib->getSymbol("dllStartPlugin");
if (!pFunc)
OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
"Cannot find symbol dllStartPlugin in library " + pluginName,
"Root::loadPlugin");
// This must call installPlugin
pFunc();
}
#endif
}
以上代碼中,DynLibManager::getSingleton().load( pluginName )的加載程序會最終呼叫到DynLib的Load函式,此Load函式的核心部分是:
mInst = (DYNLIB_HANDLE)DYNLIB_LOAD( name.c_str() );
其中DYNLIB_LOAD是預先定義好的一個宏,其定義如下:
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
# define DYNLIB_HANDLE hInstance
# define DYNLIB_LOAD( a ) LoadLibraryEx( a, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
# define DYNLIB_GETSYM( a, b ) GetProcAddress( a, b )
# define DYNLIB_UNLOAD( a ) !FreeLibrary( a )
struct HINSTANCE__;
typedef struct HINSTANCE__* hInstance;
#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_ANDROID || OGRE_PLATFORM == OGRE_PLATFORM_NACL
# define DYNLIB_HANDLE void*
# define DYNLIB_LOAD( a ) dlopen( a, RTLD_LAZY | RTLD_GLOBAL)
# define DYNLIB_GETSYM( a, b ) dlsym( a, b )
# define DYNLIB_UNLOAD( a ) dlclose( a )
#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
# define DYNLIB_HANDLE void*
# define DYNLIB_LOAD( a ) mac_loadDylib( a )
# define DYNLIB_GETSYM( a, b ) dlsym( a, b )
# define DYNLIB_UNLOAD( a ) dlclose( a )
#endif
通過這個宏定義,實作了對不同平臺的動態庫加載的抽象,解決了之前提出的第二個問題,
Ogre會在每個要被動態加載的dll庫物件中宣告一個名為“dllStartPlugin”的函式,以RenderSystem_Direct3D9.dll為例:
#ifndef OGRE_STATIC_LIB
namespace Ogre
{
D3D9Plugin* plugin;
extern "C" void _OgreD3D9Export dllStartPlugin(void) throw()
{
plugin = OGRE_NEW D3D9Plugin();
Root::getSingleton().installPlugin(plugin);
}
extern "C" void _OgreD3D9Export dllStopPlugin(void)
{
Root::getSingleton().uninstallPlugin(plugin);
OGRE_DELETE plugin;
}
}
#endif
當加載完RenderSystem_Direct3D9.dll后,緊接著就呼叫"dllStartPlugin"函式,而在此函式中會生成一個D3D9Plugin的物件,并通過Root::installPlugin介面將此物件指標回傳給核心庫的Root物件,這樣一來,核心庫就可以通過這個指標來訪問動態加載的動態庫中的物件了,之前提出的第一個問題得到解決,
在早期的Ogre版本中,這種技術只用來處理三大模塊的分離,到了后期,Ogre引入了SampleBrowser的概念,同時將各Sampler也編譯成相應的dll文件,這樣一來,每個Sampler的加載和運行也以Plugin插件技術為基礎了,不論是早期的模塊分離,還是后期的Sampler演示,都會用一個.cfg配制檔案來描述要加載的Plugin插件,引擎會先讀取相應的.cfg檔案,再根據此配制檔案的描述來搜索和加載所需析Plugin插件,這就使得模塊的加載變得更加腳本化了,從而更方便,更靈活了,
Ogre的Plugin原理的啟示:
當需要將程式進行模塊化處理時,Ogre的這種Plugin技術是頗值得借鑒的,應用它可以在采用面向物件的編程技術并進行動態加載動態庫的時候,相當方便地對代碼邏輯進行模塊化設計,在此基礎上如果再引入配制檔案以實作自動加載,則會使程式的使用變得更為靈活和方便,
平平疑問記錄如下:
Ogre會在每個要被動態加載的dll庫物件中宣告一個名為“dllStartPlugin”的函式,
這里目前還沒理解,先記錄以后解決,
轉載自:https://www.cnblogs.com/yzwalkman/archive/2012/12/20/2826687.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/304069.html
標籤:其他
下一篇:用Qt做的拼圖小游戲
