How to create an android non-native app using ogre sdk?

Discussion of issues specific to mobile platforms such as iOS, Android, Symbian and Meego.
Post Reply
sarath_10
Gnoblar
Posts: 15
Joined: Tue Jun 11, 2013 10:38 am
x 1

How to create an android non-native app using ogre sdk?

Post by sarath_10 »

I have seen the GLES2 sample provided in the Ogre Android sdk(OgreSDK_Android_v1-9-0RC1). But it is pure native app, is it possible to create a application by creating the UI layer completely in java and the core renderering alone in the native layer ? If not, is it possible to add the UI elements(in java) on top of the native activity as created in the GLES2 sample ?
robert82h
Gnoblar
Posts: 23
Joined: Thu Jun 13, 2013 5:41 pm
x 7

Re: How to create an android non-native app using ogre sdk?

Post by robert82h »

Yes that's possible, look at the OgreJNI example. It has a regular Activity that sets up a SurfaceView and passes the window handle to Ogre. Then your Java code repeatedly calls a native function to render single frames. You should be able to overlay whatever you like on top of the SurfaceView. You will have to write input handling code in Java and pass the events to native code, but I found input handling is much easier using Java anyway (for example detecting pinching and other gestures is covered by the Android SDK).

I'm not sure how you would extend a native activity with regular Android controls. It's probably possible but the other way looks more flexible to me.
sarath_10
Gnoblar
Posts: 15
Joined: Tue Jun 11, 2013 10:38 am
x 1

Re: How to create an android non-native app using ogre sdk?

Post by sarath_10 »

@robert82h
Thanks for the reply. I tried using OgreJNI as per you suggestion and it is working fine.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

I am not able to extend the OgreJNI example to do anything more than render the viewport background color. I extended the example to use a resources.cfg file and load a simple scene which displays the ogre head. The log shows that the mesh and materials are loading fine, but I only see the viewport background color.

I tried also to adapt the native activity GLES2 sample in the prebuilt SDK to instead use JNI. I get the same results ... I can set the viewport background color but I cant render anything else.

Any advice from those who have JNI working? Not sure what I am missing. Thanks everyone for your time! :)
robert82h
Gnoblar
Posts: 23
Joined: Thu Jun 13, 2013 5:41 pm
x 7

Re: How to create an android non-native app using ogre sdk?

Post by robert82h »

I had this problem until I started using RTSS. After creating a scene manager, add this to activate RTSS:

Code: Select all

#ifdef USE_RTSHADER_SYSTEM
		// Setup shaders
		Ogre::RTShader::ShaderGenerator::initialize();

		// The Shader generator instance
		Ogre::RTShader::ShaderGenerator* gen = Ogre::RTShader::ShaderGenerator::getSingletonPtr();

		// Create and register the material manager listener if it doesn't exist yet.
		if(material_mgr_listener_ == NULL) {
			material_mgr_listener_ = new ShaderGeneratorTechniqueResolverListener(gen);
			Ogre::MaterialManager::getSingleton().addListener(material_mgr_listener_);
		}

		gen->addSceneManager(scene_mgr_);
#endif
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

Thanks for the hint, Robert. The interesting thing is that I switched out the material for one with a purely gles2 shader technique and still didn't see anything, so I wasn't sure the issue had anything to do with RTSS. OgreJNI does not initialize RTSS, but the GLES2 example in the prebuilt android SDK does and I had the same results after adapting that code to work within OgreJNI.

Still, I will go over this all again with additional care knowing that you have it working just fine. I must be missing something.
robert82h
Gnoblar
Posts: 23
Joined: Thu Jun 13, 2013 5:41 pm
x 7

Re: How to create an android non-native app using ogre sdk?

Post by robert82h »

What device are you using? If it's not running Android 4.2.2, you can use OpenGL ES Tracer (http://developer.android.com/tools/help/gltracer.html) to see the GL calls and associated textures, geometries, etc. If your device has a Tegra chipset, you can also use PerfHUD ES (https://developer.nvidia.com/nvidia-perfhud-es).

