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 }
-
Path where the application is located (path to SampleBrowser)
-
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.