Jul 02

The authors of the book OpenGL(R) ES 2.0 Programming Guide have updated their Web site to cover the new iPhone 3G S. The site can be found here:  http://www.opengles-book.com

From the site you can download a new chapter in PDF format titled “OpenGL ES 2.0 on the iPhone 3G S” which describes what you need to do to compile specifically for the new hardware.  The site also contains updated examples ported to the iPhone that you can download and run.

Two things to note about the examples – if you just try to compile and run them without reading the PDF file first you may have a problem.  The chapter points out that you need to compile the Common project first in order for things to run.

Second – I had one small problem with the MipMap2D example.  The file MipMap2D.c was in the project folder – but for some reason the project link was broken.  So I just added the file again and I could compile and run it.

Jun 26

If you would like advice on iPhone game programming from the people behind such games as Tap Tap Revenge, Enigmo and Flick Fishing then you will want to get your hands on a copy of iPhone Games Projects, published by Apress. You can order it from Amazon or buy a PDF version from the Apress Web site.

The book came out the same month OS 3.0 came out. So it won’t have the latest info. But there is still plenty of info and code that will probably still work in the new operating system and on the new hardware.

The first chapter contains no code and is about the fine art of simplicity. It is written by Joachim Bondo – the man behind the Deep Green chess app. I keep running into people who try to stuff complex desktop apps on to the iPhone. They and everyone else need to read this chapter.

The next chapter is by PJ Cabrera. I didn’t even know that the Mac could do Rails programming by default. Within five minutes of his instructions I used Rails to get a test server running on my Mac Book Pro. This was so I could use it to test his code on REST-based Web Services.

Aaron “Flick Fishing” Fothergill wrote the next chapter titled “Rapid Game Development Using (Mostly) Standard C” He discusses code he hacked from the iPhone Crash Landing app to whip up a 2D demo game in (mostly) C. I may review his mods to build a better Sprite class.

Brian “Enigmo” Greenstone writes about game optimization, discussing compiler settings, texture compression, graphics and audio optimization, performance tools, etc.  This chapter contains a lot of useful advice – don’t skip it!

Olivier Hennessy and Clayton Kane of Posimotion (Bikini Hunt) discuss game design, including selecting an engine and documentation.

Michael Kasprzak discusses portable code, game loops, event management, and frame skipping.  I’ll have to re-read his chapter again and work his ideas into a revised OpenGL ES template.

Mike “Tap Tap” Lee discusses graphics and animation and using Shark to find bottlenecks in your code.

Finally Richard Zito and Matthew Aitken discuss Bonjour Networking and Socket Programming. I see a lot complaints in iTunes that people want to be able to network their games. If you can master that it could be a selling feature.  Bonjour lets you network among friends on a LAN without needing a central server.  For the latest technology you should also check out the Apple guide to the Game Kit.

If you’ve been counting you figured out there are only eight chapters. I am glad to see that some publishers are going for quality over quantity. There’s more than enough info in this book to make it worth your while.

Tags: , , , ,

Jun 19

I had reserved my iPhone 3G S last week and went into the Apple store to pick it up today. I strolled in around noon, so there were no crowds. Even though I was the only customer waiting outside the store, security still made me zig zag through the ropes to get to the entrance …

I hit a snag setting things up online because I have credit protection (Capital One got it for me when they had to apologize for a rogue employee accessing my data … ). An Apple employee had to get someone from AT&T on the phone so they could relay four multiple choice questions about my credit history. Once that was straightened out they opened up the box, hooked the phone up to a laptop, activated it and off I went.

Now that I have the hardware to test OpenGL ES 2.0 apps – look out! I’ve been reading up on the subject and hope to post some sample code over the summer.

It turns out I had pre-ordered the book iPhone Games Projects and that happened to arrive today. Look for a review soon – as well as a review of the book OpenGL ES 2.0: Programming Guide.

