Pioneering Software

Innovation, quality, care.

Gloss Caustic Shader for iPhone

| Comments

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.

Gloss Caustic Shader on 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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 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.

Your feedback

As always, very welcome. Thanks again Ole. Your improvements are much appreciated. You can find Ole’s work at GitHub. Mine also at GitHub.

Comments