Skip to content
Draft
13 changes: 10 additions & 3 deletions flixel/FlxSprite.hx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package flixel;

import flixel.FlxBasic.IFlxBasic;
import flixel.FlxBasic;
import flixel.animation.FlxAnimationController;
import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.FlxFrame;
Expand All @@ -16,6 +16,7 @@ import flixel.util.FlxBitmapDataUtil;
import flixel.util.FlxColor;
import flixel.util.FlxDestroyUtil;
import flixel.util.FlxDirectionFlags;
import flixel.util.FlxSignal;
import openfl.display.BitmapData;
import openfl.display.BlendMode;
import openfl.geom.ColorTransform;
Expand Down Expand Up @@ -286,14 +287,16 @@ class FlxSprite extends FlxObject
* applied after the frame is clipped. Use `clipToWorldBounds` or `clipToViewBounds` to convert
*/
public var clipRect(default, set):FlxRect;
var _lastClipRect = FlxRect.get(Math.NaN);
var _lastClipRect:FlxRect;

/**
* GLSL shader for this sprite. Avoid changing it frequently as this is a costly operation.
* @since 4.1.0
*/
public var shader:FlxShader;


public final onFrameChange = new FlxSignal();

/**
* The actual frame used for sprite rendering
*/
Expand Down Expand Up @@ -406,6 +409,7 @@ class FlxSprite extends FlxObject
_halfSize = FlxPoint.get();
_matrix = new FlxMatrix();
_scaledOrigin = new FlxPoint();
_lastClipRect = FlxRect.get(Math.NaN);
}

/**
Expand All @@ -430,6 +434,7 @@ class FlxSprite extends FlxObject
_halfSize = FlxDestroyUtil.put(_halfSize);
_scaledOrigin = FlxDestroyUtil.put(_scaledOrigin);
_lastClipRect = FlxDestroyUtil.put(_lastClipRect);
onFrameChange.removeAll();

framePixels = FlxDestroyUtil.dispose(framePixels);

Expand Down Expand Up @@ -1855,6 +1860,8 @@ class FlxSprite extends FlxObject
if (clipRect != null)
_frame.clip(clipRect);

onFrameChange.dispatch();

return frame;
}

Expand Down
113 changes: 113 additions & 0 deletions flixel/graphics/FlxSliceSprite.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package flixel.graphics;

import flixel.graphics.frames.FlxFrame;
import flixel.graphics.frames.slice.FlxSpriteSlicer;
import flixel.math.FlxPoint;
import flixel.math.FlxRect;
import flixel.util.FlxDestroyUtil;

/**
* A `FlxSprite` with a 9-slice scaling. The `sliceRect` determines how to divide the 9 sections,
* and `displayWidth` and `displayHeight` determine how much the frame is stretched when drawn.
* If `sliceRect` is null, and the curret frame's `slice` is non-null, that slice rect is used
*
* **Note:** All of the slicing functionality is done via `FlxSpriteSlicer`, making it easy to
* add to any other class that extends FlxSprite
*
* @since 6.2.0
*/
class FlxSliceSprite extends flixel.FlxSprite
{
/**
* Controls the slicing of this sprite, `null` means no slicing
*/
public var sliceRect(get, set):Null<FlxRect>;
inline function get_sliceRect() { return slicer.rect; }
inline function set_sliceRect(value) { return slicer.rect = value; }

/**
* How large to draw the sliced sprite, relative to the `frameWidth`.
* If the value is `0` or less, the frameWidth is used
*/
public var displayWidth(get, set):Float;
inline function get_displayWidth() { return slicer.displayWidth; }
inline function set_displayWidth(value)
{
frameWidth = Std.int(value);
return slicer.displayWidth = value;
}

/**
* How large to draw the sliced sprite, relative to the `frameHeight`
* If the value is `0` or less, the frameWidth is used
*/
public var displayHeight(get, set):Float;
inline function get_displayHeight() { return slicer.displayHeight; }
inline function set_displayHeight(value)
{
frameHeight = Std.int(value);
return slicer.displayHeight = value;
}

/**
* The sprite's 9-slicing data
*/
var slicer(default, null):FlxSpriteSlicer;

override function initVars():Void
{
super.initVars();

slicer = new FlxSpriteSlicer(this);
}

override function destroy():Void
{
super.destroy();

slicer = FlxDestroyUtil.destroy(slicer);
}

override function updateHitbox()
{
return slicer.hasValidSlicing() ? slicer.updateTargetHitbox() : super.updateHitbox();
}

override function getGraphicBounds(?rect:FlxRect):FlxRect
{
return slicer.hasValidSlicing() ? slicer.getTargetGraphicBounds(rect) : super.getGraphicBounds(rect);
}

override function drawComplex(camera:FlxCamera):Void
{
if (slicer.hasValidSlicing())
slicer.drawComplex(camera);
else
super.drawComplex(camera);
}

override function viewToFrameHelper(viewX:Float, viewY:Float, ?camera:FlxCamera, ?result:FlxPoint):FlxPoint
{
result = super.viewToFrameHelper(viewX, viewY, camera, result);

if (slicer.hasValidSlicing())
slicer.displayToFrame(result, result);

return result;
}

override function worldToFrameSimpleHelper(worldX:Float, worldY:Float, ?result:FlxPoint):FlxPoint
{
result = super.worldToFrameSimpleHelper(worldX, worldY, result);

if (slicer.hasValidSlicing())
slicer.displayToFrame(result, result);

return result;
}

override function prepareComplexMatrix(matrix, frame, camera)
{
super.prepareComplexMatrix(matrix, frame, camera);
}
}
19 changes: 18 additions & 1 deletion flixel/graphics/atlas/AtlasBase.hx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,24 @@ typedef AtlasPos =
/**
* Rectangle struct use for atlas json parsing, { x:Float, y:Float, w:Float, h:Float }
*/
typedef AtlasRect = AtlasPos & AtlasSize;
@:forward
abstract AtlasRect(AtlasPos & AtlasSize) from AtlasPos & AtlasSize
{
public var l(get, never):Float; inline function get_l() return this.x;
public var r(get, never):Float; inline function get_r() return this.x + this.w;
public var t(get, never):Float; inline function get_t() return this.y;
public var b(get, never):Float; inline function get_b() return this.y + this.h;

overload public inline extern function toFlxRect(rect:flixel.math.FlxRect)
{
return rect.set(this.x, this.y, this.w, this.h);
}

overload public inline extern function toFlxRect()
{
return flixel.math.FlxRect.get(this.x, this.y, this.w, this.h);
}
}

