• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Ogre源碼剖析3–可擴(kuò)展性&插件機(jī)制

             

            Ogre是一個(gè)跨操作系統(tǒng)平臺(tái)的開(kāi)源3D引擎,既支持DirectX,也支持使用OpenGL,支持可替換的場(chǎng)景管理算法(BSP, OCT)。為Ogre提供這些靈活可擴(kuò)展性的基礎(chǔ)之一就是其面向插件的設(shè)計(jì)。

             

            很多常用的軟件大都提供了插件接口,用以擴(kuò)展應(yīng)用程序設(shè)計(jì)者最初未想到的功能,比較常見(jiàn)的譬如PhotoShop的濾鏡,After Effect中的各種插件(最有名的比如shine),3dMax的插件譬如渲染器,魔獸世界的輔助插件等等。

            通常,插件本身通常也需要實(shí)現(xiàn)主應(yīng)用程序所需要的必要接口,從而使得插件可以被應(yīng)用程序加載執(zhí)行。此外,插件的實(shí)現(xiàn)也需要由主應(yīng)用程序提供一些接口api,通過(guò)這些接口,插件可以對(duì)主應(yīng)用程序的功能進(jìn)行調(diào)用。

            插件可以是動(dòng)態(tài)鏈接庫(kù)(win32平臺(tái)上為DLL文件),也可以是以腳本的形式提供的,比如魔獸世界中的插件就是使用lua編寫(xiě)的,插件也可能是某種應(yīng)用程序自定義的文件,只要該應(yīng)用程序提供了創(chuàng)建該類文件的方法并實(shí)現(xiàn)解析、執(zhí)行功能即可。(不同的實(shí)現(xiàn)形式各有利弊,具體需要參考插件及應(yīng)用程序所處的運(yùn)行環(huán)境進(jìn)行取舍)

            采用插件的一個(gè)巨大的好處,以及很多應(yīng)用程序中使用插件的主要目的就是,我們可以在不需要改動(dòng)應(yīng)用程序本身的情況下擴(kuò)展應(yīng)用程序的功能。

             

            在Ogre中,插件被用來(lái)提供渲染子系統(tǒng)(RenderSystem),不同類別的圖形API被封裝在不同的渲染子系統(tǒng)的視線當(dāng)中,Ogre默認(rèn)提供了DX和OpenGL的實(shí)現(xiàn),甚至,如果我們樂(lè)意,甚至可以只用繪點(diǎn)函數(shù)實(shí)現(xiàn)一套純軟件的渲染子系統(tǒng)提供給Ogre使用。以此為例,用簡(jiǎn)單的形式來(lái)展示這種實(shí)現(xiàn)大概類似于下面這樣:

            class RenderSystem

            {

                     
            // … operations that a render system need to support

            };

            // In DX_RenderSystem.dll (in plugin dx rendersystem )

            class DX_RenderSystem : public RenderSystem

            {

                     
            // … implementation & override of the operations from RenderSystem using DirectX

            };

            // In GL_RenderSystem.dll (in plugin openGL rendersystem)

            class GL_RenderSystem : public RenderSystem

            {

                     
            // … implementation & override of the operations from RenderSystem using OpenGL

            };

            // …. We could implement any other rendersystem as we like

             

            在引擎的內(nèi)部(OgreMain),插件在初始化的時(shí)候,將一個(gè)渲染子系統(tǒng)的實(shí)例創(chuàng)建出來(lái)(可能是DX_RenderSystem,也可能是 GL_RenderSystem,也可能是其他),并將之掛接到OgreMain的Root對(duì)象當(dāng)中。此后,OgreMain中的Root所有的渲染操作也就可以通過(guò)該接口訪問(wèn)插件中創(chuàng)建的渲染子系統(tǒng)了。

             

                     本文接下來(lái)分析Ogre是如何實(shí)現(xiàn)插件的,以及插件是如何與OgreMain主引擎進(jìn)行配合的。

                     事實(shí)上,想編寫(xiě)一個(gè)插件是很簡(jiǎn)單的,我們只需要約定幾個(gè)接口,插件將這些接口實(shí)現(xiàn)了,主應(yīng)用程序通過(guò)某種機(jī)制(配置文件
            /遍歷某個(gè)目錄)加載插件,并查找接口在插件中是否被實(shí)現(xiàn)了,如果實(shí)現(xiàn)了,則調(diào)用之即可。

             

            一個(gè)簡(jiǎn)單的例子如下:

            // in xx.dll

            __declspec(dllexport) 
            extern “C”    // __declspec(dllexport)告知編譯器需要將該函數(shù)導(dǎo)出

                                                                             
            // extern “C” 告知編譯器不要對(duì)函數(shù)做C++名字重整

            const char* GetPluginName(void)

            {

                     
            return “Test Plugin”;

            }

             

            // in application

            HMODULE hInst 
            = LoadLibrary(”xx.dll”);

            if (!hInst) return;

            typedef 
            const char* (*GetPluginNameFunc)(void);

            GetPluginNameFunc pFunc 
            = GetProcAddress(hInst, “GetPluginName”);

            if (!pFunc) return;

            const char* szPluginName = pFunc();

            // … do other things

             

            事實(shí)上,在C語(yǔ)言里,我們就可以通過(guò)這種方式,約定一套需要實(shí)現(xiàn)的接口,交給插件實(shí)現(xiàn)即可。在這里,插件的功能都是在dll中實(shí)現(xiàn)的,我們需要加載 dll,保存句柄,并在插件卸載的時(shí)候釋放相應(yīng)的資源。在C
            ++中,我們顯然可以做的更好一點(diǎn),比如將dll模塊相關(guān)的功能以及資源封裝起來(lái):

             

            class DynLib

            {

            public:

                     
            bool Load(const char* szPluginPath);

                     
            void* GetProcAddress(const char* szProcName);

            private:

                     HMODULE m_hInst;

            };

             

            bool DynLib::Load(const char* szPluginPath)

            {

            m_hInst 
            = LoadLibrary(szPluginPath);

            return m_hInst != NULL;

            }

             

            void* DynLib::GetProcAddress(const char* szProcName)

            {

                     
            return ::GetProcAddress(m_hInst, szProcName);

            }

             

            這樣一來(lái),我們就有了一個(gè)DLL的簡(jiǎn)單封裝。

            但是一個(gè)dll里未必只能有一個(gè)插件,假若我們簡(jiǎn)單的把插件接口設(shè)計(jì)為一套C導(dǎo)出函數(shù),我們就不得不面對(duì)這種局限。經(jīng)典的做法依舊是抽象,Ogre中定義了一個(gè)插件接口,每一個(gè)實(shí)現(xiàn)了插件接口的實(shí)例都代表了一個(gè)插件,如下:

             

            class Plugin

            {

            public:

                     
            virtual const String& getName() = 0;

                     
            virtual void install() = 0;

                     
            virtual void initialize() = 0;

                     
            virtual void shutdown() = 0;

                     
            virtual void uninstall() = 0;

            };

             

            Ogre的每一個(gè)插件都需要實(shí)現(xiàn)以上接口。該接口提供的功能包括:

            install 插件被加載時(shí)調(diào)用。

            initialize 插件被初始化時(shí)調(diào)用。

            shutdown 插件被反初始化時(shí)調(diào)用。

            uninstall 插件被卸載時(shí)調(diào)用。

             

            不過(guò),單有這個(gè)接口,插件還是無(wú)法工作。插件中還需要提供兩個(gè)約定的C導(dǎo)出函數(shù)。這個(gè)稍后再說(shuō)。

             

            Ogre在Root對(duì)象中統(tǒng)一管理插件,因此Root對(duì)象提供了以下與插件相關(guān)的接口:

            class Root

            {

                     
            // …

            void loadPlugin(const String& pluginName);

            void unloadPlugin(const String& pluginName);

            void installPlugin(Plugin* plugin);

            void uninstallPlugin(Plugin* plugin);

            // 以及對(duì)應(yīng)的處理多個(gè)插件的接口

                     
            // …

            };

             

            當(dāng)loadPlugin函數(shù)被調(diào)用時(shí),Ogre將加載該插件的dll,從中查找并調(diào)用名為dllStartPlugin的導(dǎo)出函數(shù)。

            對(duì)應(yīng)的,當(dāng)unloadPlugin函數(shù)被調(diào)用時(shí),Ogre將從該dll中調(diào)用dllStopPlugin函數(shù)。并將該dll卸載。

             

            每個(gè)插件在實(shí)現(xiàn)的時(shí)候,都必須提供上述的兩個(gè)C導(dǎo)出函數(shù)。其中,dllStartPlugin負(fù)責(zé)創(chuàng)建插件實(shí)例,并調(diào)用 Root::installPlugin,將創(chuàng)建好的插件指針傳遞給Root對(duì)象。在這里,dllStartPlugin實(shí)際可以創(chuàng)建多個(gè)插件實(shí)例,并依次調(diào)用Root::installPlugin,這樣我們就可以在一個(gè)DLL中包含多個(gè)插件了。在dllStopPlugin時(shí),則需要調(diào)用 Root::uninstallPlugin,并將插件DLL中創(chuàng)建的plugin實(shí)例釋放掉。

             

            一個(gè)典型的dllStartPlugin的實(shí)現(xiàn)像這樣:

             

            class D3D9Plugin : public Plugin

            {

                     
            //

            };

             

            D3D9Plugin
            * plugin;

            __declspec(dllexport) 
            extern “C”

            void dllStrartPlugin(void)

            {

                     plugin 
            = new D3D9Plugin();

                     Root::getSingleton().installPlugin(plugin);

            }

             

            __declspec(dllexport) 
            extern “C”

            void dllStopPlugin(void)

            {

            Root::getSingleton().uninstallPlugin(plugin);

            delete plugin;

            }

             

            Root::getSingleton().installPlugin(plugin)會(huì)負(fù)責(zé)調(diào)用插件的install以及initialise操作,并將插件的指針存放起來(lái),以備卸載時(shí)使用。

             

            Plugin::install以及Plugin::initialise則分別負(fù)責(zé)創(chuàng)建OgreMain提供擴(kuò)展功能接口的實(shí)例,以及將創(chuàng)建好的對(duì)象掛載到應(yīng)用程序當(dāng)中。

             

            一個(gè)典型的Plugin的行為像這樣:

             

            void BspSceneManagerPlugin::install()

            {

                     mBspFactory 
            = new BspSceneManagerFactory();

            }

             

            void BspSceneManagerPlugin::initialise()

            {

                     Root::getSingleton().addSceneManagerFactory(mBspFactory);

            }

             

            其中,BspSceneManagerFactory是繼承自O(shè)greMain中的SceneManagerFactory的派生類。

            class BspSceneManagerFactory : public SceneManagerFactory {…} )

             

            通過(guò)將場(chǎng)景管理器工廠添加到Root對(duì)象當(dāng)中,插件動(dòng)態(tài)的將其功能添加到了OgreMain當(dāng)中。

             

            PS: SceneManagerFactory是一個(gè)用于創(chuàng)建SceneManager的工廠。SceneManager則是被用于場(chǎng)景管理的管理器。具體的 SceneManager也根據(jù)算法不同而不同,Ogre自帶提供了兩種類型的場(chǎng)景管理算法插件:Bsp以及Octree(實(shí)現(xiàn)了兩個(gè)對(duì)應(yīng)的插件,分別是 Plugin_BSPSceneManager以及Plugin_OctreeSceneManager)。

             

            通過(guò)上述方式,OgreMain核心引擎并不需要關(guān)心場(chǎng)景管理算法的具體實(shí)現(xiàn),不需要關(guān)心渲染子系統(tǒng)的具體實(shí)現(xiàn),不需要關(guān)心粒子系統(tǒng)的具體實(shí)現(xiàn),等等。一切這些擴(kuò)展性的功能都通過(guò)插件實(shí)現(xiàn),并在加載時(shí)動(dòng)態(tài)掛載到OgreMain當(dāng)中,供OgreMain的引擎核心使用。

             

            使用插件時(shí)幾個(gè)需要注意的地方:

            1,  調(diào)用插件DLL方法創(chuàng)建的對(duì)象需要交由插件DLL釋放。(因?yàn)椴煌逆溄訂卧赡芫哂胁煌膬?nèi)存管理上下文環(huán)境,此處的new與彼處的new在語(yǔ)義上未必等同)

            2,  調(diào)用插件DLL方法獲取的插件內(nèi)對(duì)象的引用或指針,在插件DLL卸載之后就是無(wú)效的,必須保證不再使用。(比較容易引發(fā)問(wèn)題的一個(gè)典型例子是從插件中傳遞回一個(gè)引用計(jì)數(shù)字符串,當(dāng)DLL被卸載后,字符串內(nèi)指向?qū)嶋H數(shù)據(jù)的指針已經(jīng)無(wú)效,但是在該對(duì)象析構(gòu)時(shí),仍需要訪問(wèn)該指針)

            posts - 94, comments - 138, trackbacks - 0, articles - 94

            Copyright © RichardHe

            中文成人久久久久影院免费观看| 久久人人爽人人爽人人片av高请| 久久久久亚洲精品男人的天堂| 国产香蕉97碰碰久久人人| 久久久无码精品亚洲日韩京东传媒 | 性高湖久久久久久久久| 2021久久国自产拍精品| 亚洲а∨天堂久久精品9966| 国产精品18久久久久久vr| 伊人久久大香线蕉综合5g| 91久久成人免费| 久久精品国产亚洲AV香蕉| 亚洲国产成人久久综合碰| 99re这里只有精品热久久| 久久亚洲日韩看片无码| 精品国产青草久久久久福利 | 久久这里只有精品视频99| 日韩人妻无码精品久久久不卡| 日韩久久久久中文字幕人妻| www久久久天天com| 伊人久久精品无码二区麻豆| 欧美亚洲另类久久综合婷婷| 久久精品一区二区三区不卡| 午夜欧美精品久久久久久久| 久久笫一福利免费导航| 久久久久久一区国产精品| 91精品国产91久久久久久青草| 久久精品黄AA片一区二区三区| 国产美女亚洲精品久久久综合| 欧美伊人久久大香线蕉综合69| 精品免费久久久久国产一区| 亚洲国产成人久久综合碰碰动漫3d| 久久青青草原精品国产| 亚洲精品无码久久一线| 久久SE精品一区二区| 久久人做人爽一区二区三区| 久久最新免费视频| 亚洲欧美一区二区三区久久| 色8激情欧美成人久久综合电| 狠狠精品久久久无码中文字幕| 日本免费久久久久久久网站|