ogre Learning Notes - Day 4

Keywords: ogre

ogre Learning Notes - Day 4

It took two days to buy a new hard drive and reinstall the system because the computer's C drive was damaged.

Look back at SampleBrowser's previous studies and recall.

SamplerBrowser loads some Sample resources, generates a UI, and clicks to select Sample.
There are three points here

  • How to load resources
  • How to create a UI
  • How to load a scene

The UI belongs to a component, regardless of it for the time being. First look at loading resources and loading scenarios.

Resource Loading

Sample* loadSamples()
{
    Ogre::ConfigFile cfg;
#if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
    // ...
#else
    cfg.load(mFSLayer->getConfigFilePath("samples.cfg"));
#endif
}

Just look at the Windows section. First, a configuration file is loaded through FileSystemLayer::getConfigFilePath. But this profile has only one name, where is it stored?
Find files by vscode ctrl+p and find many. Open them all and see that they are all the same.

SampleFolder=.
SamplePlugin=DefaultSamples
#SamplePlugin=PlayPenTests

This format resembles.ini [key=value].
By name, SampleFolder=. means that Sample's folders are using sibling directories. SamplePlugin doesn't know what that means.

The question is, there is only one name. How do I know which one is?

Ogre::String getConfigFilePath(Ogre::String filename) const
{
    // look for the requested file in several locations:
    
    // 1. in the writable path (so user can provide custom files)
    Ogre::String path = getWritablePath(filename);
    if (fileExists(path))
        return path;
    
    // 2. in the config file search paths
    for (const String& cpath : mConfigPaths)
    {
        path = cpath + filename;
        if (fileExists(path))
            return path;
    }
    
    // 3. fallback to current working dir
    return filename;
}

First, find a writable path

Ogre::String getWritablePath(const Ogre::String& filename) const
{
    return mHomePath + filename;
}

An mHomePath appears and debugging finds that it is a non-existent path.

Then, look for configPaths.

Look at the homepath and how configpath is assigned.

  • HomePath

            void setHomePath(const Ogre::String &path){
                mHomePath = path;
            }
    

    At a glance, I see the setHomePath function, and the debugging doesn't work! Helplessly, search globally.

    void FileSystemLayer::prepareUserHome(const Ogre::String& subdir)
    {
        // fill mHomePath
    #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        WCHAR wpath[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, 0, wpath)))
            widePathToOgreString(mHomePath, wpath);
    #elif OGRE_PLATFORM == OGRE_PLATFORM_WINRT
        widePathToOgreString(mHomePath, Windows::Storage::ApplicationData::Current->LocalFolder->Path->Data());
    #endif
    
        if(!mHomePath.empty())
        {
            mHomePath += '\\' + subdir + '\\';
            // create release subdir
            if (!createDirectory(mHomePath))
            {
                // couldn't create directory, fall back to current working dir
                mHomePath.clear();
            }
        }
    }
    
    FileSystemLayer(const Ogre::String& subdir)
    {
        // determine directories to search for config files
        getConfigPaths();
        // prepare write location in user directory
        prepareUserHome(subdir);
    }
    
    ApplicationContextBase::ApplicationContextBase(const Ogre::String& appName)
    {
        mAppName = appName;
        mFSLayer = new Ogre::FileSystemLayer(mAppName);
    
    // ...
    }
    

    hOME PATH takes the user's document path through SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE,...), then adds the name of the application to make up the path. For example: C:/Users/xxx/Documents/SampleBrowser/

  • configPaths

        void FileSystemLayer::getConfigPaths()
        {
    #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            // try to determine the application's path
            String appPath = getModulePath(false);
    #elif OGRE_PLATFORM == OGRE_PLATFORM_WINRT
            Ogre::String appPath;
            widePathToOgreString(appPath, Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data());
    #endif
    
            // use application path as config search path
            if (!appPath.empty())
                mConfigPaths.push_back(appPath + '\\');
    #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
            // look relative to the DLL according to PIP structure
            mConfigPaths.push_back(StringUtil::normalizeFilePath(getModulePath(true)+"/../../../bin/"));
    #endif
        }
    
  1. Path where the application is located (path to SampleBrowser)

  2. Path where dll is located

    Follow this line of thought and you'll find samples.cfg that you really use.
    Paths are found in sequence, so when files are renamed, it is easy to find them wrong.

