Initializing Ogre::Root with a GLKit view controller

Discussion of issues specific to mobile platforms such as iOS, Android, Symbian and Meego.
Post Reply
cheshirekow
Gnoblar
Posts: 21
Joined: Thu Dec 16, 2010 5:13 pm

Initializing Ogre::Root with a GLKit view controller

Post by cheshirekow »

So, after trying to use CEGUI, myGUI, and librocket without much success... I've decided to try to use the iOS native GUI and embed the game in a view... doing segues between them. The gui isn't really part of the game... just setup, preferences, and leader board, so I'm totally happy having them on separate "scenes". Also, from the sounds of things (http://www.ogre3d.org/forums/viewtopic.php?f=21&t=71050, for instance) it sounds like I can put another view on top of the game and add buttons and things to that if I need any during game play.

So right now I have an ogre game which works but has no gui using the standard setup where ogre does everything.

I also have a separate project where I've setup up a POC for the gui and one of the "scenes" is GLKitViewController derived. This class creates a GLES2 context. Now I need to figure out how setup ogre using this context to render in this view. So here's what I got so far. I'm in the process of trying to make it work (as in, debugging segfaults), but I'd like to know if I'm understanding it correctly.

Code: Select all

within GLKitViewController
    in viewDidLoad
        1) create openGLES2 context, mCtx
        2) create an Ogre::Root object, mRoot
        3) create an openGLES Render system object
            mRenderSystem = 
        4) mRoot->setRenderSystem(mRenderSystem)
        5) initialize the root but don't create a window
            mRoot->initialize(false)
        6) create parameter list, params
            colourDepth          = 32    # in xcode, color format rgb8888
            externalWindowHandle = 0
            externalGLControl    = false # i think ogre should still 'own'
                                         # the context right
            externalGLContext    = mCtx
            externalViewHandle   = mView # a GLKitView pointer
            externalViewControllerHandle = this
            contentScalingFactor = 2.0   # still don't understand this, but
                                         # this value 'works' in my current
                                         # code
        7) "create" the render window
            mRoot->createRenderWindow( "OgreWindow", width, height, true, params)
Is this all sane? The documentation says externalGLControl and externalGLContext are "OpenGL specific". I'm not sure if that means it includes "all OpenGLs" or just straight up OpenGL not OpenGLES.

Also, I'm not sure if I should be using GLKitView/Controller and pass in the context pointer, or a regular UIView/Controller and no context, assuming ogre will create it.

I'd appreciate any insight!!
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: Initializing Ogre::Root with a GLKit view controller

Post by masterfalcon »

It all sounds sane. Is there any particular reason that you are using GLKit? The regular UIKit classes should work unless there's a reason that you are tied to GLKit. I'm not sure if that case has been tested.
cheshirekow
Gnoblar
Posts: 21
Joined: Thu Dec 16, 2010 5:13 pm

Re: Initializing Ogre::Root with a GLKit view controller

Post by cheshirekow »

The reason is my ignorance. So I've switched to trying with the normal UIView and UIViewController... but, as mentioned in this thread: http://www.ogre3d.org/forums/viewtopic.php?f=2&t=71508 it seems that ogre reassigns the root view controller when I use this method. Is there any way to avoid that? I'm not sure that my use case is the same as magengyu's from that thread. I've got a storyboard setup which takes the user through the process of picking game preferences (speed, etc) before launching the game. My plan was to initialize the game inside a separate view controller, and then "present" that view controller from the preferences screen. When the game is paused or the player crashes, the preferences screen can dismiss the presented "game" view controller.

As masterfalcon mentioned in that other thread, this isn't the primary use case... but it *seems* to me to be possible. Any suggestions on how to make this work?

Here is the code where I instantiate my ogre view controller from the story board:

Code: Select all

        // create the data store and synchronize data with database
        m_dataStore = new forestrunner::desktop::DataStore();
        m_dataStore->init();
        
        // create the game view controller 
        self.ogreVC = [self.storyboard 
                instantiateViewControllerWithIdentifier:@"GameView"];
        [self.ogreVC setDataStore: m_dataStore];
        
        // grab a reference to the UIView forcing the view to load
        UIView* mainView = self.ogreVC.view;
        
        // instanciate the game application and initialize it
        [self.ogreVC initOgre: self.view.window];
        
        // segue to the next scene (nickname)
        [self performSegueWithIdentifier: @"SegueLoadToNick" sender: self];
The Ogre View controller's initOgre method looks like this

Code: Select all

    UIWindow*           gWin  = window;
    UIView*             gView = self.gameView;
    UIViewController*   gVC   = self;
    
    unsigned int width  = gView.frame.size.width;
    unsigned int height = gView.frame.size.height;
    
    m_app.init(gWin,gView,gVC,width,height);
And the application's init method looks like this

Code: Select all


bool Application::init(
        void* uiWindow, 
        void* uiView,
        void* uiViewController,
        unsigned int width,
        unsigned int height )
{
    // instantiate the dummy logger so that it gets set as the singleton
    // for cegui (note: we're not using cegui anymore)
    // CEGUI::DummyLogger* guiLog = new CEGUI::DummyLogger();

    m_uiWindow          = uiWindow;
    m_uiView            = uiView;
    m_uiViewController  = uiViewController;
    m_width             = width;
    m_height            = height;
    
    std::cout << "Initializing ios::Application with \n----------------"
        "\nuiWind: " << (void*)uiWindow << 
        "\nuiView: " << (void*)uiView <<
        "\n  uiVC: " << (void*)uiViewController <<
        "\n     w: " << width <<
        "\n     h: " << height <<
        std::endl; 

    if (!setup())
        return false;
        
    std::cout << "ios::Application setup finished" << std::endl;

    m_iosTimer = OGRE_NEW Ogre::Timer();
    m_iosTimer->reset();

    mRoot->clearEventTimes();

    return true;
}
setup() does some of the usual stuff but the important part is this

