Skip to content

Commit c7bf42a

Browse files
authored
Improve FlxBitmapText rendering when using renderTile with clipRect (#3395)
* check cliprect changes earlier * trigger CI again * optional alpha arg * add various colorTransform helpers * add FlxFrame.overlaps * make FlxFrame constructor public * add CharList and cleanup text rendering/iteration * add forEachBorder helper * add rect.contains, frame.contains and frame.isContained * improve draw perf by avoiding unnecessary frame clipping * doc plus optional alpha * unit tests * doc * use MatrixVector to cache draw matrices * resuse a frame instance for tile drawing * test more optional args * remove rgb optional args
1 parent 47e69f8 commit c7bf42a

File tree

9 files changed

+902
-308
lines changed

9 files changed

+902
-308
lines changed

flixel/graphics/frames/FlxFrame.hx

Lines changed: 184 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,13 @@ class FlxFrame implements IFlxDestroyable
139139
*/
140140
public var type:FlxFrameType;
141141

142-
var tileMatrix:Vector<Float>;
143-
144-
var blitMatrix:Vector<Float>;
142+
/** Internal cache used to draw this frame **/
143+
var tileMatrix:MatrixVector;
144+
145+
/** Internal cache used to draw this frame **/
146+
var blitMatrix:MatrixVector;
145147

146-
@:allow(flixel.graphics.FlxGraphic)
147-
@:allow(flixel.graphics.frames.FlxFramesCollection)
148-
function new(parent:FlxGraphic, angle = FlxFrameAngle.ANGLE_0, flipX = false, flipY = false, duration = 0.0)
148+
public function new(parent:FlxGraphic, angle = FlxFrameAngle.ANGLE_0, flipX = false, flipY = false, duration = 0.0)
149149
{
150150
this.parent = parent;
151151
this.angle = angle;
@@ -158,35 +158,21 @@ class FlxFrame implements IFlxDestroyable
158158
sourceSize = FlxPoint.get();
159159
offset = FlxPoint.get();
160160

161-
blitMatrix = new Vector<Float>(6);
161+
blitMatrix = new MatrixVector();
162162
if (FlxG.renderTile)
163-
tileMatrix = new Vector<Float>(6);
163+
tileMatrix = new MatrixVector();
164164
}
165165

166166
@:allow(flixel.graphics.frames.FlxFramesCollection)
167167
@:allow(flixel.graphics.frames.FlxBitmapFont)
168168
function cacheFrameMatrix():Void
169169
{
170-
prepareBlitMatrix(_matrix, true);
171-
blitMatrix[0] = _matrix.a;
172-
blitMatrix[1] = _matrix.b;
173-
blitMatrix[2] = _matrix.c;
174-
blitMatrix[3] = _matrix.d;
175-
blitMatrix[4] = _matrix.tx;
176-
blitMatrix[5] = _matrix.ty;
170+
blitMatrix.copyFrom(this, true);
177171

178172
if (FlxG.renderTile)
179-
{
180-
prepareBlitMatrix(_matrix, false);
181-
tileMatrix[0] = _matrix.a;
182-
tileMatrix[1] = _matrix.b;
183-
tileMatrix[2] = _matrix.c;
184-
tileMatrix[3] = _matrix.d;
185-
tileMatrix[4] = _matrix.tx;
186-
tileMatrix[5] = _matrix.ty;
187-
}
173+
tileMatrix.copyFrom(this, false);
188174
}
189-
175+
190176
/**
191177
* Applies frame rotation to the specified matrix, which should be used for tiling or blitting.
192178
* Required for rotated frame support.
@@ -195,7 +181,7 @@ class FlxFrame implements IFlxDestroyable
195181
* @param blit Whether specified matrix will be used for blitting or for tile rendering.
196182
* @return Transformed matrix.
197183
*/
198-
inline function prepareBlitMatrix(mat:FlxMatrix, blit:Bool = true):FlxMatrix
184+
inline function prepareBlitMatrix(mat:FlxMatrix, blit = true):FlxMatrix
199185
{
200186
mat.identity();
201187

@@ -218,7 +204,7 @@ class FlxFrame implements IFlxDestroyable
218204
}
219205

220206
/**
221-
* Rotates and flips matrix. This method expects matrix which was prepared by `prepareBlitMatrix()`.
207+
* Rotates and flips matrix. This method expects matrix which was prepared by `MatrixVector.copyTo()`.
222208
* Internal use only.
223209
*
224210
* @param mat Matrix to transform
@@ -278,7 +264,7 @@ class FlxFrame implements IFlxDestroyable
278264
*/
279265
function prepareTransformedBlitMatrix(mat:FlxMatrix, rotation:FlxFrameAngle = FlxFrameAngle.ANGLE_0, flipX:Bool = false, flipY:Bool = false):FlxMatrix
280266
{
281-
mat = fillBlitMatrix(mat);
267+
blitMatrix.copyTo(mat);
282268
return rotateAndFlip(mat, rotation, flipX, flipY);
283269
}
284270

@@ -299,12 +285,7 @@ class FlxFrame implements IFlxDestroyable
299285
return mat;
300286
}
301287