Update: with RTSS, make sure you're not being caught by https://ogre3d.atlassian.net/browse/OGRE-214
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

Ah here we go ... I was testing on a tegra3 device. I think you nailed it with that JIRA issue and when I debug the same thing will be happening to me. Interestingly I don't think this happens on a Nexus 7, but I know you had this on the Asus Transformer and I am using an Ouya at the moment. Does not occur on Galaxy Nexus which I should have tested earlier. Lack of sleep really makes a difference in problem solving skills.

Thanks for your help, Robert! Kudos for you, bro!
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

Yes, the fix from OGRE-214 works fine. Just FYI, this happens with or without RTSS.

Thanks again!
haley01
Gnoblar
Posts: 1
Joined: Wed Jul 24, 2013 7:56 am

Re: How to create an android non-native app using ogre sdk?

Post by haley01 »

Hello...nice post. I am fresher for android development and I read above information about how to create an non-native app using ogre sdk. Please share more detail about android apps. Thank you.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

First follow the quickstart guide and cross compile Ogre for android: http://www.ogre3d.org/tikiwiki/CMake%20 ... on=Android

Then you will find an OgreJNI example in your build directory. Add RTSS and some resource locations to that example, and you are ready to display entities. You can see examples of how to do so in the samplebrowser, in the GLES2 example in the prebuilt SDK, or in some of the examples in this forum.
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

I notice some folks are having trouble extending the JNI sample. Here's a cut and paste JNI example that loads resources from a cfg file, initializes RTSS, and then attaches the ogrehead.mesh into the scene. You can copy all the assets over from the SampleBrowserNDK if you need .. just remember it'll take your app some time to parse all the material scripts during startup.

Code: Select all

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include <jni.h>
#include <EGL/egl.h>
#include <android/api-level.h>
#include <android/native_window_jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include "OgrePlatform.h"
#include "OgreRoot.h"
#include "OgreRenderWindow.h"
#include "OgreArchiveManager.h"
#include "Android/OgreAndroidEGLWindow.h"
#include "Android/OgreAPKFileSystemArchive.h"
#include "Android/OgreAPKZipArchive.h"

#ifdef OGRE_BUILD_PLUGIN_OCTREE
#	include "OgreOctreePlugin.h"
#endif

#ifdef OGRE_BUILD_PLUGIN_PFX
#	include "OgreParticleFXPlugin.h"
#endif

#ifdef OGRE_BUILD_COMPONENT_OVERLAY
#	include "OgreOverlaySystem.h"
#endif

#include "OgreConfigFile.h"

#ifdef OGRE_BUILD_RENDERSYSTEM_GLES2
#	include "OgreGLES2Plugin.h"
#	define GLESRS GLES2Plugin
#else
#	include "OgreGLESPlugin.h"
#	define GLESRS GLESPlugin
#endif

#include "OgreRTShaderSystem.h"
#include "OgreEntity.h"

using namespace Ogre;

class ShaderGeneratorTechniqueResolverListener : public Ogre::MaterialManager::Listener
{
public:
	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 = Ogre::RTShader::ShaderGenerator::getSingletonPtr()->createShaderBasedTechnique(
				originalMaterial->getName(), 
				Ogre::MaterialManager::DEFAULT_SCHEME_NAME, 
				schemeName);	

			// Case technique registration succeeded.
			if (techniqueCreated)
			{
				// Force creating the shaders for the generated technique.
				Ogre::RTShader::ShaderGenerator::getSingletonPtr()->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;
	}
};

static ShaderGeneratorTechniqueResolverListener* gMatListener = NULL;

static bool gInit = false;
static Ogre::Root* gRoot = NULL;
static Ogre::RenderWindow* gRenderWnd = NULL;

#ifdef OGRE_BUILD_PLUGIN_OCTREE
static Ogre::OctreePlugin* gOctreePlugin = NULL;
#endif

#ifdef OGRE_BUILD_PLUGIN_PFX
static Ogre::ParticleFXPlugin* gParticleFXPlugin = NULL;
#endif

#ifdef OGRE_BUILD_COMPONENT_OVERLAY
static Ogre::OverlaySystem* gOverlaySystem = NULL; 
#endif

