How to use Ogre in UIView

Problems building or running the engine, queries about how to use features etc.
Post Reply
magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

How to use Ogre in UIView

Post by magengyu »

I've been stucked in this problem for several weeks.
I read several threads about this and they suggested using "externalWindowHandle" for Ogre to create render window.
I have succesfully implemented such code on MFC HWND, it is quite convient and straight forward.

But on iOS, I met some problem.
I found that, the "externalWindowHandle" requires a UIWindow pointer instead of UIView.
If I pass a UIView to externalWindowHandle, the program crash and error message is

Code: Select all

-[UIView setRootViewController:]: Unrecognized selector
It seems ogre will create rootviewcontroller and set as the rootviewcontroller of given external UIWindow.
So I did another experiment, create a second UIWinodow and init Ogre with this window. program runs alright, and 3D model is shown.
my code is quite simple, I did not use the template, and just a simple initOgre() function in the AppDelegate file

Code: Select all

#include "ogre.h"
#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    Ogre::Root*			m_ogreRoot;
    Ogre::RenderWindow*		m_ogreWindow;		// required Ogre object, render windth
    Ogre::SceneManager*		m_sceneManager;	// required Ogre object
    Ogre::Camera*			m_pCamera;
    Ogre::Viewport*			m_pViewport;
}

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIWindow *window2;

- (void) initOgre:(id)hwnd;
@synthesize window = _window;
@synthesize window2;

- (void)initOgre:(id)hwnd
{
	Ogre::String rootpath = Ogre::macBundlePath() + "/";
    
	m_ogreRoot = new Ogre::Root("", rootpath+"ogre.cfg");
    
	Ogre::GLESPlugin* mGLESPlugin = new Ogre::GLESPlugin();
	m_ogreRoot->installPlugin(mGLESPlugin);
    
	// create window
	m_ogreWindow = m_ogreRoot->initialise(false);
	Ogre::String wndHandle = Ogre::StringConverter::toString((long)hwnd);
	Ogre::NameValuePairList parms;
	parms["externalWindowHandle"] = wndHandle;
	m_ogreWindow = m_ogreRoot->createRenderWindow("Render", 200, 300, false, &parms);
        
	// create scene
	m_sceneManager = m_ogreRoot->createSceneManager(Ogre::ST_GENERIC);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(rootpath+"Sinbad.zip","Zip");
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    
	Ogre::Entity* headEnt = m_sceneManager->createEntity("sinbad.mesh");
	m_sceneManager->getRootSceneNode()->attachObject(headEnt);
    
	m_pCamera = m_sceneManager->createCamera("Camera");
	m_pCamera->setPosition(Ogre::Vector3(0, 0, 60));
	m_pCamera->lookAt(Ogre::Vector3(0, 0, 0));
	m_pCamera->setNearClipDistance(1);
    
	m_pViewport = m_ogreWindow->addViewport(m_pCamera);
	m_pViewport->setBackgroundColour(Ogre::ColourValue(0.8f, 0.7f, 0.6f, 1.0f));
    
	m_pCamera->setAspectRatio(Ogre::Real(m_pViewport->getActualWidth()) / Ogre::Real(m_pViewport->getActualHeight()));
	
	m_pViewport->setCamera(m_pCamera);
    
	m_ogreWindow->setActive(true);
	m_ogreWindow->update();
    
	m_ogreRoot->renderOneFrame();
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    [self.window makeKeyAndVisible];
 
    UIViewController* vc = [[UIViewController alloc] init];
    self.window.rootViewController = vc;
    //[self initOgre:vc.view];
    
    window2 = [[UIWindow alloc] initWithFrame:CGRectMake(10,10,200,300)];
    [self initOgre:window2];
        
    return YES;
}
but using a second UIWindow is the last thing I want. it is no difference with using ogre's autocreated UIWindow.

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

Have you tried "externalViewHandle"?

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

masterfalcon wrote:Have you tried "externalViewHandle"?
I just tried this "externalViewHandle", crash with a different error message:

Code: Select all