302-
mat.a = tileMatrix[0];
303-
mat.b = tileMatrix[1];
304-
mat.c = tileMatrix[2];
305-
mat.d = tileMatrix[3];
306-
mat.tx = tileMatrix[4];
307-
mat.ty = tileMatrix[5];
288+
tileMatrix.copyTo(mat);
308289

309290
var doFlipX = flipX != this.flipX;
310291
var doFlipY = flipY != this.flipY;
@@ -315,17 +296,6 @@ class FlxFrame implements IFlxDestroyable
315296
return rotateAndFlip(mat, rotation, doFlipX, doFlipY);
316297
}
317298

318-
inline function fillBlitMatrix(mat:FlxMatrix):FlxMatrix
319-
{
320-
mat.a = blitMatrix[0];
321-
mat.b = blitMatrix[1];
322-
mat.c = blitMatrix[2];
323-
mat.d = blitMatrix[3];
324-
mat.tx = blitMatrix[4];
325-
mat.ty = blitMatrix[5];
326-
return mat;
327-
}
328-
329299
/**
330300
* Draws frame on specified `BitmapData` object.
331301
*
@@ -355,7 +325,7 @@ class FlxFrame implements IFlxDestroyable
355325
}
356326
else
357327
{
358-
fillBlitMatrix(_matrix);
328+
blitMatrix.copyTo(_matrix);
359329
if (point != null)
360330
_matrix.translate(point.x, point.y);
361331

@@ -584,7 +554,53 @@ class FlxFrame implements IFlxDestroyable
584554
copyTo(clippedFrame);
585555
return clippedFrame.clip(rect);
586556
}
587-
557+
558+
/**
559+
* Whether there is any overlap between this frame and the given rect. If clipping this frame to
560+
* the given rect would result in an empty frame, the result is `false`
561+
* @since 6.1.0
562+
*/
563+
public function overlaps(rect:FlxRect)
564+
{
565+
rect.x += frame.x - offset.x;
566+
rect.y += frame.y - offset.y;
567+
final result = rect.overlaps(frame);
568+
rect.x -= frame.x - offset.x;
569+
rect.y -= frame.y - offset.y;
570+
return result;
571+
}
572+
573+
574+
/**
575+
* Whether this frame fully contains the given rect. If clipping this frame to
576+
* the given rect would result in a smaller frame, the result is `false`
577+
* @since 6.1.0
578+
*/
579+
public function contains(rect:FlxRect)
580+
{
581+
rect.x += frame.x - offset.x;
582+
rect.y += frame.y - offset.y;
583+
final result = frame.contains(rect);
584+
rect.x -= frame.x - offset.x;
585+
rect.y -= frame.y - offset.y;
586+
return result;
587+
}
588+
589+
/**
590+
* Whether this frame is fully contained by the given rect. If clipping this frame to
591+
* the given rect would result in a smaller frame, the result is `false`
592+
* @since 6.1.0
593+
*/
594+
public function isContained(rect:FlxRect)
595+
{
596+
rect.x += frame.x - offset.x;
597+
rect.y += frame.y - offset.y;
598+
final result = rect.contains(frame);
599+
rect.x -= frame.x - offset.x;
600+
rect.y -= frame.y - offset.y;
601+
return result;
602+
}
603+
588604
/**
589605
* Clips this frame to the desired rect
590606
*
@@ -777,4 +793,125 @@ abstract FlxUVRect(FlxRect) from FlxRect to flixel.util.FlxPool.IFlxPooled
777793
{
778794
return FlxRect.get(l, t, r, b);
779795
}
796+
}
797+
798+
/**
799+
* Used internally instead of a FlxMatrix, for some unknown reason.
800+
* Perhaps improves performance, tbh, I'm skeptical
801+
*/
802+
abstract MatrixVector(Vector<Float>)
803+
{
804+
public var a(get, set):Float;
805+
inline function get_a() return this[0];
806+
inline function set_a(value:Float) return this[0] = value;
807+
808+
public var b(get, set):Float;
809+
inline function get_b() return this[1];
810+
inline function set_b(value:Float) return this[1] = value;
811+
812+
public var c(get, set):Float;
813+
inline function get_c() return this[2];
814+
inline function set_c(value:Float) return this[2] = value;
815+
816+
public var d(get, set):Float;
817+
inline function get_d() return this[3];
818+
inline function set_d(value:Float) return this[3] = value;
819+
820+
public var tx(get, set):Float;
821+
inline function get_tx() return this[4];
822+
inline function set_tx(value:Float) return this[4] = value;
823+
824+
public var ty(get, set):Float;
825+
inline function get_ty() return this[5];
826+
inline function set_ty(value:Float) return this[5] = value;
827+
828+
829+
public inline function new ()
830+
{
831+
this = new Vector<Float>(6);
832+
identity();
833+
}
834+
835+
public inline function identity()
836+
{
837+
a = 1;
838+
b = 0;
839+
c = 0;
840+
d = 1;
841+
tx = 0;
842+
ty = 0;
843+
}
844+
845+
public inline function set(a = 1.0, b = 0.0, c = 0.0, d = 1.0, tx = 0.0, ty = 0.0)
846+
{
847+
set_a(a);
848+
set_b(b);
849+
set_c(c);
850+
set_d(d);
851+
set_tx(tx);
852+
set_ty(ty);
853+
return this;
854+
}
855+
856+
public inline function translate(dx:Float, dy:Float)
857+
{
858+
tx += dx;
859+
ty += dy;
860+
return this;
861+
}
862+
863+
public inline function scale(sx:Float, sy:Float)
864+
{
865+
a *= sx;
866+
b *= sy;
867+
c *= sx;
868+
d *= sy;
869+
tx *= sx;
870+
ty *= sy;
871+
return this;
872+
}
873+
874+
overload public inline extern function copyFrom(frame:FlxFrame, forBlit = true):MatrixVector
875+
{
876+
identity();
877+
878+
if (forBlit)
879+
translate(-frame.frame.x, -frame.frame.y);
880+
881+
if (frame.angle == FlxFrameAngle.ANGLE_90)
882+
{
883+
set(-b, a, -d, c, -ty, tx);
884+
translate(frame.frame.height, 0);
885+
}
886+
else if (frame.angle == FlxFrameAngle.ANGLE_NEG_90)
887+
{
888+
set(b, -a, d, -c, ty, -tx);
889+
translate(0, frame.frame.width);
890+
}
891+
892+
translate(frame.offset.x, frame.offset.y);
893+
return cast this;
894+
}
895+
896+
overload public inline extern function copyFrom(mat:FlxMatrix):MatrixVector
897+
{
898+
a = mat.a;
899+
b = mat.b;
900+
c = mat.c;
901+
d = mat.d;
902+
tx = mat.tx;
903+
ty = mat.ty;
904+
return cast this;
905+
}
906+
907+
public inline function copyTo(mat:FlxMatrix):FlxMatrix
908+
{
909+
mat.a = a;
910+
mat.b = b;
911+
mat.c = c;
912+
mat.d = d;
913+
mat.tx = tx;
914+
mat.ty = ty;
915+
return mat;
916+
}
780917
}

flixel/math/FlxRect.hx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,23 @@ class FlxRect implements IFlxPooled
285285
return result;
286286
}
287287

288+
/**
289+
* Checks to see if this rectangle fully contains another
290+
*
291+
* @param rect The other rectangle
292+
* @return Whether this rectangle contains the given rectangle
293+
* @since 6.1.0
294+
*/
295+
public inline function contains(rect:FlxRect):Bool
296+
{
297+
final result = rect.left >= left
298+
&& rect.right <= right
299+
&& rect.top >= top
300+
&& rect.bottom <= bottom;
301+
rect.putWeak();
302+
return result;
303+
}
304+
288305
/**
289306
* Returns true if this FlxRect contains the FlxPoint
290307
*

0 commit comments

Comments
 (0)