Added "inclusive" parameter to getPreviousKeyframe() and getNextKeyframe() in KeyframeList to define whether the next/previous keyframe may have the same timestamp as the realTime parameter

Fixed a bug in KeyframeList#getPositionOnPath where a non-inclusive getPreviousKeyframe call resulted in an incorrect position value
This commit is contained in:
CrushedPixel
2015-07-14 13:48:48 +02:00
parent 3e77e72f5a
commit d057553223
6 changed files with 26 additions and 24 deletions

View File

@@ -83,18 +83,18 @@ public class GuiEditKeyframe extends GuiScreen {
KeyframeList<Marker> markerKeyframes = ReplayHandler.getMarkerKeyframes(); KeyframeList<Marker> markerKeyframes = ReplayHandler.getMarkerKeyframes();
if(keyframeType == KeyframeType.POSITION) { if(keyframeType == KeyframeType.POSITION) {
previous = positionKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp() - 1); previous = positionKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp(), false);
next = positionKeyframes.getNextKeyframe(keyframe.getRealTimestamp() + 1); next = positionKeyframes.getNextKeyframe(keyframe.getRealTimestamp(), false);
screenTitle = I18n.format("replaymod.gui.editkeyframe.title.pos"); screenTitle = I18n.format("replaymod.gui.editkeyframe.title.pos");
} else if(keyframeType == KeyframeType.TIME) { } else if(keyframeType == KeyframeType.TIME) {
previous = timeKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp() - 1); previous = timeKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp(), false);
next = timeKeyframes.getNextKeyframe(keyframe.getRealTimestamp() + 1); next = timeKeyframes.getNextKeyframe(keyframe.getRealTimestamp(), false);
screenTitle = I18n.format("replaymod.gui.editkeyframe.title.time"); screenTitle = I18n.format("replaymod.gui.editkeyframe.title.time");
} else if(keyframeType == KeyframeType.MARKER) { } else if(keyframeType == KeyframeType.MARKER) {
previous = markerKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp() - 1); previous = markerKeyframes.getPreviousKeyframe(keyframe.getRealTimestamp(), false);
next = markerKeyframes.getNextKeyframe(keyframe.getRealTimestamp() + 1); next = markerKeyframes.getNextKeyframe(keyframe.getRealTimestamp(), false);
} }
ReplayMod.replaySender.setReplaySpeed(0); ReplayMod.replaySender.setReplaySpeed(0);

View File

