ogre研究之第一個程序(一)

第一次發送超過字數了,被迫剪成兩篇!

上一篇我們介紹瞭如何搭建開發環境,並創建了一個空白的窗口程序。
這裏我們主要是實現在程序中裝載一個簡單的模型並顯示出來。
首先看一下效果吧,(模型就是ogre例子中的robot.mesh),如下:


例子很簡單,代碼頁不多,就4行。我們還是一步一步來分析吧。
首先我們上一個項目中的OgreDemo1類繼承自ExampleApplication類,我們之所以什麼都沒

有做就能創建一個窗口,就是因爲ExampleApplication爲我們實現了。
首先我們打開ExampleApplication類,可以看到包含了如下幾個成員變量(加入了少許註釋)

//ogre的程序"根"任何ogre程序都會有改對象     
Root *mRoot;     
//攝像機鏡頭     
Camera* mCamera;     
//場景管理器     
SceneManager* mSceneMgr;     
//對於每一幀進行處理的類     
ExampleFrameListener* mFrameListener;     
//渲染窗口     
RenderWindow* mWindow;     
//資源文件的路徑字符串     
Ogre::String mResourcePath;
這裏的ExampleFrameListener類,如果你暫時還不清楚是做什麼的,不要緊,後面我們慢慢介紹。
知道了這些成員變量,我們在返回OgreDemo1.c文件中看看入口函數WinMain中是如何書寫的呢
?很簡單就一句話:
app.go();
先將源代碼貼出來,加了詳細注意:
ExampleApplication.h
#ifndef __ExampleApplication_H__     
#define __ExampleApplication_H__     
    
#include "Ogre.h"     
#include "OgreConfigFile.h"     
#include "ExampleFrameListener.h"     
    
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE     
#include <CoreFoundation/CoreFoundation.h>     
    
std::string macBundlePath()     
{     
    char path[1024];     
    CFBundleRef mainBundle = CFBundleGetMainBundle();     
    assert(mainBundle);     
    
    CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);     
    assert(mainBundleURL);     
    
    CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);     
    assert(cfStringRef);     
    
    CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);     
    
    CFRelease(mainBundleURL);     
    CFRelease(cfStringRef);     
    
    return std::string(path);     
}     
#endif     
    
using namespace Ogre;     
    
/** Base class which manages the standard startup of an Ogre application.    
    Designed to be subclassed for specific examples if required.    
*/    
class ExampleApplication     
{     
public:     
    ExampleApplication()     
    {     
        mFrameListener = 0;     
        mRoot = 0;     
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE     
        mResourcePath = macBundlePath() + "/Contents/Resources/";     
#else     
        mResourcePath = "";     
#endif     
    }     
    /// Standard destructor     
    virtual ~ExampleApplication()     
    {     
        if (mFrameListener)     
            delete mFrameListener;     
        if (mRoot)     
            OGRE_DELETE mRoot;     
    }     
    
    /// 程序的入口     
    virtual void go(void)     
    {     
        //進行初始化工作     
        if (!setup())     
            return;     
        //開始渲染     
        mRoot->startRendering();     
        // 清理屏幕     
        destroyScene();     
    }     
    
protected:     
    //ogre的程序"根"任何ogre程序都會有改對象     
    Root *mRoot;     
    //攝像機鏡頭     
    Camera* mCamera;     
    //場景管理器     
    SceneManager* mSceneMgr;     
    //對於每一幀進行處理的類     
    ExampleFrameListener* mFrameListener;     
    //渲染窗口     
    RenderWindow* mWindow;     
    //資源文件的路徑字符串     
    Ogre::String mResourcePath;     
    //初始化應用程序     
    virtual bool setup(void)     
    {     
        String pluginsPath;     
#ifndef OGRE_STATIC_LIB     
        pluginsPath = mResourcePath + "plugins.cfg";     
#endif     
        //構建Root對象     
        mRoot = OGRE_NEW Root(pluginsPath,      
            mResourcePath + "ogre.cfg", mResourcePath + "Ogre.log");     
        //配置資源文件相關     
        setupResources();     
        //配置,主要用於初始化渲染窗口     
        bool carryOn = configure();     
        if (!carryOn) return false;     
        //創建場景管理器     
        chooseSceneManager();     
        //創建攝像機     
        createCamera();     
        //創建視口     
        createViewports();     
             
        TextureManager::getSingleton().setDefaultNumMipmaps(5);     
        //創建資源監聽     
        createResourceListener();     
        //牀在資源     
        loadResources();     
        //創建屏幕,必須重寫,也就是我們OgreDemo1類中(我們現實模型需要實現的)     
        createScene();     
        //創建幀監聽     
        createFrameListener();     
        return true;     
    }     
    /** 是否配置完成,完成則初始化系統 */    
    virtual bool configure(void)     
    {     
        //判斷是否進入(即運行過了配置窗口,進入demo窗口)     
        if(mRoot->showConfigDialog())     
        {     
            //初始化系統,得到一個渲染窗口對象     
            mWindow = mRoot->initialise(true);     
            return true;     
        }     
        else    
        {     
            return false;     
        }     
    }     
    
