1 /*
2  * OgreApplicationContext.cpp
3  *
4  *  Created on: 18.05.2016
5  *      Author: pavel
6  */
7 
8 #include "OgreApplicationContext.h"
9 
10 #include "OgreRoot.h"
11 #include "OgreGpuProgramManager.h"
12 #include "OgreConfigFile.h"
13 #include "OgreRenderWindow.h"
14 #include "OgreViewport.h"
15 #include "OgreOverlaySystem.h"
16 #include "OgreDataStream.h"
17 #include "OgreBitesConfigDialog.h"
18 #include "OgreWindowEventUtilities.h"
19 
20 #include "OgreConfigPaths.h"
21 
22 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
23 #include "OgreArchiveManager.h"
24 #include "OgreFileSystem.h"
25 #include "OgreZip.h"
26 #endif
27 
28 #if OGRE_BITES_HAVE_SDL
29 #include <SDL.h>
30 #include <SDL_video.h>
31 #include <SDL_syswm.h>
32 
33 #include "SDLInputMapping.h"
34 #endif
35 
36 namespace OgreBites {
37 
38 static const char* SHADER_CACHE_FILENAME = "cache.bin";
39 
ApplicationContext(const Ogre::String & appName,bool)40 ApplicationContext::ApplicationContext(const Ogre::String& appName, bool)
41 #if (OGRE_THREAD_PROVIDER == 3) && (OGRE_NO_TBB_SCHEDULER == 1)
42     : mTaskScheduler(tbb::task_scheduler_init::deferred)
43     #endif
44 {
45     mAppName = appName;
46     mFSLayer = new Ogre::FileSystemLayer(mAppName);
47     mRoot = NULL;
48     mOverlaySystem = NULL;
49     mFirstRun = true;
50 
51 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
52     mAAssetMgr = NULL;
53     mAConfig = NULL;
54 #endif
55 
56 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
57     mMaterialMgrListener = NULL;
58     mShaderGenerator = NULL;
59 #endif
60 }
61 
~ApplicationContext()62 ApplicationContext::~ApplicationContext()
63 {
64     delete mFSLayer;
65 }
66 
initApp()67 void ApplicationContext::initApp()
68 {
69     createRoot();
70 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
71     if (!oneTimeConfig()) return;
72 
73     if (!mFirstRun) mRoot->setRenderSystem(mRoot->getRenderSystemByName(mNextRenderer));
74 
75     setup();
76 
77     mRoot->saveConfig();
78 
79     Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();
80 
81     // Clear event times
82     Ogre::Root::getSingleton().clearEventTimes();
83 #else
84 
85     if (!oneTimeConfig()) return;
86 
87 #if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
88     // if the context was reconfigured, set requested renderer
89     if (!mFirstRun) mRoot->setRenderSystem(mRoot->getRenderSystemByName(mNextRenderer));
90 #endif
91 
92     setup();
93 #endif
94 }
95 
closeApp()96 void ApplicationContext::closeApp()
97 {
98     shutdown();
99     if (mRoot)
100     {
101 #if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
102         mRoot->saveConfig();
103 #endif
104         OGRE_DELETE mRoot;
105         mRoot = NULL;
106     }
107 
108 #ifdef OGRE_STATIC_LIB
109     mStaticPluginLoader.unload();
110 #endif
111 
112 #if (OGRE_THREAD_PROVIDER == 3) && (OGRE_NO_TBB_SCHEDULER == 1)
113     if (mTaskScheduler.is_active())
114         mTaskScheduler.terminate();
115 #endif
116 }
117 
initialiseRTShaderSystem()118 bool ApplicationContext::initialiseRTShaderSystem()
119 {
120 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
121     if (Ogre::RTShader::ShaderGenerator::initialize())
122     {
123         mShaderGenerator = Ogre::RTShader::ShaderGenerator::getSingletonPtr();
124 
125 #if OGRE_PLATFORM != OGRE_PLATFORM_WINRT
126         // Core shader libs not found -> shader generating will fail.
127         if (mRTShaderLibPath.empty())
128             return false;
129 #endif
130 
131         // Create and register the material manager listener if it doesn't exist yet.
132         if (!mMaterialMgrListener) {
133             mMaterialMgrListener = new SGTechniqueResolverListener(mShaderGenerator);
134             Ogre::MaterialManager::getSingleton().addListener(mMaterialMgrListener);
135         }
136     }
137 
138     return true;
139 #else
140     return false;
141 #endif
142 }
143 
setRTSSWriteShadersToDisk(bool write)144 void ApplicationContext::setRTSSWriteShadersToDisk(bool write)
145 {
146 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
147     if(!write) {
148         mShaderGenerator->setShaderCachePath("");
149         return;
150     }
151 
152     // Set shader cache path.
153 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
154     mShaderGenerator->setShaderCachePath(mFSLayer->getWritablePath(""));
155 #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE
156     mShaderGenerator->setShaderCachePath(mFSLayer->getWritablePath("org.ogre3d.RTShaderCache/"));
157 #else
158     mShaderGenerator->setShaderCachePath(mRTShaderLibPath+"/cache/");
159 #endif
160 #endif
161 }
162 
destroyRTShaderSystem()163 void ApplicationContext::destroyRTShaderSystem()
164 {
165 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
166     //mShaderGenerator->removeAllShaderBasedTechniques();
167     //mShaderGenerator->flushShaderCache();
168 
169     // Restore default scheme.
170     Ogre::MaterialManager::getSingleton().setActiveScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
171 
172     // Unregister the material manager listener.
173     if (mMaterialMgrListener != NULL)
174     {
175         Ogre::MaterialManager::getSingleton().removeListener(mMaterialMgrListener);
176         delete mMaterialMgrListener;
177         mMaterialMgrListener = NULL;
178     }
179 
180     // Destroy RTShader system.
181     if (mShaderGenerator != NULL)
182     {
183         Ogre::RTShader::ShaderGenerator::destroy();
184         mShaderGenerator = NULL;
185     }
186 #endif
187 }
188 
setup()189 void ApplicationContext::setup()
190 {
191     mRoot->initialise(false);
192     createWindow(mAppName);
193 
194     locateResources();
195     initialiseRTShaderSystem();
196     loadResources();
197 
198     // adds context as listener to process context-level (above the sample level) events
199     mRoot->addFrameListener(this);
200 }
201 
createRoot()202 void ApplicationContext::createRoot()
203 {
204 #if (OGRE_THREAD_PROVIDER == 3) && (OGRE_NO_TBB_SCHEDULER == 1)
205     mTaskScheduler.initialize(OGRE_THREAD_HARDWARE_CONCURRENCY);
206 #endif
207 
208 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID || OGRE_PLATFORM == OGRE_PLATFORM_EMSCRIPTEN
209     mRoot = OGRE_NEW Ogre::Root("");
210 #else
211     Ogre::String pluginsPath;
212 #   ifndef OGRE_STATIC_LIB
213     pluginsPath = mFSLayer->getConfigFilePath("plugins.cfg");
214 
215     if (!Ogre::FileSystemLayer::fileExists(pluginsPath))
216     {
217         pluginsPath = Ogre::FileSystemLayer::resolveBundlePath(OGRE_CONFIG_DIR "/plugins" OGRE_BUILD_SUFFIX ".cfg");
218     }
219 #   endif
220 
221     mRoot = OGRE_NEW Ogre::Root(pluginsPath, mFSLayer->getWritablePath("ogre.cfg"),
222                                 mFSLayer->getWritablePath("ogre.log"));
223 #endif
224 
225 #ifdef OGRE_STATIC_LIB
226     mStaticPluginLoader.load();
227 #endif
228     mOverlaySystem = OGRE_NEW Ogre::OverlaySystem();
229 }
230 
oneTimeConfig()231 bool ApplicationContext::oneTimeConfig()
232 {
233 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID || OGRE_PLATFORM == OGRE_PLATFORM_EMSCRIPTEN
234     mRoot->setRenderSystem(mRoot->getAvailableRenderers().at(0));
235 #else
236     if (!mRoot->restoreConfig()) {
237         return mRoot->showConfigDialog(OgreBites::getNativeConfigDialog());
238     }
239 #endif
240     return true;
241 }
242 
createDummyScene()243 void ApplicationContext::createDummyScene()
244 {
245     mWindows[0].render->removeAllViewports();
246     Ogre::SceneManager* sm = mRoot->createSceneManager("DefaultSceneManager", "DummyScene");
247     sm->addRenderQueueListener(mOverlaySystem);
248     Ogre::Camera* cam = sm->createCamera("DummyCamera");
249     mWindows[0].render->addViewport(cam);
250 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
251     // Initialize shader generator.
252     // Must be before resource loading in order to allow parsing extended material attributes.
253     if (!initialiseRTShaderSystem())
254     {
255         OGRE_EXCEPT(Ogre::Exception::ERR_FILE_NOT_FOUND,
256                     "Shader Generator Initialization failed - Core shader libs path not found",
257                     "ApplicationContext::createDummyScene");
258     }
259 
260     mShaderGenerator->addSceneManager(sm);
261 #endif // OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
262 }
263 
destroyDummyScene()264 void ApplicationContext::destroyDummyScene()
265 {
266     if(!mRoot->hasSceneManager("DummyScene"))
267         return;
268 
269     Ogre::SceneManager*  dummyScene = mRoot->getSceneManager("DummyScene");
270 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
271     mShaderGenerator->removeSceneManager(dummyScene);
272 #endif
273     dummyScene->removeRenderQueueListener(mOverlaySystem);
274     mWindows[0].render->removeAllViewports();
275     mRoot->destroySceneManager(dummyScene);
276 }
277 
enableShaderCache() const278 void ApplicationContext::enableShaderCache() const
279 {
280     Ogre::GpuProgramManager::getSingleton().setSaveMicrocodesToCache(true);
281 
282     // Load for a package version of the shaders.
283     Ogre::String path = mFSLayer->getWritablePath(SHADER_CACHE_FILENAME);
284     std::ifstream inFile(path.c_str(), std::ios::binary);
285     if (!inFile.is_open())
286     {
287         Ogre::LogManager::getSingleton().logWarning("Could not open '"+path+"'");
288         return;
289     }
290     Ogre::LogManager::getSingleton().logMessage("Loading shader cache from '"+path+"'");
291     Ogre::DataStreamPtr istream(new Ogre::FileStreamDataStream(path, &inFile, false));
292     Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(istream);
293 }
294 
addInputListener(NativeWindowType * win,InputListener * lis)295 void ApplicationContext::addInputListener(NativeWindowType* win, InputListener* lis)
296 {
297     uint32_t id = 0;
298 #if OGRE_BITES_HAVE_SDL
299     id = SDL_GetWindowID(win);
300 #endif
301     mInputListeners.insert(std::make_pair(id, lis));
302 }
303 
304 
removeInputListener(NativeWindowType * win,InputListener * lis)305 void ApplicationContext::removeInputListener(NativeWindowType* win, InputListener* lis)
306 {
307     uint32_t id = 0;
308 #if OGRE_BITES_HAVE_SDL
309     id = SDL_GetWindowID(win);
310 #endif
311     mInputListeners.erase(std::make_pair(id, lis));
312 }
313 
frameRenderingQueued(const Ogre::FrameEvent & evt)314 bool ApplicationContext::frameRenderingQueued(const Ogre::FrameEvent& evt)
315 {
316     for(InputListenerList::iterator it = mInputListeners.begin();
317             it != mInputListeners.end(); ++it) {
318         it->second->frameRendered(evt);
319     }
320 
321     return true;
322 }
323 
createWindow(const Ogre::String & name,Ogre::uint32 w,Ogre::uint32 h,Ogre::NameValuePairList miscParams)324 NativeWindowPair ApplicationContext::createWindow(const Ogre::String& name, Ogre::uint32 w, Ogre::uint32 h, Ogre::NameValuePairList miscParams)
325 {
326     NativeWindowPair ret = {NULL, NULL};
327 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
328     miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(reinterpret_cast<size_t>(mWindows[0].native));
329     miscParams["androidConfig"] = Ogre::StringConverter::toString(reinterpret_cast<size_t>(mAConfig));
330     miscParams["preserveContext"] = "true"; //Optionally preserve the gl context, prevents reloading all resources, this is false by default
331 
332     mWindows[0].render = Ogre::Root::getSingleton().createRenderWindow(name, 0, 0, false, &miscParams);
333     ret = mWindows[0];
334 #else
335     Ogre::ConfigOptionMap ropts = mRoot->getRenderSystem()->getConfigOptions();
336 
337     if(w == 0 && h == 0)
338     {
339         std::istringstream mode(ropts["Video Mode"].currentValue);
340         Ogre::String token;
341         mode >> w; // width
342         mode >> token; // 'x' as seperator between width and height
343         mode >> h; // height
344     }
345 
346     if(miscParams.empty())
347     {
348         miscParams["FSAA"] = ropts["FSAA"].currentValue;
349         miscParams["vsync"] = ropts["VSync"].currentValue;
350         miscParams["gamma"] = ropts["sRGB Gamma Conversion"].currentValue;
351     }
352 
353     if(!mWindows.empty()) {
354         // additional windows should reuse the context
355         miscParams["currentGLContext"] = "true";
356     }
357 
358 
359 
360 #if OGRE_BITES_HAVE_SDL
361     if(!SDL_WasInit(SDL_INIT_VIDEO)) {
362         SDL_InitSubSystem(SDL_INIT_VIDEO);
363     }
364 
365     Uint32 flags = SDL_WINDOW_RESIZABLE;
366 
367     if(ropts["Full Screen"].currentValue == "Yes"){
368        flags = SDL_WINDOW_FULLSCREEN;
369     } else {
370        flags = SDL_WINDOW_RESIZABLE;
371     }
372 
373     ret.native = SDL_CreateWindow(name.c_str(),
374                                 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags);
375 
376 #if OGRE_PLATFORM == OGRE_PLATFORM_EMSCRIPTEN
377     SDL_GL_CreateContext(ret.native);
378     miscParams["currentGLContext"] = "true";
379 #else
380     SDL_SysWMinfo wmInfo;
381     SDL_VERSION(&wmInfo.version);
382     SDL_GetWindowWMInfo(ret.native, &wmInfo);
383 #endif
384 
385 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
386     miscParams["parentWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.x11.window));
387 #elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32
388     miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.win.window));
389 #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE
390     assert(wmInfo.subsystem == SDL_SYSWM_COCOA);
391     miscParams["externalWindowHandle"] = Ogre::StringConverter::toString(size_t(wmInfo.info.cocoa.window));
392 #endif
393 #endif
394     ret.render = mRoot->createRenderWindow(name, w, h, false, &miscParams);
395     mWindows.push_back(ret);
396 #endif
397 
398 #if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID && !OGRE_BITES_HAVE_SDL
399     WindowEventUtilities::_addRenderWindow(ret.render);
400 #endif
401 
402     return ret;
403 }
404 
405 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
initAppForAndroid(AAssetManager * assetMgr,ANativeWindow * window)406 void ApplicationContext::initAppForAndroid(AAssetManager* assetMgr, ANativeWindow* window)
407 {
408     mAConfig = AConfiguration_new();
409     AConfiguration_fromAssetManager(mAConfig, assetMgr);
410     mAAssetMgr = assetMgr;
411 
412     mWindows.resize(1);
413     mWindows[0].native = window;
414 
415     initApp();
416 }
417 
openAPKFile(const Ogre::String & fileName)418 Ogre::DataStreamPtr ApplicationContext::openAPKFile(const Ogre::String& fileName)
419 {
420     Ogre::Archive* apk = Ogre::ArchiveManager::getSingleton().load("", "APKFileSystem", true);
421     return apk->open(fileName);
422 }
423 
_fireInputEventAndroid(AInputEvent * event,int wheel)424 void ApplicationContext::_fireInputEventAndroid(AInputEvent* event, int wheel) {
425     Event evt = {0};
426 
427     static TouchFingerEvent lastTouch = {0};
428 
429     if(wheel) {
430         evt.type = MOUSEWHEEL;
431         evt.wheel.y = wheel;
432         _fireInputEvent(evt, 0);
433         lastTouch.fingerId = -1; // prevent move-jump after pinch is over
434         return;
435     }
436 
437     if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
438         int32_t action = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction(event);
439 
440         switch (action) {
441         case AMOTION_EVENT_ACTION_DOWN:
442             evt.type = FINGERDOWN;
443             break;
444         case AMOTION_EVENT_ACTION_UP:
445             evt.type = FINGERUP;
446             break;
447         case AMOTION_EVENT_ACTION_MOVE:
448             evt.type = FINGERMOTION;
449             break;
450         default:
451             return;
452         }
453 
454         Ogre::RenderWindow* win = getRenderWindow();
455 
456         evt.tfinger.fingerId = AMotionEvent_getPointerId(event, 0);
457         evt.tfinger.x = AMotionEvent_getRawX(event, 0) / win->getWidth();
458         evt.tfinger.y = AMotionEvent_getRawY(event, 0) / win->getHeight();
459 
460         if(evt.type == FINGERMOTION) {
461             if(evt.tfinger.fingerId != lastTouch.fingerId)
462                 return; // wrong finger
463 
464             evt.tfinger.dx = evt.tfinger.x - lastTouch.x;
465             evt.tfinger.dy = evt.tfinger.y - lastTouch.y;
466         }
467 
468         lastTouch = evt.tfinger;
469     } else {
470         if(AKeyEvent_getKeyCode(event) != AKEYCODE_BACK)
471             return;
472 
473         evt.type = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN ? KEYDOWN : KEYUP;
474         evt.key.keysym.sym = SDLK_ESCAPE;
475     }
476 
477     _fireInputEvent(evt, 0);
478 }
479 #endif
480 
_fireInputEvent(const Event & event,uint32_t windowID) const481 void ApplicationContext::_fireInputEvent(const Event& event, uint32_t windowID) const
482 {
483     for(InputListenerList::iterator it = mInputListeners.begin();
484             it != mInputListeners.end(); ++it)
485     {
486         if(it->first != windowID) continue;
487 
488         InputListener& l = *it->second;
489 
490         switch (event.type)
491         {
492         case KEYDOWN:
493             l.keyPressed(event.key);
494             break;
495         case KEYUP:
496             l.keyReleased(event.key);
497             break;
498         case MOUSEBUTTONDOWN:
499             l.mousePressed(event.button);
500             break;
501         case MOUSEBUTTONUP:
502             l.mouseReleased(event.button);
503             break;
504         case MOUSEWHEEL:
505             l.mouseWheelRolled(event.wheel);
506             break;
507         case MOUSEMOTION:
508             l.mouseMoved(event.motion);
509             break;
510         case FINGERDOWN:
511             // for finger down we have to move the pointer first
512             l.touchMoved(event.tfinger);
513             l.touchPressed(event.tfinger);
514             break;
515         case FINGERUP:
516             l.touchReleased(event.tfinger);
517             break;
518         case FINGERMOTION:
519             l.touchMoved(event.tfinger);
520             break;
521         }
522     }
523 }
524 
setWindowGrab(NativeWindowType * win,bool _grab)525 void ApplicationContext::setWindowGrab(NativeWindowType* win, bool _grab)
526 {
527 #if OGRE_BITES_HAVE_SDL
528     SDL_bool grab = SDL_bool(_grab);
529 
530     SDL_SetWindowGrab(win, grab);
531     SDL_SetRelativeMouseMode(grab);
532 #endif
533 }
534 
getDefaultMediaDir()535 Ogre::String ApplicationContext::getDefaultMediaDir()
536 {
537     return Ogre::FileSystemLayer::resolveBundlePath(OGRE_MEDIA_DIR);
538 }
539 
locateResources()540 void ApplicationContext::locateResources()
541 {
542     // load resource paths from config file
543     Ogre::ConfigFile cf;
544 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
545     Ogre::ArchiveManager::getSingleton().addArchiveFactory( new Ogre::APKFileSystemArchiveFactory(mAAssetMgr) );
546     Ogre::ArchiveManager::getSingleton().addArchiveFactory( new Ogre::APKZipArchiveFactory(mAAssetMgr) );
547     Ogre::Archive* apk = Ogre::ArchiveManager::getSingleton().load("", "APKFileSystem", true);
548     cf.load(apk->open(mFSLayer->getConfigFilePath("resources.cfg")));
549 #else
550     Ogre::String resourcesPath = mFSLayer->getConfigFilePath("resources.cfg");
551     if (Ogre::FileSystemLayer::fileExists(resourcesPath) || OGRE_PLATFORM == OGRE_PLATFORM_EMSCRIPTEN)
552     {
553         cf.load(resourcesPath);
554     }
555     else
556     {
557         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
558             getDefaultMediaDir(), "FileSystem",
559             Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
560     }
561 
562 #endif
563 
564     Ogre::String sec, type, arch;
565     // go through all specified resource groups
566     Ogre::ConfigFile::SettingsBySection_::const_iterator seci;
567     for(seci = cf.getSettingsBySection().begin(); seci != cf.getSettingsBySection().end(); ++seci) {
568         sec = seci->first;
569         const Ogre::ConfigFile::SettingsMultiMap& settings = seci->second;
570         Ogre::ConfigFile::SettingsMultiMap::const_iterator i;
571 
572         // go through all resource paths
573         for (i = settings.begin(); i != settings.end(); i++)
574         {
575             type = i->first;
576             arch = Ogre::FileSystemLayer::resolveBundlePath(i->second);
577 
578             Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch, type, sec);
579         }
580     }
581 
582     sec = Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME;
583     const Ogre::ResourceGroupManager::LocationList genLocs = Ogre::ResourceGroupManager::getSingleton().getResourceLocationList(sec);
584 
585     OgreAssert(!genLocs.empty(), ("Resource Group '"+sec+"' must contain at least one entry").c_str());
586 
587     arch = genLocs.front().archive->getName();
588 
589 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
590     arch = Ogre::FileSystemLayer::resolveBundlePath("Contents/Resources/Media");
591 #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
592     arch = Ogre::FileSystemLayer::resolveBundlePath("Media");
593 #else
594     arch = Ogre::StringUtil::replaceAll(arch, "Media/../../Tests/Media", "");
595     arch = Ogre::StringUtil::replaceAll(arch, "media/../../Tests/Media", "");
596 #endif
597     type = genLocs.front().archive->getType();
598 
599     bool hasCgPlugin = false;
600     const Ogre::Root::PluginInstanceList& plugins = getRoot()->getInstalledPlugins();
601     for(size_t i = 0; i < plugins.size(); i++)
602     {
603         if(plugins[i]->getName() == "Cg Program Manager")
604         {
605             hasCgPlugin = true;
606             break;
607         }
608     }
609 
610     bool use_HLSL_Cg_shared = hasCgPlugin || Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("hlsl");
611 
612     // Add locations for supported shader languages
613     if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
614     {
615         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/GLSLES", type, sec);
616     }
617     else if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsl"))
618     {
619         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/GLSL120", type, sec);
620 
621         if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsl150"))
622         {
623             Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/GLSL150", type, sec);
624         }
625         else
626         {
627             Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/GLSL", type, sec);
628         }
629 
630         if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsl400"))
631         {
632             Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/GLSL400", type, sec);
633         }
634     }
635     else if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("hlsl"))
636     {
637         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/HLSL", type, sec);
638     }
639 
640     if(hasCgPlugin)
641         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/Cg", type, sec);
642     if (use_HLSL_Cg_shared)
643         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch + "/materials/programs/HLSL_Cg", type, sec);
644 
645 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
646     mRTShaderLibPath = arch + "/RTShaderLib";
647     Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/materials", type, sec);
648 
649     if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsles"))
650     {
651         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/GLSL", type, sec);
652         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/GLSLES", type, sec);
653     }
654     else if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("glsl"))
655     {
656         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/GLSL", type, sec);
657     }
658     else if(Ogre::GpuProgramManager::getSingleton().isSyntaxSupported("hlsl"))
659     {
660         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/HLSL", type, sec);
661     }
662 
663     if(hasCgPlugin)
664         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/Cg", type, sec);
665     if (use_HLSL_Cg_shared)
666         Ogre::ResourceGroupManager::getSingleton().addResourceLocation(mRTShaderLibPath + "/HLSL_Cg", type, sec);
667 
668 #endif /* OGRE_BUILD_COMPONENT_RTSHADERSYSTEM */
669 }
670 
loadResources()671 void ApplicationContext::loadResources()
672 {
673     Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
674 }
675 
reconfigure(const Ogre::String & renderer,Ogre::NameValuePairList & options)676 void ApplicationContext::reconfigure(const Ogre::String &renderer, Ogre::NameValuePairList &options)
677 {
678     mNextRenderer = renderer;
679     Ogre::RenderSystem* rs = mRoot->getRenderSystemByName(renderer);
680 
681     // set all given render system options
682     for (Ogre::NameValuePairList::iterator it = options.begin(); it != options.end(); it++)
683     {
684         rs->setConfigOption(it->first, it->second);
685 
686 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
687         // Change the viewport orientation on the fly if requested
688         if(it->first == "Orientation")
689         {
690             Ogre::RenderWindow* win = getRenderWindow();
691 
692             if (it->second == "Landscape Left")
693                 win->getViewport(0)->setOrientationMode(Ogre::OR_LANDSCAPELEFT, true);
694             else if (it->second == "Landscape Right")
695                 win->getViewport(0)->setOrientationMode(Ogre::OR_LANDSCAPERIGHT, true);
696             else if (it->second == "Portrait")
697                 win->getViewport(0)->setOrientationMode(Ogre::OR_PORTRAIT, true);
698         }
699 #endif
700     }
701 
702 #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
703     // Need to save the config on iOS to make sure that changes are kept on disk
704     mRoot->saveConfig();
705 #endif
706     mRoot->queueEndRendering();   // break from render loop
707 }
708 
shutdown()709 void ApplicationContext::shutdown()
710 {
711     const auto& gpuMgr = Ogre::GpuProgramManager::getSingleton();
712     if (gpuMgr.getSaveMicrocodesToCache() && gpuMgr.isCacheDirty())
713     {
714         Ogre::String path = mFSLayer->getWritablePath(SHADER_CACHE_FILENAME);
715         std::fstream outFile(path.c_str(), std::ios::out | std::ios::binary);
716 
717         if (outFile.is_open())
718         {
719             Ogre::LogManager::getSingleton().logMessage("Writing shader cache to "+path);
720             Ogre::DataStreamPtr ostream(new Ogre::FileStreamDataStream(path, &outFile, false));
721             gpuMgr.saveMicrocodeCache(ostream);
722         }
723         else
724             Ogre::LogManager::getSingleton().logWarning("Cannot open shader cache for writing "+path);
725     }
726 
727 #ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
728     // Destroy the RT Shader System.
729     destroyRTShaderSystem();
730 #endif
731 
732     for(WindowList::iterator it = mWindows.begin(); it != mWindows.end(); ++it)
733     {
734 #if !OGRE_BITES_HAVE_SDL
735         // remove window event listener before destroying it
736         WindowEventUtilities::_removeRenderWindow(it->render);
737 #endif
738         mRoot->destroyRenderTarget(it->render);
739     }
740 
741     if (mOverlaySystem)
742     {
743         OGRE_DELETE mOverlaySystem;
744     }
745 
746 #if OGRE_BITES_HAVE_SDL
747     for(WindowList::iterator it = mWindows.begin(); it != mWindows.end(); ++it)
748     {
749         if(it->native)
750             SDL_DestroyWindow(it->native);
751     }
752     if(!mWindows.empty()) {
753         SDL_QuitSubSystem(SDL_INIT_VIDEO);
754     }
755 #endif
756 
757     mWindows.clear();
758     mInputListeners.clear();
759 
760 #if OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
761     AConfiguration_delete(mAConfig);
762 #endif
763 }
764 
pollEvents()765 void ApplicationContext::pollEvents()
766 {
767 #if OGRE_BITES_HAVE_SDL
768     if(mWindows.empty())
769     {
770         // SDL events not initialized
771         return;
772     }
773 
774     SDL_Event event;
775     while (SDL_PollEvent(&event))
776     {
777         switch (event.type)
778         {
779         case SDL_QUIT:
780             mRoot->queueEndRendering();
781             break;
782         case SDL_WINDOWEVENT:
783             if(event.window.event != SDL_WINDOWEVENT_RESIZED)
784                 continue;
785 
786             for(WindowList::iterator it = mWindows.begin(); it != mWindows.end(); ++it)
787             {
788                 if(event.window.windowID != SDL_GetWindowID(it->native))
789                     continue;
790 
791                 Ogre::RenderWindow* win = it->render;
792                 win->windowMovedOrResized();
793                 windowResized(win);
794             }
795             break;
796         default:
797             _fireInputEvent(convert(event), event.window.windowID);
798             break;
799         }
800     }
801 
802 #   if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
803     // hacky workaround for black window on OSX
804     for(const auto& win : mWindows)
805     {
806         SDL_SetWindowSize(win.native, win.render->getWidth(), win.render->getHeight());
807         win.render->windowMovedOrResized();
808     }
809 #   endif
810 #elif OGRE_PLATFORM == OGRE_PLATFORM_ANDROID
811     for(WindowList::iterator it = mWindows.begin(); it != mWindows.end(); ++it)
812     {
813         Ogre::RenderWindow* win = it->render;
814         win->windowMovedOrResized();
815         windowResized(win);
816     }
817 #else
818     // just avoid "window not responding"
819     WindowEventUtilities::messagePump();
820 #endif
821 }
822 
823 }
824