Skip to content

Commit

Permalink
Only compute animation frames when needed to improve performance (#1)
Browse files Browse the repository at this point in the history
* Optimize animations by only doing calculations in onUse()

* Use new onTick() instead of removed onUse()

* Change core version to use 4.x-1.20 branch
  • Loading branch information
soir20 committed Oct 7, 2023
1 parent a1868a8 commit abb6b84
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,21 @@ public final class AnimationComponent {
private final int Y_IN_BASE;

/**
* Updates the animation on tick.
* Updates the animation state on tick.
* @param currentFrame current frame of the animated texture (to which all animations write)
* @param predefinedFrames predefined frames in the base texture
* @param ticks number of ticks that have passed since the last time this method was called
*/
public void onTick(CurrentFrameView currentFrame, List<Frame> predefinedFrames) {
public void onTick(CurrentFrameView currentFrame, List<Frame> predefinedFrames, int ticks) {
Optional<Long> timeOptional = TIME_GETTER.get();

if (timeOptional.isPresent()) {
long currentTime = timeOptional.get();
int ticksToAdd = Math.floorMod(currentTime - STATE.ticks(), SYNC_TICKS) + TICKS_UNTIL_START;
int ticksUntilTime = Math.floorMod(currentTime - STATE.ticks(), SYNC_TICKS) + TICKS_UNTIL_START;

STATE.tick(ticksToAdd);
STATE.tick(ticksUntilTime);
} else {
STATE.tick(1);
STATE.tick(ticks);
}

int startIndex = FRAME_INDEX_MAPPER.applyAsInt(STATE.startIndex());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@ public AnimationGroupComponent(Collection<Pair<AnimationComponent, Optional<List
}

@Override
public void onTick(CurrentFrameView currentFrame, FrameGroup<? extends PersistentFrameView> predefinedFrames) {
public void onTick(CurrentFrameView currentFrame, FrameGroup<? extends PersistentFrameView> predefinedFrames, int ticks) {
if (predefinedFrameCache == null) {
predefinedFrameCache = wrapFrames(predefinedFrames);
}

COMPONENTS.forEach((pair) ->
pair.getSecond().ifPresentOrElse(
(frames) -> pair.getFirst().onTick(currentFrame, frames),
() -> pair.getFirst().onTick(currentFrame, predefinedFrameCache)
)
pair.getSecond().ifPresentOrElse(
(frames) -> pair.getFirst().onTick(currentFrame, frames, ticks),
() -> pair.getFirst().onTick(currentFrame, predefinedFrameCache, ticks)
)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public void tick_SyncedTimeGetterReturnsNull_NullPointerException() {
.build();

expectedException.expect(NullPointerException.class);
component.onTick(new MockCurrentFrameView(), makeMockFrames(5));
component.onTick(new MockCurrentFrameView(), makeMockFrames(5), 1);
}

@Test
Expand All @@ -216,7 +216,7 @@ public void tick_NotSyncedLoop_SameAnimFrame() {
MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

while (tick.getAndIncrement() < animationLength) {
component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);
}

assertEquals(indexToColor(0), currentFrameView.color(0, 0));
Expand All @@ -238,7 +238,7 @@ public void tick_NotSyncedPartWay_CorrectAnimFrame() {

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);
}

assertEquals(
Expand All @@ -263,7 +263,7 @@ public void tick_NotSyncedPartWayWithSkipTicksLessThanFirstFrameLength_CorrectAn

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);
}

assertEquals(
Expand All @@ -288,7 +288,7 @@ public void tick_NotSyncedPartWayWithSkipTicksMoreThanFirstFrameLength_CorrectAn

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);
}

assertEquals(
Expand All @@ -313,7 +313,7 @@ public void tick_SyncsToSameLoopInitialTime_SameAnimFrame() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(10, 1, indexToColor(0), indexToColor(1)),
Expand All @@ -337,7 +337,7 @@ public void tick_SyncsToSameNegativeInitialTime_SameAnimFrame() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
indexToColor(0),
Expand All @@ -361,7 +361,7 @@ public void tick_SyncsForward_FrameAtTime() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 15, indexToColor(8), indexToColor(9)),
Expand All @@ -385,7 +385,7 @@ public void tick_SyncsBackward_FrameAtTime() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 65, indexToColor(8), indexToColor(9)),
Expand All @@ -409,7 +409,7 @@ public void tick_SyncsForwardWithSkipTicksLessThanFirstFrameLength_FrameAtTime()

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 20, indexToColor(8), indexToColor(9)),
Expand All @@ -433,7 +433,7 @@ public void tick_SyncsForwardWithSkipTicksMoreThanFirstFrameLength_FrameAtTime()

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 30, indexToColor(8), indexToColor(9)),
Expand All @@ -457,7 +457,7 @@ public void tick_SyncsBackwardWithSkipTicksLessThanFirstFrameLength_FrameAtTime(

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 70, indexToColor(8), indexToColor(9)),
Expand All @@ -481,7 +481,7 @@ public void tick_SyncsBackwardWithSkipTicksMoreThanFirstFrameLength_FrameAtTime(

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 81, indexToColor(8), indexToColor(9)),
Expand All @@ -505,7 +505,7 @@ public void tick_VeryLargeSyncTicks_FrameAtTime() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(90, 15, indexToColor(8), indexToColor(9)),
Expand All @@ -529,7 +529,7 @@ public void tick_VeryLargeTime_FrameAtTime() {

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();

component.onTick(currentFrameView, makeMockFrames(frames));
component.onTick(currentFrameView, makeMockFrames(frames), 1);

assertEquals(
INTERPOLATOR.interpolate(60, 42, indexToColor(5), indexToColor(6)),
Expand Down Expand Up @@ -567,7 +567,7 @@ public void tick_NonZeroBaseCoord_CorrectAnimFrame() {

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
component.onTick(currentFrameView, mockFrames);
component.onTick(currentFrameView, mockFrames, 1);
}

assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void tick_OneComponentUsesPredefined_ComponentTicked() {

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
groupComponent.onTick(currentFrameView, persistentFrames);
groupComponent.onTick(currentFrameView, persistentFrames, 1);
}

assertEquals(
Expand Down Expand Up @@ -128,7 +128,7 @@ public void tick_OneComponentUsesPartFrames_ComponentTicked() {

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
groupComponent.onTick(currentFrameView, persistentFrames);
groupComponent.onTick(currentFrameView, persistentFrames, 1);
}

assertEquals(
Expand Down Expand Up @@ -213,7 +213,7 @@ public void tick_MixedComponents_ComponentsTickedInOrder() {

int animationLength = 330;
for (int tick = 0; tick < animationLength; tick++) {
groupComponent.onTick(currentFrameView, persistentFrames);
groupComponent.onTick(currentFrameView, persistentFrames, 1);
}

assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ public void build_NotSyncedNoPredefinedFrames_DefaultFrameTimeUsed() {
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
}
assertEquals(indexToColor(expectedFrame % MOCK_FRAME_GROUP.get().frames()), currentFrameView.color(0, 0));
}
Expand All @@ -141,11 +142,12 @@ public void build_NotSyncedHasMorePredefinedFramesThanActualFrames_PredefinedFra
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
int time = LARGE_MOCK_FRAME_LIST.get((expectedFrame - 1) % LARGE_MOCK_FRAME_LIST.size()).rightInt();
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
}
assertEquals(
indexToColor(LARGE_MOCK_FRAME_LIST.get(expectedFrame % LARGE_MOCK_FRAME_LIST.size()).leftInt()),
Expand All @@ -170,11 +172,12 @@ public void build_NotSyncedHasFewerPredefinedFramesThanActualFrames_PredefinedFr
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
int time = SMALL_MOCK_FRAME_LIST.get((expectedFrame - 1) % SMALL_MOCK_FRAME_LIST.size()).rightInt();
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
}
assertEquals(
indexToColor(SMALL_MOCK_FRAME_LIST.get(expectedFrame % SMALL_MOCK_FRAME_LIST.size()).leftInt()),
Expand Down Expand Up @@ -202,7 +205,7 @@ public void build_SyncedNoPredefinedFrames_DefaultFrameTimeUsed() {

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()), 1);
}
assertEquals(indexToColor(expectedFrame % MOCK_FRAME_GROUP.get().frames()), currentFrameView.color(0, 0));
}
Expand All @@ -224,11 +227,12 @@ public void build_SyncedHasMorePredefinedFramesThanActualFrames_PredefinedFrameT
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
int time = LARGE_MOCK_FRAME_LIST.get((expectedFrame - 1) % LARGE_MOCK_FRAME_LIST.size()).rightInt();
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
}
assertEquals(
indexToColor(LARGE_MOCK_FRAME_LIST.get(expectedFrame % LARGE_MOCK_FRAME_LIST.size()).leftInt()),
Expand All @@ -253,11 +257,12 @@ public void build_SyncedHasFewerPredefinedFramesThanActualFrames_PredefinedFrame
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());

for (int expectedFrame = 1; expectedFrame < 6; expectedFrame++) {
int time = SMALL_MOCK_FRAME_LIST.get((expectedFrame - 1) % SMALL_MOCK_FRAME_LIST.size()).rightInt();
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
}
assertEquals(
indexToColor(SMALL_MOCK_FRAME_LIST.get(expectedFrame % SMALL_MOCK_FRAME_LIST.size()).leftInt()),
Expand Down Expand Up @@ -349,10 +354,11 @@ public void build_AlphaSmoothDisabled_AlphaNotSmoothed() {
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());
DefaultAlphaInterpolator interpolator = new DefaultAlphaInterpolator();

for (int tick = 1; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
assertEquals(
interpolator.interpolate(time, tick, indexToColor(0), indexToColor(1)),
currentFrameView.color(0, 1)
Expand All @@ -376,10 +382,11 @@ public void build_AlphaSmoothEnabled_AlphaSmoothed() {
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());
SmoothAlphaInterpolator interpolator = new SmoothAlphaInterpolator();

for (int tick = 1; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
assertEquals(
interpolator.interpolate(time, tick, indexToColor(0), indexToColor(1)),
currentFrameView.color(0, 1)
Expand Down Expand Up @@ -507,10 +514,11 @@ public void build_AnimationHasMultipleParts_PartsAppliedInSizeOrderAfterTicks()
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames());
DefaultAlphaInterpolator interpolator = new DefaultAlphaInterpolator();

for (int tick = 1; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(MOCK_FRAME_GROUP.get().frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);
assertEquals(
interpolator.interpolate(time, tick, indexToColor(10), indexToColor(11)),
currentFrameView.color(1, 1)
Expand Down Expand Up @@ -608,6 +616,7 @@ private static void checkChangedPoints(FrameGroup<MutableFrameView> frameGroup,
);

MockCurrentFrameView currentFrameView = new MockCurrentFrameView();
MockPersistentFrameGroup persistentFrameGroup = new MockPersistentFrameGroup(frameGroup.frames());

Set<Long> changedPoints = new HashSet<>();
Set<Integer> nonInterpolatedColors = Set.of(
Expand All @@ -618,7 +627,7 @@ private static void checkChangedPoints(FrameGroup<MutableFrameView> frameGroup,
);
for (int frame = 0; frame < frameGroup.frames(); frame++) {
for (int tick = 0; tick < time; tick++) {
component.onTick(currentFrameView, new MockPersistentFrameGroup(frameGroup.frames()));
component.onTick(currentFrameView, persistentFrameGroup, 1);

for (int y = 0; y < currentFrameView.height(); y++) {
for (int x = 0; x < currentFrameView.width(); x++) {
Expand Down

0 comments on commit abb6b84

Please sign in to comment.