    virtual void chooseSceneManager(void)     
    {     
        // 創建一個場景管理器(場景類型,窗口標題)     
        mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "ExampleSMInstance");     
    }     
    virtual void createCamera(void)     
    {     
        // 創建一個攝像機     
        mCamera = mSceneMgr->createCamera("PlayerCam");     
    
        // 設置攝像機的位置     
        mCamera->setPosition(Vector3(0,0,500));     
        // 設置觀察點     
        mCamera->lookAt(Vector3(0,0,-300));     
        // 設置最近裁剪距離,如果超出則不顯示     
        mCamera->setNearClipDistance(5);     
        //同樣還有設置最遠裁剪距離     
        //mCamera->setFarClipDistance(1000);     
    }     
    //創建幀監聽     
    virtual void createFrameListener(void)     
    {     
        //實例化幀監聽,(渲染窗口,攝像機)     
        mFrameListener= new ExampleFrameListener(mWindow, mCamera);     
        //設置是否顯示調試信息(比如:fps...)     
        mFrameListener->showDebugOverlay(true);     
        //添加幀監聽到root中     
        mRoot->addFrameListener(mFrameListener);     
    }     
    //創建屏幕     
    virtual void createScene(void) = 0;      
    //清屏     
    virtual void destroyScene(void){}     
    /* 創建視口並初始化 */    
    virtual void createViewports(void)     
    {     
        // 創建一個“視口”     
        Viewport* vp = mWindow->addViewport(mCamera);     
        //設置背景顏色     
        vp->setBackgroundColour(ColourValue(0,0,0));     
    
        //設置屏幕的長寬比(視口的寬度和高度比,目前的寬屏電腦)     
        mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));     
    }     
    
    /// 初始化資源,比如:模型、貼圖等資源     
    virtual void setupResources(void)     
    {     
        ConfigFile cf;     
        //讀取配置文件     
        cf.load(mResourcePath + "resources.cfg");     
        ConfigFile::SectionIterator seci = cf.getSectionIterator();     
        String secName, typeName, archName;     
        while (seci.hasMoreElements())     
        {     
            secName = seci.peekNextKey();     
            ConfigFile::SettingsMultiMap *settings = seci.getNext();     
            ConfigFile::SettingsMultiMap::iterator i;     
            for (i = settings->begin(); i != settings->end(); ++i)     
            {     
                //取得並添加資源文件     
                typeName = i->first;     
                archName = i->second;     
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE     
                ResourceGroupManager::getSingleton().addResourceLocation(     
                    String(macBundlePath() + "/" + archName), typeName, secName);     
#else     
                ResourceGroupManager::getSingleton().addResourceLocation(     
                    archName, typeName, secName);     
#endif     
            }     
        }     
    }     
    
    //創建資源監聽,比如(正在裝載資源,請稍等界面)     
    virtual void createResourceListener(void)     
    {     
    }     
    
    //裝載資源     
    virtual void loadResources(void)     
    {     
        ResourceGroupManager::getSingleton().initialiseAllResourceGroups();     
    }     
};     
    
    
#endif 

ExampleFrameListener.h

#ifndef __ExampleFrameListener_H__     
#define __ExampleFrameListener_H__     
    
#include "Ogre.h"     
#include "OgreStringConverter.h"     
#include "OgreException.h"     
#define OIS_DYNAMIC_LIB     
#include <OIS/OIS.h>     
    
using namespace Ogre;     
    
