From 7a1f7bd41888a47411420e45428e89319a728296 Mon Sep 17 00:00:00 2001 From: DaveDubUK Date: Wed, 5 Nov 2014 20:11:11 +0000 Subject: [PATCH] Update to walk.js v 1.1 Revised code structure (see /libraries for new files), walk animation completely overhauled (now using geometric wave generators, Fourier synthesis and Butterworth LP filtering for selected motion curve construction), redesigned sidestepping animations, tweaked flying animations, decreased maximum walk speed in Interface to more natural human value, improved Hydra support, added support for Leap motion, animation file sizes optimised, cleared out code used to work around now fixed bugs, lots of minor tweaks and improvements. walk.js is now under 100,000 characters, but I had to use tabs instead of 4 spaces to get it below the threshold. --- examples/libraries/walkApi.js | 409 ++ examples/libraries/walkFilters.js | 230 + examples/libraries/walkInterface.js | 2713 ++++++++++++ examples/walk.js | 6105 +++++++++++---------------- interface/src/avatar/MyAvatar.cpp | 2 +- 5 files changed, 5761 insertions(+), 3698 deletions(-) create mode 100644 examples/libraries/walkApi.js create mode 100644 examples/libraries/walkFilters.js create mode 100644 examples/libraries/walkInterface.js diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js new file mode 100644 index 0000000000..90b9dad623 --- /dev/null +++ b/examples/libraries/walkApi.js @@ -0,0 +1,409 @@ +// +// walkObjects.js +// +// version 1.000 +// +// Created by David Wooldridge, Autumn 2014 +// +// Motion, state and Transition objects for use by the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// constructor for the Motion object +Motion = function() { + + this.setGender = function(gender) { + + this.avatarGender = gender; + + switch(this.avatarGender) { + + case MALE: + + this.selWalk = walkAssets.maleStandardWalk; + this.selStand = walkAssets.maleStandOne; + this.selFlyUp = walkAssets.maleFlyingUp; + this.selFly = walkAssets.maleFlying; + this.selFlyDown = walkAssets.maleFlyingDown; + this.selSideStepLeft = walkAssets.maleSideStepLeft; + this.selSideStepRight = walkAssets.maleSideStepRight; + this.curAnim = this.selStand; + return; + + case FEMALE: + + this.selWalk = walkAssets.femaleStandardWalk; + this.selStand = walkAssets.femaleStandOne; + this.selFlyUp = walkAssets.femaleFlyingUp; + this.selFly = walkAssets.femaleFlying; + this.selFlyDown = walkAssets.femaleFlyingDown; + this.selSideStepLeft = walkAssets.femaleSideStepLeft; + this.selSideStepRight = walkAssets.femaleSideStepRight; + this.curAnim = this.selStand; + return; + } + } + + this.hydraCheck = function() { + + // function courtesy of Thijs Wenker, frisbee.js + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2); + return hydrasConnected; + } + + // settings + this.armsFree = this.hydraCheck(); // automatically sets true for Hydra support - temporary fix + this.makesFootStepSounds = true; + this.avatarGender = MALE; + this.motionPitchMax = 60; + this.motionRollMax = 40; + + // timing + this.frameStartTime = 0; // used for measuring frame execution times + this.frameExecutionTimeMax = 0; // keep track of the longest frame execution time + this.cumulativeTime = 0.0; + this.lastWalkStartTime = 0; + + // selected animations + this.selWalk = walkAssets.maleStandardWalk; + this.selStand = walkAssets.maleStandOne; + this.selFlyUp = walkAssets.maleFlyingUp; + this.selFly = walkAssets.maleFlying; + this.selFlyDown = walkAssets.maleFlyingDown; + this.selSideStepLeft = walkAssets.maleSideStepLeft; + this.selSideStepRight = walkAssets.maleSideStepRight; + + // the currently selected animation, joint and transition + this.curAnim = this.selStand; + this.curJointIndex = 0; + this.curTransition = null; + + // zero out avi's joints, curl the fingers nicely then take some measurements + this.avatarJointNames = MyAvatar.getJointNames(); + if (!this.armsFree) { + + for (var i = 0; i < this.avatarJointNames.length; i++) { + + if (i > 17 || i < 34) + // left hand fingers + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(16, 0, 0)); + + else if (i > 33 || i < 38) + // left hand thumb + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(4, 0, 0)); + + else if (i > 41 || i < 58) + // right hand fingers + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(16, 0, 0)); + + else if (i > 57 || i < 62) + // right hand thumb + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(4, 0, 0)); + + else + // zero out the remaining joints + MyAvatar.clearJointData(this.avatarJointNames[i]); + } + } + + this.footRPos = MyAvatar.getJointPosition("RightFoot"); + this.hipsToFeet = MyAvatar.getJointPosition("Hips").y - this.footRPos.y; + + // walkwheel (foot / ground speed matching) + this.direction = FORWARDS; + this.nextStep = RIGHT; + this.nFrames = 0; + this.strideLength = this.selWalk.calibration.strideLengthForwards; + this.walkWheelPos = 0; + + this.advanceWalkWheel = function(angle){ + + this.walkWheelPos += angle; + if (motion.walkWheelPos >= 360) + this.walkWheelPos = this.walkWheelPos % 360; + } + + // last frame history + this.lastDirection = 0; + this.lastVelocity = 0; + +}; // end Motion constructor + +// finite state machine +state = (function () { + + return { + + // the finite list of states + STANDING: 1, + WALKING: 2, + SIDE_STEP: 3, + FLYING: 4, + EDIT_WALK_STYLES: 5, + EDIT_WALK_TWEAKS: 6, + EDIT_WALK_JOINTS: 7, + EDIT_STANDING: 8, + EDIT_FLYING: 9, + EDIT_FLYING_UP: 10, + EDIT_FLYING_DOWN: 11, + EDIT_SIDESTEP_LEFT: 12, + EDIT_SIDESTEP_RIGHT: 14, + currentState: this.STANDING, + + // status vars + powerOn: true, + minimised: true, + editing:false, + editingTranslation: false, + + setInternalState: function(newInternalState) { + + switch (newInternalState) { + + case this.WALKING: + + this.currentState = this.WALKING; + this.editing = false; + motion.lastWalkStartTime = new Date().getTime(); + walkInterface.updateMenu(); + return; + + case this.FLYING: + + this.currentState = this.FLYING; + this.editing = false; + motion.lastWalkStartTime = 0; + walkInterface.updateMenu(); + return; + + case this.SIDE_STEP: + + this.currentState = this.SIDE_STEP; + this.editing = false; + motion.lastWalkStartTime = new Date().getTime(); + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_STYLES: + + this.currentState = this.EDIT_WALK_STYLES; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_TWEAKS: + + this.currentState = this.EDIT_WALK_TWEAKS; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_JOINTS: + + this.currentState = this.EDIT_WALK_JOINTS; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_STANDING: + + this.currentState = this.EDIT_STANDING; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selStand; + walkInterface.updateMenu(); + return; + + case this.EDIT_SIDESTEP_LEFT: + + this.currentState = this.EDIT_SIDESTEP_LEFT; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selSideStepLeft; + walkInterface.updateMenu(); + return; + + case this.EDIT_SIDESTEP_RIGHT: + + this.currentState = this.EDIT_SIDESTEP_RIGHT; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selSideStepRight; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING: + + this.currentState = this.EDIT_FLYING; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFly; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING_UP: + + this.currentState = this.EDIT_FLYING_UP; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFlyUp; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING_DOWN: + + this.currentState = this.EDIT_FLYING_DOWN; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFlyDown; + walkInterface.updateMenu(); + return; + + case this.STANDING: + default: + + this.currentState = this.STANDING; + this.editing = false; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selStand; + walkInterface.updateMenu(); + + // initialisation - runs at script startup only + if (motion.strideLength === 0) { + + motion.setGender(MALE); + if (motion.direction === BACKWARDS) + motion.strideLength = motion.selWalk.calibration.strideLengthBackwards; + else + motion.strideLength = motion.selWalk.calibration.strideLengthForwards; + } + return; + } + } + } +})(); // end state object literal + +// constructor for animation Transition +Transition = function(lastAnimation, nextAnimation, reachPoses, transitionDuration, easingLower, easingUpper) { + + this.lastAnim = lastAnimation; // name of last animation + if (lastAnimation === motion.selWalk || + nextAnimation === motion.selSideStepLeft || + nextAnimation === motion.selSideStepRight) + 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 === motion.selWalk || + nextAnimation === motion.selSideStepLeft || + nextAnimation === motion.selSideStepRight) + 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; // placeholder / stub: array of reach poses for squash and stretch techniques + 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 = 6; // how much to turn the walkwheel each frame when transitioning to / from walking + 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? + +}; // end Transition constructor + + +walkAssets = (function () { + + // path to the sounds used for the footsteps + var _pathToSounds = 'https://s3.amazonaws.com/hifi-public/sounds/Footsteps/'; + + // 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")); + + // load the animation datafiles + Script.include(pathToAssets+"animations/dd-female-standard-walk-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-up-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-down-animation.js"); + Script.include(pathToAssets+"animations/dd-female-standing-one-animation.js"); + Script.include(pathToAssets+"animations/dd-female-sidestep-left-animation.js"); + Script.include(pathToAssets+"animations/dd-female-sidestep-right-animation.js"); + Script.include(pathToAssets+"animations/dd-male-standard-walk-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-up-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-down-animation.js"); + Script.include(pathToAssets+"animations/dd-male-standing-one-animation.js"); + Script.include(pathToAssets+"animations/dd-male-sidestep-left-animation.js"); + Script.include(pathToAssets+"animations/dd-male-sidestep-right-animation.js"); + + // read in the animation files + var _FemaleStandardWalkFile = new FemaleStandardWalk(); + var _femaleStandardWalk = _FemaleStandardWalkFile.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 _MaleStandardWalkFile = new MaleStandardWalk(filter); + var _maleStandardWalk = _MaleStandardWalkFile.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(); + + return { + + // expose the sound assets + footsteps: _footsteps, + + // expose the animation assets + femaleStandardWalk: _femaleStandardWalk, + femaleFlyingUp: _femaleFlyingUp, + femaleFlying: _femaleFlying, + femaleFlyingDown: _femaleFlyingDown, + femaleStandOne: _femaleStandOne, + femaleSideStepLeft: _femaleSideStepLeft, + femaleSideStepRight: _femaleSideStepRight, + maleStandardWalk: _maleStandardWalk, + maleFlyingUp: _maleFlyingUp, + maleFlying: _maleFlying, + maleFlyingDown: _maleFlyingDown, + maleStandOne: _maleStandOne, + maleSideStepLeft: _maleSideStepLeft, + maleSideStepRight: _maleSideStepRight, + } +})(); \ No newline at end of file diff --git a/examples/libraries/walkFilters.js b/examples/libraries/walkFilters.js new file mode 100644 index 0000000000..608618e580 --- /dev/null +++ b/examples/libraries/walkFilters.js @@ -0,0 +1,230 @@ +// +// walkFilters.js +// +// version 1.000 +// +// Created by David Wooldridge, Autumn 2014 +// +// Provides a variety of filters for use by the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +AveragingFilter = function(length) { + + //this.name = name; + this.pastValues = []; + + for(var i = 0; i < length; i++) { + + this.pastValues.push(0); + } + + // single arg is the nextInputValue + this.process = function() { + + if (this.pastValues.length === 0 && arguments[0]) { + return arguments[0]; + } + else if (arguments[0]) { + + // apply quick and simple LP filtering + this.pastValues.push(arguments[0]); + this.pastValues.shift(); + var nextOutputValue = 0; + for (var ea in this.pastValues) nextOutputValue += this.pastValues[ea]; + return nextOutputValue / this.pastValues.length; + } + else return 0; + }; +}; + +// 2nd order Butterworth LP filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html +// provides LP filtering with a more stable frequency / phase response +ButterworthFilter = function(cutOff) { + + switch(cutOff) { + + case 5: + + this.gain = 20.20612010; + this.coeffOne = -0.4775922501; + this.coeffTwo = 1.2796324250; + break; + } + + // initialise the arrays + this.xv = []; + this.yv = []; + for(var i = 0; i < 3; i++) { + this.xv.push(0); + this.yv.push(0); + } + + // process values + this.process = function(nextInputValue) { + + this.xv[0] = this.xv[1]; + this.xv[1] = this.xv[2]; + this.xv[2] = nextInputValue / this.gain; + + this.yv[0] = this.yv[1]; + this.yv[1] = this.yv[2]; + this.yv[2] = (this.xv[0] + this.xv[2]) + + 2 * this.xv[1] + + (this.coeffOne * this.yv[0]) + + (this.coeffTwo * this.yv[1]); + + return this.yv[2]; + }; +}; // end Butterworth filter contructor + +// Add harmonics to a given sine wave to form square, sawtooth or triangle waves +// Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html +WaveSynth = function(waveShape, numHarmonics, smoothing) { + + this.numHarmonics = numHarmonics; + this.waveShape = waveShape; + this.averagingFilter = new AveragingFilter(smoothing); + + // NB: frequency in radians + this.shapeWave = function(frequency) { + + // make some shapes + var harmonics = 0; + var multiplier = 0; + var iterations = this.numHarmonics * 2 + 2; + if (this.waveShape === TRIANGLE) iterations++; + + for(var n = 2; n < iterations; n++) { + + switch(this.waveShape) { + + case SAWTOOTH: + + multiplier = 1 / n; + harmonics += multiplier * Math.sin(n * frequency); + break; + + case TRIANGLE: + + if (n % 2 === 1) { + + var mulitplier = 1 / (n * n); + + // multiply every (4n-1)th harmonic by -1 + if (n === 3 || n === 7 || n === 11 || n === 15) + mulitplier *= -1; + harmonics += mulitplier * Math.sin(n * frequency); + } + break; + + case SQUARE: + + if (n % 2 === 1) { + + multiplier = 1 / n; + harmonics += multiplier * Math.sin(n * frequency); + } + break; + } + } + + // smooth the result and return + return this.averagingFilter.process(harmonics); + }; +}; + +// Create a wave shape by summing pre-calcualted sinusoidal harmonics +HarmonicsFilter = function(magnitudes, phaseAngles) { + + this.magnitudes = magnitudes; + this.phaseAngles = phaseAngles; + + this.calculate = function(twoPiFT) { + + var harmonics = 0; + var numHarmonics = magnitudes.length; + + for(var n = 0; n < numHarmonics; n++) + + harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]); + + return harmonics; + }; +}; + +// the main filter object literal +filter = (function() { + + // Bezier private functions + 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) }; + + return { + + // helper methods + degToRad: function(degrees) { + + var convertedValue = degrees * Math.PI / 180; + return convertedValue; + }, + + radToDeg: function(radians) { + + var convertedValue = radians * 180 / Math.PI; + return convertedValue; + }, + + // these filters need instantiating, as they hold arrays of previous values + createAveragingFilter: function(length) { + + var newAveragingFilter = new AveragingFilter(length); + return newAveragingFilter; + }, + + createButterworthFilter: function(cutoff) { + + var newButterworthFilter = new ButterworthFilter(cutoff); + return newButterworthFilter; + }, + + createWaveSynth: function(waveShape, numHarmonics, smoothing) { + + var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing); + return newWaveSynth; + }, + + createHarmonicsFilter: function(magnitudes, phaseAngles) { + + var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles); + return newHarmonicsFilter; + }, + + + // the following filters do not need separate instances, as they hold no previous values + bezier: function(percent, C1, C2, C3, C4) { + + // Bezier functions for more natural transitions + // based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/ + var pos = {x: 0, y: 0}; + 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; + }, + + // simple clipping filter (faster way to make square waveforms) + clipTrough: function(inputValue, peak, strength) { + + var outputValue = inputValue * strength; + if (outputValue < -peak) + outputValue = -peak; + + return outputValue; + } + } + +})(); \ No newline at end of file diff --git a/examples/libraries/walkInterface.js b/examples/libraries/walkInterface.js new file mode 100644 index 0000000000..71e4462933 --- /dev/null +++ b/examples/libraries/walkInterface.js @@ -0,0 +1,2713 @@ +// +// walkInterface.js +// +// version 1.000 +// +// Created by David Wooldridge, Autumn 2014 +// +// Presents the UI for the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +walkInterface = (function() { + + // controller element positions and 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 _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 menu buttons + var _bigButtonsY = 408; // distance from top of panel to top of first big button + + // arrays of overlay names + var _sliderThumbOverlays = []; + var _backgroundOverlays = []; + var _buttonOverlays = []; + var _jointsControlOverlays = []; + var _bigbuttonOverlays = []; + + // reference to the internal state + var _state = { + editingTranslation: false + }; + + // reference to the Motion object + var _motion = null; + + var _walkAssets = null; + + // constants + var MAX_WALK_SPEED = 1257; + + // look and feel + var momentaryButtonTimer = null; + + // all slider controls have a range (with the exception of phase controls that are always +-180) + var _sliderRanges = { + "joints": [{ + "name": "hips", + "pitchRange": 12, + "yawRange": 18, + "rollRange": 12, + "pitchOffsetRange": 25, + "yawOffsetRange": 25, + "rollOffsetRange": 25, + "swayRange": 0.12, + "bobRange": 0.05, + "thrustRange": 0.05, + "swayOffsetRange": 0.25, + "bobOffsetRange": 0.25, + "thrustOffsetRange": 0.25 + }, { + "name": "upperLegs", + "pitchRange": 30, + "yawRange": 35, + "rollRange": 35, + "pitchOffsetRange": 20, + "yawOffsetRange": 20, + "rollOffsetRange": 20 + }, { + "name": "lowerLegs", + "pitchRange": 10, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 180, + "yawOffsetRange": 20, + "rollOffsetRange": 20 + }, { + "name": "feet", + "pitchRange": 10, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 180, + "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 + }] + }; + + // load overlay images + var _controlsMinimisedTab = Overlays.addOverlay("image", { + x: Window.innerWidth - 58, + y: Window.innerHeight - 145, + width: 50, + height: 50, + imageURL: pathToAssets + 'overlay-images/ddao-minimise-tab.png', + visible: true, + alpha: 0.9 + }); + + var _controlsBackground = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/ddao-background-edit-tweaks.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditTweaks); + + var _controlsBackgroundWalkEditHipTrans = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-translation.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditHipTrans); + + var _controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-joints.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditJoints); + + // load character joint selection control images + var _hipsJointsTranslation = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-hips-translation.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_hipsJointsTranslation); + + var _hipsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/ddao-background-edit-head.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_headJointControl); + + + // slider thumb overlays + var _sliderOne = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/ddao-joints-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: pathToAssets + "overlay-images/ddao-joints-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: pathToAssets + "overlay-images/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: pathToAssets + "overlay-images/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 _femaleBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 60, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 60, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 120, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 120, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 180, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/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 + _bigButtonsY + 180, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-footsteps-big-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_footstepsBigButtonSelected); + + + // walk styles + _bigButtonsY = 121; + var _standardWalkBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-select-button-standard.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_standardWalkBigButton); + + var _standardWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-select-button-standard-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_standardWalkBigButtonSelected); + + // various show / hide GUI element functions + function minimiseDialog(minimise) { + + if (momentaryButtonTimer) { + Script.clearInterval(momentaryButtonTimer); + momentaryButtonTimer = null; + } + + if (minimise) { + setBackground(); + hideMenuButtons(); + setSliderThumbsVisible(false); + hideJointSelectors(); + initialiseFrontPanel(false); + Overlays.editOverlay(_controlsMinimisedTab, { + visible: true + }); + } else { + Overlays.editOverlay(_controlsMinimisedTab, { + visible: false + }); + } + }; + + function setBackground(backgroundID) { + for (var i in _backgroundOverlays) { + if (_backgroundOverlays[i] === backgroundID) + Overlays.editOverlay(_backgroundOverlays[i], { + visible: true + }); + else Overlays.editOverlay(_backgroundOverlays[i], { + visible: false + }); + } + }; + + // top row menu type buttons (on | walk | stand | fly | hide) + function hideMenuButtons() { + for (var i in _buttonOverlays) { + Overlays.editOverlay(_buttonOverlays[i], { + visible: false + }); + } + }; + + function hideJointSelectors() { + 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 setButtonOverlayVisible(buttonOverlayName) { + for (var i in _buttonOverlays) { + if (_buttonOverlays[i] === buttonOverlayName) { + Overlays.editOverlay(buttonOverlayName, { + visible: true + }); + } + } + }; + + function initialiseFrontPanel(showButtons) { + + if (_motion.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 (_motion.armsFree) { + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: false + }); + + } else { + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: showButtons + }); + } + if (_motion.makesFootStepSounds) { + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: false + }); + + } else { + + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: showButtons + }); + } + }; + + function initialiseWalkStylesPanel(showButtons) { + + // set all big buttons to hidden, but skip the first 8, as are used by 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: true + }); + } + + // set the currently selected one + if (_motion.selWalk === _walkAssets.femaleStandardWalk || + _motion.selWalk === _walkAssets.maleStandardWalk) { + + Overlays.editOverlay(_standardWalkBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_standardWalkBigButton, { + visible: false + }); + } + }; + + function initialiseWalkTweaksPanel() { + + // sliders for commonly required walk adjustments + var i = 0; + var yLocation = _backgroundY + 71; + + // walk speed + var sliderXPos = _motion.curAnim.calibration.frequency / MAX_WALK_SPEED * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // lean (hips pitch offset) + sliderXPos = (((_sliderRanges.joints[0].pitchOffsetRange + _motion.curAnim.joints[0].pitchOffset) / 2) / + _sliderRanges.joints[0].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // stride (upper legs pitch) + sliderXPos = _motion.curAnim.joints[1].pitch / _sliderRanges.joints[1].pitchRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Legs separation (upper legs roll offset) + sliderXPos = (((_sliderRanges.joints[1].rollOffsetRange + _motion.curAnim.joints[1].rollOffset) / 2) / + _sliderRanges.joints[1].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Legs forward (upper legs pitch offset) + sliderXPos = (((_sliderRanges.joints[1].pitchOffsetRange + _motion.curAnim.joints[1].pitchOffset) / 2) / + _sliderRanges.joints[1].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Lower legs splay (lower legs roll offset) + sliderXPos = (((_sliderRanges.joints[2].rollOffsetRange + _motion.curAnim.joints[2].rollOffset) / 2) / + _sliderRanges.joints[2].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Arms forward (upper arms yaw offset) + sliderXPos = (((_sliderRanges.joints[9].yawOffsetRange + _motion.curAnim.joints[9].yawOffset) / 2) / + _sliderRanges.joints[9].yawOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Arms out (upper arm pitch offset) + sliderXPos = (((_sliderRanges.joints[9].pitchOffsetRange - _motion.curAnim.joints[9].pitchOffset) / 2) / + _sliderRanges.joints[9].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Lower arms splay (lower arm pitch offset) + sliderXPos = (((_sliderRanges.joints[10].pitchOffsetRange - _motion.curAnim.joints[10].pitchOffset) / 2) / + _sliderRanges.joints[10].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + }; + + function initialiseJointsEditingPanel() { + + var i = 0; + var yLocation = _backgroundY + 359; + hideJointSelectors(); + + if (_state.editingTranslation) { + + // display the joint control selector for hips translations + Overlays.editOverlay(_hipsJointsTranslation, {visible: true}); + + // Hips sway + var sliderXPos = _motion.curAnim.joints[0].sway / _sliderRanges.joints[0].swayRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Hips bob + sliderXPos = _motion.curAnim.joints[0].bob / _sliderRanges.joints[0].bobRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Hips thrust + sliderXPos = _motion.curAnim.joints[0].thrust / _sliderRanges.joints[0].thrustRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Sway Phase + sliderXPos = (90 + _motion.curAnim.joints[0].swayPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Bob Phase + sliderXPos = (90 + _motion.curAnim.joints[0].bobPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Thrust Phase + sliderXPos = (90 + _motion.curAnim.joints[0].thrustPhase / 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 we centre them + sliderXPos = (((_sliderRanges.joints[0].swayOffsetRange + _motion.curAnim.joints[0] + .swayOffset) / 2) / _sliderRanges.joints[0].swayOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[0].bobOffsetRange + _motion.curAnim.joints[0] + .bobOffset) / 2) / _sliderRanges.joints[0].bobOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[0].thrustOffsetRange + _motion.curAnim.joints[0] + .thrustOffset) / 2) / _sliderRanges.joints[0].thrustOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + } else { + + switch (_motion.curJointIndex) { + + 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; + } + + var sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].pitch / + _sliderRanges.joints[_motion.curJointIndex].pitchRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].yaw / + _sliderRanges.joints[_motion.curJointIndex].yawRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].roll / + _sliderRanges.joints[_motion.curJointIndex].rollRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // set phases (full range, -180 to 180) + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].pitchPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].yawPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].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 we offset + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].pitchOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].yawOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].yawOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].yawOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].rollOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].rollOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + } + }; + + // 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 + }); + + if (_state.currentState === _state.EDIT_WALK_JOINTS || + _state.currentState === _state.EDIT_STANDING || + _state.currentState === _state.EDIT_FLYING || + _state.currentState === _state.EDIT_FLYING_UP || + _state.currentState === _state.EDIT_FLYING_DOWN || + _state.currentState === _state.EDIT_SIDESTEP_LEFT || + _state.currentState === _state.EDIT_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) { + _motion.curJointIndex = 0; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 63 && clickX < 132 && clickY > 156 && clickY < 202) { + _motion.curJointIndex = 1; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 203 && clickY < 250) { + _motion.curJointIndex = 2; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 250 && clickY < 265) { + _motion.curJointIndex = 3; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 265 && clickY < 280) { + _motion.curJointIndex = 4; + initialiseJointsEditingPanel(); + return; + } else if (clickX > 78 && clickX < 121 && clickY > 111 && clickY < 128) { + _motion.curJointIndex = 5; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 78 && clickX < 128 && clickY > 89 && clickY < 111) { + _motion.curJointIndex = 6; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 85 && clickX < 118 && clickY > 77 && clickY < 94) { + _motion.curJointIndex = 7; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 64 && clickX < 125 && clickY > 55 && clickY < 77) { + _motion.curJointIndex = 8; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 44 && clickX < 73 && clickY > 71 && clickY < 94) || + (clickX > 125 && clickX < 144 && clickY > 71 && clickY < 94)) { + _motion.curJointIndex = 9; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 28 && clickX < 57 && clickY > 94 && clickY < 119) || + (clickX > 137 && clickX < 170 && clickY > 97 && clickY < 114)) { + _motion.curJointIndex = 10; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 18 && clickX < 37 && clickY > 115 && clickY < 136) || + (clickX > 157 && clickX < 182 && clickY > 115 && clickY < 136)) { + _motion.curJointIndex = 11; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 81 && clickX < 116 && clickY > 12 && clickY < 53) { + _motion.curJointIndex = 12; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 188 && clickX < 233 && clickY > 6 && clickY < 34) { + + // translation editing radio selection + if (_state.editingTranslation) { + + hideJointSelectors(); + setBackground(_controlsBackgroundWalkEditJoints); + _state.editingTranslation = false; + + } else { + + hideJointSelectors(); + setBackground(_controlsBackgroundWalkEditHipTrans); + _state.editingTranslation = true; + } + initialiseJointsEditingPanel(); + return; + } + } + + switch (clickedOverlay) { + + case _offButton: + + _state.powerOn = true; + Overlays.editOverlay(_offButton, { + visible: false + }); + Overlays.editOverlay(_onButton, { + visible: true + }); + _state.setInternalState(state.STANDING); + return; + + case _controlsMinimisedTab: + + _state.minimised = false; + minimiseDialog(_state.minimised); + _state.setInternalState(_state.STANDING); + return; + + case _hideButton: + _hideButtonSelected: + + Overlays.editOverlay(_hideButton, { + visible: false + }); + Overlays.editOverlay(_hideButtonSelected, { + visible: true + }); + _state.minimised = true; + momentaryButtonTimer = Script.setInterval(function() { + minimiseDialog(_state.minimised); + }, 80); + return; + + case _backButton: + + Overlays.editOverlay(_backButton, { + visible: false + }); + Overlays.editOverlay(_backButtonSelected, { + visible: true + }); + momentaryButtonTimer = Script.setInterval(function() { + + _state.setInternalState(_state.STANDING); + Overlays.editOverlay(_backButton, { + visible: false + }); + Overlays.editOverlay(_backButtonSelected, { + visible: false + }); + Script.clearInterval(momentaryButtonTimer); + momentaryButtonTimer = null; + }, 80); + return; + + case _footstepsBigButton: + + _motion.makesFootStepSounds = true; + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: false + }); + return; + + case _footstepsBigButtonSelected: + + _motion.makesFootStepSounds = false; + Overlays.editOverlay(_footstepsBigButton, { + visible: true + }); + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: false + }); + return; + + case _femaleBigButton: + case _maleBigButtonSelected: + + _motion.setGender(FEMALE); + + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_femaleBigButton, { + visible: false + }); + Overlays.editOverlay(_maleBigButton, { + visible: true + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: false + }); + return; + + case _maleBigButton: + case _femaleBigButtonSelected: + + _motion.setGender(MALE); + + Overlays.editOverlay(_femaleBigButton, { + visible: true + }); + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_maleBigButton, { + visible: false + }); + return; + + case _armsFreeBigButton: + + _motion.armsFree = true; + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: false + }); + return; + + case _armsFreeBigButtonSelected: + + _motion.armsFree = false; + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: true + }); + return; + + case _standardWalkBigButton: + + if (_motion.avatarGender === FEMALE) _motion.selWalk = _motion.femaleStandardWalk; + else _motion.selWalk = _motion.maleStandardWalk; + _motion.curAnim = _motion.selWalk; + initialiseWalkStylesPanel(true); + return; + + case _standardWalkBigButtonSelected: + + // toggle forwards / backwards walk display + if (_motion.direction === FORWARDS) { + _motion.direction = BACKWARDS; + } else _motion.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; + + case _configWalkButtonSelected: + case _configStandButtonSelected: + case _configSideStepLeftButtonSelected: + case _configSideStepRightButtonSelected: + case _configFlyingButtonSelected: + case _configFlyingUpButtonSelected: + case _configFlyingDownButtonSelected: + case _configWalkStylesButtonSelected: + case _configWalkTweaksButtonSelected: + case _configWalkJointsButtonSelected: + + // exit edit modes + _motion.curAnim = _motion.selStand; + _state.setInternalState(_state.STANDING); + break; + + case _onButton: + + _state.powerOn = false; + _state.setInternalState(state.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 + }); + _state.setInternalState(_state.STANDING); + break; + + case _configWalkStylesButton: + + _state.setInternalState(_state.EDIT_WALK_STYLES); + break; + + case _configWalkTweaksButton: + + _state.setInternalState(_state.EDIT_WALK_TWEAKS); + break; + + case _configWalkJointsButton: + + _state.setInternalState(_state.EDIT_WALK_JOINTS); + break; + + case _configWalkButton: + + _state.setInternalState(_state.EDIT_WALK_STYLES); + break; + + case _configStandButton: + + _state.setInternalState(_state.EDIT_STANDING); + break; + + case _configSideStepLeftButton: + _state.setInternalState(_state.EDIT_SIDESTEP_LEFT); + + break; + + case _configSideStepRightButton: + + _state.setInternalState(_state.EDIT_SIDESTEP_RIGHT); + break; + + case _configFlyingButton: + + _state.setInternalState(_state.EDIT_FLYING); + break; + + case _configFlyingUpButton: + + _state.setInternalState(_state.EDIT_FLYING_UP); + break; + + case _configFlyingDownButton: + + _state.setInternalState(_state.EDIT_FLYING_DOWN); + break; + } + }; + + function mouseMoveEvent(event) { + + // workaround for bug (https://worklist.net/20160) + if ((event.x > 310 && event.x < 318 && event.y > 1350 && event.y < 1355) || + (event.x > 423 && event.x < 428 && event.y > 1505 && event.y < 1508 )) return; + + if (_state.currentState === _state.EDIT_WALK_JOINTS || + _state.currentState === _state.EDIT_STANDING || + _state.currentState === _state.EDIT_FLYING || + _state.currentState === _state.EDIT_FLYING_UP || + _state.currentState === _state.EDIT_FLYING_DOWN || + _state.currentState === _state.EDIT_SIDESTEP_LEFT || + _state.currentState === _state.EDIT_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 or sway + Overlays.editOverlay(_sliderOne, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].sway = + thumbPositionNormalised * _sliderRanges.joints[0].swayRange; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].pitch = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].pitchRange; + } + + } else if (_movingSliderTwo) { + + // currently selected joint yaw or bob + Overlays.editOverlay(_sliderTwo, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].bob = + thumbPositionNormalised * _sliderRanges.joints[0].bobRange; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].yaw = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].yawRange; + } + + } else if (_movingSliderThree) { + + // currently selected joint roll or thrust + Overlays.editOverlay(_sliderThree, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].thrust = + thumbPositionNormalised * _sliderRanges.joints[0].thrustRange; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].roll = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].rollRange; + } + + } else if (_movingSliderFour) { + + // currently selected joint pitch phase + Overlays.editOverlay(_sliderFour, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].swayPhase = newPhase; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].pitchPhase = newPhase; + } + + } else if (_movingSliderFive) { + + // currently selected joint yaw phase; + Overlays.editOverlay(_sliderFive, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].bobPhase = newPhase; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].yawPhase = newPhase; + } + + } else if (_movingSliderSix) { + + // currently selected joint roll phase + Overlays.editOverlay(_sliderSix, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + + _motion.curAnim.joints[0].thrustPhase = newPhase; + + } else { + + _motion.curAnim.joints[_motion.curJointIndex].rollPhase = newPhase; + } + + } else if (_movingSliderSeven) { + + // currently selected joint pitch offset + Overlays.editOverlay(_sliderSeven, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[0].swayOffsetRange; + _motion.curAnim.joints[0].swayOffset = newOffset; + + } else { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].pitchOffset = newOffset; + } + + } else if (_movingSliderEight) { + + // currently selected joint yaw offset + Overlays.editOverlay(_sliderEight, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 *_sliderRanges.joints[0].bobOffsetRange; + _motion.curAnim.joints[0].bobOffset = newOffset; + + } else { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].yawOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].yawOffset = newOffset; + } + + } else if (_movingSliderNine) { + + // currently selected joint roll offset + Overlays.editOverlay(_sliderNine, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[0].thrustOffsetRange; + _motion.curAnim.joints[0].thrustOffset = newOffset; + + } else { + + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].rollOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].rollOffset = newOffset; + } + } + + } // end if editing joints + else if (_state.currentState === _state.EDIT_WALK_TWEAKS) { + + // sliders for commonly required walk adjustments + 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 + Overlays.editOverlay(_sliderOne, { + x: sliderX + _minSliderX + }); + _motion.curAnim.calibration.frequency = thumbPositionNormalised * MAX_WALK_SPEED; + + } else if (_movingSliderTwo) { + + // lean (hips pitch offset) + Overlays.editOverlay(_sliderTwo, { + x: sliderX + _minSliderX + }); + var newOffset = (thumbPositionNormalised - 0.5) * 2 * _sliderRanges.joints[0].pitchOffsetRange; + _motion.curAnim.joints[0].pitchOffset = newOffset; + + } else if (_movingSliderThree) { + + // stride (upper legs pitch) + Overlays.editOverlay(_sliderThree, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].pitch = thumbPositionNormalised * _sliderRanges.joints[1].pitchRange; + + } else if (_movingSliderFour) { + + // legs separation (upper legs roll) + Overlays.editOverlay(_sliderFour, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].rollOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[1].rollOffsetRange; + + } else if (_movingSliderFive) { + + // legs forward (lower legs pitch offset) + Overlays.editOverlay(_sliderFive, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].pitchOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[1].pitchOffsetRange; + + } else if (_movingSliderSix) { + + // lower legs splay (lower legs roll offset) + Overlays.editOverlay(_sliderSix, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[2].rollOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[2].rollOffsetRange; + + } else if (_movingSliderSeven) { + + // arms forward (upper arms yaw offset) + Overlays.editOverlay(_sliderSeven, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[9].yawOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[9].yawOffsetRange; + + } else if (_movingSliderEight) { + + // arms out (upper arm pitch offset) + Overlays.editOverlay(_sliderEight, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[9].pitchOffset = (thumbPositionNormalised - 0.5) * + -2 * _sliderRanges.joints[9].pitchOffsetRange; + + } else if (_movingSliderNine) { + + // lower arms splay (lower arm pitch offset) + Overlays.editOverlay(_sliderNine, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[10].pitchOffset = (thumbPositionNormalised - 0.5) * + -2 * _sliderRanges.joints[10].pitchOffsetRange; + } + + } // if tweaking + }; + + function mouseReleaseEvent(event) { + + 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; + }; + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + + // Script ending + Script.scriptEnding.connect(function() { + + // delete the background overlays + for (var i in _backgroundOverlays) { + Overlays.deleteOverlay(_backgroundOverlays[i]); + } + // delete the button overlays + for (var i in _buttonOverlays) { + Overlays.deleteOverlay(_buttonOverlays[i]); + } + // delete the slider thumb overlays + for (var i in _sliderThumbOverlays) { + Overlays.deleteOverlay(_sliderThumbOverlays[i]); + } + // delete the character joint control overlays + for (var i in _jointsControlOverlays) { + Overlays.deleteOverlay(_jointsControlOverlays[i]); + } + // delete the big button overlays + for (var i in _bigbuttonOverlays) { + Overlays.deleteOverlay(_bigbuttonOverlays[i]); + } + // delete the mimimised tab + Overlays.deleteOverlay(_controlsMinimisedTab); + }); + + // public methods + return { + + // gather references to objects from the walk.js script + initialise: function(state, motion, walkAssets) { + + _state = state; + _motion = motion; + _walkAssets = walkAssets; + }, + + updateMenu: function() { + + if (!_state.minimised) { + + switch (_state.currentState) { + + case _state.EDIT_WALK_STYLES: + case _state.EDIT_WALK_TWEAKS: + case _state.EDIT_WALK_JOINTS: + + hideMenuButtons(); + initialiseFrontPanel(false); + hideJointSelectors(); + + if (_state.currentState === _state.EDIT_WALK_STYLES) { + + setBackground(_controlsBackgroundWalkEditStyles); + initialiseWalkStylesPanel(true); + setSliderThumbsVisible(false); + hideJointSelectors(); + setButtonOverlayVisible(_configWalkStylesButtonSelected); + setButtonOverlayVisible(_configWalkTweaksButton); + setButtonOverlayVisible(_configWalkJointsButton); + + } else if (_state.currentState === _state.EDIT_WALK_TWEAKS) { + + setBackground(_controlsBackgroundWalkEditTweaks); + initialiseWalkStylesPanel(false); + setSliderThumbsVisible(true); + hideJointSelectors(); + initialiseWalkTweaksPanel(); + setButtonOverlayVisible(_configWalkStylesButton); + setButtonOverlayVisible(_configWalkTweaksButtonSelected); + setButtonOverlayVisible(_configWalkJointsButton); + + } else if (_state.currentState === _state.EDIT_WALK_JOINTS) { + + if (_state.editingTranslation) + setBackground(_controlsBackgroundWalkEditHipTrans); + else + setBackground(_controlsBackgroundWalkEditJoints); + + initialiseWalkStylesPanel(false); + setSliderThumbsVisible(true); + setButtonOverlayVisible(_configWalkStylesButton); + setButtonOverlayVisible(_configWalkTweaksButton); + setButtonOverlayVisible(_configWalkJointsButtonSelected); + initialiseJointsEditingPanel(); + } + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + + case _state.EDIT_STANDING: + case _state.EDIT_SIDESTEP_LEFT: + case _state.EDIT_SIDESTEP_RIGHT: + + if (_state.editingTranslation) + setBackground(_controlsBackgroundWalkEditHipTrans); + else + setBackground(_controlsBackgroundWalkEditJoints); + hideMenuButtons(); + initialiseWalkStylesPanel(false); + initialiseFrontPanel(false); + + if (_state.currentState === _state.EDIT_SIDESTEP_LEFT) { + + setButtonOverlayVisible(_configSideStepRightButton); + setButtonOverlayVisible(_configSideStepLeftButtonSelected); + setButtonOverlayVisible(_configStandButton); + + } else if (_state.currentState === _state.EDIT_SIDESTEP_RIGHT) { + + setButtonOverlayVisible(_configSideStepRightButtonSelected); + setButtonOverlayVisible(_configSideStepLeftButton); + setButtonOverlayVisible(_configStandButton); + + } else if (_state.currentState === _state.EDIT_STANDING) { + + setButtonOverlayVisible(_configSideStepRightButton); + setButtonOverlayVisible(_configSideStepLeftButton); + setButtonOverlayVisible(_configStandButtonSelected); + } + initialiseJointsEditingPanel(); + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + + case _state.EDIT_FLYING: + case _state.EDIT_FLYING_UP: + case _state.EDIT_FLYING_DOWN: + + setBackground(_controlsBackgroundWalkEditJoints); + hideMenuButtons(); + initialiseWalkStylesPanel(false); + initialiseFrontPanel(false); + if (_state.currentState === _state.EDIT_FLYING) { + + setButtonOverlayVisible(_configFlyingUpButton); + setButtonOverlayVisible(_configFlyingDownButton); + setButtonOverlayVisible(_configFlyingButtonSelected); + + } else if (_state.currentState === _state.EDIT_FLYING_UP) { + + setButtonOverlayVisible(_configFlyingUpButtonSelected); + setButtonOverlayVisible(_configFlyingDownButton); + setButtonOverlayVisible(_configFlyingButton); + + } else if (_state.currentState === _state.EDIT_FLYING_DOWN) { + + setButtonOverlayVisible(_configFlyingUpButton); + setButtonOverlayVisible(_configFlyingDownButtonSelected); + setButtonOverlayVisible(_configFlyingButton); + } + initialiseJointsEditingPanel(); + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + + case _state.STANDING: + case _state.WALKING: + case _state.FLYING: + case _state.SIDE_STEP: + default: + + hideMenuButtons(); + hideJointSelectors(); + setBackground(_controlsBackground); + if (_state.powerOn) setButtonOverlayVisible(_onButton); + else setButtonOverlayVisible(_offButton); + setButtonOverlayVisible(_configWalkButton); + setButtonOverlayVisible(_configStandButton); + setButtonOverlayVisible(_configFlyingButton); + setButtonOverlayVisible(_hideButton); + setSliderThumbsVisible(false); + initialiseFrontPanel(true); + initialiseWalkStylesPanel(false); + return; + } + } + } + }; // end public methods (return) + +})(); \ No newline at end of file diff --git a/examples/walk.js b/examples/walk.js index a9e8f401d6..1e1cd7748b 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,3851 +1,2562 @@ // // walk.js // -// version 1.007b +// version 1.1 // -// Created by Davedub, August / September 2014 +// Created by David Wooldridge, Autumn 2014 +// +// Animates an avatar using procedural animation techniques // // 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; +var MAX_WALK_SPEED = 2.5; +var TAKE_FLIGHT_SPEED = 4.55; +var TOP_SPEED = 300; +var UP = 1; +var DOWN = 2; +var LEFT = 4; +var RIGHT = 8; +var FORWARDS = 16; +var BACKWARDS = 32; -// start of animation control section -var cumulativeTime = 0.0; -var lastOrientation; +// ovelay images location +var pathToAssets = 'http://s3.amazonaws.com/hifi-public/WalkScript/'; -// 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) { +// load the UI +Script.include("./libraries/walkInterface.js"); - // 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 +// load filters (Bezier, Butterworth, add harmonics, averaging) +Script.include("./libraries/walkFilters.js"); -// 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 +// load objects, constructors and assets (state, Motion, Transition, walkAssets) +Script.include("./libraries/walkApi.js"); -// 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 +// initialise the motion state / history object +var motion = new Motion(); -// 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; -} +// initialise Transitions +var nullTransition = new Transition(); +motion.curTransition = nullTransition; -// 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); - } +// initialise the UI +walkInterface.initialise(state, motion, walkAssets); - // recentDirection 'method' args: (direction enum, number of steps back to compare) - this.recentDirection = function () { +// wave shapes +var SAWTOOTH = 1; +var TRIANGLE = 2; +var SQUARE = 4; - if( arguments[0] && arguments[1] ) { +// filters for synthesising more complex, natural waveforms +var leanPitchFilter = filter.createAveragingFilter(15); +var leanRollFilter = filter.createAveragingFilter(15); +var hipsYawShaper = filter.createWaveSynth(TRIANGLE, 3, 2); +var hipsBobLPFilter = filter.createButterworthFilter(5); - 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) { + if (state.powerOn) { - frameStartTime = new Date().getTime(); - cumulativeTime += deltaTime; - nFrames++; - var speed = 0; + motion.frameStartTime = new Date().getTime(); + motion.cumulativeTime += deltaTime; + motion.nFrames++; + var speed = 0; - // firstly check for editing modes, as these require no positioning calculations - var editing = false; - switch(INTERNAL_STATE) { + // check for editing modes first, as these require no positioning calculations + switch (state.currentState) { - 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; - } + case state.EDIT_WALK_STYLES: + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + 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(); + case state.EDIT_WALK_TWEAKS: + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; - // 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()); + case state.EDIT_WALK_JOINTS: + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; - if(!editing) { + case state.EDIT_STANDING: + motion.curAnim = motion.selStand; + motion.direction = FORWARDS; + animateAvatar(deltaTime, speed); + break; - // 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 + case state.EDIT_SIDESTEP_LEFT: + motion.curAnim = motion.selSideStepLeft; + motion.direction = LEFT; + animateAvatar(deltaTime, speed); + break; - // calcualte (local) change in velocity - var velocity = MyAvatar.getVelocity(); - speed = Vec3.length(velocity); + case state.EDIT_SIDESTEP_RIGHT: + motion.curAnim = motion.selSideStepRight; + motion.direction = RIGHT; + animateAvatar(deltaTime, speed); + break; - // 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++; - } + case state.EDIT_FLYING: + motion.curAnim = motion.selFly; + motion.direction = FORWARDS; + animateAvatar(deltaTime, speed); + break; - deltaX = localVelocity.x; - deltaY = localVelocity.y; - deltaZ = -localVelocity.z; + case state.EDIT_FLYING_UP: + motion.curAnim = motion.selFlyUp; + motion.direction = UP; + animateAvatar(deltaTime, speed); + break; + + case state.EDIT_FLYING_DOWN: + motion.curAnim = motion.selFlyDown; + motion.direction = DOWN; + animateAvatar(deltaTime, speed); + break; + + default: + break; + } + + // calcualte velocity and speed + var velocity = MyAvatar.getVelocity(); + speed = Vec3.length(velocity); + + if (motion.curTransition !== nullTransition) { + + // finish any live transition before changing state + animateAvatar(deltaTime, speed); + return; + } + var localVelocity = {x: 0, y: 0, z: 0}; + if (speed > 0) + localVelocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), velocity); + + if (!state.editing) { + + // determine the candidate animation state + var actionToTake = undefined; + if (speed < 0.05) actionToTake = state.STANDING; // as per MIN_AVATAR_SPEED, MyAvatar.cpp + else if (speed < TAKE_FLIGHT_SPEED) actionToTake = state.WALKING; + else if (speed >= TAKE_FLIGHT_SPEED) actionToTake = state.FLYING; // 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; - } - } + if (Math.abs(localVelocity.x) > Math.abs(localVelocity.y) && + Math.abs(localVelocity.x) > Math.abs(localVelocity.z)) { - // 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 + if (localVelocity.x < 0) motion.direction = LEFT; + else motion.direction = RIGHT; + + } else if (Math.abs(localVelocity.y) > Math.abs(localVelocity.x) && + Math.abs(localVelocity.y) > Math.abs(localVelocity.z)) { + + if (localVelocity.y > 0) motion.direction = UP; + else motion.direction = DOWN; + + } else if (Math.abs(localVelocity.z) > Math.abs(localVelocity.x) && + Math.abs(localVelocity.z) > Math.abs(localVelocity.y)) { + + if (localVelocity.z < 0) motion.direction = FORWARDS; + else motion.direction = BACKWARDS; + } // 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}; + if (actionToTake === state.WALKING && + (motion.direction === LEFT || + motion.direction === RIGHT)) + actionToTake = state.SIDE_STEP; + // maybe at walking speed, but flying up or down? + if (actionToTake === state.WALKING && + (motion.direction === UP))// || + //motion.direction === DOWN)) + actionToTake = state.FLYING; // select appropriate animation and initiate Transition if required - switch(actionToTake) { + switch (actionToTake) { - case STANDING: + case state.STANDING: - if( standHints > requiredHints || INTERNAL_STATE===STANDING) { // wait for a few consecutive hints (17mS each) + // do we need to change state? + if (state.currentState !== state.STANDING) { - standHints = 0; - walkHints = 0; - flyHints = 0; + switch (motion.curAnim) { - // do we need to change state? - if( INTERNAL_STATE!==STANDING ) { + case motion.selWalk: - // initiate the transition - if(currentTransition) { - delete currentTransition; - currentTransition = null; - } + // Walking to standing + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.25, + {x: 0.1, y: 0.5}, + {x: -0.25, y: 1.22}); + break; - switch(currentAnimation) { + case motion.selSideStepLeft: + case motion.selSideStepRight: - case selectedWalk: + break; - // Walking to Standing - var timeWalking = new Date().getTime() - framesHistory.lastWalkStartTime; + default: - var bezierCoeffsOne = {x:0.0, y:1.0}; - var bezierCoeffsTwo = {x:0.0, y:1.0}; - var transitionTime = 0.4; + // flying to standing + motion.curTransition = new Transition( + motion.curAnim, + motion.selStand, + [], 0.25, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + state.setInternalState(state.STANDING); + motion.curAnim = motion.selStand; + } + animateAvatar(deltaTime, speed); + break; - // 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 state.WALKING: + if (state.currentState !== state.WALKING) { - case selectedSideStepLeft: - case selectedSideStepRight: + if (motion.direction === BACKWARDS) + motion.walkWheelPos = motion.selWalk.calibration.startAngleBackwards; + + else motion.walkWheelPos = motion.selWalk.calibration.startAngleForwards; + + switch (motion.curAnim) { + + case motion.selStand: + + // Standing to Walking + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.1, + {x: 0.5, y: 0.1}, + {x: 0.5, y: 0.9}); + break; + + case motion.selSideStepLeft: + case motion.selSideStepRight: + + break; + + default: + + // Flying to Walking + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.1, + {x: 0.24, y: 0.03}, + {x: 0.42, y: 1.0}); + break; + } + state.setInternalState(state.WALKING); + } + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; + + case state.SIDE_STEP: + + var selSideStep = 0; + if (motion.direction === LEFT) { + + if (motion.lastDirection !== LEFT) + motion.walkWheelPos = motion.selSideStepLeft.calibration.cycleStart; + selSideStep = motion.selSideStepLeft; + + } else { + + if (motion.lastDirection !== RIGHT) + motion.walkWheelPos = motion.selSideStepRight.calibration.cycleStart; + selSideStep = motion.selSideStepRight; + } + + if (state.currentState !== state.SIDE_STEP) { + + if (motion.direction === LEFT) { + + motion.walkWheelPos = motion.selSideStepLeft.calibration.cycleStart; + switch (motion.curAnim) { + + case motion.selStand: 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 + motion.walkWheelPos = motion.selSideStepRight.calibration.cycleStart; + switch (motion.curAnim) { - // initiate a Transition - if(currentTransition && currentTransition.nextAnimation!==selectedFly) { - delete currentTransition; - currentTransition = null; - } - switch(currentAnimation) { + case motion.selStand: - case selectedStand: + break; - currentTransition = new Transition(currentAnimation, selectedFly, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; + default: - 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; + break; } } - animateAvatar(deltaTime, speed, principleDirection); + state.setInternalState(state.SIDE_STEP); } + motion.curAnim = selSideStep; + animateAvatar(deltaTime, speed); + break; + + case state.FLYING: + + if (state.currentState !== state.FLYING) + state.setInternalState(state.FLYING); + + // change animation for flying directly up or down + if (motion.direction === UP) { + + if (motion.curAnim !== motion.selFlyUp) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: + + // standing | walking to flying up + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyUp, + [], 0.25, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + + case motion.selSideStepLeft: + case motion.selSideStepRight: + + break; + + default: + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyUp, + [], 0.35, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + motion.curAnim = motion.selFlyUp; + } + + } else if (motion.direction == DOWN) { + + if (motion.curAnim !== motion.selFlyDown) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyDown, + [], 0.35, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + + case motion.selSideStepLeft: + case motion.selSideStepRight: + + break; + + default: + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyDown, + [], 0.5, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + motion.curAnim = motion.selFlyDown; + } + + } else { + + if (motion.curAnim !== motion.selFly) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFly, + [], 0.35, + {x: 1.44, y:0.24}, + {x: 0.61, y:0.92}); + break; + + case motion.selSideStepLeft: + case motion.selSideStepRight: + + break; + + default: + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFly, + [], 0.75, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + motion.curAnim = motion.selFly; + } + } + animateAvatar(deltaTime, speed); break; } // end switch(actionToTake) - } // end if(!editing) + } // end if (!state.editing) + + // record the frame's direction and local avatar's local velocity for future reference + motion.lastDirection = motion.direction; + motion.lastVelocity = localVelocity; + } +}); + +// the faster we go, the further we lean forward. the angle is calcualted here +function getLeanPitch(speed) { + + if (speed > TOP_SPEED) speed = TOP_SPEED; + var leanProgress = speed / TOP_SPEED; + + if (motion.direction === LEFT || + motion.direction === RIGHT) + leanProgress = 0; + + else { + + var responseSharpness = 1.5; + if (motion.direction == BACKWARDS) responseSharpness = 3.0; + + leanProgress = filter.bezier((1 - leanProgress), + {x: 0, y: 0.0}, + {x: 0, y: responseSharpness}, + {x: 0, y: 1.5}, + {x: 1, y: 1}).y; + + // determine final pitch and adjust for direction of momentum + if (motion.direction === BACKWARDS) + leanProgress = -motion.motionPitchMax * leanProgress; + else + leanProgress = motion.motionPitchMax * leanProgress; + } + + // return the smoothed response + return leanPitchFilter.process(leanProgress); +} + +// calculate the angle at which to bank into corners when turning +function getLeanRoll(deltaTime, speed) { + + var leanRollProgress = 0; + if (speed > TOP_SPEED) speed = TOP_SPEED; + + // what's our our anglular velocity? + var angularVelocityMax = 70; // from observation + var angularVelocity = filter.radToDeg(MyAvatar.getAngularVelocity().y); + if (angularVelocity > angularVelocityMax) angularVelocity = angularVelocityMax; + if (angularVelocity < -angularVelocityMax) angularVelocity = -angularVelocityMax; + + leanRollProgress = speed / TOP_SPEED; + + if (motion.direction !== LEFT && + motion.direction !== RIGHT) + leanRollProgress *= (Math.abs(angularVelocity) / angularVelocityMax); + + // apply our response curve + leanRollProgress = filter.bezier((1 - leanRollProgress), + {x: 0, y: 0}, + {x: 0, y: 1}, + {x: 0, y: 1}, + {x: 1, y: 1}).y; + // which way to lean? + var turnSign = -1; + if (angularVelocity < 0.001) turnSign = 1; + if (motion.direction === BACKWARDS || + motion.direction === LEFT) + turnSign *= -1; + + if (motion.direction === LEFT || + motion.direction === RIGHT) + leanRollProgress *= 2; + + // add damping with simple averaging filter + leanRollProgress = leanRollFilter.process(turnSign * leanRollProgress); + return motion.motionRollMax * leanRollProgress; +} + +function playFootstep(side) { + + var options = new AudioInjectionOptions(); + options.position = Camera.getPosition(); + options.volume = 0.2; + var soundNumber = 2; // 0 to 2 + if (side === RIGHT && motion.makesFootStepSounds) + Audio.playSound(walkAssets.footsteps[soundNumber + 1], options); + else if (side === LEFT && motion.makesFootStepSounds) + Audio.playSound(walkAssets.footsteps[soundNumber], options); +} + +// animate the avatar using sine wave generators. inspired by Victorian clockwork dolls +function animateAvatar(deltaTime, speed) { + + var cycle = motion.cumulativeTime; + var transProgress = 1; + var adjFreq = motion.curAnim.calibration.frequency; + + // legs phase and cycle reversal for walking backwards + var reverseModifier = 0; + var reverseSignModifier = 1; + if (motion.direction === BACKWARDS) { + reverseModifier = -180; + reverseSignModifier = -1; + } + + // don't lean into the direction of travel if going up + var leanMod = 1; + if (motion.direction === UP) + leanMod = 0; + + // adjust leaning direction for flying + var flyingModifier = 1; + if (state.currentState.FLYING) + flyingModifier = -1; + + if (motion.curTransition !== nullTransition) { + + // new transiton? + if (motion.curTransition.progress === 0 && + motion.curTransition.walkingAtStart) { + + if (state.currentState !== state.SIDE_STEP) { + + // work out where we want the walk cycle to stop + var leftStop = motion.selWalk.calibration.stopAngleForwards + 180; + var rightStop = motion.selWalk.calibration.stopAngleForwards; + + if (motion.direction === BACKWARDS) { + leftStop = motion.selWalk.calibration.stopAngleBackwards + 180; + rightStop = motion.selWalk.calibration.stopAngleBackwards; + } + + // find the closest stop point from the walk wheel's angle + var angleToLeftStop = 180 - Math.abs(Math.abs(motion.walkWheelPos - leftStop) - 180); + var angleToRightStop = 180 - Math.abs(Math.abs(motion.walkWheelPos - rightStop) - 180); + if (motion.walkWheelPos > angleToLeftStop) angleToLeftStop = 360 - angleToLeftStop; + if (motion.walkWheelPos > angleToRightStop) angleToRightStop = 360 - angleToRightStop; - // record the frame's stats for later reference - var thisMotion = new RecentMotion(localVelocity, acceleration, principleDirection, INTERNAL_STATE); - framesHistory.recentMotions.push(thisMotion); - framesHistory.recentMotions.shift(); + motion.curTransition.walkWheelIncrement = 3; + // keep the walkwheel turning by setting the walkWheelIncrement + // until our feet are tucked nicely underneath us. + if (angleToLeftStop < angleToRightStop) - // before we go, populate the stats overlay - if( statsOn ) { + motion.curTransition.walkStopAngle = leftStop; - var cumulativeTimeMS = Math.floor(cumulativeTime*1000); - var deltaTimeMS = deltaTime * 1000; - var frameExecutionTime = new Date().getTime() - frameStartTime; - if(frameExecutionTime>frameExecutionTimeMax) frameExecutionTimeMax = frameExecutionTime; + else + motion.curTransition.walkStopAngle = rightStop; - var angluarVelocity = Vec3.length(MyAvatar.getAngularVelocity()); + } else { - 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; + // freeze wheel for sidestepping transitions (for now) + motion.curTransition.walkWheelIncrement = 0; } + } // end if (new transition and curTransition.walkingAtStart) + + // update the Transition progress + var elapasedTime = (new Date().getTime() - motion.curTransition.startTime) / 1000; + motion.curTransition.progress = elapasedTime / motion.curTransition.transitionDuration; + transProgress = filter.bezier((1 - motion.curTransition.progress), {x: 0, y: 0}, + motion.curTransition.easingLower, + motion.curTransition.easingUpper, {x: 1, y: 1}).y; + + if (motion.curTransition.progress >= 1) { + + // time to kill off the transition + delete motion.curTransition; + motion.curTransition = nullTransition; + + } else { + + if (motion.curTransition.walkingAtStart) { + + if (state.currentState !== state.SIDE_STEP) { + + // 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 ((motion.walkWheelPos > (motion.curTransition.walkStopAngle - tolerance)) && + (motion.walkWheelPos < (motion.curTransition.walkStopAngle + tolerance))) { + + motion.curTransition.walkWheelIncrement = 0; + } + // keep turning walk wheel until both feet are below the avi + + motion.advanceWalkWheel(motion.curTransition.walkWheelIncrement); + //motion.curTransition.walkWheelAdvance += motion.curTransition.walkWheelIncrement; + } + else motion.curTransition.walkWheelIncrement = 0; // sidestep + } + } } // end motion.curTransition !== nullTransition + + + // walking? then get the stride length + if (motion.curAnim === motion.selWalk) { + + // if the timing's right, take a snapshot of the stride max and recalibrate + var strideMaxAt = motion.curAnim.calibration.forwardStrideMaxAt; + if (motion.direction === BACKWARDS) + strideMaxAt = motion.curAnim.calibration.backwardsStrideMaxAt; + + var tolerance = 1.0; + if (motion.walkWheelPos < (strideMaxAt + tolerance) && + motion.walkWheelPos > (strideMaxAt - tolerance)) { + + // measure and save stride length + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); + + if (motion.direction === FORWARDS) + motion.curAnim.calibration.strideLengthForwards = motion.strideLength; + else if (motion.direction === BACKWARDS) + motion.curAnim.calibration.strideLengthBackwards = motion.strideLength; + + } else { + + // use the saved value for stride length + if (motion.direction === FORWARDS) + motion.strideLength = motion.curAnim.calibration.strideLengthForwards; + else if (motion.direction === BACKWARDS) + motion.strideLength = motion.curAnim.calibration.strideLengthBackwards; } - } -}); + } // end get walk stride length + // sidestepping? get the stride length + if (motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight) { -// overlays start + // if the timing's right, take a snapshot of the stride max and recalibrate the stride length + var tolerance = 1.0; + if (motion.direction === LEFT) { -// 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 + if (motion.walkWheelPos < motion.curAnim.calibration.strideMaxAt + tolerance && + motion.walkWheelPos > motion.curAnim.calibration.strideMaxAt - tolerance) { -// arrays of overlay names -var sliderThumbOverlays = []; // thumb sliders -var backgroundOverlays = []; -var buttonOverlays = []; -var jointsControlOverlays = []; -var bigButtonOverlays = []; + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); + motion.curAnim.calibration.strideLength = motion.strideLength; + } else motion.strideLength = motion.selSideStepLeft.calibration.strideLength; -// 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); + } else if (motion.direction === RIGHT) { -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); + if (motion.walkWheelPos < motion.curAnim.calibration.strideMaxAt + tolerance && + motion.walkWheelPos > motion.curAnim.calibration.strideMaxAt - tolerance) { -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 footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); + motion.curAnim.calibration.strideLength = motion.strideLength; -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); + } else motion.strideLength = motion.selSideStepRight.calibration.strideLength; + } + } // end get sidestep stride length -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); + // turn the walk wheel + if (motion.curAnim === motion.selWalk || + motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight || + motion.curTransition.walkingAtStart) { -// 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 - }); + // wrap the stride length around a 'surveyor's wheel' twice and calculate + // the angular speed at the given (linear) speed: + // omega = v / r , where r = circumference / 2 PI , where circumference = 2 * stride length + var strideLength = motion.strideLength; + var wheelRadius = strideLength / Math.PI; + var angularVelocity = speed / wheelRadius; -// 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); + // calculate the degrees turned (at this angular speed) since last frame + var radiansTurnedSinceLastFrame = deltaTime * angularVelocity; + var degreesTurnedSinceLastFrame = filter.radToDeg(radiansTurnedSinceLastFrame); -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); + // if we are in an edit mode, we will need fake time to turn the wheel + if (state.currentState !== state.WALKING && + state.currentState !== state.SIDE_STEP) + degreesTurnedSinceLastFrame = motion.curAnim.calibration.frequency / 70; -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); + // advance the walk wheel the appropriate amount + motion.advanceWalkWheel(degreesTurnedSinceLastFrame); -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); + // set the new values for the exact correct walk cycle speed + adjFreq = 1; + cycle = motion.walkWheelPos; -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); + } // end of walk wheel and stride length calculation -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); + // motion vars + var pitchOsc = 0; + var pitchOscLeft = 0; + var pitchOscRight = 0; + var yawOsc = 0; + var yawOscLeft = 0; + var yawOscRight = 0; + var rollOsc = 0; + var pitchOffset = 0; + var yawOffset = 0; + var rollOffset = 0; + var swayOsc = 0; + var bobOsc = 0; + var thrustOsc = 0; + var swayOscLast = 0; + var bobOscLast = 0; + var thrustOscLast = 0; -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); + // historical (for transitions) + var pitchOscLast = 0; + var pitchOscLeftLast = 0; + var pitchOscRightLast = 0; + var yawOscLast = 0; + var rollOscLast = 0; + var pitchOffsetLast = 0; + var yawOffsetLast = 0; + var rollOffsetLast = 0; -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); + // feet + var sideStepFootPitchModifier = 1; + var sideStepHandPitchSign = 1; -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); + // The below code should probably be optimised into some sort of loop, where + // the joints are iterated through. However, this has not been done yet, as there + // are still some quite fundamental changes to be made (e.g. turning on the spot + // animation and sidestepping transitions) so it's been left as is for ease of + // understanding and editing. -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); + // calculate hips translation + if (motion.curTransition !== nullTransition) { -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); + if (motion.curTransition.walkingAtStart) { -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); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].swayPhase)) + motion.curAnim.joints[0].swayOffset; -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); + var bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) bobPhase += 90; + bobOsc = motion.curAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + bobPhase)) + + motion.curAnim.joints[0].bobOffset; + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; -// 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); + swayOscLast = motion.curTransition.lastAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].swayPhase)) + + motion.curTransition.lastAnim.joints[0].swayOffset; + var bobPhaseLast = motion.curTransition.lastAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) bobPhaseLast +=90; + bobOscLast = motion.curTransition.lastAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.walkWheelPos + bobPhaseLast)); + bobOscLast = filter.clipTrough(bobOscLast, motion.curTransition.lastAnim.joints[0].bob , 2); + bobOscLast = hipsBobLPFilter.process(bobOscLast); + bobOscLast += motion.curTransition.lastAnim.joints[0].bobOffset; -// 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); + thrustOscLast = motion.curTransition.lastAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[0].thrustPhase)) + + motion.curTransition.lastAnim.joints[0].thrustOffset; -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); + } // end if walking at start of transition + else { -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); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(cycle * adjFreq + motion.curAnim.joints[0].swayPhase)) + + motion.curAnim.joints[0].swayOffset; -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 bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) bobPhase += 90; + bobOsc = motion.curAnim.joints[0].bob * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + bobPhase)); + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { -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); + // apply clipping filter to flatten the curve's peaks (inputValue, peak, strength) + bobOsc = filter.clipTrough(bobOsc, motion.curAnim.joints[0].bob , 2); + bobOsc = hipsBobLPFilter.process(bobOsc); + } + bobOsc += motion.curAnim.joints[0].bobOffset; -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); + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; -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); + swayOscLast = motion.curTransition.lastAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].swayPhase)) + + motion.curTransition.lastAnim.joints[0].swayOffset; -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); + bobOscLast = motion.curTransition.lastAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].bobPhase)) + + motion.curTransition.lastAnim.joints[0].bobOffset; -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); + thrustOscLast = motion.curTransition.lastAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].thrustPhase)) + + motion.curTransition.lastAnim.joints[0].thrustOffset; + } -// big button overlays - front panel -var bigButtonYOffset = 408; // distance from top of panel to top of first button + swayOsc = (transProgress * swayOsc) + ((1 - transProgress) * swayOscLast); + bobOsc = (transProgress * bobOsc) + ((1 - transProgress) * bobOscLast); + thrustOsc = (transProgress * thrustOsc) + ((1 - transProgress) * thrustOscLast); -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); + }// if current transition active + else { -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); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(cycle * adjFreq + motion.curAnim.joints[0].swayPhase)) + + motion.curAnim.joints[0].swayOffset; -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); + bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) bobPhase += 90; + bobOsc = motion.curAnim.joints[0].bob * Math.sin(filter.degToRad(cycle * adjFreq * 2 + bobPhase)); + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { -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); + // apply clipping filter to flatten the curve's peaks (inputValue, peak, strength) + bobOsc = filter.clipTrough(bobOsc, motion.curAnim.joints[0].bob , 2); + bobOsc = hipsBobLPFilter.process(bobOsc); + } + bobOsc += motion.curAnim.joints[0].bobOffset; -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); + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; + } -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); + // convert local hips translations to global and apply + var aviOrientation = MyAvatar.orientation; + var front = Quat.getFront(aviOrientation); + var right = Quat.getRight(aviOrientation); + var up = Quat.getUp(aviOrientation); + var aviFront = Vec3.multiply(front, thrustOsc); + var aviRight = Vec3.multiply(right, swayOsc); + var aviUp = Vec3.multiply(up, bobOsc); + var aviTranslationOffset = {x: 0, y: 0, z: 0}; -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); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviFront); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviRight); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviUp); -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); + MyAvatar.setSkeletonOffset({ + x: aviTranslationOffset.x, + y: aviTranslationOffset.y, + z: aviTranslationOffset.z + }); + // hips rotation + if (motion.curTransition !== nullTransition) { -// 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); + if (motion.curTransition.walkingAtStart) { -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); + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[0].pitchPhase)) + motion.curAnim.joints[0].pitchOffset; -// 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." - }); + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].yawPhase - reverseModifier)) + motion.curAnim.joints[0].yawOffset; -// 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) { + rollOsc = motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].rollPhase)) + motion.curAnim.joints[0].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[0].pitchPhase)) + + motion.curTransition.lastAnim.joints[0].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].yawPhase)); + + yawOscLast += motion.curTransition.lastAnim.joints[0].yaw * + hipsYawShaper.shapeWave(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].yawPhase - reverseModifier)) + + motion.curTransition.lastAnim.joints[0].yawOffset; + + rollOscLast = (motion.curTransition.lastAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].rollPhase)) + + motion.curTransition.lastAnim.joints[0].rollOffset); + + } else { + + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].pitchPhase)) + + motion.curAnim.joints[0].pitchOffset; + + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[0].yawPhase - reverseModifier)) + + motion.curAnim.joints[0].yawOffset; + + rollOsc = motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[0].rollPhase)) + + motion.curAnim.joints[0].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].pitchPhase)) + + motion.curTransition.lastAnim.joints[0].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].yawPhase - reverseModifier)) + + motion.curTransition.lastAnim.joints[0].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].rollPhase)) + + motion.curTransition.lastAnim.joints[0].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); - 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 } ); + + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[0].pitchPhase)) + + motion.curAnim.joints[0].pitchOffset; + + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[0].yawPhase)); + + yawOsc += motion.curAnim.joints[0].yaw * + hipsYawShaper.shapeWave(filter.degToRad(cycle * adjFreq) + + motion.curAnim.joints[0].yawPhase - reverseModifier)+ + motion.curAnim.joints[0].yawOffset; + + rollOsc = (motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[0].rollPhase)) + + motion.curAnim.joints[0].rollOffset); } - if(armsFree) { - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(armsFreeBigButton, { visible: false } ); + + // apply hips rotation + MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees( + pitchOsc + (leanMod * getLeanPitch(speed)), + yawOsc, + rollOsc + getLeanRoll(deltaTime, speed))); + + // upper legs + if (state.currentState !== state.SIDE_STEP && + state.currentState !== state.EDIT_SIDESTEP_LEFT && + state.currentState !== state.EDIT_SIDESTEP_RIGHT) { + + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + reverseModifier * motion.curAnim.joints[1].pitchPhase)); + + pitchOscRight = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + reverseModifier * motion.curAnim.joints[1].pitchPhase)); + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[1].pitch * + motion.curTransition.lastAnim.harmonics.leftUpperLeg.calculate( + filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].pitchPhase + 180 + reverseModifier)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[1].pitch * + motion.curTransition.lastAnim.harmonics.rightUpperLeg.calculate( + filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].pitchPhase + reverseModifier)); + + yawOscLast = motion.curTransition.lastAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[1].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[1].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[1].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.leftUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + 180 + reverseModifier)); + pitchOscRight = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.rightUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + reverseModifier)); + } else { + + pitchOscLeft = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + pitchOscRight = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + } + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + reverseModifier * motion.curTransition.lastAnim.joints[1].pitchPhase)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + reverseModifier * motion.curTransition.lastAnim.joints[1].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[1].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[1].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[1].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[1].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[1].rollOffset; + } + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.leftUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + 180 + reverseModifier)); + pitchOscRight = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.rightUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + reverseModifier)); + } else { + + pitchOscLeft = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + pitchOscRight = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + } + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + } + + // apply the upper leg rotations + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( + pitchOscLeft + pitchOffset, + yawOsc - yawOffset, + -rollOsc + rollOffset)); + + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( + pitchOscRight + pitchOffset, + yawOsc + yawOffset, + -rollOsc - rollOffset)); + + // lower leg + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].pitchPhase)); + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].rollPhase)); + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[2].pitch * + motion.curTransition.lastAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[2].pitch * + motion.curTransition.lastAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[2].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[2].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[2].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase + 180)); + pitchOscRight = motion.curAnim.harmonics.rightLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + } + pitchOscLeft *= motion.curAnim.joints[2].pitch; + pitchOscRight *= motion.curAnim.joints[2].pitch; + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[2].rollPhase)); + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[2].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[2].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[2].rollOffset; + } + + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + rollOscLeft = rollOsc; + rollOscRight = rollOsc; + + } else { // end if transitioning + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase + 180)); + pitchOscRight = motion.curAnim.harmonics.rightLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + } + + pitchOscLeft *= motion.curAnim.joints[2].pitch; + pitchOscRight *= motion.curAnim.joints[2].pitch; + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].rollPhase)); + + rollOsc = motion.curAnim.joints[2].roll; + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + } + + pitchOscLeft += pitchOffset; + pitchOscRight += pitchOffset; + + // apply lower leg joint rotations + MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( + pitchOscLeft, + yawOsc + yawOffset, + rollOsc + rollOffset)); + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + pitchOscRight, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + } // end if !state.SIDE_STEP + + else if (state.currentState === state.SIDE_STEP || + state.currentState === state.EDIT_SIDESTEP_LEFT || + state.currentState === state.EDIT_SIDESTEP_RIGHT) { + + // sidestepping uses the sinewave generators slightly differently for the legs + pitchOsc = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].pitchPhase)); + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].rollPhase)); + + // apply upper leg rotations for sidestepping + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( + -pitchOsc + motion.curAnim.joints[1].pitchOffset, + yawOsc + motion.curAnim.joints[1].yawOffset, + rollOsc + motion.curAnim.joints[1].rollOffset)); + + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( + pitchOsc + motion.curAnim.joints[1].pitchOffset, + yawOsc - motion.curAnim.joints[1].yawOffset, + -rollOsc - motion.curAnim.joints[1].rollOffset)); + + // calculate lower leg joint rotations for sidestepping + pitchOsc = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].rollPhase)); + + // apply lower leg joint rotations + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + -pitchOsc + motion.curAnim.joints[2].pitchOffset, + yawOsc - motion.curAnim.joints[2].yawOffset, + rollOsc - motion.curAnim.joints[2].rollOffset)); + + MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( + pitchOsc + motion.curAnim.joints[2].pitchOffset, + yawOsc + motion.curAnim.joints[2].yawOffset, + rollOsc + motion.curAnim.joints[2].rollOffset)); + } + + // feet + if (motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight ) { + + sideStepHandPitchSign = -1; + sideStepFootPitchModifier = 0.5; + } + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].pitchPhase) + 180); + + pitchOscRight = motion.curAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].pitchPhase)); + + yawOsc = motion.curAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].yawPhase)); + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[3].pitch * + motion.curTransition.lastAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * motion.walkWheelPos + + motion.curTransition.lastAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[3].pitch * + motion.curTransition.lastAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * motion.walkWheelPos + + motion.curTransition.lastAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + yawOscLast = motion.curTransition.lastAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[3].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[3].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[3].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[3].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[3].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRight = motion.curAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase)); + + pitchOscRight = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase + 180)); + } + + yawOsc = motion.curAnim.joints[3].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].yawPhase)); + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[3].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[3].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[3].rollOffset; + } + + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + } else { - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } ); - Overlays.editOverlay(armsFreeBigButton, { visible: showButtons } ); + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRight = motion.curAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase)); + + pitchOscRight = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase + 180)); + } + + yawOsc = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].yawPhase)); + + pitchOscLeft *= motion.curAnim.joints[3].pitch; + pitchOscRight *= motion.curAnim.joints[3].pitch; + + yawOsc *= motion.curAnim.joints[3].yaw; + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; } - if(playFootStepSounds) { - Overlays.editOverlay(footstepsBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(footstepsBigButton, { visible: false } ); + + // apply foot rotations + MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees( + pitchOscLeft + pitchOffset, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( + pitchOscRight + pitchOffset, + yawOsc + yawOffset, + rollOsc + 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 (state.currentState === state.WALKING || + state.currentState === state.SIDE_STEP || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS || + state.currentState === state.EDIT_SIDESTEP_LEFT || + state.currentState === state.EDIT_SIDESTEP_RIGHT) { + + // find dy/dx by determining the cosine wave for the foot's pitch function. + var feetPitchDifferential = Math.cos(filter.degToRad((cycle * adjFreq) + motion.curAnim.joints[3].pitchPhase)); + var threshHold = 0.9; // sets the audio trigger point. with accuracy. + if (feetPitchDifferential < -threshHold && + motion.nextStep === LEFT && + motion.direction !== UP && + motion.direction !== DOWN) { + + playFootstep(LEFT); + motion.nextStep = RIGHT; + } else if (feetPitchDifferential > threshHold && + motion.nextStep === RIGHT && + motion.direction !== UP && + motion.direction !== DOWN) { + + playFootstep(RIGHT); + motion.nextStep = LEFT; + } + } + + // toes + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].pitchPhase)); + + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].yawPhase)); + + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].rollPhase)); + + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[4].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[4].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[4].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * cycle * adjFreq) + + motion.curAnim.joints[4].pitchPhase)); + + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].yawPhase)); + + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].rollPhase)); + + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[4].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[4].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[4].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + } 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) { + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * cycle * adjFreq) + + motion.curAnim.joints[4].pitchPhase)); - selectedJointIndex = propertyIndex; + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].yawPhase)); - // 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; - } + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].rollPhase)); - // 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 }); + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; } - if(!showButtons) return; + // apply toe rotations + MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc + yawOffset, + rollOsc + rollOffset)); - // set all the non-selected ones to showing - for(var i = 8 ; i < bigButtonOverlays.length ; i+=2) { - Overlays.editOverlay(bigButtonOverlays[i], { visible: showButtons }); + MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + // spine + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim + .joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[5].pitchPhase)) + + motion.curTransition.lastAnim.joints[5].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[5].yawPhase)) + + motion.curTransition.lastAnim.joints[5].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[5].rollPhase)) + + motion.curTransition.lastAnim.joints[5].rollOffset; + } else { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim.joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[5].pitchPhase)) + + motion.curTransition.lastAnim.joints[5].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[5].yawPhase)) + + motion.curTransition.lastAnim.joints[5].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[5].rollPhase)) + + motion.curTransition.lastAnim.joints[5].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim.joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; } - // set the currently selected one - if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { - Overlays.editOverlay(strutWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(strutWalkBigButton, {visible: false}); + // apply spine joint rotations + MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + // spine 1 + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[6].pitchPhase)) + + motion.curTransition.lastAnim.joints[6].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[6].yawPhase)) + + motion.curTransition.lastAnim.joints[6].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[6].rollPhase)) + + motion.curTransition.lastAnim.joints[6].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[6].pitchPhase)) + + motion.curTransition.lastAnim.joints[6].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[6].yawPhase)) + + motion.curTransition.lastAnim.joints[6].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[6].rollPhase)) + + motion.curTransition.lastAnim.joints[6].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; } + + // apply spine1 joint rotations + MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + // spine 2 + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[7].pitchPhase)) + + motion.curTransition.lastAnim.joints[7].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[7].yawPhase)) + + motion.curTransition.lastAnim.joints[7].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[7].rollPhase)) + + motion.curTransition.lastAnim.joints[7].rollOffset; + } else { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * 2 * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].pitchPhase)) + + motion.curTransition.lastAnim.joints[7].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].yawPhase)) + + motion.curTransition.lastAnim.joints[7].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].rollPhase)) + + motion.curTransition.lastAnim.joints[7].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + } + + // apply spine2 joint rotations + MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + if (!motion.armsFree) { + + // shoulders + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].pitchPhase)) + + motion.curTransition.lastAnim.joints[8].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].rollPhase)) + + motion.curTransition.lastAnim.joints[8].rollOffset; + + yawOffsetLast = motion.curTransition.lastAnim.joints[8].yawOffset; + + } else { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].pitchPhase)) + + motion.curTransition.lastAnim.joints[8].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].rollPhase)) + + motion.curTransition.lastAnim.joints[8].rollOffset; + + yawOffsetLast = motion.curTransition.lastAnim.joints[8].yawOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + } + + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc + yawOffset, rollOsc)); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc - yawOffset, -rollOsc)); + + // upper arms + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[9].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[9].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[9].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].rollPhase)) + + motion.curTransition.lastAnim.joints[9].rollOffset; + + pitchOffsetLast = motion.curTransition.lastAnim.joints[9].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[9].yawOffset; + + } else { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[9].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].pitchPhase)) + + yawOscLast = motion.curTransition.lastAnim.joints[9].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[9].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].rollPhase)) + + motion.curTransition.lastAnim.joints[9].rollOffset; + + pitchOffsetLast = motion.curTransition.lastAnim.joints[9].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[9].yawOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + } + + MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( + (-1 * flyingModifier) * pitchOsc + pitchOffset, + yawOsc - yawOffset, + rollOsc)); + + MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc + yawOffset, + -rollOsc)); + + // forearms + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].pitchPhase)) + + motion.curTransition.lastAnim.joints[10].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].rollPhase)); + + yawOffsetLast = motion.curTransition.lastAnim.joints[10].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[10].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].pitchPhase)) + + motion.curTransition.lastAnim.joints[10].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].rollPhase)); + + yawOffsetLast = motion.curTransition.lastAnim.joints[10].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[10].rollOffset; + } + + // blend the animations + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = -(transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + } + + // apply forearms rotations + MyAvatar.setJointData("RightForeArm", + Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc + yawOffset, rollOsc + rollOffset)); + MyAvatar.setJointData("LeftForeArm", + Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc - yawOffset, rollOsc - rollOffset)); + + // hands + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].rollPhase)); + + pitchOscLast = motion.curTransition.lastAnim.joints[11].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].pitchPhase)) + + motion.curTransition.lastAnim.joints[11].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[11].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].yawPhase)) + + motion.curTransition.lastAnim.joints[11].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[11].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].rollPhase)) + + rollOffset = motion.curAnim.joints[11].rollOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[11].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].rollPhase)); + + rollOffset = motion.curAnim.joints[11].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[11].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].pitchPhase)) + + motion.curTransition.lastAnim.joints[11].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[11].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].yawPhase)) + + motion.curTransition.lastAnim.joints[11].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[11].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].rollPhase)) + + rollOffset = motion.curAnim.joints[11].rollOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[11].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].rollPhase)); + + rollOffset = motion.curAnim.joints[11].rollOffset; + } + + // set the hand rotations + MyAvatar.setJointData("RightHand", + Quat.fromPitchYawRollDegrees(sideStepHandPitchSign * pitchOsc, yawOsc, rollOsc + rollOffset)); + MyAvatar.setJointData("LeftHand", + Quat.fromPitchYawRollDegrees(pitchOsc, -yawOsc, rollOsc - rollOffset)); + + } // end if (!motion.armsFree) + + // head and neck + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + + pitchOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[12].pitchPhase)) + + motion.curTransition.lastAnim.joints[12].pitchOffset; + + yawOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[12].yawPhase)) + + motion.curTransition.lastAnim.joints[12].yawOffset; + + rollOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[12].rollPhase)) + + motion.curTransition.lastAnim.joints[12].rollOffset; + + } else { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + + pitchOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[12].pitchPhase)) + + motion.curTransition.lastAnim.joints[12].pitchOffset; + + yawOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[12].yawPhase)) + + motion.curTransition.lastAnim.joints[12].yawOffset; + + rollOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[12].rollPhase)) + + motion.curTransition.lastAnim.joints[12].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + } + + MyAvatar.setJointData("Head", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + MyAvatar.setJointData("Neck", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); } -// 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); \ No newline at end of file +// Begin by setting an internal state +state.setInternalState(state.STANDING); \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 623631d5e5..53454d3d3b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -49,7 +49,7 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; -const float MAX_WALKING_SPEED = 4.5f; +const float MAX_WALKING_SPEED = 2.5f; // human walking speed const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this