Ole Begemann has done some very useful work, porting the gloss-caustic shader to iPhone OS. This work has been long overdue. Many thanks Ole!
I’ve merged Ole’s changes into my Git repo, albeit with a few modifications. This article outlines the changes to the changes.
What has changed?
I’ll not dig too much into Ole’s enhancements. Ole does that on his page. In summary:
- Shader sources compile for OS X and iPhone OS.
- Has two sample projects, one for OS X and the other for iPhone.
Why does it need porting?
The fundamental difference between iPhone and OS X for the gloss-caustic shader concerns its use of NSColor. Simply put, iPhone does not have such a class; instead, it has UIColor with limited support for colour spaces and no support for RGB-to-HSB conversion.
Strangely, you can make the reverse conversion, from HSB to RGB by invoking class method
+colorWithHue:saturation:brightness:alpha:
and UIKit answers with a colour with triple RGB components whence you can access the red, green, blue and alpha component values. But iPhone has no instance method
-getHue:saturation:brightness:alpha:
as does OS X.
The basic approach
The simple approach Ole takes is to surround the difference between OS X and iPhone with #if TARGET_OS_IPHONE
, #else
, #endif
blocks. Xcode defines TARGET_OS_IPHONE
only when compiling for iPhone.
Under normal circumstances, I would avoid this approach since it makes code difficult to read and maintenance harder in the long run. Nevertheless, the pre-processor conditional blocks turns out relatively small in number and in extent. Each one in general surrounds just one line of code: the first condition presents the iPhone’s UIColor-based alternative, while the second condition presents OS X’s NSColor-based alternative.
Maintaining semantics
Ole has included a number of useful functions for colour conversion, based on work by Erica Sadun and some standard RGB-to-HSB conversion code. I’ve repackaged these as extensions on UIColor with semantics mirroring that of NSColor.
Interface for UIColor(RRUIKit)
as follows.
// Fill in some of the "missing" UIColor methods, making UIColor more compatible
// with NSColor. This includes access to individual colour components and HSV
// conversion. Use similar method signatures and semantics as far as possible.
@interface UIColor(RRUIKit)
- (UIColor *)colorUsingColorSpaceModel:(CGColorSpaceModel)model;
- (CGColorSpaceRef)colorSpace;
- (CGColorSpaceModel)colorSpaceModel;
- (NSUInteger)numberOfComponents;
- (void)getComponents:(CGFloat *)components;
- (CGFloat)redComponent;
- (CGFloat)greenComponent;
- (CGFloat)blueComponent;
- (CGFloat)alphaComponent;
//---------------------------------------------------- Hue-Saturation-Brightness
- (void)getHue:(CGFloat *)hue saturation:(CGFloat *)saturation brightness:(CGFloat *)brightness alpha:(CGFloat *)alpha;
// Answers the components of RGB colours as hue, saturation and
// brightness. Adds the missing UIColor method for converting RGB to
// HSB. This method assumes that self (an instance of UIColor) has RGB
// colour model.
@end
Serialisation
Ole implements a set of extensions on RRGlossCausticShader
for saving shader setting to a dictionary. I’ve enhanced this functionality by implementing the NSCoding
protocol for shader and matcher classes.
Coding adds a level of extra flexibility. The coding protocol lets you serialise trees of objects (the shader and its enclosed matcher) by archiving to any data stream.
Key-value coding
I’ve also simplified the iPhone sample’s view controller. iPhone OS does not include bindings. Hence implementing the update cycle within the controller can become rather tedious when there are many control elements, such as with gloss-caustic shaders.
My enhancement on Ole’s enhencement employs key-value coding, i.e. accessing properties via -valueForKeyPath:
and -setValue:forKeyPath:
. It makes things a little less long-winded.