views:

91

answers:

2

Hi,

I've recently started learning programming to make my own 3D OpenGL game on the iPhone and have made reasonably decent progress so far. I started off using the basic OpenGL example that is provided with the iPhone SDK which helped me get off to a good start. However, as I'm starting to get the hang of things, it has occurred to me that I'm unnecessarily programming in Objective C which will make it harder to port the game to other platforms in the future. So I figured that it would be best to make it properly C++ now to avoid lots of extra work later.

To clarify: I'm not actually using any calls to Apple (Objective C) functions or anything, its just that I've based all my clases on the Objective C-style init/dealloc/etc, so that my engine looks like Objective C classes when used. My aim is to replace all the objective C stuff with the C++ equivalents... the trouble is that, being pretty new to C++, I'm not sure what corresponds with what!

Here's a simple example of one of my classes (myLight), in its current Objective C incarnation:

//  myLight.h

#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>

@interface myLight : NSObject {
    char *name;
    GLfloat *ambient, *diffuse, *specular, *position, *spotDirection;
    GLfloat spotRadius;

    GLfloat *matAmbient, *matDiffuse, *matSpecular;
    GLfloat shininess;
    Byte lightType;
}
@property (readonly) char *name;
@property (assign) GLfloat *position;
@property (assign) GLfloat *spotDirection;

@property (assign) GLfloat *ambient;
@property (assign) GLfloat *diffuse;
@property (assign) GLfloat *specular;

- (id)initWithContentsFromDatastream:(NSData *)fileData;
- (void)set;

@end

And the corresponding .mm file:

//  myLight.m

#import "myLight.h"

@implementation myLight
@synthesize name, ambient, diffuse, specular, position, spotDirection;

- (id)initWithContentsFromDatastream:(NSData *)fileData {
    self = [super init];
    NSData *fileContents = fileData;
    uint ptr = 0;

    Byte nameLength;
    [fileContents getBytes:&nameLength range: NSMakeRange(ptr, sizeof(Byte))];
    ptr++;

    name = new char[nameLength];
    [fileContents getBytes:name range: NSMakeRange(ptr, (nameLength * sizeof(char)) )];
    ptr = ptr + (nameLength * sizeof(char) );

    [fileContents getBytes:&lightType range: NSMakeRange(ptr, sizeof(Byte))];
    ptr++;

    position = new GLfloat[4];
    for(int j = 0; j < (4); j++)
        [fileContents getBytes:&position[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
    ptr = ptr + (4 * sizeof(float));

    if(lightType==2){
        spotDirection = new GLfloat[3];
        for(int j = 0; j < (3); j++)
            [fileContents getBytes:&spotDirection[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
        ptr = ptr + (3 * sizeof(float));

        [fileContents getBytes:&spotRadius range: NSMakeRange(ptr, sizeof(float))];
        ptr = ptr + sizeof(float);
    } else 
        spotDirection = NULL;

    diffuse = new GLfloat[4];
    for(int j = 0; j < (4); j++)
        [fileContents getBytes:&diffuse[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
    ptr = ptr + (4 * sizeof(float));

    ambient = new GLfloat[4];
    for(int j = 0; j < (4); j++)
        [fileContents getBytes:&ambient[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
    ptr = ptr + (4 * sizeof(float));

    specular = new GLfloat[4];
    for(int j = 0; j < (4); j++)
        [fileContents getBytes:&specular[j] range: NSMakeRange( (j* sizeof(float) ) + ptr, sizeof(float))];
    ptr = ptr + (4 * sizeof(float));

    [self set];

  return self;
}

- (void)set{
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT0, GL_POSITION, position);

    if(lightType==2)
        glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection);
}

- (void)dealloc {
    delete[] specular;
    delete[] ambient;
    delete[] diffuse;

    if (spotDirection)
        delete[] spotDirection;

    delete[] position;
    delete[] name;

    [super dealloc];
}

@end

If someone could point out which lines need to be changed and, more importantly, what they should be changed to to make it compile as pure C++, I'd really appreciate it.

Many Thanks!

+4  A: 

First of all, please keep in mind that Objective-C is not just a "different format" of C, it's a separate language and more important, in the case of Cocoa, a separate framework. Therefore if you want to be able to port your project to other platforms in the future, you not only have to get rid of Objective-C but also of the Cocoa framework.

To map the classes from Objective-C to C++ you would have to do the following:

  • create a new C++ class to replace the old class
  • create constructors for the -init... methods
  • create a destructor for the -dealloc method
  • create other methods which duplicate the functionality
  • for properties you would probably create getters and setters instead
  • replace the #import with #include directives, as this directive only exists in Objective-C (make sure that the headers you include are protected against multiple includes)
  • get rid of usages of NS... classes and methods, as those are part of the Cocoa framework and most probably cannot be ported

You should take some time to consider how you will use the code you're writing. Porting 1:1 is probably not such a great idea as there are many differences in idioms between coding in Cocoa and C++ (or any other language/framework).

frenetisch applaudierend
Thanks for the very useful answer. I was aware of some of the gotchas you mentioned, but I do really appreciate the specifics.I had naively expected to be still able to use NS* classes in my C++ code (although only for MacOS, of course), so that was news to me also!I'll try and think about this a little more anyway.. thanks for the advice!
You're welcome of course :-) Just a note: If you need your code working only on Mac OS X you can still use the NS* classes in C++ code (it's actually Objective-C++ code then, but this is handled silently by the compiler). When I mentioned getting rid of the NS* classes I was referring to the "port the code to another platform" part of your question.
frenetisch applaudierend
Ah right, understood. So you can use the NS* classes..? How..? (if you wouldn't mind explaining briefly!)
You can use them like you would in pure Objective-C. As far as I know you have to use the file ending .mm for files mixing C++ and Objective-C though, otherwise the compiler might not recognize the language. But if you do this, you tie your code to the OS X platform, and if you expose any Objective-C classes in your headers, also the code using your classes must use Objective-C++.
frenetisch applaudierend
Ah good, at least that works as expected then!Great, thanks again!
+1  A: 

Most of the applications logic may be translatable to C++, but there are going to be things that have no straightforward equivalent in C++. For example:

  1. There is no @encode() compiler directive (which is used for NSValue and a few other classes).
  2. There is no straightforward equivalent to doesNotRecognizeSelector:, respondsToSelector:, conformsToProtocol: or performSelector: (and other methods of similar nature).
  3. In Objective-C it is fine to send a message to nil, but in C++ it is not OK to call a member function on a null pointer.
  4. Objective-C allows extending existing classes using class categories, for example, you can add a method to NSString which counts the number of spaces, called numberOfSpaces and it will be available for all NSString instances in your application.
  5. C++ does not have a finally block for try/catch, but Objective-C has @finally for @try/@catch.

If you plan on releasing your application to multiple platforms, what you could do is try to abstract as much as you can into a separate library. Your iPhone application can be written in Objective-C and use functions from your library, and if you plan on porting it to another system whose frameworks require C++, then you can write a C++ application and use the same functions from the same library. I imagine your library would basically consist of [at least] your drawing routines and core game engine logic.

dreamlax
Useful information to know, thanks!