Since I used to have a video podcast (http://rockosphere.blip.tv/) I’ll be looking at what I can do with the video camera too.

I was also looking at Skype for iPhone today. I discovered that the headset for the iPhone – that comes with a mic – works in my iPod Touch. So if you have Skype, a wireless connection and the mic-enabled headset (which you can buy from Apple for $30 if you don’t also own an iPhone) you can make calls from your iPod Touch.

Tags: ,

Jun 10

According to engadget.com: iPhone 3G S supports OpenGL ES 2.0, but 3G only supports 1.1 — will the App Store splinter?

“When we were breaking down the meaty differences between the old-school 3G and the 3G S yesterday, we made an assumption about support for OpenGL ES 2.0 3D graphics APIs in the original iPhone 3G based on the fact that it had been available in the iPhone OS 3.0 SDK for several betas. Turns out, though, that the graphics processor in the 3G S — the PowerVR SGX — supports hardware acceleration of both OpenGL ES 1.1 and 2.0 while the more pedestrian PowerVR MBX found in the iPhone 3G supports 1.1 alone.”

And since there is no new iPod Touch the same probably goes for that.

This is one of the reasons I was holding off on discussing anymore OpenGL. I was waiting to see what happened. It’s not surprising that the existing chipsets can’t be updated through software to support OpenGL ES 2.0.  I was just waiting to see if the new hardware would support 2.0.  So developers will need to make a decision.  I think I’m going to shift focus to the new chipset and 2.0.    Though I wouldn’t rule out building 1.1 apps entirely.   I could always experiment with #ifdef’ing the code to support both.

Jun 02

If you’d like to write an app that uses the location of the iPhone or iPod Touch (longitude and latitude), here’s a good tutorial:

Hello There: A CoreLocation Tutorial

I used the info to write a quick app that logs my location. In the simulator it will always tell you that it’s in Cupertino. When I tested it on an iPod Touch over wireless it worked great.

Because there are security and privacy issues it will ask permission first on the actual device. You and your users will also need to turn on the capabilitiy in your device settings.

While playing around with this feature I experimented with other apps that are supposed to figure out my location. Some of them didn’t work. All I can figure is they were compiled with an earlier SDK.

Tags: , ,

May 26

Here is an example of how to create a view that contains a UITableView that doesn’t take over the whole screen.  An example of an application that uses a small table is the Stocks application that comes with the iPhone / iPod Touch.  You may think you need a UITableViewController – but that only gets in the way and takes over the view.

  • Create a View-based iPhone application and call it TableSize1
  • Modify TableSize1ViewController.h so that it looks like this:

TableSize1ViewController.h

//
//  TableSize1ViewController.h
//  TableSize1
//
//  Created by Mitchell Allen on 5/26/09.
//  Copyright __MyCompanyName__ 2009. All rights reserved.
//
 
#import 
 
@interface TableSize1ViewController : UIViewController {
 
	UITableView *tableView;
}
 
@property (retain, nonatomic) UITableView *tableView;
 
@end

 

  • Modify TableSize1ViewController.m so that it looks like this:

TableSize1ViewController.m

//
//  TableSize1ViewController.m
//  TableSize1
//
//  Created by Mitchell Allen on 5/26/09.
//  Copyright __MyCompanyName__ 2009. All rights reserved.
//
 
#import "TableSize1ViewController.h"
 
@implementation TableSize1ViewController
 
@synthesize tableView;
 
- (void)viewDidLoad {
 
}
 
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 
    return 1;
}
 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;  // Test hack to display multiple rows.
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
 
	NSString *szCell = [[NSString alloc] initWithFormat: @"Row %i", indexPath.row ];
 
	[cell setText:szCell];
 
	[szCell release];
 
    // Set up the cell
    return cell;
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic -- create and push a new view controller
}
 
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}
 
- (void)dealloc {
    [super dealloc];
}
 
@end
  • In the Resources folder, double-click TableSize1ViewController.xib to launch Interface Builder
  • From Library / Cocoa Touch Plugin / Data Views drag a Table View on to the View and make it about half the height of the view (Select Tools / Library from the main menu if it isn’t visible)
  • Click on the new Table View
  • Click on the second tab in the Inspector window (Select Tools / Inspector from the main menu if it isn’t visible)
  • After clicking the second tab, the title of the Inspector window should be Table View Connections
  • Under Outlets: for both dataSource and delegate, drag the mouse from the circles next to them to the File’s Owner icon in the TableSize1ViewController.xib window.
  • Under Referencing Outlets: drag from New Referencing Outlet to the File’s Owner icon and select tableView.
  • With Interface Builder in focus, select File / Save
  • Go back to your project window and click Build and Go
  • Your application should now display a table that only takes up half the screen.

Tags: , , , ,

May 25

Here is an easy way to create headers and footers for iPhone Table Views.

  1. In your Xcode project right-click on the Resources folder
  2. Select: Add / New File … / iPhone OS / User Interfaces / View XIB / [Next]
  3. Call it HeaderView.xib and click Finish
  4. GIve the View a unique background color and set the height to 44
  5. Repeat for FooterView.xib
  6. Save both files

In your UITableViewController class modify viewDidLoad to contain the following (the editing = YES line is optional – just showing you how to display those cool delete widgets):