static Ogre::GLESRS* gGLESPlugin = NULL;

static Ogre::SceneManager* pSceneMgr = NULL;
static Ogre::Camera* pCamera = NULL;
static JavaVM* gVM = NULL;

AAssetManager* gAssetMgr = NULL;

static Ogre::DataStreamPtr openAPKFile(const Ogre::String& fileName)
{
	Ogre::DataStreamPtr stream;
    AAsset* asset = AAssetManager_open(gAssetMgr, 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;
}

extern "C" 
{
	JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) 
	{
		gVM = vm;
		return JNI_VERSION_1_4;
	}

	JNIEXPORT void JNICALL 	Java_org_ogre3d_android_OgreActivityJNI_create(JNIEnv * env, jobject obj, jobject assetManager)
	{
        if(gInit)
			return;
         
        gRoot = new Ogre::Root();

		gGLESPlugin = OGRE_NEW GLESRS();
		gRoot->installPlugin(gGLESPlugin);
			
#ifdef OGRE_BUILD_PLUGIN_OCTREE
		gOctreePlugin = OGRE_NEW OctreePlugin();
		gRoot->installPlugin(gOctreePlugin);
#endif
			
#ifdef OGRE_BUILD_PLUGIN_PFX
		gParticleFXPlugin = OGRE_NEW ParticleFXPlugin();
		gRoot->installPlugin(gParticleFXPlugin);
#endif

#ifdef OGRE_BUILD_COMPONENT_OVERLAY
		gOverlaySystem = OGRE_NEW OverlaySystem(); 
#endif
		
		gRoot->setRenderSystem(gRoot->getAvailableRenderers().at(0));
        gRoot->initialise(false);
        gInit = true;
		
		gAssetMgr = AAssetManager_fromJava(env, assetManager);
		if (gAssetMgr) 
		{
			ArchiveManager::getSingleton().addArchiveFactory( new APKFileSystemArchiveFactory(gAssetMgr) );
			ArchiveManager::getSingleton().addArchiveFactory( new APKZipArchiveFactory(gAssetMgr) );
		}
	}
	
	JNIEXPORT void JNICALL Java_org_ogre3d_android_OgreActivityJNI_destroy(JNIEnv * env, jobject obj)
	{
		if(!gInit)
			return;
                
        gInit = false;
                
#ifdef OGRE_BUILD_COMPONENT_OVERLAY
		OGRE_DELETE gOverlaySystem; 
		gOverlaySystem = NULL;
#endif

        OGRE_DELETE gRoot;
        gRoot = NULL;
        gRenderWnd = NULL;

#ifdef OGRE_BUILD_PLUGIN_PFX
		OGRE_DELETE gParticleFXPlugin;
		gParticleFXPlugin = NULL;
#endif

#ifdef OGRE_BUILD_PLUGIN_OCTREE
		OGRE_DELETE gOctreePlugin;
		gOctreePlugin = NULL;
#endif

		OGRE_DELETE gGLESPlugin;
		gGLESPlugin = NULL;
	}
	

    JNIEXPORT void JNICALL Java_org_ogre3d_android_OgreActivityJNI_initWindow(JNIEnv * env, jobject obj,  jobject surface)
	{
		if(surface)
		{
			ANativeWindow* nativeWnd = ANativeWindow_fromSurface(env, surface);
			if (nativeWnd && gRoot)
			{
				if (!gRenderWnd) 
				{
					Ogre::NameValuePairList opt;
					opt["externalWindowHandle"] = Ogre::StringConverter::toString((int)nativeWnd);
					gRenderWnd = Ogre::Root::getSingleton().createRenderWindow("OgreWindow", 0, 0, false, &opt);
					
					
					if(pSceneMgr == NULL)
					{
						// open config file to load resource groups
						Ogre::ConfigFile cf;
						cf.load(openAPKFile("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);
							}
						}
						Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
						
						Ogre::RTShader::ShaderGenerator::initialize();
						Ogre::RTShader::ShaderGenerator::getSingletonPtr()->setTargetLanguage("glsles");
						gMatListener = new ShaderGeneratorTechniqueResolverListener();
						Ogre::MaterialManager::getSingleton().addListener(gMatListener);
	
						pSceneMgr = gRoot->createSceneManager(Ogre::ST_GENERIC);
						Ogre::RTShader::ShaderGenerator::getSingletonPtr()->addSceneManager(pSceneMgr);
						Ogre::Entity* pEntity = pSceneMgr->createEntity("OgreHead", "ogrehead.mesh");
						Ogre::SceneNode* pNode = pSceneMgr->getRootSceneNode()->createChildSceneNode();
						pNode->attachObject(pEntity);

						Ogre::Light* pDirLight = pSceneMgr->createLight();
						pDirLight->setDirection(Ogre::Vector3(0,-1,0));
						pDirLight->setType(Ogre::Light::LT_DIRECTIONAL);
						pNode->attachObject(pDirLight);
						
						pCamera = pSceneMgr->createCamera("MyCam");
						pCamera->setNearClipDistance(1.0f);
						pCamera->setFarClipDistance(100000.0f);
						pCamera->setPosition(0,0,100.0f);
						pCamera->lookAt(0,0,0);
						pCamera->setAutoAspectRatio(true);
		
						Ogre::Viewport* vp = gRenderWnd->addViewport(pCamera);
						vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
						vp->setMaterialScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);	
						
						Ogre::RTShader::ShaderGenerator::getSingletonPtr()->invalidateScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
					}						
				}
				else
				{
					static_cast<Ogre::AndroidEGLWindow*>(gRenderWnd)->_createInternalResources(nativeWnd, NULL);
				}                        
			}
		}
	}
	
    JNIEXPORT void JNICALL Java_org_ogre3d_android_OgreActivityJNI_termWindow(JNIEnv * env, jobject obj)
	{
		if(gRoot && gRenderWnd)
		{
			static_cast<Ogre::AndroidEGLWindow*>(gRenderWnd)->_destroyInternalResources();
		}
	}
	
	JNIEXPORT void JNICALL Java_org_ogre3d_android_OgreActivityJNI_renderOneFrame(JNIEnv * env, jobject obj)
	{
		if(gRenderWnd != NULL && gRenderWnd->isActive())
		{
			try
			{
				if(gVM->AttachCurrentThread(&env, NULL) < 0) 					
					return;
				
				gRenderWnd->windowMovedOrResized();
				gRoot->renderOneFrame();
				
				//gVM->DetachCurrentThread();				
			}catch(Ogre::RenderingAPIException ex) {}
		}
	}
};

