Last active
July 30, 2026 14:41
-
-
Save Geokureli/6b0c7cab38874fec6d2cef1d5d79288c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package flixel.graphics.frames.slice; | |
| import flixel.graphics.frames.FlxFrame; | |
| import flixel.graphics.frames.slice.FlxFrameSlices; | |
| import flixel.graphics.frames.slice.FlxSliceSection; | |
| import flixel.math.FlxRect; | |
| import flixel.util.FlxDestroyUtil; | |
| /** | |
| * Controls 9-slicing of FlxFrames, used by `FlxSliceSprite` or other | |
| * types that have a `FlxSpriteSlicer` | |
| * @since 6.1.0 | |
| */ | |
| class FlxFrameSlices implements IFlxDestroyable | |
| { | |
| /** | |
| * The 9-slicing of this frame | |
| */ | |
| public var rect(get, never):Null<FlxRect>; | |
| function get_rect() return sections != null ? sections[CC] : null; | |
| final parent:FlxFrame; | |
| var sections:Null<FlxSliceSectionList<FlxRect>> = null; | |
| public function new (parent:FlxFrame) | |
| { | |
| this.parent = parent; | |
| } | |
| public function destroy() | |
| { | |
| clear(); | |
| } | |
| public function copyFrom(slice:FlxFrameSlices) | |
| { | |
| clear(); | |
| if (slice.sections != null) | |
| sections = [for (rect in slice.sections) rect.clone()]; | |
| } | |
| /** | |
| * Clears any frame data of this frame slice | |
| */ | |
| public function clear() | |
| { | |
| if (sections == null) | |
| return; | |
| for (rect in sections) | |
| rect.put(); | |
| sections = null; | |
| } | |
| /** | |
| * Sets the slicing data of this frame slice | |
| */ | |
| public function set(rect:FlxRect) | |
| { | |
| clear(); | |
| sections = createSourceRects(rect, parent.frame); | |
| } | |
| /** | |
| * Initializes the given frame to match the desired section of this slice data | |
| * | |
| * @param section The section of the 9 slice | |
| * @param sub The frame to initialize | |
| */ | |
| public function initSectionFrame(section:FlxSliceSection, sub:FlxFrame) | |
| { | |
| parent.subFrameTo(sections[section], sub); | |
| } | |
| // @:arrayAccess | |
| public inline function getSection(index:FlxSliceSection) | |
| { | |
| return sections[index]; | |
| } | |
| public inline function iterator() | |
| { | |
| return sections.iterator(); | |
| } | |
| public inline function keys() | |
| { | |
| return sections.keys(); | |
| } | |
| public inline function keyValueIterator() | |
| { | |
| return sections.keyValueIterator(); | |
| } | |
| static function createSourceRects(rect:FlxRect, parentRect:FlxRect) | |
| { | |
| final sections:FlxSliceSectionList<FlxRect> = [for (i in FlxSliceSection) null]; | |
| final x = [0, rect.x, rect.right, parentRect.width]; | |
| final y = [0, rect.y, rect.bottom, parentRect.height]; | |
| rect.putWeak(); | |
| for (section in FlxSliceSection) | |
| { | |
| final col = section.column; | |
| final row = section.row; | |
| final sectionRect = FlxRect.get(); | |
| sectionRect.setBounds(x[col], y[row], x[col + 1], y[row + 1]); | |
| sections[section] = sectionRect; | |
| } | |
| return sections; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package flixel.graphics.frames.slice; | |
| import flixel.util.FlxBits; | |
| @:build(flixel.system.macros.FlxBitFlagMacro.buildBits()) | |
| enum abstract FlxSliceSection(Int) | |
| { | |
| var TL; var TC; var TR; | |
| var CL; var CC; var CR; | |
| var BL; var BC; var BR; | |
| static final LOG2 = Math.log(2); | |
| static inline var COLUMNS = 3; | |
| static inline var ROWS = 3; | |
| var index(get, never):Int; | |
| inline function get_index() return Std.int(Math.log(this) / LOG2); | |
| public var row(get, never):Int; | |
| inline function get_row() return Std.int(index / 3); | |
| public var column(get, never):Int; | |
| inline function get_column() return index % 3; | |
| } | |
| @:forward | |
| @:forward.new | |
| @:forward.static | |
| abstract FlxSliceSectionFlags(FlxBits<FlxSliceSection>) from FlxBits<FlxSliceSection> to FlxBits<FlxSliceSection> | |
| { | |
| public function toString() | |
| { | |
| final bits = []; | |
| for (bit in FlxSliceSection.iterator()) | |
| { | |
| if (this.has(bit)) | |
| bits.push(bit.toString()); | |
| } | |
| return bits.join(" | "); | |
| } | |
| @:op(A | B) static function or<T>(a:FlxSliceSectionFlags, b:FlxSliceSectionFlags):FlxSliceSectionFlags; | |
| @:commutative | |
| @:op(A | B) static function orBits<T>(a:FlxSliceSectionFlags, b:FlxSliceSection):FlxSliceSectionFlags; | |
| } | |
| @:access(flixel.graphics.frames.slice.FlxSliceSection) | |
| @:forward(length) | |
| @:forward.variance | |
| abstract FlxSliceSectionList<T>(Array<T>) from Array<T> | |
| { | |
| public function new(defaultValue:()->T) | |
| { | |
| this = [for (i in FlxSliceSection) defaultValue()]; | |
| } | |
| @:arrayAccess | |
| public inline function get(section:FlxSliceSection) | |
| { | |
| return this[intFromBit(section)]; | |
| } | |
| @:arrayAccess | |
| public inline function set(section:FlxSliceSection, value:T) | |
| { | |
| return this[intFromBit(section)] = value; | |
| } | |
| public inline function iterator() | |
| { | |
| return this.iterator(); | |
| } | |
| public inline function keys() | |
| { | |
| return FlxSliceSection.iterator(); | |
| } | |
| public inline function keyValueIterator() | |
| { | |
| return new SectionListKeyValueIterator(this); | |
| } | |
| static inline function intFromBit(bit:FlxSliceSection) | |
| { | |
| return bit.index; | |
| } | |
| } | |
| class SectionListKeyValueIterator<T> | |
| { | |
| final list:FlxSliceSectionList<T>; | |
| var iter = FlxSliceSection.iterator(); | |
| public inline function new(list) | |
| { | |
| this.list = list; | |
| } | |
| public inline function hasNext():Bool | |
| { | |
| return iter.hasNext(); | |
| } | |
| public inline function next() | |
| { | |
| final key:FlxSliceSection = iter.next(); | |
| final value = list[key]; | |
| return { value: value, key: key }; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package flixel.graphics.frames.slice; | |
| import flixel.graphics.frames.FlxFrame; | |
| import flixel.graphics.frames.slice.FlxFrameSlices; | |
| import flixel.graphics.frames.slice.FlxSliceSection; | |
| import flixel.math.FlxMath; | |
| import flixel.math.FlxMatrix; | |
| import flixel.math.FlxPoint; | |
| import flixel.math.FlxRect; | |
| import flixel.util.FlxDestroyUtil; | |
| /** | |
| * Applies 9-slicing to a FlxSprite, for an example of use this, look at `FlxSliceSprite` | |
| * @since 6.2.0 | |
| */ | |
| class FlxSpriteSlicer implements IFlxDestroyable | |
| { | |
| final target:FlxSprite; | |
| var targetFrame(get, never):FlxFrame; | |
| inline function get_targetFrame() @:privateAccess return target._frame; | |
| var targetFrameWidth(get, never):Int; | |
| inline function get_targetFrameWidth() @:privateAccess return Std.int(target._frame.sourceSize.x); | |
| var targetFrameHeight(get, never):Int; | |
| inline function get_targetFrameHeight() @:privateAccess return Std.int(target._frame.sourceSize.y); | |
| /** | |
| * The 9-slicing rect to apply to the target where the top, left, bottom and right | |
| * Determine where to slice the current frame. A value of `null` means "no slicing", | |
| * unless the current frame's `slice` rect is defined, then that rect is used. | |
| */ | |
| public var rect:Null<FlxRect> = null; | |
| /** | |
| * The current, active slicing rect, used internally to detect changes to `rect` | |
| */ | |
| var currentRect = new FlxRect(Math.NaN); | |
| var frameDirty = false; | |
| /** | |
| * Internal frames used to draw each of the 9 sections | |
| */ | |
| var subframes:FlxSliceSectionList<FlxFrame>; | |
| /** | |
| * Internal rects that define where each section will be drawn | |
| */ | |
| var destRects:FlxSliceSectionList<FlxRect>; | |
| /** | |
| * Whether to stretch or tile each section, only affects edges and the center | |
| */ | |
| final drawModes = new FlxSliceSectionList<FlxSliceDisplayMode>(()->STRETCH); | |
| /** | |
| * How large to draw the sliced sprite | |
| */ | |
| public var displayWidth:Float = 0.0; | |
| /** | |
| * How large to draw the sliced sprite | |
| */ | |
| public var displayHeight:Float = 0.0; | |
| var lastDisplayWidth:Float = 0.0; | |
| var lastDisplayHeight:Float = 0.0; | |
| public function new (target:FlxSprite) | |
| { | |
| this.target = target; | |
| target.onFrameChange.add(()->frameDirty = true); | |
| subframes = [for (section in FlxSliceSection) new FlxFrame(null)]; | |
| } | |
| public function destroy() | |
| { | |
| currentRect = FlxDestroyUtil.put(currentRect); | |
| FlxDestroyUtil.putArray(cast destRects); | |
| FlxDestroyUtil.destroyArray(cast subframes); | |
| destRects = null; | |
| subframes = null; | |
| } | |
| /** | |
| * Whether this slicer is needed given the current slice rect and desired display size | |
| */ | |
| public function hasValidSlicing() | |
| { | |
| // The frame before the clipRect was applied, compared to targetFrame which is clipped | |
| final rect = target.frame.frame; | |
| return rect != null | |
| && displayWidth > 0 && displayHeight > 0 | |
| && (displayWidth != rect.width || displayHeight != rect.height); | |
| } | |
| public function setDisplaySize(width:Float, height:Float) | |
| { | |
| displayWidth = width; | |
| displayHeight = height; | |
| } | |
| public function setScaledDisplaySize(width:Float, height:Float) | |
| { | |
| displayWidth = width / target.scale.x; | |
| displayHeight = height / target.scale.y; | |
| } | |
| function getValidRect(rect:FlxRect) | |
| { | |
| return clipValidRect(rect.clone()); | |
| } | |
| function clipValidRect(rect:FlxRect) | |
| { | |
| rect.left = FlxMath.bound(rect.left , 0, targetFrameWidth ); | |
| rect.top = FlxMath.bound(rect.top , 0, targetFrameHeight); | |
| rect.right = FlxMath.bound(rect.right , rect.left, targetFrameWidth ); | |
| rect.bottom = FlxMath.bound(rect.bottom, rect.top , targetFrameHeight); | |
| return rect; | |
| } | |
| /** | |
| * similar to sprite.updateHitbox() but accounts for the slicer's displaySize | |
| */ | |
| public function updateTargetHitbox() | |
| { | |
| target.width = Math.abs(target.scale.x) * displayWidth; | |
| target.height = Math.abs(target.scale.y) * displayHeight; | |
| target.offset.set(-0.5 * (target.width - displayWidth), -0.5 * (target.height - displayHeight)); | |
| target.centerOrigin(); | |
| } | |
| /** | |
| * similar to sprite.updategetGraphicBoundsHitbox() but accounts for the slicer's displaySize | |
| */ | |
| public function getTargetGraphicBounds(?rect:FlxRect):FlxRect | |
| { | |
| if (!hasValidSlicing()) | |
| return target.getGraphicBounds(rect); | |
| if (rect == null) | |
| rect = FlxRect.get(); | |
| rect.set(target.x, target.y); | |
| if (target.pixelPerfectPosition) | |
| rect.floor(); | |
| updateCache(); | |
| final sliceOrigin = FlxPoint.get(frameToDisplayXUnsafe(target.origin.x), frameToDisplayYUnsafe(target.origin.y)); | |
| final scaledOrigin = FlxPoint.get(sliceOrigin.x * target.scale.x, sliceOrigin.y * target.scale.y); | |
| rect.x += sliceOrigin.x - target.offset.x - scaledOrigin.x; | |
| rect.y += sliceOrigin.y - target.offset.y - scaledOrigin.y; | |
| final frameWidth = displayWidth > 0 ? displayWidth : targetFrameWidth; | |
| final frameHeight = displayHeight > 0 ? displayHeight : targetFrameHeight; | |
| rect.setSize(frameWidth * target.scale.x, frameHeight * target.scale.y); | |
| if (target.angle % 360 != 0) | |
| rect.getRotatedBounds(target.angle, scaledOrigin, rect); | |
| scaledOrigin.put(); | |
| sliceOrigin.put(); | |
| return rect; | |
| } | |
| /** | |
| * Draws the target according to the slice rect | |
| * @param camera The camera to which to draw | |
| */ | |
| public function drawComplex(camera:FlxCamera) | |
| { | |
| updateCache(); | |
| for (section in FlxSliceSection) | |
| { | |
| drawSectionComplex(section, camera); | |
| } | |
| } | |
| /** | |
| * Calls `drawFunc` with every valid section | |
| * @param drawFunc A custom drawing function | |
| */ | |
| public function drawCustom(drawFunc:(FlxFrame, FlxRect)->Void) | |
| { | |
| updateCache(); | |
| for (section=>frame in subframes) | |
| { | |
| if (frame.frame.width > 0 && frame.frame.height > 0) | |
| drawFunc(frame, destRects[section]); | |
| } | |
| } | |
| static final globalDrawMatrix = new FlxMatrix(); | |
| @:access(flixel.FlxSprite) | |
| function drawSectionComplex(section:FlxSliceSection, camera:FlxCamera):Void | |
| { | |
| final frame = subframes[section]; | |
| if (frame.frame.width <= 0 || frame.frame.height <= 0) | |
| return; | |
| final rect = destRects[section]; | |
| final mode = drawModes[section]; | |
| final matrix = globalDrawMatrix; | |
| frame.prepareMatrix(matrix, FlxFrameAngle.ANGLE_0, target.checkFlipX(), target.checkFlipY()); | |
| if (target.clipRect != null) | |
| matrix.translate(-Math.max(0, target.clipRect.x), -Math.max(0, target.clipRect.y)); | |
| switch mode | |
| { | |
| case STRETCH: | |
| matrix.scale(rect.width / frame.frame.width, rect.height / frame.frame.height); | |
| case REPEAT: | |
| throw "REPEAT is not implemented, yet"; | |
| // TODO: draw one quad with repeat enabled? | |
| } | |
| matrix.translate(-target.origin.x, -target.origin.y); | |
| matrix.translate(rect.x, rect.y); | |
| matrix.scale(target.scale.x, target.scale.y); | |
| if (target.bakedRotationAngle <= 0) | |
| { | |
| target.updateTrig(); | |
| if (target.angle != 0) | |
| matrix.rotateWithTrig(target._cosAngle, target._sinAngle); | |
| } | |
| final point = target.getScreenPosition(camera).subtract(target.offset); | |
| point.add(target.origin.x, target.origin.y); | |
| matrix.translate(point.x, point.y); | |
| point.put(); | |
| if (target.isPixelPerfectRender(camera)) | |
| { | |
| matrix.tx = Math.floor(matrix.tx); | |
| matrix.ty = Math.floor(matrix.ty); | |
| } | |
| camera.drawPixels(frame, target.framePixels, matrix, target.colorTransform, target.blend, target.antialiasing, target.shader); | |
| } | |
| function updateCache() | |
| { | |
| checkSourceRects(); | |
| checkDestRects(); | |
| } | |
| function checkSourceRects() | |
| { | |
| if (rect != null) | |
| { | |
| if (rectsNotMatch(rect, currentRect) || frameDirty) | |
| updateSourceRects(rect); | |
| } | |
| else | |
| { | |
| currentRect.set(Math.NaN); | |
| } | |
| } | |
| function updateSourceRects(rect:FlxRect) | |
| { | |
| currentRect.copyFrom(rect); | |
| frameDirty = false; | |
| final srcBounds = FlxRect.get(0, 0, targetFrameWidth, targetFrameHeight); | |
| final srcSlice = getValidRect(rect); | |
| if (target.clipRect != null) | |
| { | |
| srcBounds.copyFrom(target.clipRect); | |
| clipValidRect(srcBounds); | |
| clipToSmart(srcSlice, srcBounds); | |
| } | |
| final x = [srcBounds.x, srcSlice.x, srcSlice.right, srcBounds.right]; | |
| final y = [srcBounds.y, srcSlice.y, srcSlice.bottom, srcBounds.bottom]; | |
| srcBounds.put(); | |
| srcSlice.put(); | |
| final rectHelper = FlxRect.get(); | |
| for (section in FlxSliceSection) | |
| { | |
| final col = section.column; | |
| final row = section.row; | |
| final sub = subframes[section]; | |
| rectHelper.setBounds(x[col], y[row], x[col + 1], y[row + 1]); | |
| targetFrame.subFrameTo(rectHelper, sub); | |
| sub.offset.copyFrom(targetFrame.offset); | |
| sub.cacheFrameMatrix(); | |
| } | |
| rectHelper.put(); | |
| updateDestRects(); | |
| } | |
| function updateSourceRectsFromFrame(frame:FlxFrame) | |
| { | |
| currentRect.copyFrom(frame.slice); | |
| frameDirty = false; | |
| frame.initSliceSections(subframes); | |
| updateDestRects(); | |
| } | |
| function checkDestRects() | |
| { | |
| if (displayWidth != lastDisplayWidth || displayHeight != lastDisplayHeight) | |
| { | |
| lastDisplayWidth = displayWidth; | |
| lastDisplayHeight = displayHeight; | |
| if (displayWidth > 0 && displayHeight > 0) | |
| updateDestRects(); | |
| } | |
| } | |
| function updateDestRects() | |
| { | |
| final srcBounds = FlxRect.get(0, 0, targetFrameWidth, targetFrameHeight); | |
| final srcSlice = getValidRect(currentRect); | |
| if (target.clipRect != null) | |
| { | |
| srcBounds.copyFrom(target.clipRect); | |
| clipValidRect(srcBounds); | |
| clipToSmart(srcSlice, srcBounds); | |
| } | |
| final x = | |
| [ frameToDisplayXUnsafe(srcBounds.x) | |
| , frameToDisplayXUnsafe(srcSlice.x) | |
| , frameToDisplayXUnsafe(srcSlice.right) | |
| , frameToDisplayXUnsafe(srcBounds.right) | |
| ]; | |
| final y = | |
| [ frameToDisplayYUnsafe(srcBounds.y) | |
| , frameToDisplayYUnsafe(srcSlice.y) | |
| , frameToDisplayYUnsafe(srcSlice.bottom) | |
| , frameToDisplayYUnsafe(srcBounds.bottom) | |
| ]; | |
| srcBounds.put(); | |
| srcSlice.put(); | |
| FlxDestroyUtil.putArray(cast destRects); | |
| destRects = []; | |
| for (section in FlxSliceSection) | |
| { | |
| final col = section.column; | |
| final row = section.row; | |
| destRects[section] = FlxRect.get().setBounds(x[col], y[row], x[col + 1], y[row + 1]); | |
| // destRects[section].x += section.column - 1; | |
| // destRects[section].y += section.row - 1; | |
| } | |
| } | |
| /** | |
| * Transforms the given position from the original frame to where it will be | |
| * drawn, relative to the target's position | |
| * @param x A position on the original frame | |
| */ | |
| public function frameToDisplayX(x:Float) | |
| { | |
| return hasValidSlicing() ? frameToDisplayXUnsafe(x) : x; | |
| } | |
| /** | |
| * Transforms the given position from the original frame to where it will be | |
| * drawn, relative to the target's position | |
| * @param y A position on the original frame | |
| */ | |
| public function frameToDisplayY(y:Float) | |
| { | |
| return hasValidSlicing() ? frameToDisplayYUnsafe(y) : y; | |
| } | |
| function frameToDisplayXUnsafe(x:Float) | |
| { | |
| if (x < currentRect.x) | |
| return x; | |
| if (x > currentRect.right) | |
| return displayWidth - targetFrameWidth + x; | |
| final middleScaleX = (displayWidth - targetFrameWidth + currentRect.width) / currentRect.width; | |
| return currentRect.x + (x - currentRect.x) * middleScaleX; | |
| } | |
| function frameToDisplayYUnsafe(y:Float) | |
| { | |
| if (y < currentRect.y) | |
| return y; | |
| if (y > currentRect.bottom) | |
| return displayHeight - targetFrameHeight + y; | |
| final middleScaleY = (displayHeight - targetFrameHeight + currentRect.height) / currentRect.height; | |
| return currentRect.y + (y - currentRect.y) * middleScaleY; | |
| } | |
| overload public inline extern function displayToFrame(display:FlxPoint, ?result:FlxPoint):FlxPoint | |
| { | |
| return displayToFrameHelper(display.x, display.y, result); | |
| } | |
| overload public inline extern function displayToFrame(displayX:Float, displayY:Float, ?result:FlxPoint):FlxPoint | |
| { | |
| return displayToFrameHelper(displayX, displayY, result); | |
| } | |
| function displayToFrameHelper(displayX:Float, displayY:Float, ?result:FlxPoint):FlxPoint | |
| { | |
| if (hasValidSlicing()) | |
| { | |
| result.x = displayToFrameXUnsafe(displayX); | |
| result.y = displayToFrameYUnsafe(displayY); | |
| } | |
| else | |
| { | |
| result.x = displayX; | |
| result.y = displayY; | |
| } | |
| return result; | |
| } | |
| /** | |
| * Transforms the given position from the stretched display to the original frame | |
| * @param x A position on the stretched display | |
| */ | |
| public function displayToFrameX(x:Float) | |
| { | |
| return hasValidSlicing() ? displayToFrameXUnsafe(x) : x; | |
| } | |
| /** | |
| * Transforms the given position from the stretched display to the original frame | |
| * @param y A position on the stretched display | |
| */ | |
| public function displayToFrameY(y:Float) | |
| { | |
| return hasValidSlicing() ? displayToFrameYUnsafe(y) : y; | |
| } | |
| function displayToFrameXUnsafe(x:Float) | |
| { | |
| if (x < rect.x) | |
| return x; | |
| if (x > displayWidth - (targetFrameWidth - rect.right)) | |
| return x - displayWidth + targetFrameWidth; | |
| final middleScaleX = (displayWidth - targetFrameWidth + rect.width) / rect.width; | |
| return (x - rect.x) / middleScaleX + rect.x; | |
| } | |
| function displayToFrameYUnsafe(y:Float) | |
| { | |
| if (y < rect.y) | |
| return y; | |
| if (y > displayHeight - (targetFrameHeight - rect.bottom)) | |
| return y - displayHeight + targetFrameHeight; | |
| final middleScaleY = (displayHeight - targetFrameHeight + rect.height) / rect.height; | |
| return (y - rect.y) / middleScaleY + rect.y; | |
| } | |
| /** | |
| * Similar to clipTo but the result will always be inside b, even if there is no overlap | |
| * @param a The rect to clip | |
| * @param b The rect to which `a` is clipped | |
| */ | |
| function clipToSmart(a:FlxRect, b:FlxRect) | |
| { | |
| if (a.left > b.right) | |
| { | |
| a.x = b.right; | |
| a.width = 0; | |
| } | |
| else if (a.right < b.left) | |
| { | |
| a.x = b.left; | |
| a.width = 0; | |
| } | |
| else | |
| { | |
| a.left = a.left < b.left ? b.left : a.left; | |
| a.right = a.right > b.right ? b.right : a.right; | |
| } | |
| if (a.top > b.bottom) | |
| { | |
| a.y = b.bottom; | |
| a.height = 0; | |
| } | |
| else if (a.bottom < b.top) | |
| { | |
| a.y = b.top; | |
| a.height = 0; | |
| } | |
| else | |
| { | |
| a.top = a.top < b.y ? b.y : a.y; | |
| a.bottom = a.bottom > b.bottom ? b.bottom : a.bottom; | |
| } | |
| return a; | |
| } | |
| static function rectsMatch(a:FlxRect, b:FlxRect) | |
| { | |
| return (a == null && b == null) || (a != null && b != null && a.equals(b)); | |
| } | |
| static function rectsNotMatch(a:FlxRect, b:FlxRect) | |
| { | |
| return !rectsMatch(a, b); | |
| } | |
| } | |
| enum abstract FlxSliceDisplayMode(Int) | |
| { | |
| /** | |
| * The pattern will repeat to fit the destinatio | |
| */ | |
| var REPEAT; | |
| /** | |
| * The pattern will stretch to fit the destinatio | |
| */ | |
| var STRETCH; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment