From 552427061303986c4df53a5282e1d3e3cd96f8b3 Mon Sep 17 00:00:00 2001 From: DaveDubUK Date: Wed, 10 Sep 2014 23:57:10 +0700 Subject: [PATCH 01/40] walk.js script for https://worklist.net/19970 walk.js script for https://worklist.net/19970 --- examples/walk.js | 2540 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2540 insertions(+) create mode 100644 examples/walk.js diff --git a/examples/walk.js b/examples/walk.js new file mode 100644 index 0000000000..de349a95b8 --- /dev/null +++ b/examples/walk.js @@ -0,0 +1,2540 @@ +// +// walk.js +// +// +// 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 +// + + +// Set asset paths here: + +// path to the animation files +//var pathToAnimFiles = 'http://localhost/downloads/hf/scripts/animation-files/'; // loads fine (files must be present on localhost) +//var pathToAnimFiles = 'http://highfidelity.davedub.co.uk/procedural/walk/animation-files/'; // files present, but load with errors - weird +var pathToAnimFiles = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/files/'; // working (but only without https) + +// path to the images used for the overlays +//var pathToOverlays = 'http://localhost/downloads/hf/overlays/'; // loads fine (files must be present on localhost) +//var pathToOverlays = 'http://highfidelity.davedub.co.uk/procedural/walk/overlays/'; // files present, but won't load - weird +var pathToOverlays = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/images/'; // 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/'; +//var pathToSounds = 'http://localhost/downloads/hf/sounds/Footsteps/'; + + +// load all the animation datafiles ( 15 female, 15 male ~ 240k ) +Script.include(pathToAnimFiles+"dd-female-cool-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-elderly-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-power-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-run-animation.js"); +Script.include(pathToAnimFiles+"dd-female-sexy-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-shuffle-animation.js"); +Script.include(pathToAnimFiles+"dd-female-random-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-strut-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-female-tough-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-standing-two-animation.js"); +Script.include(pathToAnimFiles+"dd-female-standing-three-animatiom.js"); +Script.include(pathToAnimFiles+"dd-male-cool-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-elderly-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-power-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-run-animation.js"); +Script.include(pathToAnimFiles+"dd-male-sexy-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-shuffle-animation.js"); +Script.include(pathToAnimFiles+"dd-male-random-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-strut-walk-animation.js"); +Script.include(pathToAnimFiles+"dd-male-tough-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-standing-two-animation.js"); +Script.include(pathToAnimFiles+"dd-male-standing-three-animation.js"); + +// read in the data from the animation files +var FemaleCoolWalkFile = new FemaleCoolWalk(); +var femaleCoolWalk = FemaleCoolWalkFile.loadAnimation(); +var FemaleElderlyWalkFile = new FemaleElderlyWalk(); +var femaleElderlyWalk = FemaleElderlyWalkFile.loadAnimation(); +var FemalePowerWalkFile = new FemalePowerWalk(); +var femalePowerWalk = FemalePowerWalkFile.loadAnimation(); +var FemaleRunFile = new FemaleRun(); +var femaleRun = FemaleRunFile.loadAnimation(); +var FemaleSexyWalkFile = new FemaleSexyWalk(); +var femaleSexyWalk = FemaleSexyWalkFile.loadAnimation(); +var FemaleShuffleFile = new FemaleShuffle(); +var femaleShuffle = FemaleShuffleFile.loadAnimation(); +var FemaleRandomWalkFile = new FemaleRandomWalk(); +var femaleRandomWalk = FemaleRandomWalkFile.loadAnimation(); +var FemaleStrutWalkFile = new FemaleStrutWalk(); +var femaleStrutWalk = FemaleStrutWalkFile.loadAnimation(); +var FemaleToughWalkFile = new FemaleToughWalk(); +var femaleToughWalk = FemaleToughWalkFile.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 FemaleStandTwoFile = new FemaleStandingTwo(); +var femaleStandTwo = FemaleStandTwoFile.loadAnimation(); +var FemaleStandThreeFile = new FemaleStandingThree(); +var femaleStandThree = FemaleStandThreeFile.loadAnimation(); +var MaleCoolWalkFile = new MaleCoolWalk(); +var maleCoolWalk = MaleCoolWalkFile.loadAnimation(); +var MaleElderlyWalkFile = new MaleElderlyWalk(); +var maleElderlyWalk = MaleElderlyWalkFile.loadAnimation(); +var MalePowerWalkFile = new MalePowerWalk(); +var malePowerWalk = MalePowerWalkFile.loadAnimation(); +var MaleRunFile = new MaleRun(); +var maleRun = MaleRunFile.loadAnimation(); +var MaleSexyWalkFile = new MaleSexyWalk(); +var maleSexyWalk = MaleSexyWalkFile.loadAnimation(); +var MaleShuffleFile = new MaleShuffle(); +var maleShuffle = MaleShuffleFile.loadAnimation(); +var MaleRandomWalkFile = new MaleRandomWalk(); +var maleRandomWalk = MaleRandomWalkFile.loadAnimation(); +var MaleStrutWalkFile = new MaleStrutWalk(); +var maleStrutWalk = MaleStrutWalkFile.loadAnimation(); +var MaleToughWalkFile = new MaleToughWalk(); +var maleToughWalk = MaleToughWalkFile.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 MaleStandTwoFile = new MaleStandingTwo(); +var maleStandTwo = MaleStandTwoFile.loadAnimation(); +var MaleStandThreeFile = new MaleStandingThree(); +var maleStandThree = MaleStandThreeFile.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 (always +-180)) +var sliderRanges = +{ + "joints":[ + { + "name":"hips", + "pitchRange":25, + "yawRange":25, + "rollRange":25, + "pitchOffsetRange":25, + "yawOffsetRange":25, + "rollOffsetRange":25, + "thrustRange":0.1, + "bobRange":0.5, + "swayRange":0.08 + }, + { + "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 = 2; +var WALKING = 4; +var FLYING = 8; +var CONFIG_WALK_STYLES = 16; +var CONFIG_WALK_TWEAKS = 32; +var CONFIG_WALK_JOINTS = 64; +var CONFIG_STANDING = 128; +var CONFIG_FLYING = 256; +var INTERNAL_STATE = STANDING; + +// status +var powerOn = true; +var paused = false; // pause animation playback whilst adjusting certain parameters +var minimised = false; +var armsFree = false; // set true for hydra support - experimental +var statsOn = false; + +// constants +var MAX_WALK_SPEED = 1257; // max oscillation speed +var FLYING_SPEED = 12.5; // m/s - real humans can't run any faster +var TERMINAL_VELOCITY = 300; +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 MALE = 64; +var FEMALE = 128; + +// start of animation control section +var cumulativeTime = 0.0; +var lastOrientation; +var movementDirection = DIRECTION_FORWARDS; +var playFootStepSounds = true; +var avatarGender = FEMALE; +var selectedWalk = femaleStrutWalk; // the currently selected animation walk file +var selectedStand = femaleStandOne; +var selectedFlyUp = femaleFlyingUp; +var selectedFly = femaleFlying; +var selectedFlyDown = femaleFlyingDown; +var currentAnimation = selectedStand; // the current animation +var selectedJointIndex = 0; // the index of the joint currently selected for editing +// stride calibration +var maxFootForward = 0; +var maxFootBackwards = 0; +var strideLength = 0; +// walkwheel (foot / ground speed matching) +var walkCycleStart = 105; // best foot forwards - TODO: if different for different anims, add as setting to anim files +var walkWheelPosition = walkCycleStart; + + +// for showing walk wheel stats +var nFrames = 0; + +// convert hips translations to global (i.e. take account of avi orientation) +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.addThrust(AviTranslationOffset * 10); + MyAvatar.position = {x: MyAvatar.position.x + AviTranslationOffset.x, + y: MyAvatar.position.y + AviTranslationOffset.y, + z: MyAvatar.position.z + AviTranslationOffset.z }; +} + +// convert a local (to the avi) translation to a global one +function globalToLocal(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; +} + +// zero out all joints +function resetJoints() { + var avatarJointNames = MyAvatar.getJointNames(); + for (var i = 0; i < avatarJointNames.length; i++) { + //MyAvatar.setJointData(avatarJointNames[i], Quat.fromPitchYawRollDegrees(0,0,0)); + MyAvatar.clearJointData(avatarJointNames[i]); + } +} +// play footstep sound +function playFootstep(side) { + var options = new AudioInjectionOptions(); + options.position = Camera.getPosition(); + options.volume = 0.7; + var walkNumber = 2; // 0 to 2 + if(side===DIRECTION_RIGHT && playFootStepSounds) { + //print('playing right footstep - if you can not hear sound, try turning your mic on then off again.'); + Audio.playSound(footsteps[walkNumber+1], options); + } + else if(side===DIRECTION_LEFT && playFootStepSounds) { + //print('playing left footstep - if you can not hear sound, try turning your mic on then off again.'); + Audio.playSound(footsteps[walkNumber], options); + } +} + +// this is work in progress +// currently, it's not known if there are working finger joints on the avi +function curlFingers() { + MyAvatar.setJointData("RightHandMiddle1", Quat.fromPitchYawRollDegrees(90,0,0)); + for(var i = 24 ; i < 44 ; i++) { + MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,90,0)); + } + for(var i = 48 ; i < 68 ; i++) { + MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(10,0,90)); + } +} + +// maths functions +function toRadians(degreesValue) { + return degreesValue * Math.PI / 180; +} +function toDegrees(radiansValue) { + return radiansValue * 180 / Math.PI; +} +function cubicRoot(x) { + var y = Math.pow(Math.abs(x), 1/3); + return x < 0 ? -y : y; +} + +// animateAvatar - animates the avatar - TODO doxygen comments? +var nextStep = DIRECTION_RIGHT; // first step is always right, because the sine waves say so + +function animateAvatar(deltaTime, velocity, principleDirection) { + + // some slider adjustemnts cause a nasty flicker when adjusting + // pausing the animation stops this + if(paused) return; + + var adjustedFrequency = currentAnimation.settings.baseFrequency; // now only relevant for standing and flying + + // simple legs phase reversal for walking backwards + var forwardModifier = 1; + if(principleDirection===DIRECTION_BACKWARDS) { + forwardModifier = -1; + } + + // no need to lean forwards with speed increase if going directly upwards + var leanPitchModifier = 1; + if(principleDirection===DIRECTION_UP) { + leanPitchModifier = 0; + } + + + if(currentAnimation === selectedWalk) { + + if(INTERNAL_STATE===CONFIG_WALK_STYLES || + INTERNAL_STATE===CONFIG_WALK_TWEAKS || + INTERNAL_STATE===CONFIG_WALK_JOINTS) { + + var footPos = globalToLocal(MyAvatar.getJointPosition("RightFoot")); + var hipsPos = globalToLocal(MyAvatar.getJointPosition("Hips")); + + // calibrate stride length whilst not actually moving (for accuracy) + if((hipsPos.z - footPos.z)maxFootForward) maxFootForward = (hipsPos.z - footPos.z); + + strideLength = 2 * (maxFootForward-maxFootBackwards); + + // TODO: take note of the avi's stride length (can store in anim file or recalculate each time worn or edited) + print('Stride length calibration: Your stride length is ' + strideLength + ' metres'); // ~ 0.8211 + } + else { + + if(strideLength===0) strideLength = 1.6422; // default for if not calibrated yet + + // 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 + 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 = toDegrees(radiansTurnedSinceLastFrame); + + // advance the walk wheel the appropriate amount + // TODO: use radians, as Math.sin needs radians below anyway! + walkWheelPosition += degreesTurnedSinceLastFrame; + if( walkWheelPosition >= 360 ) + walkWheelPosition = walkWheelPosition % 360; + + // set the new value for the exact correct walking speed for this velocity + adjustedFrequency = 1; + cumulativeTime = walkWheelPosition; + + // show stats and walk wheel? + if(statsOn) { + + nFrames++; + var distanceTravelled = velocity * deltaTime; + var deltaTimeMS = deltaTime * 1000; + + // draw the walk wheel + var yOffset = hipsToFeetDistance - wheelRadius; + var sinWalkWheelPosition = wheelRadius * Math.sin(toRadians((forwardModifier*-1) * walkWheelPosition)); + var cosWalkWheelPosition = wheelRadius * Math.cos(toRadians((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(toRadians(forwardModifier * walkWheelPosition+90)); + cosWalkWheelPosition = wheelRadius * Math.cos(toRadians(forwardModifier * walkWheelPosition+90)); + var wheelYPos = {x:0, y:sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition}; + var wheelYEnd = {x:0, y:-sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition}; + Overlays.editOverlay(walkWheelYLine, {position:wheelYPos, end:wheelYEnd}); + Overlays.editOverlay(walkWheelZLine, {position:wheelZPos, end:wheelZEnd}); + + // populate debug overlay + var debugInfo = 'Frame number: '+nFrames + + '\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\nStride: '+strideLength.toFixed(3) + + ' m\nWheel position: '+cumulativeTime.toFixed(1) + + ' deg\n'; + Overlays.editOverlay(debugText, {text: debugInfo}); + + //print('strideLength '+strideLength.toFixed(4)+' deltaTime '+deltaTimeMS.toFixed(4)+' distanceTravelled '+distanceTravelled.toFixed(3)+' velocity '+velocity.toFixed(3)+' angularVelocity '+angularVelocity.toFixed(3)+' degreesTurnedSinceLastFrame '+degreesTurnedSinceLastFrame.toFixed(3) + ' cumulativeTime '+cumulativeTime.toFixed(3)); + } + } + + } else { + nFrames = 0; + walkWheelPosition = walkCycleStart; // best foot forwards for next time we walk + } + + // TODO: optimise by precalculating and re-using Math.sin((cumulativeTime * femaleSexyWalk.settings.baseFrequency) when there is no phase to be applied + // TODO: optimise by 'baking' offsets and phases after editing and use during normal playback + + // calcualte hips translation + //var motorOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[0].thrustPhase)) + currentAnimation.joints[0].thrustOffset; + //var swayOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[0].swayPhase)) + currentAnimation.joints[0].swayOffset; + //var bobOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[0].bobPhase)) + currentAnimation.joints[0].bobOffset; + + // calculate hips rotation + var pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) + + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; + var yawOscillation = currentAnimation.joints[0].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + + currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset; + var rollOscillation = (currentAnimation.joints[0].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + + currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset); + + // apply hips translation TODO: get this working! + //translateHips({x:swayOscillation*currentAnimation.joints[0].sway, y:motorOscillation*currentAnimation.joints[0].thrust, z:bobOscillation*currentAnimation.joints[0].bob}); + + // apply hips rotation + MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees(-pitchOscillation + (forwardModifier * (leanPitchModifier*getLeanPitch(velocity))), // getLeanPitch - lean forwards as velocity increased + yawOscillation, // Yup, that's correct ;-) + rollOscillation + getLeanRoll(deltaTime,velocity))); // getLeanRoll - banking on cornering + + // calculate upper leg rotations + + // TODO: clean up here - increase stride a bit as velocity increases + var runningModifier = velocity / currentAnimation.settings.takeFlightVelocity; + if(runningModifier>1) { + runningModifier *= 2; + runningModifier += 0.5; + } + else if(runningModifier>0) { + runningModifier *= 2; + runningModifier += 0.5; + } + else runningModifier = 1; // standing + + runningModifier = 1; // TODO - remove this little disabling hack! + + pitchOscillation = runningModifier * currentAnimation.joints[1].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase))); + yawOscillation = currentAnimation.joints[1].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[1].yawPhase)); + rollOscillation = currentAnimation.joints[1].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[1].rollPhase)); + + // apply upper leg rotations + var strideAdjusterPitch = 0; + var strideAdjusterPitchOffset = 0; + var strideAdjusterSeparationAngle = 0; + if(INTERNAL_STATE===WALKING || + INTERNAL_STATE===CONFIG_WALK_STYLES || + INTERNAL_STATE===CONFIG_WALK_TWEAKS || + INTERNAL_STATE===CONFIG_WALK_JOINTS) { + strideAdjusterPitch = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.upperLegsPitch; + strideAdjusterPitchOffset = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.upperLegsPitchOffset; + strideAdjusterSeparationAngle = currentAnimation.adjusters.legsSeparation.strength * currentAnimation.adjusters.legsSeparation.separationAngle; + } + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( + pitchOscillation + currentAnimation.joints[1].pitchOffset + strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[1].pitchPhase)) + strideAdjusterPitchOffset), + yawOscillation + currentAnimation.joints[1].yawOffset, + -rollOscillation - strideAdjusterSeparationAngle - currentAnimation.joints[1].rollOffset )); + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( + - pitchOscillation + currentAnimation.joints[1].pitchOffset - strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[1].pitchPhase)) - strideAdjusterPitchOffset), + yawOscillation - currentAnimation.joints[1].yawOffset, + -rollOscillation + strideAdjusterSeparationAngle + currentAnimation.joints[1].rollOffset )); + + // calculate lower leg joint rotations + strideAdjusterPitch = 0; + strideAdjusterPitchOffset = 0; + if(INTERNAL_STATE===WALKING || + INTERNAL_STATE===CONFIG_WALK_STYLES || + INTERNAL_STATE===CONFIG_WALK_TWEAKS || + INTERNAL_STATE===CONFIG_WALK_JOINTS) { + strideAdjusterPitch = currentAnimation.adjusters.stride.strength * currentAnimation.adjusters.stride.lowerLegsPitch; + strideAdjusterPitchOffset = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.lowerLegsPitchOffset; + } + pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase)); + yawOscillation = currentAnimation.joints[2].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].yawPhase)); + rollOscillation = currentAnimation.joints[2].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].rollPhase)); + + // apply lower leg joint rotations + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + -pitchOscillation + currentAnimation.joints[2].pitchOffset - strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[2].pitchPhase)) + strideAdjusterPitchOffset), + 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 + strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[2].pitchPhase)) - strideAdjusterPitchOffset), + yawOscillation + currentAnimation.joints[2].yawOffset, + rollOscillation + currentAnimation.joints[2].rollOffset)); + + // foot joint oscillation is a hard curve to replicate + var wave = 1;//(baseOscillation + 1)/2; // TODO: finish this - +ve num between 0 and 1 gives a kick at the forward part of the swing + pitchOscillation = wave * currentAnimation.joints[3].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase)); + yawOscillation = currentAnimation.joints[3].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].yawPhase)); + rollOscillation = currentAnimation.joints[3].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].rollPhase)); + MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( pitchOscillation + currentAnimation.joints[3].pitchOffset, yawOscillation + currentAnimation.joints[3].yawOffset, rollOscillation + currentAnimation.joints[3].rollOffset)); + MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees(-pitchOscillation + currentAnimation.joints[3].pitchOffset, yawOscillation - currentAnimation.joints[3].yawOffset, rollOscillation - currentAnimation.joints[3].rollOffset)); + + if(INTERNAL_STATE===WALKING || + INTERNAL_STATE===CONFIG_WALK_STYLES || + INTERNAL_STATE===CONFIG_WALK_TWEAKS || + INTERNAL_STATE===CONFIG_WALK_JOINTS) { + // 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. As luck would have it, we're using a sine wave, so finding dy/dx is as + // simple as determining the cosine wave for the foot's pitch function... + var feetPitchDifferential = Math.cos(toRadians((cumulativeTime * 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 joint oscillation + pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].pitchPhase)); + yawOscillation = currentAnimation.joints[4].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset; + rollOscillation = currentAnimation.joints[4].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset; + MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees(-pitchOscillation + currentAnimation.joints[4].pitchOffset, yawOscillation, rollOscillation)); + MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( pitchOscillation + currentAnimation.joints[4].pitchOffset, yawOscillation, rollOscillation)); + + // calculate spine joint rotations + pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; + yawOscillation = currentAnimation.joints[5].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset; + rollOscillation = currentAnimation.joints[5].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset; + + // apply spine joint rotations + MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees(-pitchOscillation, yawOscillation, rollOscillation)); + + // calcualte spine 1 rotatations + pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; + yawOscillation = currentAnimation.joints[6].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset; + rollOscillation = currentAnimation.joints[6].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset; + + // apply spine1 joint rotations + MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees( pitchOscillation, -yawOscillation, rollOscillation)); + + // spine 2 + pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[7].pitchPhase)) + currentAnimation.joints[7].pitchOffset; + yawOscillation = currentAnimation.joints[7].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[7].yawPhase)) + currentAnimation.joints[7].yawOffset; + rollOscillation = currentAnimation.joints[7].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[7].rollPhase)) + currentAnimation.joints[7].rollOffset; + + // apply spine2 joint rotations + MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees(-pitchOscillation, yawOscillation, -rollOscillation)); + + if(!armsFree) { + + // shoulders + pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; + yawOscillation = currentAnimation.joints[8].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[8].yawPhase)); + rollOscillation = currentAnimation.joints[8].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset; + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation + currentAnimation.joints[8].yawOffset, rollOscillation )); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation - currentAnimation.joints[8].yawOffset, -rollOscillation )); + + // upper arms + pitchOscillation = currentAnimation.joints[9].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[9].pitchPhase)) + currentAnimation.joints[9].pitchOffset; + yawOscillation = currentAnimation.joints[9].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[9].yawPhase)); + rollOscillation = currentAnimation.joints[9].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[9].rollPhase)) + currentAnimation.joints[9].rollOffset; + MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - currentAnimation.joints[9].yawOffset, rollOscillation )); + MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + currentAnimation.joints[9].yawOffset, -rollOscillation )); + + // forearms + pitchOscillation = currentAnimation.joints[10].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].pitchPhase)) + currentAnimation.joints[10].pitchOffset; + yawOscillation = currentAnimation.joints[10].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].yawPhase)); + rollOscillation = currentAnimation.joints[10].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].rollPhase)); + MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + currentAnimation.joints[10].yawOffset, rollOscillation + currentAnimation.joints[10].rollOffset )); + MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - currentAnimation.joints[10].yawOffset, rollOscillation - currentAnimation.joints[10].rollOffset )); + + // hands + pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset; + yawOscillation = currentAnimation.joints[11].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset; + rollOscillation = currentAnimation.joints[11].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].rollPhase)) ; + MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation + currentAnimation.joints[11].rollOffset)); + MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollDegrees( pitchOscillation, -yawOscillation, rollOscillation - currentAnimation.joints[11].rollOffset)); + + } // if(!armsFree) + + // head + pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset; + yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset; + rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(toRadians(( cumulativeTime * 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)); +} + + + +// getBezier from: http://13thparallel.com/archive/bezier-curves/ +//====================================\\ +// 13thParallel.org Beziér Curve Code \\ +// by Dan Pupius (www.pupius.net) \\ +//====================================\\ +/* +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; +} +*/ + + +// the faster we go, the further we lean forward. the angle is calcualted here +var leanAngles = [0,0,0,0,0,0,0,0,0,0]; // smooth out and add damping with simple averaging filter. 20 tap = too much damping, 10 pretty good +function getLeanPitch(velocity) { + + if(velocity>TERMINAL_VELOCITY) velocity=TERMINAL_VELOCITY; + + var leanAngle = velocity / TERMINAL_VELOCITY * currentAnimation.settings.flyingHipsPitch; + + // simple averaging filter + leanAngles.push(leanAngle); + leanAngles.shift(); // FIFO + var totalLeanAngles = 0; + for(ea in leanAngles) totalLeanAngles += leanAngles[ea]; + var finalLeanAngle = totalLeanAngles / leanAngles.length; + + //print('final lean angle '+finalLeanAngle); // we found that native support already follows a curve - see graph in forum post + + return finalLeanAngle; + + // work in progress - apply bezier curve to lean / velocity response + + /*var percentTotalLean = velocity / TERMINAL_VELOCITY; + + no curve applied - used for checking results only + var linearLeanAngle = percentTotalLean * currentAnimation.settings.flyingHipsPitch; + + // make the hips pitch / velocity curve follow a nice bezier + // bezier control points + Q1 = coord(0,0); + Q2 = coord(0.2,0.8); + Q3 = coord(0.8,0.2); + Q4 = coord(1,1); + + var easedLean = getBezier(percentTotalLean, Q1, Q2, Q3, Q4); + var leanAngle = (1-easedLean.x) * currentAnimation.settings.flyingHipsPitch; + //print('before bezier: '+linearLeanAngle.toFixed(4)+' after bezier '+leanAngle.toFixed(4)); + + // simple averaging filter + leanAngles.push(leanAngle); + leanAngles.shift(); // FIFO + var totalLeanAngles = 0; + for(ea in leanAngles) totalLeanAngles += leanAngles[ea]; + var finalLeanAngle = totalLeanAngles / leanAngles.length; + + print('before bezier: '+linearLeanAngle.toFixed(4));//+' after bezier '+leanAngle.toFixed(4)); + + return finalLeanAngle; + */ +} + +// calculate the angle at which to bank into corners when turning +var angularVelocities = [0,0,0,0,0,0,0,0,0,0]; // smooth out and add damping with simple averaging filter +function getLeanRoll(deltaTime,velocity) { + + var angularVelocityMax = 70; + var currentOrientationVec3 = Quat.safeEulerAngles(MyAvatar.orientation); + var lastOrientationVec3 = Quat.safeEulerAngles(lastOrientation); + var deltaYaw = lastOrientationVec3.y-currentOrientationVec3.y; + var angularVelocity = deltaYaw / deltaTime; + if(angularVelocity>70) angularVelocity = angularVelocityMax; + if(angularVelocity<-70) angularVelocity = -angularVelocityMax; + angularVelocities.push(angularVelocity); + angularVelocities.shift(); // FIFO + var totalAngularVelocities = 0; + for(ea in angularVelocities) totalAngularVelocities += angularVelocities[ea]; + var averageAngularVelocity = totalAngularVelocities / angularVelocities.length; + var velocityAdjuster = Math.sqrt(velocity/TERMINAL_VELOCITY); // put a little curvature on our otherwise linear velocity modifier + if(velocityAdjuster>1) velocityAdjuster = 1; + if(velocityAdjuster<0) velocityAdjuster = 0; + var leanRoll = velocityAdjuster * (averageAngularVelocity/angularVelocityMax) * currentAnimation.settings.maxBankingAngle; + //print('delta time is '+deltaTime.toFixed(4)+' and delta yaw is '+deltaYaw+' angular velocity is '+angularVelocity+' and average angular velocity is '+averageAngularVelocity+' and velocityAdjuster is '+velocityAdjuster+' and final value is '+leanRoll); + //print('array: '+angularVelocities.toString()); + lastOrientation = MyAvatar.orientation; + return leanRoll; +} + +// sets up the interface componenets and updates the internal state +function setInternalState(newInternalState) { + + switch(newInternalState) { + + case WALKING: + print('WALKING'); + if(!minimised) doStandardMenu(); + INTERNAL_STATE = WALKING; + currentAnimation = selectedWalk; + break; + + case FLYING: + print('FLYING'); + if(!minimised) doStandardMenu(); + INTERNAL_STATE = FLYING; + currentAnimation = selectedFly; + break; + + 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); + } + break; + + 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(); + } + break; + + 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); + Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + initialiseWalkJointsPanel(selectedJointIndex); + } + break; + + case CONFIG_STANDING: + INTERNAL_STATE = CONFIG_STANDING; + currentAnimation = selectedStand; + if(!minimised) { + hidebuttonOverlays(); + hideJointControls(); + doStandardMenu(); + showFrontPanelButtons(false); + showWalkStyleButtons(false); + setBackground(controlsBackgroundWalkEditJoints); + setButtonOverlayVisible(configStandButtonSelected); + Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + initialiseWalkJointsPanel(selectedJointIndex); + } + break; + + case CONFIG_FLYING: + INTERNAL_STATE = CONFIG_FLYING; + currentAnimation = selectedFly; + if(!minimised) { + hidebuttonOverlays(); + hideJointControls(); + doStandardMenu(); + showFrontPanelButtons(false); + showWalkStyleButtons(false); + setBackground(controlsBackgroundWalkEditJoints); + setButtonOverlayVisible(configFlyingButtonSelected); + Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + initialiseWalkJointsPanel(selectedJointIndex); + } + break; + + case STANDING: + default: + print('STANDING'); + INTERNAL_STATE = STANDING; + if(!minimised) doStandardMenu(); + currentAnimation = selectedStand; + break; + } +} + +// 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 - a system very similar to switch debouncing in electronics design +var standHints = 0; +var walkHints = 0; +var flyHints = 0; +var requiredHints = 3; // debounce state changes - how many times do we get a state change request before we actually change state? +var lastDirection = DIRECTION_FORWARDS; + +Script.update.connect(function(deltaTime) { + + if(powerOn) { + + cumulativeTime += deltaTime; + + // firstly test for user configuration states + switch(INTERNAL_STATE) { + + case CONFIG_WALK_STYLES: + currentAnimation = selectedWalk; + animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); + return; + case CONFIG_WALK_TWEAKS: + currentAnimation = selectedWalk; + animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); + return; + case CONFIG_WALK_JOINTS: + currentAnimation = selectedWalk; + animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); + return; + case CONFIG_STANDING: + currentAnimation = selectedStand; + animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); + return; + case CONFIG_FLYING: + currentAnimation = selectedFly; + animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); + return; + default: + break; + } + + // calcualte (local) change in position and velocity + var velocityVector = MyAvatar.getVelocity(); + var velocity = Vec3.length(velocityVector); + + // determine the candidate animation to play + var actionToTake = 0; + if( velocity < 0.1) { + actionToTake = STANDING; + standHints++; + } + else if(velocity=FLYING_SPEED) { + actionToTake = FLYING; + flyHints++; + } + + // calculate overriding (local) direction of translation for use later when decide which animation should be played + var principleDirection = 0; + var localVelocity = globalToLocal(velocityVector); + var deltaX = localVelocity.x; + var deltaY = -localVelocity.y; + var deltaZ = -localVelocity.z; + + // TODO: find out why there is a reported high up / down velocity as we near walking -> standing... + var directionChangeThreshold = 0.3; // this little hack makes it a bit better, but at the cost of delayed updated chagne in direction etc :-( + if(velocityMath.abs(deltaY) + &&Math.abs(deltaX)>Math.abs(deltaZ)) { + if(deltaX<0) { + principleDirection = DIRECTION_RIGHT;//print('velocity = '+velocity + ' DIRECTION_RIGHT: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } else { + principleDirection = DIRECTION_LEFT;//print('velocity = '+velocity + ' DIRECTION_LEFT: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } + } + else if(Math.abs(deltaY)>Math.abs(deltaX) + &&Math.abs(deltaY)>Math.abs(deltaZ)) { + if(deltaY>0) { + principleDirection = DIRECTION_DOWN;//print('velocity = '+velocity + ' DIRECTION_DOWN: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } + else { + principleDirection = DIRECTION_UP;//print('velocity = '+velocity + ' DIRECTION_UP: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } + } + else if(Math.abs(deltaZ)>Math.abs(deltaX) + &&Math.abs(deltaZ)>Math.abs(deltaY)) { + if(deltaZ>0) { + principleDirection = DIRECTION_BACKWARDS;//print('velocity = '+velocity + ' DIRECTION_BACKWARDS: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } else { + principleDirection = DIRECTION_FORWARDS;//print('velocity = '+velocity + ' DIRECTION_FORWARDS: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + } + } + } + lastDirection = principleDirection; + + // select appropriate animation + switch(actionToTake) { + + case STANDING: + if( standHints > requiredHints || INTERNAL_STATE===STANDING) { // wait for a few consecutive hints (17mS each) + + standHints = 0; + walkHints = 0; + flyHints = 0; + if(INTERNAL_STATE!==STANDING) setInternalState(STANDING); + currentAnimation = selectedStand; + animateAvatar(1,0,principleDirection); + } + return; + + case WALKING: + if( walkHints > requiredHints || INTERNAL_STATE===WALKING) { // wait for few consecutive hints (17mS each) + + standHints = 0; + walkHints = 0; + flyHints = 0; + if(INTERNAL_STATE!==WALKING) setInternalState(WALKING); + + // change animation for flying directly up or down + if(principleDirection===DIRECTION_UP) { + currentAnimation = selectedFlyUp; + } + else if(principleDirection===DIRECTION_DOWN) { + currentAnimation = selectedFlyDown; + } + else { + currentAnimation = selectedWalk; + } + animateAvatar(deltaTime, velocity, principleDirection); + } + return; + + 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 + if(principleDirection===DIRECTION_UP) { + currentAnimation = selectedFlyUp; + } + else if(principleDirection===DIRECTION_DOWN) { + currentAnimation = selectedFlyDown; + } + else currentAnimation = selectedFly; + animateAvatar(deltaTime, velocity, principleDirection); + } + return; + } + } +}); + + +// overlays start + +// controller dimensions +var backgroundWidth = 350; +var backgroundHeight = 700; +var backgroundX = Window.innerWidth-backgroundWidth-50; +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/2 - jointsControlWidth/2; +var jointsControlY = backgroundY/2 - 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 = []; + + +// take a deep breath then load up the overlays +// UI backgrounds +var controlsBackground = Overlays.addOverlay("image", { + bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +backgroundOverlays.push(controlsBackground); + +var controlsBackgroundWalkEditStyles = Overlays.addOverlay("image", { + bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-styles.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +backgroundOverlays.push(controlsBackgroundWalkEditStyles); + +var controlsBackgroundWalkEditTweaks = Overlays.addOverlay("image", { + bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-tweaks.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +backgroundOverlays.push(controlsBackgroundWalkEditTweaks); + +var controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", { + bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-joints.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +backgroundOverlays.push(controlsBackgroundWalkEditJoints); + +var controlsBackgroundFlyingEdit = Overlays.addOverlay("image", { + bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-flying-edit.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +backgroundOverlays.push(controlsBackgroundFlyingEdit); + + +// minimised tab - not put in array, as is a one off +var controlsMinimisedTab = Overlays.addOverlay("image", { + bounds: { x: Window.innerWidth - 35, y: Window.innerHeight/2 - 175, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-tab.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + +// load character joint selection control images +var hipsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-hips.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(hipsJointControl); + +var upperLegsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-upper-legs.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(upperLegsJointControl); + +var lowerLegsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-lower-legs.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(lowerLegsJointControl); + +var feetJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-feet.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(feetJointControl); + +var toesJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-toes.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(toesJointControl); + +var spineJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-spine.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(spineJointControl); + +var spine1JointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-spine1.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(spine1JointControl); + +var spine2JointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-spine2.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(spine2JointControl); + +var shouldersJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-shoulders.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(shouldersJointControl); + +var upperArmsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-upper-arms.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(upperArmsJointControl); + +var forearmsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-forearms.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(forearmsJointControl); + +var handsJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-hands.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(handsJointControl); + +var headJointControl = Overlays.addOverlay("image", { + bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-background-edit-head.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +jointsControlOverlays.push(headJointControl); + + +// sider thumb overlays +var sliderOne = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderOne); +var sliderTwo = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderTwo); +var sliderThree = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderThree); +var sliderFour = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderFour); +var sliderFive = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderFive); +var sliderSix = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderSix); +var sliderSeven = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderSeven); +var sliderEight = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderEight); +var sliderNine = Overlays.addOverlay("image", { + bounds: { x: 0, y: 0, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +sliderthumbOverlays.push(sliderNine); + + +// button overlays +var onButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-on-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(onButton); +var offButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-off-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(offButton); +var configWalkButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-walk-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkButton); +var configWalkButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-walk-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkButtonSelected); +var configStandButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-stand-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configStandButton); +var configStandButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-stand-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configStandButtonSelected); +var configFlyingButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-fly-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configFlyingButton); +var configFlyingButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-edit-fly-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configFlyingButtonSelected); +var hideButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-hide-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(hideButton); +var hideButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-hide-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(hideButtonSelected); +var configWalkStylesButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-styles-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkStylesButton); +var configWalkStylesButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-styles-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkStylesButtonSelected); +var configWalkTweaksButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-tweaks-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkTweaksButton); +var configWalkTweaksButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-tweaks-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkTweaksButtonSelected); +var configWalkJointsButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-bones-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkJointsButton); +var configWalkJointsButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-bones-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(configWalkJointsButtonSelected); +var backButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-back-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +buttonOverlays.push(backButton); +var backButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-back-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +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: 1, height: 1}, + imageURL: pathToOverlays+"ddao-female-big-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +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 + }); +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 + }); +bigButtonOverlays.push(maleBigButton); + +var maleBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-male-big-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(maleBigButtonSelected); + +var armsFreeBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-arms-free-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(armsFreeBigButton); + +var armsFreeBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-arms-free-button-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(armsFreeBigButtonSelected); + +var footstepsBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-footsteps-big-button.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +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 + }); +bigButtonOverlays.push(footstepsBigButtonSelected); + + +// walk styles +bigButtonYOffset = 121; +var strutWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-strut.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(strutWalkBigButton); + +var strutWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-strut-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(strutWalkBigButtonSelected); + +bigButtonYOffset += 60 +var sexyWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-sexy.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(sexyWalkBigButton); + +var sexyWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-sexy-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(sexyWalkBigButtonSelected); + +bigButtonYOffset += 60; +var powerWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-power-walk.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(powerWalkBigButton); + +var powerWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-power-walk-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(powerWalkBigButtonSelected); + +bigButtonYOffset += 60; +var shuffleBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-shuffle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(shuffleBigButton); + +var shuffleBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-shuffle-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(shuffleBigButtonSelected); + +bigButtonYOffset += 60; +var runBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-run.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(runBigButton); + +var runBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-run-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(runBigButtonSelected); + +bigButtonYOffset += 60; +var sneakyWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-sneaky.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(sneakyWalkBigButton); + +var sneakyWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-sneaky-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(sneakyWalkBigButtonSelected); + +bigButtonYOffset += 60; +var toughWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-tough.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(toughWalkBigButton); + +var toughWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-tough-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(toughWalkBigButtonSelected); + +bigButtonYOffset += 60; +var coolWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-cool.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(coolWalkBigButton); + +var coolWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-cool-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(coolWalkBigButtonSelected); + +bigButtonYOffset += 60; +var elderlyWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-elderly.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(elderlyWalkBigButton); + +var elderlyWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + imageURL: pathToOverlays+"ddao-walk-select-button-elderly-selected.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +bigButtonOverlays.push(elderlyWalkBigButtonSelected); + +// 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: false, + 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: false, + anchor: "MyAvatar" + }); + +var debugText = Overlays.addOverlay("text", { + x: Window.innerWidth/2 + 200, + y: Window.innerHeight/2 - 300, + width: 200, + height: 130, + color: { red: 255, green: 255, blue: 255}, + textColor: { red: 255, green: 255, blue: 255}, + topMargin: 5, + leftMargin: 5, + visible: false, + backgroundColor: { red: 255, green: 255, blue: 255}, + text: "Debug area\nNothing to report yet." + }); + +// 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) { + + var bigButtonWidth = 1; + var bigButtonHeight = 1; + + if(showButtons) { + var bigButtonWidth = 230; + var bigButtonHeight = 36; + } + if(avatarGender===FEMALE) { + Overlays.editOverlay(femaleBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(femaleBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(maleBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(maleBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + } else { + Overlays.editOverlay(femaleBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(femaleBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(maleBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(maleBigButton, { width: 1, height: 1 } ); + } + if(armsFree) { + Overlays.editOverlay(armsFreeBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(armsFreeBigButton, { width: 1, height: 1 } ); + } else { + Overlays.editOverlay(armsFreeBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(armsFreeBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + } + if(playFootStepSounds) { + Overlays.editOverlay(footstepsBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(footstepsBigButton, { width: 1, height: 1 } ); + } else { + Overlays.editOverlay(footstepsBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(footstepsBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + } +} +function minimiseDialog() { + + if(minimised) { + setBackground(); + hidebuttonOverlays(); + setSliderthumbsVisible(false); + hideJointControls(); + showFrontPanelButtons(false); + Overlays.editOverlay(controlsMinimisedTab, { width: 36, height: 351 } ); + } else { + setInternalState(STANDING); // show all the controls again + Overlays.editOverlay(controlsMinimisedTab, { width: 1, height: 1 } ); + } +} +function setBackground(backgroundName) { + for(var i in backgroundOverlays) { + if(backgroundOverlays[i] === backgroundName) + Overlays.editOverlay(backgroundName, {width: backgroundWidth, height: backgroundHeight } ); + else Overlays.editOverlay(backgroundOverlays[i], { width: 1, height: 1} ); + } +} +function setButtonOverlayVisible(buttonOverlayName) { + for(var i in buttonOverlays) { + if(buttonOverlays[i] === buttonOverlayName) { + Overlays.editOverlay(buttonOverlayName, { width: 60, height: 47 } ); + } + } +} +// top row menu type buttons (smaller) +function hidebuttonOverlays() { + for(var i in buttonOverlays) { + Overlays.editOverlay(buttonOverlays[i], { width: 1, height: 1 } ); + } +} +function hideJointControls() { + for(var i in jointsControlOverlays) { + Overlays.editOverlay(jointsControlOverlays[i], { width: 1, height: 1 } ); + } +} +function setSliderthumbsVisible(visible) { + var sliderThumbSize = 0; + if(visible) sliderThumbSize = 25; + for(var i = 0 ; i < sliderthumbOverlays.length ; i++) { + Overlays.editOverlay(sliderthumbOverlays[i], { width: sliderThumbSize, height: sliderThumbSize} ); + } +} +function initialiseWalkJointsPanel(propertyIndex) { + + selectedJointIndex = propertyIndex; + + // set the image for the selected joint on the character control + hideJointControls(); + switch (selectedJointIndex) { + case 0: + Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 1: + Overlays.editOverlay(upperLegsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 2: + Overlays.editOverlay(lowerLegsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 3: + Overlays.editOverlay(feetJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 4: + Overlays.editOverlay(toesJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 5: + Overlays.editOverlay(spineJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 6: + Overlays.editOverlay(spine1JointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 7: + Overlays.editOverlay(spine2JointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 8: + Overlays.editOverlay(shouldersJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 9: + Overlays.editOverlay(upperArmsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 10: + Overlays.editOverlay(forearmsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 11: + Overlays.editOverlay(handsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + break; + case 12: + Overlays.editOverlay(headJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[selectedJointIndex].yaw / sliderRanges.joints[selectedJointIndex].yawRange * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[selectedJointIndex].roll / sliderRanges.joints[selectedJointIndex].rollRange * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + + // set phases (full range, -180 to 180) + sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].pitchPhase/2)/180 * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].yawPhase/2)/180 * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].rollPhase/2)/180 * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + + // 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = (((sliderRanges.joints[selectedJointIndex].yawOffsetRange+currentAnimation.joints[selectedJointIndex].yawOffset)/2)/sliderRanges.joints[selectedJointIndex].yawOffsetRange) * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + sliderXPos = (((sliderRanges.joints[selectedJointIndex].rollOffsetRange+currentAnimation.joints[selectedJointIndex].rollOffset)/2)/sliderRanges.joints[selectedJointIndex].rollOffsetRange) * sliderRangeX; + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); +} + +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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.settings.takeFlightVelocity / 300 * sliderRangeX; // start flying speed + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[0].sway / sliderRanges.joints[0].swayRange * sliderRangeX; // Hips sway + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[0].bob / sliderRanges.joints[0].bobRange * sliderRangeX; // Hips bob + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[0].thrust / sliderRanges.joints[0].thrustRange * sliderRangeX; // Hips thrust + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = (0.5+(currentAnimation.adjusters.legsSeparation.strength/2)) * sliderRangeX; // legs separation + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.adjusters.stride.strength * sliderRangeX; // stride + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = currentAnimation.joints[9].yaw / sliderRanges.joints[9].yawRange * sliderRangeX; // arms swing - is just upper arms yaw + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + sliderXPos = (((sliderRanges.joints[9].pitchOffsetRange-currentAnimation.joints[9].pitchOffset)/2)/sliderRanges.joints[9].pitchOffsetRange) * sliderRangeX; // arms out - is just upper arms pitch offset + Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); +} + +function showWalkStyleButtons(showButtons) { + + var bigButtonWidth = 230; + var bigButtonHeight = 36; + + if(!showButtons) { + bigButtonWidth = 1; + bigButtonHeight = 1; + } + + // 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], {width: 1, height: 1}); + } + + if(!showButtons) return; + + // set all the non-selected ones to showing + for(var i = 8 ; i < bigButtonOverlays.length ; i+=2) { + Overlays.editOverlay(bigButtonOverlays[i], {width: bigButtonWidth, height: bigButtonHeight}); + } + + // set the currently selected one + if(selectedWalk === femaleSexyWalk || selectedWalk === maleSexyWalk) { + Overlays.editOverlay(sexyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(sexyWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { + Overlays.editOverlay(strutWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(strutWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femalePowerWalk || selectedWalk === malePowerWalk) { + Overlays.editOverlay(powerWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(powerWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleShuffle || selectedWalk === maleShuffle) { + Overlays.editOverlay(shuffleBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(shuffleBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleRun || selectedWalk === maleRun) { + Overlays.editOverlay(runBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(runBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleRandomWalk || selectedWalk === maleRandomWalk) { + Overlays.editOverlay(sneakyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(sneakyWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleToughWalk || selectedWalk === maleToughWalk) { + Overlays.editOverlay(toughWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(toughWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleCoolWalk || selectedWalk === maleCoolWalk) { + Overlays.editOverlay(coolWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(coolWalkBigButton, {width: 1, height: 1}); + } + else if(selectedWalk === femaleElderlyWalk || selectedWalk === maleElderlyWalk) { + Overlays.editOverlay(elderlyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(elderlyWalkBigButton, {width: 1, height: 1}); + } +} + +// 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, { width: 1, height: 1 } ); + Overlays.editOverlay(hideButtonSelected, { width: 60, height: 47 } ); + return; + + case backButton: + Overlays.editOverlay(backButton, { width: 1, height: 1 } ); + Overlays.editOverlay(backButtonSelected, { width: 60, height: 47 } ); + return; + + case controlsMinimisedTab: + // TODO: add visual user feedback for tab click + return; + + case footstepsBigButton: + playFootStepSounds = true; + Overlays.editOverlay(footstepsBigButtonSelected, { width: 230, height: 36 } ); + Overlays.editOverlay(footstepsBigButton, { width: 1, height: 1 } ); + return; + + case footstepsBigButtonSelected: + playFootStepSounds = false; + Overlays.editOverlay(footstepsBigButton, { width: 230, height: 36 } ); + Overlays.editOverlay(footstepsBigButtonSelected, { width: 1, height: 1 } ); + return; + + case femaleBigButton: + case maleBigButtonSelected: + avatarGender = FEMALE; + selectedWalk = femaleStrutWalk; + selectedStand = femaleStandOne; + selectedFlyUp = femaleFlyingUp; + selectedFly = femaleFlying; + selectedFlyDown = femaleFlyingDown; + Overlays.editOverlay(femaleBigButtonSelected, { width: 230, height: 36 } ); + Overlays.editOverlay(femaleBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(maleBigButton, { width: 230, height: 36 } ); + Overlays.editOverlay(maleBigButtonSelected, { width: 1, height: 1 } ); + return; + + case armsFreeBigButton: + armsFree = true; + Overlays.editOverlay(armsFreeBigButtonSelected, { width: 230, height: 36 } ); + Overlays.editOverlay(armsFreeBigButton, { width: 1, height: 1 } ); + return; + + case armsFreeBigButtonSelected: + armsFree = false; + Overlays.editOverlay(armsFreeBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(armsFreeBigButton, { width: 230, height: 36 } ); + return; + + case maleBigButton: + case femaleBigButtonSelected: + avatarGender = MALE; + selectedWalk = maleStrutWalk; + selectedStand = maleStandOne; + selectedFlyUp = maleFlyingUp; + selectedFly = maleFlying; + selectedFlyDown = maleFlyingDown; + Overlays.editOverlay(femaleBigButton, { width: 230, height: 36 } ); + Overlays.editOverlay(femaleBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(maleBigButtonSelected, { width: 230, height: 36 } ); + Overlays.editOverlay(maleBigButton, { width: 1, height: 1 } ); + return; + + case coolWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleCoolWalk; + else selectedWalk = maleCoolWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case coolWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleCoolWalk; + else selectedWalk = maleCoolWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case elderlyWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleElderlyWalk; + else selectedWalk = maleElderlyWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case powerWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femalePowerWalk; + else selectedWalk = malePowerWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case runBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleRun; + else selectedWalk = maleRun; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case sexyWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleSexyWalk; + else selectedWalk = maleSexyWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case shuffleBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleShuffle; + else selectedWalk = maleShuffle; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case sneakyWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleRandomWalk; + else selectedWalk = maleRandomWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case strutWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleStrutWalk; + else selectedWalk = maleStrutWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + case toughWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleToughWalk; + else selectedWalk = maleToughWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + maxFootForward = 0; + maxFootBackwards = 0; + break; + + 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) { + + // 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) { + initialiseWalkJointsPanel(0); + return; + } + else if(clickX>63&&clickX<132&&clickY>156&&clickY<202) { + initialiseWalkJointsPanel(1); + return; + } + else if(clickX>58&&clickX<137&&clickY>203&&clickY<250) { + initialiseWalkJointsPanel(2); + return; + } + else if(clickX>58&&clickX<137&&clickY>250&&clickY<265) { + initialiseWalkJointsPanel(3); + return; + } + else if(clickX>58&&clickX<137&&clickY>265&&clickY<280) { + initialiseWalkJointsPanel(4); + return; + } + else if(clickX>78&&clickX<121&&clickY>111&&clickY<128) { + initialiseWalkJointsPanel(5); + return; + } + else if(clickX>78&&clickX<128&&clickY>89&&clickY<111) { + initialiseWalkJointsPanel(6); + return; + } + else if(clickX>85&&clickX<118&&clickY>77&&clickY<94) { + initialiseWalkJointsPanel(7); + return; + } + else if(clickX>64&&clickX<125&&clickY>55&&clickY<77) { + initialiseWalkJointsPanel(8); + return; + } + else if((clickX>44&&clickX<73&&clickY>71&&clickY<94) + ||(clickX>125&&clickX<144&&clickY>71&&clickY<94)) { + initialiseWalkJointsPanel(9); + return; + } + else if((clickX>28&&clickX<57&&clickY>94&&clickY<119) + ||(clickX>137&&clickX<170&&clickY>97&&clickY<114)) { + initialiseWalkJointsPanel(10); + return; + } + else if((clickX>18&&clickX<37&&clickY>115&&clickY<136) + ||(clickX>157&&clickX<182&&clickY>115&&clickY<136)) { + initialiseWalkJointsPanel(11); + return; + } + else if(clickX>81&&clickX<116&&clickY>12&&clickY<53) { + initialiseWalkJointsPanel(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) { + + 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.adjusters.legsSeparation.strength = (thumbPositionNormalised-0.5)/2; + } + else if(movingSliderSeven) { // stride + Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} ); + currentAnimation.adjusters.stride.strength = thumbPositionNormalised; + } + 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, {width: 0, height: 0} ); + Overlays.editOverlay(onButton, {width: 60, height: 47 } ); + stand(); + } + else if(clickedOverlay === hideButton || clickedOverlay === hideButtonSelected){ + Overlays.editOverlay(hideButton, { width: 60, height: 47 } ); + Overlays.editOverlay(hideButtonSelected, { width: 1, height: 1 } ); + 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 configFlyingButtonSelected: + case configWalkStylesButtonSelected: + case configWalkTweaksButtonSelected: + case configWalkJointsButtonSelected: + setInternalState(STANDING); + break; + + case onButton: + powerOn = false; + setInternalState(STANDING); + Overlays.editOverlay(offButton, {width: 60, height: 47 } ); + Overlays.editOverlay(onButton, {width: 0, height: 0} ); + resetJoints(); + break; + + case backButton: + case backButtonSelected: + Overlays.editOverlay(backButton, { width: 1, height: 1 } ); + Overlays.editOverlay(backButtonSelected, { width: 1, height: 1 } ); + 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 + break; + + case configStandButton: + setInternalState(CONFIG_STANDING); + break; + + case configFlyingButton: + setInternalState(CONFIG_FLYING); + 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(debugText); +}); + + +function keyPressEvent(event) { + + //print('keyPressEvent: '+event.text); + + 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'); + } + if (event.text == "t") { + statsOn = !statsOn; + if(statsOn) { + print('wheel stats on (t to turn off again)'); + Overlays.editOverlay(debugText, {visible: true}); + Overlays.editOverlay(walkWheelYLine, {visible: true}); + Overlays.editOverlay(walkWheelZLine, {visible: true}); + } else { + print('wheel stats off (t to turn on again)'); + Overlays.editOverlay(debugText, {visible: false}); + Overlays.editOverlay(walkWheelYLine, {visible: false}); + Overlays.editOverlay(walkWheelZLine, {visible: false}); + } + } +} +Controller.keyPressEvent.connect(keyPressEvent); + + + + + +// debug and other info +var VERBOSE = false; + +// TODO: implement joint mapping using reg expressions to cover a wide range of avi bone structures +var jointList = MyAvatar.getJointNames(); +var jointMappings = "\n# Avatar joint list start"; +for (var i = 0; i < jointList.length; i++) { + jointMappings = jointMappings + "\njointIndex = " + jointList[i] + " = " + i; +} +print(jointMappings + "\n# walk.js avatar joint list end"); + +// 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)); + MyAvatar.clearJointData(jointList[i]); +} +var hipsToFeetDistance = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightFoot").y; +print('\nwalk.js: Hips to feet: '+hipsToFeetDistance); + + +//////////////////////////////////////////// +// begin by setting the to state STANDING // +//////////////////////////////////////////// + +//curlFingers(); +setInternalState(STANDING); \ No newline at end of file From 80aa5e45f8f65eb83ae3972974812b80b9064a2b Mon Sep 17 00:00:00 2001 From: DaveDubUK Date: Thu, 25 Sep 2014 11:51:11 +0700 Subject: [PATCH 02/40] Update to walk.js 1.006b Update to walk.js 1.006b --- examples/walk.js | 3976 +++++++++++++++++++++++++++++++++------------- 1 file changed, 2885 insertions(+), 1091 deletions(-) diff --git a/examples/walk.js b/examples/walk.js index de349a95b8..17091b7f36 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,6 +1,7 @@ // // walk.js // +// version 1.006b // // Created by Davedub, August / September 2014 // @@ -15,19 +16,19 @@ // path to the animation files //var pathToAnimFiles = 'http://localhost/downloads/hf/scripts/animation-files/'; // loads fine (files must be present on localhost) //var pathToAnimFiles = 'http://highfidelity.davedub.co.uk/procedural/walk/animation-files/'; // files present, but load with errors - weird -var pathToAnimFiles = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/files/'; // working (but only without https) +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://localhost/downloads/hf/overlays/'; // loads fine (files must be present on localhost) +//var pathToOverlays = 'http://localhost/downloads/hf/scripts/overlays/'; // loads fine (files must be present on localhost) //var pathToOverlays = 'http://highfidelity.davedub.co.uk/procedural/walk/overlays/'; // files present, but won't load - weird -var pathToOverlays = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/images/'; // working (but only without https) +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/'; //var pathToSounds = 'http://localhost/downloads/hf/sounds/Footsteps/'; -// load all the animation datafiles ( 15 female, 15 male ~ 240k ) +// load all the animation datafiles Script.include(pathToAnimFiles+"dd-female-cool-walk-animation.js"); Script.include(pathToAnimFiles+"dd-female-elderly-walk-animation.js"); Script.include(pathToAnimFiles+"dd-female-power-walk-animation.js"); @@ -41,8 +42,8 @@ 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-standing-two-animation.js"); -Script.include(pathToAnimFiles+"dd-female-standing-three-animatiom.js"); +Script.include(pathToAnimFiles+"dd-female-sidestep-left-animation.js"); +Script.include(pathToAnimFiles+"dd-female-sidestep-right-animation.js"); Script.include(pathToAnimFiles+"dd-male-cool-walk-animation.js"); Script.include(pathToAnimFiles+"dd-male-elderly-walk-animation.js"); Script.include(pathToAnimFiles+"dd-male-power-walk-animation.js"); @@ -56,8 +57,8 @@ 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-standing-two-animation.js"); -Script.include(pathToAnimFiles+"dd-male-standing-three-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 FemaleCoolWalkFile = new FemaleCoolWalk(); @@ -86,10 +87,10 @@ var FemaleFlyingDownFile = new FemaleFlyingDown(); var femaleFlyingDown = FemaleFlyingDownFile.loadAnimation(); var FemaleStandOneFile = new FemaleStandingOne(); var femaleStandOne = FemaleStandOneFile.loadAnimation(); -var FemaleStandTwoFile = new FemaleStandingTwo(); -var femaleStandTwo = FemaleStandTwoFile.loadAnimation(); -var FemaleStandThreeFile = new FemaleStandingThree(); -var femaleStandThree = FemaleStandThreeFile.loadAnimation(); +var FemaleSideStepLeftFile = new FemaleSideStepLeft(); +var femaleSideStepLeft = FemaleSideStepLeftFile.loadAnimation(); +var FemaleSideStepRightFile = new FemaleSideStepRight(); +var femaleSideStepRight = FemaleSideStepRightFile.loadAnimation(); var MaleCoolWalkFile = new MaleCoolWalk(); var maleCoolWalk = MaleCoolWalkFile.loadAnimation(); var MaleElderlyWalkFile = new MaleElderlyWalk(); @@ -116,10 +117,10 @@ var MaleFlyingDownFile = new MaleFlyingDown(); var maleFlyingDown = MaleFlyingDownFile.loadAnimation(); var MaleStandOneFile = new MaleStandingOne(); var maleStandOne = MaleStandOneFile.loadAnimation(); -var MaleStandTwoFile = new MaleStandingTwo(); -var maleStandTwo = MaleStandTwoFile.loadAnimation(); -var MaleStandThreeFile = new MaleStandingThree(); -var maleStandThree = MaleStandThreeFile.loadAnimation(); +var MaleSideStepLeftFile = new MaleSideStepLeft(); +var maleSideStepLeft = MaleSideStepLeftFile.loadAnimation(); +var MaleSideStepRightFile = new MaleSideStepRight(); +var maleSideStepRight = MaleSideStepRightFile.loadAnimation(); // read in the sounds var footsteps = []; @@ -130,230 +131,218 @@ 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 (always +-180)) -var sliderRanges = -{ - "joints":[ - { - "name":"hips", - "pitchRange":25, - "yawRange":25, - "rollRange":25, - "pitchOffsetRange":25, - "yawOffsetRange":25, - "rollOffsetRange":25, - "thrustRange":0.1, - "bobRange":0.5, - "swayRange":0.08 - }, - { - "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 - } - ] -} +// 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 = 2; -var WALKING = 4; -var FLYING = 8; -var CONFIG_WALK_STYLES = 16; -var CONFIG_WALK_TWEAKS = 32; -var CONFIG_WALK_JOINTS = 64; -var CONFIG_STANDING = 128; -var CONFIG_FLYING = 256; +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 = false; -var armsFree = false; // set true for hydra support - experimental +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 = 12.5; // m/s - real humans can't run any faster -var TERMINAL_VELOCITY = 300; +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 MALE = 64; -var FEMALE = 128; +var DIRECTION_NONE = 64; +var MALE = 1; +var FEMALE = 2; // start of animation control section var cumulativeTime = 0.0; var lastOrientation; -var movementDirection = DIRECTION_FORWARDS; -var playFootStepSounds = true; -var avatarGender = FEMALE; -var selectedWalk = femaleStrutWalk; // the currently selected animation walk file -var selectedStand = femaleStandOne; -var selectedFlyUp = femaleFlyingUp; -var selectedFly = femaleFlying; -var selectedFlyDown = femaleFlyingDown; + +// 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 -// stride calibration -var maxFootForward = 0; -var maxFootBackwards = 0; -var strideLength = 0; +var currentTransition = null; // used as a pointer to a Transition + // walkwheel (foot / ground speed matching) -var walkCycleStart = 105; // best foot forwards - TODO: if different for different anims, add as setting to anim files -var walkWheelPosition = walkCycleStart; +//var walkCycleStart = 140; // 105 for female strut... best foot forwards - TODO: if found to be different for different anims, add as setting to anim files +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 -// for showing walk wheel stats -var nFrames = 0; +// 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; + // TODO: add INTERNAL_STATE so can remove 'hints' system for state changes +} -// convert hips translations to global (i.e. take account of avi orientation) -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); +// 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); + } - //MyAvatar.addThrust(AviTranslationOffset * 10); - MyAvatar.position = {x: MyAvatar.position.x + AviTranslationOffset.x, - y: MyAvatar.position.y + AviTranslationOffset.y, - z: MyAvatar.position.z + AviTranslationOffset.z }; + // 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++; + //print('looking for '+directionAsString(arguments[0])+' directionCount '+directionCount+' count '+i+' dircetion '+directionAsString(this.recentMotions[i].principleDirection)); + } + 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) + + //print('Transition initiated from '+this.lastAnimation.name+' to '+this.nextAnimation.name+' duration '+transitionDuration.toFixed(2)); } // convert a local (to the avi) translation to a global one -function globalToLocal(localTranslation) { +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; + 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; } -// zero out all joints +// 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.addThrust(AviTranslationOffset * 10); + 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.setJointData(avatarJointNames[i], Quat.fromPitchYawRollDegrees(0,0,0)); @@ -362,9 +351,10 @@ function resetJoints() { } // play footstep sound function playFootstep(side) { + var options = new AudioInjectionOptions(); options.position = Camera.getPosition(); - options.volume = 0.7; + options.volume = 0.5; var walkNumber = 2; // 0 to 2 if(side===DIRECTION_RIGHT && playFootStepSounds) { //print('playing right footstep - if you can not hear sound, try turning your mic on then off again.'); @@ -376,338 +366,1420 @@ function playFootstep(side) { } } -// this is work in progress -// currently, it's not known if there are working finger joints on the avi +// put the fingers into a relaxed pose function curlFingers() { - MyAvatar.setJointData("RightHandMiddle1", Quat.fromPitchYawRollDegrees(90,0,0)); - for(var i = 24 ; i < 44 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,90,0)); + + // left hand fingers + for(var i = 18 ; i < 34 ; i++) { + MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(8,0,0)); } - for(var i = 48 ; i < 68 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(10,0,90)); + // 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)); } } -// maths functions -function toRadians(degreesValue) { - return degreesValue * Math.PI / 180; -} -function toDegrees(radiansValue) { - return radiansValue * 180 / Math.PI; -} -function cubicRoot(x) { - var y = Math.pow(Math.abs(x), 1/3); - return x < 0 ? -y : y; -} -// animateAvatar - animates the avatar - TODO doxygen comments? -var nextStep = DIRECTION_RIGHT; // first step is always right, because the sine waves say so +// additional maths functions +function degToRad(degreesValue) { return degreesValue * Math.PI / 180; } +function radToDeg(radiansValue) { return radiansValue * 180 / Math.PI; } +//function cubicRoot(x) { var y = Math.pow(Math.abs(x), 1/3); return x < 0 ? -y : y; } +// animateAvatar - sine wave generators working like clockwork function animateAvatar(deltaTime, velocity, principleDirection) { - // some slider adjustemnts cause a nasty flicker when adjusting + // adjusting the walk speed in edit mode causes a nasty flicker // pausing the animation stops this if(paused) return; - var adjustedFrequency = currentAnimation.settings.baseFrequency; // now only relevant for standing and flying + var cycle = cumulativeTime; + var transitionProgress = 1; + var adjustedFrequency = currentAnimation.settings.baseFrequency; - // simple legs phase reversal for walking backwards + // upper legs phase reversal for walking backwards var forwardModifier = 1; - if(principleDirection===DIRECTION_BACKWARDS) { + if(principleDirection===DIRECTION_BACKWARDS) forwardModifier = -1; - } - // no need to lean forwards with speed increase if going directly upwards + // don't want to lean forwards if going directly upwards var leanPitchModifier = 1; - if(principleDirection===DIRECTION_UP) { + if(principleDirection===DIRECTION_UP) leanPitchModifier = 0; - } + // is there a Transition to include? + if(currentTransition!==null) { - if(currentAnimation === selectedWalk) { + // if is a new transiton + if(currentTransition.progress===0) { - if(INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS) { + if( currentTransition.walkingAtStart ) { - var footPos = globalToLocal(MyAvatar.getJointPosition("RightFoot")); - var hipsPos = globalToLocal(MyAvatar.getJointPosition("Hips")); + if( INTERNAL_STATE !== SIDE_STEPPING ) { - // calibrate stride length whilst not actually moving (for accuracy) - if((hipsPos.z - footPos.z)maxFootForward) maxFootForward = (hipsPos.z - footPos.z); + // 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; + } - strideLength = 2 * (maxFootForward-maxFootBackwards); + // 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; - // TODO: take note of the avi's stride length (can store in anim file or recalculate each time worn or edited) - print('Stride length calibration: Your stride length is ' + strideLength + ' metres'); // ~ 0.8211 - } - else { + currentTransition.walkWheelIncrement = 6; - if(strideLength===0) strideLength = 1.6422; // default for if not calibrated yet + // keep the walkwheel turning by setting the walkWheelIncrement until our feet are tucked nicely underneath us. + // fold back (reverse walk) if we just missed our stop target on the walkwheel when we stopped walking - depricated + //var stepIncrement = 2; // just used to set currentTransition.walkWheelIncrement in multiple locations + if( angleToLeftStop < angleToRightStop ) { - // 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 - var wheelRadius = strideLength / Math.PI; - var angularVelocity = velocity / wheelRadius; + //if(angleToLeftStop<270) currentTransition.walkStopAngle = rightStop; + //else if(walkWheelPosition>angleToLeftStop) currentTransition.walkStopAngle = rightStop; + //else currentTransition.walkStopAngle = leftStop; - // calculate the degrees turned (at this angular velocity) since last frame - var radiansTurnedSinceLastFrame = deltaTime * angularVelocity; - var degreesTurnedSinceLastFrame = toDegrees(radiansTurnedSinceLastFrame); + currentTransition.walkStopAngle = leftStop; - // advance the walk wheel the appropriate amount - // TODO: use radians, as Math.sin needs radians below anyway! - walkWheelPosition += degreesTurnedSinceLastFrame; - if( walkWheelPosition >= 360 ) - walkWheelPosition = walkWheelPosition % 360; + //if( leftStop > 270 && walkWheelPosition < 90 ) currentTransition.walkWheelIncrement = -stepIncrement; + //else if( walkWheelPosition > 270 && leftStop < 90 ) currentTransition.walkWheelIncrement = stepIncrement; + //else if( walkWheelPosition < leftStop ) currentTransition.walkWheelIncrement = stepIncrement; + //else if( walkWheelPosition >= leftStop ) currentTransition.walkWheelIncrement = -stepIncrement; + //currentTransition.walkWheelIncrement = stepIncrement; - // set the new value for the exact correct walking speed for this velocity - adjustedFrequency = 1; - cumulativeTime = walkWheelPosition; + } else { - // show stats and walk wheel? - if(statsOn) { + //if(angleToRightStop<270) currentTransition.walkStopAngle = leftStop; + //else if(walkWheelPosition>angleToRightStop) currentTransition.walkStopAngle = leftStop; + //else currentTransition.walkStopAngle = rightStop; + currentTransition.walkStopAngle = rightStop; - nFrames++; - var distanceTravelled = velocity * deltaTime; - var deltaTimeMS = deltaTime * 1000; + //currentTransition.walkStopAngle = rightStop; + //if( rightStop > 270 && walkWheelPosition < 90 ) currentTransition.walkWheelIncrement = -stepIncrement; + //else if( walkWheelPosition > 270 && rightStop < 90 ) currentTransition.walkWheelIncrement = stepIncrement; + //else if( walkWheelPosition < rightStop ) currentTransition.walkWheelIncrement = stepIncrement; + //else if( walkWheelPosition >= rightStop ) currentTransition.walkWheelIncrement = -stepIncrement; + //currentTransition.walkWheelIncrement = stepIncrement; + } - // draw the walk wheel - var yOffset = hipsToFeetDistance - wheelRadius; - var sinWalkWheelPosition = wheelRadius * Math.sin(toRadians((forwardModifier*-1) * walkWheelPosition)); - var cosWalkWheelPosition = wheelRadius * Math.cos(toRadians((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(toRadians(forwardModifier * walkWheelPosition+90)); - cosWalkWheelPosition = wheelRadius * Math.cos(toRadians(forwardModifier * walkWheelPosition+90)); - var wheelYPos = {x:0, y:sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition}; - var wheelYEnd = {x:0, y:-sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition}; - Overlays.editOverlay(walkWheelYLine, {position:wheelYPos, end:wheelYEnd}); - Overlays.editOverlay(walkWheelZLine, {position:wheelZPos, end:wheelZEnd}); + //print('walkWheelPosition '+walkWheelPosition.toFixed(2)+' leftStop '+leftStop+' rightStop '+rightStop+' angleToLeftStop '+angleToLeftStop.toFixed(2)+' angleToRightStop '+angleToRightStop.toFixed(2)+' stop angle '+currentTransition.walkStopAngle) - // populate debug overlay - var debugInfo = 'Frame number: '+nFrames - + '\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\nStride: '+strideLength.toFixed(3) - + ' m\nWheel position: '+cumulativeTime.toFixed(1) - + ' deg\n'; - Overlays.editOverlay(debugText, {text: debugInfo}); + } else { - //print('strideLength '+strideLength.toFixed(4)+' deltaTime '+deltaTimeMS.toFixed(4)+' distanceTravelled '+distanceTravelled.toFixed(3)+' velocity '+velocity.toFixed(3)+' angularVelocity '+angularVelocity.toFixed(3)+' degreesTurnedSinceLastFrame '+degreesTurnedSinceLastFrame.toFixed(3) + ' cumulativeTime '+cumulativeTime.toFixed(3)); + // just freeze wheel for sidestepping + 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 = 10; // must be greater than the walkWheel increment + if(( walkWheelPosition > (currentTransition.walkStopAngle - tolerance )) && + ( walkWheelPosition < (currentTransition.walkStopAngle + tolerance ))) { + + //print('stop now? walkWheelAdvance '+currentTransition.walkWheelAdvance); + + //if( currentTransition.walkWheelAdvance < 45 ) { + + // currentTransition.walkStopAngle += 180; // not enough of a transition - keep moving... + // if( currentTransition.walkStopAngle > 360 ) currentTransition.walkStopAngle %= 360; + + // print('walkStopAngle incremented '); + //} + //else + currentTransition.walkWheelIncrement = 0; + } + // keep turning walk wheel until both feet are below the avi + + //print('walkWheelAdvance '+currentTransition.walkWheelAdvance); + 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; // 130 + var strideTwo = 220; // 300 + + 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'); + //print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees. footRPos '+footRPos.x.toFixed(3)+' footLPos '+footLPos.x.toFixed(3)+' footOffsetX '+footOffsetX.toFixed(3)); + 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'); + //print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees. footRPos '+footRPos.x.toFixed(3)+' footLPos '+footLPos.x.toFixed(3)+' footOffsetX '+footOffsetX.toFixed(3)); + 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 TODO: get this working in normal motion! + 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 TODO: get this working! + 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 {//if( currentTransition.walkingAtEnd ) { + + 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); + + //print('Hips: '+pitchOscillation+' '+yawOscillation+' '+rollOscillation); } else { - nFrames = 0; - walkWheelPosition = walkCycleStart; // best foot forwards for next time we walk + + 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); } - // TODO: optimise by precalculating and re-using Math.sin((cumulativeTime * femaleSexyWalk.settings.baseFrequency) when there is no phase to be applied - // TODO: optimise by 'baking' offsets and phases after editing and use during normal playback - - // calcualte hips translation - //var motorOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[0].thrustPhase)) + currentAnimation.joints[0].thrustOffset; - //var swayOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[0].swayPhase)) + currentAnimation.joints[0].swayOffset; - //var bobOscillation = Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[0].bobPhase)) + currentAnimation.joints[0].bobOffset; - - // calculate hips rotation - var pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency * 2) - + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; - var yawOscillation = currentAnimation.joints[0].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) - + currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset; - var rollOscillation = (currentAnimation.joints[0].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) - + currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset); - - // apply hips translation TODO: get this working! - //translateHips({x:swayOscillation*currentAnimation.joints[0].sway, y:motorOscillation*currentAnimation.joints[0].thrust, z:bobOscillation*currentAnimation.joints[0].bob}); - // apply hips rotation - MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees(-pitchOscillation + (forwardModifier * (leanPitchModifier*getLeanPitch(velocity))), // getLeanPitch - lean forwards as velocity increased - yawOscillation, // Yup, that's correct ;-) - rollOscillation + getLeanRoll(deltaTime,velocity))); // getLeanRoll - banking on cornering + 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 - // calculate upper leg rotations + // upper legs + if( INTERNAL_STATE!==SIDE_STEPPING && + INTERNAL_STATE!==CONFIG_SIDESTEP_LEFT && + INTERNAL_STATE!==CONFIG_SIDESTEP_RIGHT ) { - // TODO: clean up here - increase stride a bit as velocity increases - var runningModifier = velocity / currentAnimation.settings.takeFlightVelocity; - if(runningModifier>1) { - runningModifier *= 2; - runningModifier += 0.5; + // 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 { //if( currentTransition.walkingAtEnd ) { + + 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; } - else if(runningModifier>0) { - runningModifier *= 2; - runningModifier += 0.5; + + // 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 ) { + + // As luck would have it, we're using sine waves, so 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; + } } - else runningModifier = 1; // standing - runningModifier = 1; // TODO - remove this little disabling hack! + // toes + if(currentTransition!==null) { - pitchOscillation = runningModifier * currentAnimation.joints[1].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase))); - yawOscillation = currentAnimation.joints[1].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[1].yawPhase)); - rollOscillation = currentAnimation.joints[1].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[1].rollPhase)); + if(currentTransition.walkingAtStart) { - // apply upper leg rotations - var strideAdjusterPitch = 0; - var strideAdjusterPitchOffset = 0; - var strideAdjusterSeparationAngle = 0; - if(INTERNAL_STATE===WALKING || - INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS) { - strideAdjusterPitch = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.upperLegsPitch; - strideAdjusterPitchOffset = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.upperLegsPitchOffset; - strideAdjusterSeparationAngle = currentAnimation.adjusters.legsSeparation.strength * currentAnimation.adjusters.legsSeparation.separationAngle; - } - MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( - pitchOscillation + currentAnimation.joints[1].pitchOffset + strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[1].pitchPhase)) + strideAdjusterPitchOffset), - yawOscillation + currentAnimation.joints[1].yawOffset, - -rollOscillation - strideAdjusterSeparationAngle - currentAnimation.joints[1].rollOffset )); - MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( - - pitchOscillation + currentAnimation.joints[1].pitchOffset - strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[1].pitchPhase)) - strideAdjusterPitchOffset), - yawOscillation - currentAnimation.joints[1].yawOffset, - -rollOscillation + strideAdjusterSeparationAngle + currentAnimation.joints[1].rollOffset )); + 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; - // calculate lower leg joint rotations - strideAdjusterPitch = 0; - strideAdjusterPitchOffset = 0; - if(INTERNAL_STATE===WALKING || - INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS) { - strideAdjusterPitch = currentAnimation.adjusters.stride.strength * currentAnimation.adjusters.stride.lowerLegsPitch; - strideAdjusterPitchOffset = currentAnimation.adjusters.stride.strength*currentAnimation.adjusters.stride.lowerLegsPitchOffset; - } - pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase)); - yawOscillation = currentAnimation.joints[2].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].yawPhase)); - rollOscillation = currentAnimation.joints[2].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[2].rollPhase)); + pitchOffset = currentAnimation.joints[4].pitchOffset; - // apply lower leg joint rotations - MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( - -pitchOscillation + currentAnimation.joints[2].pitchOffset - strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[2].pitchPhase)) + strideAdjusterPitchOffset), - 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 + strideAdjusterPitch * (Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[2].pitchPhase)) - strideAdjusterPitchOffset), - yawOscillation + currentAnimation.joints[2].yawOffset, - rollOscillation + currentAnimation.joints[2].rollOffset)); + 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; - // foot joint oscillation is a hard curve to replicate - var wave = 1;//(baseOscillation + 1)/2; // TODO: finish this - +ve num between 0 and 1 gives a kick at the forward part of the swing - pitchOscillation = wave * currentAnimation.joints[3].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase)); - yawOscillation = currentAnimation.joints[3].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].yawPhase)); - rollOscillation = currentAnimation.joints[3].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency ) + currentAnimation.joints[3].rollPhase)); - MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( pitchOscillation + currentAnimation.joints[3].pitchOffset, yawOscillation + currentAnimation.joints[3].yawOffset, rollOscillation + currentAnimation.joints[3].rollOffset)); - MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees(-pitchOscillation + currentAnimation.joints[3].pitchOffset, yawOscillation - currentAnimation.joints[3].yawOffset, rollOscillation - currentAnimation.joints[3].rollOffset)); + pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset; - if(INTERNAL_STATE===WALKING || - INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS) { - // 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. As luck would have it, we're using a sine wave, so finding dy/dx is as - // simple as determining the cosine wave for the foot's pitch function... - var feetPitchDifferential = Math.cos(toRadians((cumulativeTime * 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; - } - } + } else { //if( currentTransition.walkingAtEnd ) { - // toes joint oscillation - pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].pitchPhase)); - yawOscillation = currentAnimation.joints[4].yaw * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset; - rollOscillation = currentAnimation.joints[4].roll * Math.sin(toRadians((cumulativeTime * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset; - MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees(-pitchOscillation + currentAnimation.joints[4].pitchOffset, yawOscillation, rollOscillation)); - MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( pitchOscillation + currentAnimation.joints[4].pitchOffset, yawOscillation, rollOscillation)); + 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; - // calculate spine joint rotations - pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; - yawOscillation = currentAnimation.joints[5].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset; - rollOscillation = currentAnimation.joints[5].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].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 { //if( currentTransition.walkingAtEnd ) { + + 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)); + MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - // calcualte spine 1 rotatations - pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; - yawOscillation = currentAnimation.joints[6].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset; - rollOscillation = currentAnimation.joints[6].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset; + // 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 { //if( currentTransition.walkingAtEnd ) { + + 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)); + MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); // spine 2 - pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[7].pitchPhase)) + currentAnimation.joints[7].pitchOffset; - yawOscillation = currentAnimation.joints[7].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[7].yawPhase)) + currentAnimation.joints[7].yawOffset; - rollOscillation = currentAnimation.joints[7].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[7].rollPhase)) + currentAnimation.joints[7].rollOffset; + 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 { //if( currentTransition.walkingAtEnd ) { + + 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)); + MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); if(!armsFree) { // shoulders - pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; - yawOscillation = currentAnimation.joints[8].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[8].yawPhase)); - rollOscillation = currentAnimation.joints[8].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset; - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation + currentAnimation.joints[8].yawOffset, rollOscillation )); - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation - currentAnimation.joints[8].yawOffset, -rollOscillation )); + 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 { //if( currentTransition.walkingAtEnd ) { + + 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 - pitchOscillation = currentAnimation.joints[9].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[9].pitchPhase)) + currentAnimation.joints[9].pitchOffset; - yawOscillation = currentAnimation.joints[9].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[9].yawPhase)); - rollOscillation = currentAnimation.joints[9].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[9].rollPhase)) + currentAnimation.joints[9].rollOffset; - MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - currentAnimation.joints[9].yawOffset, rollOscillation )); - MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + currentAnimation.joints[9].yawOffset, -rollOscillation )); + 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 { //if( currentTransition.walkingAtEnd ) { + + 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 - pitchOscillation = currentAnimation.joints[10].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].pitchPhase)) + currentAnimation.joints[10].pitchOffset; - yawOscillation = currentAnimation.joints[10].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].yawPhase)); - rollOscillation = currentAnimation.joints[10].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[10].rollPhase)); - MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + currentAnimation.joints[10].yawOffset, rollOscillation + currentAnimation.joints[10].rollOffset )); - MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - currentAnimation.joints[10].yawOffset, rollOscillation - currentAnimation.joints[10].rollOffset )); + 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 { //if( currentTransition.walkingAtEnd ) { + + 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; + } + + // transitionProgress pitchOscillation yawOscillation rollOscillation + //print(transitionProgress+' '+pitchOscillation+' '+yawOscillation+' '+rollOscillation); + + // apply forearms rotations + MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + yawOffset, rollOscillation + rollOffset )); + MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - yawOffset, rollOscillation - rollOffset )); // hands - pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset; - yawOscillation = currentAnimation.joints[11].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset; - rollOscillation = currentAnimation.joints[11].roll * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[11].rollPhase)) ; - MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation + currentAnimation.joints[11].rollOffset)); - MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollDegrees( pitchOscillation, -yawOscillation, rollOscillation - currentAnimation.joints[11].rollOffset)); + var sideStepSign = 1; + if(INTERNAL_STATE===SIDE_STEPPING) { + sideStepSign = 1; + } // TODO: check status of hand rotations + if(currentTransition!==null) { - } // if(!armsFree) + if(currentTransition.walkingAtStart) { - // head - pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(toRadians(( cumulativeTime * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset; - yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(toRadians(( cumulativeTime * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset; - rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(toRadians(( cumulativeTime * 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)); + 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 { //if( currentTransition.walkingAtEnd ) { + + 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 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 { //if( currentTransition.walkingAtEnd ) { + + 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; + } + + // TODO: see if can animate separate heads in any way... + 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 )); } -// getBezier from: http://13thparallel.com/archive/bezier-curves/ -//====================================\\ -// 13thParallel.org Beziér Curve Code \\ -// by Dan Pupius (www.pupius.net) \\ -//====================================\\ -/* -coord = function (x,y) { +// getBezier - 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}; @@ -719,110 +1791,168 @@ 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(); + 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 = [0,0,0,0,0,0,0,0,0,0]; // smooth out and add damping with simple averaging filter. 20 tap = too much damping, 10 pretty good +var leanAngles = []; // smooth out and add damping with simple averaging filter. +leanAngles.length = 15; + function getLeanPitch(velocity) { +/* + // lean backwards when decelerating a lot. skid to a halt. working, but I don't like the effect - will use a reach pose later instead + var accelerationResponse = recentMotions[0].acceleration.z; + var accelerationResponseMax = 45; // max degrees hip pitch + + if(velocityaccelerationResponseMax) + accelerationResponse = accelerationResponseMax; + else if(accelerationResponse<-accelerationResponseMax) + accelerationResponse = -accelerationResponseMax; + // apply yet another averaging filter... + accelerationResponseAngles.push(accelerationResponse); + accelerationResponseAngles.shift(); + var finalAccelerationResponse = 0; + for(ea in accelerationResponseAngles) finalAccelerationResponse += accelerationResponseAngles[ea]; + finalAccelerationResponse /= accelerationResponseAngles.length; + + // calculate any skid for this frame and apply it + var skidDistance = -0.01 * hipsToFeetDistance * Math.sin(degToRad(finalAccelerationResponse)); + if(Math.abs(skidDistance)>0.001 && INTERNAL_STATE===STANDING) { // show skids when stopping + var skidVector = localToGlobal({ x:0, y:0, z:skidDistance }); + print('skidDistance '+skidDistance+' metres'); + MyAvatar.position = Vec3.sum(MyAvatar.position, skidVector); + } + if(Math.abs(accelerationResponse)>0) print('accelerationResponse '+accelerationResponse.toFixed(3)+' recent acceleration '+recentMotions[0].acceleration.z.toFixed(3)); +*/ 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; + //var leanProgressButterworth = filterButterworth(leanProgressBezier); - var leanAngle = velocity / TERMINAL_VELOCITY * currentAnimation.settings.flyingHipsPitch; - - // simple averaging filter - leanAngles.push(leanAngle); + // 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 finalLeanAngle = totalLeanAngles / leanAngles.length; + var leanProgressAverageFiltered = totalLeanAngles / leanAngles.length; - //print('final lean angle '+finalLeanAngle); // we found that native support already follows a curve - see graph in forum post - - return finalLeanAngle; - - // work in progress - apply bezier curve to lean / velocity response - - /*var percentTotalLean = velocity / TERMINAL_VELOCITY; - - no curve applied - used for checking results only - var linearLeanAngle = percentTotalLean * currentAnimation.settings.flyingHipsPitch; - - // make the hips pitch / velocity curve follow a nice bezier - // bezier control points - Q1 = coord(0,0); - Q2 = coord(0.2,0.8); - Q3 = coord(0.8,0.2); - Q4 = coord(1,1); - - var easedLean = getBezier(percentTotalLean, Q1, Q2, Q3, Q4); - var leanAngle = (1-easedLean.x) * currentAnimation.settings.flyingHipsPitch; - //print('before bezier: '+linearLeanAngle.toFixed(4)+' after bezier '+leanAngle.toFixed(4)); - - // simple averaging filter - leanAngles.push(leanAngle); - leanAngles.shift(); // FIFO - var totalLeanAngles = 0; - for(ea in leanAngles) totalLeanAngles += leanAngles[ea]; - var finalLeanAngle = totalLeanAngles / leanAngles.length; - - print('before bezier: '+linearLeanAngle.toFixed(4));//+' after bezier '+leanAngle.toFixed(4)); - - return finalLeanAngle; - */ + // 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 angularVelocities = [0,0,0,0,0,0,0,0,0,0]; // smooth out and add damping with simple averaging filter -function getLeanRoll(deltaTime,velocity) { +var leanRollAngles = []; // smooth out and add damping with simple averaging filter +leanRollAngles.length = 25; - var angularVelocityMax = 70; +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; - var angularVelocity = deltaYaw / deltaTime; - if(angularVelocity>70) angularVelocity = angularVelocityMax; - if(angularVelocity<-70) angularVelocity = -angularVelocityMax; - angularVelocities.push(angularVelocity); - angularVelocities.shift(); // FIFO - var totalAngularVelocities = 0; - for(ea in angularVelocities) totalAngularVelocities += angularVelocities[ea]; - var averageAngularVelocity = totalAngularVelocities / angularVelocities.length; - var velocityAdjuster = Math.sqrt(velocity/TERMINAL_VELOCITY); // put a little curvature on our otherwise linear velocity modifier - if(velocityAdjuster>1) velocityAdjuster = 1; - if(velocityAdjuster<0) velocityAdjuster = 0; - var leanRoll = velocityAdjuster * (averageAngularVelocity/angularVelocityMax) * currentAnimation.settings.maxBankingAngle; - //print('delta time is '+deltaTime.toFixed(4)+' and delta yaw is '+deltaYaw+' angular velocity is '+angularVelocity+' and average angular velocity is '+averageAngularVelocity+' and velocityAdjuster is '+velocityAdjuster+' and final value is '+leanRoll); - //print('array: '+angularVelocities.toString()); lastOrientation = MyAvatar.orientation; - return leanRoll; + + 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; } -// sets up the interface componenets and updates the internal state +// set up the interface components, update the internal state and kick off any transitions function setInternalState(newInternalState) { + var debugShowStateChanges = false; + switch(newInternalState) { case WALKING: - print('WALKING'); + + if(debugShowStateChanges) print('WALKING'); if(!minimised) doStandardMenu(); INTERNAL_STATE = WALKING; - currentAnimation = selectedWalk; - break; + return; case FLYING: - print('FLYING'); + + if(debugShowStateChanges) print('FLYING'); if(!minimised) doStandardMenu(); INTERNAL_STATE = FLYING; - currentAnimation = selectedFly; - break; + return; + + case SIDE_STEPPING: + + if(debugShowStateChanges) print('SIDE_STEPPING'); + if(!minimised) doStandardMenu(); + INTERNAL_STATE = SIDE_STEPPING; + return; case CONFIG_WALK_STYLES: + INTERNAL_STATE = CONFIG_WALK_STYLES; currentAnimation = selectedWalk; if(!minimised) { @@ -836,11 +1966,12 @@ function setInternalState(newInternalState) { setButtonOverlayVisible(configWalkTweaksButton); setButtonOverlayVisible(configWalkJointsButton); setButtonOverlayVisible(backButton); - setSliderthumbsVisible(false); + setSliderThumbsVisible(false); } - break; + return; case CONFIG_WALK_TWEAKS: + INTERNAL_STATE = CONFIG_WALK_TWEAKS; currentAnimation = selectedWalk; if(!minimised) { @@ -856,9 +1987,10 @@ function setInternalState(newInternalState) { setButtonOverlayVisible(backButton); initialiseWalkTweaks(); } - break; + return; case CONFIG_WALK_JOINTS: + INTERNAL_STATE = CONFIG_WALK_JOINTS; currentAnimation = selectedWalk; if(!minimised) { @@ -871,50 +2003,136 @@ function setInternalState(newInternalState) { setButtonOverlayVisible(configWalkTweaksButton); setButtonOverlayVisible(configWalkJointsButtonSelected); setButtonOverlayVisible(backButton); - Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); - initialiseWalkJointsPanel(selectedJointIndex); + initialiseJointsEditingPanel(selectedJointIndex); } - break; + return; case CONFIG_STANDING: + INTERNAL_STATE = CONFIG_STANDING; currentAnimation = selectedStand; if(!minimised) { hidebuttonOverlays(); - hideJointControls(); - doStandardMenu(); showFrontPanelButtons(false); showWalkStyleButtons(false); setBackground(controlsBackgroundWalkEditJoints); + setButtonOverlayVisible(onButton); + setButtonOverlayVisible(configSideStepRightButton); + setButtonOverlayVisible(configSideStepLeftButton); setButtonOverlayVisible(configStandButtonSelected); - Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); - initialiseWalkJointsPanel(selectedJointIndex); + setButtonOverlayVisible(backButton); + initialiseJointsEditingPanel(selectedJointIndex); } - break; + 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(); - hideJointControls(); - doStandardMenu(); showFrontPanelButtons(false); showWalkStyleButtons(false); setBackground(controlsBackgroundWalkEditJoints); + setButtonOverlayVisible(onButton); + setButtonOverlayVisible(configFlyingUpButton); + setButtonOverlayVisible(configFlyingDownButton); setButtonOverlayVisible(configFlyingButtonSelected); - Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); - initialiseWalkJointsPanel(selectedJointIndex); + setButtonOverlayVisible(backButton); + initialiseJointsEditingPanel(selectedJointIndex); } - break; + 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: - print('STANDING'); + + if(debugShowStateChanges) print('STANDING'); INTERNAL_STATE = STANDING; if(!minimised) doStandardMenu(); - currentAnimation = selectedStand; - break; + + // initialisation - runs at script startup only + if(strideLength===0) { + + if(principleDirection===DIRECTION_BACKWARDS) + strideLength = selectedWalk.calibration.strideLengthBackwards; + else + strideLength = selectedWalk.calibration.strideLengthForwards; + + curlFingers(); + } + return; } } @@ -926,159 +2144,516 @@ function setInternalState(newInternalState) { var standHints = 0; var walkHints = 0; var flyHints = 0; -var requiredHints = 3; // debounce state changes - how many times do we get a state change request before we actually change state? -var lastDirection = DIRECTION_FORWARDS; +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 test for user configuration states + // 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, 0, DIRECTION_FORWARDS); - return; + animateAvatar(deltaTime, speed, principleDirection); + editing = true; + break; case CONFIG_WALK_TWEAKS: currentAnimation = selectedWalk; - animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); - return; + animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); + editing = true; + break; case CONFIG_WALK_JOINTS: currentAnimation = selectedWalk; - animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); - return; + animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); + editing = true; + break; case CONFIG_STANDING: currentAnimation = selectedStand; - animateAvatar(deltaTime, 0, DIRECTION_FORWARDS); - return; + 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, 0, DIRECTION_FORWARDS); - return; + 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; } - // calcualte (local) change in position and velocity - var velocityVector = MyAvatar.getVelocity(); - var velocity = Vec3.length(velocityVector); + // 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(); - // determine the candidate animation to play - var actionToTake = 0; - if( velocity < 0.1) { - actionToTake = STANDING; - standHints++; - } - else if(velocity=FLYING_SPEED) { - actionToTake = FLYING; - flyHints++; - } + // 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()); - // calculate overriding (local) direction of translation for use later when decide which animation should be played - var principleDirection = 0; - var localVelocity = globalToLocal(velocityVector); - var deltaX = localVelocity.x; - var deltaY = -localVelocity.y; - var deltaZ = -localVelocity.z; + if(!editing) { - // TODO: find out why there is a reported high up / down velocity as we near walking -> standing... - var directionChangeThreshold = 0.3; // this little hack makes it a bit better, but at the cost of delayed updated chagne in direction etc :-( - if(velocity= 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;//print('velocity = '+velocity + ' DIRECTION_RIGHT: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + principleDirection = DIRECTION_RIGHT; } else { - principleDirection = DIRECTION_LEFT;//print('velocity = '+velocity + ' DIRECTION_LEFT: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + principleDirection = DIRECTION_LEFT; } } else if(Math.abs(deltaY)>Math.abs(deltaX) &&Math.abs(deltaY)>Math.abs(deltaZ)) { if(deltaY>0) { - principleDirection = DIRECTION_DOWN;//print('velocity = '+velocity + ' DIRECTION_DOWN: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + principleDirection = DIRECTION_UP; } else { - principleDirection = DIRECTION_UP;//print('velocity = '+velocity + ' DIRECTION_UP: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + principleDirection = DIRECTION_DOWN; } } else if(Math.abs(deltaZ)>Math.abs(deltaX) &&Math.abs(deltaZ)>Math.abs(deltaY)) { if(deltaZ>0) { - principleDirection = DIRECTION_BACKWARDS;//print('velocity = '+velocity + ' DIRECTION_BACKWARDS: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + principleDirection = DIRECTION_FORWARDS; } else { - principleDirection = DIRECTION_FORWARDS;//print('velocity = '+velocity + ' DIRECTION_FORWARDS: deltaX '+deltaX+' deltaY '+deltaY+' deltaZ '+deltaZ); + 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 + // but for now, we have to deal with states like 'standing in the air' + + // 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; + //print('You were walking for '+timeWalking+' mS'); + + 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: + + //currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.3, {x:0.5,y:0.08}, {x:0.05,y:0.75}); + 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;//selectedSideStep.calibration.sideStepCycleStartLeft; + + } else { + + walkWheelPosition = sideStepCycleStartRight;//selectedSideStep.calibration.sideStepCycleStartRight; + } + switch(currentAnimation) { + + case selectedStand: + + //currentTransition = new Transition(currentAnimation, selectedSideStep, [], 0.8, {x:0.5,y:0.08}, {x:0.28,y:1}); + break; + + default: + + //currentTransition = new Transition(currentAnimation, selectedSideStep, [], 0.8, {x:0.5,y:0.08}, {x:0.28,y:1}); + 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 ) { + + // quick test for the frame execution time measurement + // lots of console logging messes up execution times pretty well! + //for(var doh = 0 ; doh < 10 ; doh++) { + // //var fake = doh * doh * doh; + // print('faking bad coding...'+doh); + //} + + 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; + } } - lastDirection = principleDirection; - - // select appropriate animation - switch(actionToTake) { - - case STANDING: - if( standHints > requiredHints || INTERNAL_STATE===STANDING) { // wait for a few consecutive hints (17mS each) - - standHints = 0; - walkHints = 0; - flyHints = 0; - if(INTERNAL_STATE!==STANDING) setInternalState(STANDING); - currentAnimation = selectedStand; - animateAvatar(1,0,principleDirection); - } - return; - - case WALKING: - if( walkHints > requiredHints || INTERNAL_STATE===WALKING) { // wait for few consecutive hints (17mS each) - - standHints = 0; - walkHints = 0; - flyHints = 0; - if(INTERNAL_STATE!==WALKING) setInternalState(WALKING); - - // change animation for flying directly up or down - if(principleDirection===DIRECTION_UP) { - currentAnimation = selectedFlyUp; - } - else if(principleDirection===DIRECTION_DOWN) { - currentAnimation = selectedFlyDown; - } - else { - currentAnimation = selectedWalk; - } - animateAvatar(deltaTime, velocity, principleDirection); - } - return; - - 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 - if(principleDirection===DIRECTION_UP) { - currentAnimation = selectedFlyUp; - } - else if(principleDirection===DIRECTION_DOWN) { - currentAnimation = selectedFlyDown; - } - else currentAnimation = selectedFly; - animateAvatar(deltaTime, velocity, principleDirection); - } - return; - } } }); @@ -1088,373 +2663,498 @@ Script.update.connect(function(deltaTime) { // controller dimensions var backgroundWidth = 350; var backgroundHeight = 700; -var backgroundX = Window.innerWidth-backgroundWidth-50; +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/2 - jointsControlWidth/2; -var jointsControlY = backgroundY/2 - jointsControlHeight/2; +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 sliderThumbOverlays = []; // thumb sliders var backgroundOverlays = []; var buttonOverlays = []; var jointsControlOverlays = []; var bigButtonOverlays = []; -// take a deep breath then load up the overlays -// UI backgrounds +// take a deep breath and... + +// load UI backgrounds var controlsBackground = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, imageURL: pathToOverlays+"ddao-background.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); backgroundOverlays.push(controlsBackground); var controlsBackgroundWalkEditStyles = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); backgroundOverlays.push(controlsBackgroundWalkEditStyles); var controlsBackgroundWalkEditTweaks = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); backgroundOverlays.push(controlsBackgroundWalkEditTweaks); var controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); backgroundOverlays.push(controlsBackgroundWalkEditJoints); var controlsBackgroundFlyingEdit = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); backgroundOverlays.push(controlsBackgroundFlyingEdit); + + // minimised tab - not put in array, as is a one off var controlsMinimisedTab = Overlays.addOverlay("image", { - bounds: { x: Window.innerWidth - 35, y: Window.innerHeight/2 - 175, width: 1, height: 1}, - imageURL: pathToOverlays+"ddao-tab.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1 - }); + 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: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(hipsJointControl); var upperLegsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(upperLegsJointControl); var lowerLegsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(lowerLegsJointControl); var feetJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(feetJointControl); var toesJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(toesJointControl); var spineJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(spineJointControl); var spine1JointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(spine1JointControl); var spine2JointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(spine2JointControl); var shouldersJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(shouldersJointControl); var upperArmsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(upperArmsJointControl); var forearmsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(forearmsJointControl); var handsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(handsJointControl); var headJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); jointsControlOverlays.push(headJointControl); // sider thumb overlays var sliderOne = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderOne); +sliderThumbOverlays.push(sliderOne); var sliderTwo = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderTwo); +sliderThumbOverlays.push(sliderTwo); var sliderThree = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderThree); +sliderThumbOverlays.push(sliderThree); var sliderFour = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderFour); +sliderThumbOverlays.push(sliderFour); var sliderFive = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderFive); +sliderThumbOverlays.push(sliderFive); var sliderSix = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderSix); +sliderThumbOverlays.push(sliderSix); var sliderSeven = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderSeven); +sliderThumbOverlays.push(sliderSeven); var sliderEight = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderEight); +sliderThumbOverlays.push(sliderEight); var sliderNine = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 1, height: 1}, + bounds: { x: 0, y: 0, width: 25, height: 25 }, imageURL: pathToOverlays+"ddao-slider-handle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -sliderthumbOverlays.push(sliderNine); +sliderThumbOverlays.push(sliderNine); // button overlays var onButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(onButton); var offButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(offButton); var configWalkButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkButton); var configWalkButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkButtonSelected); var configStandButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configStandButton); var configStandButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configStandButtonSelected); + var configFlyingButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configFlyingButton); var configFlyingButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + 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: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(hideButton); var hideButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(hideButtonSelected); var configWalkStylesButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkStylesButton); var configWalkStylesButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkStylesButtonSelected); var configWalkTweaksButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkTweaksButton); var configWalkTweaksButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + 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: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkJointsButton); var configWalkJointsButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(configWalkJointsButtonSelected); + var backButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(backButton); var backButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); buttonOverlays.push(backButtonSelected); @@ -1462,10 +3162,11 @@ buttonOverlays.push(backButtonSelected); 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: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(femaleBigButton); @@ -1473,7 +3174,8 @@ 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(femaleBigButtonSelected); @@ -1481,39 +3183,44 @@ 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(maleBigButton); var maleBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(maleBigButtonSelected); var armsFreeBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(armsFreeBigButton); var armsFreeBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(armsFreeBigButtonSelected); var footstepsBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(footstepsBigButton); @@ -1521,7 +3228,8 @@ 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(footstepsBigButtonSelected); @@ -1529,154 +3237,172 @@ bigButtonOverlays.push(footstepsBigButtonSelected); // walk styles bigButtonYOffset = 121; var strutWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(strutWalkBigButton); var strutWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + 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 + alpha: 1, + visible: false }); bigButtonOverlays.push(strutWalkBigButtonSelected); bigButtonYOffset += 60 var sexyWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-sexy.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(sexyWalkBigButton); var sexyWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-sexy-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(sexyWalkBigButtonSelected); bigButtonYOffset += 60; var powerWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-power-walk.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(powerWalkBigButton); var powerWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-power-walk-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(powerWalkBigButtonSelected); bigButtonYOffset += 60; var shuffleBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-shuffle.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(shuffleBigButton); var shuffleBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-shuffle-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(shuffleBigButtonSelected); bigButtonYOffset += 60; var runBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-run.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(runBigButton); var runBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-run-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(runBigButtonSelected); bigButtonYOffset += 60; -var sneakyWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, - imageURL: pathToOverlays+"ddao-walk-select-button-sneaky.png", +var randomWalkBigButton = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, + imageURL: pathToOverlays+"ddao-walk-select-button-random.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -bigButtonOverlays.push(sneakyWalkBigButton); +bigButtonOverlays.push(randomWalkBigButton); -var sneakyWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, - imageURL: pathToOverlays+"ddao-walk-select-button-sneaky-selected.png", +var randomWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, + imageURL: pathToOverlays+"ddao-walk-select-button-random-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); -bigButtonOverlays.push(sneakyWalkBigButtonSelected); +bigButtonOverlays.push(randomWalkBigButtonSelected); bigButtonYOffset += 60; var toughWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-tough.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(toughWalkBigButton); var toughWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-tough-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(toughWalkBigButtonSelected); bigButtonYOffset += 60; var coolWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-cool.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(coolWalkBigButton); var coolWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-cool-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(coolWalkBigButtonSelected); bigButtonYOffset += 60; var elderlyWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-elderly.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(elderlyWalkBigButton); var elderlyWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 1, height: 1}, + bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, imageURL: pathToOverlays+"ddao-walk-select-button-elderly-selected.png", color: { red: 255, green: 255, blue: 255}, - alpha: 1 + alpha: 1, + visible: false }); bigButtonOverlays.push(elderlyWalkBigButtonSelected); @@ -1687,7 +3413,7 @@ var walkWheelZLine = Overlays.addOverlay("line3d", { color: { red: 0, green: 255, blue: 255}, alpha: 1, lineWidth: 5, - visible: false, + visible: statsOn, anchor: "MyAvatar" }); var walkWheelYLine = Overlays.addOverlay("line3d", { @@ -1696,22 +3422,44 @@ var walkWheelYLine = Overlays.addOverlay("line3d", { color: { red: 255, green: 0, blue: 255}, alpha: 1, lineWidth: 5, - visible: false, + visible: statsOn, anchor: "MyAvatar" }); - -var debugText = Overlays.addOverlay("text", { - x: Window.innerWidth/2 + 200, - y: Window.innerHeight/2 - 300, +var debugStats = Overlays.addOverlay("text", { + x: backgroundX-199, y: backgroundY, width: 200, - height: 130, - color: { red: 255, green: 255, blue: 255}, - textColor: { red: 255, green: 255, blue: 255}, + 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: 5, - visible: false, - backgroundColor: { red: 255, green: 255, blue: 255}, - text: "Debug area\nNothing to report yet." + 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 @@ -1725,43 +3473,36 @@ function doStandardMenu() { setButtonOverlayVisible(configStandButton); setButtonOverlayVisible(configFlyingButton); setButtonOverlayVisible(hideButton); - setSliderthumbsVisible(false); + setSliderThumbsVisible(false); showFrontPanelButtons(true); showWalkStyleButtons(false); } function showFrontPanelButtons(showButtons) { - var bigButtonWidth = 1; - var bigButtonHeight = 1; - - if(showButtons) { - var bigButtonWidth = 230; - var bigButtonHeight = 36; - } if(avatarGender===FEMALE) { - Overlays.editOverlay(femaleBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); - Overlays.editOverlay(femaleBigButton, { width: 1, height: 1 } ); - Overlays.editOverlay(maleBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(maleBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(femaleBigButtonSelected, { visible: showButtons } ); + Overlays.editOverlay(femaleBigButton, { visible: false } ); + Overlays.editOverlay(maleBigButtonSelected, { visible: false } ); + Overlays.editOverlay(maleBigButton, { visible: showButtons } ); } else { - Overlays.editOverlay(femaleBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(femaleBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); - Overlays.editOverlay(maleBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); - Overlays.editOverlay(maleBigButton, { width: 1, height: 1 } ); + 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, { width: bigButtonWidth, height: bigButtonHeight } ); - Overlays.editOverlay(armsFreeBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(armsFreeBigButtonSelected, { visible: showButtons } ); + Overlays.editOverlay(armsFreeBigButton, { visible: false } ); } else { - Overlays.editOverlay(armsFreeBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(armsFreeBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } ); + Overlays.editOverlay(armsFreeBigButton, { visible: showButtons } ); } if(playFootStepSounds) { - Overlays.editOverlay(footstepsBigButtonSelected, { width: bigButtonWidth, height: bigButtonHeight } ); - Overlays.editOverlay(footstepsBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(footstepsBigButtonSelected, { visible: showButtons } ); + Overlays.editOverlay(footstepsBigButton, { visible: false } ); } else { - Overlays.editOverlay(footstepsBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(footstepsBigButton, { width: bigButtonWidth, height: bigButtonHeight } ); + Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } ); + Overlays.editOverlay(footstepsBigButton, { visible: showButtons } ); } } function minimiseDialog() { @@ -1769,48 +3510,46 @@ function minimiseDialog() { if(minimised) { setBackground(); hidebuttonOverlays(); - setSliderthumbsVisible(false); + setSliderThumbsVisible(false); hideJointControls(); showFrontPanelButtons(false); - Overlays.editOverlay(controlsMinimisedTab, { width: 36, height: 351 } ); + Overlays.editOverlay(controlsMinimisedTab, { visible: true } ); } else { setInternalState(STANDING); // show all the controls again - Overlays.editOverlay(controlsMinimisedTab, { width: 1, height: 1 } ); + Overlays.editOverlay(controlsMinimisedTab, { visible: false } ); } } function setBackground(backgroundName) { for(var i in backgroundOverlays) { if(backgroundOverlays[i] === backgroundName) - Overlays.editOverlay(backgroundName, {width: backgroundWidth, height: backgroundHeight } ); - else Overlays.editOverlay(backgroundOverlays[i], { width: 1, height: 1} ); + 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, { width: 60, height: 47 } ); + Overlays.editOverlay(buttonOverlayName, { visible: true } ); } } } // top row menu type buttons (smaller) function hidebuttonOverlays() { for(var i in buttonOverlays) { - Overlays.editOverlay(buttonOverlays[i], { width: 1, height: 1 } ); + Overlays.editOverlay(buttonOverlays[i], { visible: false } ); } } function hideJointControls() { for(var i in jointsControlOverlays) { - Overlays.editOverlay(jointsControlOverlays[i], { width: 1, height: 1 } ); + Overlays.editOverlay(jointsControlOverlays[i], { visible: false } ); } } -function setSliderthumbsVisible(visible) { - var sliderThumbSize = 0; - if(visible) sliderThumbSize = 25; - for(var i = 0 ; i < sliderthumbOverlays.length ; i++) { - Overlays.editOverlay(sliderthumbOverlays[i], { width: sliderThumbSize, height: sliderThumbSize} ); +function setSliderThumbsVisible(thumbsVisible) { + for(var i = 0 ; i < sliderThumbOverlays.length ; i++) { + Overlays.editOverlay(sliderThumbOverlays[i], { visible: thumbsVisible } ); } } -function initialiseWalkJointsPanel(propertyIndex) { +function initialiseJointsEditingPanel(propertyIndex) { selectedJointIndex = propertyIndex; @@ -1818,43 +3557,43 @@ function initialiseWalkJointsPanel(propertyIndex) { hideJointControls(); switch (selectedJointIndex) { case 0: - Overlays.editOverlay(hipsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(hipsJointControl, { visible: true }); break; case 1: - Overlays.editOverlay(upperLegsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(upperLegsJointControl, { visible: true }); break; case 2: - Overlays.editOverlay(lowerLegsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(lowerLegsJointControl, { visible: true }); break; case 3: - Overlays.editOverlay(feetJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(feetJointControl, { visible: true }); break; case 4: - Overlays.editOverlay(toesJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(toesJointControl, { visible: true }); break; case 5: - Overlays.editOverlay(spineJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(spineJointControl, { visible: true }); break; case 6: - Overlays.editOverlay(spine1JointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(spine1JointControl, { visible: true }); break; case 7: - Overlays.editOverlay(spine2JointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(spine2JointControl, { visible: true }); break; case 8: - Overlays.editOverlay(shouldersJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(shouldersJointControl, { visible: true }); break; case 9: - Overlays.editOverlay(upperArmsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(upperArmsJointControl, { visible: true }); break; case 10: - Overlays.editOverlay(forearmsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(forearmsJointControl, { visible: true }); break; case 11: - Overlays.editOverlay(handsJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(handsJointControl, { visible: true }); break; case 12: - Overlays.editOverlay(headJointControl, { bounds: { x: backgroundX+75, y: backgroundY+92, width: 200, height: 300}} ); + Overlays.editOverlay(headJointControl, { visible: true }); break; } @@ -1863,28 +3602,34 @@ function initialiseWalkJointsPanel(propertyIndex) { var yLocation = backgroundY+359; // pitch your role - var sliderXPos = currentAnimation.joints[selectedJointIndex].pitch / sliderRanges.joints[selectedJointIndex].pitchRange * sliderRangeX; - Overlays.editOverlay(sliderthumbOverlays[i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); - sliderXPos = currentAnimation.joints[selectedJointIndex].yaw / sliderRanges.joints[selectedJointIndex].yawRange * sliderRangeX; - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); - sliderXPos = currentAnimation.joints[selectedJointIndex].roll / sliderRanges.joints[selectedJointIndex].rollRange * sliderRangeX; - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); - sliderXPos = (((sliderRanges.joints[selectedJointIndex].yawOffsetRange+currentAnimation.joints[selectedJointIndex].yawOffset)/2)/sliderRanges.joints[selectedJointIndex].yawOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); - sliderXPos = (((sliderRanges.joints[selectedJointIndex].rollOffsetRange+currentAnimation.joints[selectedJointIndex].rollOffset)/2)/sliderRanges.joints[selectedJointIndex].rollOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=30, width: 25, height: 25}} ); + 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() { @@ -1894,83 +3639,77 @@ function initialiseWalkTweaks() { var yLocation = backgroundY+71; var sliderXPos = currentAnimation.settings.baseFrequency / MAX_WALK_SPEED * sliderRangeX; // walk speed - Overlays.editOverlay(sliderthumbOverlays[i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); - sliderXPos = currentAnimation.settings.takeFlightVelocity / 300 * sliderRangeX; // start flying speed - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + 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], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); - sliderXPos = (0.5+(currentAnimation.adjusters.legsSeparation.strength/2)) * sliderRangeX; // legs separation - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); - sliderXPos = currentAnimation.adjusters.stride.strength * sliderRangeX; // stride - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); - sliderXPos = currentAnimation.joints[9].yaw / sliderRanges.joints[9].yawRange * sliderRangeX; // arms swing - is just upper arms yaw - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); - sliderXPos = (((sliderRanges.joints[9].pitchOffsetRange-currentAnimation.joints[9].pitchOffset)/2)/sliderRanges.joints[9].pitchOffsetRange) * sliderRangeX; // arms out - is just upper arms pitch offset - Overlays.editOverlay(sliderthumbOverlays[++i], { bounds: { x: minSliderX + sliderXPos, y: yLocation+=60, width: 25, height: 25}} ); + 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) { - var bigButtonWidth = 230; - var bigButtonHeight = 36; - - if(!showButtons) { - bigButtonWidth = 1; - bigButtonHeight = 1; - } - // 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], {width: 1, height: 1}); + 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], {width: bigButtonWidth, height: bigButtonHeight}); + Overlays.editOverlay(bigButtonOverlays[i], { visible: showButtons }); } // set the currently selected one if(selectedWalk === femaleSexyWalk || selectedWalk === maleSexyWalk) { - Overlays.editOverlay(sexyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(sexyWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(sexyWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(sexyWalkBigButton, {visible: false}); } else if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { - Overlays.editOverlay(strutWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(strutWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(strutWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(strutWalkBigButton, {visible: false}); } else if(selectedWalk === femalePowerWalk || selectedWalk === malePowerWalk) { - Overlays.editOverlay(powerWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(powerWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(powerWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(powerWalkBigButton, {visible: false}); } else if(selectedWalk === femaleShuffle || selectedWalk === maleShuffle) { - Overlays.editOverlay(shuffleBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(shuffleBigButton, {width: 1, height: 1}); + Overlays.editOverlay(shuffleBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(shuffleBigButton, {visible: false}); } else if(selectedWalk === femaleRun || selectedWalk === maleRun) { - Overlays.editOverlay(runBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(runBigButton, {width: 1, height: 1}); + Overlays.editOverlay(runBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(runBigButton, {visible: false}); } else if(selectedWalk === femaleRandomWalk || selectedWalk === maleRandomWalk) { - Overlays.editOverlay(sneakyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(sneakyWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(randomWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(randomWalkBigButton, {visible: false}); } else if(selectedWalk === femaleToughWalk || selectedWalk === maleToughWalk) { - Overlays.editOverlay(toughWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(toughWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(toughWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(toughWalkBigButton, {visible: false}); } else if(selectedWalk === femaleCoolWalk || selectedWalk === maleCoolWalk) { - Overlays.editOverlay(coolWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(coolWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(coolWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(coolWalkBigButton, {visible: false}); } else if(selectedWalk === femaleElderlyWalk || selectedWalk === maleElderlyWalk) { - Overlays.editOverlay(elderlyWalkBigButtonSelected, {width: bigButtonWidth, height: bigButtonHeight}); - Overlays.editOverlay(elderlyWalkBigButton, {width: 1, height: 1}); + Overlays.editOverlay(elderlyWalkBigButtonSelected, { visible: showButtons }); + Overlays.editOverlay(elderlyWalkBigButton, {visible: false}); } } @@ -1993,13 +3732,13 @@ function mousePressEvent(event) { switch (clickedOverlay) { case hideButton: - Overlays.editOverlay(hideButton, { width: 1, height: 1 } ); - Overlays.editOverlay(hideButtonSelected, { width: 60, height: 47 } ); + Overlays.editOverlay(hideButton, { visible: false } ); + Overlays.editOverlay(hideButtonSelected, { visible: true } ); return; case backButton: - Overlays.editOverlay(backButton, { width: 1, height: 1 } ); - Overlays.editOverlay(backButtonSelected, { width: 60, height: 47 } ); + Overlays.editOverlay(backButton, { visible: false } ); + Overlays.editOverlay(backButtonSelected, { visible: true } ); return; case controlsMinimisedTab: @@ -2008,14 +3747,14 @@ function mousePressEvent(event) { case footstepsBigButton: playFootStepSounds = true; - Overlays.editOverlay(footstepsBigButtonSelected, { width: 230, height: 36 } ); - Overlays.editOverlay(footstepsBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(footstepsBigButtonSelected, { visible: true } ); + Overlays.editOverlay(footstepsBigButton, { visible: false } ); return; case footstepsBigButtonSelected: playFootStepSounds = false; - Overlays.editOverlay(footstepsBigButton, { width: 230, height: 36 } ); - Overlays.editOverlay(footstepsBigButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(footstepsBigButton, { visible: true } ); + Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } ); return; case femaleBigButton: @@ -2026,22 +3765,24 @@ function mousePressEvent(event) { selectedFlyUp = femaleFlyingUp; selectedFly = femaleFlying; selectedFlyDown = femaleFlyingDown; - Overlays.editOverlay(femaleBigButtonSelected, { width: 230, height: 36 } ); - Overlays.editOverlay(femaleBigButton, { width: 1, height: 1 } ); - Overlays.editOverlay(maleBigButton, { width: 230, height: 36 } ); - Overlays.editOverlay(maleBigButtonSelected, { width: 1, height: 1 } ); + 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, { width: 230, height: 36 } ); - Overlays.editOverlay(armsFreeBigButton, { width: 1, height: 1 } ); + Overlays.editOverlay(armsFreeBigButtonSelected, { visible: true } ); + Overlays.editOverlay(armsFreeBigButton, { visible: false } ); return; case armsFreeBigButtonSelected: armsFree = false; - Overlays.editOverlay(armsFreeBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(armsFreeBigButton, { width: 230, height: 36 } ); + Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } ); + Overlays.editOverlay(armsFreeBigButton, { visible: true } ); return; case maleBigButton: @@ -2052,10 +3793,62 @@ function mousePressEvent(event) { selectedFlyUp = maleFlyingUp; selectedFly = maleFlying; selectedFlyDown = maleFlyingDown; - Overlays.editOverlay(femaleBigButton, { width: 230, height: 36 } ); - Overlays.editOverlay(femaleBigButtonSelected, { width: 1, height: 1 } ); - Overlays.editOverlay(maleBigButtonSelected, { width: 230, height: 36 } ); - Overlays.editOverlay(maleBigButton, { width: 1, height: 1 } ); + 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 sexyWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleSexyWalk; + else selectedWalk = maleSexyWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + return; + + case powerWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femalePowerWalk; + else selectedWalk = malePowerWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + return; + + case shuffleBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleShuffle; + else selectedWalk = maleShuffle; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + return; + + case runBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleRun; + else selectedWalk = maleRun; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + return; + + case randomWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleRandomWalk; + else selectedWalk = maleRandomWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); + return; + + case toughWalkBigButton: + if(avatarGender===FEMALE) selectedWalk = femaleToughWalk; + else selectedWalk = maleToughWalk; + currentAnimation = selectedWalk; + showWalkStyleButtons(true); return; case coolWalkBigButton: @@ -2063,90 +3856,30 @@ function mousePressEvent(event) { else selectedWalk = maleCoolWalk; currentAnimation = selectedWalk; showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case coolWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleCoolWalk; - else selectedWalk = maleCoolWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; + return; case elderlyWalkBigButton: if(avatarGender===FEMALE) selectedWalk = femaleElderlyWalk; else selectedWalk = maleElderlyWalk; currentAnimation = selectedWalk; showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; + return; - case powerWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femalePowerWalk; - else selectedWalk = malePowerWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; + case sexyWalkBigButtonSelected: + case elderlyWalkBigButtonSelected: + case powerWalkBigButtonSelected: + case shuffleBigButtonSelected: + case runBigButtonSelected: + case randomWalkBigButtonSelected: + case toughWalkBigButtonSelected: + case coolWalkBigButtonSelected:*/ + case strutWalkBigButtonSelected: - case runBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleRun; - else selectedWalk = maleRun; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case sexyWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleSexyWalk; - else selectedWalk = maleSexyWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case shuffleBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleShuffle; - else selectedWalk = maleShuffle; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case sneakyWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleRandomWalk; - else selectedWalk = maleRandomWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case strutWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleStrutWalk; - else selectedWalk = maleStrutWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; - - case toughWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleToughWalk; - else selectedWalk = maleToughWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - maxFootForward = 0; - maxFootBackwards = 0; - break; + // toggle forwards / backwards walk display + if(principleDirection===DIRECTION_FORWARDS) { + principleDirection=DIRECTION_BACKWARDS; + } else principleDirection=DIRECTION_FORWARDS; + return; case sliderOne: movingSliderOne = true; @@ -2185,78 +3918,87 @@ function mousePressEvent(event) { return; } - if(INTERNAL_STATE===CONFIG_WALK_JOINTS || - INTERNAL_STATE===CONFIG_STANDING || - INTERNAL_STATE===CONFIG_FLYING) { + 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 + // 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) { - initialiseWalkJointsPanel(0); + initialiseJointsEditingPanel(0); return; } else if(clickX>63&&clickX<132&&clickY>156&&clickY<202) { - initialiseWalkJointsPanel(1); + initialiseJointsEditingPanel(1); return; } else if(clickX>58&&clickX<137&&clickY>203&&clickY<250) { - initialiseWalkJointsPanel(2); + initialiseJointsEditingPanel(2); return; } else if(clickX>58&&clickX<137&&clickY>250&&clickY<265) { - initialiseWalkJointsPanel(3); + initialiseJointsEditingPanel(3); return; } else if(clickX>58&&clickX<137&&clickY>265&&clickY<280) { - initialiseWalkJointsPanel(4); + initialiseJointsEditingPanel(4); return; } else if(clickX>78&&clickX<121&&clickY>111&&clickY<128) { - initialiseWalkJointsPanel(5); + initialiseJointsEditingPanel(5); return; } else if(clickX>78&&clickX<128&&clickY>89&&clickY<111) { - initialiseWalkJointsPanel(6); + initialiseJointsEditingPanel(6); return; } else if(clickX>85&&clickX<118&&clickY>77&&clickY<94) { - initialiseWalkJointsPanel(7); + initialiseJointsEditingPanel(7); return; } else if(clickX>64&&clickX<125&&clickY>55&&clickY<77) { - initialiseWalkJointsPanel(8); + initialiseJointsEditingPanel(8); return; } else if((clickX>44&&clickX<73&&clickY>71&&clickY<94) ||(clickX>125&&clickX<144&&clickY>71&&clickY<94)) { - initialiseWalkJointsPanel(9); + initialiseJointsEditingPanel(9); return; } else if((clickX>28&&clickX<57&&clickY>94&&clickY<119) ||(clickX>137&&clickX<170&&clickY>97&&clickY<114)) { - initialiseWalkJointsPanel(10); + initialiseJointsEditingPanel(10); return; } else if((clickX>18&&clickX<37&&clickY>115&&clickY<136) ||(clickX>157&&clickX<182&&clickY>115&&clickY<136)) { - initialiseWalkJointsPanel(11); + initialiseJointsEditingPanel(11); return; } else if(clickX>81&&clickX<116&&clickY>12&&clickY<53) { - initialiseWalkJointsPanel(12); + 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) { + 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; @@ -2322,7 +4064,7 @@ function mouseMoveEvent(event) { } else if(movingSliderTwo) { // take flight speed Overlays.editOverlay(sliderTwo, { x: sliderX + minSliderX} ); - currentAnimation.settings.takeFlightVelocity = thumbPositionNormalised * 300; + //currentAnimation.settings.takeFlightVelocity = thumbPositionNormalised * 300; } else if(movingSliderThree) { // hips sway Overlays.editOverlay(sliderThree, { x: sliderX + minSliderX} ); @@ -2338,11 +4080,11 @@ function mouseMoveEvent(event) { } else if(movingSliderSix) { // legs separation Overlays.editOverlay(sliderSix, { x: sliderX + minSliderX} ); - currentAnimation.adjusters.legsSeparation.strength = (thumbPositionNormalised-0.5)/2; + currentAnimation.joints[1].rollOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[1].rollOffsetRange; } else if(movingSliderSeven) { // stride Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} ); - currentAnimation.adjusters.stride.strength = thumbPositionNormalised; + currentAnimation.joints[1].pitch = thumbPositionNormalised * sliderRanges.joints[1].pitchRange; } else if(movingSliderEight) { // arms swing = upper arms yaw Overlays.editOverlay(sliderEight, { x: sliderX + minSliderX} ); @@ -2363,13 +4105,13 @@ function mouseReleaseEvent(event) { if(clickedOverlay === offButton) { powerOn = true; - Overlays.editOverlay(offButton, {width: 0, height: 0} ); - Overlays.editOverlay(onButton, {width: 60, height: 47 } ); + Overlays.editOverlay(offButton, { visible: false } ); + Overlays.editOverlay(onButton, { visible: true } ); stand(); } else if(clickedOverlay === hideButton || clickedOverlay === hideButtonSelected){ - Overlays.editOverlay(hideButton, { width: 60, height: 47 } ); - Overlays.editOverlay(hideButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(hideButton, { visible: true } ); + Overlays.editOverlay(hideButtonSelected, { visible: false } ); minimised = true; minimiseDialog(); } @@ -2389,11 +4131,16 @@ function mouseReleaseEvent(event) { 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: @@ -2403,15 +4150,15 @@ function mouseReleaseEvent(event) { case onButton: powerOn = false; setInternalState(STANDING); - Overlays.editOverlay(offButton, {width: 60, height: 47 } ); - Overlays.editOverlay(onButton, {width: 0, height: 0} ); + Overlays.editOverlay(offButton, { visible: true } ); + Overlays.editOverlay(onButton, { visible: false } ); resetJoints(); break; case backButton: case backButtonSelected: - Overlays.editOverlay(backButton, { width: 1, height: 1 } ); - Overlays.editOverlay(backButtonSelected, { width: 1, height: 1 } ); + Overlays.editOverlay(backButton, { visible: false } ); + Overlays.editOverlay(backButtonSelected, { visible: false } ); setInternalState(STANDING); break; @@ -2428,16 +4175,32 @@ function mouseReleaseEvent(event) { break; case configWalkButton: - setInternalState(CONFIG_WALK_STYLES); // set the default walk adjustment panel here + 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; } } } @@ -2458,8 +4221,8 @@ Script.scriptEnding.connect(function() { Overlays.deleteOverlay(buttonOverlays[i]); } // remove the slider thumb overlays - for(var i in sliderthumbOverlays) { - Overlays.deleteOverlay(sliderthumbOverlays[i]); + for(var i in sliderThumbOverlays) { + Overlays.deleteOverlay(sliderThumbOverlays[i]); } // remove the character joint control overlays for(var i in bigButtonOverlays) { @@ -2475,15 +4238,17 @@ Script.scriptEnding.connect(function() { // remove the walk wheel overlays Overlays.deleteOverlay(walkWheelYLine); Overlays.deleteOverlay(walkWheelZLine); - Overlays.deleteOverlay(debugText); + 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) { - //print('keyPressEvent: '+event.text); - - if (event.text == "q") { + 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'); @@ -2491,19 +4256,51 @@ function keyPressEvent(event) { print('\n'); print(JSON.stringify(currentAnimation), null, '\t'); } - if (event.text == "t") { + // advanced editing + else if (event.text == "r") { + // zero out everything + //for(var i= 0 ; i < currentAnimation.joints.length ; i++) { + // currentAnimation.joints[i].pitch = 0; + // currentAnimation.joints[i].yaw = 0; + // currentAnimation.joints[i].roll = 0; + // currentAnimation.joints[i].pitchPhase = 0; + // currentAnimation.joints[i].yawPhase = 0; + // currentAnimation.joints[i].rollPhase = 0; + // currentAnimation.joints[i].pitchOffset = 0; + // currentAnimation.joints[i].yawOffset = 0; + // currentAnimation.joints[i].rollOffset = 0; + // if(i===0) { + // currentAnimation.joints[i].thrust = 0; + // currentAnimation.joints[i].sway = 0; + // currentAnimation.joints[i].bob = 0; + // } + print('...'); + //} + } + else if (event.text == "t") { statsOn = !statsOn; - if(statsOn) { - print('wheel stats on (t to turn off again)'); - Overlays.editOverlay(debugText, {visible: true}); - Overlays.editOverlay(walkWheelYLine, {visible: true}); - Overlays.editOverlay(walkWheelZLine, {visible: true}); - } else { - print('wheel stats off (t to turn on again)'); - Overlays.editOverlay(debugText, {visible: false}); - Overlays.editOverlay(walkWheelYLine, {visible: false}); - Overlays.editOverlay(walkWheelZLine, {visible: false}); - } + 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}); + } + // this is a dev tool for tweaking individual values. edit and use freely + else if (event.text == "[") { + var jointNum = 0; + var anim = currentAnimation; + var frequency = currentAnimation.settings.baseFrequency; + frequency-=5; + currentAnimation.settings.baseFrequency = frequency; + //print(anim.name+' thrustPhase is now '+anim.joints[jointNum].thrustPhase+' for the '+anim.joints[jointNum].name+' joint'); + } + else if (event.text == "]") { + var jointNum = 0; + var anim = currentAnimation; + var frequency = currentAnimation.settings.baseFrequency; + frequency+=5; + currentAnimation.settings.baseFrequency = frequency; + //print(anim.name+' bobPhase is now '+anim.joints[jointNum].thrustPhase+' for the '+anim.joints[jointNum].name+' joint'); } } Controller.keyPressEvent.connect(keyPressEvent); @@ -2513,7 +4310,6 @@ Controller.keyPressEvent.connect(keyPressEvent); // debug and other info -var VERBOSE = false; // TODO: implement joint mapping using reg expressions to cover a wide range of avi bone structures var jointList = MyAvatar.getJointNames(); @@ -2525,16 +4321,14 @@ print(jointMappings + "\n# walk.js avatar joint list end"); // 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)); - MyAvatar.clearJointData(jointList[i]); + MyAvatar.setJointData(i, Quat.fromPitchYawRollDegrees(0,0,0)); + //MyAvatar.clearJointData(jointList[i]); } +// used to position the visual representation of the walkwheel only var hipsToFeetDistance = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightFoot").y; print('\nwalk.js: Hips to feet: '+hipsToFeetDistance); -//////////////////////////////////////////// -// begin by setting the to state STANDING // -//////////////////////////////////////////// - -//curlFingers(); +// This script is designed around the Finite State Machine (FSM) +// model, so to start things up we just select the STANDING state. setInternalState(STANDING); \ No newline at end of file From 3581b0d0c3c5ab72cecf3e36726f4dbe7588dece Mon Sep 17 00:00:00 2001 From: DaveDubUK Date: Sat, 27 Sep 2014 22:47:42 +0700 Subject: [PATCH 03/40] update to 1.007b Code cleanup --- examples/walk.js | 587 +++++------------------------------------------ 1 file changed, 52 insertions(+), 535 deletions(-) diff --git a/examples/walk.js b/examples/walk.js index 17091b7f36..a9e8f401d6 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,58 +1,32 @@ // // walk.js // -// version 1.006b +// 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 // - -// Set asset paths here: - // path to the animation files -//var pathToAnimFiles = 'http://localhost/downloads/hf/scripts/animation-files/'; // loads fine (files must be present on localhost) -//var pathToAnimFiles = 'http://highfidelity.davedub.co.uk/procedural/walk/animation-files/'; // files present, but load with errors - weird -var pathToAnimFiles = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/animation-files/'; // working (but only without https) +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://localhost/downloads/hf/scripts/overlays/'; // loads fine (files must be present on localhost) -//var pathToOverlays = 'http://highfidelity.davedub.co.uk/procedural/walk/overlays/'; // files present, but won't load - weird 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/'; -//var pathToSounds = 'http://localhost/downloads/hf/sounds/Footsteps/'; - -// load all the animation datafiles -Script.include(pathToAnimFiles+"dd-female-cool-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-elderly-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-power-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-run-animation.js"); -Script.include(pathToAnimFiles+"dd-female-sexy-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-shuffle-animation.js"); -Script.include(pathToAnimFiles+"dd-female-random-walk-animation.js"); +// load the animation datafiles Script.include(pathToAnimFiles+"dd-female-strut-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-tough-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-cool-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-elderly-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-power-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-run-animation.js"); -Script.include(pathToAnimFiles+"dd-male-sexy-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-shuffle-animation.js"); -Script.include(pathToAnimFiles+"dd-male-random-walk-animation.js"); Script.include(pathToAnimFiles+"dd-male-strut-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-tough-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"); @@ -61,24 +35,8 @@ 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 FemaleCoolWalkFile = new FemaleCoolWalk(); -var femaleCoolWalk = FemaleCoolWalkFile.loadAnimation(); -var FemaleElderlyWalkFile = new FemaleElderlyWalk(); -var femaleElderlyWalk = FemaleElderlyWalkFile.loadAnimation(); -var FemalePowerWalkFile = new FemalePowerWalk(); -var femalePowerWalk = FemalePowerWalkFile.loadAnimation(); -var FemaleRunFile = new FemaleRun(); -var femaleRun = FemaleRunFile.loadAnimation(); -var FemaleSexyWalkFile = new FemaleSexyWalk(); -var femaleSexyWalk = FemaleSexyWalkFile.loadAnimation(); -var FemaleShuffleFile = new FemaleShuffle(); -var femaleShuffle = FemaleShuffleFile.loadAnimation(); -var FemaleRandomWalkFile = new FemaleRandomWalk(); -var femaleRandomWalk = FemaleRandomWalkFile.loadAnimation(); var FemaleStrutWalkFile = new FemaleStrutWalk(); var femaleStrutWalk = FemaleStrutWalkFile.loadAnimation(); -var FemaleToughWalkFile = new FemaleToughWalk(); -var femaleToughWalk = FemaleToughWalkFile.loadAnimation(); var FemaleFlyingUpFile = new FemaleFlyingUp(); var femaleFlyingUp = FemaleFlyingUpFile.loadAnimation(); var FemaleFlyingFile = new FemaleFlying(); @@ -91,24 +49,8 @@ var FemaleSideStepLeftFile = new FemaleSideStepLeft(); var femaleSideStepLeft = FemaleSideStepLeftFile.loadAnimation(); var FemaleSideStepRightFile = new FemaleSideStepRight(); var femaleSideStepRight = FemaleSideStepRightFile.loadAnimation(); -var MaleCoolWalkFile = new MaleCoolWalk(); -var maleCoolWalk = MaleCoolWalkFile.loadAnimation(); -var MaleElderlyWalkFile = new MaleElderlyWalk(); -var maleElderlyWalk = MaleElderlyWalkFile.loadAnimation(); -var MalePowerWalkFile = new MalePowerWalk(); -var malePowerWalk = MalePowerWalkFile.loadAnimation(); -var MaleRunFile = new MaleRun(); -var maleRun = MaleRunFile.loadAnimation(); -var MaleSexyWalkFile = new MaleSexyWalk(); -var maleSexyWalk = MaleSexyWalkFile.loadAnimation(); -var MaleShuffleFile = new MaleShuffle(); -var maleShuffle = MaleShuffleFile.loadAnimation(); -var MaleRandomWalkFile = new MaleRandomWalk(); -var maleRandomWalk = MaleRandomWalkFile.loadAnimation(); var MaleStrutWalkFile = new MaleStrutWalk(); var maleStrutWalk = MaleStrutWalkFile.loadAnimation(); -var MaleToughWalkFile = new MaleToughWalk(); -var maleToughWalk = MaleToughWalkFile.loadAnimation(); var MaleFlyingUpFile = new MaleFlyingUp(); var maleFlyingUp = MaleFlyingUpFile.loadAnimation(); var MaleFlyingFile = new MaleFlying(); @@ -201,7 +143,6 @@ var selectedJointIndex = 0; // the index of the joint currently selected for edi var currentTransition = null; // used as a pointer to a Transition // walkwheel (foot / ground speed matching) -//var walkCycleStart = 140; // 105 for female strut... best foot forwards - TODO: if found to be different for different anims, add as setting to anim files var sideStepCycleStartLeft = 270; var sideStepCycleStartRight = 90; var walkWheelPosition = 0; @@ -220,7 +161,6 @@ function RecentMotion(velocity, acceleration, principleDirection, state) { this.acceleration = acceleration; this.principleDirection = principleDirection; this.state = state; - // TODO: add INTERNAL_STATE so can remove 'hints' system for state changes } // constructor for the FramesHistory object @@ -231,8 +171,7 @@ function FramesHistory() { this.recentMotions.push(blank); } - // recentDirection 'method' - // args: (direction enum, number of steps back to compare) + // recentDirection 'method' args: (direction enum, number of steps back to compare) this.recentDirection = function () { if( arguments[0] && arguments[1] ) { @@ -244,15 +183,13 @@ function FramesHistory() { for(var i = 0 ; i < arguments[1] ; i++ ) { if( this.recentMotions[i].principleDirection === arguments[0] ) directionCount++; - //print('looking for '+directionAsString(arguments[0])+' directionCount '+directionCount+' count '+i+' dircetion '+directionAsString(this.recentMotions[i].principleDirection)); } return directionCount / arguments[1] === 1 ? true : false; } return false; } - // recentState 'method' - // args: (state enum, number of steps back to compare) + // recentState 'method' args: (state enum, number of steps back to compare) this.recentState = function () { if( arguments[0] && arguments[1] ) { @@ -298,8 +235,6 @@ function Transition(lastAnimation, nextAnimation, reachPoses, transitionDuration 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) - - //print('Transition initiated from '+this.lastAnimation.name+' to '+this.nextAnimation.name+' duration '+transitionDuration.toFixed(2)); } // convert a local (to the avi) translation to a global one @@ -333,8 +268,6 @@ function translateHips(localHipsTranslation) { AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviFront); AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviRight); AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviUp); - - //MyAvatar.addThrust(AviTranslationOffset * 10); MyAvatar.position = {x: MyAvatar.position.x + AviTranslationOffset.x, y: MyAvatar.position.y + AviTranslationOffset.y, z: MyAvatar.position.z + AviTranslationOffset.z }; @@ -345,10 +278,10 @@ function resetJoints() { var avatarJointNames = MyAvatar.getJointNames(); for (var i = 0; i < avatarJointNames.length; i++) { - //MyAvatar.setJointData(avatarJointNames[i], Quat.fromPitchYawRollDegrees(0,0,0)); MyAvatar.clearJointData(avatarJointNames[i]); } } + // play footstep sound function playFootstep(side) { @@ -357,11 +290,9 @@ function playFootstep(side) { options.volume = 0.5; var walkNumber = 2; // 0 to 2 if(side===DIRECTION_RIGHT && playFootStepSounds) { - //print('playing right footstep - if you can not hear sound, try turning your mic on then off again.'); Audio.playSound(footsteps[walkNumber+1], options); } else if(side===DIRECTION_LEFT && playFootStepSounds) { - //print('playing left footstep - if you can not hear sound, try turning your mic on then off again.'); Audio.playSound(footsteps[walkNumber], options); } } @@ -387,17 +318,14 @@ function curlFingers() { } } - // additional maths functions -function degToRad(degreesValue) { return degreesValue * Math.PI / 180; } -function radToDeg(radiansValue) { return radiansValue * 180 / Math.PI; } -//function cubicRoot(x) { var y = Math.pow(Math.abs(x), 1/3); return x < 0 ? -y : y; } +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) { +function animateAvatar( deltaTime, velocity, principleDirection ) { - // adjusting the walk speed in edit mode causes a nasty flicker - // pausing the animation stops this + // adjusting the walk speed in edit mode causes a nasty flicker. pausing the animation stops this if(paused) return; var cycle = cumulativeTime; @@ -441,42 +369,18 @@ function animateAvatar(deltaTime, velocity, principleDirection) { currentTransition.walkWheelIncrement = 6; // keep the walkwheel turning by setting the walkWheelIncrement until our feet are tucked nicely underneath us. - // fold back (reverse walk) if we just missed our stop target on the walkwheel when we stopped walking - depricated - //var stepIncrement = 2; // just used to set currentTransition.walkWheelIncrement in multiple locations if( angleToLeftStop < angleToRightStop ) { - //if(angleToLeftStop<270) currentTransition.walkStopAngle = rightStop; - //else if(walkWheelPosition>angleToLeftStop) currentTransition.walkStopAngle = rightStop; - //else currentTransition.walkStopAngle = leftStop; - currentTransition.walkStopAngle = leftStop; - //if( leftStop > 270 && walkWheelPosition < 90 ) currentTransition.walkWheelIncrement = -stepIncrement; - //else if( walkWheelPosition > 270 && leftStop < 90 ) currentTransition.walkWheelIncrement = stepIncrement; - //else if( walkWheelPosition < leftStop ) currentTransition.walkWheelIncrement = stepIncrement; - //else if( walkWheelPosition >= leftStop ) currentTransition.walkWheelIncrement = -stepIncrement; - //currentTransition.walkWheelIncrement = stepIncrement; - } else { - //if(angleToRightStop<270) currentTransition.walkStopAngle = leftStop; - //else if(walkWheelPosition>angleToRightStop) currentTransition.walkStopAngle = leftStop; - //else currentTransition.walkStopAngle = rightStop; currentTransition.walkStopAngle = rightStop; - - //currentTransition.walkStopAngle = rightStop; - //if( rightStop > 270 && walkWheelPosition < 90 ) currentTransition.walkWheelIncrement = -stepIncrement; - //else if( walkWheelPosition > 270 && rightStop < 90 ) currentTransition.walkWheelIncrement = stepIncrement; - //else if( walkWheelPosition < rightStop ) currentTransition.walkWheelIncrement = stepIncrement; - //else if( walkWheelPosition >= rightStop ) currentTransition.walkWheelIncrement = -stepIncrement; - //currentTransition.walkWheelIncrement = stepIncrement; } - //print('walkWheelPosition '+walkWheelPosition.toFixed(2)+' leftStop '+leftStop+' rightStop '+rightStop+' angleToLeftStop '+angleToLeftStop.toFixed(2)+' angleToRightStop '+angleToRightStop.toFixed(2)+' stop angle '+currentTransition.walkStopAngle) - } else { - // just freeze wheel for sidestepping + // freeze wheel for sidestepping transitions currentTransition.walkWheelIncrement = 0; } } @@ -500,25 +404,13 @@ function animateAvatar(deltaTime, velocity, principleDirection) { if( INTERNAL_STATE !== SIDE_STEPPING ) { // if at a stop angle, hold the walk wheel position for remainder of transition - var tolerance = 10; // must be greater than the walkWheel increment + var tolerance = 7; // must be greater than the walkWheel increment if(( walkWheelPosition > (currentTransition.walkStopAngle - tolerance )) && ( walkWheelPosition < (currentTransition.walkStopAngle + tolerance ))) { - //print('stop now? walkWheelAdvance '+currentTransition.walkWheelAdvance); - - //if( currentTransition.walkWheelAdvance < 45 ) { - - // currentTransition.walkStopAngle += 180; // not enough of a transition - keep moving... - // if( currentTransition.walkStopAngle > 360 ) currentTransition.walkStopAngle %= 360; - - // print('walkStopAngle incremented '); - //} - //else currentTransition.walkWheelIncrement = 0; } // keep turning walk wheel until both feet are below the avi - - //print('walkWheelAdvance '+currentTransition.walkWheelAdvance); walkWheelPosition += currentTransition.walkWheelIncrement; currentTransition.walkWheelAdvance += currentTransition.walkWheelIncrement; } @@ -540,8 +432,8 @@ function animateAvatar(deltaTime, velocity, principleDirection) { // 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; // 130 - var strideTwo = 220; // 300 + var strideOne = 40; + var strideTwo = 220; if( principleDirection === DIRECTION_BACKWARDS ) { strideOne = 130; @@ -556,20 +448,19 @@ function animateAvatar(deltaTime, velocity, principleDirection) { 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(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) { + } else { + + if(principleDirection===DIRECTION_FORWARDS) strideLength = currentAnimation.calibration.strideLengthForwards; - } else if (principleDirection===DIRECTION_BACKWARDS) { + else if (principleDirection===DIRECTION_BACKWARDS) strideLength = currentAnimation.calibration.strideLengthBackwards; - } } } else if(( INTERNAL_STATE===SIDE_STEPPING || @@ -588,8 +479,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { 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'); - //print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees. footRPos '+footRPos.x.toFixed(3)+' footLPos '+footLPos.x.toFixed(3)+' footOffsetX '+footOffsetX.toFixed(3)); + if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees'); currentAnimation.calibration.strideLengthLeft = strideLength; } else { @@ -606,8 +496,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { 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'); - //print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees. footRPos '+footRPos.x.toFixed(3)+' footLPos '+footLPos.x.toFixed(3)+' footOffsetX '+footOffsetX.toFixed(3)); + if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees'); currentAnimation.calibration.strideLengthRight = strideLength; } else { @@ -715,7 +604,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { 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 || @@ -727,12 +615,12 @@ function animateAvatar(deltaTime, velocity, principleDirection) { INTERNAL_STATE===CONFIG_FLYING_UP || INTERNAL_STATE===CONFIG_FLYING_DOWN ) { - // calculate hips translation TODO: get this working in normal motion! + // 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 TODO: get this working! + // apply hips translation translateHips({x:swayOscillation*currentAnimation.joints[0].sway, y:motorOscillation*currentAnimation.joints[0].thrust, z:bobOscillation*currentAnimation.joints[0].bob}); } @@ -760,7 +648,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { rollOscillationLast = (currentTransition.lastAnimation.joints[0].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[0].rollPhase)) + currentTransition.lastAnimation.joints[0].rollOffset); - } else {//if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2) + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; @@ -786,8 +674,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - //print('Hips: '+pitchOscillation+' '+yawOscillation+' '+rollOscillation); - } else { pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2) @@ -1014,7 +900,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { yawOffsetLast = currentTransition.lastAnimation.joints[3].yawOffset; rollOffsetLast = currentTransition.lastAnimation.joints[3].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } 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)); @@ -1064,9 +950,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { 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. + // 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 || @@ -1075,8 +959,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - // As luck would have it, we're using sine waves, so finding dy/dx is as - // simple as determining the cosine wave for the foot's pitch function. + // 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 && @@ -1114,7 +997,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } 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; @@ -1156,7 +1039,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees(-pitchOscillation + pitchOffset, yawOscillation, rollOscillation)); MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation, rollOscillation)); - // spine if( currentTransition !== null ) { @@ -1176,8 +1058,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { rollOscillationLast = currentTransition.lastAnimation.joints[5].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[5].rollPhase)) + currentTransition.lastAnimation.joints[5].rollOffset; - - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[5].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; @@ -1218,7 +1099,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { // apply spine joint rotations MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - // spine 1 if(currentTransition!==null) { @@ -1238,7 +1118,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[6].rollPhase)) + currentTransition.lastAnimation.joints[6].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[6].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; @@ -1298,7 +1178,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].rollPhase)) + currentTransition.lastAnimation.joints[7].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[7].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2) @@ -1380,7 +1260,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { yawOffsetLast = currentTransition.lastAnimation.joints[8].yawOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[8].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; @@ -1458,7 +1338,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { pitchOffsetLast = currentTransition.lastAnimation.joints[9].pitchOffset; yawOffsetLast = currentTransition.lastAnimation.joints[9].yawOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[9].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) @@ -1559,7 +1439,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { yawOffsetLast = currentTransition.lastAnimation.joints[10].yawOffset; rollOffsetLast = currentTransition.lastAnimation.joints[10].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[10].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) @@ -1621,9 +1501,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { rollOffset = currentAnimation.joints[10].rollOffset; } - // transitionProgress pitchOscillation yawOscillation rollOscillation - //print(transitionProgress+' '+pitchOscillation+' '+yawOscillation+' '+rollOscillation); - // apply forearms rotations MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + yawOffset, rollOscillation + rollOffset )); MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - yawOffset, rollOscillation - rollOffset )); @@ -1632,7 +1509,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { var sideStepSign = 1; if(INTERNAL_STATE===SIDE_STEPPING) { sideStepSign = 1; - } // TODO: check status of hand rotations + } if(currentTransition!==null) { if(currentTransition.walkingAtStart) { @@ -1655,7 +1532,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { rollOffset = currentAnimation.joints[11].rollOffset; rollOffsetLast = currentTransition.lastAnimation.joints[11].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } else { pitchOscillation = currentAnimation.joints[11].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) @@ -1712,7 +1589,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { } // end if(!armsFree) - // head (includes neck joint) - currently zeroed out in STANDING by request + // head (includes neck joint) - currently zeroed out in STANDING animation files by request if( currentTransition !== null ) { if(currentTransition.walkingAtStart) { @@ -1738,7 +1615,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[12].rollPhase)) + currentTransition.lastAnimation.joints[12].rollOffset; - } else { //if( currentTransition.walkingAtEnd ) { + } 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; @@ -1760,7 +1637,6 @@ function animateAvatar(deltaTime, velocity, principleDirection) { + currentTransition.lastAnimation.joints[12].rollOffset; } - // TODO: see if can animate separate heads in any way... pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); @@ -1778,7 +1654,7 @@ function animateAvatar(deltaTime, velocity, principleDirection) { -// getBezier - src: Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/ +// 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; @@ -1801,10 +1677,8 @@ function getBezier(percent,C1,C2,C3,C4) { 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; +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) { @@ -1820,46 +1694,17 @@ function filterButterworth(nextInputValue) 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) { -/* - // lean backwards when decelerating a lot. skid to a halt. working, but I don't like the effect - will use a reach pose later instead - var accelerationResponse = recentMotions[0].acceleration.z; - var accelerationResponseMax = 45; // max degrees hip pitch - - if(velocityaccelerationResponseMax) - accelerationResponse = accelerationResponseMax; - else if(accelerationResponse<-accelerationResponseMax) - accelerationResponse = -accelerationResponseMax; - // apply yet another averaging filter... - accelerationResponseAngles.push(accelerationResponse); - accelerationResponseAngles.shift(); - var finalAccelerationResponse = 0; - for(ea in accelerationResponseAngles) finalAccelerationResponse += accelerationResponseAngles[ea]; - finalAccelerationResponse /= accelerationResponseAngles.length; - - // calculate any skid for this frame and apply it - var skidDistance = -0.01 * hipsToFeetDistance * Math.sin(degToRad(finalAccelerationResponse)); - if(Math.abs(skidDistance)>0.001 && INTERNAL_STATE===STANDING) { // show skids when stopping - var skidVector = localToGlobal({ x:0, y:0, z:skidDistance }); - print('skidDistance '+skidDistance+' metres'); - MyAvatar.position = Vec3.sum(MyAvatar.position, skidVector); - } - if(Math.abs(accelerationResponse)>0) print('accelerationResponse '+accelerationResponse.toFixed(3)+' recent acceleration '+recentMotions[0].acceleration.z.toFixed(3)); -*/ 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; - //var leanProgressButterworth = filterButterworth(leanProgressBezier); // simple averaging filter seems to give best results leanAngles.push(leanProgressBezier); @@ -1926,27 +1771,22 @@ function getLeanRoll(deltaTime, velocity) { // set up the interface components, update the internal state and kick off any transitions function setInternalState(newInternalState) { - var debugShowStateChanges = false; - - switch(newInternalState) { + switch(newInternalState) { case WALKING: - if(debugShowStateChanges) print('WALKING'); if(!minimised) doStandardMenu(); INTERNAL_STATE = WALKING; return; case FLYING: - if(debugShowStateChanges) print('FLYING'); if(!minimised) doStandardMenu(); INTERNAL_STATE = FLYING; return; case SIDE_STEPPING: - if(debugShowStateChanges) print('SIDE_STEPPING'); if(!minimised) doStandardMenu(); INTERNAL_STATE = SIDE_STEPPING; return; @@ -2118,7 +1958,6 @@ function setInternalState(newInternalState) { case STANDING: default: - if(debugShowStateChanges) print('STANDING'); INTERNAL_STATE = STANDING; if(!minimised) doStandardMenu(); @@ -2138,9 +1977,8 @@ function setInternalState(newInternalState) { // 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 - a system very similar to switch debouncing in electronics design +// 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; @@ -2303,7 +2141,6 @@ Script.update.connect(function(deltaTime) { // 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 - // but for now, we have to deal with states like 'standing in the air' // maybe at walking speed, but sideways? if( actionToTake === WALKING && @@ -2361,9 +2198,9 @@ Script.update.connect(function(deltaTime) { switch(currentAnimation) { case selectedWalk: + // Walking to Standing var timeWalking = new Date().getTime() - framesHistory.lastWalkStartTime; - //print('You were walking for '+timeWalking+' mS'); var bezierCoeffsOne = {x:0.0, y:1.0}; var bezierCoeffsTwo = {x:0.0, y:1.0}; @@ -2382,7 +2219,6 @@ Script.update.connect(function(deltaTime) { case selectedSideStepLeft: case selectedSideStepRight: - //currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.3, {x:0.5,y:0.08}, {x:0.05,y:0.75}); break; default: @@ -2430,6 +2266,7 @@ Script.update.connect(function(deltaTime) { 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; @@ -2464,22 +2301,20 @@ Script.update.connect(function(deltaTime) { if( principleDirection === DIRECTION_LEFT ) { - walkWheelPosition = sideStepCycleStartLeft;//selectedSideStep.calibration.sideStepCycleStartLeft; + walkWheelPosition = sideStepCycleStartLeft; } else { - walkWheelPosition = sideStepCycleStartRight;//selectedSideStep.calibration.sideStepCycleStartRight; + walkWheelPosition = sideStepCycleStartRight; } switch(currentAnimation) { case selectedStand: - //currentTransition = new Transition(currentAnimation, selectedSideStep, [], 0.8, {x:0.5,y:0.08}, {x:0.28,y:1}); break; default: - //currentTransition = new Transition(currentAnimation, selectedSideStep, [], 0.8, {x:0.5,y:0.08}, {x:0.28,y:1}); break; } setInternalState(SIDE_STEPPING); @@ -2607,13 +2442,6 @@ Script.update.connect(function(deltaTime) { // before we go, populate the stats overlay if( statsOn ) { - // quick test for the frame execution time measurement - // lots of console logging messes up execution times pretty well! - //for(var doh = 0 ; doh < 10 ; doh++) { - // //var fake = doh * doh * doh; - // print('faking bad coding...'+doh); - //} - var cumulativeTimeMS = Math.floor(cumulativeTime*1000); var deltaTimeMS = deltaTime * 1000; var frameExecutionTime = new Date().getTime() - frameStartTime; @@ -2682,8 +2510,6 @@ var jointsControlOverlays = []; var bigButtonOverlays = []; -// take a deep breath and... - // load UI backgrounds var controlsBackground = Overlays.addOverlay("image", { bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, @@ -2730,9 +2556,6 @@ var controlsBackgroundFlyingEdit = Overlays.addOverlay("image", { }); 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, @@ -2742,8 +2565,6 @@ var controlsMinimisedTab = Overlays.addOverlay("image", { alpha: 0.9 }); - - // load character joint selection control images var hipsJointControl = Overlays.addOverlay("image", { bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, @@ -3088,8 +2909,6 @@ var configWalkTweaksButtonSelected = Overlays.addOverlay("image", { }); 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", @@ -3254,158 +3073,6 @@ var strutWalkBigButtonSelected = Overlays.addOverlay("image", { }); bigButtonOverlays.push(strutWalkBigButtonSelected); -bigButtonYOffset += 60 -var sexyWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-sexy.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(sexyWalkBigButton); - -var sexyWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-sexy-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(sexyWalkBigButtonSelected); - -bigButtonYOffset += 60; -var powerWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-power-walk.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(powerWalkBigButton); - -var powerWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-power-walk-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(powerWalkBigButtonSelected); - -bigButtonYOffset += 60; -var shuffleBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-shuffle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(shuffleBigButton); - -var shuffleBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-shuffle-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(shuffleBigButtonSelected); - -bigButtonYOffset += 60; -var runBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-run.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(runBigButton); - -var runBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-run-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(runBigButtonSelected); - -bigButtonYOffset += 60; -var randomWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-random.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(randomWalkBigButton); - -var randomWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-random-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(randomWalkBigButtonSelected); - -bigButtonYOffset += 60; -var toughWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-tough.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(toughWalkBigButton); - -var toughWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-tough-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(toughWalkBigButtonSelected); - -bigButtonYOffset += 60; -var coolWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-cool.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(coolWalkBigButton); - -var coolWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-cool-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(coolWalkBigButtonSelected); - -bigButtonYOffset += 60; -var elderlyWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-elderly.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(elderlyWalkBigButton); - -var elderlyWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-elderly-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(elderlyWalkBigButtonSelected); - // overlays to show the walk wheel stats var walkWheelZLine = Overlays.addOverlay("line3d", { position: { x: 0, y: 0, z:hipsToFeetDistance }, @@ -3675,42 +3342,10 @@ function showWalkStyleButtons(showButtons) { } // set the currently selected one - if(selectedWalk === femaleSexyWalk || selectedWalk === maleSexyWalk) { - Overlays.editOverlay(sexyWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(sexyWalkBigButton, {visible: false}); - } - else if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { + if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { Overlays.editOverlay(strutWalkBigButtonSelected, { visible: showButtons }); Overlays.editOverlay(strutWalkBigButton, {visible: false}); } - else if(selectedWalk === femalePowerWalk || selectedWalk === malePowerWalk) { - Overlays.editOverlay(powerWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(powerWalkBigButton, {visible: false}); - } - else if(selectedWalk === femaleShuffle || selectedWalk === maleShuffle) { - Overlays.editOverlay(shuffleBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(shuffleBigButton, {visible: false}); - } - else if(selectedWalk === femaleRun || selectedWalk === maleRun) { - Overlays.editOverlay(runBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(runBigButton, {visible: false}); - } - else if(selectedWalk === femaleRandomWalk || selectedWalk === maleRandomWalk) { - Overlays.editOverlay(randomWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(randomWalkBigButton, {visible: false}); - } - else if(selectedWalk === femaleToughWalk || selectedWalk === maleToughWalk) { - Overlays.editOverlay(toughWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(toughWalkBigButton, {visible: false}); - } - else if(selectedWalk === femaleCoolWalk || selectedWalk === maleCoolWalk) { - Overlays.editOverlay(coolWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(coolWalkBigButton, {visible: false}); - } - else if(selectedWalk === femaleElderlyWalk || selectedWalk === maleElderlyWalk) { - Overlays.editOverlay(elderlyWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(elderlyWalkBigButton, {visible: false}); - } } // mouse event handlers @@ -3809,70 +3444,6 @@ function mousePressEvent(event) { showWalkStyleButtons(true); return; -/* case sexyWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleSexyWalk; - else selectedWalk = maleSexyWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case powerWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femalePowerWalk; - else selectedWalk = malePowerWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case shuffleBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleShuffle; - else selectedWalk = maleShuffle; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case runBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleRun; - else selectedWalk = maleRun; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case randomWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleRandomWalk; - else selectedWalk = maleRandomWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case toughWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleToughWalk; - else selectedWalk = maleToughWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case coolWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleCoolWalk; - else selectedWalk = maleCoolWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case elderlyWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleElderlyWalk; - else selectedWalk = maleElderlyWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case sexyWalkBigButtonSelected: - case elderlyWalkBigButtonSelected: - case powerWalkBigButtonSelected: - case shuffleBigButtonSelected: - case runBigButtonSelected: - case randomWalkBigButtonSelected: - case toughWalkBigButtonSelected: - case coolWalkBigButtonSelected:*/ case strutWalkBigButtonSelected: // toggle forwards / backwards walk display @@ -4249,33 +3820,11 @@ var sideStep = 0.002; // i.e. 2mm increments whilst sidestepping - JS movement k 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 + // 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'); - } - // advanced editing - else if (event.text == "r") { - // zero out everything - //for(var i= 0 ; i < currentAnimation.joints.length ; i++) { - // currentAnimation.joints[i].pitch = 0; - // currentAnimation.joints[i].yaw = 0; - // currentAnimation.joints[i].roll = 0; - // currentAnimation.joints[i].pitchPhase = 0; - // currentAnimation.joints[i].yawPhase = 0; - // currentAnimation.joints[i].rollPhase = 0; - // currentAnimation.joints[i].pitchOffset = 0; - // currentAnimation.joints[i].yawOffset = 0; - // currentAnimation.joints[i].rollOffset = 0; - // if(i===0) { - // currentAnimation.joints[i].thrust = 0; - // currentAnimation.joints[i].sway = 0; - // currentAnimation.joints[i].bob = 0; - // } - print('...'); - //} } else if (event.text == "t") { statsOn = !statsOn; @@ -4285,50 +3834,18 @@ function keyPressEvent(event) { Overlays.editOverlay(walkWheelYLine, {visible: statsOn}); Overlays.editOverlay(walkWheelZLine, {visible: statsOn}); } - // this is a dev tool for tweaking individual values. edit and use freely - else if (event.text == "[") { - var jointNum = 0; - var anim = currentAnimation; - var frequency = currentAnimation.settings.baseFrequency; - frequency-=5; - currentAnimation.settings.baseFrequency = frequency; - //print(anim.name+' thrustPhase is now '+anim.joints[jointNum].thrustPhase+' for the '+anim.joints[jointNum].name+' joint'); - } - else if (event.text == "]") { - var jointNum = 0; - var anim = currentAnimation; - var frequency = currentAnimation.settings.baseFrequency; - frequency+=5; - currentAnimation.settings.baseFrequency = frequency; - //print(anim.name+' bobPhase is now '+anim.joints[jointNum].thrustPhase+' for the '+anim.joints[jointNum].name+' joint'); - } } Controller.keyPressEvent.connect(keyPressEvent); - - - - -// debug and other info - -// TODO: implement joint mapping using reg expressions to cover a wide range of avi bone structures +// get the list of joint names var jointList = MyAvatar.getJointNames(); -var jointMappings = "\n# Avatar joint list start"; -for (var i = 0; i < jointList.length; i++) { - jointMappings = jointMappings + "\njointIndex = " + jointList[i] + " = " + i; -} -print(jointMappings + "\n# walk.js avatar joint list end"); // 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)); - //MyAvatar.clearJointData(jointList[i]); } // used to position the visual representation of the walkwheel only var hipsToFeetDistance = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightFoot").y; -print('\nwalk.js: Hips to feet: '+hipsToFeetDistance); - -// This script is designed around the Finite State Machine (FSM) -// model, so to start things up we just select the STANDING state. +// This script is designed around the Finite State Machine (FSM) model, so to start things up we just select the STANDING state. setInternalState(STANDING); \ No newline at end of file From b2229a9a9fd0929d5128d7f0bacc2abfbcaf9eaa Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 2 Oct 2014 12:05:20 -0700 Subject: [PATCH 04/40] Update editModels.js to automatically resize new models to their naturalDimensions --- examples/editModels.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/examples/editModels.js b/examples/editModels.js index 5c426c9fb3..0532d1bc85 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1211,19 +1211,42 @@ var toolBar = (function () { Overlays.editOverlay(loadFileMenuItem, { visible: active }); } + var RESIZE_INTERVAL = 50; + var RESIZE_TIMEOUT = 20000; + var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; function addModel(url) { var position; position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getFront(MyAvatar.orientation), SPAWN_DISTANCE)); if (position.x > 0 && position.y > 0 && position.z > 0) { - Entities.addEntity({ + var entityId = Entities.addEntity({ type: "Model", position: position, dimensions: { x: DEFAULT_DIMENSION, y: DEFAULT_DIMENSION, z: DEFAULT_DIMENSION }, modelURL: url }); print("Model added: " + url); + + var checkCount = 0; + function resize() { + var entityProperties = Entities.getEntityProperties(entityId); + var naturalDimensions = entityProperties.naturalDimensions; + + if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) { + if (checkCount < RESIZE_TIMEOUT / RESIZE_INTERVAL) { + Script.setTimeout(resize, RESIZE_INTERVAL); + } else { + print("Resize failed: timed out waiting for model (" + url + ") to load"); + } + } else { + entityProperties.dimensions = naturalDimensions; + Entities.editEntity(entityId, entityProperties); + } + } + + Script.setTimeout(resize, 50); + } else { print("Can't add model: Model would be out of bounds."); } From d7f383f74a3bf3ff17ce2868b14a2a9ec4f7412a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 2 Oct 2014 12:10:20 -0700 Subject: [PATCH 05/40] Fix failure case when resizing a new model --- examples/editModels.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/editModels.js b/examples/editModels.js index 0532d1bc85..503e3a6dad 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1233,6 +1233,8 @@ var toolBar = (function () { var entityProperties = Entities.getEntityProperties(entityId); var naturalDimensions = entityProperties.naturalDimensions; + checkCount++; + if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) { if (checkCount < RESIZE_TIMEOUT / RESIZE_INTERVAL) { Script.setTimeout(resize, RESIZE_INTERVAL); From e70c57cb95a6af326c3fd8cf73934f6757aab2d5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 6 Oct 2014 08:37:07 -0700 Subject: [PATCH 06/40] Replace magic numbers wiht const values --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 503e3a6dad..820fe613c8 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1236,7 +1236,7 @@ var toolBar = (function () { checkCount++; if (naturalDimensions.x == 0 && naturalDimensions.y == 0 && naturalDimensions.z == 0) { - if (checkCount < RESIZE_TIMEOUT / RESIZE_INTERVAL) { + if (checkCount < RESIZE_MAX_CHECKS) { Script.setTimeout(resize, RESIZE_INTERVAL); } else { print("Resize failed: timed out waiting for model (" + url + ") to load"); @@ -1247,7 +1247,7 @@ var toolBar = (function () { } } - Script.setTimeout(resize, 50); + Script.setTimeout(resize, RESIZE_INTERVAL); } else { print("Can't add model: Model would be out of bounds."); From f89b225da2d8c11017ec405d72328813224723ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:17:25 -0700 Subject: [PATCH 07/40] handle local socket changes by monitoring every so often --- assignment-client/src/octree/OctreeServer.cpp | 2 +- interface/src/FileLogger.cpp | 2 +- libraries/networking/src/HifiSockAddr.cpp | 41 +++++++++---------- libraries/networking/src/HifiSockAddr.h | 2 +- libraries/networking/src/LimitedNodeList.cpp | 29 ++++++++++++- libraries/networking/src/LimitedNodeList.h | 5 +++ libraries/networking/src/NodeList.cpp | 4 +- 7 files changed, 56 insertions(+), 29 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 5833d8a764..42af8ff1b9 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -940,7 +940,7 @@ void OctreeServer::run() { qDebug("--statusHost=%s", statusHost); _statusHost = statusHost; } else { - _statusHost = QHostAddress(getHostOrderLocalAddress()).toString(); + _statusHost = getLocalAddress().toString(); } qDebug("statusHost=%s", qPrintable(_statusHost)); diff --git a/interface/src/FileLogger.cpp b/interface/src/FileLogger.cpp index cb3d43925d..4808842036 100644 --- a/interface/src/FileLogger.cpp +++ b/interface/src/FileLogger.cpp @@ -28,7 +28,7 @@ FileLogger::FileLogger(QObject* parent) : setExtraDebugging(false); _fileName = FileUtils::standardPath(LOGS_DIRECTORY); - QHostAddress clientAddress = QHostAddress(getHostOrderLocalAddress()); + QHostAddress clientAddress = getLocalAddress(); QDateTime now = QDateTime::currentDateTime(); _fileName.append(QString(FILENAME_FORMAT).arg(clientAddress.toString(), now.toString(DATETIME_FORMAT))); } diff --git a/libraries/networking/src/HifiSockAddr.cpp b/libraries/networking/src/HifiSockAddr.cpp index d30f7944d7..97e9721356 100644 --- a/libraries/networking/src/HifiSockAddr.cpp +++ b/libraries/networking/src/HifiSockAddr.cpp @@ -90,32 +90,29 @@ QDataStream& operator>>(QDataStream& dataStream, HifiSockAddr& sockAddr) { return dataStream; } -quint32 getHostOrderLocalAddress() { +QHostAddress getLocalAddress() { - static int localAddress = 0; + QHostAddress localAddress; - if (localAddress == 0) { - foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { - if (networkInterface.flags() & QNetworkInterface::IsUp - && networkInterface.flags() & QNetworkInterface::IsRunning - && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { - // we've decided that this is the active NIC - // enumerate it's addresses to grab the IPv4 address - foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { - // make sure it's an IPv4 address that isn't the loopback - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { - qDebug("Node's local address is %s", entry.ip().toString().toLocal8Bit().constData()); - - // set our localAddress and break out - localAddress = entry.ip().toIPv4Address(); - break; - } + foreach(const QNetworkInterface &networkInterface, QNetworkInterface::allInterfaces()) { + if (networkInterface.flags() & QNetworkInterface::IsUp + && networkInterface.flags() & QNetworkInterface::IsRunning + && networkInterface.flags() & ~QNetworkInterface::IsLoopBack) { + // we've decided that this is the active NIC + // enumerate it's addresses to grab the IPv4 address + foreach(const QNetworkAddressEntry &entry, networkInterface.addressEntries()) { + // make sure it's an IPv4 address that isn't the loopback + if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) { + + // set our localAddress and break out + localAddress = entry.ip(); + break; } } - - if (localAddress != 0) { - break; - } + } + + if (!localAddress.isNull()) { + break; } } diff --git a/libraries/networking/src/HifiSockAddr.h b/libraries/networking/src/HifiSockAddr.h index 8a591a60b8..42f815390a 100644 --- a/libraries/networking/src/HifiSockAddr.h +++ b/libraries/networking/src/HifiSockAddr.h @@ -58,7 +58,7 @@ private: uint qHash(const HifiSockAddr& key, uint seed); -quint32 getHostOrderLocalAddress(); +QHostAddress getLocalAddress(); Q_DECLARE_METATYPE(HifiSockAddr) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 507788009a..a428f1f495 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -70,6 +70,7 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _nodeHashMutex(QMutex::Recursive), _nodeSocket(this), _dtlsSocket(NULL), + _localSockAddr(), _publicSockAddr(), _numCollectedPackets(0), _numCollectedBytes(0), @@ -89,6 +90,15 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short const int LARGER_BUFFER_SIZE = 1048576; changeSocketBufferSizes(LARGER_BUFFER_SIZE); + // check for local socket updates every so often + const int LOCAL_SOCKET_UPDATE_INTERVAL_MSECS = 5 * 1000; + QTimer* localSocketUpdate = new QTimer(this); + connect(localSocketUpdate, &QTimer::timeout, this, &LimitedNodeList::updateLocalSockAddr); + localSocketUpdate->start(LOCAL_SOCKET_UPDATE_INTERVAL_MSECS); + + // check the local socket right now + updateLocalSockAddr(); + _packetStatTimer.start(); } @@ -652,6 +662,23 @@ bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { return false; } +void LimitedNodeList::updateLocalSockAddr() { + HifiSockAddr newSockAddr(getLocalAddress(), _nodeSocket.localPort()); + if (newSockAddr != _localSockAddr) { + + if (_localSockAddr.isNull()) { + qDebug() << "Local socket is" << newSockAddr; + } else { + qDebug() << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr; + } + + + _localSockAddr = newSockAddr; + + emit localSockAddrChanged(_localSockAddr); + } +} + void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr, QUuid headerID, const QUuid& connectionRequestID) { @@ -662,7 +689,7 @@ void LimitedNodeList::sendHeartbeatToIceServer(const HifiSockAddr& iceServerSock QByteArray iceRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeIceServerHeartbeat, headerID); QDataStream iceDataStream(&iceRequestByteArray, QIODevice::Append); - iceDataStream << _publicSockAddr << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()); + iceDataStream << _publicSockAddr << _localSockAddr; if (!connectionRequestID.isNull()) { iceDataStream << connectionRequestID; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a7ffc7ec28..1b30375fad 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -127,11 +127,15 @@ public slots: void removeSilentNodes(); + void updateLocalSockAddr(); + void killNodeWithUUID(const QUuid& nodeUUID); signals: void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID); void nodeAdded(SharedNodePointer); void nodeKilled(SharedNodePointer); + + void localSockAddrChanged(const HifiSockAddr& localSockAddr); void publicSockAddrChanged(const HifiSockAddr& publicSockAddr); protected: static std::auto_ptr _sharedInstance; @@ -153,6 +157,7 @@ protected: QMutex _nodeHashMutex; QUdpSocket _nodeSocket; QUdpSocket* _dtlsSocket; + HifiSockAddr _localSockAddr; HifiSockAddr _publicSockAddr; int _numCollectedPackets; int _numCollectedBytes; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 905fc06eeb..cac4071fb2 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -302,9 +302,7 @@ void NodeList::sendDomainServerCheckIn() { QDataStream packetStream(&domainServerPacket, QIODevice::Append); // pack our data to send to the domain-server - packetStream << _ownerType << _publicSockAddr - << HifiSockAddr(QHostAddress(getHostOrderLocalAddress()), _nodeSocket.localPort()) - << (quint8) _nodeTypesOfInterest.size(); + packetStream << _ownerType << _publicSockAddr << _localSockAddr << (quint8) _nodeTypesOfInterest.size(); // copy over the bytes for node types of interest, if required foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) { From b61e659382001fa474b9c1efd88b1a4c66fc147e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:18:50 -0700 Subject: [PATCH 08/40] send an ICE heartbeat anytime the domain-server local socket changes --- domain-server/src/DomainServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 61310cad75..cceb55ab62 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -357,7 +357,8 @@ void DomainServer::setupAutomaticNetworking() { connect(iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::performICEUpdates); iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); - // call our sendHeartbeaToIceServer immediately anytime a public address changes + // call our sendHeartbeaToIceServer immediately anytime a local or public socket changes + connect(nodeList, &LimitedNodeList::localSockAddrChanged, this &DomainServer::sendHearbeatToIceServer); connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); // tell the data server which type of automatic networking we are using From 0459254e3f705f1449b1e90a4c142411e879c2bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:24:48 -0700 Subject: [PATCH 09/40] fix connection to slot for local addr update, refresh AcctManager after restart --- domain-server/src/DomainServer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index cceb55ab62..232348e05a 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -57,6 +57,11 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); + + // make sure we have a fresh AccountManager instance + // (need this since domain-server can restart itself and maintain static variables) + AccountManager::getInstance(true); + _settingsManager.setupConfigMap(arguments()); installNativeEventFilter(&_shutdownEventListener); @@ -82,10 +87,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : void DomainServer::restart() { qDebug() << "domain-server is restarting."; - // make sure all static instances are reset - LimitedNodeList::getInstance()->reset(); - AccountManager::getInstance(true); - exit(DomainServer::EXIT_CODE_REBOOT); } @@ -358,7 +359,7 @@ void DomainServer::setupAutomaticNetworking() { iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); // call our sendHeartbeaToIceServer immediately anytime a local or public socket changes - connect(nodeList, &LimitedNodeList::localSockAddrChanged, this &DomainServer::sendHearbeatToIceServer); + connect(nodeList, &LimitedNodeList::localSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); connect(nodeList, &LimitedNodeList::publicSockAddrChanged, this, &DomainServer::sendHearbeatToIceServer); // tell the data server which type of automatic networking we are using From 89cc7c7b0d4593c13715b15b8a5e22e6c1f4d7a8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:35:44 -0700 Subject: [PATCH 10/40] add an optional forced reset of NetworkAccessManager --- domain-server/src/DomainServer.cpp | 2 ++ libraries/networking/src/NetworkAccessManager.cpp | 5 +++-- libraries/networking/src/NetworkAccessManager.h | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 232348e05a..5a8f8fb40e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -57,6 +57,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); + // force a refresh of the NetworkAccessManager instance for this thread + NetworkAccessManager::getInstance(true); // make sure we have a fresh AccountManager instance // (need this since domain-server can restart itself and maintain static variables) diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index e92760d303..6e2580f51e 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -15,8 +15,8 @@ QThreadStorage networkAccessManagers; -NetworkAccessManager& NetworkAccessManager::getInstance() { - if (!networkAccessManagers.hasLocalData()) { +NetworkAccessManager& NetworkAccessManager::getInstance(bool forceReset) { + if (!networkAccessManagers.hasLocalData() || forceReset) { networkAccessManagers.setLocalData(new NetworkAccessManager()); } @@ -24,4 +24,5 @@ NetworkAccessManager& NetworkAccessManager::getInstance() { } NetworkAccessManager::NetworkAccessManager() { + } diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index 9594170518..6636a0eae6 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -18,7 +18,7 @@ class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: - static NetworkAccessManager& getInstance(); + static NetworkAccessManager& getInstance(bool forceReset = false); private: NetworkAccessManager(); From a441c5fb166ed3902dd17080b073204a9db59d83 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:42:47 -0700 Subject: [PATCH 11/40] don't use an unecessary subclass of QNetworkAccessManager --- libraries/networking/src/NetworkAccessManager.cpp | 10 +++------- libraries/networking/src/NetworkAccessManager.h | 7 ++----- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index 6e2580f51e..161170a87d 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -13,16 +13,12 @@ #include "NetworkAccessManager.h" -QThreadStorage networkAccessManagers; +QThreadStorage networkAccessManagers; -NetworkAccessManager& NetworkAccessManager::getInstance(bool forceReset) { +QNetworkAccessManager& NetworkAccessManager::getInstance(bool forceReset) { if (!networkAccessManagers.hasLocalData() || forceReset) { - networkAccessManagers.setLocalData(new NetworkAccessManager()); + networkAccessManagers.setLocalData(new QNetworkAccessManager()); } return *networkAccessManagers.localData(); } - -NetworkAccessManager::NetworkAccessManager() { - -} diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index 6636a0eae6..3a236f7041 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -15,13 +15,10 @@ #include /// Wrapper around QNetworkAccessManager to restrict at one instance by thread -class NetworkAccessManager : public QNetworkAccessManager { +class NetworkAccessManager : public QObject { Q_OBJECT public: - static NetworkAccessManager& getInstance(bool forceReset = false); - -private: - NetworkAccessManager(); + static QNetworkAccessManager& getInstance(bool forceReset = false); }; #endif // hifi_NetworkAccessManager_h \ No newline at end of file From 78f8aba504b9f9eca90509a75a604c4897c32c0f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:44:47 -0700 Subject: [PATCH 12/40] fix for NetworkAccessManager getInstance return --- libraries/networking/src/AccountManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 7d924d02de..bb471442ea 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -187,7 +187,7 @@ void AccountManager::invokedRequest(const QString& path, const JSONCallbackParameters& callbackParams, const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; @@ -359,7 +359,7 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) void AccountManager::requestAccessToken(const QString& login, const QString& password) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request; @@ -431,7 +431,7 @@ void AccountManager::requestAccessTokenError(QNetworkReply::NetworkError error) } void AccountManager::requestProfile() { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QUrl profileURL = _authURL; profileURL.setPath("/api/v1/users/profile"); From 484c0d30cb92d9794d9bac6837fe2d33b52a8282 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 09:54:52 -0700 Subject: [PATCH 13/40] don't require refresh of NetworkAccessManager, should handle restarts --- domain-server/src/DomainServer.cpp | 3 --- libraries/networking/src/NetworkAccessManager.cpp | 6 +++--- libraries/networking/src/NetworkAccessManager.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 5a8f8fb40e..7352729fa4 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -57,9 +57,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); - // force a refresh of the NetworkAccessManager instance for this thread - NetworkAccessManager::getInstance(true); - // make sure we have a fresh AccountManager instance // (need this since domain-server can restart itself and maintain static variables) AccountManager::getInstance(true); diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index 161170a87d..841b7491c7 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -15,9 +15,9 @@ QThreadStorage networkAccessManagers; -QNetworkAccessManager& NetworkAccessManager::getInstance(bool forceReset) { - if (!networkAccessManagers.hasLocalData() || forceReset) { - networkAccessManagers.setLocalData(new QNetworkAccessManager()); +QNetworkAccessManager& NetworkAccessManager::getInstance() { + if (!networkAccessManagers.hasLocalData()) { + networkAccessManagers.setLocalData(new QNetworkAccessManager()); } return *networkAccessManagers.localData(); diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index 3a236f7041..d911d935dc 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -18,7 +18,7 @@ class NetworkAccessManager : public QObject { Q_OBJECT public: - static QNetworkAccessManager& getInstance(bool forceReset = false); + static QNetworkAccessManager& getInstance(); }; #endif // hifi_NetworkAccessManager_h \ No newline at end of file From 253fe53571d67df7fd00b208c7c02528a47dd14c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 10:40:56 -0700 Subject: [PATCH 14/40] cleanup a couple of debug lines --- domain-server/src/DomainServer.cpp | 1 + libraries/networking/src/DomainHandler.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7352729fa4..b95756f5f0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -957,6 +957,7 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) { } void DomainServer::requestCurrentPublicSocketViaSTUN() { + qDebug() << "Sending STUN request to retrieve public socket information."; LimitedNodeList::getInstance()->sendSTUNRequest(); } diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 5714e6923d..760c9f4c04 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -90,7 +90,7 @@ void DomainHandler::setSockAddr(const HifiSockAddr& sockAddr, const QString& hos void DomainHandler::setUUID(const QUuid& uuid) { if (uuid != _uuid) { _uuid = uuid; - qDebug() << "Domain uuid changed to" << uuidStringWithoutCurlyBraces(_uuid); + qDebug() << "Domain ID changed to" << uuidStringWithoutCurlyBraces(_uuid); } } From 319cf34b837e9fc88202ed1be5387e7faa9bdcb1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 12:23:49 -0700 Subject: [PATCH 15/40] use an ephemeral port when using auto-networking for domain-server --- domain-server/src/DomainServer.cpp | 18 +++++++++++------- libraries/networking/src/LimitedNodeList.cpp | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b95756f5f0..ce2a3b0052 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -189,6 +189,11 @@ bool DomainServer::optionallySetupOAuth() { const QString DOMAIN_CONFIG_ID_KEY = "id"; +const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; +const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; +const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; +const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; + void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { const QString CUSTOM_PORT_OPTION = "port"; @@ -196,7 +201,12 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { QVariantMap& settingsMap = _settingsManager.getSettingsMap(); - if (settingsMap.contains(CUSTOM_PORT_OPTION)) { + QVariant autoNetworkingValue = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH); + + if (!autoNetworkingValue.isNull() && autoNetworkingValue.toString() == FULL_AUTOMATIC_NETWORKING_VALUE) { + // when using full networking use an ephemeral port + domainServerPort = 0; + } else if (settingsMap.contains(CUSTOM_PORT_OPTION)) { domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt(); } @@ -310,12 +320,7 @@ bool DomainServer::optionallySetupAssignmentPayment() { return true; } -const QString FULL_AUTOMATIC_NETWORKING_VALUE = "full"; -const QString IP_ONLY_AUTOMATIC_NETWORKING_VALUE = "ip"; -const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; - void DomainServer::setupAutomaticNetworking() { - const QString METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH = "metaverse.automatic_networking"; if (!didSetupAccountManagerWithAccessToken()) { qDebug() << "Cannot setup domain-server automatic networking without an access token."; @@ -957,7 +962,6 @@ void DomainServer::transactionJSONCallback(const QJsonObject& data) { } void DomainServer::requestCurrentPublicSocketViaSTUN() { - qDebug() << "Sending STUN request to retrieve public socket information."; LimitedNodeList::getInstance()->sendSTUNRequest(); } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index a428f1f495..d7c8f4bd12 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -580,7 +580,7 @@ void LimitedNodeList::sendSTUNRequest() { memcpy(stunRequestPacket + packetIndex, randomUUID.toRfc4122().data(), NUM_TRANSACTION_ID_BYTES); // lookup the IP for the STUN server - static HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); + HifiSockAddr stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT); _nodeSocket.writeDatagram((char*) stunRequestPacket, sizeof(stunRequestPacket), stunSockAddr.getAddress(), stunSockAddr.getPort()); From 3cd71a33c921c8d409ad7dfcd4fb1e2511460d09 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 12:28:44 -0700 Subject: [PATCH 16/40] disable ephemeral port for DS until ACs can discover --- domain-server/src/DomainServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ce2a3b0052..6b2faffe01 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -204,8 +204,8 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { QVariant autoNetworkingValue = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH); if (!autoNetworkingValue.isNull() && autoNetworkingValue.toString() == FULL_AUTOMATIC_NETWORKING_VALUE) { - // when using full networking use an ephemeral port - domainServerPort = 0; + // when using full networking use an ephemeral port - disabled until nodes can find us this way + // domainServerPort = 0; } else if (settingsMap.contains(CUSTOM_PORT_OPTION)) { domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt(); } From 0fd7ec34fc5323180fb7437b22d337d17d2764e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 12:34:12 -0700 Subject: [PATCH 17/40] remove an unused const --- assignment-client/src/audio/AudioMixer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 681cc58cb3..37d89f3790 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -364,7 +364,6 @@ int AudioMixer::addStreamToMixForListeningNodeWithStream(AudioMixerClientData* l const float ZERO_DB = 1.0f; const float NEGATIVE_ONE_DB = 0.891f; const float NEGATIVE_THREE_DB = 0.708f; - const float NEGATIVE_SIX_DB = 0.501f; const float FILTER_GAIN_AT_0 = ZERO_DB; // source is in front const float FILTER_GAIN_AT_90 = NEGATIVE_ONE_DB; // source is incident to left or right ear From 1de473a01324ca47354c309105f67c231eedca7f Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Mon, 6 Oct 2014 14:27:25 -0600 Subject: [PATCH 18/40] Fixing globals var scopt --- examples/libraries/globals.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/libraries/globals.js b/examples/libraries/globals.js index 211e0d56b6..1bd851af77 100644 --- a/examples/libraries/globals.js +++ b/examples/libraries/globals.js @@ -8,4 +8,4 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var HIFI_PUBLIC_BUCKET = "https://s3.amazonaws.com/hifi-public/"; \ No newline at end of file +HIFI_PUBLIC_BUCKET = "https://s3.amazonaws.com/hifi-public/"; From 499e748d54b062f20ef6b893c00aa645db9a316f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 13:45:11 -0700 Subject: [PATCH 19/40] rebind the node socket when switching to ThreadedAssignment --- libraries/networking/src/LimitedNodeList.cpp | 7 +++++++ libraries/networking/src/LimitedNodeList.h | 2 ++ libraries/networking/src/ThreadedAssignment.cpp | 3 +++ 3 files changed, 12 insertions(+) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 507788009a..0279c9b697 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -576,6 +576,13 @@ void LimitedNodeList::sendSTUNRequest() { stunSockAddr.getAddress(), stunSockAddr.getPort()); } +void LimitedNodeList::rebindNodeSocket() { + quint16 oldPort = _nodeSocket.localPort(); + + _nodeSocket.close(); + _nodeSocket.bind(QHostAddress::AnyIPv4, oldPort); +} + bool LimitedNodeList::processSTUNResponse(const QByteArray& packet) { // check the cookie to make sure this is actually a STUN response // and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index a7ffc7ec28..406b851d0e 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -69,6 +69,8 @@ public: const QUuid& getSessionUUID() const { return _sessionUUID; } void setSessionUUID(const QUuid& sessionUUID); + + void rebindNodeSocket(); QUdpSocket& getNodeSocket() { return _nodeSocket; } QUdpSocket& getDTLSSocket(); diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index cd80c441c1..6d2e366499 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -59,6 +59,9 @@ void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeTy NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(nodeType); + // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread + nodeList->rebindNodeSocket(); + QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); From 08147380c71444950ab2b08c49a49c018dccbb18 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 6 Oct 2014 14:09:23 -0700 Subject: [PATCH 20/40] Fix property names used for text overlay colors --- examples/overlaysExample.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/overlaysExample.js b/examples/overlaysExample.js index 2161b1c903..fef502c761 100644 --- a/examples/overlaysExample.js +++ b/examples/overlaysExample.js @@ -64,8 +64,8 @@ var text = Overlays.addOverlay("text", { y: 100, width: 150, height: 50, - color: { red: 0, green: 0, blue: 0}, - textColor: { red: 255, green: 0, blue: 0}, + backgroundColor: { red: 255, green: 255, blue: 255}, + color: { red: 255, green: 0, blue: 0}, topMargin: 4, leftMargin: 4, text: "Here is some text.\nAnd a second line." From 12deec928c002c5ec01af00ff65b7de5390fb5b9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 Oct 2014 14:15:22 -0700 Subject: [PATCH 21/40] add tick marks to planar ellipse/circle overlays --- examples/libraries/entitySelectionTool.js | 23 +++- interface/src/ui/overlays/Circle3DOverlay.cpp | 118 +++++++++++++++++- interface/src/ui/overlays/Circle3DOverlay.h | 21 ++++ 3 files changed, 157 insertions(+), 5 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index e07fb752e5..d9cf2c54fd 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -169,7 +169,14 @@ SelectionDisplay = (function () { alpha: 0.2, solid: true, visible: false, - rotation: yawOverlayRotation + rotation: yawOverlayRotation, + hasTickMarks: true, + majorTickMarksAngle: 12.5, + minorTickMarksAngle: 0, + majorTickMarksLength: -0.25, + minorTickMarksLength: 0, + majorTickMarksColor: { red: 0, green: 0, blue: 0 }, + minorTickMarksColor: { red: 0, green: 0, blue: 0 }, }); var rotateOverlayOuter = Overlays.addOverlay("circle3d", { @@ -179,7 +186,15 @@ SelectionDisplay = (function () { alpha: 0.2, solid: true, visible: false, - rotation: yawOverlayRotation + rotation: yawOverlayRotation, + + hasTickMarks: true, + majorTickMarksAngle: 45.0, + minorTickMarksAngle: 5, + majorTickMarksLength: 0.25, + minorTickMarksLength: 0.1, + majorTickMarksColor: { red: 0, green: 0, blue: 0 }, + minorTickMarksColor: { red: 0, green: 0, blue: 0 }, }); var rotateOverlayCurrent = Overlays.addOverlay("circle3d", { @@ -571,7 +586,7 @@ SelectionDisplay = (function () { innerRadius: 0.9, startAt: 0, endAt: 360, - alpha: outerAlpha + alpha: outerAlpha, }); Overlays.editOverlay(rotateOverlayCurrent, @@ -584,7 +599,7 @@ SelectionDisplay = (function () { size: outerRadius, startAt: 0, endAt: 0, - innerRadius: 0.9 + innerRadius: 0.9, }); // TODO: we have not implemented the rotating handle/controls yet... so for now, these handles are hidden diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index cecec29130..6ff256d48e 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -21,8 +21,15 @@ Circle3DOverlay::Circle3DOverlay() : _startAt(0.0f), _endAt(360.0f), _outerRadius(1.0f), - _innerRadius(0.0f) + _innerRadius(0.0f), + _hasTickMarks(false), + _majorTickMarksAngle(0.0f), + _minorTickMarksAngle(0.0f), + _majorTickMarksLength(0.0f), + _minorTickMarksLength(0.0f) { + _majorTickMarksColor.red = _majorTickMarksColor.green = _majorTickMarksColor.blue = (unsigned char)0; + _minorTickMarksColor.red = _minorTickMarksColor.green = _minorTickMarksColor.blue = (unsigned char)0; } Circle3DOverlay::~Circle3DOverlay() { @@ -142,6 +149,66 @@ void Circle3DOverlay::render() { glVertex2f(lastOuterPoint.x, lastOuterPoint.y); glEnd(); } + + // draw our tick marks + // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise + // we just draw a line... + if (getHasTickMarks()) { + glBegin(GL_LINES); + + // draw our major tick marks + if (getMajorTickMarksAngle() > 0.0f && getMajorTickMarksLength() != 0.0f) { + + xColor color = getMajorTickMarksColor(); + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + float angle = startAt; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMajorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); + glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); + + glVertex2f(thisPointA.x, thisPointA.y); + glVertex2f(thisPointB.x, thisPointB.y); + + angle += getMajorTickMarksAngle(); + } + } + + // draw our minor tick marks + if (getMinorTickMarksAngle() > 0.0f && getMinorTickMarksLength() != 0.0f) { + + xColor color = getMinorTickMarksColor(); + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + float angle = startAt; + float angleInRadians = glm::radians(angle); + float tickMarkLength = getMinorTickMarksLength(); + float startRadius = (tickMarkLength > 0.0f) ? innerRadius : outerRadius; + float endRadius = startRadius + tickMarkLength; + + while (angle <= endAt) { + angleInRadians = glm::radians(angle); + + glm::vec2 thisPointA(cos(angleInRadians) * startRadius, sin(angleInRadians) * startRadius); + glm::vec2 thisPointB(cos(angleInRadians) * endRadius, sin(angleInRadians) * endRadius); + + glVertex2f(thisPointA.x, thisPointA.y); + glVertex2f(thisPointB.x, thisPointB.y); + + angle += getMinorTickMarksAngle(); + } + } + + glEnd(); + } + glPopMatrix(); glPopMatrix(); @@ -173,6 +240,55 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) { if (innerRadius.isValid()) { setInnerRadius(innerRadius.toVariant().toFloat()); } + + QScriptValue hasTickMarks = properties.property("hasTickMarks"); + if (hasTickMarks.isValid()) { + setHasTickMarks(hasTickMarks.toVariant().toBool()); + } + + QScriptValue majorTickMarksAngle = properties.property("majorTickMarksAngle"); + if (majorTickMarksAngle.isValid()) { + setMajorTickMarksAngle(majorTickMarksAngle.toVariant().toFloat()); + } + + QScriptValue minorTickMarksAngle = properties.property("minorTickMarksAngle"); + if (minorTickMarksAngle.isValid()) { + setMinorTickMarksAngle(minorTickMarksAngle.toVariant().toFloat()); + } + + QScriptValue majorTickMarksLength = properties.property("majorTickMarksLength"); + if (majorTickMarksLength.isValid()) { + setMajorTickMarksLength(majorTickMarksLength.toVariant().toFloat()); + } + + QScriptValue minorTickMarksLength = properties.property("minorTickMarksLength"); + if (minorTickMarksLength.isValid()) { + setMinorTickMarksLength(minorTickMarksLength.toVariant().toFloat()); + } + + QScriptValue majorTickMarksColor = properties.property("majorTickMarksColor"); + if (majorTickMarksColor.isValid()) { + QScriptValue red = majorTickMarksColor.property("red"); + QScriptValue green = majorTickMarksColor.property("green"); + QScriptValue blue = majorTickMarksColor.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + _majorTickMarksColor.red = red.toVariant().toInt(); + _majorTickMarksColor.green = green.toVariant().toInt(); + _majorTickMarksColor.blue = blue.toVariant().toInt(); + } + } + + QScriptValue minorTickMarksColor = properties.property("minorTickMarksColor"); + if (minorTickMarksColor.isValid()) { + QScriptValue red = minorTickMarksColor.property("red"); + QScriptValue green = minorTickMarksColor.property("green"); + QScriptValue blue = minorTickMarksColor.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + _minorTickMarksColor.red = red.toVariant().toInt(); + _minorTickMarksColor.green = green.toVariant().toInt(); + _minorTickMarksColor.blue = blue.toVariant().toInt(); + } + } } diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index cea9db0384..791d951105 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -26,17 +26,38 @@ public: float getEndAt() const { return _endAt; } float getOuterRadius() const { return _outerRadius; } float getInnerRadius() const { return _innerRadius; } + bool getHasTickMarks() const { return _hasTickMarks; } + float getMajorTickMarksAngle() const { return _majorTickMarksAngle; } + float getMinorTickMarksAngle() const { return _minorTickMarksAngle; } + float getMajorTickMarksLength() const { return _majorTickMarksLength; } + float getMinorTickMarksLength() const { return _minorTickMarksLength; } + xColor getMajorTickMarksColor() const { return _majorTickMarksColor; } + xColor getMinorTickMarksColor() const { return _minorTickMarksColor; } void setStartAt(float value) { _startAt = value; } void setEndAt(float value) { _endAt = value; } void setOuterRadius(float value) { _outerRadius = value; } void setInnerRadius(float value) { _innerRadius = value; } + void setHasTickMarks(bool value) { _hasTickMarks = value; } + void setMajorTickMarksAngle(float value) { _majorTickMarksAngle = value; } + void setMinorTickMarksAngle(float value) { _minorTickMarksAngle = value; } + void setMajorTickMarksLength(float value) { _majorTickMarksLength = value; } + void setMinorTickMarksLength(float value) { _minorTickMarksLength = value; } + void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; } + void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; } protected: float _startAt; float _endAt; float _outerRadius; float _innerRadius; + bool _hasTickMarks; + float _majorTickMarksAngle; + float _minorTickMarksAngle; + float _majorTickMarksLength; + float _minorTickMarksLength; + xColor _majorTickMarksColor; + xColor _minorTickMarksColor; }; From 65b559ca3d4fdb2877fe5912f35e930ea9faceb2 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Mon, 6 Oct 2014 15:21:51 -0600 Subject: [PATCH 22/40] Missed one --- interface/src/ui/ModelsBrowser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 9ff839256d..0f89c44d23 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -26,7 +26,7 @@ const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "attachments" }; -static const QString S3_URL = "http://highfidelity-public.s3-us-west-1.amazonaws.com"; +static const QString S3_URL = "https://s3.amazonaws.com/hifi-public"; static const QString PUBLIC_URL = "http://public.highfidelity.io"; static const QString MODELS_LOCATION = "models/"; From 6aba2359ed0646d77a2b5cec0320b4de8242d46f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Oct 2014 14:27:43 -0700 Subject: [PATCH 23/40] Tweak low velocity avatar keyboard control. --- interface/src/avatar/MyAvatar.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index a31c25b572..469df6066d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -49,8 +49,8 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; -const float MIN_KEYBOARD_CONTROL_SPEED = 1.5f; -const float MAX_WALKING_SPEED = 3.0f * MIN_KEYBOARD_CONTROL_SPEED; +const float MIN_KEYBOARD_CONTROL_SPEED = 0.75f; +const float MAX_WALKING_SPEED = 4.5f; // TODO: normalize avatar speed for standard avatar size, then scale all motion logic // to properly follow avatar size. @@ -1262,21 +1262,19 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe // Compute the target keyboard velocity (which ramps up slowly, and damps very quickly) // the max magnitude of which depends on what we're doing: - float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED; float motorLength = glm::length(_keyboardMotorVelocity); + float finalMaxMotorSpeed = hasFloor ? _scale * MAX_WALKING_SPEED : _scale * MAX_KEYBOARD_MOTOR_SPEED; + float speedGrowthTimescale = 2.0f; + float speedIncreaseFactor = 1.8f; + motorLength *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) { // an active keyboard motor should never be slower than this - _keyboardMotorVelocity = _scale * MIN_KEYBOARD_CONTROL_SPEED * direction; + motorLength = _scale * MIN_KEYBOARD_CONTROL_SPEED; motorEfficiency = 1.0f; - } else { - float KEYBOARD_MOTOR_LENGTH_TIMESCALE = 2.0f; - float INCREASE_FACTOR = 1.8f; - motorLength *= 1.0f + glm::clamp(deltaTime / KEYBOARD_MOTOR_LENGTH_TIMESCALE, 0.0f, 1.0f) * INCREASE_FACTOR; - if (motorLength > finalMaxMotorSpeed) { - motorLength = finalMaxMotorSpeed; - } - _keyboardMotorVelocity = motorLength * direction; + } else if (motorLength > finalMaxMotorSpeed) { + motorLength = finalMaxMotorSpeed; } + _keyboardMotorVelocity = motorLength * direction; _isPushing = true; } } else { From 07832fdd686911df1c4b5a94689f6e02d724c773 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 6 Oct 2014 14:34:19 -0700 Subject: [PATCH 24/40] fix include for https relative urls --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 47e0ced6bf..f45ae19939 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -681,7 +681,7 @@ void ScriptEngine::include(const QString& includeFile) { QUrl url = resolveInclude(includeFile); QString includeContents; - if (url.scheme() == "http" || url.scheme() == "ftp") { + if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << includeFile; From 14cd04435905630b41d51d66b02d9b000ec9bfcf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 14:41:16 -0700 Subject: [PATCH 25/40] handle custom local UDP port for domain-server from webpage --- domain-server/resources/describe-settings.json | 8 ++++++++ domain-server/resources/web/js/settings.js | 5 +++++ domain-server/src/DomainServerSettingsManager.cpp | 3 +++ 3 files changed, 16 insertions(+) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 2fbe33a4e1..cadbc4d2c8 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -33,6 +33,14 @@ "label": "None: use the network information I have entered for this domain at data.highfidelity.io" } ] + }, + { + "name": "port", + "label": "Local UDP Port", + "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.", + "default": "40102", + "type": "int", + "advanced": true } ] }, diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 48b3b15e8f..5c3dfdd6dd 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -46,6 +46,11 @@ var viewHelpers = { form_group += "" } else { + + if (input_type == 'integer') { + input_type = "text" + } + form_group += "" diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 28b1151f2d..7c92f1cc51 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -254,11 +254,14 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ QString settingType = groupObject[SETTING_DESCRIPTION_TYPE_KEY].toString(); const QString INPUT_DOUBLE_TYPE = "double"; + const QString INPUT_INTEGER_TYPE = "int"; // make sure the resulting json value has the right type if (settingType == INPUT_DOUBLE_TYPE) { settingsVariant[key] = rootValue.toString().toDouble(); + } else if (settingType == INPUT_INTEGER_TYPE) { + settingsVariant[key] = rootValue.toString().toInt(); } else { settingsVariant[key] = rootValue.toString(); } From 78920234bbf51495b211d43c6e052033de785d42 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 14:49:15 -0700 Subject: [PATCH 26/40] handle changed domain-server port on start --- domain-server/resources/describe-settings.json | 2 +- domain-server/src/DomainServer.cpp | 15 ++++----------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index cadbc4d2c8..568931e074 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -35,7 +35,7 @@ ] }, { - "name": "port", + "name": "local_port", "label": "Local UDP Port", "help": "This is the local port your domain-server binds to for UDP connections.
Depending on your router, this may need to be changed to run multiple full automatic networking domain-servers in the same network.", "default": "40102", diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 6b2faffe01..fa7a0fe012 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -196,20 +196,13 @@ const QString DISABLED_AUTOMATIC_NETWORKING_VALUE = "disabled"; void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { - const QString CUSTOM_PORT_OPTION = "port"; - unsigned short domainServerPort = DEFAULT_DOMAIN_SERVER_PORT; + const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; + + QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); + unsigned short domainServerPort = (unsigned short) localPortValue.toUInt(); QVariantMap& settingsMap = _settingsManager.getSettingsMap(); - QVariant autoNetworkingValue = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH); - - if (!autoNetworkingValue.isNull() && autoNetworkingValue.toString() == FULL_AUTOMATIC_NETWORKING_VALUE) { - // when using full networking use an ephemeral port - disabled until nodes can find us this way - // domainServerPort = 0; - } else if (settingsMap.contains(CUSTOM_PORT_OPTION)) { - domainServerPort = (unsigned short) settingsMap.value(CUSTOM_PORT_OPTION).toUInt(); - } - unsigned short domainServerDTLSPort = 0; if (_isUsingDTLS) { From f19c5c98503f38b24e57372177ea8a135c2a52a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 14:57:38 -0700 Subject: [PATCH 27/40] repair NetworkAccessManager returns, handle custom AS port in assignment-client --- assignment-client/src/Agent.cpp | 2 +- assignment-client/src/AssignmentClient.cpp | 21 ++++++++++++++++---- interface/src/Application.cpp | 2 +- interface/src/ScriptsModel.cpp | 2 +- libraries/audio/src/Sound.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 4 ++-- libraries/avatars/src/Recording.cpp | 2 +- libraries/networking/src/NodeList.cpp | 8 +------- libraries/script-engine/src/ScriptEngine.cpp | 4 ++-- 9 files changed, 27 insertions(+), 20 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ea49b90852..140742ce88 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -206,7 +206,7 @@ void Agent::run() { scriptURL = QUrl(_payload); } - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply *reply = networkAccessManager.get(QNetworkRequest(scriptURL)); QNetworkDiskCache* cache = new QNetworkDiskCache(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 24b6127d63..b30cd355d1 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -59,6 +59,7 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : const QString ASSIGNMENT_POOL_OPTION = "pool"; const QString ASSIGNMENT_WALLET_DESTINATION_ID_OPTION = "wallet"; const QString CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION = "a"; + const QString CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION = "p"; Assignment::Type requestAssignmentType = Assignment::AllTypes; @@ -87,17 +88,29 @@ AssignmentClient::AssignmentClient(int &argc, char **argv) : // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NodeType::Unassigned); + + unsigned short assignmentServerPort = DEFAULT_DOMAIN_SERVER_PORT; + + // check for an overriden assignment server port + if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION)) { + assignmentServerPort = + argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION).toString().toUInt(); + } + + HifiSockAddr assignmentServerSocket(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, assignmentServerPort); // check for an overriden assignment server hostname if (argumentVariantMap.contains(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION)) { _assignmentServerHostname = argumentVariantMap.value(CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION).toString(); - // set the custom assignment socket on our NodeList - HifiSockAddr customAssignmentSocket = HifiSockAddr(_assignmentServerHostname, DEFAULT_DOMAIN_SERVER_PORT); - - nodeList->setAssignmentServerSocket(customAssignmentSocket); + // change the hostname for our assignment server + assignmentServerSocket = HifiSockAddr(_assignmentServerHostname, assignmentServerSocket.getPort()); } + + nodeList->setAssignmentServerSocket(assignmentServerSocket); + qDebug() << "Assignment server socket is" << assignmentServerSocket; + // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required qDebug() << "Waiting for assignment -" << _requestAssignment; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 215848b355..a31b148d1b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -350,7 +350,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkDiskCache* cache = new QNetworkDiskCache(); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); networkAccessManager.setCache(cache); diff --git a/interface/src/ScriptsModel.cpp b/interface/src/ScriptsModel.cpp index 8bea122338..b95b6ae735 100644 --- a/interface/src/ScriptsModel.cpp +++ b/interface/src/ScriptsModel.cpp @@ -117,7 +117,7 @@ void ScriptsModel::requestRemoteFiles(QString marker) { } url.setQuery(query); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 6fa002a664..2266385425 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -78,7 +78,7 @@ Sound::Sound(const QUrl& sampleURL, bool isStereo, QObject* parent) : // assume we have a QApplication or QCoreApplication instance and use the // QNetworkAccess manager to grab the raw audio file at the given URL - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); qDebug() << "Requesting audio file" << sampleURL.toDisplayString(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ef7083e3bf..62cde44909 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1048,7 +1048,7 @@ void AvatarData::setBillboardFromURL(const QString &billboardURL) { QNetworkRequest billboardRequest; billboardRequest.setUrl(QUrl(billboardURL)); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* networkReply = networkAccessManager.get(billboardRequest); connect(networkReply, SIGNAL(finished()), this, SLOT(setBillboardFromNetworkReply())); } @@ -1113,7 +1113,7 @@ void AvatarData::updateJointMappings() { _jointNames.clear(); if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* networkReply = networkAccessManager.get(QNetworkRequest(_skeletonModelURL)); connect(networkReply, SIGNAL(finished()), this, SLOT(setJointMappingsFromNetworkReply())); } diff --git a/libraries/avatars/src/Recording.cpp b/libraries/avatars/src/Recording.cpp index 7465eb1aac..0d089a2bd2 100644 --- a/libraries/avatars/src/Recording.cpp +++ b/libraries/avatars/src/Recording.cpp @@ -385,7 +385,7 @@ RecordingPointer readRecordingFromFile(RecordingPointer recording, const QString if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { // Download file if necessary qDebug() << "Downloading recording at" << url; - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index cac4071fb2..25531861ca 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -418,13 +418,7 @@ void NodeList::sendAssignment(Assignment& assignment) { packetStream << assignment; - static HifiSockAddr DEFAULT_ASSIGNMENT_SOCKET(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME, DEFAULT_DOMAIN_SERVER_PORT); - - const HifiSockAddr* assignmentServerSocket = _assignmentServerSocket.isNull() - ? &DEFAULT_ASSIGNMENT_SOCKET - : &_assignmentServerSocket; - - _nodeSocket.writeDatagram(packet, assignmentServerSocket->getAddress(), assignmentServerSocket->getPort()); + _nodeSocket.writeDatagram(packet, _assignmentServerSocket.getAddress(), _assignmentServerSocket.getPort()); } void NodeList::pingPunchForInactiveNode(const SharedNodePointer& node) { diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 47e0ced6bf..26466ddc47 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -157,7 +157,7 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, emit errorMessage("ERROR Loading file:" + fileName); } } else { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading script at" << url; QEventLoop loop; @@ -682,7 +682,7 @@ void ScriptEngine::include(const QString& includeFile) { QString includeContents; if (url.scheme() == "http" || url.scheme() == "ftp") { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << includeFile; QEventLoop loop; From a358b4e2af55f5e66eeea594479d69a23326d43e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 14:57:54 -0700 Subject: [PATCH 28/40] repair another reference to NetworkAccessManager --- interface/src/ui/ModelsBrowser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 0f89c44d23..7a76bc2d7d 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -221,7 +221,7 @@ void ModelHandler::update() { } for (int i = 0; i < _model.rowCount(); ++i) { QUrl url(_model.item(i,0)->data(Qt::UserRole).toString()); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.head(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); @@ -272,7 +272,7 @@ void ModelHandler::queryNewFiles(QString marker) { // Download url.setQuery(query); - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); From b4cfce8ffa36a2b2cfe2089e79ecd9ee2933ab97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 6 Oct 2014 14:58:23 -0700 Subject: [PATCH 29/40] final NetworkAccessManager return repairs --- interface/src/ui/ScriptEditorWidget.cpp | 2 +- interface/src/ui/overlays/ImageOverlay.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ScriptEditorWidget.cpp b/interface/src/ui/ScriptEditorWidget.cpp index 1473e4a6a0..b55c753061 100644 --- a/interface/src/ui/ScriptEditorWidget.cpp +++ b/interface/src/ui/ScriptEditorWidget.cpp @@ -150,7 +150,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) { disconnect(_scriptEngine, &ScriptEngine::finished, this, &ScriptEditorWidget::onScriptFinished); } } else { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << scriptPath; QEventLoop loop; diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index 8322b9bea4..2b4e1e2f56 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -37,7 +37,7 @@ ImageOverlay::~ImageOverlay() { // TODO: handle setting image multiple times, how do we manage releasing the bound texture? void ImageOverlay::setImageURL(const QUrl& url) { _isLoaded = false; - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, &ImageOverlay::replyFinished); } From 63730a37da0f39ad93c18fd8e17b5718eeabbb6e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 6 Oct 2014 15:26:47 -0700 Subject: [PATCH 30/40] Bring initial walk speed down for easier maneuvering around people --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 469df6066d..087d670760 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -49,7 +49,7 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; -const float MIN_KEYBOARD_CONTROL_SPEED = 0.75f; +const float MIN_KEYBOARD_CONTROL_SPEED = 0.50f; const float MAX_WALKING_SPEED = 4.5f; // TODO: normalize avatar speed for standard avatar size, then scale all motion logic From d1ea91bdf5def0f3c3b4388758f12cba77496570 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 7 Oct 2014 10:15:09 -0700 Subject: [PATCH 31/40] Update CONTRIBUTING.md Updated to new URLs for coding standard, worklist. Updated details on how to contribute via Worklist. --- CONTRIBUTING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72eab372cd..4f1153b4f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -The project embraces distributed development and if you'd like to help, we'll pay you -- find out more at Worklist.net. If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on Worklist.net. +The project embraces distributed development and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net). If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on Worklist.net. We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.io @@ -16,7 +16,7 @@ Contributing git checkout -b new_branch_name ``` 4. Code - * Follow the [coding standard](https://github.com/highfidelity/hifi/wiki/Coding-Standard) + * Follow the [coding standard](http://docs.highfidelity.io/v1.0/docs/coding-standard) 5. Commit * Use [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) 6. Update your branch @@ -38,11 +38,11 @@ Contributing Reporting Bugs === -1. Always update to the latest code on master, it is possible the bug has already been fixed! -2. Search the [repository issues](https://github.com/highfidelity/hifi/issues) to make sure that somebody has not already reported the same bug. -3. Open an [issue on GitHub](https://github.com/highfidelity/hifi/issues) including information about your system and how to reproduce the bug. +1. Always update to the latest code on master, we make many merges every day and it is possible the bug has already been fixed! +2. Search jobs [on Worklist](https://worklist.net) to make sure that somebody has not already reported the same bug. +3. Add a [job on Worklist](https://worklist.net/job/add) including information about your system and how to reproduce the bug. Requesting a feature === -1. Search the [repository issues](https://github.com/highfidelity/hifi/issues) to make sure that somebody has not already requested the same feature. If you find a matching request, feel free to add any additional comments to the existing issue. -2. Submit an [issue on GitHub](https://github.com/highfidelity/hifi/issues) that is tagged as a feature. \ No newline at end of file +1. Search the [the Worklist](https://worklist.net) to make sure that somebody has not already requested the same feature. If you find a matching request, feel free to add any additional comments to the existing issue. +2. Add a [job on Worklist](https://worklist.net/job/add) that is labeled as a Feature (and select any other appropriate Labels) and includes a detailed description of your request. From 484d97a2b8e1213047db1d62ec2b10624bc72c2f Mon Sep 17 00:00:00 2001 From: Grayson Stebbins Date: Tue, 7 Oct 2014 10:20:15 -0700 Subject: [PATCH 32/40] Update README.md Added section about documentation, turned Worklist URLs into links. --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d5fa8de1b4..5ab725d6b6 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ lab experimenting with Virtual Worlds and VR. In this repository you'll find the source to many of the components in our alpha-stage virtual world. The project embraces distributed development -and if you'd like to help, we'll pay you -- find out more at Worklist.net. +and if you'd like to help, we'll pay you -- find out more at [Worklist.net](https://worklist.net). If you find a small bug and have a fix, pull requests are welcome. If you'd like to get paid for your work, make sure you report the bug via a job on -Worklist.net. +[Worklist.net](https://worklist.net). We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.io @@ -14,6 +14,10 @@ send your resume to hiring@highfidelity.io ##### Chat with us Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! +Documentation +========= +Documenation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). + Build Instructions ========= All information required to build is found in the [build guide](BUILD.md). From 30740afe8049bfe58687611d4f4c7cb5e48ae11e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 7 Oct 2014 12:42:29 -0700 Subject: [PATCH 33/40] fix a typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ab725d6b6..90f1ca0dc7 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you hav Documentation ========= -Documenation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). +Documentation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). Build Instructions ========= From ea4c5a8900f04f67add8eca5c0da61008da52c9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 7 Oct 2014 14:18:05 -0700 Subject: [PATCH 34/40] repairs for new user scoped paths --- domain-server/resources/web/js/settings.js | 2 +- interface/src/Menu.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 48b3b15e8f..bf382f7ace 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -292,7 +292,7 @@ function chooseFromHighFidelityDomains(clickedButton) { modal_buttons["success"] = { label: 'Create new domain', callback: function() { - window.open("https://data.highfidelity.io/domains", '_blank'); + window.open("https://data.highfidelity.io/users/domains", '_blank'); } } modal_body = "

You do not have any domains in your High Fidelity account." + diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5f2e3d767a..d82fb85c8c 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1234,7 +1234,7 @@ void Menu::toggleLocationList() { if (!_userLocationsDialog) { JavascriptObjectMap locationObjectMap; locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); - _userLocationsDialog = DataWebDialog::dialogForPath("/locations", locationObjectMap); + _userLocationsDialog = DataWebDialog::dialogForPath("/user/locations", locationObjectMap); } if (!_userLocationsDialog->isVisible()) { @@ -1278,7 +1278,7 @@ void Menu::nameLocation() { if (!_newLocationDialog) { JavascriptObjectMap locationObjectMap; locationObjectMap.insert("InterfaceLocation", LocationScriptingInterface::getInstance()); - _newLocationDialog = DataWebDialog::dialogForPath("/locations/new", locationObjectMap); + _newLocationDialog = DataWebDialog::dialogForPath("/user/locations/new", locationObjectMap); } if (!_newLocationDialog->isVisible()) { From 67fdfbb7f1a5d09e9f565c1c0ae94048afbfdf08 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 7 Oct 2014 14:19:15 -0700 Subject: [PATCH 35/40] fix for user domains path in domain settings --- domain-server/resources/web/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index bf382f7ace..b964887d19 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -292,7 +292,7 @@ function chooseFromHighFidelityDomains(clickedButton) { modal_buttons["success"] = { label: 'Create new domain', callback: function() { - window.open("https://data.highfidelity.io/users/domains", '_blank'); + window.open("https://data.highfidelity.io/user/domains", '_blank'); } } modal_body = "

You do not have any domains in your High Fidelity account." + From 373d2f0532e5f4c4bd0fb6aa715500d9dc81121a Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 7 Oct 2014 14:50:29 -0700 Subject: [PATCH 36/40] Work-around for right hand roll on Windows is no longer needed --- examples/leapHands.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index 1095a9f4dc..3352ea243b 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -31,7 +31,6 @@ var leapHands = (function () { CALIBRATED = 2, CALIBRATION_TIME = 1000, // milliseconds PI = 3.141593, - isWindows, avatarScale, avatarFaceModelURL, avatarSkeletonModelURL, @@ -132,9 +131,6 @@ var leapHands = (function () { if (hands[0].controller.isActive() && hands[1].controller.isActive()) { leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; - - // TODO: Temporary detection of Windows to work around Leap Controller problem. - isWindows = (hands[1].controller.getAbsRotation().z > (0.25 * PI)); } else { calibrationStatus = UNCALIBRATED; return; @@ -398,12 +394,6 @@ var leapHands = (function () { handPitch = 2.0 * -wristAbsRotation.x; handYaw = 2.0 * wristAbsRotation.y; - // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. - // Approximate fix is to add a fudge factor. - if (h === 1 && isWindows) { - handRoll = handRoll + 0.6 * PI; - } - // Hand position and orientation ... if (h === 0) { handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), From ec6b6999a0a234bd2b8850e27fa553a1d5a17daf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 7 Oct 2014 15:29:57 -0700 Subject: [PATCH 37/40] fix for location hash in address bar --- interface/src/ui/AddressBarDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 26505af0be..399f46f26d 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -26,7 +26,7 @@ AddressBarDialog::AddressBarDialog() : void AddressBarDialog::setupUI() { const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; - const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, @user, #location"; + const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /path"; const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; const int ADDRESSBAR_MIN_WIDTH = 200; From 6e81bde7bd7ac120afd2fba2fe3ff78126dd05a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 7 Oct 2014 15:30:44 -0700 Subject: [PATCH 38/40] make position path clearer for address bar --- interface/src/ui/AddressBarDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/AddressBarDialog.cpp b/interface/src/ui/AddressBarDialog.cpp index 399f46f26d..d81eaa36b4 100644 --- a/interface/src/ui/AddressBarDialog.cpp +++ b/interface/src/ui/AddressBarDialog.cpp @@ -26,7 +26,7 @@ AddressBarDialog::AddressBarDialog() : void AddressBarDialog::setupUI() { const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;"; - const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /path"; + const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z"; const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;"; const int ADDRESSBAR_MIN_WIDTH = 200; From a3cce3ae2286e8f39bda7f05597da2caeecfb169 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 8 Oct 2014 10:11:18 -0700 Subject: [PATCH 39/40] Fix Leap hand roll --- examples/leapHands.js | 48 +++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index 3352ea243b..222c0e4cf1 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -30,7 +30,6 @@ var leapHands = (function () { CALIBRATING = 1, CALIBRATED = 2, CALIBRATION_TIME = 1000, // milliseconds - PI = 3.141593, avatarScale, avatarFaceModelURL, avatarSkeletonModelURL, @@ -314,11 +313,7 @@ var leapHands = (function () { j, side, handOffset, - handRoll, - handPitch, - handYaw, handRotation, - wristAbsRotation, locRotation, cameraOrientation, inverseAvatarOrientation; @@ -357,20 +352,22 @@ var leapHands = (function () { handOffset.x = -handOffset.x; // Hand rotation in camera coordinates ... - // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; - handYaw = 2.0 * -wristAbsRotation.y; - // TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. - handRoll = PI + handRoll; + handRotation = wrists[h].controller.getAbsRotation(); + handRotation = { + x: handRotation.z, + y: handRotation.y, + z: handRotation.x, + w: handRotation.w + }; if (h === 0) { - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + handRotation.x = -handRotation.x; + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 }), handRotation); } else { - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + handRotation.z = -handRotation.z; + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation); } // Hand rotation in avatar coordinates ... @@ -388,19 +385,22 @@ var leapHands = (function () { z: hands[h].zeroPosition.z - handOffset.z }; - // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * -wristAbsRotation.x; - handYaw = 2.0 * wristAbsRotation.y; + handRotation = wrists[h].controller.getAbsRotation(); + handRotation = { + x: handRotation.z, + y: handRotation.y, + z: handRotation.x, + w: handRotation.w + }; - // Hand position and orientation ... if (h === 0) { + handRotation.x = -handRotation.x; handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + handRotation); } else { + handRotation.z = -handRotation.z; handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + handRotation); } } From d064919cb00cbbd7d292b9277d6ae37a67d6d1a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 8 Oct 2014 10:41:16 -0700 Subject: [PATCH 40/40] fix a missed reference to NetworkAccessManager --- libraries/script-engine/src/ScriptEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 19d1758c4a..51789aec3a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -682,7 +682,7 @@ void ScriptEngine::include(const QString& includeFile) { QString includeContents; if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { - NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(url)); qDebug() << "Downloading included script at" << includeFile; QEventLoop loop;