Friday, June 8, 2012

Simply Make My First Irrlicht App for iPhone(iOS) with XCode 4.2

Before you start, you need to successfully compile Irrlicht library. To do it, you can refer to this posting.
Hereafter I adapt the first one of the official Irrlicht tutorials.
  1. Irrlicht for OpenGL ES only deals with textures with a 2-powered size.
    Get 'media/sydney.bmp' in Irrlicht library source folder(Irrlicht_ogles from the prerequisite guide). Open it with your graphic application and scale it to width 256 pixels and height 256 pixels. Changing only the size without scaling doesn't work. Save it as sydney256x256.bmp.

  2. Let's create an XCode project. Run XCode 4.2.
    On the menu, choose File - New - New Project. In the dialog box that pops up, choose the top-right item, Simple View Application in iOS-Application section.
    Let's name it IrrlichtApp. Choose the parent folder of Irrlicht library source folder so that this new project resides next to Irrlicht library source folder.
    Change all the extensions .m to .mm (ViewController.m, AppDelegate.m, [Supporting Files]/main.mm) to .mm in order to compile C++. 

  3. Let's add a few graphic assets.
    Run Finder and open the folder of this project. Next to your IrrlichtApp.xcodeproj, create a folder named Assets. Copy sydney256x256.bmp into Assets folder and copy sydney.md2 from 'media' folder in Irrlicht library source folder into Assets folder. Right-click on the project head(red rectangle in the picture) in the leftmost column and Choose Add Files to "IrrlichtApp"... on the popup menu.
    In the dialogbox that pops up, find and click on Assets folder and in the lower part therein choose Create folder references for any added folders among the options. Click Add button.

  4. Let's make this app full-screen without the status bar at the top.
    Expand IrrlichtApp/Supporting Files under the project head and click on IrrlichtApp-Info.plist. A table show up to the right. Right-click on the white space under the last table item. Choose Add Row on the popup menu.
    A new item at the end shows up with a pop-up list as in the next picture. Choose Status bar is initially hidden from the list.
    Click the spinner(red rectangle in the next picture) on the right side of the third column(Value) of the new row in the table.
    Choose YES from the pop-up list.

  5. Let's add Irrlicht library as project.
    Right-click on the project head in the leftmost column and choose Add Files to "IrrlichtApp"... on the popup menu. Find source/Irrlicht/MacOSX/MacOSX.xcodeproj in Irrlicht library folder and choose it.
    Click on IrrlichtApp project head in the leftmost column. To the right, click on IrrlichtApp under PROJECT, the first section in the second column, To the right, click on Build Settings tab at the top in the table. Scroll the long table down a lot until you find Search Paths section and double-click the input cell on the right of Header Search Paths row(instead you can use the search box at the top of this table). In the popup dialogbox that shows up, click on the plus-sign button in the lower-left corner as in the next picture.
    The first row will be activated for input. Type '../Irrlicht_ogles/include' into the activated right cell and click Done button in the bottom-right corner.

  6. Let's add necessary libraries for linking.
    In the second column from the left, click on IrrlichtApp under TARGETS, the second section and to the right, click on Build Phases tab at the top.
    Expand the third bar by clicking on the dark small triangle at the left of the bar and click on the plus-sign button in the bottom-left corner of the opened bar.
    In the dialogbox that has shown up, choose libIrrlicht.a under Workspace section as in the above picture and click Add button in the bottom-left corner. Also add OpenGLES.framework, QuartzCore.framework under iOS 5.0 section in the same way.

  7. Let's establish the project dependency.
    You still stay at [Build Phases] tab. Loot at the first bar named [Target Dependencies] and by clicking the dark triangle at the left of the bar, expand it.
    Click the plus-sign in the bottom-left corner of the opened bar and the dialogbox in the next picture pops up.
    Choose libIrrlicht.a under [IrrlichtApp/MacOSX]. Make sure that a new item named [libIrricht.a (MacOSX)] is inserted in the opened bar.

  8. Let's add actual code.
    Note that in the following, lines in the boldface need to be added.
    Open IrrlichtApp-Prefix.pch, the precompiled header under IrrlichtApp/Supporting Files and add the following code.
    #ifdef __OBJC__
        #import <UIKit/UIKit.h>
        #import <Foundation/Foundation.h>
        #import <QuartzCore/CoreAnimation.h>
    #endif
    
    #ifdef __cplusplus
    #include <irrlicht.h>
    using namespace irr ;
    using namespace core ;
    using namespace scene ;
    using namespace video ;
    using namespace io ;
    using namespace gui ;
    #endif
    
    Open ViewController.h and add the following code.
    @interface ViewController : UIViewController
    {
        CADisplayLink* m_oDispLnk ;
        IrrlichtDevice* m_pDevice ;
    }
    @end
    
    Open ViewController.mm and add the following code.
    -(void) viewWillAppear:(BOOL)a_animated
    {
        [super viewWillAppear:a_animated];
        
        SIrrlichtCreationParameters params;
        params.DriverType = video::EDT_OGLES1;
        params.WindowSize = core::dimension2d<u32>(320,480);
        params.WindowId   = self.view;
        params.Bits       = 32;
        m_pDevice = createDeviceEx( (const SIrrlichtCreationParameters)params ) ;
        if( ! m_pDevice ) return ;
        
        NSString* oBunPath = [ [NSBundle mainBundle] bundlePath ] ;
        m_pDevice->getFileSystem()->changeWorkingDirectoryTo( [oBunPath cStringUsingEncoding:NSASCIIStringEncoding] ) ;
        
        IVideoDriver* driver = m_pDevice->getVideoDriver() ;
        ISceneManager* smgr = m_pDevice->getSceneManager() ;
        
        IAnimatedMesh* mesh = smgr->getMesh( "./Assets/sydney.md2" ) ;
        if( ! mesh ) return ;
        
        IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
        if( node )
        {
            node->setMaterialFlag(EMF_LIGHTING, false);
            node->setMD2Animation(scene::EMAT_STAND);
            ITexture* pTex = driver->getTexture( "./Assets/sydney256x256.bmp" ) ;
            node->setMaterialTexture( 0, pTex ) ;
        }
        smgr->addCameraSceneNode( 0, vector3df(0,30,-40), vector3df(0,5,0) ) ;
        
        // iOS timer.
        m_oDispLnk = [ [UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(updateDisplay) ] ;
        [ m_oDispLnk addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes ] ;
    }
    
    
    -(void) updateDisplay
    {
        m_pDevice->run() ;
        
        m_pDevice->getVideoDriver()->beginScene( true, true, SColor(255,100,101,140) ) ;
        
        m_pDevice->getSceneManager()->drawAll() ;
        //m_pDevice->getGUIEnvironment()->drawAll() ;
        
        m_pDevice->getVideoDriver()->endScene();
    }
    
    
    -(void) viewDidDisappear:(BOOL)a_animated
    {
        [super viewDidDisappear:a_animated];
        
        if( m_oDispLnk != nil )
            [ m_oDispLnk invalidate ] ;
        
        if( m_oDispLnk != NULL )
            m_pDevice->drop();
    }
    
    Save all the files(Opt-Cmd+S).

  9. Now build and run it(Cmd+R).

14 comments:

  1. I followed your tutorial but if i want to run the app on an iOS-Devic ei get the following error:

    Undefined symbols for architecture armv7:
    "_createDeviceEx", referenced from:
    -[WWSMasterViewController viewWillAppear:] in WWSMasterViewController.o
    -[WWSDetailViewController viewWillAppear:] in WWSDetailViewController.o
    ld: symbol(s) not found for architecture armv7
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    ReplyDelete
  2. No i recogized now, that it don't work in Simulator too.

    ReplyDelete
    Replies
    1. It might be due to [Target Dependencies]. You can see it as the first bar in the picture at step 6. Using the plus sign, try to add libIrrlicht.a under [IrrlichtApp/MaxOSX]. Please let me know the result. If this is successful, I'll have to update this guide according to your result.

      Delete
    2. Sorry i didn't follow completly you guid. I imported the libs from the Projectfolder itself, not the complet MacOSX Project.

      Delete
    3. Now I am at the old Position. Project runs in Simulator but not on device. same errors.

      Delete
  3. Could it be, that createDeviceEx() is just available on Simulator ?

    ReplyDelete
    Replies
    1. I inserted the new step 7. Without the project dependency, Xcode doesn't compile the depended-on library according to the current target device. I hope this change will help you.
      Please check if the new change doesn't break this guide.

      Delete
    2. Yes this works.

      But isn't there any other way to solve this ? The Project is such big now...

      Delete
    3. I am happy that you have succeeded with this way. In fact, this is quite a bookish way. As a workaround, once you have built the library for the current device, you can break the project dependency.

      Delete
    4. Could you create an empty project without including the whole MacOSX Project ?

      I think that would be very useful for everybody.

      Delete
    5. Currently I am busy studying Ogre engine. After I master Ogre, I will try your suggestion.

      Delete
  4. I am getting error when i start to run code in my device :

    Undefined symbols for architecture armv7s:
    "irr::video::createImageLoaderPVR()", referenced from:
    irr::video::CNullDriver::CNullDriver(irr::io::IFileSystem*, irr::core::dimension2d const&) in libIrrlicht.a(CNullDriver.o)
    irr::video::CNullDriver::CNullDriver(irr::io::IFileSystem*, irr::core::dimension2d const&) in libIrrlicht.a(CNullDriver.o)
    "irr::CIrrDeviceIPhone::CIrrDeviceIPhone(irr::SIrrlichtCreationParameters const&)", referenced from:
    _createDeviceEx in libIrrlicht.a(Irrlicht.o)
    ld: symbol(s) not found for architecture armv7s
    clang-real++: error: linker command failed with exit code 1 (use -v to see invocation)

    ReplyDelete
  5. Hi,

    I get error:
    /Users/paulo/Documents/workspaces/xcode/johnson/johnson/CameraViewController.mm:42:25: Cast of Objective-C pointer type 'UIView *' to C pointer type 'void *' requires a bridged cast

    In line:
    params.WindowId = (void*)self.view;

    If i put bridged tag, i got malloc error:

    params.WindowId = (__bridge void *)(self.view);

    Error:

    Loaded mesh: Assets/sydney.md2
    johnson(4510,0x3db3d18c) malloc: *** mach_vm_map(size=4294705152) failed (error code=3)
    *** error: can't allocate region
    *** set a breakpoint in malloc_error_break to debug
    libc++abi.dylib: terminating with uncaught exception of type std::bad_alloc

    Can you help me?

    ReplyDelete