-[UIView setMWindowName:]: Unrecognized selector
I googled this "setMWindowName". it is implemented in OgreEAGLWindow.mm.
Shall I use someting like OgreEAGLView instead of UIView? but there is no "OgreEAGLWindow.h" in ogre's include directory.

and in the window initialize step, shall I pass both externalWindowHandle and externalViewHandle? such as

Code: Select all

Ogre::NameValuePairList parms;
parms["externalWindowHandle"] = wndHandle;
parms["externalViewHandle"] = viewHandle;
m_ogreWindow = m_ogreRoot->createRenderWindow("Render", 200, 300, false, &parms);

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

I check the source code in OgreSDK, the externalviewhandle part is

Code: Select all

        
mView.mWindowName = mName;          
OgreAssert([mView.layer isKindOfClass:[CAEAGLLayer class]], "EAGL2Window: View's Core Animation layer is not a CAEAGLLayer. This is a requirement for using OpenGL ES for drawing.");  
So I thought if I implement a EAGLView with a mWindowName member, as the externalviewhandle. it might work.

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

Finally it works.
Using Ogre in UIView is not as simple as in Windows.
The problem is in the Ogre UIWindow and UIView resize part. Ogre SDK code, ogreEAGLView.mm and ogreEAGLWindow.mm

Code: Select all

        
if (UIDeviceOrientationIsLandscape(deviceOrientation))
{
      w = std::max(width, height);
      h = std::min(width, height);
}
else
{
     h = std::max(width, height);
     w = std::min(width, height);
}
These max() and min() only works in full screen model.
In our subview model, if the subview resized, then w and h will swap. error occures, see my another thread http://www.ogre3d.org/forums/viewtopic.php?f=2&t=71442

To fix this, we need to pass our own UIWindow and UIView to the Ogre rendersystem.
And the ogreEAGLView has a member variable mWindowName. so I implement myEAGLView as:

Code: Select all

#include "ogre.h"
#import <UIKit/UIKit.h>
#import "QuartzCore/CAEAGLLayer.h"

@interface myEAGLView : UIView
{
    Ogre::String mWindowName;
}

@property (assign, nonatomic) Ogre::String mWindowName;

@end


@implementation myEAGLView

@synthesize mWindowName;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    return self;
}

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

@end
and in the initialize part, the code is

Code: Select all


- (void)initOgreWithWnd:(UIWindow*)hwnd andView:(UIView*)hview
{
    Ogre::String rootpath = Ogre::macBundlePath() + "/";
    
	m_ogreRoot = new Ogre::Root("", rootpath+"ogre.cfg");
    
    Ogre::GLESPlugin* mGLESPlugin = new Ogre::GLESPlugin();
    m_ogreRoot->installPlugin(mGLESPlugin);
    
	// create window
	m_ogreWindow = m_ogreRoot->initialise(false);
	Ogre::String wndHandle = Ogre::StringConverter::toString((long)hwnd);
	Ogre::String viewHandle = Ogre::StringConverter::toString((long)hview);
	Ogre::NameValuePairList parms;
	parms["externalWindowHandle"] = wndHandle;
	parms["externalViewHandle"] = viewHandle;
	m_ogreWindow = m_ogreRoot->createRenderWindow("Render", 200, 300, false, &parms);

	// create scene
	m_sceneManager = m_ogreRoot->createSceneManager(Ogre::ST_GENERIC);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(rootpath+"Sinbad.zip","Zip");
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    
	Ogre::Entity* headEnt = m_sceneManager->createEntity("sinbad.mesh");
	m_sceneManager->getRootSceneNode()->attachObject(headEnt);
    
	m_pCamera = m_sceneManager->createCamera("Camera");
	m_pCamera->setPosition(Ogre::Vector3(0, 0, 60));
	m_pCamera->lookAt(Ogre::Vector3(0, 0, 0));
	m_pCamera->setNearClipDistance(1);
    
	m_pViewport = m_ogreWindow->addViewport(m_pCamera);
	m_pViewport->setBackgroundColour(Ogre::ColourValue(0.8f, 0.7f, 0.6f, 1.0f));
    
	m_pCamera->setAspectRatio(Ogre::Real(m_pViewport->getActualWidth()) / Ogre::Real(m_pViewport->getActualHeight()));
	
	m_pViewport->setCamera(m_pCamera);
    
	m_ogreWindow->setActive(true);
	m_ogreWindow->update();
    
	m_ogreRoot->renderOneFrame();
}