class ExampleFrameListener: public FrameListener, public WindowEventListener     
{     
protected:     
    virtual void updateStats(void)     
    {     
        static String currFps = "Current FPS: ";     
        static String avgFps = "Average FPS: ";     
        static String bestFps = "Best FPS: ";     
        static String worstFps = "Worst FPS: ";     
        static String tris = "Triangle Count: ";     
        static String batches = "Batch Count: ";     
    
        // 需要更新debug信息時更新     
        try {     
            OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");     
            OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");     
            OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps");     
            OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");     
    
            const RenderTarget::FrameStats& stats = mWindow->getStatistics();     
            guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS));     
            guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS));     
            guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS)     
                +" "+StringConverter::toString(stats.bestFrameTime)+" ms");     
            guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS)     
                +" "+StringConverter::toString(stats.worstFrameTime)+" ms");     
    
            OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris");     
            guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount));     
    
            OverlayElement* guiBatches = OverlayManager::getSingleton().getOverlayElement("Core/NumBatches");     
            guiBatches->setCaption(batches + StringConverter::toString(stats.batchCount));     
    
            OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText");     
            guiDbg->setCaption(mDebugText);     
        }     
        catch(...) { /* ignore */ }     
    }     
    
public:     
    // 構造函數,初始化成員變量     
    ExampleFrameListener(RenderWindow* win, Camera* cam, bool bufferedKeys = false, bool bufferedMouse = false,     
                 bool bufferedJoy = false ) :     
        mCamera(cam), mTranslateVector(Vector3::ZERO), mCurrentSpeed(0), mWindow(win), mStatsOn(true), mNumScreenShots(0),     
        mMoveScale(0.0f), mRotScale(0.0f), mTimeUntilNextToggle(0), mFiltering(TFO_BILINEAR),     
        mAniso(1), mSceneDetailIndex(0), mMoveSpeed(100), mRotateSpeed(36), mDebugOverlay(0),     
        mInputManager(0), mMouse(0), mKeyboard(0), mJoy(0)     
    {     
        //得到debug視圖     
        mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay");     
        //日誌管理器     
        LogManager::getSingletonPtr()->logMessage("*** Initializing OIS ***");     
        OIS::ParamList pl;     
        size_t windowHnd = 0;     
        std::ostringstream windowHndStr;     
        //取得自定義的屬性     
        win->getCustomAttribute("WINDOW", &windowHnd);     
        windowHndStr << windowHnd;     
        pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));     
        //創建輸入管理器     
        mInputManager = OIS::InputManager::createInputSystem( pl );     
    
        //創建輸入設備、鼠標、鍵盤、搖桿     
        mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject( OIS::OISKeyboard, bufferedKeys ));     
        mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject( OIS::OISMouse, bufferedMouse ));     
        try {     
            mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject( OIS::OISJoyStick, bufferedJoy ));     
        }     
        catch(...) {     
            mJoy = 0;     
        }     
    
        //根據窗口的大小來設置鼠標的初始裁剪區域     
        windowResized(mWindow);     
        //顯示debug信息     
        showDebugOverlay(true);     
    
        //註冊一個windows窗口事件監聽     
        WindowEventUtilities::addWindowEventListener(mWindow, this);     
    }     
    
    //調整鼠標裁剪區域     
    virtual void windowResized(RenderWindow* rw)     
    {     
        unsigned int width, height, depth;     
        int left, top;     
        //取得窗口矩陣     
        rw->getMetrics(width, height, depth, left, top);     
        //得到鼠標     
        const OIS::MouseState &ms = mMouse->getMouseState();     
        ms.width = width;     
        ms.height = height;     
    }     
    
    //關閉窗口之前進行的處理     
    virtual void windowClosed(RenderWindow* rw)     
    {     
        //檢測是否關閉了我們的渲染窗口     
        if( rw == mWindow )     
        {     
            if( mInputManager )     
            {     
                //清除輸入設備     
                mInputManager->destroyInputObject( mMouse );     
                mInputManager->destroyInputObject( mKeyboard );     
                mInputManager->destroyInputObject( mJoy );     
                //銷燬輸入管理器     
                OIS::InputManager::destroyInputSystem(mInputManager);     
                mInputManager = 0;     
            }     
        }     
    }     
    
    virtual ~ExampleFrameListener()     
    {     
        //移除所有的窗口事件監聽     
        WindowEventUtilities::removeWindowEventListener(mWindow, this);     
        //關閉窗口     
        windowClosed(mWindow);     
    }     
    //按鍵事件處理     
    virtual bool processUnbufferedKeyInput(const FrameEvent& evt)     
    {     
    
        if(mKeyboard->isKeyDown(OIS::KC_A))     
            mTranslateVector.x = -mMoveScale;   // 向左移動攝像頭矩陣     
    
        if(mKeyboard->isKeyDown(OIS::KC_D))     
            mTranslateVector.x = mMoveScale;    // Move camera RIGHT     
    
        if(mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W) )     
            mTranslateVector.z = -mMoveScale;   // Move camera forward     
    
        if(mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S) )     
            mTranslateVector.z = mMoveScale;    // Move camera backward     
    
        if(mKeyboard->isKeyDown(OIS::KC_PGUP))     
            mTranslateVector.y = mMoveScale;    // Move camera up     
    
        if(mKeyboard->isKeyDown(OIS::KC_PGDOWN))     
            mTranslateVector.y = -mMoveScale;   // Move camera down     
    
        if(mKeyboard->isKeyDown(OIS::KC_RIGHT))     
            mCamera->yaw(-mRotScale);     
    
        if(mKeyboard->isKeyDown(OIS::KC_LEFT))     
            mCamera->yaw(mRotScale);     
    
        if( mKeyboard->isKeyDown(OIS::KC_ESCAPE) || mKeyboard->isKeyDown(OIS::KC_Q) )     
            return false;     
    
        if( mKeyboard->isKeyDown(OIS::KC_F) && mTimeUntilNextToggle <= 0 )     
        {     
            mStatsOn = !mStatsOn;     
            showDebugOverlay(mStatsOn);     
            mTimeUntilNextToggle = 1;     
        }     
    
        if( mKeyboard->isKeyDown(OIS::KC_T) && mTimeUntilNextToggle <= 0 )     
        {     
            switch(mFiltering)     
            {     
            case TFO_BILINEAR:     
                mFiltering = TFO_TRILINEAR;     
                mAniso = 1;     
                break;     
            case TFO_TRILINEAR:     
                mFiltering = TFO_ANISOTROPIC;     
                mAniso = 8;     
                break;     
            case TFO_ANISOTROPIC:     
                mFiltering = TFO_BILINEAR;     
                mAniso = 1;     
                break;     
            default: break;     
            }     
            MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering);     
            MaterialManager::getSingleton().setDefaultAnisotropy(mAniso);     
    
            showDebugOverlay(mStatsOn);     
            mTimeUntilNextToggle = 1;     
        }     
    
        if(mKeyboard->isKeyDown(OIS::KC_SYSRQ) && mTimeUntilNextToggle <= 0)     
        {     
            std::ostringstream ss;     
            ss << "screenshot_" << ++mNumScreenShots << ".png";     
            mWindow->writeContentsToFile(ss.str());     
            mTimeUntilNextToggle = 0.5;     
            mDebugText = "Saved: " + ss.str();     
        }     
    
        if(mKeyboard->isKeyDown(OIS::KC_R) && mTimeUntilNextToggle <=0)     
        {     
            mSceneDetailIndex = (mSceneDetailIndex+1)%3 ;     
            switch(mSceneDetailIndex) {     
                case 0 : mCamera->setPolygonMode(PM_SOLID); break;//設置多邊形的模式     
                case 1 : mCamera->setPolygonMode(PM_WIREFRAME); break;     
                case 2 : mCamera->setPolygonMode(PM_POINTS); break;     
            }     
            mTimeUntilNextToggle = 0.5;     
        }     
    
        static bool displayCameraDetails = false;     
        if(mKeyboard->isKeyDown(OIS::KC_P) && mTimeUntilNextToggle <= 0)     
        {     
            displayCameraDetails = !displayCameraDetails;     
            mTimeUntilNextToggle = 0.5;     
            if (!displayCameraDetails)     
                mDebugText = "";     
        }     
    
        if(displayCameraDetails)     
            mDebugText = "P: " + StringConverter::toString(mCamera->getDerivedPosition()) +     
                         " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation());     
        return true;     
    }     
    //鼠標事件處理     
    virtual bool processUnbufferedMouseInput(const FrameEvent& evt)     
    {     
    
        // Rotation factors, may not be used if the second mouse button is pressed     
        // 2nd mouse button - slide, otherwise rotate     
        const OIS::MouseState &ms = mMouse->getMouseState();     
        if( ms.buttonDown( OIS::MB_Right ) )     
        {     
            mTranslateVector.x += ms.X.rel * 0.13;     
            mTranslateVector.y -= ms.Y.rel * 0.13;     
        }     
        else    
        {     
            mRotX = Degree(-ms.X.rel * 0.13);     
            mRotY = Degree(-ms.Y.rel * 0.13);     
        }     
    
        return true;     
    }     
    
    //移動攝像頭     
    virtual void moveCamera()     
    {     
        //偏移     
        mCamera->yaw(mRotX);     
        //傾斜     
        mCamera->pitch(mRotY);     
        //移動攝像機到指定位置     
        mCamera->moveRelative(mTranslateVector);     
    }     
    //顯示debug信息     
    virtual void showDebugOverlay(bool show)     
    {     
        if (mDebugOverlay)     
        {     
            if (show)     
                mDebugOverlay->show();     
            else    
                mDebugOverlay->hide();     
        }     
    }     
    
    // 渲染隊列     
    bool frameRenderingQueued(const FrameEvent& evt)     
    {     
    
        if(mWindow->isClosed())  return false;     
    
        mSpeedLimit = mMoveScale * evt.timeSinceLastFrame;     
    
        //捕獲、更新設備     
        mKeyboard->capture();     
        mMouse->capture();     
        if( mJoy ) mJoy->capture();     
    
        bool buffJ = (mJoy) ? mJoy->buffered() : true;     
    
        Ogre::Vector3 lastMotion = mTranslateVector;     
        if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )     
        {     
            // one of the input modes is immediate, so setup what is needed for immediate movement     
            if (mTimeUntilNextToggle >= 0)     
                mTimeUntilNextToggle -= evt.timeSinceLastFrame;     
    
            // Move about 100 units per second     
            mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;     
            // Take about 10 seconds for full rotation     
            mRotScale = mRotateSpeed * evt.timeSinceLastFrame;     
    
            mRotX = 0;     
            mRotY = 0;     
            mTranslateVector = Ogre::Vector3::ZERO;     
    
        }     
    
        //Check to see which device is not buffered, and handle it     
        if( !mKeyboard->buffered() )     
            if( processUnbufferedKeyInput(evt) == false )     
                return false;     
        if( !mMouse->buffered() )     
            if( processUnbufferedMouseInput(evt) == false )     
                return false;     
    
        // ramp up / ramp down speed     
        if (mTranslateVector == Ogre::Vector3::ZERO)     
        {     
            // decay (one third speed)     
            mCurrentSpeed -= evt.timeSinceLastFrame * 0.3;     
            mTranslateVector = lastMotion;     
        }     
        else    
        {     
            // ramp up     
            mCurrentSpeed += evt.timeSinceLastFrame;     
    
        }     
        // Limit motion speed     
        if (mCurrentSpeed > 1.0)     
            mCurrentSpeed = 1.0;     
        if (mCurrentSpeed < 0.0)     
            mCurrentSpeed = 0.0;     
    
        mTranslateVector *= mCurrentSpeed;     
    
    
        if( !mMouse->buffered() || !mKeyboard->buffered() || !buffJ )     
            moveCamera();     
    
        return true;     
    }     
    
    //幀結束,更新狀態     
    bool frameEnded(const FrameEvent& evt)     
    {     
        updateStats();     
        return true;     
    }     
    
