On my quest to understand Ogre for Android I disassembled the SampleBrowser and the TinyOgre Example and managed to get a running example that is relatively small and easy to understand compared to the huge amount of code in the SampleBrowser/SampleContext/Sample .....
Since this is an Open Source Engine, I hope some other people might help tidying up the code so that we can create a nice Android Example.
Personally, I use the NSight Tegra, Visual Studio Edition to create and run my Android projects - I simply prefer the easier Visual Studio compared to writing scripts. I will also upload the visual studio project later on. Should you want to create and hopefully share those scripts, I will add a list with the required libraries and all.
Credit goes to the creators of the SampleBrowser and the Frameworks
Now to get started we need the following:
Compile the SampleBrowserDummy according to this wiki article. That means that you'll have to download cmake, the Android NDK, the Android SDK, Ant, Ogre 1.9, the Ogre Android Dependencies and some kind of make. Just follow the guide =)
That way you will have all the libraries compiled all nicely. Should you have problems with that, please read this forum topic
Now create an Android project of your choice.
Basically we're looking to create an Android Native Application. That means we make an Android Application without Java code.
I removed all the other code paths and left only the Android stuff. To keep the code short, I left out the Input.
The main.c file
Code: Select all
#include "OgrePlatform.h"
#include "TinyOgre.h"
#include "SampleBrowser_Android.h"
TinyOgre* OgreBites::OgreAndroidBridge::mBrowser = NULL;
Ogre::RenderWindow* OgreBites::OgreAndroidBridge::mRenderWnd = NULL;
Ogre::Root* OgreBites::OgreAndroidBridge::mRoot = NULL;
bool OgreBites::OgreAndroidBridge::mInit = false;
#ifdef OGRE_STATIC_LIB
Ogre::StaticPluginLoader* OgreBites::OgreAndroidBridge::mStaticPluginLoader = NULL;
#endif
/**
init the dummy
init the OgreAndroidBridge which does some setting up and preparing
The app needs to be handled in a special way as it behavesdifferently compared to a desktop programm
There are new states which need to be handled. That's what the Bridge does.
the go command is fired
the app handler receives the init app call and reacts to it
APP_CMD_INIT_WINDOW
loads configuration
creates the TinyOgre module.
initAppForAndroid(mRenderWnd, app, NULL, NULL); is called. this basically sends the window and the app to the tinyogre module
initApp(); this initializes the app and starts it.
creates root
setup
init resource groups
shader cache
creates scene manager
inits RT shader system
adds scene manager to rt shader system
loads resources
adds frame listener.
the go command does the loop as soon as the window and all is set up properly
this is basically a manual loop instead of the usual ogre startRendering command or some such.
*/
void android_main(struct android_app* state) {
// Make sure glue isn't stripped.
app_dummy();
OgreBites::OgreAndroidBridge::init(state);
OgreBites::OgreAndroidBridge::go(state);
}
Code: Select all
#ifndef __SampleBrowser_Android_H__
#define __SampleBrowser_Android_H__
#ifdef OGRE_STATIC_LIB
# ifdef OGRE_BUILD_RENDERSYSTEM_GL
# define OGRE_STATIC_GL
# endif
# ifdef OGRE_BUILD_RENDERSYSTEM_GLES
# define OGRE_STATIC_GLES
# undef USE_RTSHADER_SYSTEM
# endif
# ifdef OGRE_BUILD_RENDERSYSTEM_GLES2
#undef OGRE_STATIC_GLES
# define USE_RTSHADER_SYSTEM
# define OGRE_STATIC_GLES2
# endif
# if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WINRT
# ifdef OGRE_BUILD_RENDERSYSTEM_D3D9
# define OGRE_STATIC_Direct3D9
# endif
// dx11 will only work on vista and above, so be careful about statically linking
# ifdef OGRE_BUILD_RENDERSYSTEM_D3D11
# define OGRE_STATIC_Direct3D11
# endif
# endif
# ifdef OGRE_BUILD_PLUGIN_BSP
# define OGRE_STATIC_BSPSceneManager
# endif
# ifdef OGRE_BUILD_PLUGIN_PFX
# define OGRE_STATIC_ParticleFX
# endif
# ifdef OGRE_BUILD_PLUGIN_CG
# define OGRE_STATIC_CgProgramManager
# endif
# ifdef OGRE_USE_PCZ
# ifdef OGRE_BUILD_PLUGIN_PCZ
# define OGRE_STATIC_PCZSceneManager
# define OGRE_STATIC_OctreeZone
# endif
# else
# ifdef OGRE_BUILD_PLUGIN_OCTREE
# define OGRE_STATIC_OctreeSceneManager
# endif
# endif
# include "OgreStaticPluginLoader.h"
#endif
#include "OIS.h"
#include <android_native_app_glue.h>
#include <android/log.h>
#include <EGL/egl.h>
#include "OgrePlatform.h"
#include "TinyOgre.h"
#include "Android/OgreAndroidEGLWindow.h"
#ifdef USE_RTSHADER_SYSTEM
# include "OgreRTShaderSystem.h"
#endif
#ifdef OGRE_STATIC_LIB
# include "OgreStaticPluginLoader.h"
#endif
#if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
# error This header is for use with Android only
#endif
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Ogre", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "Ogre", __VA_ARGS__))
using namespace Ogre;
namespace OgreBites
{
//class OgreAndroidBridge;
/*=============================================================================
| Ogre Android bridge
=============================================================================*/
class OgreAndroidBridge
{
public:
static void init(struct android_app* state)
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "samplebrowser_android.h OgreAndroidBridge init called");
//registering the app window state handler
state->onAppCmd = &OgreAndroidBridge::handleCmd;
if(mInit)
return;
mRoot = new Ogre::Root();
#ifdef OGRE_STATIC_LIB
mStaticPluginLoader = new Ogre::StaticPluginLoader();
mStaticPluginLoader->load();
#else
#error "need ogre static libs"
#endif
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "samplebrowser_android.h OgreAndroidBridge init StaticPluginLoader loaded");
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "samplebrowser_android.h OgreAndroidBridge init setting rendersystem");
mRoot->setRenderSystem(mRoot->getAvailableRenderers().at(0));
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "samplebrowser_android.h OgreAndroidBridge init root init");
mRoot->initialise(false);
mInit = true;
}
static void shutdown()
{
if(!mInit)
return;
mInit = false;
if(mBrowser)
{
mBrowser->closeApp();
OGRE_DELETE mBrowser;
mBrowser = NULL;
}
OGRE_DELETE mRoot;
mRoot = NULL;
mRenderWnd = NULL;
#ifdef OGRE_STATIC_LIB
mStaticPluginLoader->unload();
delete mStaticPluginLoader;
mStaticPluginLoader = NULL;
#endif
}
static void handleCmd(struct android_app* app, int32_t cmd)
{
switch (cmd)
{
case APP_CMD_SAVE_STATE:
break;
case APP_CMD_INIT_WINDOW:
if (app->window && mRoot)
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "OgreAndroidBridge handleCmd APP_CMD_INIT_WINDOW");
AConfiguration* config = AConfiguration_new();
AConfiguration_fromAssetManager(config, app->activity->assetManager);
if (!mRenderWnd)
{
Ogre::NameValuePairList opt;
opt["externalWindowHandle"] = Ogre::StringConverter::toString((int)app->window);
opt["androidConfig"] = Ogre::StringConverter::toString((int)config);
mRenderWnd = Ogre::Root::getSingleton().createRenderWindow("OgreWindow", 0, 0, false, &opt);
if(!mBrowser)
{
mBrowser = OGRE_NEW TinyOgre();
mBrowser->initAppForAndroid(mRenderWnd, app, NULL, NULL);
mBrowser->initApp();
//mInputInjector = new AndroidInputInjector(mBrowser, mTouch, mKeyboard);
}
}
else
{
static_cast<AndroidEGLWindow*>(mRenderWnd)->_createInternalResources(app->window, config);
}
AConfiguration_delete(config);
}
break;
case APP_CMD_TERM_WINDOW:
if(mRoot && mRenderWnd)
static_cast<AndroidEGLWindow*>(mRenderWnd)->_destroyInternalResources();
break;
case APP_CMD_GAINED_FOCUS:
break;
case APP_CMD_LOST_FOCUS:
break;
case APP_CMD_CONFIG_CHANGED:
break;
}
}
static void go(struct android_app* state)
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "samplebrowser_android.h OgreAndroidBridge go called - this starts a massive loop");
int ident, events;
struct android_poll_source* source;
while (true)
{
while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0)
{
if (source != NULL)
source->process(state, source);
if (state->destroyRequested != 0)
return;
}
if(mRenderWnd != NULL && mRenderWnd->isActive())
{
mRenderWnd->windowMovedOrResized();
mRoot->renderOneFrame();
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "OMGLOOP");
}
}
}
static Ogre::RenderWindow* getRenderWindow()
{
return mRenderWnd;
}
private:
static TinyOgre* mBrowser;
static Ogre::RenderWindow* mRenderWnd;
static Ogre::Root* mRoot;
static bool mInit;
#ifdef OGRE_STATIC_LIB
static Ogre::StaticPluginLoader* mStaticPluginLoader;
#endif
};
}
#endif
Code: Select all
#ifndef __TinyOgre_h_
#define __TinyOgre_h_
//#include "Ogre.h"
//#include "OgreOverlaySystem.h"
#include <iostream>
#include "InputContext.h"
#include "OgreFileSystemLayer.h"
#include "SdkTrays.h"
#include <android_native_app_glue.h>
#include "Android/OgreAPKFileSystemArchive.h"
#include "Android/OgreAPKZipArchive.h"
#include <android/log.h>
#define ENABLE_SHADERS_CACHE_SAVE 1
#define ENABLE_SHADERS_CACHE_LOAD 1
#ifdef OGRE_STATIC_LIB
# ifdef USE_RTSHADER_SYSTEM
# include "OgreRTShaderSystem.h"
// Remove the comment below in order to make the RTSS use valid path for writing down the generated shaders.
// If cache path is not set - all shaders are generated to system memory.
//#define _RTSS_WRITE_SHADERS_TO_DISK
# endif // USE_RTSHADER_SYSTEM
#endif // OGRE_STATIC_LIB
#ifdef USE_RTSHADER_SYSTEM
/** This class demonstrates basic usage of the RTShader system.
It sub class the material manager listener class and when a target scheme callback
is invoked with the shader generator scheme it tries to create an equivalent shader
based technique based on the default technique of the given material.
*/
class ShaderGeneratorTechniqueResolverListener : public Ogre::MaterialManager::Listener
{
public:
ShaderGeneratorTechniqueResolverListener(Ogre::RTShader::ShaderGenerator* pShaderGenerator)
{
mShaderGenerator = pShaderGenerator;
}
/** This is the hook point where shader based technique will be created.
It will be called whenever the material manager won't find appropriate technique
that satisfy the target scheme name. If the scheme name is out target RT Shader System
scheme name we will try to create shader generated technique for it.
*/
virtual Ogre::Technique* handleSchemeNotFound(unsigned short schemeIndex,
const Ogre::String& schemeName, Ogre::Material* originalMaterial, unsigned short lodIndex,
const Ogre::Renderable* rend)
{
Ogre::Technique* generatedTech = NULL;
// Case this is the default shader generator scheme.
if (schemeName == Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME)
{
bool techniqueCreated;
// Create shader generated technique for this material.
techniqueCreated = mShaderGenerator->createShaderBasedTechnique(
originalMaterial->getName(),
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
schemeName);
// Case technique registration succeeded.
if (techniqueCreated)
{
// Force creating the shaders for the generated technique.
mShaderGenerator->validateMaterial(schemeName, originalMaterial->getName());
// Grab the generated technique.
Ogre::Material::TechniqueIterator itTech = originalMaterial->getTechniqueIterator();
while (itTech.hasMoreElements())
{
Ogre::Technique* curTech = itTech.getNext();
if (curTech->getSchemeName() == schemeName)
{
generatedTech = curTech;
break;
}
}
}
}
return generatedTech;
}
protected:
Ogre::RTShader::ShaderGenerator* mShaderGenerator; // The shader generator instance.
};
#endif // USE_RTSHADER_SYSTEM
class TinyOgre :
public Ogre::FrameListener,
public Ogre::WindowEventListener
{
public:
TinyOgre(void)
:mRoot(0),
mCamera(0),
mSceneMgr(0),
mWindow(0),
mResourcesCfg(Ogre::StringUtil::BLANK),
mPluginsCfg(Ogre::StringUtil::BLANK),
mResourcesLoaded(false),
mContentSetup(false),
mDone(false)
{
mFSLayer = OGRE_NEW_T(Ogre::FileSystemLayer, Ogre::MEMCATEGORY_GENERAL)(OGRE_VERSION_NAME);
};
virtual ~TinyOgre(void)
{
};
/*-----------------------------------------------------------------------------
| Creates the OGRE root.
-----------------------------------------------------------------------------*/
virtual void createRoot()
{
mRoot = Ogre::Root::getSingletonPtr();
mOverlaySystem = OGRE_NEW Ogre::OverlaySystem();
}
virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt)
{
//mCamera->frameRenderingQueued(evt); // if dialog isn't up, then update the camera
return true;
}
virtual void setupView()
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h setting up view,cameras");
// setup default viewport layout and camera
mCamera = mSceneMgr->createCamera("MainCamera");
mViewport = mWindow->addViewport(mCamera);
mCamera->setAspectRatio((Ogre::Real)mViewport->getActualWidth() / (Ogre::Real)mViewport->getActualHeight());
mCamera->setAutoAspectRatio(true);
mCamera->setNearClipDistance(0.1);
mCamera->setPosition(Ogre::Vector3(0,10,-180));
mCamera->lookAt(Ogre::Vector3(0,0,0));
}
virtual void setupContent()
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h setting up content");
// setup some basic lighting for our scene
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3));
mSceneMgr->createLight()->setPosition(20, 80, 50);
//mTrayMgr->showCursor();
// create a floor mesh resource
Ogre::MeshManager::getSingleton().createPlane("floor", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
Ogre::Plane(Ogre::Vector3::UNIT_Y, -30), 1000, 1000, 10, 10, true, 1, 8, 8, Ogre::Vector3::UNIT_Z);
// create a floor entity, give it a material, and place it at the origin
Ogre::Entity* floor = mSceneMgr->createEntity("Floor", "floor");
floor->setMaterialName("Examples/BumpyMetal");
mSceneMgr->getRootSceneNode()->attachObject(floor);
// create an ogre head entity and place it at the origin
mSceneMgr->getRootSceneNode()->attachObject(mSceneMgr->createEntity("Head", "ogrehead.mesh"));
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h setting up finished");
}
/*-----------------------------------------------------------------------------
| Quits the current sample and starts a new one.
-----------------------------------------------------------------------------*/
virtual void runSample()
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h runSample called");
mWindow->removeAllViewports(); // wipe viewports
// assign mRoot here in case Root was initialised after the Sample's constructor ran.
//mRoot = Ogre::Root::getSingletonPtr();
//locateResources();
setupView();
mResourcesLoaded = true;
setupContent();
mContentSetup = true;
mDone = false;
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h runSample finished");
}
/*-----------------------------------------------------------------------------
| Creates a scene manager for the sample. A generic one is the default,
| but many samples require a special kind of scene manager.
-----------------------------------------------------------------------------*/
virtual void createSceneManager()
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h creating scene manager");
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
if(mOverlaySystem)
mSceneMgr->addRenderQueueListener(mOverlaySystem);
}
/*-----------------------------------------------------------------------------
| init pre-created window for android
-----------------------------------------------------------------------------*/
/**
settung up the application for the android platform. Adding functionality for the APK file and setting the precreated window.
*/
void initAppForAndroid(Ogre::RenderWindow *window, struct android_app* app, OIS::MultiTouch *mouse, OIS::Keyboard *keyboard)
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initAppForAndroid called");
mWindow = window;
if(app != NULL)
{
mAssetMgr = app->activity->assetManager;
Ogre::ArchiveManager::getSingleton().addArchiveFactory( new Ogre::APKFileSystemArchiveFactory(app->activity->assetManager) );
Ogre::ArchiveManager::getSingleton().addArchiveFactory( new Ogre::APKZipArchiveFactory(app->activity->assetManager) );
}
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initAppForAndroid done");
}
/*-----------------------------------------------------------------------------
| This function initializes the render system and resources.
-----------------------------------------------------------------------------*/
/**
initializes the whole app.
@pre this needs to be called after initAppForAndroid
*/
virtual void initApp()
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp called");
createRoot();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp root created");
setup();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp setup done");
runSample();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp sample ran");
//mRoot->saveConfig();
Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp _initRenderTargets done");
// Clear event times
Ogre::Root::getSingleton().clearEventTimes();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "tinyogre.h initApp finished");
}
/*-----------------------------------------------------------------------------
| Initialize the RT Shader system.
-----------------------------------------------------------------------------*/
virtual bool initializeRTShaderSystem(Ogre::SceneManager* sceneMgr)
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h initializing RTShaderSystem");
if (Ogre::RTShader::ShaderGenerator::initialize())
{
mShaderGenerator = Ogre::RTShader::ShaderGenerator::getSingletonPtr();
mShaderGenerator->addSceneManager(sceneMgr);
/*
#if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID && OGRE_PLATFORM != OGRE_PLATFORM_NACL && OGRE_PLATFORM != OGRE_PLATFORM_WINRT
// Setup core libraries and shader cache path.
Ogre::StringVector groupVector = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
Ogre::StringVector::iterator itGroup = groupVector.begin();
Ogre::StringVector::iterator itGroupEnd = groupVector.end();
Ogre::String shaderCoreLibsPath;
Ogre::String shaderCachePath;
for (; itGroup != itGroupEnd; ++itGroup)
{
Ogre::ResourceGroupManager::LocationList resLocationsList = Ogre::ResourceGroupManager::getSingleton().getResourceLocationList(*itGroup);
Ogre::ResourceGroupManager::LocationList::iterator it = resLocationsList.begin();
Ogre::ResourceGroupManager::LocationList::iterator itEnd = resLocationsList.end();
bool coreLibsFound = false;
// Try to find the location of the core shader lib functions and use it
// as shader cache path as well - this will reduce the number of generated files
// when running from different directories.
for (; it != itEnd; ++it)
{
if ((*it)->archive->getName().find("RTShaderLib") != Ogre::String::npos)
{
shaderCoreLibsPath = (*it)->archive->getName() + "/cache/";
shaderCachePath = shaderCoreLibsPath;
coreLibsFound = true;
break;
}
}
// Core libs path found in the current group.
if (coreLibsFound)
break;
}
// Core shader libs not found -> shader generating will fail.
if (shaderCoreLibsPath.empty())
return false;
#ifdef _RTSS_WRITE_SHADERS_TO_DISK
// Set shader cache path.
mShaderGenerator->setShaderCachePath(shaderCachePath);
#endif
#endif*/
// Create and register the material manager listener if it doesn't exist yet.
if (mMaterialMgrListener == NULL) {
mMaterialMgrListener = new ShaderGeneratorTechniqueResolverListener(mShaderGenerator);
Ogre::MaterialManager::getSingleton().addListener(mMaterialMgrListener);
}
}
return true;
}
/*-----------------------------------------------------------------------------
| Finalize the RT Shader system.
-----------------------------------------------------------------------------*/
virtual void finalizeRTShaderSystem()
{
// Restore default scheme.
Ogre::MaterialManager::getSingleton().setActiveScheme(Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
// Unregister the material manager listener.
if (mMaterialMgrListener != NULL)
{
Ogre::MaterialManager::getSingleton().removeListener(mMaterialMgrListener);
delete mMaterialMgrListener;
mMaterialMgrListener = NULL;
}
// Finalize RTShader system.
if (mShaderGenerator != NULL)
{
Ogre::RTShader::ShaderGenerator::finalize();
mShaderGenerator = NULL;
}
}
/*-----------------------------------------------------------------------------
| Finalize the RT Shader system.
-----------------------------------------------------------------------------*/
virtual Ogre::String getShaderCacheFileName()
{
#if OGRE_DEBUG_MODE
return "cache_d.bin";
#else
return "cache.bin";
#endif
}
/*-----------------------------------------------------------------------------
| Finds context-wide resource groups. I load paths from a config file here,
| but you can choose your resource locations however you want.
-----------------------------------------------------------------------------*/
virtual void locateResources()
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h locateResources called");
// load resource paths from config file
Ogre::ConfigFile cf;
cf.load(openAPKFile(mFSLayer->getConfigFilePath("resources.cfg")));
Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
Ogre::String sec, type, arch;
// go through all specified resource groups
while (seci.hasMoreElements())
{
sec = seci.peekNextKey();
Ogre::ConfigFile::SettingsMultiMap* settings = seci.getNext();
Ogre::ConfigFile::SettingsMultiMap::iterator i;
// go through all resource paths
for (i = settings->begin(); i != settings->end(); i++)
{
type = i->first;
arch = i->second;
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(arch, type, sec);
}
}
}
/*-----------------------------------------------------------------------------
| Cleans up and shuts down the context.
-----------------------------------------------------------------------------*/
virtual void shutdown()
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h shutdown called");
// remove window event listener before shutting down OIS
Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this);
#if defined(ENABLE_SHADERS_CACHE_SAVE)
if (Ogre::GpuProgramManager::getSingleton().isCacheDirty())
{
Ogre::String path = mFSLayer->getWritablePath(getShaderCacheFileName());
FILE * outFile = fopen(path.c_str(), "wb");
if (outFile)
{
Ogre::LogManager::getSingleton().logMessage("Writing shader cache to ");
Ogre::LogManager::getSingleton().logMessage(path.c_str());
Ogre::DataStreamPtr ostream(new Ogre::FileHandleDataStream(path.c_str(), outFile, Ogre::DataStream::WRITE));
Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(ostream);
ostream->close();
}
}
#endif
if (mTrayMgr)
{
delete mTrayMgr;
mTrayMgr = 0;
}
mWindow = 0;
#ifdef USE_RTSHADER_SYSTEM
// Finalize the RT Shader System.
finalizeRTShaderSystem();
#endif // USE_RTSHADER_SYSTEM
}
/*-----------------------------------------------------------------------------
| Processes window size change event. Adjusts mouse's region to match that
| of the window. You could also override this method to prevent resizing.
-----------------------------------------------------------------------------*/
virtual void windowResized(Ogre::RenderWindow* rw)
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h windowResized called");
if(mCamera)
mCamera->setAspectRatio((Ogre::Real)mViewport->getActualWidth() / (Ogre::Real)mViewport->getActualHeight());
}
/*-----------------------------------------------------------------------------
| Notify the window size changed or it was moved
-----------------------------------------------------------------------------*/
virtual void windowMovedOrResized()
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h windowMovedOrResized called");
mWindow->windowMovedOrResized(); // notify window
windowResized(mWindow); // notify window event listeners
}
/*-----------------------------------------------------------------------------
| Loads context-wide resource groups. I chose here to simply initialise all
| groups, but you can fully load specific ones if you wish.
-----------------------------------------------------------------------------*/
virtual void loadResources()
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h loading resources");
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}
/*-----------------------------------------------------------------------------
| Creates the render window to be used for this context. I use an auto-created
| window here, but you can also create an external window if you wish.
| Just don't forget to initialise the root.
-----------------------------------------------------------------------------*/
virtual Ogre::RenderWindow* createWindow()
{
return mRoot->initialise(true);
}
/*-----------------------------------------------------------------------------
| Extends setup to create dummy scene and tray interface.
-----------------------------------------------------------------------------*/
virtual void setup()
{
//the window should be created already. if not, create a new one
if(mWindow == NULL)
{
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h setup window wasn't created before. Creating it now.");
mWindow = createWindow();
}
__android_log_write(ANDROID_LOG_VERBOSE, "DEBUGGING", "tinyogre.h setup locating resources");
locateResources();
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Essential");
//mTrayMgr = new SdkTrayManager("BrowserControls", mWindow, mInputContext, this);
//mTrayMgr->showBackdrop("SdkTrays/Bands");
//mTrayMgr->getTrayContainer(TL_NONE)->hide();
#if defined(ENABLE_SHADERS_CACHE_LOAD)
// Load for a package version of the shaders.
Ogre::String path = getShaderCacheFileName();
FILE * inFile = NULL;
inFile = fopen(path.c_str(), "rb");
// If that does not exist, see if there is a version in the writable location.
if (!inFile)
{
path = mFSLayer->getWritablePath(getShaderCacheFileName());
inFile = fopen(path.c_str(), "rb");
}
if (inFile)
{
Ogre::LogManager::getSingleton().logMessage("Loading shader cache from ");
Ogre::LogManager::getSingleton().logMessage(path.c_str());
Ogre::DataStreamPtr istream(new Ogre::FileHandleDataStream(path.c_str(), inFile, Ogre::DataStream::READ));
Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache(istream);
}
#endif
//creates a dummy scene that:
// shows the GUI
// initializes the shader system
//createDummyScene();
//creating scene manager
createSceneManager();
//initializing the RT shader system ...
bool success = initializeRTShaderSystem(mSceneMgr);
if (!success)
{
OGRE_EXCEPT(Ogre::Exception::ERR_FILE_NOT_FOUND,
"Shader Generator Initialization failed - Core shader libs path not found",
"SampleBrowser::createDummyScene");
}
#ifdef USE_RTSHADER_SYSTEM
//mShaderGenerator->addSceneManager(mSceneMgr);
#endif
loadResources();
Ogre::TextureManager::getSingleton().setDefaultNumMipmaps(5);
// adds context as listener to process context-level (above the sample level) events
mRoot->addFrameListener(this);
Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this);
//setupWidgets();
windowResized(mWindow); // adjust menus for resolution
}
/*-----------------------------------------------------------------------------
| This function closes down the application - saves the configuration then
| shutdowns.
-----------------------------------------------------------------------------*/
virtual void closeApp()
{
shutdown();
}
/*-----------------------------------------------------------------------------
| Creates dummy scene to allow rendering GUI in viewport.
-----------------------------------------------------------------------------*/
/**
creates dummy scene for GUI rendering AND Real Time Shader System initialization.
*/
virtual void createDummyScene()
{
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "creating dummy scene");
mWindow->removeAllViewports();
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "creating dummy scene Scenemanager");
Ogre::SceneManager* sm = mRoot->createSceneManager(Ogre::ST_GENERIC, "DummyScene");
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "creating dummy scene adding renderqueuelistener");
sm->addRenderQueueListener(mOverlaySystem);
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "creating dummy scene adding camera");
Ogre::Camera* cam = sm->createCamera("DummyCamera");
__android_log_write(ANDROID_LOG_INFO, "DEBUGGING", "creating dummy scene adding adding viewport");
mViewport = mWindow->addViewport(cam);
sm->setAmbientLight(Ogre::ColourValue(0.25, 0.25, 0.25));
//initializing shader system...
#ifdef USE_RTSHADER_SYSTEM
// Initialize shader generator.
// Must be before resource loading in order to allow parsing extended material attributes.
bool success = initializeRTShaderSystem(sm);
if (!success)
{
OGRE_EXCEPT(Ogre::Exception::ERR_FILE_NOT_FOUND,
"Shader Generator Initialization failed - Core shader libs path not found",
"SampleBrowser::createDummyScene");
}
if(mRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION) == false)
{
//newViewport->setMaterialScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
// creates shaders for base material BaseWhite using the RTSS
Ogre::MaterialPtr baseWhite = Ogre::MaterialManager::getSingleton().getByName("BaseWhite", Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
baseWhite->setLightingEnabled(false);
mShaderGenerator->createShaderBasedTechnique(
"BaseWhite",
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
mShaderGenerator->validateMaterial(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME,
"BaseWhite");
if(baseWhite->getNumTechniques() > 1)
{
baseWhite->getTechnique(0)->getPass(0)->setVertexProgram(
baseWhite->getTechnique(1)->getPass(0)->getVertexProgram()->getName());
baseWhite->getTechnique(0)->getPass(0)->setFragmentProgram(
baseWhite->getTechnique(1)->getPass(0)->getFragmentProgram()->getName());
}
// creates shaders for base material BaseWhiteNoLighting using the RTSS
mShaderGenerator->createShaderBasedTechnique(
"BaseWhiteNoLighting",
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
mShaderGenerator->validateMaterial(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME,
"BaseWhiteNoLighting");
Ogre::MaterialPtr baseWhiteNoLighting = Ogre::MaterialManager::getSingleton().getByName("BaseWhiteNoLighting", Ogre::ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
if(baseWhite->getNumTechniques() > 1)
{
baseWhiteNoLighting->getTechnique(0)->getPass(0)->setVertexProgram(
baseWhiteNoLighting->getTechnique(1)->getPass(0)->getVertexProgram()->getName());
baseWhiteNoLighting->getTechnique(0)->getPass(0)->setFragmentProgram(
baseWhiteNoLighting->getTechnique(1)->getPass(0)->getFragmentProgram()->getName());
}
}
#else
#error "USE_RTSHADER_SYSTEM not used"
#endif // USE_RTSHADER_SYSTEM
#ifdef USE_RTSHADER_SYSTEM
if(mRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION) == false)
{
Ogre::RTShader::ShaderGenerator::getSingletonPtr()->addSceneManager(mRoot->getSceneManager("DummyScene"));
}
#endif // USE_RTSHADER_SYSTEM
}
protected:
/**
Opens the APK file to access files within.
*/
Ogre::DataStreamPtr openAPKFile(const Ogre::String& fileName)
{
Ogre::DataStreamPtr stream;
AAsset* asset = AAssetManager_open(mAssetMgr, fileName.c_str(), AASSET_MODE_BUFFER);
if(asset)
{
off_t length = AAsset_getLength(asset);
void* membuf = OGRE_MALLOC(length, Ogre::MEMCATEGORY_GENERAL);
memcpy(membuf, AAsset_getBuffer(asset), length);
AAsset_close(asset);
stream = Ogre::DataStreamPtr(new Ogre::MemoryDataStream(membuf, length, true, true));
}
return stream;
}
AAssetManager* mAssetMgr; // Android asset manager to access files inside apk
Ogre::FileSystemLayer* mFSLayer; // File system abstraction layer
Ogre::OverlaySystem* mOverlaySystem; // Overlay system
OgreBites::SdkTrayManager* mTrayMgr; // SDK tray interface
Ogre::Root *mRoot;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
Ogre::String mResourcesCfg;
Ogre::String mPluginsCfg;
Ogre::Viewport* mViewport; // main viewport
bool mResourcesLoaded;
bool mContentSetup;
bool mDone;
#ifdef USE_RTSHADER_SYSTEM
Ogre::RTShader::ShaderGenerator* mShaderGenerator; // The Shader generator instance.
ShaderGeneratorTechniqueResolverListener* mMaterialMgrListener; // Shader generator material manager listener.
#endif // USE_RTSHADER_SYSTEM
};
#endif // #ifndef __TinyOgre_h_
In the attachment you can find the project. It includes almost everything - except the assets directory, which you can copy from your $(OGRE_HOME)\androidbuild\SampleBrowserNDK folder.
The paths should all be set relative to $(OGRE_HOME). I compiled Ogre into the $(OGRE_HOME)\androidbuild\ folder. The solution is in the $(SOLUTION_FOLDER).
You can, of course change these to absolute paths - an especially easy task if you use Visual Studio.
That's all for now. A quick and dirty post with a not-so-quick but dirty solution. Hope it helps some of you anyhow.
Hints:
Always make sure you're using the same toolchain for everything - if you don't you'll likely get linker errors.
[EDIT] there are some issues with this code. for example it doesn't always properly load - working on a solution