Skip to content

Commit

Permalink
Add Sprite.getBounds.
Browse files Browse the repository at this point in the history
  • Loading branch information
aduros committed Nov 4, 2012
1 parent f687f90 commit dd4269d
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 15 deletions.
74 changes: 74 additions & 0 deletions src/flambe/display/Sprite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import flambe.input.PointerEvent;
import flambe.math.FMath;
import flambe.math.Matrix;
import flambe.math.Point;
import flambe.math.Rectangle;
import flambe.scene.Director;
import flambe.util.Signal1;
import flambe.util.Value;
Expand Down Expand Up @@ -157,6 +158,26 @@ class Sprite extends Component
return (sprite != null && sprite.containsLocal(x, y)) ? sprite : null;
}

/**
* Calculate the bounding box of an entity hierarchy. Returns the smallest rectangle in local
* coordinates that fully encloses all child sprites.
*/
public static function getBounds (entity :Entity, ?result :Rectangle) :Rectangle
{
if (result == null) {
result = new Rectangle();
}

// The width and height of this rectangle are hijacked to store the bottom right corner
result.set(FMath.FLOAT_MAX, FMath.FLOAT_MAX, FMath.FLOAT_MIN, FMath.FLOAT_MIN);
getBoundsImpl(entity, null, result);

// Convert back to a true width and height
result.width -= result.x;
result.height -= result.y;
return result;
}

/**
* The "natural" width of this sprite, without any transformations being applied. Used for hit
* testing.
Expand Down Expand Up @@ -381,6 +402,59 @@ class Sprite extends Component
return pointerEnabled;
}

private static function getBoundsImpl (entity :Entity, matrix :Matrix, result :Rectangle)
{
var sprite = entity.get(Sprite);
if (sprite != null) {
matrix = (matrix != null)
? Matrix.multiply(matrix, sprite.getLocalMatrix()) // Allocation!
: sprite.getLocalMatrix();

// Extend the rectangle out to fit this sprite
var width = sprite.getNaturalWidth(), height = sprite.getNaturalHeight();
extendRect(matrix, 0, 0, result);
extendRect(matrix, width, 0, result);
extendRect(matrix, width, height, result);
extendRect(matrix, 0, height, result);
}

// Recurse into all visible director scenes
var director = entity.get(Director);
if (director != null) {
var scenes = director.visibleScenes;
var ii = 0, ll = scenes.length;
while (ii < ll) {
getBoundsImpl(scenes[ii], matrix, result);
++ii;
}
}

// Recurse into all children
var children = entity._internal_children;
var ii = 0, ll = children.length;
while (ii < ll) {
var child = children[ii];
if (child != null) {
getBoundsImpl(child, matrix, result);
}
++ii;
}
}

private static function extendRect (matrix :Matrix, x :Float, y :Float, rect :Rectangle)
{
var p = matrix.transform(x, y, _scratchPoint);
x = p.x;
y = p.y;

// The width and height of the rectangle are treated like the bottom right point, rather
// than a true width and height offset
if (x < rect.x) rect.x = x;
if (y < rect.y) rect.y = y;
if (x > rect.width) rect.width = x;
if (y > rect.height) rect.height = y;
}

private static var _scratchPoint = new Point();

// Various flags used by Sprite and subclasses
Expand Down
29 changes: 29 additions & 0 deletions src/flambe/math/Rectangle.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Flambe - Rapid game development
// https://github.com/aduros/flambe/blob/master/LICENSE.txt

package flambe.math;

/**
* A 2D rectangle.
*/
class Rectangle
{
public var x :Float;
public var y :Float;
public var width :Float;
public var height :Float;

public function new (x :Float = 0, y :Float = 0, width :Float = 0, height :Float = 0)
{
set(x, y, width, height);
}

public function set (x :Float, y :Float, width :Float, height :Float)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
12 changes: 3 additions & 9 deletions src/flambe/swf/BitmapSprite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,13 @@ class BitmapSprite extends Sprite
{
super();
this.symbol = symbol;
anchorX._ = symbol.anchorX;
anchorY._ = symbol.anchorY;
}

override public function draw (ctx :DrawingContext)
{
ctx.drawSubImage(symbol.atlas, -symbol.anchorX, -symbol.anchorY,
symbol.x, symbol.y, symbol.width, symbol.height);
}

override public function containsLocal (localX :Float, localY :Float)
{
// We can't set the _anchorX/Y properties, since they're modified by LayerAnimator, so
// instead they have to be handled specially when drawing and hit testing
return super.containsLocal(localX+symbol.anchorX, localY+symbol.anchorY);
ctx.drawSubImage(symbol.atlas, 0, 0, symbol.x, symbol.y, symbol.width, symbol.height);
}

override public function getNaturalWidth () :Float
Expand Down
12 changes: 6 additions & 6 deletions src/flambe/swf/MovieSprite.hx
Original file line number Diff line number Diff line change
Expand Up @@ -260,19 +260,19 @@ private class LayerAnimator
alpha += (nextKf.alpha-alpha) * interp;
}

// From an identity matrix, append the skew
// From an identity matrix, append the translation, then skew
var matrix = sprite.getLocalMatrix();
var sinX = Math.sin(skewX), cosX = Math.cos(skewX);
var sinY = Math.sin(skewY), cosY = Math.cos(skewY);
matrix.set(cosY, sinY, -sinX, cosX, 0, 0);
matrix.set(cosY, sinY, -sinX, cosX, x, y);

// Append the scale
matrix.scale(scaleX, scaleY);

// Append the translation, and prepend the pivot
var pivotX = kf.pivotX, pivotY = kf.pivotY;
matrix.m02 = x - matrix.m00*pivotX - matrix.m01*pivotY;
matrix.m12 = y - matrix.m10*pivotY - matrix.m11*pivotY;
// Append the pivot
var pivotX = kf.pivotX + sprite.anchorX._;
var pivotY = kf.pivotY + sprite.anchorY._;
matrix.translate(-pivotX, -pivotY);

sprite.alpha._ = alpha;
}
Expand Down

0 comments on commit dd4269d

Please sign in to comment.