Archive for the ‘Apple’ Category

Pong game with Qt

Monday, March 5th, 2012

The next incarnation of the Pong game written in C++ is called QPong because it uses Qt toolkit to provide its UI. The source code is available on Github as Xcode project. All base classes were copied without any modifications but integration with Qt required some fine adjustments in a way the project is built.

Since Qt is written in C++ there is no need to mix any languages as it was the case with Cocoa Pong application. Nonetheless I still have to create a custom implementation of the game's drawing context class which is called QDrawingContext:

#include <QtGui/QtGui>
#include "DrawingContext.h"

class QDrawingContext : public Pong::DrawingContext {

public:
    QDrawingContext(QPainter *painter);
    virtual ~QDrawingContext();
    virtual void setFillColor(Pong::RGBColor const &color);
    virtual void fillRectangle(Pong::Rectangle bounds);
    virtual void fillOval(Pong::Rectangle bounds);

private:
    QPainter *_painter;
    QColor _qFillColor;
};

Note that I left #include statements and they reference 'QtGui/QtGui' instead of just 'QtGui' because that's how you should do it in Xcode. Its implementation uses QPainter to do the actual drawing:

QDrawingContext::QDrawingContext(QPainter *painter) : _qFillColor(0, 0, 0) {
    _painter = painter;
}

QDrawingContext::~QDrawingContext() {
}

void QDrawingContext::setFillColor(Pong::RGBColor const &color) {
    DrawingContext::setFillColor(color);
    _qFillColor = QColor(color.red * 255, color.green * 255, color.blue * 255);
}

void QDrawingContext::fillRectangle(Pong::Rectangle bounds) {
    _painter->setBrush(_qFillColor);
    QRectF qbounds = QRectFromRectangle(bounds);
    _painter->drawRect(qbounds);
}

void QDrawingContext::fillOval(Pong::Rectangle bounds) {
    _painter->setBrush(_qFillColor);
    QRectF qbounds = QRectFromRectangle(bounds);
    _painter->drawEllipse(qbounds);
}

Although integration was easy for the source code it was not so for the IDE. It turns out that Qt has its own compiler called 'moc' which generates some additional C++ code for classes with Q_OBJECT macro. It is required to provide certain meta-information about the object and should be a part of the build process. Hopefully I was not the first person to cope with this so I found this handy post that explains how to make Xcode to create mocables. My version is roughly the same:

cd "$PROJECT_DIR"/QPong
rm -f QPong.pro
qmake -project -o QPong.pro
qmake -spec macx-g++ QPong.pro
make mocables

Note that you have to call this script before compilation phase. You should actually run it once first to generate moc_* files and add them to the project so they got compiled with the rest of the project files.

Pong game with Objective-C++

Monday, March 5th, 2012

My weekend project was to write a Pong game in C++ and make it portable enough to work with different UI toolkits. The first incarnation is called XPong and uses Cocoa to provide native UI for the game. It is published on Github and could be compiled and launched on OS X.

The natural way to integrate C++ and Objective-C code is to use Objective-C++ which is basically a mix of the two without any new features. Naturally you either declare C++ class which makes use of Objective-C objects or otherwise define an Objective-C class which makes use of C++ code. On the project level if you have a portable C++ module you typically have to use this module from Objective-C application and instrument the module to call back the Objective-C frameworks.

Using Objective-C in C++ classes

Let's look at example: objects in the Pong game have to draw themselves, and to do so they should call Cocoa APIs. In particular they have to use NSBezierPath to fill rectangles and ovals. To localize dependency on particular drawing methods Pong game introduces abstract class DrawingContext:

class DrawingContext {

public:
    DrawingContext() : _fillColor(RGBColor(1)) {}
    virtual ~DrawingContext() {}
    RGBColor fillColor() const { return _fillColor; }
    virtual void setFillColor(RGBColor const &color) { _fillColor = color; }
    virtual void fillRectangle(Rectangle bounds) = 0;
    virtual void fillOval(Rectangle bounds) = 0;

private:
    RGBColor _fillColor;
};