@@ -65,9 +65,10 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
/** /**
* Returns the first Keyframe that comes before a given value. * Returns the first Keyframe that comes before a given value.
* @param realTime The value to use * @param realTime The value to use
* @param inclusive Whether the previous Keyframe might have the same timestamp as <b>realTime</b>
* @return The first Keyframe prior to the given value * @return The first Keyframe prior to the given value
*/ */
public Keyframe<K> getPreviousKeyframe(int realTime) { public Keyframe<K> getPreviousKeyframe(int realTime, boolean inclusive) {
if(this.isEmpty()) return null; if(this.isEmpty()) return null;
Keyframe<K> backup = null; Keyframe<K> backup = null;
@@ -76,7 +77,7 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
for(Keyframe<K> kf : this) { for(Keyframe<K> kf : this) {
if(kf.getRealTimestamp() < realTime) { if((inclusive && kf.getRealTimestamp() <= realTime) || (!inclusive && kf.getRealTimestamp() < realTime)) {
found.add(kf); found.add(kf);
} else if(kf.getRealTimestamp() == realTime) { } else if(kf.getRealTimestamp() == realTime) {
backup = kf; backup = kf;
@@ -93,16 +94,17 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
/** /**
* Returns the first Keyframe that comes after a given value. * Returns the first Keyframe that comes after a given value.
* @param realTime The value to use * @param realTime The value to use
* @param inclusive Whether the next Keyframe might have the same timestamp as <b>realTime</b>
* @return The first Keyframe after the given value * @return The first Keyframe after the given value
*/ */
public Keyframe<K> getNextKeyframe(int realTime) { public Keyframe<K> getNextKeyframe(int realTime, boolean inclusive) {
if(this.isEmpty()) return null; if(this.isEmpty()) return null;
Keyframe<K> backup = null; Keyframe<K> backup = null;
for(Keyframe<K> kf : this) { for(Keyframe<K> kf : this) {
if(kf.getRealTimestamp() > realTime) { if((inclusive && kf.getRealTimestamp() >= realTime) || (!inclusive && kf.getRealTimestamp() > realTime)) {
return kf; //first found element is next return kf; //first found element is next
} else if(kf.getRealTimestamp() == realTime) { } else if(kf.getRealTimestamp() == realTime) {
backup = kf; backup = kf;
@@ -179,8 +181,8 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
* @return A value between 0 and 1 * @return A value between 0 and 1
*/ */
private float getPositionOnPath(int timestamp) { private float getPositionOnPath(int timestamp) {
Keyframe previousKeyframe = getPreviousKeyframe(timestamp); Keyframe previousKeyframe = getPreviousKeyframe(timestamp, true);
Keyframe nextKeyframe = getNextKeyframe(timestamp); Keyframe nextKeyframe = getNextKeyframe(timestamp, true);
int previousTimestamp = 0; int previousTimestamp = 0;
int nextTimestamp = 0; int nextTimestamp = 0;
@@ -203,7 +205,7 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
int currentPos = timestamp - previousTimestamp; int currentPos = timestamp - previousTimestamp;
float currentStepPercentage = (float) currentPos / (float) currentPosDiff; float currentStepPercentage = (float) currentPos / (float) currentPosDiff;
if(Float.isInfinite(currentStepPercentage)) currentStepPercentage = 0; if(Float.isInfinite(currentStepPercentage) || Float.isNaN(currentStepPercentage)) currentStepPercentage = 0;
float value = (indexOf(previousKeyframe) + currentStepPercentage) / float value = (indexOf(previousKeyframe) + currentStepPercentage) /
(float)(size() - 1); (float)(size() - 1);

View File

@@ -539,7 +539,7 @@ public class ReplayHandler {
//if shift is down, it will refer to the previous Time Keyframe instead of the last one //if shift is down, it will refer to the previous Time Keyframe instead of the last one
if(shiftMode) { if(shiftMode) {
int realTime = getRealTimelineCursor(); int realTime = getRealTimelineCursor();
keyframe = timeKeyframes.getPreviousKeyframe(realTime); keyframe = timeKeyframes.getPreviousKeyframe(realTime, false);
} else { } else {
keyframe = timeKeyframes.last(); keyframe = timeKeyframes.last();
} }

View File

@@ -206,8 +206,8 @@ public class ReplayProcess {
int curRealReplayTime = (int) (lastRealReplayTime + timeStep); int curRealReplayTime = (int) (lastRealReplayTime + timeStep);
Keyframe<AdvancedPosition> lastPos = ReplayHandler.getPositionKeyframes().getPreviousKeyframe(curRealReplayTime); Keyframe<AdvancedPosition> lastPos = ReplayHandler.getPositionKeyframes().getPreviousKeyframe(curRealReplayTime, true);
Keyframe<AdvancedPosition> nextPos = ReplayHandler.getPositionKeyframes().getNextKeyframe(curRealReplayTime); Keyframe<AdvancedPosition> nextPos = ReplayHandler.getPositionKeyframes().getNextKeyframe(curRealReplayTime, true);
boolean spectating = false; boolean spectating = false;
@@ -239,8 +239,8 @@ public class ReplayProcess {
} }
} }
Keyframe<TimestampValue> lastTime = ReplayHandler.getTimeKeyframes().getPreviousKeyframe(curRealReplayTime); Keyframe<TimestampValue> lastTime = ReplayHandler.getTimeKeyframes().getPreviousKeyframe(curRealReplayTime, true);
Keyframe<TimestampValue> nextTime = ReplayHandler.getTimeKeyframes().getNextKeyframe(curRealReplayTime); Keyframe<TimestampValue> nextTime = ReplayHandler.getTimeKeyframes().getNextKeyframe(curRealReplayTime, true);
int lastTimeStamp = 0; int lastTimeStamp = 0;
int nextTimeStamp = 0; int nextTimeStamp = 0;

View File

@@ -217,16 +217,16 @@ public class VideoRenderer {
int posCount = ReplayHandler.getPositionKeyframes().size(); int posCount = ReplayHandler.getPositionKeyframes().size();
AdvancedPosition pos = new AdvancedPosition(); AdvancedPosition pos = new AdvancedPosition();
Keyframe<AdvancedPosition> lastPos = positionKeyframes.getPreviousKeyframe(videoTime); Keyframe<AdvancedPosition> lastPos = positionKeyframes.getPreviousKeyframe(videoTime, true);
Keyframe<AdvancedPosition> nextPos = null; Keyframe<AdvancedPosition> nextPos = null;
if (movement == null || lastPos == null) { if (movement == null || lastPos == null) {
// Stay at one position, no movement // Stay at one position, no movement
Keyframe<AdvancedPosition> keyframe = positionKeyframes.getNextKeyframe(-1); Keyframe<AdvancedPosition> keyframe = positionKeyframes.getNextKeyframe(-1, true);
assert keyframe != null; assert keyframe != null;
pos = keyframe.getValue(); pos = keyframe.getValue();
} else { } else {
// Position interpolation // Position interpolation
nextPos = positionKeyframes.getNextKeyframe(videoTime); nextPos = positionKeyframes.getNextKeyframe(videoTime, true);
int lastPosStamp = lastPos.getRealTimestamp(); int lastPosStamp = lastPos.getRealTimestamp();
int nextPosStamp = (nextPos == null ? lastPos : nextPos).getRealTimestamp(); int nextPosStamp = (nextPos == null ? lastPos : nextPos).getRealTimestamp();
@@ -275,8 +275,8 @@ public class VideoRenderer {
// WARNING: The rest of this method contains some magic for which Marius is responsible // WARNING: The rest of this method contains some magic for which Marius is responsible
// Time interpolation // Time interpolation
Keyframe<TimestampValue> lastTime = timeKeyframes.getPreviousKeyframe(videoTime); Keyframe<TimestampValue> lastTime = timeKeyframes.getPreviousKeyframe(videoTime, false);
Keyframe<TimestampValue> nextTime = timeKeyframes.getNextKeyframe(videoTime); Keyframe<TimestampValue> nextTime = timeKeyframes.getNextKeyframe(videoTime, false);
int lastTimeStamp = 0; int lastTimeStamp = 0;
int nextTimeStamp = 0; int nextTimeStamp = 0;