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