PARMANOIR

Projected coordinates of a 3D CALayer

There's no explicit method to get projected coordinates of a 3D CALayer, but you can use convertRect:fromLayer to almost get them. Thanks to Simon Fraser on the Quartz ML for that.

Suppose you have layers setup like that :

rootLayer
  layerHavingA3DTransform
    layer1
    layer2
    layer3

layer1, layer2, layer3 will be transformed by layerHavingA3DTransform and will appear 3D. To get their projected coordinates, use

CGRect projectedRect = [layer1 convertRect:localRect toLayer:[self layer]];

This will transform localRect, a rect in layer1 coordinates to root layer coordinates. If you want the layer extent, that's -bounds.width/2, -bounds.height/2, bounds.width, bounds.height for the default anchorPoint of (0.5, 0.5). Note that projectedRect is in layer coordinates, not in NSView coordinates. For this case I had manually centered layerHavingA3DTransform in the view and got coordinates reflecting that, going from -size to +size.

I only tested axis aligned layers. If you want coordinates from a rotated layer, you might try convertPoint:fromLayer to convert each layer point.

Oval radial gradients

Radial gradients are filled by moving a circle along a line, while changing its color. They look nice but a bit too 'circly' for my tastes, and I couldn't figure out how to squash them. Turns out it's really simple !, as the points you use to define them obey the same rules as any other primitive : they're transformed by the view matrix. Use CGContextScaleCTM(context, 1, someSquashValue) then draw as usual with CGContextDrawRadialGradient.

Image:Radial gradients.png

This will squash your gradient's circle and its height, so you'll need to compensate CGContextDrawRadialGradient's startCenter and endCenter. Once there, you can draw a really nice radial background.

Core Animation's convertPoint:toLayer: and sublayerTransform

Quick note : if you have a container CALayer containing layers arranged in a grid, have a sublayerTransform setup on it, and want to get its transformed layer coordinates on a mouseDown, you'll need a helper layer :
// We're in mouseDown
CGPoint point = NSPointToCGPoint([self convertPoint:event.locationInWindow fromView:nil]);

// Build a dummy CALayer and insert it
CALayer* helperLayer = [CALayer layer];
[containerLayer addSublayer:helperLayer];

// Get coordinates
CGPoint layerPoint = [[self layer] convertPoint:point toLayer:helperLayer];

// Remove our helper layer
[helperLayer removeFromSuperlayer];
Now why can't we just ask for containerLayer's coordinates ? Because it has a sublayerTransform, so its coordinates are really the same as its parent. We can't ask for one of containerLayer.sublayers either : being laid out (layouted ? :) ) in a grid, they each have their own coordinate system. We therefore use a dummy layer : it has a default position of [0, 0] and will give the point transformed trough sublayerTransform.

ImageKit's HUD Controls1

Frustrated by the absence of HUD controls in Leopard ? ImageKit may alleviate a little, if you dare use undocumented stuff.

Image:ImageKit HUD Controls.png

Add Quartz.framework to your project, open your NIB, drag sliders in and set their class to IKGraySlider (top one in the screenshot) or IKSlider (bottom one). The white spinner is IKSmallProgressIndicator, it has to be setup in code.

Thanks to F-Script for the spying around. There are more classes but I can't get them to work. Also, plenty of images in /System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/ImageKit.framework/Versions/A/Resources/

Sample code

Image:iconZip.png HUD Controls.zip

Changing the background color of an NSButton

If you want to color or visually change one of your controls, the easiest way to do it is with Core Image. In Interface Builder, click wants Core Animation Layer, and add content filters.

Image:Changing background color of NSButton.png

This one uses Color Monochrome to color the button. In Dynamic overloading : sample code, I used Color Matrix but strangely it's not available in my version of IB. Well, you can always set it up in code. It's better than overloading all NSButtons' drawRect — that's quite overkill to color just one button. :)

Core Animation is right handed4

Right handed ? Count to 3 on your left and right hands. Align your fingers so that each finger is perpendicular to the other two. One, two, three gives the axes : X, Y, Z. Line up your hands so that X goes left and Y goes up. Now each hand's Z goes opposite the other's. Your right hand is your Core Animation frame, same as OpenGL.

For some reason I thought CA was left handed — I had my layers set with a positive Z value. The layers showed up where I was expecting them, but visually it was a mess : the far layers were drawn on top of the near layers ! Using a negative Z value fixed the glitch.

Perspective in CA, using 3D CALayers and a perspective transform :

your eye     layers are closer (bigger) here         layers have same size as in 2D        layers are farther (smaller) here

------------------ positive Z value ------------------------- zero Z value ----------------------- negative Z value---------

Core Animation is mostly 2D

Being a layer engine, Core Animation doesn't care much about 3D. Yes, you can setup a projection transform but it will be limited :
  • myLayer.transform = projectionTransform only myLayer will have perspective, not its sublayers
  • myLayer.sublayerTransform = projectionTransform only myLayer's sublayers will have perspective, not myLayer nor its sublayers's sublayers

If you want a CALayer to have perspective and one of its sublayers to also have perspective, make sure they both have a perspective transform applied.

I find myself treating CALayers as if they were living in a 3D world, but Core Animation is not a mini OpenGL to handle textured rectangles. I wish it were, though.
2008 05 14Projected coordinates of a 3D CALayer
2008 05 10Oval radial gradients
2008 05 06Core Animation's convertPoint:toLayer: and sublayerTransform
2008 05 051ImageKit's HUD Controls
2008 05 01Changing the background color of an NSButton
2008 05 014Core Animation is right handed
2008 04 29Core Animation is mostly 2D
2008 04 27Dynamic overloading : sample code
2008 04 272Dynamic method over* from a Javascript standpoint
2008 04 252Cocoa : Failure to spread
2008 04 24Core Animation Bindings
2008 04 22Key Value Bastard Observing
2008 04 08Threaded Core Animation : sample code
2008 04 08Problem with invisible CALayers ?
2008 04 03Threaded Core Animation
2008 04 012Core Animation Starfield
2008 03 29Outlets from a Javascript standpoint
2008 03 29Target+action from a Javascript standpoint
2008 03 28Bindings, Outlets, Target+Action across multiple NIBs
2008 03 27Quicksilver-like search with NSPredicate

Powered by MediaWiki

Hi ! I'm learning Cocoa to (hopefully !) become an indie developer.

I've written software all my professional life, in C++, PHP, Javascript. I've designed websites and web interfaces. My last venture went into flames as clients were happy but didn't like paying very much.

I've had little luck in the B2B world, I'm hoping for a better future writing Mac applications.

Image:rss.png Feed

Planet Cocoa