Read Profile Content

Ogre::String sampleDir = cfg.getSetting("SampleFolder");        // Mac OS X just uses Resources/ directory
Ogre::StringVector sampleList = cfg.getMultiSetting("SamplePlugin");
Ogre::String startupSampleTitle = cfg.getSetting("StartupSample");
// loop through all sample plugins...
for (Ogre::StringVector::iterator i = sampleList.begin(); i != sampleList.end(); i++)
{
    try   // try to load the plugin
    {
#ifdef OGRE_STATIC_LIB
        // ...
#else
        mRoot->loadPlugin(sampleDir + *i);
#endif
    }
    catch (Ogre::Exception& e)   // plugin couldn't be loaded
    {
        Ogre::LogManager::getSingleton().logError(e.what());
        unloadedSamplePlugins.push_back(sampleDir + *i);
        continue;
    }
}

After reading the data, it is found that SamplePlugin=DefaultSamples in the configuration should be loaded by way of loadPlugin, that is, it treats sample as a plug-in! Follow its plugin action and import the DLL by name. So, find DefaultSamples. That's it in the project by name. Open DefaultSamples and find all the sample code.

Now that Sample is considered a plug-in, you don't need to delve into it any more. Go back and see how to load the scene.

Scene Loading

To load a scene, you must have a new scene object, the next breakpoint in the sample's constructor. Run the next breakpoint of the scene function runSamle. Run Discovery

DefaultSamplesPlugin::DefaultSamplesPlugin()  : SamplePlugin("DefaultSamplesPlugin")
{
    addSample(new Sample_AtomicCounters);
    addSample(new Sample_BezierPatch);
    // ...
}

When loading the plug-in, new has many scenes

Select a scene and click start. Enter runSample.

        virtual void runSample(Sample* s)
{
    // ...
    s->_setup(mWindow, mFSLayer, mOverlaySystem);   // start new sample
    // ...
}

virtual void _setup(Ogre::RenderWindow* window, Ogre::FileSystemLayer* fsLayer, Ogre::OverlaySystem* overlaySys)
{
    Sample::_setup(window, fsLayer, overlaySys);

    if(mTrayMgr)
        mControls.reset(new AdvancedRenderControls(mTrayMgr.get(), mCamera));
}
    virtual void _setup(Ogre::RenderWindow* window, Ogre::FileSystemLayer* fsLayer, Ogre::OverlaySystem* overlaySys)
    {
        mOverlaySystem = overlaySys;
        mWindow = window;

        mFSLayer = fsLayer;

        locateResources();
        createSceneManager();
        setupView();

        mCameraMan.reset(new CameraMan(mCameraNode));   // create a default camera controller

        loadResources();
        mResourcesLoaded = true;
        setupContent();
        mContentSetup = true;

        mDone = false;
    }
// BSP.h
void loadResources()
    {
        /* NOTE: The browser initialises everything at the beginning already, so we use a 0 init proportion.
           If you're not compiling this sample for use with the browser, then leave the init proportion at 0.7. */
        mTrayMgr->showLoadingBar(1, 1, 0);

        // associate the world geometry with the world resource group, and then load the group
        ResourceGroupManager& rgm = ResourceGroupManager::getSingleton();
        rgm.setCustomStagesForResourceGroup("BSPWorld", mSceneMgr->estimateWorldGeometry("maps/oa_rpg3dm2.bsp"));
        rgm.initialiseResourceGroup("BSPWorld");
        rgm.loadResourceGroup("BSPWorld");
        // one would register a ResourceGroupListener for this, if we were not to call it right away
        mSceneMgr->setWorldGeometry("maps/oa_rpg3dm2.bsp");

        mTrayMgr->hideLoadingBar();
    }

As you know the other day, in setup, you end up with loadResources(), setupContent().
Once you find a way to create/load/run a sample, you can learn about each sample individually.

Posted by XeRoZeN on Thu, 02 Dec 2021 09:12:27 -0800