Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display object clipping #1070

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions sparrow/src/Classes/SPDisplayObjectContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
{
@private
NSMutableArray *mChildren;
SPRectangle *mClipRect;
}

/// -------------
Expand Down Expand Up @@ -111,12 +112,21 @@
/// Dispatches an event on all children (recursively). The event must not bubble. */
- (void)broadcastEvent:(SPEvent *)event;

/// Returns the bounds of the container's clipRect in the given coordinate space
/// (or nil if the container doesn't have a clipRect)
- (SPRectangle *)clipBoundsInSpace:(SPDisplayObject *)targetCoordinateSpace;

/// ----------------
/// @name Properties
/// ----------------

/// The number of children of this container.
@property (nonatomic, readonly) int numChildren;

/// The object's clip rect (or nil if there's no clipping)
/// *Note*: clip rects are axis aligned with the screen, so they
/// will *not* be rotated or skewed if the DisplayObjectContainer is.
@property (nonatomic, copy) SPRectangle *clipRect;


@end
50 changes: 47 additions & 3 deletions sparrow/src/Classes/SPDisplayObjectContainer.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ static void getChildEventListeners(SPDisplayObject *object, NSString *eventType,

@implementation SPDisplayObjectContainer

@synthesize clipRect = mClipRect;

- (id)init
{
#if DEBUG
Expand Down Expand Up @@ -196,21 +198,53 @@ - (int)numChildren
return [mChildren count];
}

- (SPRectangle *)clipBoundsInSpace:(SPDisplayObject *)targetCoordinateSpace
{
if (mClipRect == nil) return nil;

float minX = FLT_MAX, maxX = -FLT_MAX, minY = FLT_MAX, maxY = -FLT_MAX;
SPMatrix *transformationMatrix = [self transformationMatrixToSpace:targetCoordinateSpace];
SPPoint *point = [[SPPoint alloc] init];
for (int i=0; i<4; ++i)
{
switch (i)
{
case 0: point.x = mClipRect.left; point.y = mClipRect.top; break;
case 1: point.x = mClipRect.left; point.y = mClipRect.bottom; break;
case 2: point.x = mClipRect.right; point.y = mClipRect.top; break;
case 3: point.x = mClipRect.right; point.y = mClipRect.bottom; break;
}
SPPoint *transformedPoint = [transformationMatrix transformPoint:point];
float tfX = transformedPoint.x;
float tfY = transformedPoint.y;
minX = MIN(minX, tfX);
maxX = MAX(maxX, tfX);
minY = MIN(minY, tfY);
maxY = MAX(maxY, tfY);
}

[point release];

return [SPRectangle rectangleWithX:minX y:minY width:maxX-minX height:maxY-minY];
}

- (SPRectangle*)boundsInSpace:(SPDisplayObject*)targetCoordinateSpace
{
SPRectangle* bounds = nil;

int numChildren = [mChildren count];

if (numChildren == 0)
{
SPMatrix *transformationMatrix = [self transformationMatrixToSpace:targetCoordinateSpace];
SPPoint *point = [SPPoint pointWithX:self.x y:self.y];
SPPoint *transformedPoint = [transformationMatrix transformPoint:point];
return [SPRectangle rectangleWithX:transformedPoint.x y:transformedPoint.y
bounds = [SPRectangle rectangleWithX:transformedPoint.x y:transformedPoint.y
width:0.0f height:0.0f];
}
else if (numChildren == 1)
{
return [[mChildren objectAtIndex:0] boundsInSpace:targetCoordinateSpace];
bounds = [[mChildren objectAtIndex:0] boundsInSpace:targetCoordinateSpace];
}
else
{
Expand All @@ -223,15 +257,24 @@ - (SPRectangle*)boundsInSpace:(SPDisplayObject*)targetCoordinateSpace
minY = MIN(minY, childBounds.y);
maxY = MAX(maxY, childBounds.y + childBounds.height);
}
return [SPRectangle rectangleWithX:minX y:minY width:maxX-minX height:maxY-minY];
bounds = [SPRectangle rectangleWithX:minX y:minY width:maxX-minX height:maxY-minY];
}

// if we have a clip rect, intersect it with our bounds
if (mClipRect != nil)
bounds = [bounds intersectionWithRectangle:[self clipBoundsInSpace:targetCoordinateSpace]];

return bounds;
}

- (SPDisplayObject*)hitTestPoint:(SPPoint*)localPoint forTouch:(BOOL)isTouch
{
if (isTouch && (!self.visible || !self.touchable))
return nil;

if (mClipRect != nil && ![mClipRect containsPoint:localPoint])
return nil;

for (int i=[mChildren count]-1; i>=0; --i) // front to back!
{
SPDisplayObject *child = [mChildren objectAtIndex:i];
Expand Down Expand Up @@ -264,6 +307,7 @@ - (void)dealloc
// 'self' is becoming invalid; thus, we have to remove any references to it.
[mChildren makeObjectsPerformSelector:@selector(setParent:) withObject:nil];
[mChildren release];
[mClipRect release];
[super dealloc];
}

Expand Down
10 changes: 10 additions & 0 deletions sparrow/src/Classes/SPRenderSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

@class SPTexture;
@class SPDisplayObject;
@class SPRectangle;

/** ------------------------------------------------------------------------------------------------

Expand All @@ -31,6 +32,8 @@
@private
uint mBoundTextureID;
BOOL mPremultipliedAlpha;
NSMutableArray *mClipRectStack;
BOOL mScissorTestEnabled;
}

/// -------------
Expand All @@ -43,6 +46,13 @@
/// Converts color and alpha into the format needed by OpenGL. Premultiplies alpha depending on state.
- (uint)convertColor:(uint)color alpha:(float)alpha;

/// Pushes a clipping rectangle to the stack, intersecting it with the last pushed clipRect.
/// Returns the pushed rectangle.
- (SPRectangle *)pushClipRect:(SPRectangle *)clipRect;

/// Pops the last clipping rectangle that was pushed to the stack.
- (void)popClipRect;

/// Resets texture binding and alpha settings.
- (void)reset;

Expand Down
66 changes: 66 additions & 0 deletions sparrow/src/Classes/SPRenderSupport.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,18 @@
#import "SPDisplayObject.h"
#import "SPTexture.h"
#import "SPMacros.h"
#import "SPRectangle.h"
#import "SPStage.h"

#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>


@interface SPRenderSupport ()
- (void)updateClipping;
@end

@implementation SPRenderSupport

@synthesize usingPremultipliedAlpha = mPremultipliedAlpha;
Expand All @@ -36,6 +43,15 @@ - (void)reset
mBoundTextureID = UINT_MAX;
mPremultipliedAlpha = YES;
[self bindTexture:nil];
[mClipRectStack release];
mClipRectStack = nil;
[self updateClipping];
}

- (void)dealloc
{
[mClipRectStack release];
[super dealloc];
}

- (void)bindTexture:(SPTexture *)texture
Expand All @@ -61,6 +77,56 @@ - (uint)convertColor:(uint)color alpha:(float)alpha
return [SPRenderSupport convertColor:color alpha:alpha premultiplyAlpha:mPremultipliedAlpha];
}

- (void)updateClipping
{
SPRectangle *clip = [mClipRectStack lastObject];
if (clip != nil)
{
if (!mScissorTestEnabled)
{
glEnable(GL_SCISSOR_TEST);
mScissorTestEnabled = YES;
}
float scaleFactor = [SPStage contentScaleFactor];
float stageHeight = SPStage.mainStage.height;

glScissor(clip.x*scaleFactor,
(stageHeight-clip.y-clip.height)*scaleFactor,
clip.width*scaleFactor,
clip.height*scaleFactor);

}
else if (mScissorTestEnabled)
{
glDisable(GL_SCISSOR_TEST);
mScissorTestEnabled = NO;
}
}

- (SPRectangle *)pushClipRect:(SPRectangle *)clipRect
{
if (mClipRectStack == nil)
mClipRectStack = [[NSMutableArray alloc] init];
else if (mClipRectStack.count > 0)
{
// intersect with the last pushed clipRect
clipRect = [clipRect intersectionWithRectangle:[mClipRectStack lastObject]];
}

[mClipRectStack addObject:clipRect];
[self updateClipping];

// return the intersected clipRect so callers can skip draw calls if the clipping
// bounds are empty
return clipRect;
}

- (void)popClipRect
{
[mClipRectStack removeLastObject];
[self updateClipping];
}

+ (uint)convertColor:(uint)color alpha:(float)alpha premultiplyAlpha:(BOOL)pma
{
if (pma)
Expand Down
15 changes: 15 additions & 0 deletions sparrow/src/Classes/SPRendering.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ @implementation SPDisplayObjectContainer (Rendering)

- (void)render:(SPRenderSupport *)support
{
if (mClipRect != nil)
{
SPRectangle *clip = [support pushClipRect:[self clipBoundsInSpace:self.stage]];
// Don't bother rendering our children if our clipping bounds
// are empty
if (clip.isEmpty)
{
[support popClipRect];
return;
}
}

float alpha = self.alpha;

for (SPDisplayObject *child in mChildren)
Expand All @@ -62,6 +74,9 @@ - (void)render:(SPRenderSupport *)support
glPopMatrix();
}
}

if (mClipRect != nil)
[support popClipRect];
}

@end
Expand Down