mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 05:52:27 +02:00
3851 lines
No EOL
178 KiB
JavaScript
3851 lines
No EOL
178 KiB
JavaScript
//
|
|
// walk.js
|
|
//
|
|
// version 1.007b
|
|
//
|
|
// Created by Davedub, August / September 2014
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
// path to the animation files
|
|
var pathToAnimFiles = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/animation-files/'; // working (but only without https)
|
|
|
|
// path to the images used for the overlays
|
|
var pathToOverlays = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/overlays/'; // working (but only without https)
|
|
|
|
// path to the sounds used for the footsteps
|
|
var pathToSounds = 'http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Footsteps/';
|
|
|
|
// load the animation datafiles
|
|
Script.include(pathToAnimFiles+"dd-female-strut-walk-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-flying-up-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-flying-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-flying-down-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-standing-one-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-sidestep-left-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-female-sidestep-right-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-strut-walk-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-flying-up-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-flying-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-flying-down-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-standing-one-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-sidestep-left-animation.js");
|
|
Script.include(pathToAnimFiles+"dd-male-sidestep-right-animation.js");
|
|
|
|
// read in the data from the animation files
|
|
var FemaleStrutWalkFile = new FemaleStrutWalk();
|
|
var femaleStrutWalk = FemaleStrutWalkFile.loadAnimation();
|
|
var FemaleFlyingUpFile = new FemaleFlyingUp();
|
|
var femaleFlyingUp = FemaleFlyingUpFile.loadAnimation();
|
|
var FemaleFlyingFile = new FemaleFlying();
|
|
var femaleFlying = FemaleFlyingFile.loadAnimation();
|
|
var FemaleFlyingDownFile = new FemaleFlyingDown();
|
|
var femaleFlyingDown = FemaleFlyingDownFile.loadAnimation();
|
|
var FemaleStandOneFile = new FemaleStandingOne();
|
|
var femaleStandOne = FemaleStandOneFile.loadAnimation();
|
|
var FemaleSideStepLeftFile = new FemaleSideStepLeft();
|
|
var femaleSideStepLeft = FemaleSideStepLeftFile.loadAnimation();
|
|
var FemaleSideStepRightFile = new FemaleSideStepRight();
|
|
var femaleSideStepRight = FemaleSideStepRightFile.loadAnimation();
|
|
var MaleStrutWalkFile = new MaleStrutWalk();
|
|
var maleStrutWalk = MaleStrutWalkFile.loadAnimation();
|
|
var MaleFlyingUpFile = new MaleFlyingUp();
|
|
var maleFlyingUp = MaleFlyingUpFile.loadAnimation();
|
|
var MaleFlyingFile = new MaleFlying();
|
|
var maleFlying = MaleFlyingFile.loadAnimation();
|
|
var MaleFlyingDownFile = new MaleFlyingDown();
|
|
var maleFlyingDown = MaleFlyingDownFile.loadAnimation();
|
|
var MaleStandOneFile = new MaleStandingOne();
|
|
var maleStandOne = MaleStandOneFile.loadAnimation();
|
|
var MaleSideStepLeftFile = new MaleSideStepLeft();
|
|
var maleSideStepLeft = MaleSideStepLeftFile.loadAnimation();
|
|
var MaleSideStepRightFile = new MaleSideStepRight();
|
|
var maleSideStepRight = MaleSideStepRightFile.loadAnimation();
|
|
|
|
// read in the sounds
|
|
var footsteps = [];
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW2Left-12db.wav"));
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW2Right-12db.wav"));
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW3Left-12db.wav"));
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW3Right-12db.wav"));
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW5Left-12db.wav"));
|
|
footsteps.push(new Sound(pathToSounds+"FootstepW5Right-12db.wav"));
|
|
|
|
// all slider controls have a range (with the exception of phase controls that are always +-180) so we store them all here
|
|
var sliderRanges = {"joints":[{"name":"hips","pitchRange":25,"yawRange":25,"rollRange":25,"pitchOffsetRange":25,"yawOffsetRange":25,"rollOffsetRange":25,"thrustRange":0.01,"bobRange":0.02,"swayRange":0.01},{"name":"upperLegs","pitchRange":90,"yawRange":35,"rollRange":35,"pitchOffsetRange":60,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"lowerLegs","pitchRange":90,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"feet","pitchRange":60,"yawRange":20,"rollRange":20,"pitchOffsetRange":60,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"toes","pitchRange":90,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"spine","pitchRange":40,"yawRange":40,"rollRange":40,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"spine1","pitchRange":20,"yawRange":40,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"spine2","pitchRange":20,"yawRange":40,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"shoulders","pitchRange":35,"yawRange":40,"rollRange":20,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"upperArms","pitchRange":90,"yawRange":90,"rollRange":90,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"lowerArms","pitchRange":90,"yawRange":90,"rollRange":120,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"hands","pitchRange":90,"yawRange":180,"rollRange":90,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"head","pitchRange":20,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":90,"rollOffsetRange":90}]};
|
|
|
|
// internal state (FSM based) constants
|
|
var STANDING = 1;
|
|
var WALKING = 2;
|
|
var SIDE_STEPPING = 3;
|
|
var FLYING = 4;
|
|
var CONFIG_WALK_STYLES = 5;
|
|
var CONFIG_WALK_TWEAKS = 6;
|
|
var CONFIG_WALK_JOINTS = 7;
|
|
var CONFIG_STANDING = 8;
|
|
var CONFIG_FLYING = 9;
|
|
var CONFIG_FLYING_UP = 10;
|
|
var CONFIG_FLYING_DOWN = 11;
|
|
var CONFIG_SIDESTEP_LEFT = 12;
|
|
var CONFIG_SIDESTEP_RIGHT = 14;
|
|
var INTERNAL_STATE = STANDING;
|
|
|
|
// status
|
|
var powerOn = true;
|
|
var paused = false; // pause animation playback whilst adjusting certain parameters
|
|
var minimised = true;
|
|
var armsFree = true; // set true for hydra support - temporary fix for Hydras
|
|
var statsOn = false;
|
|
var playFootStepSounds = true;
|
|
|
|
// constants
|
|
var MAX_WALK_SPEED = 1257; // max oscillation speed
|
|
var FLYING_SPEED = 6.4;// 12.4; // m/s - real humans can't run any faster than 12.4 m/s
|
|
var TERMINAL_VELOCITY = 300; // max speed imposed by Interface
|
|
var DIRECTION_UP = 1;
|
|
var DIRECTION_DOWN = 2;
|
|
var DIRECTION_LEFT = 4;
|
|
var DIRECTION_RIGHT = 8;
|
|
var DIRECTION_FORWARDS = 16;
|
|
var DIRECTION_BACKWARDS = 32;
|
|
var DIRECTION_NONE = 64;
|
|
var MALE = 1;
|
|
var FEMALE = 2;
|
|
|
|
// start of animation control section
|
|
var cumulativeTime = 0.0;
|
|
var lastOrientation;
|
|
|
|
// avi gender and default animations
|
|
var avatarGender = MALE;
|
|
var selectedWalk = maleStrutWalk; // the currently selected animation walk file (to edit any animation, paste it's name here and select walk editing mode)
|
|
var selectedStand = maleStandOne;
|
|
var selectedFlyUp = maleFlyingUp;
|
|
var selectedFly = maleFlying;
|
|
var selectedFlyDown = maleFlyingDown;
|
|
var selectedSideStepLeft = maleSideStepLeft;
|
|
var selectedSideStepRight = maleSideStepRight;
|
|
if(avatarGender===FEMALE) {
|
|
|
|
// to make toggling the default quick
|
|
selectedWalk = femaleStrutWalk;
|
|
selectedStand = femaleStandOne;
|
|
selectedFlyUp = femaleFlyingUp;
|
|
selectedFly = femaleFlying;
|
|
selectedFlyDown = femaleFlyingDown;
|
|
selectedSideStepLeft = femaleSideStepLeft;
|
|
selectedSideStepRight = femaleSideStepRight;
|
|
}
|
|
var currentAnimation = selectedStand; // the current animation
|
|
var selectedJointIndex = 0; // the index of the joint currently selected for editing
|
|
var currentTransition = null; // used as a pointer to a Transition
|
|
|
|
// walkwheel (foot / ground speed matching)
|
|
var sideStepCycleStartLeft = 270;
|
|
var sideStepCycleStartRight = 90;
|
|
var walkWheelPosition = 0;
|
|
var nextStep = DIRECTION_RIGHT; // first step is always right, because the sine waves say so. Unless you're mirrored.
|
|
var nFrames = 0; // counts number of frames
|
|
var strideLength = 0; // stride calibration
|
|
var aviFootSize = {x:0.1, y:0.1, z:0.25}; // experimental values for addition to stride length - TODO: analyse and confirm is increasing smaller stride lengths accuracy once we have better ground detection
|
|
|
|
// stats
|
|
var frameStartTime = 0; // when the frame first starts we take a note of the time
|
|
var frameExecutionTimeMax = 0; // keep track of the longest frame execution time
|
|
|
|
// constructor for recent RecentMotion (i.e. frame data) class
|
|
function RecentMotion(velocity, acceleration, principleDirection, state) {
|
|
this.velocity = velocity;
|
|
this.acceleration = acceleration;
|
|
this.principleDirection = principleDirection;
|
|
this.state = state;
|
|
}
|
|
|
|
// constructor for the FramesHistory object
|
|
function FramesHistory() {
|
|
this.recentMotions = [];
|
|
for(var i = 0 ; i < 10 ; i++) {
|
|
var blank = new RecentMotion({ x:0, y:0, z:0 }, { x:0, y:0, z:0 }, DIRECTION_FORWARDS, STANDING );
|
|
this.recentMotions.push(blank);
|
|
}
|
|
|
|
// recentDirection 'method' args: (direction enum, number of steps back to compare)
|
|
this.recentDirection = function () {
|
|
|
|
if( arguments[0] && arguments[1] ) {
|
|
|
|
var directionCount = 0;
|
|
if( arguments[1] > this.recentMotions.length )
|
|
arguments[1] = this.recentMotions.length;
|
|
|
|
for(var i = 0 ; i < arguments[1] ; i++ ) {
|
|
if( this.recentMotions[i].principleDirection === arguments[0] )
|
|
directionCount++;
|
|
}
|
|
return directionCount / arguments[1] === 1 ? true : false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// recentState 'method' args: (state enum, number of steps back to compare)
|
|
this.recentState = function () {
|
|
|
|
if( arguments[0] && arguments[1] ) {
|
|
|
|
var stateCount = 0;
|
|
if( arguments[1] > this.recentMotions.length )
|
|
arguments[1] = this.recentMotions.length;
|
|
|
|
for(var i = 0 ; i < arguments[1] ; i++ ) {
|
|
if( this.recentMotions[i].state === arguments[0] )
|
|
stateCount++;
|
|
}
|
|
return stateCount / arguments[1] === 1 ? true : false;
|
|
}
|
|
return false;
|
|
}
|
|
this.lastWalkStartTime = 0; // short walks and long walks need different handling
|
|
}
|
|
var framesHistory = new FramesHistory();
|
|
|
|
// constructor for animation Transition class
|
|
function Transition(lastAnimation, nextAnimation, reachPoses, transitionDuration, easingLower, easingUpper) {
|
|
this.lastAnimation = lastAnimation; // name of last animation
|
|
if(lastAnimation === selectedWalk ||
|
|
nextAnimation === selectedSideStepLeft ||
|
|
nextAnimation === selectedSideStepRight)
|
|
this.walkingAtStart = true; // boolean - is the last animation a walking animation?
|
|
else
|
|
this.walkingAtStart = false; // boolean - is the last animation a walking animation?
|
|
this.nextAnimation = nextAnimation; // name of next animation
|
|
if(nextAnimation === selectedWalk ||
|
|
nextAnimation === selectedSideStepLeft ||
|
|
nextAnimation === selectedSideStepRight)
|
|
this.walkingAtEnd = true; // boolean - is the next animation a walking animation?
|
|
else
|
|
this.walkingAtEnd = false; // boolean - is the next animation a walking animation?
|
|
this.reachPoses = reachPoses; // array of reach poses - am very much looking forward to putting these in!
|
|
this.transitionDuration = transitionDuration; // length of transition (seconds)
|
|
this.easingLower = easingLower; // Bezier curve handle (normalised)
|
|
this.easingUpper = easingUpper; // Bezier curve handle (normalised)
|
|
this.startTime = new Date().getTime(); // Starting timestamp (seconds)
|
|
this.progress = 0; // how far are we through the transition?
|
|
this.walkWheelIncrement = 3; // how much to turn the walkwheel each frame when coming to a halt. Get's set to 0 once the feet are under the avi
|
|
this.walkWheelAdvance = 0; // how many degrees the walk wheel has been advanced during the transition
|
|
this.walkStopAngle = 0; // what angle should we stop the walk cycle? (calculated on the fly)
|
|
}
|
|
|
|
// convert a local (to the avi) translation to a global one
|
|
function localToGlobal(localTranslation) {
|
|
|
|
var aviOrientation = MyAvatar.orientation;
|
|
var front = Quat.getFront(aviOrientation);
|
|
var right = Quat.getRight(aviOrientation);
|
|
var up = Quat.getUp (aviOrientation);
|
|
var aviFront = Vec3.multiply(front,localTranslation.z);
|
|
var aviRight = Vec3.multiply(right,localTranslation.x);
|
|
var aviUp = Vec3.multiply(up ,localTranslation.y);
|
|
var globalTranslation = {x:0,y:0,z:0}; // final value
|
|
globalTranslation = Vec3.sum(globalTranslation, aviFront);
|
|
globalTranslation = Vec3.sum(globalTranslation, aviRight);
|
|
globalTranslation = Vec3.sum(globalTranslation, aviUp);
|
|
return globalTranslation;
|
|
}
|
|
|
|
// similar ot above - convert hips translations to global and apply
|
|
function translateHips(localHipsTranslation) {
|
|
|
|
var aviOrientation = MyAvatar.orientation;
|
|
var front = Quat.getFront(aviOrientation);
|
|
var right = Quat.getRight(aviOrientation);
|
|
var up = Quat.getUp (aviOrientation);
|
|
var aviFront = Vec3.multiply(front,localHipsTranslation.y);
|
|
var aviRight = Vec3.multiply(right,localHipsTranslation.x);
|
|
var aviUp = Vec3.multiply(up ,localHipsTranslation.z);
|
|
var AviTranslationOffset = {x:0,y:0,z:0}; // final value
|
|
AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviFront);
|
|
AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviRight);
|
|
AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviUp);
|
|
MyAvatar.position = {x: MyAvatar.position.x + AviTranslationOffset.x,
|
|
y: MyAvatar.position.y + AviTranslationOffset.y,
|
|
z: MyAvatar.position.z + AviTranslationOffset.z };
|
|
}
|
|
|
|
// clear all joint data
|
|
function resetJoints() {
|
|
|
|
var avatarJointNames = MyAvatar.getJointNames();
|
|
for (var i = 0; i < avatarJointNames.length; i++) {
|
|
MyAvatar.clearJointData(avatarJointNames[i]);
|
|
}
|
|
}
|
|
|
|
// play footstep sound
|
|
function playFootstep(side) {
|
|
|
|
var options = new AudioInjectionOptions();
|
|
options.position = Camera.getPosition();
|
|
options.volume = 0.5;
|
|
var walkNumber = 2; // 0 to 2
|
|
if(side===DIRECTION_RIGHT && playFootStepSounds) {
|
|
Audio.playSound(footsteps[walkNumber+1], options);
|
|
}
|
|
else if(side===DIRECTION_LEFT && playFootStepSounds) {
|
|
Audio.playSound(footsteps[walkNumber], options);
|
|
}
|
|
}
|
|
|
|
// put the fingers into a relaxed pose
|
|
function curlFingers() {
|
|
|
|
// left hand fingers
|
|
for(var i = 18 ; i < 34 ; i++) {
|
|
MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(8,0,0));
|
|
}
|
|
// left hand thumb
|
|
for(var i = 34 ; i < 38 ; i++) {
|
|
MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,0,0));
|
|
}
|
|
// right hand fingers
|
|
for(var i = 42 ; i < 58 ; i++) {
|
|
MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(8,0,0));
|
|
}
|
|
// right hand thumb
|
|
for(var i = 58 ; i < 62 ; i++) {
|
|
MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,0,0));
|
|
}
|
|
}
|
|
|
|
// additional maths functions
|
|
function degToRad( degreesValue ) { return degreesValue * Math.PI / 180; }
|
|
function radToDeg( radiansValue ) { return radiansValue * 180 / Math.PI; }
|
|
|
|
// animateAvatar - sine wave generators working like clockwork
|
|
function animateAvatar( deltaTime, velocity, principleDirection ) {
|
|
|
|
// adjusting the walk speed in edit mode causes a nasty flicker. pausing the animation stops this
|
|
if(paused) return;
|
|
|
|
var cycle = cumulativeTime;
|
|
var transitionProgress = 1;
|
|
var adjustedFrequency = currentAnimation.settings.baseFrequency;
|
|
|
|
// upper legs phase reversal for walking backwards
|
|
var forwardModifier = 1;
|
|
if(principleDirection===DIRECTION_BACKWARDS)
|
|
forwardModifier = -1;
|
|
|
|
// don't want to lean forwards if going directly upwards
|
|
var leanPitchModifier = 1;
|
|
if(principleDirection===DIRECTION_UP)
|
|
leanPitchModifier = 0;
|
|
|
|
// is there a Transition to include?
|
|
if(currentTransition!==null) {
|
|
|
|
// if is a new transiton
|
|
if(currentTransition.progress===0) {
|
|
|
|
if( currentTransition.walkingAtStart ) {
|
|
|
|
if( INTERNAL_STATE !== SIDE_STEPPING ) {
|
|
|
|
// work out where we want the walk cycle to stop
|
|
var leftStop = selectedWalk.settings.stopAngleForwards + 180;
|
|
var rightStop = selectedWalk.settings.stopAngleForwards;
|
|
if( principleDirection === DIRECTION_BACKWARDS ) {
|
|
leftStop = selectedWalk.settings.stopAngleBackwards + 180;
|
|
rightStop = selectedWalk.settings.stopAngleBackwards;
|
|
}
|
|
|
|
// find the closest stop point from the walk wheel's angle
|
|
var angleToLeftStop = 180 - Math.abs( Math.abs( walkWheelPosition - leftStop ) - 180);
|
|
var angleToRightStop = 180 - Math.abs( Math.abs( walkWheelPosition - rightStop ) - 180);
|
|
if( walkWheelPosition > angleToLeftStop ) angleToLeftStop = 360 - angleToLeftStop;
|
|
if( walkWheelPosition > angleToRightStop ) angleToRightStop = 360 - angleToRightStop;
|
|
|
|
currentTransition.walkWheelIncrement = 6;
|
|
|
|
// keep the walkwheel turning by setting the walkWheelIncrement until our feet are tucked nicely underneath us.
|
|
if( angleToLeftStop < angleToRightStop ) {
|
|
|
|
currentTransition.walkStopAngle = leftStop;
|
|
|
|
} else {
|
|
|
|
currentTransition.walkStopAngle = rightStop;
|
|
}
|
|
|
|
} else {
|
|
|
|
// freeze wheel for sidestepping transitions
|
|
currentTransition.walkWheelIncrement = 0;
|
|
}
|
|
}
|
|
} // end if( currentTransition.walkingAtStart )
|
|
|
|
// calculate the Transition progress
|
|
var elapasedTime = (new Date().getTime() - currentTransition.startTime) / 1000;
|
|
currentTransition.progress = elapasedTime / currentTransition.transitionDuration;
|
|
transitionProgress = getBezier((1-currentTransition.progress), {x:0,y:0}, currentTransition.easingLower, currentTransition.easingUpper, {x:1,y:1}).y;
|
|
|
|
if(currentTransition.progress>=1) {
|
|
|
|
// time to kill off the transition
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
|
|
} else {
|
|
|
|
if( currentTransition.walkingAtStart ) {
|
|
|
|
if( INTERNAL_STATE !== SIDE_STEPPING ) {
|
|
|
|
// if at a stop angle, hold the walk wheel position for remainder of transition
|
|
var tolerance = 7; // must be greater than the walkWheel increment
|
|
if(( walkWheelPosition > (currentTransition.walkStopAngle - tolerance )) &&
|
|
( walkWheelPosition < (currentTransition.walkStopAngle + tolerance ))) {
|
|
|
|
currentTransition.walkWheelIncrement = 0;
|
|
}
|
|
// keep turning walk wheel until both feet are below the avi
|
|
walkWheelPosition += currentTransition.walkWheelIncrement;
|
|
currentTransition.walkWheelAdvance += currentTransition.walkWheelIncrement;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// will we need to use the walk wheel this frame?
|
|
if(currentAnimation === selectedWalk ||
|
|
currentAnimation === selectedSideStepLeft ||
|
|
currentAnimation === selectedSideStepRight ||
|
|
currentTransition !== null) {
|
|
|
|
// set the stride length
|
|
if( INTERNAL_STATE!==SIDE_STEPPING &&
|
|
INTERNAL_STATE!==CONFIG_SIDESTEP_LEFT &&
|
|
INTERNAL_STATE!==CONFIG_SIDESTEP_RIGHT &&
|
|
currentTransition===null ) {
|
|
|
|
// if the timing's right, take a snapshot of the stride max and recalibrate
|
|
var tolerance = 1.0; // higher the number, the higher the chance of a calibration taking place, but is traded off with lower accuracy
|
|
var strideOne = 40;
|
|
var strideTwo = 220;
|
|
|
|
if( principleDirection === DIRECTION_BACKWARDS ) {
|
|
strideOne = 130;
|
|
strideTwo = 300;
|
|
}
|
|
|
|
if(( walkWheelPosition < (strideOne+tolerance) && walkWheelPosition > (strideOne-tolerance) ) ||
|
|
( walkWheelPosition < (strideTwo+tolerance) && walkWheelPosition > (strideTwo-tolerance) )) {
|
|
|
|
// calculate the feet's offset from each other (in local Z only)
|
|
var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot"));
|
|
var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot"));
|
|
var footOffsetZ = Math.abs(footRPos.z - footLPos.z);
|
|
if(footOffsetZ>1) strideLength = 2 * footOffsetZ + aviFootSize.z; // sometimes getting very low value here - just ignore for now
|
|
if(statsOn) print('Stride length calibrated to '+strideLength.toFixed(4)+' metres at '+walkWheelPosition.toFixed(1)+' degrees');
|
|
if(principleDirection===DIRECTION_FORWARDS) {
|
|
currentAnimation.calibration.strideLengthForwards = strideLength;
|
|
} else if (principleDirection===DIRECTION_BACKWARDS) {
|
|
currentAnimation.calibration.strideLengthBackwards = strideLength;
|
|
}
|
|
|
|
} else {
|
|
|
|
if(principleDirection===DIRECTION_FORWARDS)
|
|
strideLength = currentAnimation.calibration.strideLengthForwards;
|
|
else if (principleDirection===DIRECTION_BACKWARDS)
|
|
strideLength = currentAnimation.calibration.strideLengthBackwards;
|
|
}
|
|
}
|
|
else if(( INTERNAL_STATE===SIDE_STEPPING ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) ) {
|
|
|
|
// calculate lateral stride - same same, but different
|
|
// if the timing's right, take a snapshot of the stride max and recalibrate the stride length
|
|
var tolerance = 1.0; // higher the number, the higher the chance of a calibration taking place, but is traded off with lower accuracy
|
|
if(principleDirection===DIRECTION_LEFT) {
|
|
|
|
if( walkWheelPosition < (3+tolerance) && walkWheelPosition > (3-tolerance) ) {
|
|
|
|
// calculate the feet's offset from the hips (in local X only)
|
|
var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot"));
|
|
var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot"));
|
|
var footOffsetX = Math.abs(footRPos.x - footLPos.x);
|
|
strideLength = footOffsetX;
|
|
if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees');
|
|
currentAnimation.calibration.strideLengthLeft = strideLength;
|
|
|
|
} else {
|
|
|
|
strideLength = currentAnimation.calibration.strideLengthLeft;
|
|
}
|
|
}
|
|
else if (principleDirection===DIRECTION_RIGHT) {
|
|
|
|
if( walkWheelPosition < (170+tolerance) && walkWheelPosition > (170-tolerance) ) {
|
|
|
|
// calculate the feet's offset from the hips (in local X only)
|
|
var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot"));
|
|
var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot"));
|
|
var footOffsetX = Math.abs(footRPos.x - footLPos.x);
|
|
strideLength = footOffsetX;
|
|
if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees');
|
|
currentAnimation.calibration.strideLengthRight = strideLength;
|
|
|
|
} else {
|
|
|
|
strideLength = currentAnimation.calibration.strideLengthRight;
|
|
}
|
|
}
|
|
} // end stride length calculations
|
|
|
|
// wrap the stride length around a 'surveyor's wheel' twice and calculate the angular velocity at the given (linear) velocity
|
|
// omega = v / r , where r = circumference / 2 PI , where circumference = 2 * stride length
|
|
var wheelRadius = strideLength / Math.PI;
|
|
var angularVelocity = velocity / wheelRadius;
|
|
|
|
// calculate the degrees turned (at this angular velocity) since last frame
|
|
var radiansTurnedSinceLastFrame = deltaTime * angularVelocity;
|
|
var degreesTurnedSinceLastFrame = radToDeg(radiansTurnedSinceLastFrame);
|
|
|
|
// if we are in an edit mode, we will need fake time to turn the wheel
|
|
if( INTERNAL_STATE!==WALKING &&
|
|
INTERNAL_STATE!==SIDE_STEPPING )
|
|
degreesTurnedSinceLastFrame = currentAnimation.settings.baseFrequency / 70;
|
|
|
|
if( walkWheelPosition >= 360 )
|
|
walkWheelPosition = walkWheelPosition % 360;
|
|
|
|
// advance the walk wheel the appropriate amount
|
|
if( currentTransition===null || currentTransition.walkingAtEnd )
|
|
walkWheelPosition += degreesTurnedSinceLastFrame;
|
|
|
|
// set the new values for the exact correct walk cycle speed at this velocity
|
|
adjustedFrequency = 1;
|
|
cycle = walkWheelPosition;
|
|
|
|
// show stats and walk wheel?
|
|
if(statsOn) {
|
|
|
|
var distanceTravelled = velocity * deltaTime;
|
|
var deltaTimeMS = deltaTime * 1000;
|
|
|
|
if( INTERNAL_STATE===SIDE_STEPPING ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
// draw the walk wheel turning around the z axis for sidestepping
|
|
var directionSign = 1;
|
|
if(principleDirection===DIRECTION_RIGHT) directionSign = -1;
|
|
var yOffset = hipsToFeetDistance - (wheelRadius/1.2); // /1.2 is a visual kludge, probably necessary because of either the 'avi feet penetrate floor' issue - TODO - once ground plane following is in Interface, lock this down
|
|
var sinWalkWheelPosition = wheelRadius * Math.sin(degToRad( directionSign * walkWheelPosition ));
|
|
var cosWalkWheelPosition = wheelRadius * Math.cos(degToRad( directionSign * -walkWheelPosition ));
|
|
var wheelXPos = {x: cosWalkWheelPosition, y:-sinWalkWheelPosition - yOffset, z: 0};
|
|
var wheelXEnd = {x: -cosWalkWheelPosition, y:sinWalkWheelPosition - yOffset, z: 0};
|
|
sinWalkWheelPosition = wheelRadius * Math.sin(degToRad( -directionSign * walkWheelPosition+90 ));
|
|
cosWalkWheelPosition = wheelRadius * Math.cos(degToRad( -directionSign * walkWheelPosition+90 ));
|
|
var wheelYPos = {x:cosWalkWheelPosition, y:sinWalkWheelPosition - yOffset, z: 0};
|
|
var wheelYEnd = {x:-cosWalkWheelPosition, y:-sinWalkWheelPosition - yOffset, z: 0};
|
|
Overlays.editOverlay(walkWheelYLine, {visible: true, position:wheelYPos, end:wheelYEnd});
|
|
Overlays.editOverlay(walkWheelZLine, {visible: true, position:wheelXPos, end:wheelXEnd});
|
|
|
|
} else {
|
|
|
|
// draw the walk wheel turning around the x axis for walking forwards or backwards
|
|
var yOffset = hipsToFeetDistance - (wheelRadius/1.2); // /1.2 is a visual kludge, probably necessary because of either the 'avi feet penetrate floor' issue - TODO - once ground plane following is in Interface, lock this down
|
|
var sinWalkWheelPosition = wheelRadius * Math.sin(degToRad((forwardModifier*-1) * walkWheelPosition));
|
|
var cosWalkWheelPosition = wheelRadius * Math.cos(degToRad((forwardModifier*-1) * -walkWheelPosition));
|
|
var wheelZPos = {x:0, y:-sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition};
|
|
var wheelZEnd = {x:0, y:sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition};
|
|
sinWalkWheelPosition = wheelRadius * Math.sin(degToRad(forwardModifier * walkWheelPosition+90));
|
|
cosWalkWheelPosition = wheelRadius * Math.cos(degToRad(forwardModifier * walkWheelPosition+90));
|
|
var wheelYPos = {x:0, y:sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition};
|
|
var wheelYEnd = {x:0, y:-sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition};
|
|
Overlays.editOverlay(walkWheelYLine, { visible: true, position:wheelYPos, end:wheelYEnd });
|
|
Overlays.editOverlay(walkWheelZLine, { visible: true, position:wheelZPos, end:wheelZEnd });
|
|
}
|
|
|
|
// populate stats overlay
|
|
var walkWheelInfo =
|
|
' Walk Wheel Stats\n--------------------------------------\n \n \n'
|
|
+ '\nFrame time: '+deltaTimeMS.toFixed(2)
|
|
+ ' mS\nVelocity: '+velocity.toFixed(2)
|
|
+ ' m/s\nDistance: '+distanceTravelled.toFixed(3)
|
|
+ ' m\nOmega: '+angularVelocity.toFixed(3)
|
|
+ ' rad / s\nDeg to turn: '+degreesTurnedSinceLastFrame.toFixed(2)
|
|
+ ' deg\nWheel position: '+cycle.toFixed(1)
|
|
+ ' deg\nWheel radius: '+wheelRadius.toFixed(3)
|
|
+ ' m\nHips To Feet: '+hipsToFeetDistance.toFixed(3)
|
|
+ ' m\nStride: '+strideLength.toFixed(3)
|
|
+ ' m\n';
|
|
Overlays.editOverlay(walkWheelStats, {text: walkWheelInfo});
|
|
}
|
|
} // end of walk wheel and stride length calculation
|
|
|
|
|
|
// Start applying motion
|
|
var pitchOscillation = 0;
|
|
var yawOscillation = 0;
|
|
var rollOscillation = 0;
|
|
var pitchOscillationLast = 0;
|
|
var yawOscillationLast = 0;
|
|
var rollOscillationLast = 0;
|
|
var pitchOffset = 0;
|
|
var yawOffset = 0;
|
|
var rollOffset = 0;
|
|
var pitchOffsetLast = 0;
|
|
var yawOffsetLast = 0;
|
|
var rollOffsetLast = 0;
|
|
|
|
// calcualte any hips translation
|
|
// Note: can only apply hips translations whilst in a config (edit) mode at present, not whilst under locomotion
|
|
if( INTERNAL_STATE===CONFIG_WALK_STYLES ||
|
|
INTERNAL_STATE===CONFIG_WALK_TWEAKS ||
|
|
INTERNAL_STATE===CONFIG_WALK_JOINTS ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ||
|
|
INTERNAL_STATE===CONFIG_FLYING ||
|
|
INTERNAL_STATE===CONFIG_FLYING_UP ||
|
|
INTERNAL_STATE===CONFIG_FLYING_DOWN ) {
|
|
|
|
// calculate hips translation
|
|
var motorOscillation = Math.sin(degToRad((cycle * adjustedFrequency * 2) + currentAnimation.joints[0].thrustPhase)) + currentAnimation.joints[0].thrustOffset;
|
|
var swayOscillation = Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[0].swayPhase)) + currentAnimation.joints[0].swayOffset;
|
|
var bobOscillation = Math.sin(degToRad((cycle * adjustedFrequency * 2) + currentAnimation.joints[0].bobPhase)) + currentAnimation.joints[0].bobOffset;
|
|
|
|
// apply hips translation
|
|
translateHips({x:swayOscillation*currentAnimation.joints[0].sway, y:motorOscillation*currentAnimation.joints[0].thrust, z:bobOscillation*currentAnimation.joints[0].bob});
|
|
}
|
|
|
|
// hips rotation
|
|
// apply the current Transition?
|
|
if(currentTransition!==null) {
|
|
|
|
if( currentTransition.walkingAtStart ) {
|
|
|
|
pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2)
|
|
+ currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset;
|
|
|
|
rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset);
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[0].pitch * Math.sin(degToRad(( walkWheelPosition * 2)
|
|
+ currentTransition.lastAnimation.joints[0].pitchPhase)) + currentTransition.lastAnimation.joints[0].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[0].yaw * Math.sin(degToRad(( walkWheelPosition )
|
|
+ currentTransition.lastAnimation.joints[0].yawPhase)) + currentTransition.lastAnimation.joints[0].yawOffset;
|
|
|
|
rollOscillationLast = (currentTransition.lastAnimation.joints[0].roll * Math.sin(degToRad(( walkWheelPosition )
|
|
+ currentTransition.lastAnimation.joints[0].rollPhase)) + currentTransition.lastAnimation.joints[0].rollOffset);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad((cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset;
|
|
|
|
rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad((cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset);
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[0].pitch * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2)
|
|
+ currentTransition.lastAnimation.joints[0].pitchPhase)) + currentTransition.lastAnimation.joints[0].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[0].yaw * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[0].yawPhase)) + currentTransition.lastAnimation.joints[0].yawOffset;
|
|
|
|
rollOscillationLast = (currentTransition.lastAnimation.joints[0].roll * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[0].rollPhase)) + currentTransition.lastAnimation.joints[0].rollOffset);
|
|
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad((cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset;
|
|
|
|
rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad((cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset);
|
|
}
|
|
|
|
// apply hips rotation
|
|
MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees(-pitchOscillation + (leanPitchModifier * getLeanPitch(velocity)), // getLeanPitch - lean forwards as velocity increases
|
|
yawOscillation, // Yup, that's correct ;-)
|
|
rollOscillation + getLeanRoll(deltaTime, velocity))); // getLeanRoll - banking on cornering
|
|
|
|
// upper legs
|
|
if( INTERNAL_STATE!==SIDE_STEPPING &&
|
|
INTERNAL_STATE!==CONFIG_SIDESTEP_LEFT &&
|
|
INTERNAL_STATE!==CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
// apply the current Transition to the upper legs?
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase)));
|
|
yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[1].yawPhase));
|
|
rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[1].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[1].pitchOffset;
|
|
yawOffset = currentAnimation.joints[1].yawOffset;
|
|
rollOffset = currentAnimation.joints[1].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[1].pitch
|
|
* Math.sin(degToRad( walkWheelPosition + (forwardModifier * currentTransition.lastAnimation.joints[1].pitchPhase )));
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[1].yaw
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[1].yawPhase ));
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[1].roll
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[1].rollPhase ));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[1].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[1].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[1].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase)));
|
|
yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase));
|
|
rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[1].pitchOffset;
|
|
yawOffset = currentAnimation.joints[1].yawOffset;
|
|
rollOffset = currentAnimation.joints[1].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[1].pitch
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ (forwardModifier * currentTransition.lastAnimation.joints[1].pitchPhase )));
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[1].yaw
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[1].yawPhase ));
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[1].roll
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[1].rollPhase ));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[1].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[1].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[1].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast);
|
|
yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast);
|
|
rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase)));
|
|
yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase));
|
|
rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[1].pitchOffset;
|
|
yawOffset = currentAnimation.joints[1].yawOffset;
|
|
rollOffset = currentAnimation.joints[1].rollOffset;
|
|
}
|
|
|
|
// apply the upper leg rotations
|
|
MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, -rollOscillation - rollOffset ));
|
|
MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, -rollOscillation + rollOffset ));
|
|
|
|
|
|
// lower leg
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].yawPhase));
|
|
rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[2].pitchOffset;
|
|
yawOffset = currentAnimation.joints[2].yawOffset;
|
|
rollOffset = currentAnimation.joints[2].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[2].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].pitchPhase));
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[2].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].yawPhase));
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[2].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].rollPhase));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[2].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[2].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[2].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase));
|
|
rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[2].pitchOffset;
|
|
yawOffset = currentAnimation.joints[2].yawOffset;
|
|
rollOffset = currentAnimation.joints[2].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[2].pitch
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[2].pitchPhase));
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[2].yaw
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[2].yawPhase));
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[2].roll
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[2].rollPhase));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[2].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[2].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[2].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = ( transitionProgress * pitchOscillation ) + ( (1-transitionProgress) * pitchOscillationLast );
|
|
yawOscillation = ( transitionProgress * yawOscillation ) + ( (1-transitionProgress) * yawOscillationLast );
|
|
rollOscillation = ( transitionProgress * rollOscillation ) + ( (1-transitionProgress) * rollOscillationLast );
|
|
|
|
pitchOffset = ( transitionProgress * pitchOffset ) + ( (1-transitionProgress) * pitchOffsetLast );
|
|
yawOffset = ( transitionProgress * yawOffset ) + ( (1-transitionProgress) * yawOffsetLast );
|
|
rollOffset = ( transitionProgress * rollOffset ) + ( (1-transitionProgress) * rollOffsetLast );
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[2].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase ));
|
|
yawOscillation = currentAnimation.joints[2].yaw * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase ));
|
|
rollOscillation = currentAnimation.joints[2].roll * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase ));
|
|
|
|
pitchOffset = currentAnimation.joints[2].pitchOffset;
|
|
yawOffset = currentAnimation.joints[2].yawOffset;
|
|
rollOffset = currentAnimation.joints[2].rollOffset;
|
|
}
|
|
|
|
// apply lower leg joint rotations
|
|
MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation - rollOffset ));
|
|
MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, rollOscillation + rollOffset ));
|
|
|
|
} // end if !SIDE_STEPPING
|
|
|
|
else if( INTERNAL_STATE===SIDE_STEPPING ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
// sidestepping uses the sinewave generators slightly differently for the legs
|
|
pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase));
|
|
rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase));
|
|
|
|
// apply upper leg rotations for sidestepping
|
|
MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees(
|
|
-pitchOscillation + currentAnimation.joints[1].pitchOffset,
|
|
yawOscillation + currentAnimation.joints[1].yawOffset,
|
|
rollOscillation + currentAnimation.joints[1].rollOffset ));
|
|
MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees(
|
|
pitchOscillation + currentAnimation.joints[1].pitchOffset,
|
|
yawOscillation - currentAnimation.joints[1].yawOffset,
|
|
-rollOscillation - currentAnimation.joints[1].rollOffset ));
|
|
|
|
// calculate lower leg joint rotations for sidestepping
|
|
pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase));
|
|
rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase));
|
|
|
|
// apply lower leg joint rotations
|
|
MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees(
|
|
-pitchOscillation + currentAnimation.joints[2].pitchOffset,
|
|
yawOscillation - currentAnimation.joints[2].yawOffset,
|
|
rollOscillation - currentAnimation.joints[2].rollOffset)); // TODO: needs a kick just before fwd peak
|
|
MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees(
|
|
pitchOscillation + currentAnimation.joints[2].pitchOffset,
|
|
yawOscillation + currentAnimation.joints[2].yawOffset,
|
|
rollOscillation + currentAnimation.joints[2].rollOffset));
|
|
}
|
|
|
|
// feet
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].yawPhase));
|
|
rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[3].pitchOffset;
|
|
yawOffset = currentAnimation.joints[3].yawOffset;
|
|
rollOffset = currentAnimation.joints[3].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[3].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].pitchPhase));
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[3].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].yawPhase));
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[3].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].rollPhase));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[3].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[3].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[3].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].yawPhase));
|
|
rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[3].pitchOffset;
|
|
yawOffset = currentAnimation.joints[3].yawOffset;
|
|
rollOffset = currentAnimation.joints[3].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[3].pitch
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[3].pitchPhase));
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[3].yaw
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[3].yawPhase));
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[3].roll
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[3].rollPhase));
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[3].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[3].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[3].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast);
|
|
yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast);
|
|
rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].yawPhase));
|
|
rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].rollPhase));
|
|
|
|
pitchOffset = currentAnimation.joints[3].pitchOffset;
|
|
yawOffset = currentAnimation.joints[3].yawOffset;
|
|
rollOffset = currentAnimation.joints[3].rollOffset;
|
|
}
|
|
|
|
// apply foot rotations
|
|
MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, rollOscillation + rollOffset ));
|
|
MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation - rollOffset ));
|
|
|
|
// play footfall sound yet? To determine this, we take the differential of the foot's pitch curve to decide when the foot hits the ground.
|
|
if( INTERNAL_STATE===WALKING ||
|
|
INTERNAL_STATE===SIDE_STEPPING ||
|
|
INTERNAL_STATE===CONFIG_WALK_STYLES ||
|
|
INTERNAL_STATE===CONFIG_WALK_TWEAKS ||
|
|
INTERNAL_STATE===CONFIG_WALK_JOINTS ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
// finding dy/dx is as simple as determining the cosine wave for the foot's pitch function.
|
|
var feetPitchDifferential = Math.cos(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase));
|
|
var threshHold = 0.9; // sets the audio trigger point. with accuracy.
|
|
if(feetPitchDifferential<-threshHold &&
|
|
nextStep===DIRECTION_LEFT &&
|
|
principleDirection!==DIRECTION_UP &&
|
|
principleDirection!==DIRECTION_DOWN) {
|
|
|
|
playFootstep(DIRECTION_LEFT);
|
|
nextStep = DIRECTION_RIGHT;
|
|
}
|
|
else if(feetPitchDifferential>threshHold &&
|
|
nextStep===DIRECTION_RIGHT &&
|
|
principleDirection!==DIRECTION_UP &&
|
|
principleDirection!==DIRECTION_DOWN) {
|
|
|
|
playFootstep(DIRECTION_RIGHT);
|
|
nextStep = DIRECTION_LEFT;
|
|
}
|
|
}
|
|
|
|
// toes
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset;
|
|
rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[4].pitchOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[4].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].pitchPhase));
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[4].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].yawPhase)) + currentTransition.lastAnimation.joints[4].yawOffset;;
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[4].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].rollPhase))+ currentTransition.lastAnimation.joints[4].rollOffset;
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset;
|
|
rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[4].pitchOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[4].pitch
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[4].pitchPhase));
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[4].yaw
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[4].yawPhase)) + currentTransition.lastAnimation.joints[4].yawOffset;;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[4].roll
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[4].rollPhase))+ currentTransition.lastAnimation.joints[4].rollOffset;
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset;
|
|
rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[4].pitchOffset;
|
|
}
|
|
|
|
// apply toe rotations
|
|
MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees(-pitchOscillation + pitchOffset, yawOscillation, rollOscillation));
|
|
MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation, rollOscillation));
|
|
|
|
// spine
|
|
if( currentTransition !== null ) {
|
|
|
|
if( currentTransition.walkingAtStart ) {
|
|
|
|
pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2 ) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[5].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset;
|
|
rollOscillation = currentAnimation.joints[5].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset;
|
|
|
|
// calculate where we would have been if we'd continued in the last state
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[5].pitch
|
|
* Math.sin(degToRad(( walkWheelPosition * 2 ) + currentTransition.lastAnimation.joints[5].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[5].pitchOffset;
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[5].yaw
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[5].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[5].yawOffset;
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[5].roll
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[5].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[5].rollOffset;
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[5].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[5].yaw * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset;
|
|
|
|
rollOscillation = currentAnimation.joints[5].roll * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[5].pitch
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2 )
|
|
+ currentTransition.lastAnimation.joints[5].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[5].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[5].yaw
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[5].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[5].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[5].roll
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[5].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[5].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[5].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset;
|
|
rollOscillation = currentAnimation.joints[5].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset;
|
|
}
|
|
|
|
// apply spine joint rotations
|
|
MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation ));
|
|
|
|
// spine 1
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[6].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset;
|
|
rollOscillation = currentAnimation.joints[6].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[6].pitch
|
|
* Math.sin(degToRad(( walkWheelPosition * 2 ) + currentTransition.lastAnimation.joints[6].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[6].pitchOffset;
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[6].yaw
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[6].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[6].yawOffset;
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[6].roll
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[6].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[6].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[6].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[6].yaw * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset;
|
|
|
|
rollOscillation = currentAnimation.joints[6].roll * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[6].pitch
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2 )
|
|
+ currentTransition.lastAnimation.joints[6].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[6].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[6].yaw
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[6].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[6].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[6].roll
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[6].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[6].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[6].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset;
|
|
rollOscillation = currentAnimation.joints[6].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset;
|
|
}
|
|
// apply spine1 joint rotations
|
|
MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation ));
|
|
|
|
// spine 2
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[7].pitchPhase)) + currentAnimation.joints[7].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[7].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[7].yawPhase)) + currentAnimation.joints[7].yawOffset;
|
|
rollOscillation = currentAnimation.joints[7].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[7].rollPhase)) + currentAnimation.joints[7].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[7].pitch
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[7].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[7].yaw
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[7].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[7].roll
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[7].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[7].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[7].pitchPhase))
|
|
+ currentAnimation.joints[7].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[7].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[7].yawPhase))
|
|
+ currentAnimation.joints[7].yawOffset;
|
|
|
|
rollOscillation = currentAnimation.joints[7].roll
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[7].rollPhase))
|
|
+ currentAnimation.joints[7].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[7].pitch
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[7].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[7].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[7].yaw
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[7].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[7].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[7].roll
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[7].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[7].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[7].pitchPhase))
|
|
+ currentAnimation.joints[7].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[7].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[7].yawPhase))
|
|
+ currentAnimation.joints[7].yawOffset;
|
|
|
|
rollOscillation = currentAnimation.joints[7].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[7].rollPhase))
|
|
+ currentAnimation.joints[7].rollOffset;
|
|
}
|
|
// apply spine2 joint rotations
|
|
MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation ));
|
|
|
|
if(!armsFree) {
|
|
|
|
// shoulders
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[8].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[8].yawPhase));
|
|
|
|
rollOscillation = currentAnimation.joints[8].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2)
|
|
+ currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset;
|
|
|
|
yawOffset = currentAnimation.joints[8].yawOffset;
|
|
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[8].pitch
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[8].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[8].yaw
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].yawPhase))
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[8].roll
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[8].rollOffset;
|
|
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[8].yawOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[8].pitch * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[8].yaw * Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[8].yawPhase));
|
|
|
|
rollOscillation = currentAnimation.joints[8].roll * Math.sin( degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset;
|
|
|
|
yawOffset = currentAnimation.joints[8].yawOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[8].pitch
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[8].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[8].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[8].yaw
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[8].yawPhase))
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[8].roll
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[8].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[8].rollOffset;
|
|
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[8].yawOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[8].yaw * Math.sin(degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[8].yawPhase));
|
|
|
|
rollOscillation = currentAnimation.joints[8].roll * Math.sin(degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset;
|
|
|
|
yawOffset = currentAnimation.joints[8].yawOffset;
|
|
}
|
|
|
|
MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation + yawOffset, rollOscillation ));
|
|
MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation - yawOffset, -rollOscillation ));
|
|
|
|
// upper arms
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[9].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[9].pitchPhase));
|
|
yawOscillation = currentAnimation.joints[9].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[9].yawPhase));
|
|
rollOscillation = currentAnimation.joints[9].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[9].rollPhase)) + currentAnimation.joints[9].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[9].pitchOffset;
|
|
yawOffset = currentAnimation.joints[9].yawOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[9].pitch
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].pitchPhase))
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[9].yaw
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].yawPhase))
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[9].roll
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[9].rollOffset;
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[9].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[9].yawOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[9].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[9].pitchPhase));
|
|
|
|
yawOscillation = currentAnimation.joints[9].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[9].yawPhase));
|
|
|
|
rollOscillation = currentAnimation.joints[9].roll
|
|
* Math.sin(degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[9].rollPhase))
|
|
+ currentAnimation.joints[9].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[9].pitchOffset;
|
|
yawOffset = currentAnimation.joints[9].yawOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[9].pitch
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[9].pitchPhase))
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[9].yaw
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[9].yawPhase))
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[9].roll
|
|
* Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[9].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[9].rollOffset;
|
|
|
|
pitchOffsetLast = currentTransition.lastAnimation.joints[9].pitchOffset;
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[9].yawOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast);
|
|
yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[9].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[9].pitchPhase));
|
|
|
|
yawOscillation = currentAnimation.joints[9].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[9].yawPhase));
|
|
|
|
rollOscillation = currentAnimation.joints[9].roll
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency * 2)
|
|
+ currentAnimation.joints[9].rollPhase))
|
|
+ currentAnimation.joints[9].rollOffset;
|
|
|
|
pitchOffset = currentAnimation.joints[9].pitchOffset;
|
|
yawOffset = currentAnimation.joints[9].yawOffset;
|
|
|
|
}
|
|
MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation ));
|
|
MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, -rollOscillation ));
|
|
|
|
// forearms
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[10].pitch
|
|
* Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[10].pitchPhase ))
|
|
+ currentAnimation.joints[10].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[10].yaw
|
|
* Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[10].yawPhase ));
|
|
|
|
rollOscillation = currentAnimation.joints[10].roll
|
|
* Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[10].rollPhase ));
|
|
|
|
yawOffset = currentAnimation.joints[10].yawOffset;
|
|
rollOffset = currentAnimation.joints[10].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[10].pitch
|
|
* Math.sin( degToRad(( walkWheelPosition )
|
|
+ currentTransition.lastAnimation.joints[10].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[10].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[10].yaw
|
|
* Math.sin( degToRad(( walkWheelPosition )
|
|
+ currentTransition.lastAnimation.joints[10].yawPhase));
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[10].roll
|
|
* Math.sin( degToRad(( walkWheelPosition )
|
|
+ currentTransition.lastAnimation.joints[10].rollPhase));
|
|
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[10].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[10].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[10].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].pitchPhase ))
|
|
+ currentAnimation.joints[10].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[10].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].yawPhase ));
|
|
|
|
rollOscillation = currentAnimation.joints[10].roll
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].rollPhase ));
|
|
|
|
yawOffset = currentAnimation.joints[10].yawOffset;
|
|
rollOffset = currentAnimation.joints[10].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[10].pitch
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[10].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[10].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[10].yaw
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[10].yawPhase));
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[10].roll
|
|
* Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[10].rollPhase));
|
|
|
|
yawOffsetLast = currentTransition.lastAnimation.joints[10].yawOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[10].rollOffset;
|
|
}
|
|
|
|
// blend the previous and next
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = -(transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast);
|
|
rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[10].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].pitchPhase ))
|
|
+ currentAnimation.joints[10].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[10].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].yawPhase ));
|
|
|
|
rollOscillation = currentAnimation.joints[10].roll
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[10].rollPhase ));
|
|
|
|
yawOffset = currentAnimation.joints[10].yawOffset;
|
|
rollOffset = currentAnimation.joints[10].rollOffset;
|
|
}
|
|
|
|
// apply forearms rotations
|
|
MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + yawOffset, rollOscillation + rollOffset ));
|
|
MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - yawOffset, rollOscillation - rollOffset ));
|
|
|
|
// hands
|
|
var sideStepSign = 1;
|
|
if(INTERNAL_STATE===SIDE_STEPPING) {
|
|
sideStepSign = 1;
|
|
}
|
|
if(currentTransition!==null) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[11].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset;
|
|
rollOscillation = currentAnimation.joints[11].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].rollPhase)) ;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[11].pitch
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[11].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[11].yaw
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[11].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[11].roll
|
|
* Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].rollPhase))
|
|
|
|
rollOffset = currentAnimation.joints[11].rollOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[11].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[11].pitch
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[11].pitchPhase))
|
|
+ currentAnimation.joints[11].pitchOffset;
|
|
|
|
yawOscillation = currentAnimation.joints[11].yaw
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[11].yawPhase))
|
|
+ currentAnimation.joints[11].yawOffset;
|
|
|
|
rollOscillation = currentAnimation.joints[11].roll
|
|
* Math.sin( degToRad(( cycle * adjustedFrequency )
|
|
+ currentAnimation.joints[11].rollPhase));
|
|
|
|
rollOffset = currentAnimation.joints[11].rollOffset;
|
|
|
|
pitchOscillationLast = currentTransition.lastAnimation.joints[11].pitch
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[11].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[11].pitchOffset;
|
|
|
|
yawOscillationLast = currentTransition.lastAnimation.joints[11].yaw
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[11].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[11].yawOffset;
|
|
|
|
rollOscillationLast = currentTransition.lastAnimation.joints[11].roll
|
|
* Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency
|
|
+ currentTransition.lastAnimation.joints[11].rollPhase))
|
|
|
|
rollOffset = currentAnimation.joints[11].rollOffset;
|
|
rollOffsetLast = currentTransition.lastAnimation.joints[11].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset;
|
|
yawOscillation = currentAnimation.joints[11].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset;
|
|
rollOscillation = currentAnimation.joints[11].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].rollPhase));
|
|
|
|
rollOffset = currentAnimation.joints[11].rollOffset;
|
|
}
|
|
|
|
// set the hand rotations
|
|
MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees( sideStepSign * pitchOscillation, yawOscillation, rollOscillation + rollOffset));
|
|
MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollDegrees( pitchOscillation, -yawOscillation, rollOscillation - rollOffset));
|
|
|
|
} // end if(!armsFree)
|
|
|
|
// head (includes neck joint) - currently zeroed out in STANDING animation files by request
|
|
if( currentTransition !== null ) {
|
|
|
|
if(currentTransition.walkingAtStart) {
|
|
|
|
pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2)
|
|
+ currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset;
|
|
|
|
yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset;
|
|
|
|
rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency )
|
|
+ currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset;
|
|
|
|
pitchOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].pitch
|
|
* Math.sin(degToRad(( walkWheelPosition * 2) + currentTransition.lastAnimation.joints[12].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[12].pitchOffset;
|
|
|
|
yawOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].yaw
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[12].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[12].yawOffset;
|
|
|
|
rollOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].roll
|
|
* Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[12].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[12].rollOffset;
|
|
|
|
} else {
|
|
|
|
pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset;
|
|
yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset;
|
|
rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset;
|
|
|
|
pitchOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].pitch
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2)
|
|
+ currentTransition.lastAnimation.joints[12].pitchPhase))
|
|
+ currentTransition.lastAnimation.joints[12].pitchOffset;
|
|
|
|
yawOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].yaw
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[12].yawPhase))
|
|
+ currentTransition.lastAnimation.joints[12].yawOffset;
|
|
|
|
rollOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].roll
|
|
* Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency )
|
|
+ currentTransition.lastAnimation.joints[12].rollPhase))
|
|
+ currentTransition.lastAnimation.joints[12].rollOffset;
|
|
}
|
|
|
|
pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast);
|
|
yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast);
|
|
rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast);
|
|
|
|
} else {
|
|
|
|
pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset;
|
|
yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset;
|
|
rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset;
|
|
}
|
|
|
|
MyAvatar.setJointData( "Head", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation ));
|
|
MyAvatar.setJointData( "Neck", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation ));
|
|
}
|
|
|
|
|
|
|
|
// Bezier function for applying to transitions - src: Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/
|
|
Coord = function (x,y) {
|
|
if(!x) var x=0;
|
|
if(!y) var y=0;
|
|
return {x: x, y: y};
|
|
}
|
|
|
|
function B1(t) { return t*t*t }
|
|
function B2(t) { return 3*t*t*(1-t) }
|
|
function B3(t) { return 3*t*(1-t)*(1-t) }
|
|
function B4(t) { return (1-t)*(1-t)*(1-t) }
|
|
|
|
function getBezier(percent,C1,C2,C3,C4) {
|
|
var pos = new Coord();
|
|
pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent);
|
|
pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent);
|
|
return pos;
|
|
}
|
|
|
|
// Butterworth LP filter - coeffs calculated using: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html
|
|
var NZEROS = 8;
|
|
var NPOLES = 8;
|
|
var GAIN = 17.40692157;
|
|
var xv = [0,0,0,0,0,0,0,0,0]; //xv.length = NZEROS+1;
|
|
var yv = [0,0,0,0,0,0,0,0,0]; //yv.length = NPOLES+1;
|
|
|
|
function filterButterworth(nextInputValue)
|
|
{
|
|
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8];
|
|
xv[8] = nextInputValue / GAIN;
|
|
yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8];
|
|
yv[8] = (xv[0] + xv[8]) + 8 * (xv[1] + xv[7]) + 28 * (xv[2] + xv[6])
|
|
+ 56 * (xv[3] + xv[5]) + 70 * xv[4]
|
|
+ ( -0.0033008230 * yv[0]) + ( -0.0440409341 * yv[1])
|
|
+ ( -0.2663485333 * yv[2]) + ( -0.9570250765 * yv[3])
|
|
+ ( -2.2596729000 * yv[4]) + ( -3.6088345059 * yv[5])
|
|
+ ( -3.9148571397 * yv[6]) + ( -2.6527135283 * yv[7]);
|
|
return yv[8];
|
|
}
|
|
|
|
// the faster we go, the further we lean forward. the angle is calcualted here
|
|
var leanAngles = []; // smooth out and add damping with simple averaging filter.
|
|
leanAngles.length = 15;
|
|
|
|
function getLeanPitch(velocity) {
|
|
|
|
if(velocity>TERMINAL_VELOCITY) velocity=TERMINAL_VELOCITY;
|
|
var leanProgress = velocity / TERMINAL_VELOCITY;
|
|
var responseSharpness = 1.8;
|
|
if(principleDirection==DIRECTION_BACKWARDS) responseSharpness = 3.6; // lean back a bit extra when walking backwards
|
|
var leanProgressBezier = getBezier((1-leanProgress),{x:0,y:0},{x:0,y:responseSharpness},{x:0,y:1},{x:1,y:1}).y;
|
|
|
|
// simple averaging filter seems to give best results
|
|
leanAngles.push(leanProgressBezier);
|
|
leanAngles.shift(); // FIFO
|
|
var totalLeanAngles = 0;
|
|
for(ea in leanAngles) totalLeanAngles += leanAngles[ea];
|
|
var leanProgressAverageFiltered = totalLeanAngles / leanAngles.length;
|
|
|
|
// calculate final return value
|
|
var leanPitchFinal = 0;
|
|
if(principleDirection===DIRECTION_BACKWARDS) {
|
|
leanPitchFinal = -currentAnimation.settings.flyingHipsPitch * leanProgressAverageFiltered;// + finalAccelerationResponse;
|
|
} else {
|
|
leanPitchFinal = currentAnimation.settings.flyingHipsPitch * leanProgressAverageFiltered;// + finalAccelerationResponse;
|
|
}
|
|
return leanPitchFinal;
|
|
}
|
|
|
|
// calculate the angle at which to bank into corners when turning
|
|
var leanRollAngles = []; // smooth out and add damping with simple averaging filter
|
|
leanRollAngles.length = 25;
|
|
|
|
var angularVelocities = []; // keep a record of the last few so can filter out spurious values
|
|
angularVelocities.length = 5;
|
|
|
|
function getLeanRoll(deltaTime, velocity) {
|
|
|
|
// what's our current anglular velocity?
|
|
var angularVelocityMax = 70; // from observation
|
|
var currentOrientationVec3 = Quat.safeEulerAngles(MyAvatar.orientation);
|
|
var lastOrientationVec3 = Quat.safeEulerAngles(lastOrientation);
|
|
var deltaYaw = lastOrientationVec3.y-currentOrientationVec3.y;
|
|
lastOrientation = MyAvatar.orientation;
|
|
|
|
var angularVelocity = deltaYaw / deltaTime;
|
|
if(angularVelocity>angularVelocityMax) angularVelocity = angularVelocityMax;
|
|
if(angularVelocity<-angularVelocityMax) angularVelocity = -angularVelocityMax;
|
|
|
|
// filter the angular velocity for a nicer response and a bit of wobble (intentional overshoot / ringing)
|
|
angularVelocity = filterButterworth(angularVelocity);
|
|
|
|
var turnSign = 1;
|
|
if(angularVelocity<0) turnSign = -1;
|
|
if(principleDirection===DIRECTION_BACKWARDS)
|
|
turnSign *= -1;
|
|
|
|
// calculate the amount of roll based on both angular and linear velocities
|
|
if(velocity>TERMINAL_VELOCITY) velocity = TERMINAL_VELOCITY;
|
|
var leanRollProgress = (velocity / TERMINAL_VELOCITY) * (Math.abs(angularVelocity) / angularVelocityMax);
|
|
|
|
// apply our response curve
|
|
var leanRollProgressBezier = getBezier((1-leanRollProgress),{x:0,y:0},{x:0,y:2.5},{x:0,y:1},{x:1,y:1}).y;
|
|
|
|
// simple averaging filter
|
|
leanRollAngles.push(turnSign * leanRollProgressBezier);
|
|
leanRollAngles.shift(); // FIFO
|
|
var totalLeanRollAngles = 0;
|
|
for(var ea in leanRollAngles) totalLeanRollAngles += leanRollAngles[ea];
|
|
var leanRollProgressAverageFiltered = totalLeanRollAngles / leanRollAngles.length;
|
|
|
|
return currentAnimation.settings.maxBankingAngle * leanRollProgressAverageFiltered;
|
|
}
|
|
|
|
// set up the interface components, update the internal state and kick off any transitions
|
|
function setInternalState(newInternalState) {
|
|
|
|
switch(newInternalState) {
|
|
|
|
case WALKING:
|
|
|
|
if(!minimised) doStandardMenu();
|
|
INTERNAL_STATE = WALKING;
|
|
return;
|
|
|
|
case FLYING:
|
|
|
|
if(!minimised) doStandardMenu();
|
|
INTERNAL_STATE = FLYING;
|
|
return;
|
|
|
|
case SIDE_STEPPING:
|
|
|
|
if(!minimised) doStandardMenu();
|
|
INTERNAL_STATE = SIDE_STEPPING;
|
|
return;
|
|
|
|
case CONFIG_WALK_STYLES:
|
|
|
|
INTERNAL_STATE = CONFIG_WALK_STYLES;
|
|
currentAnimation = selectedWalk;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
hideJointControls();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(true);
|
|
setBackground(controlsBackgroundWalkEditStyles);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configWalkStylesButtonSelected);
|
|
setButtonOverlayVisible(configWalkTweaksButton);
|
|
setButtonOverlayVisible(configWalkJointsButton);
|
|
setButtonOverlayVisible(backButton);
|
|
setSliderThumbsVisible(false);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_WALK_TWEAKS:
|
|
|
|
INTERNAL_STATE = CONFIG_WALK_TWEAKS;
|
|
currentAnimation = selectedWalk;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
hideJointControls();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditTweaks);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configWalkStylesButton);
|
|
setButtonOverlayVisible(configWalkTweaksButtonSelected);
|
|
setButtonOverlayVisible(configWalkJointsButton);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseWalkTweaks();
|
|
}
|
|
return;
|
|
|
|
case CONFIG_WALK_JOINTS:
|
|
|
|
INTERNAL_STATE = CONFIG_WALK_JOINTS;
|
|
currentAnimation = selectedWalk;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configWalkStylesButton);
|
|
setButtonOverlayVisible(configWalkTweaksButton);
|
|
setButtonOverlayVisible(configWalkJointsButtonSelected);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_STANDING:
|
|
|
|
INTERNAL_STATE = CONFIG_STANDING;
|
|
currentAnimation = selectedStand;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configSideStepRightButton);
|
|
setButtonOverlayVisible(configSideStepLeftButton);
|
|
setButtonOverlayVisible(configStandButtonSelected);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_SIDESTEP_LEFT:
|
|
|
|
INTERNAL_STATE = CONFIG_SIDESTEP_LEFT;
|
|
currentAnimation = selectedSideStepLeft;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configSideStepRightButton);
|
|
setButtonOverlayVisible(configSideStepLeftButtonSelected);
|
|
setButtonOverlayVisible(configStandButton);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_SIDESTEP_RIGHT:
|
|
|
|
INTERNAL_STATE = CONFIG_SIDESTEP_RIGHT;
|
|
currentAnimation = selectedSideStepRight;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configSideStepRightButtonSelected);
|
|
setButtonOverlayVisible(configSideStepLeftButton);
|
|
setButtonOverlayVisible(configStandButton);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_FLYING:
|
|
|
|
INTERNAL_STATE = CONFIG_FLYING;
|
|
currentAnimation = selectedFly;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configFlyingUpButton);
|
|
setButtonOverlayVisible(configFlyingDownButton);
|
|
setButtonOverlayVisible(configFlyingButtonSelected);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_FLYING_UP:
|
|
|
|
INTERNAL_STATE = CONFIG_FLYING_UP;
|
|
currentAnimation = selectedFlyUp;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configFlyingUpButtonSelected);
|
|
setButtonOverlayVisible(configFlyingDownButton);
|
|
setButtonOverlayVisible(configFlyingButton);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case CONFIG_FLYING_DOWN:
|
|
|
|
INTERNAL_STATE = CONFIG_FLYING_DOWN;
|
|
currentAnimation = selectedFlyDown;
|
|
if(!minimised) {
|
|
hidebuttonOverlays();
|
|
showFrontPanelButtons(false);
|
|
showWalkStyleButtons(false);
|
|
setBackground(controlsBackgroundWalkEditJoints);
|
|
setButtonOverlayVisible(onButton);
|
|
setButtonOverlayVisible(configFlyingUpButton);
|
|
setButtonOverlayVisible(configFlyingDownButtonSelected);
|
|
setButtonOverlayVisible(configFlyingButton);
|
|
setButtonOverlayVisible(backButton);
|
|
initialiseJointsEditingPanel(selectedJointIndex);
|
|
}
|
|
return;
|
|
|
|
case STANDING:
|
|
default:
|
|
|
|
INTERNAL_STATE = STANDING;
|
|
if(!minimised) doStandardMenu();
|
|
|
|
// initialisation - runs at script startup only
|
|
if(strideLength===0) {
|
|
|
|
if(principleDirection===DIRECTION_BACKWARDS)
|
|
strideLength = selectedWalk.calibration.strideLengthBackwards;
|
|
else
|
|
strideLength = selectedWalk.calibration.strideLengthForwards;
|
|
|
|
curlFingers();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Main loop
|
|
|
|
// stabilising vars - most state changes are preceded by a couple of hints that they are about to happen rather than
|
|
// momentarilly switching between states (causes flicker), we count the number of hints in a row before actually changing state
|
|
var standHints = 0;
|
|
var walkHints = 0;
|
|
var flyHints = 0;
|
|
var requiredHints = 2; // tweakable - debounce state changes - how many times do we get a state change request in a row before we actually change state? (used to be 4 or 5)
|
|
var principleDirection = 0;
|
|
|
|
// helper function for stats output
|
|
function directionAsString(directionEnum) {
|
|
|
|
switch(directionEnum) {
|
|
case DIRECTION_UP: return 'Up';
|
|
case DIRECTION_DOWN: return 'Down';
|
|
case DIRECTION_LEFT: return 'Left';
|
|
case DIRECTION_RIGHT: return 'Right';
|
|
case DIRECTION_FORWARDS: return 'Forwards';
|
|
case DIRECTION_BACKWARDS: return 'Backwards';
|
|
default: return 'Unknown';
|
|
}
|
|
}
|
|
// helper function for stats output
|
|
function internalStateAsString(internalState) {
|
|
|
|
switch(internalState) {
|
|
case STANDING: return 'Standing';
|
|
case WALKING: return 'Walking';
|
|
case SIDE_STEPPING: return 'Side Stepping';
|
|
case FLYING: return 'Flying';
|
|
default: return 'Editing';
|
|
}
|
|
}
|
|
|
|
Script.update.connect(function(deltaTime) {
|
|
|
|
if(powerOn) {
|
|
|
|
frameStartTime = new Date().getTime();
|
|
cumulativeTime += deltaTime;
|
|
nFrames++;
|
|
var speed = 0;
|
|
|
|
// firstly check for editing modes, as these require no positioning calculations
|
|
var editing = false;
|
|
switch(INTERNAL_STATE) {
|
|
|
|
case CONFIG_WALK_STYLES:
|
|
currentAnimation = selectedWalk;
|
|
animateAvatar(deltaTime, speed, principleDirection);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_WALK_TWEAKS:
|
|
currentAnimation = selectedWalk;
|
|
animateAvatar(deltaTime, speed, DIRECTION_FORWARDS);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_WALK_JOINTS:
|
|
currentAnimation = selectedWalk;
|
|
animateAvatar(deltaTime, speed, DIRECTION_FORWARDS);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_STANDING:
|
|
currentAnimation = selectedStand;
|
|
animateAvatar(deltaTime, speed, DIRECTION_FORWARDS);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_SIDESTEP_LEFT:
|
|
currentAnimation = selectedSideStepLeft;
|
|
animateAvatar(deltaTime, speed, DIRECTION_LEFT);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_SIDESTEP_RIGHT:
|
|
currentAnimation = selectedSideStepRight;
|
|
animateAvatar(deltaTime, speed, DIRECTION_RIGHT);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_FLYING:
|
|
currentAnimation = selectedFly;
|
|
animateAvatar(deltaTime, speed, DIRECTION_FORWARDS);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_FLYING_UP:
|
|
currentAnimation = selectedFlyUp;
|
|
animateAvatar(deltaTime, speed, DIRECTION_UP);
|
|
editing = true;
|
|
break;
|
|
case CONFIG_FLYING_DOWN:
|
|
currentAnimation = selectedFlyDown;
|
|
animateAvatar(deltaTime, speed, DIRECTION_DOWN);
|
|
editing = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// we have to declare these vars here ( outside 'if(!editing)' ), so they are still in scope
|
|
// when we record the frame's data and when we do the stats update at the end
|
|
var deltaX = 0;
|
|
var deltaY = 0;
|
|
var deltaZ = 0;
|
|
var acceleration = { x:0, y:0, z:0 };
|
|
var accelerationJS = MyAvatar.getAcceleration();
|
|
|
|
// calculate overriding (local) direction of translation for use later when decide which animation should be played
|
|
var inverseRotation = Quat.inverse(MyAvatar.orientation);
|
|
var localVelocity = Vec3.multiplyQbyV(inverseRotation, MyAvatar.getVelocity());
|
|
|
|
if(!editing) {
|
|
|
|
// the first thing to do is find out how fast we're going,
|
|
// what our acceleration is and which direction we're principly moving in
|
|
|
|
// calcualte (local) change in velocity
|
|
var velocity = MyAvatar.getVelocity();
|
|
speed = Vec3.length(velocity);
|
|
|
|
// determine the candidate animation to play
|
|
var actionToTake = 0;
|
|
if( speed < 0.5) {
|
|
actionToTake = STANDING;
|
|
standHints++;
|
|
}
|
|
else if( speed < FLYING_SPEED ) {
|
|
actionToTake = WALKING;
|
|
walkHints++;
|
|
}
|
|
else if( speed >= FLYING_SPEED ) {
|
|
actionToTake = FLYING;
|
|
flyHints++;
|
|
}
|
|
|
|
deltaX = localVelocity.x;
|
|
deltaY = localVelocity.y;
|
|
deltaZ = -localVelocity.z;
|
|
|
|
// determine the principle direction
|
|
if(Math.abs(deltaX)>Math.abs(deltaY)
|
|
&&Math.abs(deltaX)>Math.abs(deltaZ)) {
|
|
if(deltaX<0) {
|
|
principleDirection = DIRECTION_RIGHT;
|
|
} else {
|
|
principleDirection = DIRECTION_LEFT;
|
|
}
|
|
}
|
|
else if(Math.abs(deltaY)>Math.abs(deltaX)
|
|
&&Math.abs(deltaY)>Math.abs(deltaZ)) {
|
|
if(deltaY>0) {
|
|
principleDirection = DIRECTION_UP;
|
|
}
|
|
else {
|
|
principleDirection = DIRECTION_DOWN;
|
|
}
|
|
}
|
|
else if(Math.abs(deltaZ)>Math.abs(deltaX)
|
|
&&Math.abs(deltaZ)>Math.abs(deltaY)) {
|
|
if(deltaZ>0) {
|
|
principleDirection = DIRECTION_FORWARDS;
|
|
} else {
|
|
principleDirection = DIRECTION_BACKWARDS;
|
|
}
|
|
}
|
|
|
|
// NB: this section will change significantly once we are ground plane aware
|
|
// it will change even more once we have uneven surfaces to deal with
|
|
|
|
// maybe at walking speed, but sideways?
|
|
if( actionToTake === WALKING &&
|
|
( principleDirection === DIRECTION_LEFT ||
|
|
principleDirection === DIRECTION_RIGHT )) {
|
|
|
|
actionToTake = SIDE_STEPPING;
|
|
}
|
|
|
|
// maybe at walking speed, but flying up?
|
|
if( actionToTake === WALKING &&
|
|
( principleDirection === DIRECTION_UP )) {
|
|
|
|
actionToTake = FLYING;
|
|
standHints--;
|
|
flyHints++;
|
|
}
|
|
|
|
// maybe at walking speed, but flying down?
|
|
if( actionToTake === WALKING &&
|
|
( principleDirection === DIRECTION_DOWN )) {
|
|
|
|
actionToTake = FLYING;
|
|
standHints--;
|
|
flyHints++;
|
|
}
|
|
|
|
// log this frame's motion for later reference
|
|
var accelerationX = ( framesHistory.recentMotions[0].velocity.x - localVelocity.x ) / deltaTime;
|
|
var accelerationY = ( localVelocity.y - framesHistory.recentMotions[0].velocity.y ) / deltaTime;
|
|
var accelerationZ = ( framesHistory.recentMotions[0].velocity.z - localVelocity.z ) / deltaTime;
|
|
acceleration = {x:accelerationX, y:accelerationY, z:accelerationZ};
|
|
|
|
|
|
// select appropriate animation and initiate Transition if required
|
|
switch(actionToTake) {
|
|
|
|
case STANDING:
|
|
|
|
if( standHints > requiredHints || INTERNAL_STATE===STANDING) { // wait for a few consecutive hints (17mS each)
|
|
|
|
standHints = 0;
|
|
walkHints = 0;
|
|
flyHints = 0;
|
|
|
|
// do we need to change state?
|
|
if( INTERNAL_STATE!==STANDING ) {
|
|
|
|
// initiate the transition
|
|
if(currentTransition) {
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
}
|
|
|
|
switch(currentAnimation) {
|
|
|
|
case selectedWalk:
|
|
|
|
// Walking to Standing
|
|
var timeWalking = new Date().getTime() - framesHistory.lastWalkStartTime;
|
|
|
|
var bezierCoeffsOne = {x:0.0, y:1.0};
|
|
var bezierCoeffsTwo = {x:0.0, y:1.0};
|
|
var transitionTime = 0.4;
|
|
|
|
// very different curves for incremental steps
|
|
if( timeWalking < 550 ) {
|
|
bezierCoeffsOne = {x:0.63, y:0.17};
|
|
bezierCoeffsTwo = {x:0.77, y:0.3};
|
|
transitionTime = 0.75;
|
|
}
|
|
currentTransition = new Transition( currentAnimation, selectedStand, [], transitionTime, bezierCoeffsOne, bezierCoeffsTwo );
|
|
break;
|
|
|
|
|
|
case selectedSideStepLeft:
|
|
case selectedSideStepRight:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedStand, [], 0.3, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
}
|
|
|
|
setInternalState(STANDING);
|
|
currentAnimation = selectedStand;
|
|
|
|
}
|
|
animateAvatar(1,0,principleDirection);
|
|
}
|
|
break;
|
|
|
|
case WALKING:
|
|
case SIDE_STEPPING:
|
|
if( walkHints > requiredHints ||
|
|
INTERNAL_STATE===WALKING ||
|
|
INTERNAL_STATE===SIDE_STEPPING ) { // wait for few consecutive hints (17mS each)
|
|
|
|
standHints = 0;
|
|
walkHints = 0;
|
|
flyHints = 0;
|
|
|
|
if( actionToTake === WALKING && INTERNAL_STATE !== WALKING) {
|
|
|
|
// initiate the transition
|
|
if(currentTransition) {
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
}
|
|
|
|
// set the appropriate start position for the walk wheel
|
|
if( principleDirection === DIRECTION_BACKWARDS ) {
|
|
|
|
walkWheelPosition = selectedWalk.settings.startAngleBackwards;
|
|
|
|
} else {
|
|
|
|
walkWheelPosition = selectedWalk.settings.startAngleForwards;
|
|
}
|
|
|
|
switch(currentAnimation) {
|
|
|
|
case selectedStand:
|
|
|
|
// Standing to Walking
|
|
currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.25, {x:0.5,y:0.08}, {x:0.05,y:0.75});
|
|
break;
|
|
|
|
case selectedSideStepLeft:
|
|
case selectedSideStepRight:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.3, {x:0.5,y:0.08}, {x:0.05,y:0.75});
|
|
break;
|
|
}
|
|
framesHistory.lastWalkStartTime = new Date().getTime();
|
|
setInternalState(WALKING);
|
|
currentAnimation = selectedWalk;
|
|
}
|
|
else if(actionToTake===SIDE_STEPPING) {
|
|
|
|
var selectedSideStep = selectedSideStepRight;
|
|
if( principleDirection === DIRECTION_LEFT ) {
|
|
|
|
selectedSideStep = selectedSideStepLeft;
|
|
|
|
} else {
|
|
|
|
selectedSideStep = selectedSideStepRight;
|
|
}
|
|
|
|
if( INTERNAL_STATE !== SIDE_STEPPING ) {
|
|
|
|
if( principleDirection === DIRECTION_LEFT ) {
|
|
|
|
walkWheelPosition = sideStepCycleStartLeft;
|
|
|
|
} else {
|
|
|
|
walkWheelPosition = sideStepCycleStartRight;
|
|
}
|
|
switch(currentAnimation) {
|
|
|
|
case selectedStand:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
setInternalState(SIDE_STEPPING);
|
|
}
|
|
|
|
currentAnimation = selectedSideStep;
|
|
}
|
|
animateAvatar( deltaTime, speed, principleDirection );
|
|
}
|
|
break;
|
|
|
|
case FLYING:
|
|
|
|
if( flyHints > requiredHints - 1 || INTERNAL_STATE===FLYING ) { // wait for a few consecutive hints (17mS each)
|
|
|
|
standHints = 0;
|
|
walkHints = 0;
|
|
flyHints = 0;
|
|
|
|
if(INTERNAL_STATE!==FLYING) setInternalState(FLYING);
|
|
|
|
// change animation for flying directly up or down. TODO - check RecentMotions, if is a change then put a transition on it
|
|
if(principleDirection===DIRECTION_UP) {
|
|
|
|
if(currentAnimation !== selectedFlyUp) {
|
|
|
|
// initiate a Transition
|
|
if(currentTransition && currentTransition.nextAnimation!==selectedFlyUp) {
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
}
|
|
switch(currentAnimation) {
|
|
|
|
case selectedStand:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFlyUp, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
|
|
case selectedSideStepLeft:
|
|
case selectedSideStepRight:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFlyUp, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
}
|
|
currentAnimation = selectedFlyUp;
|
|
}
|
|
|
|
} else if(principleDirection==DIRECTION_DOWN) {
|
|
|
|
if(currentAnimation !== selectedFlyDown) { // TODO: as the locomotion gets cleaner (i.e. less false reports from Interface) this value can be reduced
|
|
|
|
// initiate a Transition
|
|
if(currentTransition && currentTransition.nextAnimation!==selectedFlyDown) {
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
}
|
|
switch(currentAnimation) {
|
|
|
|
case selectedStand:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFlyDown, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
|
|
case selectedSideStepLeft:
|
|
case selectedSideStepRight:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFlyDown, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
}
|
|
currentAnimation = selectedFlyDown;
|
|
}
|
|
|
|
} else {
|
|
|
|
if(currentAnimation !== selectedFly) { // TODO: as the locomotion gets cleaner (i.e. less false reports from Interface) this value can be reduced
|
|
|
|
// initiate a Transition
|
|
if(currentTransition && currentTransition.nextAnimation!==selectedFly) {
|
|
delete currentTransition;
|
|
currentTransition = null;
|
|
}
|
|
switch(currentAnimation) {
|
|
|
|
case selectedStand:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFly, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
|
|
case selectedSideStepLeft:
|
|
case selectedSideStepRight:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentTransition = new Transition(currentAnimation, selectedFly, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1});
|
|
break;
|
|
}
|
|
currentAnimation = selectedFly;
|
|
}
|
|
}
|
|
animateAvatar(deltaTime, speed, principleDirection);
|
|
}
|
|
break;
|
|
|
|
} // end switch(actionToTake)
|
|
|
|
} // end if(!editing)
|
|
|
|
|
|
// record the frame's stats for later reference
|
|
var thisMotion = new RecentMotion(localVelocity, acceleration, principleDirection, INTERNAL_STATE);
|
|
framesHistory.recentMotions.push(thisMotion);
|
|
framesHistory.recentMotions.shift();
|
|
|
|
|
|
// before we go, populate the stats overlay
|
|
if( statsOn ) {
|
|
|
|
var cumulativeTimeMS = Math.floor(cumulativeTime*1000);
|
|
var deltaTimeMS = deltaTime * 1000;
|
|
var frameExecutionTime = new Date().getTime() - frameStartTime;
|
|
if(frameExecutionTime>frameExecutionTimeMax) frameExecutionTimeMax = frameExecutionTime;
|
|
|
|
var angluarVelocity = Vec3.length(MyAvatar.getAngularVelocity());
|
|
|
|
var debugInfo = '\n \n \n \n Stats\n--------------------------------------\n \n \n'
|
|
+ '\nFrame number: '+nFrames
|
|
+ '\nFrame time: '+deltaTimeMS.toFixed(2)
|
|
+ ' mS\nRender time: '+frameExecutionTime.toFixed(0)
|
|
+ ' mS\nLocalised speed: '+speed.toFixed(3)
|
|
+ ' m/s\nCumulative Time '+cumulativeTimeMS.toFixed(0)
|
|
+ ' mS\nState: '+internalStateAsString(INTERNAL_STATE)
|
|
+ ' \nDirection: '+directionAsString(principleDirection)
|
|
+ ' \nAngular Velocity: ' + angluarVelocity.toFixed(3)
|
|
+ ' rad/s';
|
|
Overlays.editOverlay(debugStats, {text: debugInfo});
|
|
|
|
// update these every 250 mS (assuming 60 fps)
|
|
if( nFrames % 15 === 0 ) {
|
|
var debugInfo = ' Periodic Stats\n--------------------------------------\n \n \n'
|
|
+ ' \n \nRender time peak hold: '+frameExecutionTimeMax.toFixed(0)
|
|
+ ' mS\n \n \n(L) MyAvatar.getVelocity()'
|
|
+ ' \n \nlocalVelocityX: '+deltaX.toFixed(1)
|
|
+ ' m/s\nlocalVelocityY: '+deltaY.toFixed(1)
|
|
+ ' m/s\nlocalVelocityZ: '+deltaZ.toFixed(1)
|
|
+ ' m/s\n \n(G) MyAvatar.getAcceleration()'
|
|
+ ' \n\nAcceleration X: '+accelerationJS.x.toFixed(1)
|
|
+ ' m/s/s\nAcceleration Y: '+accelerationJS.y.toFixed(1)
|
|
+ ' m/s/s\nAcceleration Z: '+accelerationJS.z.toFixed(1)
|
|
+ ' m/s/s\n \n(L) Acceleration using\nMyAvatar.getVelocity()'
|
|
+ ' \n \nAcceleration X: '+acceleration.x.toFixed(1)
|
|
+ ' m/s/s\nAcceleration Y: '+acceleration.y.toFixed(1)
|
|
+ ' m/s/s\nAcceleration Z: '+acceleration.z.toFixed(1)
|
|
+ ' m/s/s';
|
|
Overlays.editOverlay(debugStatsPeriodic, {text: debugInfo});
|
|
frameExecutionTimeMax = 0;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
// overlays start
|
|
|
|
// controller dimensions
|
|
var backgroundWidth = 350;
|
|
var backgroundHeight = 700;
|
|
var backgroundX = Window.innerWidth-backgroundWidth-58;
|
|
var backgroundY = Window.innerHeight/2 - backgroundHeight/2;
|
|
var minSliderX = backgroundX + 30;
|
|
var maxSliderX = backgroundX + 295;
|
|
var sliderRangeX = 295 - 30;
|
|
var jointsControlWidth = 200;
|
|
var jointsControlHeight = 300;
|
|
var jointsControlX = backgroundX + backgroundWidth/2 - jointsControlWidth/2;
|
|
var jointsControlY = backgroundY + 242 - jointsControlHeight/2;
|
|
var buttonsY = 20; // distance from top of panel to buttons
|
|
|
|
// arrays of overlay names
|
|
var sliderThumbOverlays = []; // thumb sliders
|
|
var backgroundOverlays = [];
|
|
var buttonOverlays = [];
|
|
var jointsControlOverlays = [];
|
|
var bigButtonOverlays = [];
|
|
|
|
|
|
// load UI backgrounds
|
|
var controlsBackground = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight },
|
|
imageURL: pathToOverlays+"ddao-background.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
backgroundOverlays.push(controlsBackground);
|
|
|
|
var controlsBackgroundWalkEditStyles = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight },
|
|
imageURL: pathToOverlays+"ddao-background-edit-styles.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
backgroundOverlays.push(controlsBackgroundWalkEditStyles);
|
|
|
|
var controlsBackgroundWalkEditTweaks = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight },
|
|
imageURL: pathToOverlays+"ddao-background-edit-tweaks.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
backgroundOverlays.push(controlsBackgroundWalkEditTweaks);
|
|
|
|
var controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight },
|
|
imageURL: pathToOverlays+"ddao-background-edit-joints.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
backgroundOverlays.push(controlsBackgroundWalkEditJoints);
|
|
|
|
var controlsBackgroundFlyingEdit = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight },
|
|
imageURL: pathToOverlays+"ddao-background-flying-edit.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
backgroundOverlays.push(controlsBackgroundFlyingEdit);
|
|
|
|
// minimised tab - not put in array, as is a one off
|
|
var controlsMinimisedTab = Overlays.addOverlay("image", {
|
|
x: Window.innerWidth-58, y: Window.innerHeight -145, width: 50, height: 50,
|
|
//subImage: { x: 0, y: 50, width: 50, height: 50 },
|
|
imageURL: pathToOverlays + 'ddao-minimise-tab.png',
|
|
visible: minimised,
|
|
alpha: 0.9
|
|
});
|
|
|
|
// load character joint selection control images
|
|
var hipsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-hips.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(hipsJointControl);
|
|
|
|
var upperLegsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-upper-legs.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(upperLegsJointControl);
|
|
|
|
var lowerLegsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-lower-legs.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(lowerLegsJointControl);
|
|
|
|
var feetJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-feet.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(feetJointControl);
|
|
|
|
var toesJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-toes.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(toesJointControl);
|
|
|
|
var spineJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-spine.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(spineJointControl);
|
|
|
|
var spine1JointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-spine1.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(spine1JointControl);
|
|
|
|
var spine2JointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-spine2.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(spine2JointControl);
|
|
|
|
var shouldersJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-shoulders.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(shouldersJointControl);
|
|
|
|
var upperArmsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-upper-arms.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(upperArmsJointControl);
|
|
|
|
var forearmsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-forearms.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(forearmsJointControl);
|
|
|
|
var handsJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-hands.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(handsJointControl);
|
|
|
|
var headJointControl = Overlays.addOverlay("image", {
|
|
bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300},
|
|
imageURL: pathToOverlays+"ddao-background-edit-head.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
jointsControlOverlays.push(headJointControl);
|
|
|
|
|
|
// sider thumb overlays
|
|
var sliderOne = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderOne);
|
|
var sliderTwo = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderTwo);
|
|
var sliderThree = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderThree);
|
|
var sliderFour = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderFour);
|
|
var sliderFive = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderFive);
|
|
var sliderSix = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderSix);
|
|
var sliderSeven = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderSeven);
|
|
var sliderEight = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderEight);
|
|
var sliderNine = Overlays.addOverlay("image", {
|
|
bounds: { x: 0, y: 0, width: 25, height: 25 },
|
|
imageURL: pathToOverlays+"ddao-slider-handle.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
sliderThumbOverlays.push(sliderNine);
|
|
|
|
|
|
// button overlays
|
|
var onButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-on-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(onButton);
|
|
var offButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-off-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(offButton);
|
|
var configWalkButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-walk-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkButton);
|
|
var configWalkButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-walk-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkButtonSelected);
|
|
var configStandButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-stand-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configStandButton);
|
|
var configStandButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-stand-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configStandButtonSelected);
|
|
|
|
var configFlyingButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingButton);
|
|
var configFlyingButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingButtonSelected);
|
|
|
|
var configFlyingUpButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-up-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingUpButton);
|
|
var configFlyingUpButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-up-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingUpButtonSelected);
|
|
|
|
var configFlyingDownButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-down-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingDownButton);
|
|
var configFlyingDownButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-fly-down-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configFlyingDownButtonSelected);
|
|
|
|
var hideButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-hide-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(hideButton);
|
|
var hideButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-hide-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(hideButtonSelected);
|
|
var configWalkStylesButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-walk-styles-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkStylesButton);
|
|
var configWalkStylesButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-walk-styles-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkStylesButtonSelected);
|
|
var configWalkTweaksButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-walk-tweaks-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkTweaksButton);
|
|
var configWalkTweaksButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-walk-tweaks-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkTweaksButtonSelected);
|
|
|
|
var configSideStepLeftButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-sidestep-left-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configSideStepLeftButton);
|
|
var configSideStepLeftButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-sidestep-left-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configSideStepLeftButtonSelected);
|
|
|
|
var configSideStepRightButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-sidestep-right-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configSideStepRightButton);
|
|
var configSideStepRightButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-edit-sidestep-right-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configSideStepRightButtonSelected);
|
|
|
|
var configWalkJointsButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-bones-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkJointsButton);
|
|
var configWalkJointsButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-bones-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(configWalkJointsButtonSelected);
|
|
|
|
var backButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-back-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(backButton);
|
|
var backButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 },
|
|
imageURL: pathToOverlays+"ddao-back-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
buttonOverlays.push(backButtonSelected);
|
|
|
|
// big button overlays - front panel
|
|
var bigButtonYOffset = 408; // distance from top of panel to top of first button
|
|
|
|
var femaleBigButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-female-big-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(femaleBigButton);
|
|
|
|
var femaleBigButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-female-big-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(femaleBigButtonSelected);
|
|
|
|
var maleBigButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-male-big-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(maleBigButton);
|
|
|
|
var maleBigButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-male-big-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(maleBigButtonSelected);
|
|
|
|
var armsFreeBigButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-arms-free-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(armsFreeBigButton);
|
|
|
|
var armsFreeBigButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-arms-free-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(armsFreeBigButtonSelected);
|
|
|
|
var footstepsBigButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-footsteps-big-button.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(footstepsBigButton);
|
|
|
|
var footstepsBigButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 230, height: 36},
|
|
imageURL: pathToOverlays+"ddao-footsteps-big-button-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(footstepsBigButtonSelected);
|
|
|
|
|
|
// walk styles
|
|
bigButtonYOffset = 121;
|
|
var strutWalkBigButton = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 },
|
|
imageURL: pathToOverlays+"ddao-walk-select-button-strut.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(strutWalkBigButton);
|
|
|
|
var strutWalkBigButtonSelected = Overlays.addOverlay("image", {
|
|
bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 },
|
|
imageURL: pathToOverlays+"ddao-walk-select-button-strut-selected.png",
|
|
color: { red: 255, green: 255, blue: 255},
|
|
alpha: 1,
|
|
visible: false
|
|
});
|
|
bigButtonOverlays.push(strutWalkBigButtonSelected);
|
|
|
|
// overlays to show the walk wheel stats
|
|
var walkWheelZLine = Overlays.addOverlay("line3d", {
|
|
position: { x: 0, y: 0, z:hipsToFeetDistance },
|
|
end: { x: 0, y: 0, z: -hipsToFeetDistance },
|
|
color: { red: 0, green: 255, blue: 255},
|
|
alpha: 1,
|
|
lineWidth: 5,
|
|
visible: statsOn,
|
|
anchor: "MyAvatar"
|
|
});
|
|
var walkWheelYLine = Overlays.addOverlay("line3d", {
|
|
position: { x: 0, y: hipsToFeetDistance, z:0 },
|
|
end: { x: 0, y: -hipsToFeetDistance, z:0 },
|
|
color: { red: 255, green: 0, blue: 255},
|
|
alpha: 1,
|
|
lineWidth: 5,
|
|
visible: statsOn,
|
|
anchor: "MyAvatar"
|
|
});
|
|
var debugStats = Overlays.addOverlay("text", {
|
|
x: backgroundX-199, y: backgroundY,
|
|
width: 200,
|
|
height: 180,
|
|
color: { red: 204, green: 204, blue: 204},
|
|
topMargin: 10,
|
|
leftMargin: 15,
|
|
visible: statsOn,
|
|
backgroundColor: { red: 34, green: 34, blue: 34},
|
|
alpha: 1.0,
|
|
text: "Debug Stats\n\n\nNothing to report yet."
|
|
});
|
|
var debugStatsPeriodic = Overlays.addOverlay("text", {
|
|
x: backgroundX-199, y: backgroundY+179,
|
|
width: 200,
|
|
height: 392,
|
|
color: { red: 204, green: 204, blue: 204},
|
|
topMargin: 5,
|
|
leftMargin: 15,
|
|
visible: statsOn,
|
|
backgroundColor: { red: 34, green: 34, blue: 34},
|
|
alpha: 1.0,
|
|
text: "Debug Stats\n\n\nNothing to report yet."
|
|
});
|
|
var walkWheelStats = Overlays.addOverlay("text", {
|
|
x: backgroundX-199, y: backgroundY+510,
|
|
width: 200,
|
|
height: 190,
|
|
color: { red: 204, green: 204, blue: 204},
|
|
topMargin: 5,
|
|
leftMargin: 15,
|
|
visible: statsOn,
|
|
backgroundColor: { red: 34, green: 34, blue: 34},
|
|
alpha: 1.0,
|
|
text: "WalkWheel Stats\n\n\nNothing to report yet.\n\n\nPlease start walking\nto see the walkwheel."
|
|
});
|
|
|
|
// various show / hide GUI element functions
|
|
function doStandardMenu() {
|
|
hidebuttonOverlays();
|
|
hideJointControls();
|
|
setBackground(controlsBackground);
|
|
if(powerOn) setButtonOverlayVisible(onButton);
|
|
else setButtonOverlayVisible(offButton);
|
|
setButtonOverlayVisible(configWalkButton);
|
|
setButtonOverlayVisible(configStandButton);
|
|
setButtonOverlayVisible(configFlyingButton);
|
|
setButtonOverlayVisible(hideButton);
|
|
setSliderThumbsVisible(false);
|
|
showFrontPanelButtons(true);
|
|
showWalkStyleButtons(false);
|
|
}
|
|
function showFrontPanelButtons(showButtons) {
|
|
|
|
if(avatarGender===FEMALE) {
|
|
Overlays.editOverlay(femaleBigButtonSelected, { visible: showButtons } );
|
|
Overlays.editOverlay(femaleBigButton, { visible: false } );
|
|
Overlays.editOverlay(maleBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(maleBigButton, { visible: showButtons } );
|
|
} else {
|
|
Overlays.editOverlay(femaleBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(femaleBigButton, { visible: showButtons } );
|
|
Overlays.editOverlay(maleBigButtonSelected, { visible: showButtons } );
|
|
Overlays.editOverlay(maleBigButton, { visible: false } );
|
|
}
|
|
if(armsFree) {
|
|
Overlays.editOverlay(armsFreeBigButtonSelected, { visible: showButtons } );
|
|
Overlays.editOverlay(armsFreeBigButton, { visible: false } );
|
|
} else {
|
|
Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(armsFreeBigButton, { visible: showButtons } );
|
|
}
|
|
if(playFootStepSounds) {
|
|
Overlays.editOverlay(footstepsBigButtonSelected, { visible: showButtons } );
|
|
Overlays.editOverlay(footstepsBigButton, { visible: false } );
|
|
} else {
|
|
Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(footstepsBigButton, { visible: showButtons } );
|
|
}
|
|
}
|
|
function minimiseDialog() {
|
|
|
|
if(minimised) {
|
|
setBackground();
|
|
hidebuttonOverlays();
|
|
setSliderThumbsVisible(false);
|
|
hideJointControls();
|
|
showFrontPanelButtons(false);
|
|
Overlays.editOverlay(controlsMinimisedTab, { visible: true } );
|
|
} else {
|
|
setInternalState(STANDING); // show all the controls again
|
|
Overlays.editOverlay(controlsMinimisedTab, { visible: false } );
|
|
}
|
|
}
|
|
function setBackground(backgroundName) {
|
|
for(var i in backgroundOverlays) {
|
|
if(backgroundOverlays[i] === backgroundName)
|
|
Overlays.editOverlay(backgroundName, { visible: true } );
|
|
else Overlays.editOverlay(backgroundOverlays[i], { visible: false } );
|
|
}
|
|
}
|
|
function setButtonOverlayVisible(buttonOverlayName) {
|
|
for(var i in buttonOverlays) {
|
|
if(buttonOverlays[i] === buttonOverlayName) {
|
|
Overlays.editOverlay(buttonOverlayName, { visible: true } );
|
|
}
|
|
}
|
|
}
|
|
// top row menu type buttons (smaller)
|
|
function hidebuttonOverlays() {
|
|
for(var i in buttonOverlays) {
|
|
Overlays.editOverlay(buttonOverlays[i], { visible: false } );
|
|
}
|
|
}
|
|
function hideJointControls() {
|
|
for(var i in jointsControlOverlays) {
|
|
Overlays.editOverlay(jointsControlOverlays[i], { visible: false } );
|
|
}
|
|
}
|
|
function setSliderThumbsVisible(thumbsVisible) {
|
|
for(var i = 0 ; i < sliderThumbOverlays.length ; i++) {
|
|
Overlays.editOverlay(sliderThumbOverlays[i], { visible: thumbsVisible } );
|
|
}
|
|
}
|
|
function initialiseJointsEditingPanel(propertyIndex) {
|
|
|
|
selectedJointIndex = propertyIndex;
|
|
|
|
// set the image for the selected joint on the character control
|
|
hideJointControls();
|
|
switch (selectedJointIndex) {
|
|
case 0:
|
|
Overlays.editOverlay(hipsJointControl, { visible: true });
|
|
break;
|
|
case 1:
|
|
Overlays.editOverlay(upperLegsJointControl, { visible: true });
|
|
break;
|
|
case 2:
|
|
Overlays.editOverlay(lowerLegsJointControl, { visible: true });
|
|
break;
|
|
case 3:
|
|
Overlays.editOverlay(feetJointControl, { visible: true });
|
|
break;
|
|
case 4:
|
|
Overlays.editOverlay(toesJointControl, { visible: true });
|
|
break;
|
|
case 5:
|
|
Overlays.editOverlay(spineJointControl, { visible: true });
|
|
break;
|
|
case 6:
|
|
Overlays.editOverlay(spine1JointControl, { visible: true });
|
|
break;
|
|
case 7:
|
|
Overlays.editOverlay(spine2JointControl, { visible: true });
|
|
break;
|
|
case 8:
|
|
Overlays.editOverlay(shouldersJointControl, { visible: true });
|
|
break;
|
|
case 9:
|
|
Overlays.editOverlay(upperArmsJointControl, { visible: true });
|
|
break;
|
|
case 10:
|
|
Overlays.editOverlay(forearmsJointControl, { visible: true });
|
|
break;
|
|
case 11:
|
|
Overlays.editOverlay(handsJointControl, { visible: true });
|
|
break;
|
|
case 12:
|
|
Overlays.editOverlay(headJointControl, { visible: true });
|
|
break;
|
|
}
|
|
|
|
// set sliders to adjust individual joint properties
|
|
var i = 0;
|
|
var yLocation = backgroundY+359;
|
|
|
|
// pitch your role
|
|
var sliderXPos = currentAnimation.joints[selectedJointIndex].pitch
|
|
/ sliderRanges.joints[selectedJointIndex].pitchRange * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = currentAnimation.joints[selectedJointIndex].yaw
|
|
/ sliderRanges.joints[selectedJointIndex].yawRange * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = currentAnimation.joints[selectedJointIndex].roll
|
|
/ sliderRanges.joints[selectedJointIndex].rollRange * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
|
|
// set phases (full range, -180 to 180)
|
|
sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].pitchPhase/2)/180 * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].yawPhase/2)/180 * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].rollPhase/2)/180 * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
|
|
// offset ranges are also -ve thr' zero to +ve, so have to offset
|
|
sliderXPos = (((sliderRanges.joints[selectedJointIndex].pitchOffsetRange+currentAnimation.joints[selectedJointIndex].pitchOffset)/2)
|
|
/sliderRanges.joints[selectedJointIndex].pitchOffsetRange) * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = (((sliderRanges.joints[selectedJointIndex].yawOffsetRange+currentAnimation.joints[selectedJointIndex].yawOffset)/2)
|
|
/sliderRanges.joints[selectedJointIndex].yawOffsetRange) * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
sliderXPos = (((sliderRanges.joints[selectedJointIndex].rollOffsetRange+currentAnimation.joints[selectedJointIndex].rollOffset)/2)
|
|
/sliderRanges.joints[selectedJointIndex].rollOffsetRange) * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true });
|
|
}
|
|
|
|
function initialiseWalkTweaks() {
|
|
|
|
// set sliders to adjust walk properties
|
|
var i = 0;
|
|
var yLocation = backgroundY+71;
|
|
|
|
var sliderXPos = currentAnimation.settings.baseFrequency / MAX_WALK_SPEED * sliderRangeX; // walk speed
|
|
Overlays.editOverlay(sliderThumbOverlays[i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = 0 * sliderRangeX; // start flying speed - depricated
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = currentAnimation.joints[0].sway / sliderRanges.joints[0].swayRange * sliderRangeX; // Hips sway
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = currentAnimation.joints[0].bob / sliderRanges.joints[0].bobRange * sliderRangeX; // Hips bob
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = currentAnimation.joints[0].thrust / sliderRanges.joints[0].thrustRange * sliderRangeX; // Hips thrust
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = (((sliderRanges.joints[1].rollOffsetRange+currentAnimation.joints[1].rollOffset)/2) // legs separation - is upper legs roll offset
|
|
/ sliderRanges.joints[1].rollOffsetRange) * sliderRangeX;
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = currentAnimation.joints[1].pitch / sliderRanges.joints[1].pitchRange * sliderRangeX; // stride - is upper legs pitch
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = currentAnimation.joints[9].yaw / sliderRanges.joints[9].yawRange * sliderRangeX; // arms swing - is upper arms yaw
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
sliderXPos = (((sliderRanges.joints[9].pitchOffsetRange-currentAnimation.joints[9].pitchOffset)/2)
|
|
/ sliderRanges.joints[9].pitchOffsetRange) * sliderRangeX; // arms out - is upper arms pitch offset
|
|
Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true });
|
|
}
|
|
|
|
function showWalkStyleButtons(showButtons) {
|
|
|
|
// set all big buttons to hidden, but skip the first 8, as are for the front panel
|
|
for(var i = 8 ; i < bigButtonOverlays.length ; i++) {
|
|
Overlays.editOverlay(bigButtonOverlays[i], { visible: false });
|
|
}
|
|
|
|
if(!showButtons) return;
|
|
|
|
// set all the non-selected ones to showing
|
|
for(var i = 8 ; i < bigButtonOverlays.length ; i+=2) {
|
|
Overlays.editOverlay(bigButtonOverlays[i], { visible: showButtons });
|
|
}
|
|
|
|
// set the currently selected one
|
|
if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) {
|
|
Overlays.editOverlay(strutWalkBigButtonSelected, { visible: showButtons });
|
|
Overlays.editOverlay(strutWalkBigButton, {visible: false});
|
|
}
|
|
}
|
|
|
|
// mouse event handlers
|
|
var movingSliderOne = false;
|
|
var movingSliderTwo = false;
|
|
var movingSliderThree = false;
|
|
var movingSliderFour = false;
|
|
var movingSliderFive = false;
|
|
var movingSliderSix = false;
|
|
var movingSliderSeven = false;
|
|
var movingSliderEight = false;
|
|
var movingSliderNine = false;
|
|
|
|
function mousePressEvent(event) {
|
|
|
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
|
|
|
// check for a character joint control click
|
|
switch (clickedOverlay) {
|
|
|
|
case hideButton:
|
|
Overlays.editOverlay(hideButton, { visible: false } );
|
|
Overlays.editOverlay(hideButtonSelected, { visible: true } );
|
|
return;
|
|
|
|
case backButton:
|
|
Overlays.editOverlay(backButton, { visible: false } );
|
|
Overlays.editOverlay(backButtonSelected, { visible: true } );
|
|
return;
|
|
|
|
case controlsMinimisedTab:
|
|
// TODO: add visual user feedback for tab click
|
|
return;
|
|
|
|
case footstepsBigButton:
|
|
playFootStepSounds = true;
|
|
Overlays.editOverlay(footstepsBigButtonSelected, { visible: true } );
|
|
Overlays.editOverlay(footstepsBigButton, { visible: false } );
|
|
return;
|
|
|
|
case footstepsBigButtonSelected:
|
|
playFootStepSounds = false;
|
|
Overlays.editOverlay(footstepsBigButton, { visible: true } );
|
|
Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } );
|
|
return;
|
|
|
|
case femaleBigButton:
|
|
case maleBigButtonSelected:
|
|
avatarGender = FEMALE;
|
|
selectedWalk = femaleStrutWalk;
|
|
selectedStand = femaleStandOne;
|
|
selectedFlyUp = femaleFlyingUp;
|
|
selectedFly = femaleFlying;
|
|
selectedFlyDown = femaleFlyingDown;
|
|
selectedSideStepLeft = femaleSideStepLeft;
|
|
selectedSideStepRight = femaleSideStepRight;
|
|
Overlays.editOverlay(femaleBigButtonSelected, { visible: true } );
|
|
Overlays.editOverlay(femaleBigButton, { visible: false } );
|
|
Overlays.editOverlay(maleBigButton, { visible: true } );
|
|
Overlays.editOverlay(maleBigButtonSelected, { visible: false } );
|
|
return;
|
|
|
|
case armsFreeBigButton:
|
|
armsFree = true;
|
|
Overlays.editOverlay(armsFreeBigButtonSelected, { visible: true } );
|
|
Overlays.editOverlay(armsFreeBigButton, { visible: false } );
|
|
return;
|
|
|
|
case armsFreeBigButtonSelected:
|
|
armsFree = false;
|
|
Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(armsFreeBigButton, { visible: true } );
|
|
return;
|
|
|
|
case maleBigButton:
|
|
case femaleBigButtonSelected:
|
|
avatarGender = MALE;
|
|
selectedWalk = maleStrutWalk;
|
|
selectedStand = maleStandOne;
|
|
selectedFlyUp = maleFlyingUp;
|
|
selectedFly = maleFlying;
|
|
selectedFlyDown = maleFlyingDown;
|
|
selectedSideStepLeft = maleSideStepLeft;
|
|
selectedSideStepRight = maleSideStepRight;
|
|
Overlays.editOverlay(femaleBigButton, { visible: true } );
|
|
Overlays.editOverlay(femaleBigButtonSelected, { visible: false } );
|
|
Overlays.editOverlay(maleBigButtonSelected, { visible: true } );
|
|
Overlays.editOverlay(maleBigButton, { visible: false } );
|
|
return;
|
|
|
|
|
|
case strutWalkBigButton:
|
|
if(avatarGender===FEMALE) selectedWalk = femaleStrutWalk;
|
|
else selectedWalk = maleStrutWalk;
|
|
currentAnimation = selectedWalk;
|
|
showWalkStyleButtons(true);
|
|
return;
|
|
|
|
case strutWalkBigButtonSelected:
|
|
|
|
// toggle forwards / backwards walk display
|
|
if(principleDirection===DIRECTION_FORWARDS) {
|
|
principleDirection=DIRECTION_BACKWARDS;
|
|
} else principleDirection=DIRECTION_FORWARDS;
|
|
return;
|
|
|
|
case sliderOne:
|
|
movingSliderOne = true;
|
|
return;
|
|
|
|
case sliderTwo:
|
|
movingSliderTwo = true;
|
|
return;
|
|
|
|
case sliderThree:
|
|
movingSliderThree = true;
|
|
return;
|
|
|
|
case sliderFour:
|
|
movingSliderFour = true;
|
|
return;
|
|
|
|
case sliderFive:
|
|
movingSliderFive = true;
|
|
return;
|
|
|
|
case sliderSix:
|
|
movingSliderSix = true;
|
|
return;
|
|
|
|
case sliderSeven:
|
|
movingSliderSeven = true;
|
|
return;
|
|
|
|
case sliderEight:
|
|
movingSliderEight = true;
|
|
return;
|
|
|
|
case sliderNine:
|
|
movingSliderNine = true;
|
|
return;
|
|
}
|
|
|
|
if( INTERNAL_STATE===CONFIG_WALK_JOINTS ||
|
|
INTERNAL_STATE===CONFIG_STANDING ||
|
|
INTERNAL_STATE===CONFIG_FLYING ||
|
|
INTERNAL_STATE===CONFIG_FLYING_UP ||
|
|
INTERNAL_STATE===CONFIG_FLYING_DOWN ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
// check for new joint selection and update display accordingly
|
|
var clickX = event.x - backgroundX - 75;
|
|
var clickY = event.y - backgroundY - 92;
|
|
|
|
if(clickX>60&&clickX<120&&clickY>123&&clickY<155) {
|
|
initialiseJointsEditingPanel(0);
|
|
return;
|
|
}
|
|
else if(clickX>63&&clickX<132&&clickY>156&&clickY<202) {
|
|
initialiseJointsEditingPanel(1);
|
|
return;
|
|
}
|
|
else if(clickX>58&&clickX<137&&clickY>203&&clickY<250) {
|
|
initialiseJointsEditingPanel(2);
|
|
return;
|
|
}
|
|
else if(clickX>58&&clickX<137&&clickY>250&&clickY<265) {
|
|
initialiseJointsEditingPanel(3);
|
|
return;
|
|
}
|
|
else if(clickX>58&&clickX<137&&clickY>265&&clickY<280) {
|
|
initialiseJointsEditingPanel(4);
|
|
return;
|
|
}
|
|
else if(clickX>78&&clickX<121&&clickY>111&&clickY<128) {
|
|
initialiseJointsEditingPanel(5);
|
|
return;
|
|
}
|
|
else if(clickX>78&&clickX<128&&clickY>89&&clickY<111) {
|
|
initialiseJointsEditingPanel(6);
|
|
return;
|
|
}
|
|
else if(clickX>85&&clickX<118&&clickY>77&&clickY<94) {
|
|
initialiseJointsEditingPanel(7);
|
|
return;
|
|
}
|
|
else if(clickX>64&&clickX<125&&clickY>55&&clickY<77) {
|
|
initialiseJointsEditingPanel(8);
|
|
return;
|
|
}
|
|
else if((clickX>44&&clickX<73&&clickY>71&&clickY<94)
|
|
||(clickX>125&&clickX<144&&clickY>71&&clickY<94)) {
|
|
initialiseJointsEditingPanel(9);
|
|
return;
|
|
}
|
|
else if((clickX>28&&clickX<57&&clickY>94&&clickY<119)
|
|
||(clickX>137&&clickX<170&&clickY>97&&clickY<114)) {
|
|
initialiseJointsEditingPanel(10);
|
|
return;
|
|
}
|
|
else if((clickX>18&&clickX<37&&clickY>115&&clickY<136)
|
|
||(clickX>157&&clickX<182&&clickY>115&&clickY<136)) {
|
|
initialiseJointsEditingPanel(11);
|
|
return;
|
|
}
|
|
else if(clickX>81&&clickX<116&&clickY>12&&clickY<53) {
|
|
initialiseJointsEditingPanel(12);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
function mouseMoveEvent(event) {
|
|
|
|
// only need deal with slider changes
|
|
if(powerOn) {
|
|
|
|
if( INTERNAL_STATE===CONFIG_WALK_JOINTS ||
|
|
INTERNAL_STATE===CONFIG_STANDING ||
|
|
INTERNAL_STATE===CONFIG_FLYING ||
|
|
INTERNAL_STATE===CONFIG_FLYING_UP ||
|
|
INTERNAL_STATE===CONFIG_FLYING_DOWN ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_LEFT ||
|
|
INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) {
|
|
|
|
var thumbClickOffsetX = event.x - minSliderX;
|
|
var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX;
|
|
if(thumbPositionNormalised<0) thumbPositionNormalised = 0;
|
|
if(thumbPositionNormalised>1) thumbPositionNormalised = 1;
|
|
var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range
|
|
|
|
if(movingSliderOne) { // currently selected joint pitch
|
|
Overlays.editOverlay(sliderOne, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[selectedJointIndex].pitch = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].pitchRange;
|
|
}
|
|
else if(movingSliderTwo) { // currently selected joint yaw
|
|
Overlays.editOverlay(sliderTwo, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[selectedJointIndex].yaw = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].yawRange;
|
|
}
|
|
else if(movingSliderThree) { // currently selected joint roll
|
|
Overlays.editOverlay(sliderThree, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[selectedJointIndex].roll = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].rollRange;
|
|
}
|
|
else if(movingSliderFour) { // currently selected joint pitch phase
|
|
Overlays.editOverlay(sliderFour, { x: sliderX + minSliderX} );
|
|
var newPhase = 360 * thumbPositionNormalised - 180;
|
|
currentAnimation.joints[selectedJointIndex].pitchPhase = newPhase;
|
|
}
|
|
else if(movingSliderFive) { // currently selected joint yaw phase;
|
|
Overlays.editOverlay(sliderFive, { x: sliderX + minSliderX} );
|
|
var newPhase = 360 * thumbPositionNormalised - 180;
|
|
currentAnimation.joints[selectedJointIndex].yawPhase = newPhase;
|
|
}
|
|
else if(movingSliderSix) { // currently selected joint roll phase
|
|
Overlays.editOverlay(sliderSix, { x: sliderX + minSliderX} );
|
|
var newPhase = 360 * thumbPositionNormalised - 180;
|
|
currentAnimation.joints[selectedJointIndex].rollPhase = newPhase;
|
|
}
|
|
else if(movingSliderSeven) { // currently selected joint pitch offset
|
|
Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} ); // currently selected joint pitch offset
|
|
var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].pitchOffsetRange;
|
|
currentAnimation.joints[selectedJointIndex].pitchOffset = newOffset;
|
|
}
|
|
else if(movingSliderEight) { // currently selected joint yaw offset
|
|
Overlays.editOverlay(sliderEight, { x: sliderX + minSliderX} ); // currently selected joint yaw offset
|
|
var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].yawOffsetRange;
|
|
currentAnimation.joints[selectedJointIndex].yawOffset = newOffset;
|
|
}
|
|
else if(movingSliderNine) { // currently selected joint roll offset
|
|
Overlays.editOverlay(sliderNine, { x: sliderX + minSliderX} ); // currently selected joint roll offset
|
|
var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].rollOffsetRange;
|
|
currentAnimation.joints[selectedJointIndex].rollOffset = newOffset;
|
|
}
|
|
}
|
|
else if(INTERNAL_STATE===CONFIG_WALK_TWEAKS) {
|
|
|
|
var thumbClickOffsetX = event.x - minSliderX;
|
|
var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX;
|
|
if(thumbPositionNormalised<0) thumbPositionNormalised = 0;
|
|
if(thumbPositionNormalised>1) thumbPositionNormalised = 1;
|
|
var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range
|
|
|
|
if(movingSliderOne) { // walk speed
|
|
paused = true; // avoid nasty jittering
|
|
Overlays.editOverlay(sliderOne, { x: sliderX + minSliderX} );
|
|
currentAnimation.settings.baseFrequency = thumbPositionNormalised * MAX_WALK_SPEED;
|
|
}
|
|
else if(movingSliderTwo) { // take flight speed
|
|
Overlays.editOverlay(sliderTwo, { x: sliderX + minSliderX} );
|
|
//currentAnimation.settings.takeFlightVelocity = thumbPositionNormalised * 300;
|
|
}
|
|
else if(movingSliderThree) { // hips sway
|
|
Overlays.editOverlay(sliderThree, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[0].sway = thumbPositionNormalised * sliderRanges.joints[0].swayRange;
|
|
}
|
|
else if(movingSliderFour) { // hips bob
|
|
Overlays.editOverlay(sliderFour, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[0].bob = thumbPositionNormalised * sliderRanges.joints[0].bobRange;
|
|
}
|
|
else if(movingSliderFive) { // hips thrust
|
|
Overlays.editOverlay(sliderFive, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[0].thrust = thumbPositionNormalised * sliderRanges.joints[0].thrustRange;
|
|
}
|
|
else if(movingSliderSix) { // legs separation
|
|
Overlays.editOverlay(sliderSix, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[1].rollOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[1].rollOffsetRange;
|
|
}
|
|
else if(movingSliderSeven) { // stride
|
|
Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[1].pitch = thumbPositionNormalised * sliderRanges.joints[1].pitchRange;
|
|
}
|
|
else if(movingSliderEight) { // arms swing = upper arms yaw
|
|
Overlays.editOverlay(sliderEight, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[9].yaw = thumbPositionNormalised * sliderRanges.joints[9].yawRange;
|
|
}
|
|
else if(movingSliderNine) { // arms out = upper arms pitch offset
|
|
Overlays.editOverlay(sliderNine, { x: sliderX + minSliderX} );
|
|
currentAnimation.joints[9].pitchOffset = (thumbPositionNormalised-0.5) * -2 * sliderRanges.joints[9].pitchOffsetRange;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function mouseReleaseEvent(event) {
|
|
|
|
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
|
|
|
if(paused) paused = false;
|
|
|
|
if(clickedOverlay === offButton) {
|
|
powerOn = true;
|
|
Overlays.editOverlay(offButton, { visible: false } );
|
|
Overlays.editOverlay(onButton, { visible: true } );
|
|
stand();
|
|
}
|
|
else if(clickedOverlay === hideButton || clickedOverlay === hideButtonSelected){
|
|
Overlays.editOverlay(hideButton, { visible: true } );
|
|
Overlays.editOverlay(hideButtonSelected, { visible: false } );
|
|
minimised = true;
|
|
minimiseDialog();
|
|
}
|
|
else if(clickedOverlay === controlsMinimisedTab) {
|
|
minimised = false;
|
|
minimiseDialog();
|
|
}
|
|
else if(powerOn) {
|
|
|
|
if(movingSliderOne) movingSliderOne = false;
|
|
else if(movingSliderTwo) movingSliderTwo = false;
|
|
else if(movingSliderThree) movingSliderThree = false;
|
|
else if(movingSliderFour) movingSliderFour = false;
|
|
else if(movingSliderFive) movingSliderFive = false;
|
|
else if(movingSliderSix) movingSliderSix = false;
|
|
else if(movingSliderSeven) movingSliderSeven = false;
|
|
else if(movingSliderEight) movingSliderEight = false;
|
|
else if(movingSliderNine) movingSliderNine = false;
|
|
else {
|
|
|
|
switch(clickedOverlay) {
|
|
|
|
case configWalkButtonSelected:
|
|
case configStandButtonSelected:
|
|
case configSideStepLeftButtonSelected:
|
|
case configSideStepRightButtonSelected:
|
|
case configFlyingButtonSelected:
|
|
case configFlyingUpButtonSelected:
|
|
case configFlyingDownButtonSelected:
|
|
case configWalkStylesButtonSelected:
|
|
case configWalkTweaksButtonSelected:
|
|
case configWalkJointsButtonSelected:
|
|
setInternalState(STANDING);
|
|
break;
|
|
|
|
case onButton:
|
|
powerOn = false;
|
|
setInternalState(STANDING);
|
|
Overlays.editOverlay(offButton, { visible: true } );
|
|
Overlays.editOverlay(onButton, { visible: false } );
|
|
resetJoints();
|
|
break;
|
|
|
|
case backButton:
|
|
case backButtonSelected:
|
|
Overlays.editOverlay(backButton, { visible: false } );
|
|
Overlays.editOverlay(backButtonSelected, { visible: false } );
|
|
setInternalState(STANDING);
|
|
break;
|
|
|
|
case configWalkStylesButton:
|
|
setInternalState(CONFIG_WALK_STYLES);
|
|
break;
|
|
|
|
case configWalkTweaksButton:
|
|
setInternalState(CONFIG_WALK_TWEAKS);
|
|
break;
|
|
|
|
case configWalkJointsButton:
|
|
setInternalState(CONFIG_WALK_JOINTS);
|
|
break;
|
|
|
|
case configWalkButton:
|
|
setInternalState(CONFIG_WALK_STYLES); // set the default walk adjustment panel here (i.e. first panel shown when Walk button clicked)
|
|
break;
|
|
|
|
case configStandButton:
|
|
setInternalState(CONFIG_STANDING);
|
|
break;
|
|
|
|
case configSideStepLeftButton:
|
|
setInternalState(CONFIG_SIDESTEP_LEFT);
|
|
break;
|
|
|
|
case configSideStepRightButton:
|
|
setInternalState(CONFIG_SIDESTEP_RIGHT);
|
|
break;
|
|
|
|
case configFlyingButton:
|
|
setInternalState(CONFIG_FLYING);
|
|
break;
|
|
|
|
case configFlyingUpButton:
|
|
setInternalState(CONFIG_FLYING_UP);
|
|
break;
|
|
|
|
case configFlyingDownButton:
|
|
setInternalState(CONFIG_FLYING_DOWN);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
|
Controller.mousePressEvent.connect(mousePressEvent);
|
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
|
|
// Script ending
|
|
Script.scriptEnding.connect(function() {
|
|
|
|
// remove the background overlays
|
|
for(var i in backgroundOverlays) {
|
|
Overlays.deleteOverlay(backgroundOverlays[i]);
|
|
}
|
|
// remove the button overlays
|
|
for(var i in buttonOverlays) {
|
|
Overlays.deleteOverlay(buttonOverlays[i]);
|
|
}
|
|
// remove the slider thumb overlays
|
|
for(var i in sliderThumbOverlays) {
|
|
Overlays.deleteOverlay(sliderThumbOverlays[i]);
|
|
}
|
|
// remove the character joint control overlays
|
|
for(var i in bigButtonOverlays) {
|
|
Overlays.deleteOverlay(jointsControlOverlays[i]);
|
|
}
|
|
// remove the big button overlays
|
|
for(var i in bigButtonOverlays) {
|
|
Overlays.deleteOverlay(bigButtonOverlays[i]);
|
|
}
|
|
// remove the mimimised tab
|
|
Overlays.deleteOverlay(controlsMinimisedTab);
|
|
|
|
// remove the walk wheel overlays
|
|
Overlays.deleteOverlay(walkWheelYLine);
|
|
Overlays.deleteOverlay(walkWheelZLine);
|
|
Overlays.deleteOverlay(walkWheelStats);
|
|
|
|
// remove the debug stats overlays
|
|
Overlays.deleteOverlay(debugStats);
|
|
Overlays.deleteOverlay(debugStatsPeriodic);
|
|
});
|
|
|
|
var sideStep = 0.002; // i.e. 2mm increments whilst sidestepping - JS movement keys don't work well :-(
|
|
function keyPressEvent(event) {
|
|
|
|
if (event.text == "q") {
|
|
// export currentAnimation as json string when q key is pressed. reformat result at http://www.freeformatter.com/json-formatter.html
|
|
print('\n');
|
|
print('walk.js dumping animation: '+currentAnimation.name+'\n');
|
|
print('\n');
|
|
print(JSON.stringify(currentAnimation), null, '\t');
|
|
}
|
|
else if (event.text == "t") {
|
|
statsOn = !statsOn;
|
|
Overlays.editOverlay(debugStats, {visible: statsOn});
|
|
Overlays.editOverlay(debugStatsPeriodic, {visible: statsOn});
|
|
Overlays.editOverlay(walkWheelStats, {visible: statsOn});
|
|
Overlays.editOverlay(walkWheelYLine, {visible: statsOn});
|
|
Overlays.editOverlay(walkWheelZLine, {visible: statsOn});
|
|
}
|
|
}
|
|
Controller.keyPressEvent.connect(keyPressEvent);
|
|
|
|
// get the list of joint names
|
|
var jointList = MyAvatar.getJointNames();
|
|
|
|
// clear the joint data so can calculate hips to feet distance
|
|
for(var i = 0 ; i < 5 ; i++) {
|
|
MyAvatar.setJointData(i, Quat.fromPitchYawRollDegrees(0,0,0));
|
|
}
|
|
// used to position the visual representation of the walkwheel only
|
|
var hipsToFeetDistance = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightFoot").y;
|
|
|
|
// This script is designed around the Finite State Machine (FSM) model, so to start things up we just select the STANDING state.
|
|
setInternalState(STANDING); |