Code: Select all



bool Application::configure(void)
{
    m_pLog->logMessage(
            "setup: Finished setting up resources, configuring the root");

    std::stringstream strm;
    Ogre::NameValuePairList params;
    params["colourDepth"]          = "32";
    //m_params["externalGLControl"]    = "false";
    //m_params["externalGLContext"]    = "0";
    params["contentScalingFactor"] = 2.0;
    
    strm.str("");
    strm << (unsigned long)m_uiWindow;
    params["externalWindowHandle"] = strm.str();

    strm.str("");
    strm << (unsigned long)m_uiView;
    params["externalViewHandle"]   = strm.str();

    strm.str("");
    strm << (unsigned long)m_uiViewController;
    params["externalViewController"]  = strm.str();
    
    // initialize, dont' create render window
    mRoot->initialise(false, "");

    // now create render window by attaching to the iOS UIView stuff
    mWindow = mRoot->createRenderWindow("ForestRunnerOgreWindow",m_width,m_height,true,&params);

    return true;
}
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: Initializing Ogre::Root with a GLKit view controller

Post by masterfalcon »

Is that not working? There wasn't a question in there.
cheshirekow
Gnoblar
Posts: 21
Joined: Thu Dec 16, 2010 5:13 pm

Re: Initializing Ogre::Root with a GLKit view controller

Post by cheshirekow »

It isn't working. Sorry for the incoherent post. The result is that instead of the UI advancing to the next view controller (expected) I got a blank white screen (I'm pretty sure this is the view that ogre will render into). I was typing up the post at the same time as trying things and I think that I deleted and added some text at points to lose the jist of what I was asking. Basically, I want to know how to get ogre to render into a subview of a view hierarchy that is instantiated from a storyboard file. I've attempted a few more things so here we go:

I think I'm a bit out of my league here, but first of all I should note that my view controller (ForestRunner_playScene) derives from EAGLViewController (<OGRE/RenderSystems/GLES/APPLE/OgreEAGLViewController.h>). I've modified OgreEAGLWindow to have an extra boolean member "mEmbeddedView" which is set to true if the "embeddedView" configuration parameter is provided. Then I modified OgreEAGLWindow.mm to have the following

Code: Select all

        if(!mEmbeddedView)
            [mWindow addSubview:mViewController.view];

---snip----

        if(!mEmbeddedView)
            [mWindow makeKeyAndVisible];


The idea being that if I've already got a view controller and view that I want to render into, setup by the storyboard file, I dont need ogre to put it in the window for me. This solves the problem of the view controller that I give to ogre being set as the root and taking over the UI. However, I think ogre may be doing something else when initializing the OpenGLES render system that I'm not aware of. After initializing ogre, the program crashes on the next input event.

The error is "EXC_BAD_ACCESS". If I comment out initializing ogre, then the UI continues to work without crashing the app. This is very surprising to me because I disabled the code where ogre alters the window for the app, I figured that nothing on the iOS side should have changed at all given this.

I'll explain a bit what the app is doing (upper CamelCase is the name of a subclass of UIViewController):
1) the LoadingScene has a progress bar, it initializes some things (data store, ogre) and displays progress so that the user doesn't get too impatient, then it transitions (i.e. segue) to the NickScene
2) the NickScene has a text area and allows the user to enter a nickname for display on the leader board, when the user presses the "done" button it transitions (again, segue) to the PrefScene
3) the PrefScene has sliders for speed and density (it's a kind of racing game, if you will), when the user clicks "start" this view controller will present the PlayScene
4) the PlayScene has the view that I want ogre to render into

So, in the LoadingScene, I instanciate the PlayScene from the storyboard, force it to load the view, then initialize ogre. After that, I segue to the NickScene (this works). Then when I do any input (click the text area, or the done button) the app crashes. The debugger highlights UIApplicationMain so not much use there. I really do apologize for not being able to boil this down to a minimal example. What I'm hoping is that someone familiar with the render system initialization process can help me pinpoint where I should be looking for what is going wrong.

BTW, the Ogre log looks fine, with no errors or significant warnings (just warning me that my mesh is an old format).
cheshirekow
Gnoblar
Posts: 21
Joined: Thu Dec 16, 2010 5:13 pm

Re: Initializing Ogre::Root with a GLKit view controller

Post by cheshirekow »

Seems the problem causing the crash was that I forgot to modify the following line of OgreEAGLWindow.mm

Code: Select all

if(!mEmbeddedView && mViewController.view != mView)
            mViewController.view = mView;
So now the app does not crash. However, after initializing Ogre it appears that input is being ignored. I.e. in the NickScene, no input is being processed. Perhaps this is unrelated though. I will continue to look for the cause of that problem.

Edit: Seems that whatever is causing this to happen is occuring during the call to mRoot->createRenderWindow. If I return from the configure routine just prior to this call, the UI remains responsive. If I return just after, input is not responsive. As far as I can tell createRenderWindow ends up being a call to OpenGLESSupport:createRenderWindow which in turn ends up just creating a new EAGLWindow and then calling EAGLWindow::create. Thus, whatever is happening, should be happening in here. However, I've been pouring through this code and still can't find anything that could possibly be causing this problem. I still have not even enabled rendering and so this is only a side effect of initializing ogre. Any ideas why input would stop responding based on what is going on in EAGLWindow::create?

Edit 2: Hm.. it seems that even after modifying the EAGLWindow.mm file, I still must manually set the root view controller after initializing ogre. The following fixed my problem:

Code: Select all

[self.view.window setRootViewController: self];
Post Reply