Wednesday, October 26, 2011

Loading PVRTC textures without blocking iOS User Interface

While working on my new iOS game, I decided to add one of those nice view transitions when you start a new level. At first I was puzzled by the lack of a nice animation, but then it dawned on me why: iOS will only remain smooth, and show its fancy animations as long as you do not block the main thread. When starting a level, I would first load large textures on the main thread. So how to avoid this?

iOS makes it easy to offload heavy lifting to other threads by using Grand Central Dispatch and its Objective-C construct for code blocks. The trick is to decide what to offload. At first I naively did the whole texture creation on another thread. The downside of this is that you now have two threads competing for the same OpenGL context. A way around would be mutex, but there is a more elegant and simple approach to it that does not involve locking the context or adding a mutex.

The slow part of texture creation is not the uploading with glTexImage() neither the creation of the texture name with glGenTextures(). It is the file loading of the image data, and the decoding of the PVRTC that gobbles up cycles. So only the loading and decoding has to be moved to another thread. All the OpenGL calls can remain on the main thread, and no context locking is required.

I expect that most iOS developers are using the Apple-provided class PVRTexture.h/PVRTexture.m which can be found at the developer.apple.com site. Adapting this class to offload the texture load/decode on another execution thread is simple. Just follow this recipe:

First add a new member variable to PVRTexture.h


dispatch_group_t dispatchGroup;

Then, add a static var and a class method to PVRTexture.m


static dispatch_queue_t dispatchQueue;

+(void)initialize
{
dispatchQueue = dispatch_queue_create( "textureLoadingQueue", nil );
}

Next, replace this section in createGLTexture


if ([_imageData count] > 0)
{
if (_name != 0)
glDeleteTextures(1, &_name);

glGenTextures(1, &_name);
glBindTexture(GL_TEXTURE_2D, _name);
}

with just a single line


glBindTexture(GL_TEXTURE_2D, _name);

last, replace the implementation of initWithContentsOfFile with


- (id)initWithContentsOfFile:(NSString *)path
{
self = [super init];

glGenTextures( 1, &_name );

dispatchGroup = dispatch_group_create();

dispatch_group_async( dispatchGroup, dispatchQueue, ^{
//NSLog( @"Loading texture data from file" );
NSData *data = [NSData dataWithContentsOfFile:path];

_imageData = [[NSMutableArray alloc] initWithCapacity:12];

_width = _height = 0;
_internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
_hasAlpha = FALSE;

assert( data );
const BOOL unpacked = [ self unpackPVRData:data ];
assert( unpacked );
});

dispatch_group_notify( dispatchGroup, dispatch_get_main_queue(), ^{
//NSLog( @"Creating GL texture for name %d", _name );
const BOOL created = [ self createGLTexture ];
assert( created );
});

dispatch_release( dispatchGroup );
dispatchGroup = 0;

return self;
}

Some notes: I added asserts to catch missing texture data and such. If you want more graceful failures, like the original had, you may want to adapt that. Also: with this change you can do some really neat stuff, like starting your game before the textures are loaded. OpenGL will happily draw the scene if the texture data is not yet uploaded to the GPU. The world will incrementally be populated with textures, before the player's eyes. Less Waiting, More Playing: how is that not a win?

I used the same tactic for the creation of OpenDE triangle meshes used for my physics simulation. I simply keep the sim delta-time at 0.0 as long as the triangle mesh has not been built yet: let the player absorb the environment while the game is still doing its initializations.

Wednesday, September 21, 2011

The geography factor in freemium conversions

Or: why Kiwi customers rock.

I have been studying the influence of geography on the conversion of freemium users into paying customers. To do this, I analyzed three weeks of sales data from the Mac App Store for the little crane that could.

It turns out that in New Zealand, the users were very likely to buy premium content for the game. For every four downloaders, one of these would purchase additional content. I wonder if this is caused by the fact that in New Zealand internet access is often metered. This would mean that downloading free apps would already constitute a financial commitment by the New Zealand user, so the step to in-app-purchase is smaller.

