Putting Ogre inside a UIResponder

Discussion of issues specific to mobile platforms such as iOS, Android, Symbian and Meego.
Post Reply
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Putting Ogre inside a UIResponder

Post by davidc538 »

Hey everyone,

I'm not sure if I'll get an answer for this but I'm trying to get Ogre up and running on iOS. I have been able to get everything working using the Ogre Xcode templates but OIS isn't fully functional on iOS so I wanted to subclass a UIResponder to get the input so that I can use it for my application. So far though I haven't been able to make it work and have been trying different things for days. I'm starting to think it would be easier to start without a template at all as it seems to have been vastly overcomplicated by whoever wrote it.

Would it be possible for anyone to post a working Xcode project with touch input working? I've only been able to receive touchmove events and not regular touch events.

Thanks in advance.
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

Another option that is discussed on the wiki and in several other threads is to create a transparent view on top of your Ogre view and use that to receive touch events.
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

So just subclass a UIView, implement my own touch handlers and put one on top of ogre?

EDIT: also, how do I make sure the UIView goes above Ogre?
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

I think you just make it the key view. You may also need to override -canBecomeKeyView to return true.
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

Here is my code so far...

Code: Select all

#ifndef APPDELEGATE_H
#define APPDELEGATE_H

#include "OgrePlatform.h"

#if !defined(OGRE_IS_IOS)
#  error This header is for use with iOS only
#endif

#ifdef __OBJC__

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

#import "RenderWindow.h"

// To use CADisplayLink for smoother animation on iPhone comment out
// the following line or define it to 1.  Use with caution, it can
// sometimes cause input lag.
#define USE_CADISPLAYLINK 1


@interface AppDelegate : UIWindow <UIApplicationDelegate>
{
    NSTimer *mTimer;
    DemoApp demo;
    
    // Use of the CADisplayLink class is the preferred method for controlling your animation timing.
    // CADisplayLink will link to the main display and fire every vsync when added to a given run-loop.
    // The NSTimer class is used only as fallback when running on a pre 3.1 device where CADisplayLink
    // isn't available.
    id mDisplayLink;
    NSDate *mDate;
    double mLastFrameTime;
    double mStartTime;
    BOOL mDisplayLinkSupported;
}

- (void)renderOneFrame:(id)sender;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

@property (retain) NSTimer *mTimer;
@property (nonatomic) double mLastFrameTime;
@property (nonatomic) double mStartTime;

@end

@implementation AppDelegate

@synthesize mTimer;
@dynamic mLastFrameTime;
@dynamic mStartTime;

- (void)becomeKeyWindow
{
     UIWindow *mUIWindow = nil;
     Ogre::RenderWindow *mWindow = Ogre::Root::getSingleton().getAutoCreatedWindow();
     mWindow->getCustomAttribute("WINDOW", &mUIWindow);
     
     [self addSubview:mUIWindow];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    
}

- (double)mLastFrameTime
{
    return mLastFrameTime;
}

- (void)setLastFrameTime:(double)frameInterval
{
    // Frame interval defines how many display frames must pass between each time the
    // display link fires. The display link will only fire 30 times a second when the
    // frame internal is two on a display that refreshes 60 times a second. The default
    // frame interval setting of one will fire 60 times a second when the display refreshes
    // at 60 times a second. A frame interval setting of less than one results in undefined
    // behavior.
    
    if (frameInterval >= 1)
        mLastFrameTime = frameInterval;
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    // Hide the status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
    
    mLastFrameTime = 1;
    mStartTime = 0;
    mTimer = nil;
    
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    mLastFrameTime = 1;
    mStartTime = 0;
    mTimer = nil;
    
    try
    {
        demo.startDemo();
        
        Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();
        
        // Clear event times
		Ogre::Root::getSingleton().clearEventTimes();
    }
    catch( Ogre::Exception& e )
    {
        std::cerr << "An exception has occurred: " <<
        e.getFullDescription().c_str() << std::endl;
    }
    
    if (mDisplayLinkSupported)
    {
        // CADisplayLink is API new to iPhone SDK 3.1. Compiling against earlier versions will result in a warning, but can be dismissed
        // if the system version runtime check for CADisplayLink exists in -initWithCoder:. The runtime check ensures this code will
        // not be called in system versions earlier than 3.1.
        mDate = [[NSDate alloc] init];
        mLastFrameTime = -[mDate timeIntervalSinceNow];
        
        mDisplayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(renderOneFrame:)];
        [mDisplayLink setFrameInterval:mLastFrameTime];
        [mDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    else
    {
        mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f) * mLastFrameTime
                                                  target:self
                                                selector:@selector(renderOneFrame:)
                                                userInfo:nil
                                                 repeats:YES];
    }
    [pool release];
    
    [self makeKeyAndVisible];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    Ogre::Root::getSingleton().queueEndRendering();
    
    [mDate release];
    mDate = nil;
        
    [mDisplayLink invalidate];
    mDisplayLink = nil;

    [[UIApplication sharedApplication] performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    Ogre::Root::getSingleton().saveConfig();
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
}

