4

I'm using the clipping node here: http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode

ClippingNode.h

#import "cocos2d.h"
@interface ClippingNode : CCNode {
    CGRect clippingRegionInNodeCoordinates;
    CGRect clippingRegion;
}
@property (nonatomic) CGRect clippingRegion;
@end

ClippingNode.m

#import "ClippingNode.h"

@interface ClippingNode (PrivateMethods)
-(void) deviceOrientationChanged:(NSNotification*)notification;
@end

@implementation ClippingNode
-(CGRect) clippingRegion {
    return clippingRegionInNodeCoordinates;
}

-(void) setClippingRegion:(CGRect)region {

    // keep the original region coordinates in case the user wants them back unchanged
    clippingRegionInNodeCoordinates = region;
    self.position = clippingRegionInNodeCoordinates.origin;
    self.contentSize = clippingRegionInNodeCoordinates.size;

    // convert to retina coordinates if needed
    region = CC_RECT_POINTS_TO_PIXELS(region);

    // respect scaling
    clippingRegion = CGRectMake(region.origin.x * scaleX_, region.origin.y * scaleY_,
                            region.size.width * scaleX_, region.size.height * scaleY_);
}

-(void) setScale:(float)newScale {
    [super setScale:newScale];
    // re-adjust the clipping region according to the current scale factor
    [self setClippingRegion:clippingRegionInNodeCoordinates];
}

-(void) deviceOrientationChanged:(NSNotification*)notification {
    // re-adjust the clipping region according to the current orientation
    [self setClippingRegion:clippingRegionInNodeCoordinates];
}

-(void) visit {

    glEnable(GL_SCISSOR_TEST);
    CGPoint worldPosition = [self convertToWorldSpace:CGPointZero];
    const CGFloat s = [[CCDirector sharedDirector] contentScaleFactor];
    glScissor((clippingRegion.origin.x) + (worldPosition.x*s), (clippingRegion.origin.y) + (worldPosition.y*s),
          (clippingRegion.size.width), (clippingRegion.size.height));

    [super visit];

    glDisable(GL_SCISSOR_TEST);

}
@end

However, I need to clip a rotated CCNode. Any idea on how I could accomplish such a task?

docchang
  • 1,115
  • 15
  • 32
  • By rendering the node to a texture then using the texture in a sprite that can be rotated independently. Does it require the user to interact with the node? If so you would need to do some coordinate convertions between both. – rraallvv Jan 06 '13 at 04:15
  • Yes, the user is scaling, panning, rotating a picture in a rotated frame. Not sure where should I create the CCRenderTexture? at the ClippingNode the parent of ClippingNode? – docchang Jan 06 '13 at 19:41

2 Answers2

2

Replace the visit method in the class ClippingNode by this

-(void) visit
{

    float rotationAngle = 15;

    glPushMatrix();

    CCRenderTexture* renderTexture = [[CCRenderTexture renderTextureWithWidth:512 height:512] retain];

    glEnable(GL_SCISSOR_TEST);
    glScissor(0, 0, clippingRegion.size.width, clippingRegion.size.height);

    [renderTexture begin];

    glPushMatrix();
    glRotatef(rotationAngle, 0, 0, 1);
    glTranslatef(-clippingRegion.origin.x, -clippingRegion.origin.y, 0);

    [super visit];

    glPopMatrix();

    [renderTexture end];

    glDisable(GL_SCISSOR_TEST);

    renderTexture.sprite.position = CGPointMake(clippingRegion.origin.x , clippingRegion.origin.y);
    renderTexture.sprite.anchorPoint = CGPointMake(0, 1);
    renderTexture.sprite.rotation = rotationAngle;
    [renderTexture.sprite visit];

    [renderTexture release];

    glPopMatrix();
}

Basically it creates a texture where to render the ClippingNode contents

Then translate the scene so that the origin in the clipping region is now at (0,0)

Rotate the entire scene by rotationAngle

Enable the scissor

Render the scene

Translate, rotate, and render the sprite containing the texture

enter image description here

rraallvv
  • 2,875
  • 6
  • 30
  • 67
  • 1
    I'm using Cocos2d 2.0. How do you translate glRotatef and glTranslatef to 2.0? – docchang Jan 07 '13 at 06:34
  • It's been awhile since I've used cocos2d, haven't worked with 2.0, I think it only uses OpenGL ES 2.0, so it would need to add rotation and translation in the shader. I'm downloading Cocos2d 2.0 to test and update my code – rraallvv Jan 07 '13 at 13:38
  • I was hacking the code for a bit. The clipping effect also works when using RenderTexture without using `glScissor`. However the position of my image and the clipping is a bit confusing to me. I can't get it where I want it to be. – docchang Jan 07 '13 at 13:43
  • Just added my clippingNode into my project. I'm taking a screenshot programmatically. However the clipped image is not included in the screenshot. Any ideas? I'm using the screenshot function here: http://www.learn-cocos2d.com/2011/12/how-to-use-ccrendertexture-motion-blur-screenshots-drawing-sketches/#screenshot – docchang Jan 09 '13 at 00:34
  • You might want to open a new question including some screenshots, maybe other fellows could help too. – rraallvv Jan 09 '13 at 00:50
0

It only needs CCRenderTexture to finish the job. Any suggestion will be greatly appreciated.

ClippingNode.h

#import "cocos2d.h"
@interface ClippingNode : CCNode
@property (nonatomic, assign) CGSize clippingSize;
@end

ClippingNode.m

#import "ClippingNode.h"
@interface ClippingNode()
@property (nonatomic, strong) CCRenderTexture * renderTexture;
@property (nonatomic, strong) CCSprite * clippedSprite;
@end


@implementation ClippingNode
@synthesize renderTexture;
@synthesize clippedSprite;
@synthesize clippingSize;

- (void) setClippingSize:(CGSize)newClippingSize {

    //assignment
    clippingSize = newClippingSize;

    //set contentSize
    self.contentSize = clippingSize;

    //configure renderTexture
    self.renderTexture = [CCRenderTexture renderTextureWithWidth:clippingSize.width height:clippingSize.height];
    renderTexture.contentSize = CGSizeMake(clippingSize.width, clippingSize.height);

    //configure the renderTexture sprite
    self.clippedSprite = [CCSprite spriteWithTexture:renderTexture.sprite.texture];
    clippedSprite.position = self.position;
    clippedSprite.rotation = rotation_;
    clippedSprite.scaleY = -1;
}

- (void)visit {
    [renderTexture beginWithClear:0 g:0 b:0 a:1];
    [super visit];
    [renderTexture end];

    [clippedSprite visit];
}

@end

Usage:

CCSprite * spriteImage = ...;
spriteImage.position = ccp(0,0);
spriteImage.anchorPoint = ccp(0.5,0.5);

//configure clipping Node
self.clippingNode = [ClippingNode node];
clippingNode.position = ccp(size.width * 0.5f, size.height * 0.5f);
clippingNode.anchorPoint = ccp(0.5f, 0.5f);
clippingNode.rotation = -10.0f;

//configure clipping region
[clippingNode setClippingSize:CGSizeMult(spriteImage.boundingBox.size, 1.5f)];

//add content to the clipping node
[clippingNode addChild:spriteImage]
docchang
  • 1,115
  • 15
  • 32