use of gaiasky.desktop.util.camera.Keyframe in project gaiasky by langurmonkey.
the class KeyframesPathObject method refreshOrientations.
/**
* Refreshes the orientations from the keyframes
*/
public void refreshOrientations() {
int i = 0;
for (Keyframe kf : keyframes) {
VertsObject dir = orientations.get(i);
VertsObject up = orientations.get(i + 1);
refreshSingleVector(dir, kf.pos, kf.dir);
refreshSingleVector(up, kf.pos, kf.up);
i += 2;
}
}
use of gaiasky.desktop.util.camera.Keyframe in project gaiasky by langurmonkey.
the class KeyframesPathObject method unselect.
public void unselect() {
if (selected != null) {
int i = keyframes.indexOf(selected, true) * 2;
if (i >= 0) {
VertsObject dir = orientations.get(i);
VertsObject up = orientations.get(i + 1);
dir.setPrimitiveSize(0.6f * ss);
up.setPrimitiveSize(0.6f * ss);
}
initFocus();
focus.setName("");
Keyframe aux = selected;
selected = null;
selectedKnot.clear();
EventManager.publish(Event.KEYFRAME_UNSELECT, this, aux);
}
}
use of gaiasky.desktop.util.camera.Keyframe in project gaiasky by langurmonkey.
the class KeyframesWindow method build.
@Override
protected void build() {
/*
* Right and left tables
*/
Table left = new Table(skin);
left.align(Align.top | Align.left);
Table right = new Table(skin);
right.align(Align.top | Align.left);
/* LEFT - CONTROLS */
// ADD
OwnTextIconButton addKeyframe = new OwnTextIconButton(I18n.txt("gui.keyframes.add.end"), skin, "add");
addKeyframe.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.add.end"), skin));
addKeyframe.pad(pad5);
left.add(addKeyframe).left().colspan(2).padBottom(pad5).row();
addKeyframe.addListener(event -> {
if (event instanceof ChangeEvent) {
// Add at end
return addKeyframe(-1);
}
return false;
});
// SECONDS
FloatValidator secondsValidator = new FloatValidator(0.0001f, 9999.0f);
secondsValidator.setIsValidCallback(() -> {
// Enable add button
addKeyframe.setDisabled(false);
});
secondsValidator.setIsInvalidCallback(() -> {
// Disable add button
addKeyframe.setDisabled(true);
});
secondsInput = new OwnTextField("1.0", skin, secondsValidator);
secondsInput.setWidth(96f);
OwnLabel secondsLabel = new OwnLabel(I18n.txt("gui.keyframes.secsafter") + ":", skin);
left.add(secondsLabel).center().left().padRight(pad10).padBottom(pad10);
left.add(secondsInput).center().left().padBottom(pad10).row();
// NAME
LengthValidator lengthValidator = new LengthValidator(0, 15);
RegexpValidator nameValidator = new RegexpValidator(lengthValidator, "^[^*&%\\s\\+\\=\\\\\\/@#\\$&\\*()~]*$");
nameInput = new OwnTextField("", skin, nameValidator);
nameInput.setWidth(96f);
OwnLabel nameLabel = new OwnLabel(I18n.txt("gui.keyframes.name") + ":", skin);
left.add(nameLabel).center().left().padRight(pad10).padBottom(pad10);
left.add(nameInput).center().left().padBottom(pad10).row();
left.pack();
/* RIGHT - KEYFRAMES */
OwnLabel keyframesTitle = new OwnLabel(I18n.txt("gui.keyframes.list"), skin, "hud-header");
// KEYFRAMES TABLE
keyframesTable = buildKeyframesTable();
// ADD SCROLL
rightScroll = new OwnScrollPane(keyframesTable, skin, "minimalist-nobg");
rightScroll.setExpand(true);
rightScroll.setScrollingDisabled(true, false);
rightScroll.setHeight(160f);
rightScroll.setWidth(540f);
rightScroll.setFadeScrollBars(true);
right.add(keyframesTitle).top().left().padBottom(pad10).row();
right.add(rightScroll).center().left();
right.pack();
/* RE-NORMALIZE TIME */
OwnTextButton normalizeTime = new OwnTextButton(I18n.txt("gui.keyframes.normalize"), skin);
normalizeTime.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.normalize"), skin));
normalizeTime.pad(pad10);
normalizeTime.addListener((event) -> {
if (event instanceof ChangeEvent) {
if (keyframes != null && keyframes.size > 2) {
Vector3d aux = new Vector3d();
int n = keyframes.size;
double totalTime = 0;
double totalDist = 0;
for (int i = 1; i < n; i++) {
Keyframe kf0 = keyframes.get(i - 1);
Keyframe kf1 = keyframes.get(i);
totalTime += kf1.seconds;
totalDist += aux.set(kf1.pos).sub(kf0.pos).len();
}
// Loop over keyframes and assign new times
for (int i = 1; i < n; i++) {
Keyframe kf0 = keyframes.get(i - 1);
Keyframe kf1 = keyframes.get(i);
double dist = aux.set(kf1.pos).sub(kf0.pos).len();
kf1.seconds = totalTime * dist / totalDist;
}
// Reload window contents
reinitialiseKeyframes(keyframes, null);
keyframesPathObject.unselect();
logger.info(I18n.txt("gui.keyframes.normalize.done"));
}
return true;
}
return false;
});
/* ACTION BUTTONS */
HorizontalGroup buttons = new HorizontalGroup();
buttons.space(pad10);
// Open keyframes
OwnTextIconButton open = new OwnTextIconButton(I18n.txt("gui.keyframes.load"), skin, "open");
open.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.load"), skin));
open.pad(pad5);
open.addListener((event) -> {
if (event instanceof ChangeEvent) {
FileChooser fc = new FileChooser(I18n.txt("gui.download.pickloc"), skin, stage, SysUtils.getDefaultCameraDir(), FileChooser.FileChooserTarget.FILES);
fc.setShowHidden(Settings.settings.program.fileChooser.showHidden);
fc.setShowHiddenConsumer((showHidden) -> Settings.settings.program.fileChooser.showHidden = showHidden);
fc.setFileFilter(pathname -> pathname.getFileName().toString().endsWith(".gkf"));
fc.setAcceptedFiles("*.gkf");
fc.setResultListener((success, result) -> {
if (success) {
if (Files.exists(result) && Files.isRegularFile(result)) {
// Load selected file
try {
Array<Keyframe> kfs = CameraKeyframeManager.instance.loadKeyframesFile(result);
// Update current instance
reinitialiseKeyframes(kfs, null);
keyframesPathObject.unselect();
lastKeyframeFileName = result.getFileName().toString();
logger.info(I18n.txt("gui.keyframes.load.success", keyframes.size, result.getFileName()));
} catch (RuntimeException e) {
logger.error(I18n.txt("gui.keyframes.load.error", result.getFileName()), e);
Label warn = new OwnLabel(I18n.txt("error.loading.format", result.getFileName()), skin);
warn.setColor(1f, .4f, .4f, 1f);
notice.setActor(warn);
return false;
}
} else {
logger.error(I18n.txt("error.loading.notexistent", result.getFileName()));
Label warn = new OwnLabel(I18n.txt("error.loading.notexistent", result.getFileName()), skin);
warn.setColor(1f, .4f, .4f, 1f);
notice.setActor(warn);
return false;
}
}
notice.clearActor();
return true;
});
fc.show(stage);
return true;
}
return false;
});
// Save keyframes
OwnTextIconButton save = new OwnTextIconButton(I18n.txt("gui.keyframes.save"), skin, "save");
save.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.save"), skin));
save.pad(pad5);
save.addListener((event) -> {
if (event instanceof ChangeEvent) {
String suggestedName = lastKeyframeFileName == null ? df.format(new Date()) + "_keyframes.gkf" : lastKeyframeFileName;
FileNameWindow fnw = new FileNameWindow(suggestedName, stage, skin);
OwnTextField textField = fnw.getFileNameField();
fnw.setAcceptRunnable(() -> {
if (textField.isValid()) {
EventManager.publish(Event.KEYFRAMES_FILE_SAVE, fnw, keyframes, textField.getText());
lastKeyframeFileName = textField.getText();
notice.clearActor();
} else {
Label warn = new OwnLabel(I18n.txt("error.file.name.notvalid", textField.getText()), skin);
warn.setColor(1f, .4f, .4f, 1f);
notice.setActor(warn);
}
});
fnw.show(stage);
return true;
}
return false;
});
// Export to camera path
OwnTextIconButton export = new OwnTextIconButton(I18n.txt("gui.keyframes.export"), skin, "export");
export.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.export"), skin));
export.pad(pad5);
export.addListener((event) -> {
if (event instanceof ChangeEvent) {
String suggestedName = df.format(new Date()) + ".gsc";
FileNameWindow fnw = new FileNameWindow(suggestedName, stage, skin);
OwnTextField textField = fnw.getFileNameField();
fnw.setAcceptRunnable(() -> {
if (textField.isValid()) {
EventManager.publish(Event.KEYFRAMES_EXPORT, fnw, keyframes, textField.getText());
notice.clearActor();
} else {
Label warn = new OwnLabel(I18n.txt("error.file.name.notvalid", textField.getText()), skin);
warn.setColor(1f, .4f, .4f, 1f);
notice.setActor(warn);
}
});
fnw.show(stage);
return true;
}
return false;
});
// Keyframe preferences
Button preferences = new OwnTextIconButton(I18n.txt("gui.preferences"), skin, "preferences");
preferences.setName("keyframe preferences");
preferences.pad(pad5);
preferences.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.editprefs"), skin));
preferences.addListener((event) -> {
if (event instanceof ChangeEvent) {
KeyframePreferencesWindow kpw = new KeyframePreferencesWindow(stage, skin);
kpw.setAcceptRunnable(() -> {
// Resample
GaiaSky.postRunnable(() -> {
keyframesPathObject.resamplePath();
});
});
kpw.setCancelRunnable(() -> {
});
kpw.show(stage, me.getWidth(), 0);
return true;
}
return false;
});
buttons.addActor(open);
buttons.addActor(save);
buttons.addActor(export);
buttons.addActor(preferences);
/* FINAL LAYOUT */
content.add(left).top().left().padRight(pad10 * 2f).padBottom(pad10 * 3f);
content.add(right).width(592f).top().left().padBottom(pad10).row();
notice = content.add();
notice.padBottom(pad10 * 2f).expandY().center().colspan(2).row();
content.add(normalizeTime).colspan(2).bottom().center().padBottom(pad10).row();
content.add(buttons).colspan(2).bottom().right().row();
// CLEAR
OwnTextButton clear = new OwnTextButton(I18n.txt("gui.clear"), skin);
clear.setName("clear");
clear.addListener((event) -> {
if (event instanceof ChangeEvent) {
GaiaSky.postRunnable(this::clean);
return true;
}
return false;
});
buttonGroup.addActorAt(0, clear);
// HIDE
OwnTextButton hide = new OwnTextButton(I18n.txt("gui.hide"), skin);
hide.setName("hide");
hide.addListener((event) -> {
if (event instanceof ChangeEvent) {
hide();
return true;
}
return false;
});
buttonGroup.addActorAt(1, hide);
recalculateButtonSize();
}
use of gaiasky.desktop.util.camera.Keyframe in project gaiasky by langurmonkey.
the class KeyframesWindow method addKeyframeToTable.
private void addKeyframeToTable(Keyframe kf, double prevT, int index, Table table, boolean addToModel) {
// Seconds
addFrameSeconds(kf, prevT, index, table);
// Frame number
double t = 0;
for (int i = 0; ; i++) {
if (keyframes.get(i).equals(kf))
break;
t += keyframes.get(i).seconds;
}
long frame = (long) ((t + kf.seconds) * Settings.settings.frame.targetFps);
OwnLabel framesL = new OwnLabel("(" + frame + ")", skin);
framesL.setWidth(64f);
framesL.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.frames", frame, (1d / Settings.settings.frame.targetFps)), skin));
addHighlightListener(framesL, kf);
table.add(framesL).left().padRight(pad10).padBottom(pad5);
// Clock - time
Image clockimg = new Image(skin.getDrawable("clock"));
clockimg.addListener(new OwnTextTooltip(dateFormat.format(Instant.ofEpochMilli(kf.time)), skin));
clockimg.setScale(0.7f);
clockimg.setOrigin(Align.center);
addHighlightListener(clockimg, kf);
table.add(clockimg).width(clockimg.getWidth()).left().padRight(pad10).padBottom(pad5);
// Frame name
addFrameName(kf, index, table);
// Go to
OwnTextIconButton goTo = new OwnTextIconButton("", skin, "go-to");
goTo.setSize(buttonSize, buttonSize);
goTo.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.goto"), skin));
goTo.addListener((event) -> {
if (event instanceof ChangeEvent) {
// Go to keyframe
EventManager.publish(Event.CAMERA_MODE_CMD, CameraManager.CameraMode.FREE_MODE);
GaiaSky.postRunnable(() -> {
EventManager.publish(Event.CAMERA_POS_CMD, goTo, (Object) kf.pos.values());
EventManager.publish(Event.CAMERA_DIR_CMD, goTo, (Object) kf.dir.values());
EventManager.publish(Event.CAMERA_UP_CMD, goTo, (Object) kf.up.values());
EventManager.publish(Event.TIME_CHANGE_CMD, goTo, Instant.ofEpochMilli(kf.time));
});
return true;
}
return false;
});
addHighlightListener(goTo, kf);
table.add(goTo).left().padRight(pad5).padBottom(pad5);
// Seam
OwnTextIconButton seam = new OwnTextIconButton("", skin, "seam", "toggle");
seam.setSize(buttonSize, buttonSize);
seam.setChecked(kf.seam);
seam.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.seam"), skin));
seam.addListener((event) -> {
if (event instanceof ChangeEvent) {
// Make seam
kf.seam = seam.isChecked();
GaiaSky.postRunnable(() -> {
keyframesPathObject.refreshData();
if (keyframesPathObject.selected == kf) {
if (seam.isChecked())
keyframesPathObject.selectedKnot.setColor(ColorUtils.gRed);
else
keyframesPathObject.selectedKnot.setColor(ColorUtils.gWhite);
}
});
return true;
}
return false;
});
addHighlightListener(seam, kf);
table.add(seam).left().padRight(pad5).padBottom(pad5);
// Add after
OwnTextIconButton addKeyframe = new OwnTextIconButton("", skin, "add");
addKeyframe.setSize(buttonSizeL, buttonSize);
addKeyframe.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.add.after"), skin));
addKeyframe.addListener(event -> {
if (event instanceof ChangeEvent) {
// Work out keyframe properties
Keyframe k0, k1;
Vector3d pos, dir, up;
long time;
if (index < keyframes.size - 1) {
// We can interpolate
k0 = keyframes.get(index);
k1 = keyframes.get(index + 1);
pos = new Vector3d().set(k0.pos).interpolate(k1.pos, 0.5, Interpolationd.linear);
dir = new Vector3d().set(k0.dir).interpolate(k1.dir, 0.5, Interpolationd.linear);
up = new Vector3d().set(k0.up).interpolate(k1.up, 0.5, Interpolationd.linear);
time = k0.time + (long) ((k1.time - k0.time) / 2d);
} else {
// Last keyframe
k0 = keyframes.get(index - 1);
k1 = keyframes.get(index);
pos = new Vector3d().set(k0.pos).interpolate(k1.pos, 1.5, Interpolationd.linear);
dir = new Vector3d().set(k0.dir).interpolate(k1.dir, 1.5, Interpolationd.linear);
up = new Vector3d().set(k0.up).interpolate(k1.up, 1.5, Interpolationd.linear);
time = k1.time + (long) ((k1.time - k0.time) / 2d);
}
// Add at end
return addKeyframe(index + 1, pos, dir, up, time);
}
return false;
});
addHighlightListener(addKeyframe, kf);
table.add(addKeyframe).left().padRight(pad5).padBottom(pad5);
// Rubbish
OwnTextIconButton rubbish = new OwnTextIconButton("", skin, "rubbish");
rubbish.setSize(buttonSizeL, buttonSize);
rubbish.addListener(new OwnTextTooltip(I18n.txt("gui.tooltip.kf.remove"), skin));
rubbish.addListener((event) -> {
if (event instanceof ChangeEvent) {
// Remove keyframe
Array<Keyframe> newKfs = new Array<>(false, keyframes.size - 1);
for (Keyframe k : keyframes) {
if (k != kf)
newKfs.add(k);
}
// In case we removed the first
if (!newKfs.isEmpty())
newKfs.get(0).seconds = 0;
reinitialiseKeyframes(newKfs, null);
logger.info(I18n.txt("gui.keyframes.removed", kf.name));
return true;
}
return false;
});
addHighlightListener(rubbish, kf);
Cell<?> rub = table.add(rubbish).left().padBottom(pad5);
rub.row();
table.pack();
if (addToModel && keyframesPathObject != null) {
GaiaSky.postRunnable(() -> {
// Update model data
keyframesPathObject.addKnot(kf.pos, kf.dir, kf.up, kf.seam);
keyframesPathObject.segments.addPoint(kf.pos);
if (keyframes.size > 1)
keyframesPathObject.resamplePath();
});
}
}
use of gaiasky.desktop.util.camera.Keyframe in project gaiasky by langurmonkey.
the class KeyframesWindow method addKeyframe.
/**
* Adds a new keyframe at the given index position using the given camera position, orientation and time
*
* @param index The position of the keyframe, negative to add at the end
* @param cPos The position
* @param cDir The direction
* @param cUp The up
* @param cTime The time
* @return True if the keyframe was added, false otherwise
*/
private boolean addKeyframe(int index, Vector3d cPos, Vector3d cDir, Vector3d cUp, long cTime) {
try {
boolean secOk = secondsInput.isValid();
boolean nameOk = nameInput.isValid();
if (secOk && nameOk) {
// Seconds after - first keyframe at zero
double secsAfter = keyframes.size == 0 ? 0 : Double.parseDouble(secondsInput.getText());
// Name
String name;
String ni = nameInput.getText();
if (ni != null && !ni.isEmpty()) {
name = ni;
} else {
name = "Keyframe " + (keyframes.size + 1);
}
Keyframe kf = new Keyframe(name, cPos, cDir, cUp, cTime, secsAfter, false);
final boolean insert = index >= 0 && index != keyframes.size;
if (!insert) {
keyframes.add(kf);
double prevT = 0;
for (Keyframe kfr : keyframes) {
if (kfr == kf)
break;
prevT += kfr.seconds;
}
addKeyframeToTable(kf, prevT, keyframes.size - 1, keyframesTable, true);
} else {
keyframes.insert(index, kf);
}
GaiaSky.postRunnable(() -> {
if (insert)
reinitialiseKeyframes(keyframes, kf);
scrollToKeyframe(kf);
});
} else {
logger.info(I18n.txt("gui.keyframes.notadded") + "-" + I18n.txt("gui.keyframes.error.values", secOk ? I18n.txt("gui.ok") : I18n.txt("gui.wrong"), nameOk ? I18n.txt("gui.ok") : I18n.txt("gui.wrong")));
}
} catch (Exception e) {
logger.error(I18n.txt("gui.keyframes.notadded") + " - " + I18n.txt("gui.keyframes.error.input"), e);
return false;
}
return true;
}
Aggregations