Note that it is a proper C++ class which requires subclasses to implement actual painting functions using appropriate system APIs. In the XPong project we define XDrawingContext class which extends DrawingContext and implements these methods. Note that implementation file should be called XDrawingContext.mm so Xcode will know that it is an Objective-C++ code. Here is a header file for XDrawingContext:

class XDrawingContext : public Pong::DrawingContext {

public:
    XDrawingContext(NSGraphicsContext *xcontext);
    virtual ~XDrawingContext();
    virtual void setFillColor(Pong::RGBColor const &color);
    virtual void fillRectangle(Pong::Rectangle bounds);
    virtual void fillOval(Pong::Rectangle bounds);

private:
    NSGraphicsContext *_xcontext;
};

And its implementation:

XDrawingContext::XDrawingContext(NSGraphicsContext *xcontext) {
    _xcontext = [xcontext retain];
}

XDrawingContext::~XDrawingContext() {
    [_xcontext release];
}

void XDrawingContext::setFillColor(Pong::RGBColor const &color) {
    DrawingContext::setFillColor(color);
    NSColor *xcolor = [NSColor colorWithDeviceRed:color.red
                                            green:color.green
                                             blue:color.blue
                                            alpha:1];
    [xcolor setFill];
}

void XDrawingContext::fillRectangle(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithRect:NSRectFromRectangle(bounds)];
    [path fill];
}

void XDrawingContext::fillOval(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithOvalInRect:NSRectFromRectangle(bounds)];
    [path fill];
}

So that's how you call Objective-C from C++: just implement C++ class and use Objective-C calls within method implementations.

Using C++ in Objective-C classes

The next example is GameView class. It is a custom Cocoa view which will draw Pong game objects in itself and will forward user input to it. Here is its header file:

@interface GameView : NSView

@property(assign) Pong::Drawable *gameContent;
@property(assign) Pong::InputHandler *gameResponder;

@end

And here is the implementation:

@implementation GameView

@synthesize gameContent = _gameContent;
@synthesize gameResponder = _gameResponder;

- (void)drawRect:(NSRect)rect {
    [[NSColor grayColor] set];
    NSRectFill(rect);
    NSGraphicsContext *xcontext = [NSGraphicsContext currentContext];
    XDrawingContext context(xcontext);
    if (self.gameContent) {
        self.gameContent->draw(context);
    }
}

- (void)keyDown:(NSEvent *)theEvent {
    if ([theEvent.characters length] > 0) {
        const char c = [theEvent.characters characterAtIndex:0];
        if (self.gameResponder) {
            self.gameResponder->handleKey(c);
        }
    }
}

@end

I omitted some irrelevant details to show only what is important. GameView has two properties which are pointers to C++ classes. We can't release and retain C++ objects so I declare properties with 'assign' so the caller will manage their life span. Implementation of GameView methods simply invoke methods of C++ objects and that's how it works.

Objective-C++ provides an easy way to integrate C++ and Objective-C code. You literally use 'mm' extension for the files, mix the code and it works.

Apple is working on grid view?

Thursday, March 1st, 2012

Recently I posted an update for my Deviations app and got this rejection notice from Apple:


We found that your app uses one or more non-public APIs, which is not in compliance with the App Store Review Guidelines. The use of non-public APIs is not permissible because it can lead to a poor user experience should these APIs change.

We found the following non-public API/s in your app:

gridView:heightForHeaderInSection:

gridView:numberOfRowsInSection:

gridView:viewForHeaderInSection:

numberOfSectionsInGridView:

What changed is that I've added a grid component to the BaseAppKit library which has these methods defined. Review team seems to be using a tool which checks only method signatures without considering class or protocol which defines them and obviously there is some 'private' component with these methods. And obviously it's a grid.

So I'm actually pretty much happy to discover this because it could mean that iOS could soon have a nice built-in grid component which I dearly miss…