- (void)dealloc
{
    [_window release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    [self.window setBackgroundColor:[UIColor whiteColor]];
    [self.window makeKeyAndVisible];
 
    myEAGLView* glview = [[myEAGLView alloc] initWithFrame:CGRectMake(10,10,150,260)];
    [self initOgreWithWnd:nil andView:glview];

    UIViewController* vc = [[UIViewController alloc] init];
    self.window.rootViewController = vc;  // reset rootViewController
    [vc.view setFrame:CGRectMake(10, 30, 200, 300)];
    [vc.view setBackgroundColor:[UIColor redColor]];
    [vc.view addSubview:glview];           // reset view hierarchy
    
    // simple resize test
    [glview setFrame:CGRectMake(10,10,200,100)];
    m_pCamera->setAspectRatio(2.0);
    m_ogreRoot->renderOneFrame();
        
    return YES;
}
Pay attention that the rootViewController is set AFTER initOgre. because in OgreSDK, a new controller is created and is set as rootcontroller. Refer to "ogreEAGLWindow.mm". even if you pass an externalViewController, it will be set as the rootViewController. and the ogreEAGLView will be set as the main view of this controller, so there are still problems.
So my solution is to reset them after ogre initialized. It is not very elegant but works.

BTW, iOS orientation strategy really sucks, width and height need to be swapped sometimes on some window. I have not figure it out quite clearly.
Last edited by magengyu on Thu Aug 23, 2012 6:14 am, edited 2 times in total.

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

Sorry that you think the orientation support sucks. The fact is that full screen is the most common usage scenario and being used in a subview doesn't have a good test case right now. If you'd be able to provide one we could use it to help improve support for the future.

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

This has been really useful!
Be advised that it wont work if you use Ogre 1.8.0 GLES2.
Stick to the GLES render system.
I got my ogre in a view after a looonng day of trying all possible combinations.

I would gladly file some bug reports if I had a working iOS ogre build from source --- something the current cmake won't produce :(

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

What is your issue with CMake? And are you talking about using GLES 1 in 1.7 or 1.8?

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

masterfalcon wrote:Sorry that you think the orientation support sucks. The fact is that full screen is the most common usage scenario and being used in a subview doesn't have a good test case right now. If you'd be able to provide one we could use it to help improve support for the future.
Sorry for the misunderstanding. I didn't mean the ogre supporting for orientation is bad. What I mean is the orientation part in iOS SDK itself. such as height and weight swapped portrait view? (maybe, I haven't figure it out clearly)
As to ogre, I suggest a subview mode that the internal resize strategy should be disabled, and user can handle resize and orientation in their own code.
Last edited by magengyu on Thu Aug 23, 2012 1:38 am, edited 1 time in total.

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

for OpenGL ES2, I think the strategy is similar. you can create a myEAGL2View refering to the ogreEAGL2View in the ogre SDK.
But I didn't test it, so there maybe some other problems

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

masterfalcon wrote:What is your issue with CMake? And are you talking about using GLES 1 in 1.7 or 1.8?
I meant GLES1 with ogre 1.8.0 sdk for ios 5.1

My issue with cmake is I don't get it yet. I'm not friends with how cmake process and its integration with xcode 4.3 I guess.

I have a source build from the svn 1.8.0 revision which I happily use for my osx build and I dreaded having to reconfigure all the source build for ios ... which I suppose is just a matter of runing cmake ccmake again with the right parameters. :oops:

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

Yeah and i would also use a separate build directory.

I don't see why GLES 2 wouldn't work. The windowing code is essential identical to the GLES code.

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

