GuiObjectManager now allows users to set Keyframes for Transformations

Fixed a bug in KeyframeList#getClosestKeyframeForTimestamp that made it only work with AdvancedPosition Keyframes
This commit is contained in:
CrushedPixel
2015-07-11 14:26:43 +02:00
parent 3fb0d87824
commit 28f7d77800
5 changed files with 184 additions and 33 deletions

View File

@@ -32,7 +32,7 @@ public class CustomImageObject implements GuiEntryListEntry {
@Getter private float textureWidth, textureHeight;
@Getter private Transformations transformations;
@Getter private Transformations transformations = new Transformations();
public void setLinkedAsset(UUID assetUUID) throws IOException {
ReplayAsset asset = ReplayHandler.getAssetRepository().getAssetByUUID(assetUUID);

View File

@@ -6,10 +6,12 @@ import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
import eu.crushedpixel.replaymod.gui.elements.timelines.GuiTimeline;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.GuiEntryListValueEntry;
import eu.crushedpixel.replaymod.holders.*;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
@@ -18,14 +20,13 @@ import org.lwjgl.util.Point;
import java.awt.*;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
public class GuiObjectManager extends GuiScreen {
private boolean initialized = false;
private KeyframeList[] keyframeLists;
private GuiEntryList<CustomImageObject> objectList;
private GuiAdvancedButton addButton, removeButton;
@@ -61,7 +62,7 @@ public class GuiObjectManager extends GuiScreen {
GuiReplayOverlay.TEXTURE_SIZE, GuiReplayOverlay.TEXTURE_SIZE, new Runnable() {
@Override
public void run() {
addKeyframe(line);
objectKeyframeTimeline.addKeyframe(line);
}
},
null);
@@ -71,16 +72,14 @@ public class GuiObjectManager extends GuiScreen {
GuiReplayOverlay.TEXTURE_SIZE, GuiReplayOverlay.TEXTURE_SIZE, new Runnable() {
@Override
public void run() {
removeKeyframe(line);
objectKeyframeTimeline.removeKeyframe(line);
}
},
null);
@Override
public GuiElement delegate() {
boolean sel = false; //TODO
if(sel) {
if(objectKeyframeTimeline.getSelectedKeyframeRow() == line) {
return selected;
} else {
return normal;
@@ -95,14 +94,6 @@ public class GuiObjectManager extends GuiScreen {
};
}
private void addKeyframe(int line) {
}
private void removeKeyframe(int line) {
}
@Override
public void initGui() {
if(!initialized) {
@@ -161,8 +152,6 @@ public class GuiObjectManager extends GuiScreen {
nameInput = new GuiAdvancedTextField(fontRendererObj, 0, 0, 0, 20);
nameInput.hint = I18n.format("replaymod.gui.objects.properties.name");
keyframeLists = new KeyframeList[5];
objectList.addSelectionListener(new SelectionListener() {
@Override
public void onSelectionChanged(int selectionIndex) {
@@ -187,6 +176,7 @@ public class GuiObjectManager extends GuiScreen {
assetDropdown.setSelectionIndexQuietly(sel);
objectKeyframeTimeline.setTransformations(selectedObject.getTransformations());
} else {
disableElements.setEnabled(false);
}
@@ -264,7 +254,7 @@ public class GuiObjectManager extends GuiScreen {
int timelineWidth = this.width-10-timelineX + 2;
int timelineHeight = this.height-10-10-timelineY + 2;
objectKeyframeTimeline = new GuiObjectKeyframeTimeline(timelineX, timelineY, timelineWidth, timelineHeight, keyframeLists);
objectKeyframeTimeline = new GuiObjectKeyframeTimeline(timelineX, timelineY, timelineWidth, timelineHeight);
disableElements.addPart(objectKeyframeTimeline);
timelineScrollbar = new GuiScrollbar(timelineX, this.height-15, timelineWidth-21) {
@@ -389,28 +379,107 @@ public class GuiObjectManager extends GuiScreen {
public class GuiObjectKeyframeTimeline extends GuiTimeline {
private KeyframeList[] keyframeLists;
private static final int KEYFRAME_X = 74;
private static final int KEYFRAME_Y = 35;
private static final int KEYFRAME_SIZE = 5;
public int x, y, width, height;
@Getter @Setter
private Transformations transformations;
@Getter private int selectedKeyframeRow = -1;
@Getter private Keyframe selectedKeyframe = null;
private boolean dragging = false;
public GuiObjectKeyframeTimeline(int x, int y, int width, int height, KeyframeList... keyframeLists) {
public GuiObjectKeyframeTimeline(int x, int y, int width, int height) {
super(x, y, width, height);
this.keyframeLists = keyframeLists;
this.zoom = 0.1;
this.timelineLength = 10 * 60 * 1000;
this.showMarkers = true;
}
@Override
public void draw(Minecraft mc, int mouseX, int mouseY) {
super.draw(mc, mouseX, mouseY);
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
long leftTime = Math.round(timeStart * timelineLength);
long rightTime = Math.round((timeStart + zoom) * timelineLength);
double segmentLength = timelineLength * zoom;
if(transformations != null) {
for(int i = 0; i < 5; i++) {
KeyframeList keyframes = transformations.getKeyframeListByID(i);
//Draw Keyframe logos
for(Keyframe kf : (List<Keyframe>) keyframes) {
drawKeyframe(kf, (int)(i * (height / 5f)) + 10, bodyWidth, leftTime, rightTime, segmentLength);
}
}
}
}
private int getKeyframeX(int timestamp, long leftTime, int bodyWidth, double segmentLength) {
long positionInSegment = timestamp - leftTime;
double fractionOfSegment = positionInSegment / segmentLength;
return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
}
private void drawKeyframe(Keyframe kf, int y, int bodyWidth, long leftTime, long rightTime, double segmentLength) {
if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) {
int textureX = KEYFRAME_X;
int textureY = KEYFRAME_Y;
y = positionY+y;
int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
if (kf == selectedKeyframe) {
textureX += KEYFRAME_SIZE;
}
rect(keyframeX - 2, y, textureX, textureY, 5, 5);
}
}
@Override
public boolean mouseClick(Minecraft mc, int mouseX, int mouseY, int button) {
if(!enabled) return false;
super.mouseClick(mc, mouseX, mouseY, button);
int time = (int) getTimeAt(mouseX, mouseY);
if(time != -1) {
boolean clicked = false;
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
if(transformations != null) {
for(int i = 0; i < 5; i++) {
int upper = positionY + (int)(i * (height / 5f)) + 10;
int lower = upper + KEYFRAME_SIZE;
if(mouseY >= upper && mouseY <= lower) {
KeyframeList keyframes = transformations.getKeyframeListByID(i);
Keyframe closest = keyframes.getClosestKeyframeForTimestamp(time, tolerance);
selectedKeyframe = closest;
if(selectedKeyframe != null) {
selectedKeyframeRow = i;
} else {
selectedKeyframeRow = -1;
}
clicked = true;
}
}
}
if(!clicked) {
selectedKeyframe = null;
selectedKeyframeRow = -1;
}
cursorPosition = time;
dragging = true;
return true;
@@ -435,5 +504,65 @@ public class GuiObjectManager extends GuiScreen {
super.mouseRelease(mc, mouseX, mouseY, button);
this.dragging = false;
}
public void addKeyframe(int line) {
CustomImageObject currentObject = objectList.getElement(objectList.getSelectionIndex());
if(currentObject != null) {
KeyframeList list = currentObject.getTransformations().getKeyframeListByID(line);
int timestamp = objectKeyframeTimeline.cursorPosition;
Keyframe kf = null;
switch(line) {
case 0:
kf = new Keyframe(timestamp, new Position(
anchorXInput.getPreciseValue(),
anchorYInput.getPreciseValue(),
anchorZInput.getPreciseValue()));
break;
case 1:
kf = new Keyframe(timestamp, new Position(
positionXInput.getPreciseValue(),
positionYInput.getPreciseValue(),
positionZInput.getPreciseValue()));
break;
case 2:
kf = new Keyframe(timestamp, new Position(
orientationXInput.getPreciseValue(),
orientationYInput.getPreciseValue(),
orientationZInput.getPreciseValue()));
break;
case 3:
kf = new Keyframe(timestamp, new Position(
scaleXInput.getPreciseValue(),
scaleYInput.getPreciseValue(),
scaleZInput.getPreciseValue()));
break;
case 4:
kf = new Keyframe(timestamp, new NumberValue(
opacityInput.getPreciseValue()
));
break;
}
list.add(kf);
selectedKeyframe = kf;
selectedKeyframeRow = line;
}
}
public void removeKeyframe(int line) {
if(selectedKeyframeRow == line) {
CustomImageObject currentObject = objectList.getElement(objectList.getSelectionIndex());
if(currentObject != null) {
KeyframeList list = currentObject.getTransformations().getKeyframeListByID(line);
list.remove(selectedKeyframe);
selectedKeyframe = null;
selectedKeyframeRow = -1;
}
}
}
}
}

View File

@@ -13,6 +13,4 @@ public class Transformation {
private Position scale;
private double opacity;
private float width, height;
}

View File

@@ -3,17 +3,43 @@ package eu.crushedpixel.replaymod.holders;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Transformations {
private KeyframeList<Position> anchorKeyframes, positionKeyframes,
orientationKeyframes, scaleKeyframes;
private KeyframeList<NumberValue> opacityKeyframes;
private KeyframeList<Position> anchorKeyframes = new KeyframeList<Position>();
private KeyframeList<Position> positionKeyframes = new KeyframeList<Position>();
private KeyframeList<Position> orientationKeyframes = new KeyframeList<Position>();
private KeyframeList<Position> scaleKeyframes = new KeyframeList<Position>();
private KeyframeList<NumberValue> opacityKeyframes = new KeyframeList<NumberValue>();
public KeyframeList getKeyframeListByID(int id) {
switch(id) {
case 0:
return anchorKeyframes;
case 1:
return positionKeyframes;
case 2:
return orientationKeyframes;
case 3:
return scaleKeyframes;
case 4:
return opacityKeyframes;
default:
return null;
}
}
public Transformation getTransformationForTimestamp(int timestamp) {
return null;
return new Transformation(
anchorKeyframes.getInterpolatedValueForTimestamp(timestamp, true),
positionKeyframes.getInterpolatedValueForTimestamp(timestamp, true),
orientationKeyframes.getInterpolatedValueForTimestamp(timestamp, true),
scaleKeyframes.getInterpolatedValueForTimestamp(timestamp, true),
opacityKeyframes.getInterpolatedValueForTimestamp(timestamp, true).value);
}
}

View File

@@ -1,6 +1,5 @@
package eu.crushedpixel.replaymod.interpolation;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.KeyframeComparator;
@@ -108,7 +107,6 @@ public class KeyframeList<K extends KeyframeValue> extends ArrayList<Keyframe<K>
public Keyframe<K> getClosestKeyframeForTimestamp(int realTime, int tolerance) {
List<Keyframe<K>> found = new ArrayList<Keyframe<K>>();
for(Keyframe<K> kf : this) {
if(!(kf.getValue() instanceof AdvancedPosition)) continue;
if(Math.abs(kf.getRealTimestamp() - realTime) <= tolerance) {
found.add(kf);
}