protected:     
    //指向攝像機的指針     
    Camera* mCamera;     
    //一個3維向量,用於攝像機的位置變換     
    Vector3 mTranslateVector;     
    Real mCurrentSpeed;     
    //指向渲染窗口的指針     
    RenderWindow* mWindow;     
    //是否顯示調試信息     
    bool mStatsOn;     
    //debug信息     
    std::string mDebugText;     
    //主要用於截圖     
    unsigned int mNumScreenShots;     
    //該demo中,攝像機會旋轉     
    float mMoveScale;     
    //速度限制     
    float mSpeedLimit;     
    //同樣用於攝像機變換     
    Degree mRotScale;     
    //延時     
    Real mTimeUntilNextToggle ;     
    //鼠標旋轉的角度,用於攝像機的更新     
    Radian mRotX, mRotY;     
    //紋理差值的類型,枚舉類型     
    TextureFilterOptions mFiltering;     
    int mAniso;     
    int mSceneDetailIndex ;     
    //移動速度     
    Real mMoveSpeed;     
    //旋轉速度     
    Degree mRotateSpeed;     
    //debug視圖     
    Overlay* mDebugOverlay;     
    
    //一些輸入設備(輸入設備管理器)     
    OIS::InputManager* mInputManager;     
    //鼠標     
    OIS::Mouse*    mMouse;     
    //鍵盤     
    OIS::Keyboard* mKeyboard;     
    //搖桿     
    OIS::JoyStick* mJoy;     
};     
    
#endif 
接續(二)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章