- (void)viewDidLoad {
 
	self.tableView.editing = YES;	// Enable delete buttons.
 
	UIView *hView = [[[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil] objectAtIndex:0];
 
	self.tableView.tableHeaderView = hView;
 
	UIView *fView = [[[NSBundle mainBundle] loadNibNamed:@"FooterView" owner:self options:nil] objectAtIndex:0];
 
	self.tableView.tableFooterView = fView;
}

As far as I can tell you can’t lock the header and footer in place. That will require a custom table view.

Tags: , , ,

May 25

This is my first entry in a new category called “cheat sheet.”

I’m trying to build an iPhone GUI for an application. Every time I want to do something simple – like add a button – I need to pull out my books on the subject and filter through several pages to remind myself how to do it. So I’m putting the info here for myself and anyone else who finds the process unintuitive.

Let’s assume that you are adding a button to an existing UIViewController. The first thing that you need to do is add a handler for the button press to your controller class.

Your *.h file would look something like this:

#import  
 
@interface HomeViewController : UIViewController {
 
}
 
-(IBAction) configButtonPressed:(id)sender;
 
@end

Your *.m (or *.mm) file would contain the corresponding method like this:

-(IBAction) configButtonPressed:(id)sender
{
	NSLog( @"HomeViewController:configButtonPressed:sender" );
}

 

  1. Fire up Interface Builder by double-clicking on your *.xib file.  I’m assuming you already have a View set up.
  2. I’m also assuming that  Tools / Inspector and Tools / Library show when you click on the View.
  3. Under Library / Cocoa Touch Plugin / Inputs & Values drag a Round Rect Button on to your View.
  4. Double-click on the button and fill in a label.
  5. Click elsewhere on the View to get out of label editing mode and single-click the button again.
  6. Select the second tab in the Inspector (or press Apple-Key-2) – the title of the Inspector should say Button Connections.
  7. Put your mouse over the circle to the right of event labeled Touch Up Inside.
  8. Drag the mouse over the File’s Owner icon in the *.xib window.
  9. When you release the mouse, select the method that you added to your controller class (in this example configButtonPressed).
  10. Save the *.xib file, and select Build and Go to make sure you wired the button correctly.
  11. In this example when you click the button it should log something to the Debugger Console.

Tags: , ,

May 15

This is an incomplete experiment creating a class to manage an sqlite3 database on the iPhone.

The place that needs the most work is the mcaDB::queryDB() method. The plan is to eventually have this method populate an array or list that I can access after the query is finished. There are methods in PHP that do similar things.

What got me started was Chapter 11: Basic Data Persistence in Beginning iPhone Development.

You can find documentation and the API reference for SQLite here: http://www.sqlite.org.

/*
 *  mcaDB.h
 *  mcaDB1
 *
 *  Created by Mitchell Allen on 5/15/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
 
/*
 *  Instructions for linking to sqlite3 library
 *
 *  In Xcode:
 *
 *      Click on folder: Groups & File / Frameworks
 *      Select menu: Project / Add to Project ...
 *      Navigate to:  /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator[version].sdk/usr/lib/
 *      Select file: libsqlite3.dylib
 *      Uncheck: Copy items into destination groups folder if needed
 *      Change Reference Type to: Relative to Current SDK
 */
 
#include "/usr/include/sqlite3.h"
 
#include "mcaUtils.h"
 
class mcaDB {
 
protected:
 
	sqlite3	*m_database;
 
	bool m_open;
 
public:
 
	void errorDB();
 
	bool openDB( const char *szDB );
 
	void closeDB( bool bForce );
 
	bool execDB( const char *szSQL );
 
	bool queryDB( const char *szSQL );
 
};
/*
 *  mcaDB.mm
 *  mcaDB1
 *
 *  Created by Mitchell Allen on 5/15/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
 
#include "mcaDB.h"
 
void mcaDB::errorDB()
{
	mcaUtils_logString( @"ERROR", sqlite3_errmsg( m_database ) );
}
 
bool mcaDB::openDB( const char *szDB ) {
 
	NSLog( @"mcaDB::openDB( ... )" );
 
	mcaUtils_logString( @"DATABASE", szDB );
 
	if( sqlite3_open( szDB, &m_database ) != SQLITE_OK ) {
 
		errorDB();
 
		closeDB( true );
 
		return false;
	}
 
	m_open = true;
 
	return true;
}
 
void mcaDB::closeDB( bool bForce ) {
 
	NSLog( @"mcaDB::closeDB( ... )" );
 
	if( m_open || bForce ) {
 
		sqlite3_close( m_database );
 
		m_open = false;
	}
}
 
bool mcaDB::execDB( const char *szQuery ) {
 
	NSLog( @"mcaDB::execDB( ... )" );
 
	mcaUtils_logString( @"QUERY", szQuery );
 
	if( ! m_open ) return false;	
 
	if( sqlite3_exec( m_database, szQuery, NULL, NULL, NULL ) != SQLITE_OK ) {
 
		errorDB();
 
		return false;
	}
 
	return true;
}
 
bool mcaDB::queryDB( const char *szSQL ) {
 
	NSLog( @"mcaDB::queryDB( ... )" );
 
	mcaUtils_logString( @"QUERY", szSQL );
 
	if( ! m_open ) return false;
 
	sqlite3_stmt	*stmt;
 
	if( sqlite3_prepare_v2( m_database, szSQL, -1, &stmt, nil ) == SQLITE_OK) {
 
		while( sqlite3_step( stmt ) == SQLITE_ROW ) {
 
			NSLog( @" ... looping ... " );
 
			int iCols = sqlite3_column_count( stmt );
 
			for( int i = 0; i < iCols; i++ ) {
 
				const char *colName = sqlite3_column_name( stmt, i );
 
				mcaUtils_logString( @"COLUMN", colName );
 
				long colType = sqlite3_column_type( stmt, i );
 
				switch( colType ) {
 
					case SQLITE_INTEGER:
 
						int fldInt = sqlite3_column_int( stmt, i );
						mcaUtils_logInteger( @"INTEGER", fldInt );
 
						break;
					case SQLITE_FLOAT:
 
						NSLog( @"FLOAT" );
 
						float fldFloat = sqlite3_column_double( stmt, i );
						break;
					case SQLITE_TEXT:
 
						const unsigned char * fldStr = sqlite3_column_text( stmt, i );
						mcaUtils_logString( @"TEXT", (const char *) fldStr );
 
						break;
					case SQLITE_BLOB:
 
						int fldSize = sqlite3_column_bytes( stmt, i );
						mcaUtils_logInteger( @"BLOB (size)", fldSize );
						break;
					case SQLITE_NULL:
						break;
					default:
						break;
				}
			}
 
		}
 
		sqlite3_finalize(stmt);
	}
 
	return true;
}

Utility Class

This is just something I whipped up to make it easy to log info in the class above while I debug. This will probably change.

/*
 *  mcaUtils.h
 *  mcaDB1
 *
 *  Created by Mitchell Allen on 5/15/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
 
void mcaUtils_logString( NSString *szLabel, const char * str );
void mcaUtils_logInteger( NSString * szLabel, int i );
/*
 *  mcaUtils.mm
 *  mcaDB1
 *
 *  Created by Mitchell Allen on 5/15/09.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */
 
#include "mcaUtils.h"
 
void mcaUtils_logString( NSString * szLabel, const char * str )
{
	NSString *szTemp = [[NSString alloc] initWithUTF8String:str];
 
	NSString *szMessage = [[NSString alloc] initWithFormat: @"%@ = %@", szLabel, szTemp ];
 
	NSLog( szMessage );
 
	[szTemp release];
	[szMessage release];
}
 
void mcaUtils_logInteger( NSString * szLabel, int i )
{
	NSString *szMessage = [[NSString alloc] initWithFormat: @"%@ = %d", szLabel, i ];
 
	NSLog( szMessage );
 
	[szMessage release];
}

Sample Usage

This could go into say a viewController class file.

Define the name of your database.

#define TEST_DB_FILE	@"/test.db1"

Build a complete path to your database file.

- (NSString *) dataFilePath;
{
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 
	NSString *documentsDirectory = [paths objectAtIndex:0];
 
	return [documentsDirectory stringByAppendingString:TEST_DB_FILE];
}

Pass the full path of your database to an object – in say your view controllers viewDidLoad method.

    m_table.initDB( [[self dataFilePath] UTF8String] );

This is how you might define the method above. Yes, in a production environment the final method should always close the database before returning.

void testTable::initDB( const char *szDB ) {
 
	NSLog( @"START: testTable::initDB( ... )" );
 
	if( ! m_db.openDB( szDB ) ) {
 
		NSLog( @" ... ERROR opening database" );
 
		return;
	}
 
	if( ! m_db.execDB(  "DROP TABLE TEST_TABLE;" ) ) {
 
		// Since this is just a test database - we drop the table every time to start fresh.
 
		NSLog( @" ... Couldn't drop table ... ignoring " );
	}
 
	if( ! m_db.execDB(  "CREATE TABLE IF NOT EXISTS TEST_TABLE (ROW INTEGER PRIMARY KEY, PLANET TEXT);" ) ) {
 
		NSLog( @" ... ERROR creating table" );
 
		return;
	}
 
	if( ! m_db.execDB(  "INSERT OR REPLACE INTO TEST_TABLE (PLANET) VALUES ('Mercury');" ) ) {
 
		NSLog( @" ... ERROR inserting row" );
 
		return;
	}
 
	if( ! m_db.execDB(  "INSERT OR REPLACE INTO TEST_TABLE (PLANET) VALUES ('Venus');" ) ) {
 
		NSLog( @" ... ERROR inserting row" );
 
		return;
	}
 
	if( ! m_db.queryDB(  "SELECT COUNT(*) AS myCount FROM TEST_TABLE;" ) ) {
 
		NSLog( @" ... ERROR querying DB" );
 
		return;
	}
 
	if( ! m_db.queryDB(  "SELECT * FROM TEST_TABLE;" ) ) {
 
		NSLog( @" ... ERROR querying DB" );
 
		return;
	}
 
        m_db.closeDB( false );
 
	NSLog( @"END: testTable::initDB( ... )" );
}

Log Output

mcaDB1[3138:20b] START: testTable::initDB( ... )
mcaDB1[3138:20b] mcaDB::openDB( ... )
mcaDB1[3138:20b] DATABASE = /Users/apple/Library/Application Support/iPhone Simulator/User/Applications/.../Documents/test.db1
mcaDB1[3138:20b] mcaDB::execDB( ... )
mcaDB1[3138:20b] QUERY = DROP TABLE TEST_TABLE;
mcaDB1[3138:20b] mcaDB::execDB( ... )
mcaDB1[3138:20b] QUERY = CREATE TABLE IF NOT EXISTS TEST_TABLE (ROW INTEGER PRIMARY KEY, PLANET TEXT);
mcaDB1[3138:20b] mcaDB::execDB( ... )
mcaDB1[3138:20b] QUERY = INSERT OR REPLACE INTO TEST_TABLE (PLANET) VALUES ('Mercury');
mcaDB1[3138:20b] mcaDB::execDB( ... )
mcaDB1[3138:20b] QUERY = INSERT OR REPLACE INTO TEST_TABLE (PLANET) VALUES ('Venus');
mcaDB1[3138:20b] mcaDB::queryDB( ... )
mcaDB1[3138:20b] QUERY = SELECT COUNT(*) AS myCount FROM TEST_TABLE;
mcaDB1[3138:20b]  ... looping ...
mcaDB1[3138:20b] COLUMN = myCount
mcaDB1[3138:20b] INTEGER = 2
mcaDB1[3138:20b] mcaDB::queryDB( ... )
mcaDB1[3138:20b] QUERY = SELECT * FROM TEST_TABLE;
mcaDB1[3138:20b]  ... looping ...
mcaDB1[3138:20b] COLUMN = ROW
mcaDB1[3138:20b] INTEGER = 1
mcaDB1[3138:20b] COLUMN = PLANET
mcaDB1[3138:20b] TEXT = Mercury
mcaDB1[3138:20b]  ... looping ...
mcaDB1[3138:20b] COLUMN = ROW
mcaDB1[3138:20b] INTEGER = 2
mcaDB1[3138:20b] COLUMN = PLANET
mcaDB1[3138:20b] TEXT = Venus
mcaDB1[3138:20b] mcaDB::closeDB( ... )
mcaDB1[3138:20b] END: testTable::initDB( ... )

Tags: ,

May 08

Because my main interest is in developing portable video games, my focus in the blog has been OpenGL ES. But if you want to know how to develop applications that don’t use OpenGL – the best book I’ve found so far is Beginning iPhone Development: Exploring the iPhone SDK.

The book covers all the important basics and shows you how to build an iPhone UI and wire up the buttons, etc. In fact it’s the book I used to figure out how to write the touch handlers in the previous example. Besides basic interaction (taps, touches, gestures), the book also covers what’s known in the iPhone as “views” (think of them as pages of your application). It also covers things like how to design for rotation, acceleration, location, table views, tab bars, pickers, etc. It even covers the basics of using SQLite3 to save data locally.

Once you are done reading the book, you may realize just how simple it is to recreate many of the apps that you see in the App Store and in the Apple commercials using ready made components supplied by the iPhone SDK.

Even if you decide to just build an OpenGL ES app – you will probably still end up using views to create opening and configuration screens for your app. So no matter what approach you take to developing iPhone apps, you will probably find the information in this book essential.

Besides Amazon – you can buy a PDF version of the book here: http://www.apress.com/book/view/1430216263

Since the book is heavy in Objective-C code, you may also want to pick yourself up a copy of Programming in Objective-C 2.0 (2nd Edition) (Developer’s Library).

Tags: ,