A good use case for testing this is try to use the iOS gui elements as overlays for the ogre 3d view.
8) This sounds like a good idea because the iOS ui very sophisticated, robust, mature, well documented.
:evil: This sounds like a bad idea because Ogre offers other UI systems that are built to work within ogre and that are cross platform.

I've tried all sorts of approaches and haven't gotten very far:
If I manage to draw the buttons over the ogre UIView, they won't rotate along with the view.
if I manage to rotate the buttons by having subviews or multiple view controllers, the ogre view won't rotate properly or wont show at all.
such as height and weight swapped portrait view? (maybe, I haven't figure it out clearly)
masterfalcon, Have you gotten anywhere regarding orientation changes? I suspect I am struggling with the same issues as you.
As to ogre, I suggest a subview mode that the internal resize strategy should be disabled, and user can handle resize and orientation in their own code.
This sounds promising. But I would suggest exposing specific iOS rendersystem obj-c classes **or interfaces** to allow the user user to override the default behaviors.

This is what I felt I was trying to do when I copied the current ogre GLES obj-c classes to match the needs of the rendersystem, and yet I haven't succeeded in making things wok how I want.

I've derived my own view , view controller and app delegate, but the rotation and rendering magic seems to happen outside these classes somehow or get trampled by the default behaviors.

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

I have not, but I haven't devoted any time to it. I really need a test case to put in our repo.

If you have just copied them, that won't work. You'll need to actually subclass them.

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

A cpptest or a working project?

magengius' project is pretty straightforward.

http://www.ogre3d.org/forums/download/file.php?id=4475

How do you need it and I'll see what I can muster?

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

Ok, I figured this out:

my problem lies wihin lnes 372 and 379 of OgreEAGLWindow.mm

Code: Select all


            if ((opt = miscParams->find("externalViewControllerHandle")) != end)
            {
                mViewController = (EAGLViewController *)StringConverter::parseUnsignedLong(opt->second);
                if(mViewController.view != nil)
                    mView = (EAGLView *)mViewController.view;
                mUsingExternalViewController = true;
                LogManager::getSingleton().logMessage("iOS: Using an external view controller handle");
            }

I guess it should be something like

Code: Select all

                if(!mUsingExternalView && mViewController.view != nil)
                    mView = (EAGLView *)mViewController.view;
If I use a custom window and a custom view, the EAGLWindow creates a custom controller. If I ignore this controller and use my own, then the contorller created by the EAGLWindow will never know that the interface orientation changed, and will resize the view correctly but assign width/height incorrectly

( in EAGLWindow::resize() ):

Code: Select all

        // Check the orientation of the view controller and adjust dimensions
        if (UIInterfaceOrientationIsPortrait(mViewController.interfaceOrientation))
        {
            h *= std::max(width, height);
            w *= std::min(width, height);
        }
        else
        {
            w *= std::max(width, height);
            h *= std::min(width, height);
        }
This is really an inadequate assumption in the case of a Subview hierarchy, becausd if this is a the parent view should be laying out the new sizes appropriately.





A workarround for the SDK 1.8.0 user:

Set your "externalViewHandle" , "externalWindowHandle", "externalViewControllerHandle" misc params on Ogre init.
make sure that the viewController.view is equal to the externalviewHandle;

after init, like in magengyu's method set your hierarchy to what is needed, and add the view to your window:

here is my code:

Code: Select all

 

//these come from a nib file
    CustomTouchViewController * viewController = (CustomTouchViewController*) _window.rootViewController;
    CustomTouchOgreView * ogreView = (CustomTouchOgreView *) m_viewController.m_ogreView;
    UIView * rootView = viewController.m_rootView;
    [ogreView removeFromSuperview];
    [rootView removeFromSuperview];
    m_viewController.view = ogreView;
 
    m_ogreFramework->initOgreInNSView(frame.size.width , 
                                      frame.size.height , 
                                      Ogre::StringConverter::toString((size_t) ogreView),
                                      Ogre::StringConverter::toString((size_t) self.window) ,
                                      Ogre::StringConverter::toString((size_t) self.window.rootViewController));
                   
    [ogreView removeFromSuperview];
    [rootView addSubview: ogreView];
    viewController.view = rootView;
    [rootView sendSubviewToBack: ogreView];
    [self.window addSubview : rootView];
    self.window.rootViewController = viewController;
 

masterfalcon, I will be SettingUp magengius sample to use all these custom classes as well as to load the view setup from a nib file as is currently happening in my code. tomorrow

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

Ok, here is the working project with the workarround written in.

look for the workarround in AppDelegate.mm.

UI classes all get initialized and passed into the app delegate through the nib file.

All it needs is setting up the ogre sdk include and lib directories and adding the media folder to the project.

Hope i't useful.
Attachments
RenderInUIView.zip
Sample code for rendering in a uiView with all custom stuff, handling rotation and autoresizing adequately.
(224.55 KiB) Downloaded 194 times

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

Did you change the source code in ogre sdk?
because as you said, in "OgreEAGLView.mm", layoutsubview() function, and "OgreEAGLWindow.mm", resize() function, the resizing method is not for subview case.
but you inherit the EAGLView from ogre sdk, so the resize functions are still called.

I tested your project with original ogre sdk 1.8.
if I resize the ogreview in the xib file, making its width bigger than height. then the rendering result is wrong.
then I modified the resizing part in "OgreEAGLView.mm" and "OgreEAGLWindow.mm". result is correct then.

and if the ogreviw height is too small. unhandle exception occures after rotate to landscape. it is because the window height is 0 after rotate. not ogre's problem.

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

It should work when your view has an portrait aspect ratio when the controller is in portrait mode, and has a landscape aspect ratio when the controller is in landscape mode.
This is the case with the submitted code as the auto resize flags for the view yield these conditions after resizing happens.

I tested the submitted code in the simulator and didn't notice any aspect ratio problems, perhaps you modified the autorezie flags or changed the initial aspect ratio of the view?

magengyu
Kobold
Posts: 35
Joined: Sat Jul 28, 2012 7:54 am
x 1

Re: How to use Ogre in UIView

Post by magengyu »

your code works fine until I change the size of the ogreview in the xib file.
It should work when your view has an portrait aspect ratio when the controller is in portrait mode, and has a landscape aspect ratio when the controller is in landscape mode.
you are right, acording to the resizing code in the sdk, this condition must be met.

for people want to use ogre in UIView with any dimension, modification of original sdk code is required

robdr
Gnoblar
Posts: 2
Joined: Thu Mar 28, 2013 3:21 pm

Re: How to use Ogre in UIView

Post by robdr »

i tried running your project with OGRE 1.8.2 in Xcode 4.6 which gives met a EXC_BAD_ACCES error. The project runs completly fine when not running Ogre with an external view.

The stack trace:
Image

The error:
Image

Do you have any pointers? Any help is really appreciated...

User avatar
masterfalcon
OGRE Team Member
OGRE Team Member
Posts: 4270
Joined: Sun Feb 25, 2007 4:56 am
Location: Bloomington, MN
x 126
Contact:

Re: How to use Ogre in UIView

Post by masterfalcon »

I'd stick a breakpoint there and make sure that your handles are valid. Also, is there any log output when this happens?

robdr
Gnoblar
Posts: 2
Joined: Thu Mar 28, 2013 3:21 pm

Re: How to use Ogre in UIView

Post by robdr »

The handles appear to be valid:

Image

User avatar
quiasmo
Kobold
Posts: 28
Joined: Thu Jun 03, 2010 6:59 pm

Re: How to use Ogre in UIView

Post by quiasmo »

Hey robdr,

Do you have access to a debug build of your ogre SDK? if so, your best bet is to let it crash with debug build of OGRE and adjust your parameters to meed the expected conditions. :shock:

From what I remember the EAGLView needs to be generously refactored to cleanly accomodate more use cases.

Also, its very likely that the EAGLView code in OGRE has changed since ios6 came out, but my iOS build is currently under a few feet of dust and trampled by the osX version... so I can't help you with a diagnostic yet. Sorry.

If and when I get around to it I'll let you know, but I can't promisse that will happen anytime soon.

Best of Luck
Q

Post Reply