Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS / Core-Animation: 12 overlapping cards in a circle

I am trying to arrange 12 objects in the circle so that each overlaps its anticlockwise neighbour.

Something like this:

enter image description here

Problem is that if I just rely on the drawing order, one of them is always going to be completely on top, in this case the red one at 12 o'clock.

I have tried using

    {
        GlowButton* G = glowButton[ 0 ];

        float theta = 0.3;
        G.layer.transform = CATransform3DMakeRotation( theta, 0, 1, 0 );
    }

In an attempt to rotated around the vertical axis, thus tucking one side behind the neighbour, but this isn't working.

I have been told this is because core animation doesn't support depth testing.

Is there any way to do this without breaking into GL?

like image 656
P i Avatar asked Aug 30 '11 13:08

P i


2 Answers

I can think of two ways to avoid the problem:

  1. Split each of the object in half. The first draw those halves that are behind the neighbour objects, then draw those halves on top of the neighbours.

  2. Use a clipping area and draw the circle in two steps. The first clipping area restricts drawing to the left half of the picture. The second clipping area is restricted to the right half. Each time, you draw all objects. But you have to start either at the bottom or top element.

I'm not quite sure what you're doing with Core Animation so one of the approach might be a better fit or need some adaption.

like image 99
Codo Avatar answered Nov 05 '22 04:11

Codo


I have this working perfectly now. I'm very relieved not to have had to go to GL.

enter image description here

I basically draw the first (red -- at 12 o'clock) gem with a mask only allowing the right half to be visible.

Then I draw the remaining 11.

Then I draw the first one again, this time setting the mask to only show the left half.

    for( int i = 0; i <= 12; i++ )
    {
        for ( int dullGlow = 0; dullGlow <= 1; dullGlow++ )
        {
            BOOL isDull = ( dullGlow == 0 ) ? YES : NO;

            CALayer* L = [CALayer layer];

            CGImageRef dullImage = [ButtonImages dullImage: i % 12];
            CGImageRef glowImage = [ButtonImages glowImage: i % 12];

            L.contents = (id) ( isDull ? dullImage : glowImage );

            L.bounds = CGRectMake( 0, 0, buttonSize, buttonSize ); 

            L.opacity = ( isDull ? 1.0 : 0.0 );

            if( i == 0  ||  i == 12 )
            {
                CGFloat halfSize = buttonSize / 2.0;

                CGRect keepLeftHalf = CGRectMake( 0, 0, 
                                                 halfSize, buttonSize );

                CGRect keepRightHalf = CGRectMake( halfSize,  0, 
                                                  halfSize, buttonSize );

                CALayer* maskLayer = [CALayer layer];
                maskLayer.frame = ( i == 0 ) ? keepRightHalf : keepLeftHalf;
                maskLayer.backgroundColor = [UIColor greenColor].CGColor;

                maskLayer.edgeAntialiasingMask = 0x0;

                [L setMask: maskLayer];
            }

            [self.layer addSublayer: L];

            layers[ dullGlow ] [ i ] = L;

        } // dullGlow

    } // i

Setting edgeAntialiasingMask's 4 least significant bits to 0 terms of anti-aliasing on all 4 edges -- without this line I was getting a seam.

I would be very grateful if someone can explain the mechanics of the masking process -- though I achieved the correct result, I did it by trial and error.

Notice that the mask is set to ( opaque ) green, and it is the masked area that is visible -- ie for the first pass the green rectangle is covering the right half of the image, and it is this love that gets displayed.

I am guessing that for each pixel it is multiplying the layer-pixel RGBA by the alpha value on the mask-pixel

like image 30
P i Avatar answered Nov 05 '22 04:11

P i