RigoCL
Greenskin
Posts: 114
Joined: Mon Oct 14, 2013 1:41 am
Location: Chile
x 3

Re: How to create an android non-native app using ogre sdk?

Post by RigoCL »

Can't get to know the exact difference between the APK inside SampleBrowserNDK and the JNI version, I know NDK stands for Native Development Kit meaning C/C++ ported to Android (If I'm not wrong), and JNI is the full JAVA version, but what are the differences?? speed? what else?

My question arises considering that the Ogre's Android version runs very slow in my Samsung S III, I supposed this is was a very fast device, but only in the lighter samples I can get 60fps, others like the "terrain" samples simply crash two seconds after starting, or is it the debug mode that is slowing things down?
User avatar
c6burns
Beholder
Posts: 1512
Joined: Fri Feb 22, 2013 4:44 am
Location: Deep behind enemy lines
x 138

Re: How to create an android non-native app using ogre sdk?

Post by c6burns »

The samplebrowser is a pure native app, using a native activity. The JNI sample uses JNI (java native interface). Both use the NDK ... but with a native activity you manage lifecycle and everything else from native code. With JNI you manage lifecycle from java and then do rendering/anything you choose from native code (using JNI). I haven't noticed a meaningful speed difference, but I haven't done specific benchmarks.

The SIII is not exactly a next gen device at this point. The GPU is an Adreno 225. The Nexus 4 is an Adreno 320 (about 4 versions ahead).
Post Reply