typedef AtlasFrame =
{
Expand Down
58 changes: 53 additions & 5 deletions flixel/graphics/frames/FlxFrame.hx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package flixel.graphics.frames;

import flixel.graphics.FlxGraphic;
import flixel.graphics.frames.slice.FlxFrameSlices;
import flixel.graphics.frames.slice.FlxSliceSection;
import flixel.math.FlxMath;
import flixel.math.FlxMatrix;
import flixel.math.FlxPoint;
Expand Down Expand Up @@ -145,6 +147,16 @@ class FlxFrame implements IFlxDestroyable
/** Internal cache used to draw this frame **/
var blitMatrix:MatrixVector;

/**
* The 9-slice rect of this frame
*/
public var slice:FlxRect;

/**
* Internal helper for this frame's 9-slicing
*/
var sliceData:FlxFrameSlices;

public function new(parent:FlxGraphic, angle = FlxFrameAngle.ANGLE_0, flipX = false, flipY = false, duration = 0.0)
{
this.parent = parent;
Expand All @@ -161,11 +173,42 @@ class FlxFrame implements IFlxDestroyable
blitMatrix = new MatrixVector();
if (FlxG.renderTile)
tileMatrix = new MatrixVector();

sliceData = new FlxFrameSlices(this);
}

@:allow(flixel.graphics.frames.FlxFramesCollection)
@:allow(flixel.graphics.frames.FlxBitmapFont)
function cacheFrameMatrix():Void

/**
* Updates the internal helpers to prepare this frame for rendering.
* Called automaticaly in `copyTo`.
*/
public function updateCache()
{
if (slice == null && sliceData.rect != null)
sliceData.clear();
else if (slice != null && (sliceData.rect == null || sliceData.rect.equals(slice)))
sliceData.set(slice);

// TODO: Defer matrix stuff?
}

/**
* Fills the target frame sections with this frame's slice data, for rendering
* @param list
*/
public function initSliceSections(frames:FlxSliceSectionList<FlxFrame>)
{
if (slice != null)
{
for (section=>frame in frames)
sliceData.initSectionFrame(section, frame);
}
}

/**
* initializes internal data, used for rendering, usually called after creation
* @since 6.1.0
*/
public function cacheFrameMatrix():Void
{
blitMatrix.copyFrom(this, true);

Expand Down Expand Up @@ -768,7 +811,8 @@ class FlxFrame implements IFlxDestroyable
clone.angle = angle;
clone.frame = FlxDestroyUtil.put(clone.frame);
}


updateCache();
clone.offset.copyFrom(offset);
clone.flipX = flipX;
clone.flipY = flipY;
Expand All @@ -778,6 +822,9 @@ class FlxFrame implements IFlxDestroyable
clone.name = name;
clone.duration = duration;
clone.cacheFrameMatrix();
clone.slice = slice;
clone.sliceData.copyFrom(sliceData);

return clone;
}

Expand All @@ -789,6 +836,7 @@ class FlxFrame implements IFlxDestroyable
offset = FlxDestroyUtil.put(offset);
frame = FlxDestroyUtil.put(frame);
uv = FlxDestroyUtil.put(uv);
sliceData = FlxDestroyUtil.destroy(sliceData);
blitMatrix = null;
tileMatrix = null;
}
Expand Down
Loading
Loading