As a side note: the Mac version of `the little crane that could' had its biggest market in Germany, followed by UK. So even with low German conversion rates, the bulk of the revenue was generated in the German market.

Sunday, August 21, 2011

Hover bikes

I have been collecting some images of hover bikes strewn about the net. Below is what I came up with. I am toying with the idea of doing a racing game, perhaps with pod racers or hover bikes. I doubt that I have the artistic talent to model a good one, so I may have to get myself one on commission. Drop me a line if you can do something like this in Wings3D at low polygon count.



Hover bike by Mr Lakhwinder Singh Dhillon



Hover bike by Serrge



Spitfire by Joe Ulibarri



Hover bike by C Goddard


Hover bike by ershov


Hover bike by Zack Fowler


Hover bike 'ridon' by Ivan Tantsiura


Tuesday, August 16, 2011

Bram interviewed by Geek Preview

I was interviewed by the blog Geek Preview. You can read about it here, where I discuss the history of the little crane that could and more.


Thursday, August 4, 2011

Domme kamervragen

Die cda kamervragen over kwaliteit van de beveiligings cameras slaan de plank compleet mis. Met simpele statistiek en kansrekening is dit uit te leggen: Het publiek ziet alleen beelden van onopgeloste zaken. Veel beeldmateriaal is van uitstekende kwaliteit... De politie lost de zaak op, en het beeldmateriaal bereikt nooit het publiek. Hoe beter de kwaliteit, hoe kleiner de kans dat het publiek nodig is bij het oplossen daarvan. Dat de kamer zich hier over moet buigen is een schande. Bewijst maar weer eens de onkunde van politici. Wellicht is het tijd voor een technocratie?

Monday, July 4, 2011

Sunny evening in the park

It was such a beautiful summer evening today in Vancouver. Amy, Annelies and I soaked up some evening sun in the local park, and of course I brought my camera. Annelies was enjoying it, as did we. Because of the bright sun, you normally cannot use large apertures, as the picture would be over exposed. My camera however, has a built-in neutral density filter that you can activate. This enables you to get shallow depth of field in bright outdoor environments. Without it, I would have been forced to close the aperture all the way down to f/16, so I would have lost the nice blur in foreground and background. My Flickr photostream has another picture of mum and Annelies.

Friday, July 1, 2011

Canada 144 years old

Today Annelies celebrated her first Canada Day by proudly waving the red and white maple leaf flag. I've blogged before on Canada day, when Canada celebrated its 140th birthday and again at the 141th birthday.

Wednesday, June 29, 2011

X100 first image

So the Fuji X100 arrived, and here is an early shot with it. Taken with lens wide open F/2.0 and +2 Exposure Compensation, ISO 800. I cropped, mirrored and scaled it in GIMP to make it manageable for the blog. I really like the soft focus with it, and the pleasant bokeh.

So you can expect a lot of nice pictures of Annelies soon. I guess I have to sign up for a flicker account now.

Batteries

Today, my Fujifilm X100 digital camera with an hybrid viewfinder arrived from Ontario. This fine piece of equipment comes in a jewelry box, no less. I'm very anxious to test it out, but am currently waiting for the battery to charge before I can begin flashing the firmware and then shoot my first picture. While my battery charges, I was looking into purchasing a second battery as backup. Shopping for batteries is a bit like shopping for an HDMI cable: there are huge price differences for the same model battery. Now with HDMI cables I know that the cheapest cable is just as good as the overpriced rip offs. With batteries, I actually do not know. Here are two pictures of the same NP95 battery. One costs $10 and the other costs $54. Should I get the original one from fuji? Or is the replacement battery just as good? Who knows. I do know that the Dutch consumer report 'de consumentenbond' once tested non-rechargeable batteries and found out that batteries from Ikea were by far the best buy you could make: lasted extremely long, and were really cheap. Certainly not a case of 'you get what you pay for'.

Friday, June 24, 2011

the 8th incarnation

The 8th incarnation of the little crane that could is imminent. I just uploaded v1.7 to Apple for review. It will support multi tasking so that progress in a level is not lost, if you switch apps. Also there is a new level, that lets you clean up flipped over police cars after a hockey riot. It should be in the app store soon, Apple normally approves updates in a week or so.

Monday, June 6, 2011

2007 called

It is so 2007, but hey, I just signed up for Twitter. You can follow me @BramStolk. My intended primary use is communicating with gamers that play the little crane that could. I will be using the hash tag #tlctc for this. What finally made me jump on the bandwagon was today's WWDC keynote announcing full integration of Twitter at OS level. I look forward to using iOS5 and OSX Lion, and of course the newly announced iCloud. I foresee exciting times ahead, and hopefully an imminent end to the monstrosity called Microsoft Windows.

Thursday, April 14, 2011

iOS developers: maybe not a rare breed after all?

So, how scarce are iOS developers. Or maybe, how bountiful? I think I got a rough glimpse on this matter, as Apple's Game Center was shining some light on it. Based on this, I am going to venture a wild guess that between a half and one percent of all iOS gamers have a developer account, and can thus be considered to be developers themselves. If this figure is correct, it is a lot more than I intuitively expected it to be.

To aid developers with the integration of Game Center in their apps, Apple has deployed a dual infrastructure. There are the production servers, for use by the population in general. There is also the Sandbox environment, where developers can submit test-scores, and see if their code is working as expected. Once a developer starts using this Sandbox environment, it is very easy to use the Sandbox by accident for all other gaming as well (thus, not when testing their own app, but enjoying a random app-store hit for instance, to relieve some stress). If this happens, scores from test users show up in the Sandbox leader boards of other developers.

So here are some statistics from the leader boards of my game the little crane that could. On the leader board for the second level of the game (basketball court), there are as of today:

314,960 names (production servers of Game Center)
2,112 names (sandbox servers of Game Center)

This ratio would indicate that 0.7% of all iOS gamers are iOS developers. Now of course, there are some other factors that may skew this measurement. Let me list a few of them for you:

First, there is the fact that some developers actually may log out of the test account before playing my game. I must say it is a lot easier to forget, than to actually switch accounts. This factor would cause the developer-gamers to be under-reported.

next, there is a difference of adoption rate(*): a developer may be more likely to have signed up for Game Center than a general gamer. This is simply because as a developer, he should be aware of these kind of things. Ignoring Game Center impacts a developer harder than it would a casual gamer who may prefer to stay with OpenFeint for instance. This factor would cause the developer-to-gamer ratio to be over estimated.

Last, it must be mentioned that it is conceivable that there has been a problem with Apple's servers. If general gamers were routed to the sandbox server, even for a small period of time, my estimation would be completely compromised, as the developers would be grossly over-reported. If this were to be the case, the margin of error would make my estimate useless.(**)

(*)Speaking of adoption rates of Game Center by gamers: it appears low to me. My game saw well over 1M downloads, yet the most played level in my game only sees 314K names. Is it because the gamers don't bother to finish this level, or do most gamers play without a Game Center account?

(**)This scenario would be unlikely though, as I have been steadily adding new levels to the game. These new levels show a similar ratio. This is evidence against incidental server problems.

Wednesday, April 6, 2011

Work around for xcode 4.0.1 crash in NSATSGlyphStorage

If you encounter a crash each time you try to load your xcode 4.0.1 project, you may be facing the same xcode4 bug that I experienced. I managed to work around it by deleting a file. From the call stack I gathered that the crash occurred during the layout of the source code editor. So deleting the layout info stopped it from crashing upon start up. if it happens to you, delete the file:

SOMEPROJECT.xcodeproj/project.xcworkspace/xcuserdata/SOMEUSER.xcuserdatad

Tuesday, April 5, 2011

Big Crane

Look at what payed us a visit this afternoon. Not the little crane that could, but its bigger brother, the big crane. It is laying some underground transmission lines under Laurel street for BC Hydro, the electricity provider here in Vancouver.

Thursday, March 24, 2011

Help for the little crane

In the next version of the little crane that could there will be a new vehicle. Alongside the little crane, there is now a dump truck to help out our little hero in the new level 'strip mine'. Version 1.3 is in the final stages, so should be submitted to the app store this week, for an imminent release.

Also new in this release will be Japanese and Dutch localizations, and a slightly better handling of the truck. For the non-paying customers, there will be two more levels to play, as 'bridge builder' and 'train station' will now be free.

Tuesday, March 22, 2011

Playing the Toronto stock market

If you have savings that are not tied up in residential properties, and have no debts, the logical thing to do with it is to invest it in the stock market. If you don't, your money will be eaten by inflation, as interest payed by Canadian banks is ridiculously low, and does not even match inflation. Here I document what stocks I bought and why, so that for future reference I can look back on my mistakes. I thought I would do it in public, so others may learn from the mistakes I made as well. I trade my stock at Toronto, because that is cheapest for me, and I avoid the bad currency conversion rates that RBC is prone to offer you.

So the first stock I bought after opening my trading account was a boring stock, just to test the trading portal, and see how buying stock works. The stock was RA or Royal Bank of Canada, as I figured it would be reasonably stable due to its size and steady operations. I bought this for 61.40 on march 9, and so far lost a few percent on it.

The next purchase I made was triggered by the Japan earth quake. In its wake, the markets fell, and the largest losers were nuclear energy related stocks. On Toronto, Uranium One (a large uranium mining company) fell hard during a couple of days. My common sense told me that the price drop was far too large to reflect the actual change of value of the company. This is why I bought UUU for 3.81 on march 15. This turned out to be a golden decision so far, as I bought it at almost the lowest point, and the stock shot up just as hard as it fell: so far a tidy profit in just a few days.

Next up were some utility stocks. I live in Vancouver, and see how much electricity is used here to heat and cool buildings. Frequent harsh winters and frequent hot summers, coupled with the ever expanding city makes me believe the demand on electricity will rise. Even though hydroelectricity is produced cheaply here, it is sold at really high rates to the consumers (you should see the energy bill I had on a 2 bedroom Beach Avenue apt). To find the stock, I typically look for bargains. I want to see healthy business for low price-to-book ratios, with low debts. This brought me to the renewable energy producer Boralex. I bough BLX for 8.46 on march 22. Boralex does hydro and geothermal. I also bought a solar energy technology company Arise Technologies, APV for 0.15 on march 22. With the advent of electric vehicles, electricity should become a hot commodity.

My friend tipped me on the growth potential of companies that work on 3D printing. On Nasdaq, there are Stratasys and 3D Systems corp. Both have sky high price to earnings ratios, so I will hold off for now. But would they ever crash, it could be time to scoop them up as they are potential supergrowers.

So, what are your ideas on the market? I would love to read them, so leave them in the comments. Let me conclude with a warning: never invest with borrowed money, only invest what you can spare.