content/hifi-content/dave/walk-tools/walkTools/walkToolsEditor.js
2022-02-13 22:49:05 +01:00

509 lines
No EOL
26 KiB
JavaScript

//
// walkToolsEditor.js
// version 0.2
//
// Created by David Wooldridge, Summer 2015
// Copyright © 2015 - 2016 David Wooldridge.
//
// Enables realtime editing of walk.js animation files
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include('walkToolsEditorSliderRanges.js');
WalkToolsEditor = function() {
var that = {};
var _visible = false;
var _ftWheelPosition = 0;
var _globalPhase = 0;
var _currentlySelectedJoint = "Hips";
var _currentlySelectedAnimation = avatar.currentAnimation;
var _animationEditBuffer = walkAssets.createAnimationBuffer(_currentlySelectedAnimation.name);
animationOperations.deepCopy(_currentlySelectedAnimation, _animationEditBuffer);
const HOME_LOCATION = {x: 8192, y: 2.5, z: 8192};
var _dataHasBeenChanged = false;
var _editMode = 'rotation';
// web window
const EDITOR_WIDTH = 637;
const EDITOR_HEIGHT = 900;
var _innerWidth = Window.innerWidth;
var _innerHeight = Window.innerHeight;
var url = Script.resolvePath('../html/walkToolsEditor.html');
var _webView = new WebWindow('walkTools Editor', url, EDITOR_WIDTH, EDITOR_HEIGHT, false);
_webView.setPosition(_innerWidth - EDITOR_WIDTH, 0);
_webView.setVisible(_visible);
_webView.closed = function() {
print('Closing window');
};
// events from webWindow arrive here
_webView.eventBridge.webEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.type === "editorEvent") {
try {
switch (data.action) {
case "initialise":
// get lists of the hand joints
var leftHandJoints = [];
var rightHandJoints = [];
for (joint in walkAssets.animationReference.joints) {
var IKParent = walkAssets.animationReference.joints[joint].IKParent;
if (IKParent === "LeftHand") {
leftHandJoints.push(joint);
}
if (IKParent === "RightHand") {
rightHandJoints.push(joint);
}
}
// send initial data
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "initialParams",
animations: walkAssets.getAnimationNamesAsArray(),
leftHandJoints: leftHandJoints,
rightHandJoints: rightHandJoints,
currentAnimation: _currentlySelectedAnimation.name,
joint: _currentlySelectedJoint,
jointData: _animationEditBuffer.joints[_currentlySelectedJoint],
harmonicData: {}, //_animationEditBuffer.harmonics ? _animationEditBuffer.harmonics[_currentlySelectedJoint] : {},
IKChain: walkAssets.animationReference.joints[_currentlySelectedJoint].IKChain,
pairedJoint: "None",
pairedJointData: {},
pairedJointHarmonicData: {},
sliderRanges: editingScaleRanges
}));
break;
case "enableEditMode":
motion.state = EDIT;
avatar.currentAnimation = _animationEditBuffer;
break;
case "disableEditMode":
if (_dataHasBeenChanged) {
if (Window.confirm('Apply changes to '+_currentlySelectedAnimation.name+'?')) {
animationOperations.deepCopy(_animationEditBuffer, _currentlySelectedAnimation);
} else {
animationOperations.deepCopy(_currentlySelectedAnimation, _animationEditBuffer);
}
}
motion.state = STATIC;
avatar.currentAnimation = _currentlySelectedAnimation;
break;
case "selectAnimation":
if (_dataHasBeenChanged) {
if (Window.confirm('Apply changes to '+_currentlySelectedAnimation.name+'?')) {
animationOperations.deepCopy(_animationEditBuffer, _currentlySelectedAnimation);
} else {
animationOperations.deepCopy(_currentlySelectedAnimation, _animationEditBuffer);
}
}
_dataHasBeenChanged = false;
_currentlySelectedJoint = "Hips";
_currentlySelectedAnimation = walkAssets.getAnimation(data.selectedAnimation);
if (!_currentlySelectedAnimation) {
_currentlySelectedAnimation = walkAssets.getReachPose(data.selectedAnimation);
}
_animationEditBuffer = walkAssets.createAnimationBuffer(_currentlySelectedAnimation.name);
animationOperations.deepCopy(_currentlySelectedAnimation, _animationEditBuffer);
avatar.currentAnimation = _animationEditBuffer;
var IKChain = walkAssets.animationReference.joints[_currentlySelectedJoint].IKChain;
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "jointData",
frequency: _animationEditBuffer.calibration.frequency,
joint: _currentlySelectedJoint,
jointData: _animationEditBuffer.joints[_currentlySelectedJoint],
harmonicData: _animationEditBuffer.harmonics ? _animationEditBuffer.harmonics[_currentlySelectedJoint] : {},
pairedJoint: "None",
pairedJointData: {},
pairedJointHarmonicData: {},
IKChain: IKChain
}));
break;
case "getJointData":
_currentlySelectedJoint = data.selectedJoint;
_editMode = data.editMode;
// if the joint doesn't exist yet (e.g. finger joint) then create some data for the joint
if (!_animationEditBuffer.joints[data.selectedJoint]) {
_animationEditBuffer.joints[data.selectedJoint] = {
"pitch":0,
"yaw":0,
"roll":0,
"pitchPhase":0,
"yawPhase":0,
"rollPhase":0,
"pitchOffset":0,
"yawOffset":0,
"rollOffset":0
};
}
var jointData = _animationEditBuffer.joints[data.selectedJoint];
var harmonicData = _animationEditBuffer.harmonics[data.selectedJoint] ? _animationEditBuffer.harmonics[data.selectedJoint] : {};
var pairedJoint = jointPaired(data.selectedJoint);
var pairedJointData = {};
var pairedHarmonicData = {};
if (pairedJoint) {
if (!_animationEditBuffer.joints[pairedJoint]) {
_animationEditBuffer.joints[pairedJoint] = {
"pitch":0,
"yaw":0,
"roll":0,
"pitchPhase":0,
"yawPhase":0,
"rollPhase":0,
"pitchOffset":0,
"yawOffset":0,
"rollOffset":0
};
_animationEditBuffer.harmonics[pairedJoint] = {};
}
pairedJointData = _animationEditBuffer.joints[pairedJoint];
pairedHarmonicData = _animationEditBuffer.harmonics[pairedJoint] ?
_animationEditBuffer.harmonics[pairedJoint] : {};
} else {
pairedJoint = "None";
}
var IKChain = "None";
if (walkAssets.animationReference.joints[data.selectedJoint]) {
IKChain = walkAssets.animationReference.joints[data.selectedJoint].IKChain;
}
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "jointData",
joint: data.selectedJoint,
jointData: jointData,
harmonicData: harmonicData,
pairedJoint: pairedJoint,
pairedJointData: pairedJointData,
pairedHarmonicData: pairedHarmonicData,
IKChain: IKChain,
frequency: _animationEditBuffer.calibration.frequency
}));
break;
case "setJointData":
_dataHasBeenChanged = true;
_animationEditBuffer.joints[data.joint] = data.jointData;
// can't just copy entire harmonics data, as HarmonicsFilter object is not instantiated
if (data.harmonicData.pitchHarmonics) {
_animationEditBuffer.harmonics[data.joint].pitchHarmonics.numHarmonics = data.harmonicData.pitchHarmonics.numHarmonics;
}
if (data.harmonicData.yawHarmonics) {
_animationEditBuffer.harmonics[data.joint].yawHarmonics.numHarmonics = data.harmonicData.yawHarmonics.numHarmonics;
}
if (data.harmonicData.rollHarmonics) {
_animationEditBuffer.harmonics[data.joint].rollHarmonics.numHarmonics = data.harmonicData.rollHarmonics.numHarmonics;
}
if (data.joint === "Hips") {
if (data.harmonicData.swayHarmonics) {
_animationEditBuffer.harmonics[data.joint].swayHarmonics.numHarmonics = data.harmonicData.swayHarmonics.numHarmonics;
}
if (data.harmonicData.bobHarmonics) {
_animationEditBuffer.harmonics[data.joint].bobHarmonics.numHarmonics = data.harmonicData.bobHarmonics.numHarmonics;
}
if (data.harmonicData.thrustHarmonics) {
_animationEditBuffer.harmonics[data.joint].thrustHarmonics.numHarmonics = data.harmonicData.thrustHarmonics.numHarmonics;
}
}
break;
case "getJointPreRotations":
_currentlySelectedJoint = data.selectedJoint;
_editMode = data.editMode;
// if the joint doesn't exist yet (e.g. finger joint) then create some data for the joint
if (!walkAssets.preRotations.joints[data.selectedJoint]) {
_animationEditBuffer.joints[data.selectedJoint] = {
"x":0,
"y":0,
"z":0
};
}
var jointData = walkAssets.preRotations.joints[data.selectedJoint];
if (avatar.isUsingHiFiPreRotations) {
var jointNumber = MyAvatar.getJointIndex(data.selectedJoint);
var q = MyAvatar.getDefaultJointRotation(jointNumber);
jointData = Quat.safeEulerAngles(q);
print('pre-rots got');
} else print ('!Avatar.isUsingHiFiPreRotations');
//print('sending pre-rotations for '+_currentlySelectedJoint+': '+jointData.x.toFixed(1)+', '+jointData.y.toFixed(1)+', '+jointData.z.toFixed(1))
var pairedJoint = jointPaired(data.selectedJoint);
var pairedJointData = {};
if (pairedJoint) {
if (!walkAssets.preRotations.joints[pairedJoint]) {
// create if necessary
walkAssets.preRotations.joints[pairedJoint] = {
"x":0,
"y":0,
"z":0
};
}
pairedJointData = walkAssets.preRotations.joints[pairedJoint];
} else {
pairedJoint = "None";
}
var IKChain = "None";
if (walkAssets.animationReference.joints[data.selectedJoint]) {
IKChain = walkAssets.animationReference.joints[data.selectedJoint].IKChain;
}
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "jointPreRotations",
joint: data.selectedJoint,
jointData: jointData,
pairedJoint: pairedJoint,
pairedJointData: pairedJointData,
IKChain: IKChain
}));
break;
case "setPreRotations":
_dataHasBeenChanged = true;
walkAssets.preRotations.joints[data.joint] = data.jointData;
break;
case "frequencyUpdate":
_animationEditBuffer.calibration.frequency = data.frequency;
break;
case "setDirection":
switch (data.direction) {
case "North":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
break;
case "South":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 180, 0);
break;
case "East":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 90, 0);
break;
case "West":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 270, 0);
break;
case "NorthEast":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 45, 0);
break;
case "SouthEast":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 135, 0);
break;
case "SouthWest":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 225, 0);
break;
case "NorthWest":
MyAvatar.orientation = Quat.fromPitchYawRollDegrees(0, 315, 0);
break;
case "GoHome":
MyAvatar.position = HOME_LOCATION;
break;
}
break;
case "globalPhaseUpdate":
_dataHasBeenChanged = true;
globalPhaseShift(data.globalPhase);
var pairedJoint = jointPaired(_currentlySelectedJoint);
var pairedJointData = {};
var pairedHarmonicData = {};
var IKChain = walkAssets.animationReference.joints[_currentlySelectedJoint].IKChain;
if (pairedJoint) {
pairedJointData = _animationEditBuffer.joints[pairedJoint];
pairedHarmonicData = _animationEditBuffer.harmonics[pairedJoint];
}
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "jointData",
joint: _currentlySelectedJoint,
jointData: _animationEditBuffer.joints[_currentlySelectedJoint],
harmonicData: _currentlySelectedJoint.harmonics ? _currentlySelectedJoint.harmonics[_currentlySelectedJoint] : {},
pairedJoint: pairedJoint,
pairedJointData: pairedJointData,
pairedHarmonicData: pairedJoint.harmonics ? pairedJoint.harmonics[pairedJoint] : {},
IKChain: IKChain,
frequency: _animationEditBuffer.calibration.frequency
}));
break;
case "ftWheelUpdate":
_ftWheelPosition = data.ftWheelPosition;
break;
case "selectSliderRange":
switch (data.selectedSliderRange) {
case "Animation":
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "sliderRanges",
sliderRanges: editingScaleRanges
}));
break;
case "Full Range":
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "sliderRanges",
sliderRanges: fullScaleRanges
}));
break;
}
break;
case "dumpData":
if(data.editMode.editingPreRotation) {
walkTools.dumpPreRotations();
} else {
walkTools.dumpCurrentAnimation(false);
}
break;
default:
break;
}
} catch(e) {print ('Error in walkEditor events: '+e.toString());}
}
function jointPaired(jointName) {
if (walkAssets.animationReference.joints[jointName]) {
if (walkAssets.animationReference.joints[jointName].pairing) {
return walkAssets.animationReference.joints[jointName].pairing;
}
}
return false;
}
function addPhases(phaseOne, phaseTwo) {
var phaseSum = phaseOne + phaseTwo;
if (phaseSum > 180) {
phaseSum -= 360;
} else if (phaseSum < -180) {
phaseSum += 360;
}
return phaseSum;
}
function globalPhaseShift(newGobalPhase) {
if (motion.state === EDIT && walkTools.isEnabled()) {
_globalPhase = newGobalPhase;
// update any stride max at values
if (_animationEditBuffer.calibration.strideMaxAt) {
_animationEditBuffer.calibration.strideMaxAt =
addPhases(_globalPhase, _animationEditBuffer.calibration.strideMaxAt);
}
// update the phases for all axes in all joints
for (joint in _currentlySelectedAnimation.joints) {
// rotations
var pitchFrequencyMultiplier = 1;
var yawFrequencyMultiplier = 1;
var rollFrequencyMultiplier = 1;
if (_animationEditBuffer.joints[joint].pitchFrequencyMultiplier) {
pitchFrequencyMultiplier = _animationEditBuffer.joints[joint].pitchFrequencyMultiplier;
}
if (_animationEditBuffer.joints[joint].yawFrequencyMultiplier) {
yawFrequencyMultiplier = _animationEditBuffer.joints[joint].yawFrequencyMultiplier;
}
if (_animationEditBuffer.joints[joint].rollFrequencyMultiplier) {
rollFrequencyMultiplier = _animationEditBuffer.joints[joint].rollFrequencyMultiplier;
}
_animationEditBuffer.joints[joint].pitchPhase =
addPhases(pitchFrequencyMultiplier * _globalPhase,
_currentlySelectedAnimation.joints[joint].pitchPhase);
_animationEditBuffer.joints[joint].yawPhase =
addPhases(yawFrequencyMultiplier * _globalPhase,
_currentlySelectedAnimation.joints[joint].yawPhase);
_animationEditBuffer.joints[joint].rollPhase =
addPhases(rollFrequencyMultiplier * _globalPhase,
_currentlySelectedAnimation.joints[joint].rollPhase);
if (joint === "Hips") {
// Hips translations
var swayFrequencyMultiplier = 1;
var bobFrequencyMultiplier = 1;
var thrustFrequencyMultiplier = 1;
if (_animationEditBuffer.joints[joint].swayFrequencyMultiplier) {
swayFrequencyMultiplier = _animationEditBuffer.joints[joint].swayFrequencyMultiplier;
}
if (_animationEditBuffer.joints[joint].bobFrequencyMultiplier) {
bobFrequencyMultiplier = _animationEditBuffer.joints[joint].bobFrequencyMultiplier;
}
if (_animationEditBuffer.joints[joint].thrustFrequencyMultiplier) {
thrustFrequencyMultiplier = _animationEditBuffer.joints[joint].thrustFrequencyMultiplier;
}
_animationEditBuffer.joints[joint].thrustPhase =
addPhases(swayFrequencyMultiplier * _globalPhase, _currentlySelectedAnimation.joints[joint].thrustPhase);
_animationEditBuffer.joints[joint].swayPhase =
addPhases(bobFrequencyMultiplier * _globalPhase, _currentlySelectedAnimation.joints[joint].swayPhase);
_animationEditBuffer.joints[joint].bobPhase =
addPhases(thrustFrequencyMultiplier * _globalPhase, _currentlySelectedAnimation.joints[joint].bobPhase);
}
}
}
}
});
Script.update.connect(function(deltaTime) {
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "update",
ftWheelPosition: motion.frequencyTimeWheelPos
}));
});
// public methods
that.setVisible = function(visible) {
_visible = visible;
_webView.setVisible(_visible);
if (_visible) {
Window.setFocus();
//_webView.raise();
}
};
that.update = function() {
// called after animation has been reset - need to update joint values
_currentlySelectedJoint = "Hips";
var pairedJoint = "None";
var pairedJointData = {};
var pairedHarmonicData = {};
var IKChain = walkAssets.animationReference.joints[_currentlySelectedJoint].IKChain;
_webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "editorEvent",
action: "jointData",
joint: _currentlySelectedJoint,
jointData: _animationEditBuffer.joints[_currentlySelectedJoint],
harmonicData: _animationEditBuffer.harmonics[_currentlySelectedJoint],
pairedJoint: pairedJoint,
pairedJointData: pairedJointData,
pairedHarmonicData: pairedHarmonicData,
IKChain: IKChain,
frequency: _animationEditBuffer.calibration.frequency
}));
}
// used when frequency is zero and transport determining ftWheelPosition
that.getFTWheelPosition = function() {
return _ftWheelPosition;
};
// used to give walkToolsScope access to the currently selected joint
that.currentlySelectedJoint = function() {
return _currentlySelectedJoint;
};
// used for scope display
that.editMode = function() {
return _editMode;
}
return that;
};
walkToolsEditor = WalkToolsEditor();