- (void)renderOneFrame:(id)sender
{    
    if(!OgreFramework::getSingletonPtr()->isOgreToBeShutDown() &&
       Ogre::Root::getSingletonPtr() && Ogre::Root::getSingleton().isInitialised())
    {
		if(OgreFramework::getSingletonPtr()->m_pRenderWnd->isActive())
		{
			mStartTime = OgreFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU();
            
			OgreFramework::getSingletonPtr()->m_pMouse->capture();
            
			OgreFramework::getSingletonPtr()->updateOgre(mLastFrameTime);
			OgreFramework::getSingletonPtr()->m_pRoot->renderOneFrame();
            
			mLastFrameTime = OgreFramework::getSingletonPtr()->m_pTimer->getMillisecondsCPU() - mStartTime;
		}
    }
    else
    {
		[mDate release];
        mDate = nil;
            
        [mDisplayLink invalidate];
        mDisplayLink = nil;

        [[UIApplication sharedApplication] performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
    }
}

- (void)dealloc
{
    if(mTimer)
    {
        [mTimer invalidate];
        mTimer = nil;
    }
    
    [super dealloc];
}

@end

#endif

#endif

I can't figure out why but my touchesBegan and touchesMoved events will not get called. I've tried all sorts of different things. Can you tell what I'm doing wrong???
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

If I recall, the touch callbacks need to be overridden at the UIView level rather than from the UIWindow.
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

are you sure it has to be done that way? UIWindow inherits UIView so it should work..... but then again I'm new to objective c. thanks
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

also, makeKeyAndVisible and makeKeyWindow can only be called on UIWindows. so i don't know how to accomplish what your saying
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

I didn't mention them. They need to remain in the UIWindow subclass. touchesBegan, etc, should be moved to your UIView subclass. This would also be helpful, I took straight from iPhoneInputDelegate.mm in our ogredeps repository.

Code: Select all

- (BOOL)canBecomeFirstResponder
{
    return YES;
}
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

so am i supposed to make my own subclass of UIWindow that inherits my own subclass of UIView? is there a way to even do that kindof thing in objective c?

... or am i supposed to subclass UIView to handle the touch events and then add it to my UIWindow and then add the Ogre window to my subclass of UIView?

holy shit this is confusing.... thanks for your help though
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

actually i'd like to try what you mentioned earlier. subclassing a UIView and putting it on top of Ogre. question being: how do I make sure that it goes on top and not below?
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

I've been looking at that but i still don't full understand. Do I put ogre beneath the window object?
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: Putting Ogre inside a UIResponder

Post by masterfalcon »

Ogre will render to a subview of the window. The touch handling view is also a subview of the window.
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

Ok, I understand how those files are meant to be used now, but I still don't know how to initialize it in my appdelegate. could you show me how?
davidc538
Kobold
Posts: 27
Joined: Sat May 22, 2010 3:36 am

Re: Putting Ogre inside a UIResponder

Post by davidc538 »

i made it work!!!

Code: Select all

    uiInput = new UIInput();
    inputSystem = [[iOS_UIInputImpl alloc] init];
    
    [inputSystem.window addSubview:mUIWindow];
    [inputSystem setPimpl:(UIInputPimpl*)uiInput];
Post Reply