diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9131c99c6d..4173cacfc7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -61,7 +61,7 @@ const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f; const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.18; -const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.001f; +const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f; const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer"; const QString AUDIO_ENV_GROUP_KEY = "audio_env"; const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer"; @@ -465,6 +465,63 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { return streamsMixed; } +void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { + static char clientEnvBuffer[MAX_PACKET_SIZE]; + + // Send stream properties + bool hasReverb = false; + float reverbTime, wetLevel; + // find reverb properties + for (int i = 0; i < _zoneReverbSettings.size(); ++i) { + AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData()); + glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); + if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { + hasReverb = true; + reverbTime = _zoneReverbSettings[i].reverbTime; + wetLevel = _zoneReverbSettings[i].wetLevel; + break; + } + } + AudioMixerClientData* nodeData = static_cast<AudioMixerClientData*>(node->getLinkedData()); + AvatarAudioStream* stream = nodeData->getAvatarAudioStream(); + bool dataChanged = (stream->hasReverb() != hasReverb) || + (stream->hasReverb() && (stream->getRevebTime() != reverbTime || + stream->getWetLevel() != wetLevel)); + if (dataChanged) { + // Update stream + if (hasReverb) { + stream->setReverb(reverbTime, wetLevel); + } else { + stream->clearReverb(); + } + } + + // Send at change or every so often + float CHANCE_OF_SEND = 0.01f; + bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); + + if (sendData) { + int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment); + char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader; + + unsigned char bitset = 0; + if (hasReverb) { + setAtBit(bitset, HAS_REVERB_BIT); + } + + memcpy(envDataAt, &bitset, sizeof(unsigned char)); + envDataAt += sizeof(unsigned char); + + if (hasReverb) { + memcpy(envDataAt, &reverbTime, sizeof(float)); + envDataAt += sizeof(float); + memcpy(envDataAt, &wetLevel, sizeof(float)); + envDataAt += sizeof(float); + } + NodeList::getInstance()->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node); + } +} + void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { NodeList* nodeList = NodeList::getInstance(); @@ -642,7 +699,6 @@ void AudioMixer::run() { timer.start(); char clientMixBuffer[MAX_PACKET_SIZE]; - char clientEnvBuffer[MAX_PACKET_SIZE]; int usecToSleep = BUFFER_SEND_INTERVAL_USECS; @@ -759,58 +815,6 @@ void AudioMixer::run() { // pack mixed audio samples memcpy(mixDataAt, _mixSamples, NETWORK_BUFFER_LENGTH_BYTES_STEREO); mixDataAt += NETWORK_BUFFER_LENGTH_BYTES_STEREO; - - // Send stream properties - bool hasReverb = false; - float reverbTime, wetLevel; - // find reverb properties - for (int i = 0; i < _zoneReverbSettings.size(); ++i) { - AudioMixerClientData* data = static_cast<AudioMixerClientData*>(node->getLinkedData()); - glm::vec3 streamPosition = data->getAvatarAudioStream()->getPosition(); - if (_audioZones[_zoneReverbSettings[i].zone].contains(streamPosition)) { - hasReverb = true; - reverbTime = _zoneReverbSettings[i].reverbTime; - wetLevel = _zoneReverbSettings[i].wetLevel; - break; - } - } - AvatarAudioStream* stream = nodeData->getAvatarAudioStream(); - bool dataChanged = (stream->hasReverb() != hasReverb) || - (stream->hasReverb() && (stream->getRevebTime() != reverbTime || - stream->getWetLevel() != wetLevel)); - if (dataChanged) { - // Update stream - if (hasReverb) { - stream->setReverb(reverbTime, wetLevel); - } else { - stream->clearReverb(); - } - } - - // Send at change or every so often - float CHANCE_OF_SEND = 0.01f; - bool sendData = dataChanged || (randFloat() < CHANCE_OF_SEND); - - if (sendData) { - int numBytesEnvPacketHeader = populatePacketHeader(clientEnvBuffer, PacketTypeAudioEnvironment); - char* envDataAt = clientEnvBuffer + numBytesEnvPacketHeader; - - unsigned char bitset = 0; - if (hasReverb) { - setAtBit(bitset, HAS_REVERB_BIT); - } - - memcpy(envDataAt, &bitset, sizeof(unsigned char)); - envDataAt += sizeof(unsigned char); - - if (hasReverb) { - memcpy(envDataAt, &reverbTime, sizeof(float)); - envDataAt += sizeof(float); - memcpy(envDataAt, &wetLevel, sizeof(float)); - envDataAt += sizeof(float); - } - nodeList->writeDatagram(clientEnvBuffer, envDataAt - clientEnvBuffer, node); - } } else { // pack header int numBytesPacketHeader = populatePacketHeader(clientMixBuffer, PacketTypeSilentAudioFrame); @@ -826,6 +830,9 @@ void AudioMixer::run() { memcpy(mixDataAt, &numSilentSamples, sizeof(quint16)); mixDataAt += sizeof(quint16); } + + // Send audio environment + sendAudioEnvironmentPacket(node); // send mixed audio packet nodeList->writeDatagram(clientMixBuffer, mixDataAt - clientMixBuffer, node); diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index ccf7727265..cc88e368b2 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -49,6 +49,9 @@ private: /// prepares and sends a mix to one Node int prepareMixForListeningNode(Node* node); + + /// Send Audio Environment packet for a single node + void sendAudioEnvironmentPacket(SharedNodePointer node); // used on a per stream basis to run the filter on before mixing, large enough to handle the historical // data from a phase delay as well as an entire network buffer diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index a49e1072eb..ba4cfe8dfd 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -93,8 +93,8 @@ "name": "noise_muting_threshold", "label": "Noise Muting Threshold", "help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)", - "placeholder": "0.001", - "default": "0.001", + "placeholder": "0.003", + "default": "0.003", "advanced": false }, { diff --git a/examples/entityScripts/changeColorOnHover.js b/examples/entityScripts/changeColorOnHover.js index de3f5f3784..638c1bece4 100644 --- a/examples/entityScripts/changeColorOnHover.js +++ b/examples/entityScripts/changeColorOnHover.js @@ -22,13 +22,21 @@ this.oldColorKnown = true; print("storing old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); }; + + this.preload = function(entityID) { + print("preload"); + this.storeOldColor(entityID); + }; + this.hoverEnterEntity = function(entityID, mouseEvent) { + print("hoverEnterEntity"); if (!this.oldColorKnown) { this.storeOldColor(entityID); } Entities.editEntity(entityID, { color: { red: 0, green: 255, blue: 255} }); }; this.hoverLeaveEntity = function(entityID, mouseEvent) { + print("hoverLeaveEntity"); if (this.oldColorKnown) { print("leave restoring old color... this.oldColor=" + this.oldColor.red + "," + this.oldColor.green + "," + this.oldColor.blue); diff --git a/examples/entityScripts/playSoundOnClick.js b/examples/entityScripts/playSoundOnClick.js index fea68db2c3..4ab83a1952 100644 --- a/examples/entityScripts/playSoundOnClick.js +++ b/examples/entityScripts/playSoundOnClick.js @@ -12,12 +12,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function(){ - var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + var bird; + + this.preload = function(entityID) { + print("preload("+entityID.id+")"); + bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + }; + this.clickDownOnEntity = function(entityID, mouseEvent) { print("clickDownOnEntity()..."); - Audio.playSound(bird, { - position: MyAvatar.position, - volume: 0.5 + Audio.playSound(bird, { + position: MyAvatar.position, + volume: 0.5 }); }; }) diff --git a/examples/entityScripts/playSoundOnEnterOrLeave.js b/examples/entityScripts/playSoundOnEnterOrLeave.js index 6ee961af0a..07be090c31 100644 --- a/examples/entityScripts/playSoundOnEnterOrLeave.js +++ b/examples/entityScripts/playSoundOnEnterOrLeave.js @@ -12,13 +12,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // (function(){ - var bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); + var bird; function playSound(entityID) { Audio.playSound(bird, { position: MyAvatar.position, volume: 0.5 }); + } + + this.preload = function(entityID) { + print("preload("+entityID.id+")"); + bird = new Sound("http://s3.amazonaws.com/hifi-public/sounds/Animals/bushtit_1.raw"); }; this.enterEntity = function(entityID) { diff --git a/examples/html/gridControls.html b/examples/html/gridControls.html new file mode 100644 index 0000000000..e7bf1cdf8c --- /dev/null +++ b/examples/html/gridControls.html @@ -0,0 +1,193 @@ +<html> +<head> + <script> + function loaded() { + var gridColor = { red: 0, green: 0, blue: 0 }; + var gridColors = [ + { red: 0, green: 0, blue: 0 }, + { red: 128, green: 128, blue: 128 }, + { red: 255, green: 0, blue: 0 }, + { red: 0, green: 255, blue: 0}, + { red: 0, green: 0, blue: 255 }, + ]; + + posY = document.getElementById("horiz-y"); + minorSpacing = document.getElementById("minor-spacing"); + majorSpacing = document.getElementById("major-spacing"); + gridOn = document.getElementById("grid-on"); + snapToGrid = document.getElementById("snap-to-grid"); + hGridVisible = document.getElementById("horiz-grid-visible"); + + + if (window.EventBridge !== undefined) { + EventBridge.scriptEventReceived.connect(function(data) { + data = JSON.parse(data); + if (data.origin) { + + var origin = data.origin; + posY.value = origin.y; + } + + if (data.minorGridSpacing) { + minorSpacing.value = data.minorGridSpacing; + } + + if (data.majorGridEvery) { + majorSpacing.value = data.majorGridEvery; + } + + if (data.gridColor) { + gridColor = data.gridColor; + } + + if (data.snapToGrid !== undefined) { + snapToGrid.checked = data.snapToGrid == true; + } + + if (data.visible !== undefined) { + hGridVisible.checked = data.visible == true; + } + }); + + function emitUpdate() { + EventBridge.emitWebEvent(JSON.stringify({ + type: "update", + origin: { + y: posY.value, + }, + minorGridSpacing: minorSpacing.value, + majorGridEvery: majorSpacing.value, + gridColor: gridColor, + snapToGrid: snapToGrid.checked, + visible: hGridVisible.checked, + })); + } + + } + + document.addEventListener("input", emitUpdate); + hGridVisible.addEventListener("change", emitUpdate); + snapToGrid.addEventListener("change", emitUpdate); + + var gridColorBox = document.getElementById('grid-color'); + + for (var i = 0; i < gridColors.length; i++) { + var colors = gridColors[i]; + var box = document.createElement('div'); + box.setAttribute('class', 'color-box'); + box.style.background = 'rgb(' + colors.red + ', ' + colors.green + ', ' + colors.blue + ')'; + document.getElementById("grid-colors").appendChild(box); + box.addEventListener("click", function(color) { + return function() { + gridColor = color; + emitUpdate(); + } + }({ red: colors.red, green: colors.green, blue: colors.blue })); + } + + EventBridge.emitWebEvent(JSON.stringify({ type: 'init' })); + } + </script> + <style> + * { + } + + body { + margin: 0; + padding: 0; + + background: #DDD; + font-family: Sans-Serif; + font-size: 12px; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + input { + line-height: 2; + } + + .input-left { + display: inline-block; + width: 20px; + } + + .color-box { + display: inline-block; + width: 20px; + height: 20px; + border: 1px solid black; + background: blue; + margin: 2px; + } + + .color-box.highlight { + width: 18px; + height: 18px; + border: 2px solid black; + } + + .section-header { + background: #AAA; + border-bottom: 1px solid #CCC; + } + + .section-header label { + font-weight: bold; + } + + .grid-section { + border-top: 1px solid #DDD; + padding: 4px 0px 4px 20px; + background: #DDD; + } + </style> +</head> +<body onload='loaded();'> + <div class="section-header"> + <input type='checkbox' id="horiz-grid-visible"> + <label>Horizontal Grid</label> + </div> + <div class="grid-section"> + + <label>Snap to grid</label> + <div> + <div class="input-left"> + </div> + <input type='checkbox' id="snap-to-grid"> + </div> + + <label>Position (Y Axis)</label> + <div id="horizontal-position"> + <div class="input-left"> + </div> + <input type='number' id="horiz-y" class="number" value="0.0" step="0.1"></input> + </div> + + <label>Minor Grid Size</label> + <div> + <div class="input-left"> + </div> + <input type='number' id="minor-spacing" min="0" step="0.01", ></input> + </div> + + <label>Major Grid Every</label> + <div> + <div class="input-left"> + </div> + <input type='number' id="major-spacing" min="2" step="1", ></input> + </div> + + <label>Grid Color</label> + <div id="grid-colors"> + <div class="input-left"> + </div> + </div> + </div> +</body> +</html> diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 29bf1bdd79..22f75cb187 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -394,12 +394,12 @@ SelectionDisplay = (function () { var baseOverlayAngles = { x: 0, y: 0, z: 0 }; var baseOverlayRotation = Quat.fromVec3Degrees(baseOverlayAngles); var baseOfEntityProjectionOverlay = Overlays.addOverlay("rectangle3d", { - position: { x:0, y: 0, z: 0}, - size: 1, + position: { x: 1, y: 0, z: 0}, color: { red: 51, green: 152, blue: 203 }, alpha: 0.5, solid: true, visible: false, + width: 300, height: 200, rotation: baseOverlayRotation, ignoreRayIntersection: true, // always ignore this }); @@ -570,6 +570,7 @@ SelectionDisplay = (function () { xRailOverlay, yRailOverlay, zRailOverlay, + baseOfEntityProjectionOverlay, ].concat(stretchHandles); overlayNames[highlightBox] = "highlightBox"; @@ -878,20 +879,24 @@ SelectionDisplay = (function () { translateHandlesVisible = false; } - var rotation = SelectionManager.worldRotation; - var dimensions = SelectionManager.worldDimensions; - var position = SelectionManager.worldPosition; + var rotation = selectionManager.worldRotation; + var dimensions = selectionManager.worldDimensions; + var position = selectionManager.worldPosition; Overlays.editOverlay(baseOfEntityProjectionOverlay, { - visible: true, - solid:true, - lineWidth: 2.0, - position: { x: position.x, - y: 0, - z: position.z }, - - dimensions: { x: dimensions.x, y: 0, z: dimensions.z }, + visible: mode != "ROTATE_YAW" && mode != "ROTATE_PITCH" && mode != "ROTATE_ROLL", + solid: true, + // lineWidth: 2.0, + position: { + x: position.x, + y: grid.getOrigin().y, + z: position.z + }, + dimensions: { + x: dimensions.x, + y: dimensions.z + }, rotation: rotation, }); @@ -1098,6 +1103,7 @@ SelectionDisplay = (function () { var initialXZPick = null; var isConstrained = false; + var constrainMajorOnly = false; var startPosition = null; var duplicatedEntityIDs = null; var translateXZTool = { @@ -1162,15 +1168,23 @@ SelectionDisplay = (function () { if (isConstrained) { Overlays.editOverlay(xRailOverlay, { visible: false }); Overlays.editOverlay(zRailOverlay, { visible: false }); + isConstrained = false; } } + constrainMajorOnly = event.isControl; + var cornerPosition = Vec3.sum(startPosition, Vec3.multiply(-0.5, selectionManager.worldDimensions)); + vector = Vec3.subtract( + grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), + cornerPosition); + var wantDebug = false; for (var i = 0; i < SelectionManager.selections.length; i++) { var properties = SelectionManager.savedProperties[SelectionManager.selections[i].id]; + var newPosition = Vec3.sum(properties.position, { x: vector.x, y: 0, z: vector.z }); Entities.editEntity(SelectionManager.selections[i], { - position: Vec3.sum(properties.position, vector), + position: newPosition, }); if (wantDebug) { diff --git a/examples/libraries/gridTool.js b/examples/libraries/gridTool.js new file mode 100644 index 0000000000..34e25d6733 --- /dev/null +++ b/examples/libraries/gridTool.js @@ -0,0 +1,189 @@ +Grid = function(opts) { + var that = {}; + + var color = { red: 100, green: 152, blue: 203 }; + var gridColor = { red: 100, green: 152, blue: 203 }; + var gridAlpha = 1.0; + var origin = { x: 0, y: 0, z: 0 }; + var majorGridEvery = 5; + var minorGridSpacing = 0.2; + var halfSize = 40; + var yOffset = 0.001; + + var worldSize = 16384; + + var minorGridWidth = 0.5; + var majorGridWidth = 1.5; + + var snapToGrid = true; + + var gridOverlay = Overlays.addOverlay("grid", { + position: { x: 0 , y: 0, z: 0 }, + visible: true, + color: { red: 0, green: 0, blue: 128 }, + alpha: 1.0, + rotation: Quat.fromPitchYawRollDegrees(90, 0, 0), + minorGridWidth: 0.1, + majorGridEvery: 2, + }); + + that.getMinorIncrement = function() { return minorGridSpacing; }; + that.getMajorIncrement = function() { return minorGridSpacing * majorGridEvery; }; + + that.visible = false; + + that.getOrigin = function() { + return origin; + } + + that.getSnapToGrid = function() { return snapToGrid; }; + + that.setVisible = function(visible, noUpdate) { + that.visible = visible; + updateGrid(); + + if (!noUpdate) { + that.emitUpdate(); + } + } + + that.snapToGrid = function(position, majorOnly) { + if (!snapToGrid) { + return position; + } + + var spacing = majorOnly ? (minorGridSpacing * majorGridEvery) : minorGridSpacing; + + position = Vec3.subtract(position, origin); + + position.x = Math.round(position.x / spacing) * spacing; + position.y = Math.round(position.y / spacing) * spacing; + position.z = Math.round(position.z / spacing) * spacing; + + return Vec3.sum(position, origin); + } + + that.setPosition = function(newPosition, noUpdate) { + origin = Vec3.subtract(newPosition, { x: 0, y: yOffset, z: 0 }); + origin.x = 0; + origin.z = 0; + updateGrid(); + + if (!noUpdate) { + that.emitUpdate(); + } + }; + + that.emitUpdate = function() { + if (that.onUpdate) { + that.onUpdate({ + origin: origin, + minorGridSpacing: minorGridSpacing, + majorGridEvery: majorGridEvery, + gridSize: halfSize, + visible: that.visible, + snapToGrid: snapToGrid, + gridColor: gridColor, + }); + } + }; + + that.update = function(data) { + if (data.snapToGrid !== undefined) { + snapToGrid = data.snapToGrid; + } + + if (data.origin) { + var pos = data.origin; + pos.x = pos.x === undefined ? origin.x : pos.x; + pos.y = pos.y === undefined ? origin.y : pos.y; + pos.z = pos.z === undefined ? origin.z : pos.z; + that.setPosition(pos, true); + } + + if (data.minorGridSpacing) { + minorGridSpacing = data.minorGridSpacing; + } + + if (data.majorGridEvery) { + majorGridEvery = data.majorGridEvery; + } + + if (data.gridColor) { + gridColor = data.gridColor; + } + + if (data.gridSize) { + halfSize = data.gridSize; + } + + if (data.visible !== undefined) { + that.setVisible(data.visible, true); + } + + updateGrid(); + } + + function updateGrid() { + Overlays.editOverlay(gridOverlay, { + position: { x: origin.y, y: origin.y, z: -origin.y }, + visible: that.visible, + minorGridWidth: minorGridSpacing, + majorGridEvery: majorGridEvery, + color: gridColor, + alpha: gridAlpha, + }); + } + + function cleanup() { + Overlays.deleteOverlay(gridOverlay); + } + + that.addListener = function(callback) { + that.onUpdate = callback; + } + + Script.scriptEnding.connect(cleanup); + updateGrid(); + + that.onUpdate = null; + + return that; +}; + +GridTool = function(opts) { + var that = {}; + + var horizontalGrid = opts.horizontalGrid; + var verticalGrid = opts.verticalGrid; + var listeners = []; + + var url = Script.resolvePath('html/gridControls.html'); + var webView = new WebWindow(url, 200, 280); + + horizontalGrid.addListener(function(data) { + webView.eventBridge.emitScriptEvent(JSON.stringify(data)); + }); + + webView.eventBridge.webEventReceived.connect(function(data) { + data = JSON.parse(data); + if (data.type == "init") { + horizontalGrid.emitUpdate(); + } else if (data.type == "update") { + horizontalGrid.update(data); + for (var i = 0; i < listeners.length; i++) { + listeners[i](data); + } + } + }); + + that.addListener = function(callback) { + listeners.push(callback); + } + + that.setVisible = function(visible) { + webView.setVisible(visible); + } + + return that; +}; diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js new file mode 100644 index 0000000000..0175c56e18 --- /dev/null +++ b/examples/libraries/walkApi.js @@ -0,0 +1,412 @@ +// +// walkObjects.js +// +// version 1.001 +// +// Created by David Wooldridge, Autumn 2014 +// +// Motion, state and Transition objects for use by the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// constructor for the Motion object +Motion = function() { + + this.setGender = function(gender) { + + this.avatarGender = gender; + + switch(this.avatarGender) { + + case MALE: + + this.selWalk = walkAssets.maleStandardWalk; + this.selStand = walkAssets.maleStandOne; + this.selFlyUp = walkAssets.maleFlyingUp; + this.selFly = walkAssets.maleFlying; + this.selFlyDown = walkAssets.maleFlyingDown; + this.selSideStepLeft = walkAssets.maleSideStepLeft; + this.selSideStepRight = walkAssets.maleSideStepRight; + this.curAnim = this.selStand; + return; + + case FEMALE: + + this.selWalk = walkAssets.femaleStandardWalk; + this.selStand = walkAssets.femaleStandOne; + this.selFlyUp = walkAssets.femaleFlyingUp; + this.selFly = walkAssets.femaleFlying; + this.selFlyDown = walkAssets.femaleFlyingDown; + this.selSideStepLeft = walkAssets.femaleSideStepLeft; + this.selSideStepRight = walkAssets.femaleSideStepRight; + this.curAnim = this.selStand; + return; + } + } + + this.hydraCheck = function() { + + // function courtesy of Thijs Wenker, frisbee.js + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2); + return hydrasConnected; + } + + // settings + this.armsFree = this.hydraCheck(); // automatically sets true for Hydra support - temporary fix + this.makesFootStepSounds = true; + this.avatarGender = MALE; + this.motionPitchMax = 60; + this.motionRollMax = 40; + + // timing + this.frameStartTime = 0; // used for measuring frame execution times + this.frameExecutionTimeMax = 0; // keep track of the longest frame execution time + this.cumulativeTime = 0.0; + this.lastWalkStartTime = 0; + + // selected animations + this.selWalk = walkAssets.maleStandardWalk; + this.selStand = walkAssets.maleStandOne; + this.selFlyUp = walkAssets.maleFlyingUp; + this.selFly = walkAssets.maleFlying; + this.selFlyDown = walkAssets.maleFlyingDown; + this.selSideStepLeft = walkAssets.maleSideStepLeft; + this.selSideStepRight = walkAssets.maleSideStepRight; + + // the currently selected animation, joint and transition + this.curAnim = this.selStand; + this.curJointIndex = 0; + this.curTransition = null; + + // zero out avi's joints, curl the fingers nicely then take some measurements + this.avatarJointNames = MyAvatar.getJointNames(); + if (!this.armsFree) { + + for (var i = 0; i < this.avatarJointNames.length; i++) { + + if (i > 17 || i < 34) { + // left hand fingers + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(16, 0, 0)); + } else if (i > 33 || i < 38) { + // left hand thumb + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(4, 0, 0)); + } else if (i > 41 || i < 58) { + // right hand fingers + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(16, 0, 0)); + } else if (i > 57 || i < 62) { + // right hand thumb + MyAvatar.setJointData(this.avatarJointNames[i], Quat.fromPitchYawRollDegrees(4, 0, 0)); + } else { + // zero out the remaining joints + MyAvatar.clearJointData(this.avatarJointNames[i]); + } + } + } + + this.footRPos = MyAvatar.getJointPosition("RightFoot"); + this.hipsToFeet = MyAvatar.getJointPosition("Hips").y - this.footRPos.y; + + // walkwheel (foot / ground speed matching) + this.direction = FORWARDS; + this.nextStep = RIGHT; + this.nFrames = 0; + this.strideLength = this.selWalk.calibration.strideLengthForwards; + this.walkWheelPos = 0; + + this.advanceWalkWheel = function(angle){ + this.walkWheelPos += angle; + if (motion.walkWheelPos >= 360) { + this.walkWheelPos = this.walkWheelPos % 360; + } + } + + // last frame history + this.lastDirection = 0; + this.lastVelocity = 0; + this.lastStrideLength = 0; // kept for use during transitions + +}; // end Motion constructor + +// finite state machine +state = (function () { + + return { + + // the finite list of states + STANDING: 1, + WALKING: 2, + SIDE_STEP: 3, + FLYING: 4, + EDIT_WALK_STYLES: 5, + EDIT_WALK_TWEAKS: 6, + EDIT_WALK_JOINTS: 7, + EDIT_STANDING: 8, + EDIT_FLYING: 9, + EDIT_FLYING_UP: 10, + EDIT_FLYING_DOWN: 11, + EDIT_SIDESTEP_LEFT: 12, + EDIT_SIDESTEP_RIGHT: 14, + currentState: this.STANDING, + + // status vars + powerOn: true, + minimised: true, + editing: false, + editingTranslation: false, + + setInternalState: function(newInternalState) { + + switch (newInternalState) { + + case this.WALKING: + + this.currentState = this.WALKING; + this.editing = false; + motion.lastWalkStartTime = new Date().getTime(); + walkInterface.updateMenu(); + return; + + case this.FLYING: + + this.currentState = this.FLYING; + this.editing = false; + motion.lastWalkStartTime = 0; + walkInterface.updateMenu(); + return; + + case this.SIDE_STEP: + + this.currentState = this.SIDE_STEP; + this.editing = false; + motion.lastWalkStartTime = new Date().getTime(); + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_STYLES: + + this.currentState = this.EDIT_WALK_STYLES; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_TWEAKS: + + this.currentState = this.EDIT_WALK_TWEAKS; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_WALK_JOINTS: + + this.currentState = this.EDIT_WALK_JOINTS; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selWalk; + walkInterface.updateMenu(); + return; + + case this.EDIT_STANDING: + + this.currentState = this.EDIT_STANDING; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selStand; + walkInterface.updateMenu(); + return; + + case this.EDIT_SIDESTEP_LEFT: + + this.currentState = this.EDIT_SIDESTEP_LEFT; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selSideStepLeft; + walkInterface.updateMenu(); + return; + + case this.EDIT_SIDESTEP_RIGHT: + + this.currentState = this.EDIT_SIDESTEP_RIGHT; + this.editing = true; + motion.lastWalkStartTime = new Date().getTime(); + motion.curAnim = motion.selSideStepRight; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING: + + this.currentState = this.EDIT_FLYING; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFly; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING_UP: + + this.currentState = this.EDIT_FLYING_UP; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFlyUp; + walkInterface.updateMenu(); + return; + + case this.EDIT_FLYING_DOWN: + + this.currentState = this.EDIT_FLYING_DOWN; + this.editing = true; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selFlyDown; + walkInterface.updateMenu(); + return; + + case this.STANDING: + default: + + this.currentState = this.STANDING; + this.editing = false; + motion.lastWalkStartTime = 0; + motion.curAnim = motion.selStand; + walkInterface.updateMenu(); + + // initialisation - runs at script startup only + if (motion.strideLength === 0) { + + motion.setGender(MALE); + if (motion.direction === BACKWARDS) { + motion.strideLength = motion.selWalk.calibration.strideLengthBackwards; + } else { + motion.strideLength = motion.selWalk.calibration.strideLengthForwards; + } + } + return; + } + } + } +})(); // end state object literal + +// constructor for animation Transition +Transition = function(lastAnimation, nextAnimation, reachPoses, transitionDuration, easingLower, easingUpper) { + + this.lastAnim = lastAnimation; // name of last animation + this.nextAnimation = nextAnimation; // name of next animation + if (lastAnimation === motion.selWalk || + nextAnimation === motion.selSideStepLeft || + nextAnimation === motion.selSideStepRight) { + // boolean - is the last animation a walking animation? + this.walkingAtStart = true; + } else { + this.walkingAtStart = false; + } + if (nextAnimation === motion.selWalk || + nextAnimation === motion.selSideStepLeft || + nextAnimation === motion.selSideStepRight) { + // boolean - is the next animation a walking animation? + this.walkingAtEnd = true; + } else { + this.walkingAtEnd = false; + } + this.reachPoses = reachPoses; // placeholder / stub: array of reach poses for squash and stretch techniques + this.transitionDuration = transitionDuration; // length of transition (seconds) + this.easingLower = easingLower; // Bezier curve handle (normalised) + this.easingUpper = easingUpper; // Bezier curve handle (normalised) + this.startTime = new Date().getTime(); // Starting timestamp (seconds) + this.progress = 0; // how far are we through the transition? + this.walkWheelIncrement = 3; // how much to turn the walkwheel each frame when transitioning to / from walking + this.walkWheelAdvance = 0; // how many degrees the walk wheel has been advanced during the transition + this.walkStopAngle = 0; // what angle should we stop the walk cycle? + +}; // end Transition constructor + + +walkAssets = (function () { + + // path to the sounds used for the footsteps + var _pathToSounds = 'https://s3.amazonaws.com/hifi-public/sounds/Footsteps/'; + + // read in the sounds + var _footsteps = []; + _footsteps.push(new Sound(_pathToSounds+"FootstepW2Left-12db.wav")); + _footsteps.push(new Sound(_pathToSounds+"FootstepW2Right-12db.wav")); + _footsteps.push(new Sound(_pathToSounds+"FootstepW3Left-12db.wav")); + _footsteps.push(new Sound(_pathToSounds+"FootstepW3Right-12db.wav")); + _footsteps.push(new Sound(_pathToSounds+"FootstepW5Left-12db.wav")); + _footsteps.push(new Sound(_pathToSounds+"FootstepW5Right-12db.wav")); + + // load the animation datafiles + Script.include(pathToAssets+"animations/dd-female-standard-walk-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-up-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-animation.js"); + Script.include(pathToAssets+"animations/dd-female-flying-down-animation.js"); + Script.include(pathToAssets+"animations/dd-female-standing-one-animation.js"); + Script.include(pathToAssets+"animations/dd-female-sidestep-left-animation.js"); + Script.include(pathToAssets+"animations/dd-female-sidestep-right-animation.js"); + Script.include(pathToAssets+"animations/dd-male-standard-walk-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-up-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-animation.js"); + Script.include(pathToAssets+"animations/dd-male-flying-down-animation.js"); + Script.include(pathToAssets+"animations/dd-male-standing-one-animation.js"); + Script.include(pathToAssets+"animations/dd-male-sidestep-left-animation.js"); + Script.include(pathToAssets+"animations/dd-male-sidestep-right-animation.js"); + + // read in the animation files + var _FemaleStandardWalkFile = new FemaleStandardWalk(); + var _femaleStandardWalk = _FemaleStandardWalkFile.loadAnimation(); + var _FemaleFlyingUpFile = new FemaleFlyingUp(); + var _femaleFlyingUp = _FemaleFlyingUpFile.loadAnimation(); + var _FemaleFlyingFile = new FemaleFlying(); + var _femaleFlying = _FemaleFlyingFile.loadAnimation(); + var _FemaleFlyingDownFile = new FemaleFlyingDown(); + var _femaleFlyingDown = _FemaleFlyingDownFile.loadAnimation(); + var _FemaleStandOneFile = new FemaleStandingOne(); + var _femaleStandOne = _FemaleStandOneFile.loadAnimation(); + var _FemaleSideStepLeftFile = new FemaleSideStepLeft(); + var _femaleSideStepLeft = _FemaleSideStepLeftFile.loadAnimation(); + var _FemaleSideStepRightFile = new FemaleSideStepRight(); + var _femaleSideStepRight = _FemaleSideStepRightFile.loadAnimation(); + var _MaleStandardWalkFile = new MaleStandardWalk(filter); + var _maleStandardWalk = _MaleStandardWalkFile.loadAnimation(); + var _MaleFlyingUpFile = new MaleFlyingUp(); + var _maleFlyingUp = _MaleFlyingUpFile.loadAnimation(); + var _MaleFlyingFile = new MaleFlying(); + var _maleFlying = _MaleFlyingFile.loadAnimation(); + var _MaleFlyingDownFile = new MaleFlyingDown(); + var _maleFlyingDown = _MaleFlyingDownFile.loadAnimation(); + var _MaleStandOneFile = new MaleStandingOne(); + var _maleStandOne = _MaleStandOneFile.loadAnimation(); + var _MaleSideStepLeftFile = new MaleSideStepLeft(); + var _maleSideStepLeft = _MaleSideStepLeftFile.loadAnimation(); + var _MaleSideStepRightFile = new MaleSideStepRight(); + var _maleSideStepRight = _MaleSideStepRightFile.loadAnimation(); + + return { + + // expose the sound assets + footsteps: _footsteps, + + // expose the animation assets + femaleStandardWalk: _femaleStandardWalk, + femaleFlyingUp: _femaleFlyingUp, + femaleFlying: _femaleFlying, + femaleFlyingDown: _femaleFlyingDown, + femaleStandOne: _femaleStandOne, + femaleSideStepLeft: _femaleSideStepLeft, + femaleSideStepRight: _femaleSideStepRight, + maleStandardWalk: _maleStandardWalk, + maleFlyingUp: _maleFlyingUp, + maleFlying: _maleFlying, + maleFlyingDown: _maleFlyingDown, + maleStandOne: _maleStandOne, + maleSideStepLeft: _maleSideStepLeft, + maleSideStepRight: _maleSideStepRight, + } +})(); \ No newline at end of file diff --git a/examples/libraries/walkFilters.js b/examples/libraries/walkFilters.js new file mode 100644 index 0000000000..98a7562bb4 --- /dev/null +++ b/examples/libraries/walkFilters.js @@ -0,0 +1,225 @@ +// +// walkFilters.js +// +// version 1.001 +// +// Created by David Wooldridge, Autumn 2014 +// +// Provides a variety of filters for use by the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +AveragingFilter = function(length) { + + //this.name = name; + this.pastValues = []; + + for(var i = 0; i < length; i++) { + this.pastValues.push(0); + } + + // single arg is the nextInputValue + this.process = function() { + + if (this.pastValues.length === 0 && arguments[0]) { + return arguments[0]; + } else if (arguments[0]) { + // apply quick and simple LP filtering + this.pastValues.push(arguments[0]); + this.pastValues.shift(); + var nextOutputValue = 0; + for (var ea in this.pastValues) nextOutputValue += this.pastValues[ea]; + return nextOutputValue / this.pastValues.length; + } else { + return 0; + } + }; +}; + +// 2nd order Butterworth LP filter - calculate coeffs here: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html +// provides LP filtering with a more stable frequency / phase response +ButterworthFilter = function(cutOff) { + + // cut off frequency = 5Hz + this.gain = 20.20612010; + this.coeffOne = -0.4775922501; + this.coeffTwo = 1.2796324250; + + // initialise the arrays + this.xv = []; + this.yv = []; + for(var i = 0; i < 3; i++) { + this.xv.push(0); + this.yv.push(0); + } + + // process values + this.process = function(nextInputValue) { + + this.xv[0] = this.xv[1]; + this.xv[1] = this.xv[2]; + this.xv[2] = nextInputValue / this.gain; + + this.yv[0] = this.yv[1]; + this.yv[1] = this.yv[2]; + this.yv[2] = (this.xv[0] + this.xv[2]) + + 2 * this.xv[1] + + (this.coeffOne * this.yv[0]) + + (this.coeffTwo * this.yv[1]); + + return this.yv[2]; + }; +}; // end Butterworth filter contructor + +// Add harmonics to a given sine wave to form square, sawtooth or triangle waves +// Geometric wave synthesis fundamentals taken from: http://hyperphysics.phy-astr.gsu.edu/hbase/audio/geowv.html +WaveSynth = function(waveShape, numHarmonics, smoothing) { + + this.numHarmonics = numHarmonics; + this.waveShape = waveShape; + this.averagingFilter = new AveragingFilter(smoothing); + + // NB: frequency in radians + this.shapeWave = function(frequency) { + + // make some shapes + var harmonics = 0; + var multiplier = 0; + var iterations = this.numHarmonics * 2 + 2; + if (this.waveShape === TRIANGLE) { + iterations++; + } + + for(var n = 2; n < iterations; n++) { + + switch(this.waveShape) { + + case SAWTOOTH: { + + multiplier = 1 / n; + harmonics += multiplier * Math.sin(n * frequency); + break; + } + + case TRIANGLE: { + + if (n % 2 === 1) { + var mulitplier = 1 / (n * n); + // multiply (4n-1)th harmonics by -1 + if (n === 3 || n === 7 || n === 11 || n === 15) { + mulitplier *= -1; + } + harmonics += mulitplier * Math.sin(n * frequency); + } + break; + } + + case SQUARE: { + + if (n % 2 === 1) { + multiplier = 1 / n; + harmonics += multiplier * Math.sin(n * frequency); + } + break; + } + } + } + + // smooth the result and return + return this.averagingFilter.process(harmonics); + }; +}; + +// Create a wave shape by summing pre-calcualted sinusoidal harmonics +HarmonicsFilter = function(magnitudes, phaseAngles) { + + this.magnitudes = magnitudes; + this.phaseAngles = phaseAngles; + + this.calculate = function(twoPiFT) { + + var harmonics = 0; + var numHarmonics = magnitudes.length; + + for(var n = 0; n < numHarmonics; n++) { + harmonics += this.magnitudes[n] * Math.cos(n * twoPiFT - this.phaseAngles[n]); + } + return harmonics; + }; +}; + +// the main filter object literal +filter = (function() { + + // Bezier private functions + function _B1(t) { return t * t * t }; + function _B2(t) { return 3 * t * t * (1 - t) }; + function _B3(t) { return 3 * t * (1 - t) * (1 - t) }; + function _B4(t) { return (1 - t) * (1 - t) * (1 - t) }; + + return { + + // helper methods + degToRad: function(degrees) { + + var convertedValue = degrees * Math.PI / 180; + return convertedValue; + }, + + radToDeg: function(radians) { + + var convertedValue = radians * 180 / Math.PI; + return convertedValue; + }, + + // these filters need instantiating, as they hold arrays of previous values + createAveragingFilter: function(length) { + + var newAveragingFilter = new AveragingFilter(length); + return newAveragingFilter; + }, + + createButterworthFilter: function(cutoff) { + + var newButterworthFilter = new ButterworthFilter(cutoff); + return newButterworthFilter; + }, + + createWaveSynth: function(waveShape, numHarmonics, smoothing) { + + var newWaveSynth = new WaveSynth(waveShape, numHarmonics, smoothing); + return newWaveSynth; + }, + + createHarmonicsFilter: function(magnitudes, phaseAngles) { + + var newHarmonicsFilter = new HarmonicsFilter(magnitudes, phaseAngles); + return newHarmonicsFilter; + }, + + + // the following filters do not need separate instances, as they hold no previous values + bezier: function(percent, C1, C2, C3, C4) { + + // Bezier functions for more natural transitions + // based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/ + var pos = {x: 0, y: 0}; + pos.x = C1.x * _B1(percent) + C2.x * _B2(percent) + C3.x * _B3(percent) + C4.x * _B4(percent); + pos.y = C1.y * _B1(percent) + C2.y * _B2(percent) + C3.y * _B3(percent) + C4.y * _B4(percent); + return pos; + }, + + // simple clipping filter (clips bottom of wave only, special case for hips y-axis skeleton offset) + clipTrough: function(inputValue, peak, strength) { + + var outputValue = inputValue * strength; + if (outputValue < -peak) { + outputValue = -peak; + } + return outputValue; + } + } + +})(); \ No newline at end of file diff --git a/examples/libraries/walkInterface.js b/examples/libraries/walkInterface.js new file mode 100644 index 0000000000..aa0b533101 --- /dev/null +++ b/examples/libraries/walkInterface.js @@ -0,0 +1,2690 @@ +// +// walkInterface.js +// +// version 1.001 +// +// Created by David Wooldridge, Autumn 2014 +// +// Presents the UI for the walk.js script v1.1 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +walkInterface = (function() { + + // controller element positions and dimensions + var _backgroundWidth = 350; + var _backgroundHeight = 700; + var _backgroundX = Window.innerWidth - _backgroundWidth - 58; + var _backgroundY = Window.innerHeight / 2 - _backgroundHeight / 2; + var _minSliderX = _backgroundX + 30; + var _sliderRangeX = 295 - 30; + var _jointsControlWidth = 200; + var _jointsControlHeight = 300; + var _jointsControlX = _backgroundX + _backgroundWidth / 2 - _jointsControlWidth / 2; + var _jointsControlY = _backgroundY + 242 - _jointsControlHeight / 2; + var _buttonsY = 20; // distance from top of panel to menu buttons + var _bigButtonsY = 408; // distance from top of panel to top of first big button + + // arrays of overlay names + var _sliderThumbOverlays = []; + var _backgroundOverlays = []; + var _buttonOverlays = []; + var _jointsControlOverlays = []; + var _bigbuttonOverlays = []; + + // reference to the internal state + var _state = { + editingTranslation: false + }; + + // reference to the Motion object + var _motion = null; + + var _walkAssets = null; + + // constants + var MAX_WALK_SPEED = 1257; + + // look and feel + var momentaryButtonTimer = null; + + // all slider controls have a range (with the exception of phase controls that are always +-180) + var _sliderRanges = { + "joints": [{ + "name": "hips", + "pitchRange": 12, + "yawRange": 18, + "rollRange": 12, + "pitchOffsetRange": 25, + "yawOffsetRange": 25, + "rollOffsetRange": 25, + "swayRange": 0.12, + "bobRange": 0.05, + "thrustRange": 0.05, + "swayOffsetRange": 0.25, + "bobOffsetRange": 0.25, + "thrustOffsetRange": 0.25 + }, { + "name": "upperLegs", + "pitchRange": 30, + "yawRange": 35, + "rollRange": 35, + "pitchOffsetRange": 20, + "yawOffsetRange": 20, + "rollOffsetRange": 20 + }, { + "name": "lowerLegs", + "pitchRange": 10, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 180, + "yawOffsetRange": 20, + "rollOffsetRange": 20 + }, { + "name": "feet", + "pitchRange": 10, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 180, + "yawOffsetRange": 50, + "rollOffsetRange": 50 + }, { + "name": "toes", + "pitchRange": 90, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 90, + "yawOffsetRange": 20, + "rollOffsetRange": 20 + }, { + "name": "spine", + "pitchRange": 40, + "yawRange": 40, + "rollRange": 40, + "pitchOffsetRange": 90, + "yawOffsetRange": 50, + "rollOffsetRange": 50 + }, { + "name": "spine1", + "pitchRange": 20, + "yawRange": 40, + "rollRange": 20, + "pitchOffsetRange": 90, + "yawOffsetRange": 50, + "rollOffsetRange": 50 + }, { + "name": "spine2", + "pitchRange": 20, + "yawRange": 40, + "rollRange": 20, + "pitchOffsetRange": 90, + "yawOffsetRange": 50, + "rollOffsetRange": 50 + }, { + "name": "shoulders", + "pitchRange": 35, + "yawRange": 40, + "rollRange": 20, + "pitchOffsetRange": 180, + "yawOffsetRange": 180, + "rollOffsetRange": 180 + }, { + "name": "upperArms", + "pitchRange": 90, + "yawRange": 90, + "rollRange": 90, + "pitchOffsetRange": 180, + "yawOffsetRange": 180, + "rollOffsetRange": 180 + }, { + "name": "lowerArms", + "pitchRange": 90, + "yawRange": 90, + "rollRange": 120, + "pitchOffsetRange": 180, + "yawOffsetRange": 180, + "rollOffsetRange": 180 + }, { + "name": "hands", + "pitchRange": 90, + "yawRange": 180, + "rollRange": 90, + "pitchOffsetRange": 180, + "yawOffsetRange": 180, + "rollOffsetRange": 180 + }, { + "name": "head", + "pitchRange": 20, + "yawRange": 20, + "rollRange": 20, + "pitchOffsetRange": 90, + "yawOffsetRange": 90, + "rollOffsetRange": 90 + }] + }; + + // load overlay images + var _controlsMinimisedTab = Overlays.addOverlay("image", { + x: Window.innerWidth - 58, + y: Window.innerHeight - 145, + width: 50, + height: 50, + imageURL: pathToAssets + 'overlay-images/ddao-minimise-tab.png', + visible: true, + alpha: 0.9 + }); + + var _controlsBackground = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackground); + + var _controlsBackgroundWalkEditStyles = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-styles.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditStyles); + + var _controlsBackgroundWalkEditTweaks = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-tweaks.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditTweaks); + + var _controlsBackgroundWalkEditHipTrans = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-translation.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditHipTrans); + + var _controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX, + y: _backgroundY, + width: _backgroundWidth, + height: _backgroundHeight + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-joints.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _backgroundOverlays.push(_controlsBackgroundWalkEditJoints); + + // load character joint selection control images + var _hipsJointsTranslation = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-hips-translation.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_hipsJointsTranslation); + + var _hipsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-hips.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_hipsJointControl); + + var _upperLegsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-upper-legs.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_upperLegsJointControl); + + var _lowerLegsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-lower-legs.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_lowerLegsJointControl); + + var _feetJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-feet.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_feetJointControl); + + var _toesJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-toes.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_toesJointControl); + + var _spineJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-spine.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_spineJointControl); + + var _spine1JointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-spine1.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_spine1JointControl); + + var _spine2JointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-spine2.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_spine2JointControl); + + var _shouldersJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-shoulders.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_shouldersJointControl); + + var _upperArmsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-upper-arms.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_upperArmsJointControl); + + var _forearmsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-forearms.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_forearmsJointControl); + + var _handsJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-hands.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_handsJointControl); + + var _headJointControl = Overlays.addOverlay("image", { + bounds: { + x: _jointsControlX, + y: _jointsControlY, + width: 200, + height: 300 + }, + imageURL: pathToAssets + "overlay-images/ddao-background-edit-head.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _jointsControlOverlays.push(_headJointControl); + + + // slider thumb overlays + var _sliderOne = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderOne); + + var _sliderTwo = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderTwo); + + var _sliderThree = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderThree); + + var _sliderFour = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderFour); + + var _sliderFive = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderFive); + + var _sliderSix = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderSix); + + var _sliderSeven = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderSeven); + + var _sliderEight = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderEight); + + var _sliderNine = Overlays.addOverlay("image", { + bounds: { + x: 0, + y: 0, + width: 25, + height: 25 + }, + imageURL: pathToAssets + "overlay-images/ddao-slider-handle.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _sliderThumbOverlays.push(_sliderNine); + + + // button overlays + var _onButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 20, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-on-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_onButton); + + var _offButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 20, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-off-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_offButton); + + var _configWalkButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-walk-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkButton); + + var _configWalkButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-walk-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkButtonSelected); + + var _configStandButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-stand-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configStandButton); + + var _configStandButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-stand-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configStandButtonSelected); + + var _configFlyingButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingButton); + + var _configFlyingButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingButtonSelected); + + var _configFlyingUpButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-up-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingUpButton); + + var _configFlyingUpButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-up-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingUpButtonSelected); + + var _configFlyingDownButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-down-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingDownButton); + + var _configFlyingDownButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-fly-down-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configFlyingDownButtonSelected); + + var _hideButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 272, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-hide-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_hideButton); + + var _hideButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 272, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-hide-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_hideButtonSelected); + + var _configWalkStylesButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-styles-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkStylesButton); + + var _configWalkStylesButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-styles-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkStylesButtonSelected); + + var _configWalkTweaksButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-tweaks-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkTweaksButton); + + var _configWalkTweaksButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 146, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-tweaks-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkTweaksButtonSelected); + + var _configSideStepLeftButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-sidestep-left-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configSideStepLeftButton); + + var _configSideStepLeftButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 83, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-sidestep-left-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configSideStepLeftButtonSelected); + + var _configSideStepRightButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-sidestep-right-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configSideStepRightButton); + + var _configSideStepRightButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-edit-sidestep-right-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configSideStepRightButtonSelected); + + var _configWalkJointsButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-joints-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkJointsButton); + + var _configWalkJointsButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 209, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-joints-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_configWalkJointsButtonSelected); + + var _backButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 272, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-back-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_backButton); + + var _backButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + 272, + y: _backgroundY + _buttonsY, + width: 60, + height: 47 + }, + imageURL: pathToAssets + "overlay-images/ddao-back-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _buttonOverlays.push(_backButtonSelected); + + // big button overlays - front panel + var _femaleBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-female-big-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_femaleBigButton); + + var _femaleBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-female-big-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_femaleBigButtonSelected); + + var _maleBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 60, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-male-big-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_maleBigButton); + + var _maleBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 60, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-male-big-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_maleBigButtonSelected); + + var _armsFreeBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 120, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-arms-free-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_armsFreeBigButton); + + var _armsFreeBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 120, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-arms-free-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_armsFreeBigButtonSelected); + + var _footstepsBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 180, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-footsteps-big-button.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_footstepsBigButton); + + var _footstepsBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY + 180, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-footsteps-big-button-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_footstepsBigButtonSelected); + + + // walk styles + _bigButtonsY = 121; + var _standardWalkBigButton = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-select-button-standard.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_standardWalkBigButton); + + var _standardWalkBigButtonSelected = Overlays.addOverlay("image", { + bounds: { + x: _backgroundX + _backgroundWidth / 2 - 115, + y: _backgroundY + _bigButtonsY, + width: 230, + height: 36 + }, + imageURL: pathToAssets + "overlay-images/ddao-walk-select-button-standard-selected.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1, + visible: false + }); + _bigbuttonOverlays.push(_standardWalkBigButtonSelected); + + // various show / hide GUI element functions + function minimiseDialog(minimise) { + + if (momentaryButtonTimer) { + Script.clearInterval(momentaryButtonTimer); + momentaryButtonTimer = null; + } + + if (minimise) { + setBackground(); + hideMenuButtons(); + setSliderThumbsVisible(false); + hideJointSelectors(); + initialiseFrontPanel(false); + Overlays.editOverlay(_controlsMinimisedTab, { + visible: true + }); + } else { + Overlays.editOverlay(_controlsMinimisedTab, { + visible: false + }); + } + }; + + function setBackground(backgroundID) { + for (var i in _backgroundOverlays) { + if (_backgroundOverlays[i] === backgroundID) { + Overlays.editOverlay(_backgroundOverlays[i], { + visible: true + }); + } else { + Overlays.editOverlay(_backgroundOverlays[i], { visible: false }); + } + } + }; + + // top row menu type buttons (on | walk | stand | fly | hide) + function hideMenuButtons() { + for (var i in _buttonOverlays) { + Overlays.editOverlay(_buttonOverlays[i], { visible: false }); + } + }; + + function hideJointSelectors() { + for (var i in _jointsControlOverlays) { + Overlays.editOverlay(_jointsControlOverlays[i], { + visible: false + }); + } + }; + + function setSliderThumbsVisible(thumbsVisible) { + for (var i = 0; i < _sliderThumbOverlays.length; i++) { + Overlays.editOverlay(_sliderThumbOverlays[i], { + visible: thumbsVisible + }); + } + }; + + function setButtonOverlayVisible(buttonOverlayName) { + for (var i in _buttonOverlays) { + if (_buttonOverlays[i] === buttonOverlayName) { + Overlays.editOverlay(buttonOverlayName, { visible: true }); + } + } + }; + + function initialiseFrontPanel(showButtons) { + + if (_motion.avatarGender === FEMALE) { + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_femaleBigButton, { + visible: false + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_maleBigButton, { + visible: showButtons + }); + + } else { + + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_femaleBigButton, { + visible: showButtons + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_maleBigButton, { + visible: false + }); + } + if (_motion.armsFree) { + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: false + }); + + } else { + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: showButtons + }); + } + if (_motion.makesFootStepSounds) { + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: showButtons + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: false + }); + + } else { + + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: showButtons + }); + } + }; + + function initialiseWalkStylesPanel(showButtons) { + + // set all big buttons to hidden, but skip the first 8, as are used by the front panel + for (var i = 8; i < _bigbuttonOverlays.length; i++) { + Overlays.editOverlay(_bigbuttonOverlays[i], { + visible: false + }); + } + + if (!showButtons) { + return; + } + + // set all the non-selected ones to showing + for (var i = 8; i < _bigbuttonOverlays.length; i += 2) { + Overlays.editOverlay(_bigbuttonOverlays[i], { visible: true }); + } + + // set the currently selected one + if (_motion.selWalk === _walkAssets.femaleStandardWalk || + _motion.selWalk === _walkAssets.maleStandardWalk) { + + Overlays.editOverlay(_standardWalkBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_standardWalkBigButton, { + visible: false + }); + } + }; + + function initialiseWalkTweaksPanel() { + + // sliders for commonly required walk adjustments + var i = 0; + var yLocation = _backgroundY + 71; + + // walk speed + var sliderXPos = _motion.curAnim.calibration.frequency / MAX_WALK_SPEED * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // lean (hips pitch offset) + sliderXPos = (((_sliderRanges.joints[0].pitchOffsetRange + _motion.curAnim.joints[0].pitchOffset) / 2) / + _sliderRanges.joints[0].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // stride (upper legs pitch) + sliderXPos = _motion.curAnim.joints[1].pitch / _sliderRanges.joints[1].pitchRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Legs separation (upper legs roll offset) + sliderXPos = (((_sliderRanges.joints[1].rollOffsetRange + _motion.curAnim.joints[1].rollOffset) / 2) / + _sliderRanges.joints[1].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Legs forward (upper legs pitch offset) + sliderXPos = (((_sliderRanges.joints[1].pitchOffsetRange + _motion.curAnim.joints[1].pitchOffset) / 2) / + _sliderRanges.joints[1].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Lower legs splay (lower legs roll offset) + sliderXPos = (((_sliderRanges.joints[2].rollOffsetRange + _motion.curAnim.joints[2].rollOffset) / 2) / + _sliderRanges.joints[2].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Arms forward (upper arms yaw offset) + sliderXPos = (((_sliderRanges.joints[9].yawOffsetRange + _motion.curAnim.joints[9].yawOffset) / 2) / + _sliderRanges.joints[9].yawOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Arms out (upper arm pitch offset) + sliderXPos = (((_sliderRanges.joints[9].pitchOffsetRange - _motion.curAnim.joints[9].pitchOffset) / 2) / + _sliderRanges.joints[9].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + + // Lower arms splay (lower arm pitch offset) + sliderXPos = (((_sliderRanges.joints[10].pitchOffsetRange - _motion.curAnim.joints[10].pitchOffset) / 2) / + _sliderRanges.joints[10].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 60, + visible: true + }); + }; + + function initialiseJointsEditingPanel() { + + var i = 0; + var yLocation = _backgroundY + 359; + hideJointSelectors(); + + if (_state.editingTranslation) { + + // display the joint control selector for hips translations + Overlays.editOverlay(_hipsJointsTranslation, {visible: true}); + + // Hips sway + var sliderXPos = _motion.curAnim.joints[0].sway / _sliderRanges.joints[0].swayRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Hips bob + sliderXPos = _motion.curAnim.joints[0].bob / _sliderRanges.joints[0].bobRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Hips thrust + sliderXPos = _motion.curAnim.joints[0].thrust / _sliderRanges.joints[0].thrustRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Sway Phase + sliderXPos = (90 + _motion.curAnim.joints[0].swayPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Bob Phase + sliderXPos = (90 + _motion.curAnim.joints[0].bobPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // Thrust Phase + sliderXPos = (90 + _motion.curAnim.joints[0].thrustPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // offset ranges are also -ve thr' zero to +ve, so we centre them + sliderXPos = (((_sliderRanges.joints[0].swayOffsetRange + _motion.curAnim.joints[0] + .swayOffset) / 2) / _sliderRanges.joints[0].swayOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[0].bobOffsetRange + _motion.curAnim.joints[0] + .bobOffset) / 2) / _sliderRanges.joints[0].bobOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[0].thrustOffsetRange + _motion.curAnim.joints[0] + .thrustOffset) / 2) / _sliderRanges.joints[0].thrustOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + } else { + + switch (_motion.curJointIndex) { + + case 0: + Overlays.editOverlay(_hipsJointControl, { + visible: true + }); + break; + case 1: + Overlays.editOverlay(_upperLegsJointControl, { + visible: true + }); + break; + case 2: + Overlays.editOverlay(_lowerLegsJointControl, { + visible: true + }); + break; + case 3: + Overlays.editOverlay(_feetJointControl, { + visible: true + }); + break; + case 4: + Overlays.editOverlay(_toesJointControl, { + visible: true + }); + break; + case 5: + Overlays.editOverlay(_spineJointControl, { + visible: true + }); + break; + case 6: + Overlays.editOverlay(_spine1JointControl, { + visible: true + }); + break; + case 7: + Overlays.editOverlay(_spine2JointControl, { + visible: true + }); + break; + case 8: + Overlays.editOverlay(_shouldersJointControl, { + visible: true + }); + break; + case 9: + Overlays.editOverlay(_upperArmsJointControl, { + visible: true + }); + break; + case 10: + Overlays.editOverlay(_forearmsJointControl, { + visible: true + }); + break; + case 11: + Overlays.editOverlay(_handsJointControl, { + visible: true + }); + break; + case 12: + Overlays.editOverlay(_headJointControl, { + visible: true + }); + break; + } + + var sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].pitch / + _sliderRanges.joints[_motion.curJointIndex].pitchRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].yaw / + _sliderRanges.joints[_motion.curJointIndex].yawRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = _motion.curAnim.joints[_motion.curJointIndex].roll / + _sliderRanges.joints[_motion.curJointIndex].rollRange * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // set phases (full range, -180 to 180) + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].pitchPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].yawPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (90 + _motion.curAnim.joints[_motion.curJointIndex].rollPhase / 2) / 180 * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + // offset ranges are also -ve thr' zero to +ve, so we offset + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].pitchOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].yawOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].yawOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].yawOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + + sliderXPos = (((_sliderRanges.joints[_motion.curJointIndex].rollOffsetRange + + _motion.curAnim.joints[_motion.curJointIndex].rollOffset) / 2) / + _sliderRanges.joints[_motion.curJointIndex].rollOffsetRange) * _sliderRangeX; + Overlays.editOverlay(_sliderThumbOverlays[++i], { + x: _minSliderX + sliderXPos, + y: yLocation += 30, + visible: true + }); + } + }; + + // mouse event handlers + var _movingSliderOne = false; + var _movingSliderTwo = false; + var _movingSliderThree = false; + var _movingSliderFour = false; + var _movingSliderFive = false; + var _movingSliderSix = false; + var _movingSliderSeven = false; + var _movingSliderEight = false; + var _movingSliderNine = false; + + function mousePressEvent(event) { + + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + + if (_state.currentState === _state.EDIT_WALK_JOINTS || + _state.currentState === _state.EDIT_STANDING || + _state.currentState === _state.EDIT_FLYING || + _state.currentState === _state.EDIT_FLYING_UP || + _state.currentState === _state.EDIT_FLYING_DOWN || + _state.currentState === _state.EDIT_SIDESTEP_LEFT || + _state.currentState === _state.EDIT_SIDESTEP_RIGHT) { + + // check for new joint selection and update display accordingly + var clickX = event.x - _backgroundX - 75; + var clickY = event.y - _backgroundY - 92; + + if (clickX > 60 && clickX < 120 && clickY > 123 && clickY < 155) { + _motion.curJointIndex = 0; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 63 && clickX < 132 && clickY > 156 && clickY < 202) { + _motion.curJointIndex = 1; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 203 && clickY < 250) { + _motion.curJointIndex = 2; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 250 && clickY < 265) { + _motion.curJointIndex = 3; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 58 && clickX < 137 && clickY > 265 && clickY < 280) { + _motion.curJointIndex = 4; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 78 && clickX < 121 && clickY > 111 && clickY < 128) { + _motion.curJointIndex = 5; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 78 && clickX < 128 && clickY > 89 && clickY < 111) { + _motion.curJointIndex = 6; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 85 && clickX < 118 && clickY > 77 && clickY < 94) { + _motion.curJointIndex = 7; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 64 && clickX < 125 && clickY > 55 && clickY < 77) { + _motion.curJointIndex = 8; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 44 && clickX < 73 && clickY > 71 && clickY < 94) || + (clickX > 125 && clickX < 144 && clickY > 71 && clickY < 94)) { + _motion.curJointIndex = 9; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 28 && clickX < 57 && clickY > 94 && clickY < 119) || + (clickX > 137 && clickX < 170 && clickY > 97 && clickY < 114)) { + _motion.curJointIndex = 10; + initialiseJointsEditingPanel(); + return; + + } else if ((clickX > 18 && clickX < 37 && clickY > 115 && clickY < 136) || + (clickX > 157 && clickX < 182 && clickY > 115 && clickY < 136)) { + _motion.curJointIndex = 11; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 81 && clickX < 116 && clickY > 12 && clickY < 53) { + _motion.curJointIndex = 12; + initialiseJointsEditingPanel(); + return; + + } else if (clickX > 188 && clickX < 233 && clickY > 6 && clickY < 34) { + + // translation editing radio selection + if (_state.editingTranslation) { + + hideJointSelectors(); + setBackground(_controlsBackgroundWalkEditJoints); + _state.editingTranslation = false; + + } else { + + hideJointSelectors(); + setBackground(_controlsBackgroundWalkEditHipTrans); + _state.editingTranslation = true; + } + initialiseJointsEditingPanel(); + return; + } + } + + switch (clickedOverlay) { + + case _offButton: + + _state.powerOn = true; + Overlays.editOverlay(_offButton, { + visible: false + }); + Overlays.editOverlay(_onButton, { + visible: true + }); + _state.setInternalState(state.STANDING); + return; + + case _controlsMinimisedTab: + + _state.minimised = false; + minimiseDialog(_state.minimised); + _state.setInternalState(_state.STANDING); + return; + + case _hideButton: + case _hideButtonSelected: + + Overlays.editOverlay(_hideButton, {visible: false}); + Overlays.editOverlay(_hideButtonSelected, {visible: true}); + _state.minimised = true; + momentaryButtonTimer = Script.setInterval(function() { + minimiseDialog(_state.minimised); + }, 80); + return; + + case _backButton: + + Overlays.editOverlay(_backButton, { + visible: false + }); + Overlays.editOverlay(_backButtonSelected, { + visible: true + }); + momentaryButtonTimer = Script.setInterval(function() { + + _state.setInternalState(_state.STANDING); + Overlays.editOverlay(_backButton, { + visible: false + }); + Overlays.editOverlay(_backButtonSelected, { + visible: false + }); + Script.clearInterval(momentaryButtonTimer); + momentaryButtonTimer = null; + }, 80); + return; + + case _footstepsBigButton: + + _motion.makesFootStepSounds = true; + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_footstepsBigButton, { + visible: false + }); + return; + + case _footstepsBigButtonSelected: + + _motion.makesFootStepSounds = false; + Overlays.editOverlay(_footstepsBigButton, { + visible: true + }); + Overlays.editOverlay(_footstepsBigButtonSelected, { + visible: false + }); + return; + + case _femaleBigButton: + case _maleBigButtonSelected: + + _motion.setGender(FEMALE); + + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_femaleBigButton, { + visible: false + }); + Overlays.editOverlay(_maleBigButton, { + visible: true + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: false + }); + return; + + case _maleBigButton: + case _femaleBigButtonSelected: + + _motion.setGender(MALE); + + Overlays.editOverlay(_femaleBigButton, { + visible: true + }); + Overlays.editOverlay(_femaleBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_maleBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_maleBigButton, { + visible: false + }); + return; + + case _armsFreeBigButton: + + _motion.armsFree = true; + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: true + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: false + }); + return; + + case _armsFreeBigButtonSelected: + + _motion.armsFree = false; + + Overlays.editOverlay(_armsFreeBigButtonSelected, { + visible: false + }); + Overlays.editOverlay(_armsFreeBigButton, { + visible: true + }); + return; + + case _standardWalkBigButton: + + if (_motion.avatarGender === FEMALE) { + _motion.selWalk = _motion.femaleStandardWalk; + } else { + _motion.selWalk = _motion.maleStandardWalk; + } + _motion.curAnim = _motion.selWalk; + initialiseWalkStylesPanel(true); + return; + + case _standardWalkBigButtonSelected: + + // toggle forwards / backwards walk display + if (_motion.direction === FORWARDS) { + _motion.direction = BACKWARDS; + } else { + _motion.direction = FORWARDS; + } + return; + + case _sliderOne: + + _movingSliderOne = true; + return; + + case _sliderTwo: + + _movingSliderTwo = true; + return; + + case _sliderThree: + + _movingSliderThree = true; + return; + + case _sliderFour: + + _movingSliderFour = true; + return; + + case _sliderFive: + + _movingSliderFive = true; + return; + + case _sliderSix: + + _movingSliderSix = true; + return; + + case _sliderSeven: + + _movingSliderSeven = true; + return; + + case _sliderEight: + + _movingSliderEight = true; + return; + + case _sliderNine: + + _movingSliderNine = true; + return; + + case _configWalkButtonSelected: + case _configStandButtonSelected: + case _configSideStepLeftButtonSelected: + case _configSideStepRightButtonSelected: + case _configFlyingButtonSelected: + case _configFlyingUpButtonSelected: + case _configFlyingDownButtonSelected: + case _configWalkStylesButtonSelected: + case _configWalkTweaksButtonSelected: + case _configWalkJointsButtonSelected: + + // exit edit modes + _motion.curAnim = _motion.selStand; + _state.setInternalState(_state.STANDING); + return; + + case _onButton: + + _state.powerOn = false; + _state.setInternalState(state.STANDING); + Overlays.editOverlay(_offButton, { + visible: true + }); + Overlays.editOverlay(_onButton, { + visible: false + }); + return; + + case _backButton: + case _backButtonSelected: + + Overlays.editOverlay(_backButton, { + visible: false + }); + Overlays.editOverlay(_backButtonSelected, { + visible: false + }); + _state.setInternalState(_state.STANDING); + return; + + case _configWalkStylesButton: + + _state.setInternalState(_state.EDIT_WALK_STYLES); + return; + + case _configWalkTweaksButton: + + _state.setInternalState(_state.EDIT_WALK_TWEAKS); + return; + + case _configWalkJointsButton: + + _state.setInternalState(_state.EDIT_WALK_JOINTS); + return; + + case _configWalkButton: + + _state.setInternalState(_state.EDIT_WALK_STYLES); + return; + + case _configStandButton: + + _state.setInternalState(_state.EDIT_STANDING); + return; + + case _configSideStepLeftButton: + + _state.setInternalState(_state.EDIT_SIDESTEP_LEFT); + return; + + case _configSideStepRightButton: + + _state.setInternalState(_state.EDIT_SIDESTEP_RIGHT); + return; + + case _configFlyingButton: + + _state.setInternalState(_state.EDIT_FLYING); + return; + + case _configFlyingUpButton: + + _state.setInternalState(_state.EDIT_FLYING_UP); + return; + + case _configFlyingDownButton: + + _state.setInternalState(_state.EDIT_FLYING_DOWN); + return; + } + }; + + function mouseMoveEvent(event) { + + // workaround for bug (https://worklist.net/20160) + if ((event.x > 310 && event.x < 318 && event.y > 1350 && event.y < 1355) || + (event.x > 423 && event.x < 428 && event.y > 1505 && event.y < 1508 )) { + return; + } + + if (_state.currentState === _state.EDIT_WALK_JOINTS || + _state.currentState === _state.EDIT_STANDING || + _state.currentState === _state.EDIT_FLYING || + _state.currentState === _state.EDIT_FLYING_UP || + _state.currentState === _state.EDIT_FLYING_DOWN || + _state.currentState === _state.EDIT_SIDESTEP_LEFT || + _state.currentState === _state.EDIT_SIDESTEP_RIGHT) { + + var thumbClickOffsetX = event.x - _minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / _sliderRangeX; + if (thumbPositionNormalised < 0) { + thumbPositionNormalised = 0; + } else if (thumbPositionNormalised > 1) { + thumbPositionNormalised = 1; + } + var sliderX = thumbPositionNormalised * _sliderRangeX; // sets range + + if (_movingSliderOne) { + + // currently selected joint pitch or sway + Overlays.editOverlay(_sliderOne, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + _motion.curAnim.joints[0].sway = + thumbPositionNormalised * _sliderRanges.joints[0].swayRange; + } else { + _motion.curAnim.joints[_motion.curJointIndex].pitch = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].pitchRange; + } + + } else if (_movingSliderTwo) { + + // currently selected joint yaw or bob + Overlays.editOverlay(_sliderTwo, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + _motion.curAnim.joints[0].bob = + thumbPositionNormalised * _sliderRanges.joints[0].bobRange; + } else { + _motion.curAnim.joints[_motion.curJointIndex].yaw = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].yawRange; + } + + } else if (_movingSliderThree) { + + // currently selected joint roll or thrust + Overlays.editOverlay(_sliderThree, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + _motion.curAnim.joints[0].thrust = + thumbPositionNormalised * _sliderRanges.joints[0].thrustRange; + } else { + _motion.curAnim.joints[_motion.curJointIndex].roll = + thumbPositionNormalised * _sliderRanges.joints[_motion.curJointIndex].rollRange; + } + + } else if (_movingSliderFour) { + + // currently selected joint pitch phase + Overlays.editOverlay(_sliderFour, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + _motion.curAnim.joints[0].swayPhase = newPhase; + } else { + _motion.curAnim.joints[_motion.curJointIndex].pitchPhase = newPhase; + } + + } else if (_movingSliderFive) { + + // currently selected joint yaw phase; + Overlays.editOverlay(_sliderFive, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + _motion.curAnim.joints[0].bobPhase = newPhase; + } else { + _motion.curAnim.joints[_motion.curJointIndex].yawPhase = newPhase; + } + + } else if (_movingSliderSix) { + + // currently selected joint roll phase + Overlays.editOverlay(_sliderSix, { + x: sliderX + _minSliderX + }); + + var newPhase = 360 * thumbPositionNormalised - 180; + + if (_state.editingTranslation) { + _motion.curAnim.joints[0].thrustPhase = newPhase; + } else { + _motion.curAnim.joints[_motion.curJointIndex].rollPhase = newPhase; + } + + } else if (_movingSliderSeven) { + + // currently selected joint pitch offset + Overlays.editOverlay(_sliderSeven, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[0].swayOffsetRange; + _motion.curAnim.joints[0].swayOffset = newOffset; + } else { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].pitchOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].pitchOffset = newOffset; + } + + } else if (_movingSliderEight) { + + // currently selected joint yaw offset + Overlays.editOverlay(_sliderEight, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 *_sliderRanges.joints[0].bobOffsetRange; + _motion.curAnim.joints[0].bobOffset = newOffset; + } else { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].yawOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].yawOffset = newOffset; + } + + } else if (_movingSliderNine) { + + // currently selected joint roll offset + Overlays.editOverlay(_sliderNine, { + x: sliderX + _minSliderX + }); + if (_state.editingTranslation) { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[0].thrustOffsetRange; + _motion.curAnim.joints[0].thrustOffset = newOffset; + } else { + var newOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[_motion.curJointIndex].rollOffsetRange; + _motion.curAnim.joints[_motion.curJointIndex].rollOffset = newOffset; + } + } + + // end if editing joints + + } else if (_state.currentState === _state.EDIT_WALK_TWEAKS) { + + // sliders for commonly required walk adjustments + var thumbClickOffsetX = event.x - _minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / _sliderRangeX; + if (thumbPositionNormalised < 0) thumbPositionNormalised = 0; + if (thumbPositionNormalised > 1) thumbPositionNormalised = 1; + var sliderX = thumbPositionNormalised * _sliderRangeX; // sets range + + if (_movingSliderOne) { + // walk speed + Overlays.editOverlay(_sliderOne, { + x: sliderX + _minSliderX + }); + _motion.curAnim.calibration.frequency = thumbPositionNormalised * MAX_WALK_SPEED; + } else if (_movingSliderTwo) { + // lean (hips pitch offset) + Overlays.editOverlay(_sliderTwo, { + x: sliderX + _minSliderX + }); + var newOffset = (thumbPositionNormalised - 0.5) * 2 * _sliderRanges.joints[0].pitchOffsetRange; + _motion.curAnim.joints[0].pitchOffset = newOffset; + } else if (_movingSliderThree) { + // stride (upper legs pitch) + Overlays.editOverlay(_sliderThree, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].pitch = thumbPositionNormalised * _sliderRanges.joints[1].pitchRange; + } else if (_movingSliderFour) { + // legs separation (upper legs roll) + Overlays.editOverlay(_sliderFour, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].rollOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[1].rollOffsetRange; + } else if (_movingSliderFive) { + // legs forward (lower legs pitch offset) + Overlays.editOverlay(_sliderFive, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[1].pitchOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[1].pitchOffsetRange; + } else if (_movingSliderSix) { + // lower legs splay (lower legs roll offset) + Overlays.editOverlay(_sliderSix, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[2].rollOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[2].rollOffsetRange; + + } else if (_movingSliderSeven) { + // arms forward (upper arms yaw offset) + Overlays.editOverlay(_sliderSeven, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[9].yawOffset = (thumbPositionNormalised - 0.5) * + 2 * _sliderRanges.joints[9].yawOffsetRange; + } else if (_movingSliderEight) { + // arms out (upper arm pitch offset) + Overlays.editOverlay(_sliderEight, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[9].pitchOffset = (thumbPositionNormalised - 0.5) * + -2 * _sliderRanges.joints[9].pitchOffsetRange; + } else if (_movingSliderNine) { + // lower arms splay (lower arm pitch offset) + Overlays.editOverlay(_sliderNine, { + x: sliderX + _minSliderX + }); + _motion.curAnim.joints[10].pitchOffset = (thumbPositionNormalised - 0.5) * + -2 * _sliderRanges.joints[10].pitchOffsetRange; + } + } // if tweaking + }; + + function mouseReleaseEvent(event) { + + if (_movingSliderOne) { + _movingSliderOne = false; + } else if (_movingSliderTwo) { + _movingSliderTwo = false; + } else if (_movingSliderThree) { + _movingSliderThree = false; + } else if (_movingSliderFour) { + _movingSliderFour = false; + } else if (_movingSliderFive) { + _movingSliderFive = false; + } else if (_movingSliderSix) { + _movingSliderSix = false; + } else if (_movingSliderSeven) { + _movingSliderSeven = false; + } else if (_movingSliderEight) { + _movingSliderEight = false; + } else if (_movingSliderNine) { + _movingSliderNine = false; + } + }; + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + + // Script ending + Script.scriptEnding.connect(function() { + + // delete the background overlays + for (var i in _backgroundOverlays) { + Overlays.deleteOverlay(_backgroundOverlays[i]); + } + // delete the button overlays + for (var i in _buttonOverlays) { + Overlays.deleteOverlay(_buttonOverlays[i]); + } + // delete the slider thumb overlays + for (var i in _sliderThumbOverlays) { + Overlays.deleteOverlay(_sliderThumbOverlays[i]); + } + // delete the character joint control overlays + for (var i in _jointsControlOverlays) { + Overlays.deleteOverlay(_jointsControlOverlays[i]); + } + // delete the big button overlays + for (var i in _bigbuttonOverlays) { + Overlays.deleteOverlay(_bigbuttonOverlays[i]); + } + // delete the mimimised tab + Overlays.deleteOverlay(_controlsMinimisedTab); + }); + + // public methods + return { + + // gather references to objects from the walk.js script + initialise: function(state, motion, walkAssets) { + + _state = state; + _motion = motion; + _walkAssets = walkAssets; + }, + + updateMenu: function() { + + if (!_state.minimised) { + + switch (_state.currentState) { + + case _state.EDIT_WALK_STYLES: + case _state.EDIT_WALK_TWEAKS: + case _state.EDIT_WALK_JOINTS: { + + hideMenuButtons(); + initialiseFrontPanel(false); + hideJointSelectors(); + + if (_state.currentState === _state.EDIT_WALK_STYLES) { + + setBackground(_controlsBackgroundWalkEditStyles); + initialiseWalkStylesPanel(true); + setSliderThumbsVisible(false); + hideJointSelectors(); + setButtonOverlayVisible(_configWalkStylesButtonSelected); + setButtonOverlayVisible(_configWalkTweaksButton); + setButtonOverlayVisible(_configWalkJointsButton); + + } else if (_state.currentState === _state.EDIT_WALK_TWEAKS) { + + setBackground(_controlsBackgroundWalkEditTweaks); + initialiseWalkStylesPanel(false); + setSliderThumbsVisible(true); + hideJointSelectors(); + initialiseWalkTweaksPanel(); + setButtonOverlayVisible(_configWalkStylesButton); + setButtonOverlayVisible(_configWalkTweaksButtonSelected); + setButtonOverlayVisible(_configWalkJointsButton); + + } else if (_state.currentState === _state.EDIT_WALK_JOINTS) { + + if (_state.editingTranslation) { + setBackground(_controlsBackgroundWalkEditHipTrans); + } else { + setBackground(_controlsBackgroundWalkEditJoints); + } + + initialiseWalkStylesPanel(false); + setSliderThumbsVisible(true); + setButtonOverlayVisible(_configWalkStylesButton); + setButtonOverlayVisible(_configWalkTweaksButton); + setButtonOverlayVisible(_configWalkJointsButtonSelected); + initialiseJointsEditingPanel(); + } + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + } + + case _state.EDIT_STANDING: + case _state.EDIT_SIDESTEP_LEFT: + case _state.EDIT_SIDESTEP_RIGHT: { + + if (_state.editingTranslation) { + setBackground(_controlsBackgroundWalkEditHipTrans); + } else { + setBackground(_controlsBackgroundWalkEditJoints); + } + hideMenuButtons(); + initialiseWalkStylesPanel(false); + initialiseFrontPanel(false); + + if (_state.currentState === _state.EDIT_SIDESTEP_LEFT) { + + setButtonOverlayVisible(_configSideStepRightButton); + setButtonOverlayVisible(_configSideStepLeftButtonSelected); + setButtonOverlayVisible(_configStandButton); + + } else if (_state.currentState === _state.EDIT_SIDESTEP_RIGHT) { + + setButtonOverlayVisible(_configSideStepRightButtonSelected); + setButtonOverlayVisible(_configSideStepLeftButton); + setButtonOverlayVisible(_configStandButton); + + } else if (_state.currentState === _state.EDIT_STANDING) { + + setButtonOverlayVisible(_configSideStepRightButton); + setButtonOverlayVisible(_configSideStepLeftButton); + setButtonOverlayVisible(_configStandButtonSelected); + } + initialiseJointsEditingPanel(); + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + } + + case _state.EDIT_FLYING: + case _state.EDIT_FLYING_UP: + case _state.EDIT_FLYING_DOWN: { + + setBackground(_controlsBackgroundWalkEditJoints); + hideMenuButtons(); + initialiseWalkStylesPanel(false); + initialiseFrontPanel(false); + if (_state.currentState === _state.EDIT_FLYING) { + + setButtonOverlayVisible(_configFlyingUpButton); + setButtonOverlayVisible(_configFlyingDownButton); + setButtonOverlayVisible(_configFlyingButtonSelected); + + } else if (_state.currentState === _state.EDIT_FLYING_UP) { + + setButtonOverlayVisible(_configFlyingUpButtonSelected); + setButtonOverlayVisible(_configFlyingDownButton); + setButtonOverlayVisible(_configFlyingButton); + + } else if (_state.currentState === _state.EDIT_FLYING_DOWN) { + + setButtonOverlayVisible(_configFlyingUpButton); + setButtonOverlayVisible(_configFlyingDownButtonSelected); + setButtonOverlayVisible(_configFlyingButton); + } + initialiseJointsEditingPanel(); + setButtonOverlayVisible(_onButton); + setButtonOverlayVisible(_backButton); + return; + } + + case _state.STANDING: + case _state.WALKING: + case _state.FLYING: + case _state.SIDE_STEP: + default: { + + hideMenuButtons(); + hideJointSelectors(); + setBackground(_controlsBackground); + if (_state.powerOn) { + setButtonOverlayVisible(_onButton); + } else { + setButtonOverlayVisible(_offButton); + } + setButtonOverlayVisible(_configWalkButton); + setButtonOverlayVisible(_configStandButton); + setButtonOverlayVisible(_configFlyingButton); + setButtonOverlayVisible(_hideButton); + setSliderThumbsVisible(false); + initialiseFrontPanel(true); + initialiseWalkStylesPanel(false); + return; + } + } + } + } + }; // end public methods (return) +})(); \ No newline at end of file diff --git a/examples/newEditEntities.js b/examples/newEditEntities.js index 57f3f29670..68e0d0c146 100644 --- a/examples/newEditEntities.js +++ b/examples/newEditEntities.js @@ -35,6 +35,10 @@ var entityPropertyDialogBox = EntityPropertyDialogBox; Script.include("libraries/entityCameraTool.js"); var cameraManager = new CameraManager(); +Script.include("libraries/gridTool.js"); +var grid = Grid(); +gridTool = GridTool({ horizontalGrid: grid }); + selectionManager.setEventListener(selectionDisplay.updateHandles); var windowDimensions = Controller.getViewportDimensions(); @@ -51,11 +55,13 @@ var wantEntityGlow = false; var SPAWN_DISTANCE = 1; var DEFAULT_DIMENSION = 0.20; +var MENU_GRID_TOOL_ENABLED = 'Grid Tool'; var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled"; var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus"; +var SETTING_GRID_TOOL_ENABLED = 'GridToolEnabled'; var modelURLs = [ HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", @@ -262,10 +268,12 @@ var toolBar = (function () { if (activeButton === toolBar.clicked(clickedOverlay)) { isActive = !isActive; if (!isActive) { + gridTool.setVisible(false); selectionManager.clearSelections(); cameraManager.disable(); } else { cameraManager.enable(); + gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); } return true; } @@ -597,7 +605,9 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Import Models", shortcutKey: "CTRL+META+I", afterItem: "Export Models" }); Menu.addMenuItem({ menuName: "Developer", menuItemName: "Debug Ryans Rotation Problems", isCheckable: true }); - Menu.addMenuItem({ menuName: "View", menuItemName: MENU_INSPECT_TOOL_ENABLED, afterItem: "Edit Entities Help...", + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_GRID_TOOL_ENABLED, afterItem: "Edit Entities Help...", isCheckable: true, + isChecked: Settings.getValue(SETTING_GRID_TOOL_ENABLED) == 'true'}); + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_INSPECT_TOOL_ENABLED, afterItem: MENU_GRID_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_INSPECT_TOOL_ENABLED) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_INSPECT_TOOL_ENABLED, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); @@ -623,6 +633,8 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Import Models"); Menu.removeMenuItem("Developer", "Debug Ryans Rotation Problems"); + Settings.setValue(SETTING_GRID_TOOL_ENABLED, Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); + Menu.removeMenuItem("View", MENU_GRID_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); } @@ -734,6 +746,10 @@ function handeMenuEvent(menuItem) { } } else if (menuItem == "Import Models") { modelImporter.doImport(); + } else if (menuItem == MENU_GRID_TOOL_ENABLED) { + if (isActive) { + gridTool.setVisible(Menu.isOptionChecked(MENU_GRID_TOOL_ENABLED)); + } } tooltip.show(false); } @@ -759,25 +775,32 @@ Controller.keyReleaseEvent.connect(function (event) { if (isActive) { cameraManager.enable(); } + } else if (event.text == 'g') { + if (isActive && selectionManager.hasSelection()) { + var newPosition = selectionManager.worldPosition; + newPosition = Vec3.subtract(newPosition, { x: 0, y: selectionManager.worldDimensions.y * 0.5, z: 0 }); + grid.setPosition(newPosition); + } } else if (isActive) { var delta = null; + var increment = event.isShifted ? grid.getMajorIncrement() : grid.getMinorIncrement(); if (event.text == 'UP') { if (event.isControl || event.isAlt) { - delta = { x: 0, y: 1, z: 0 }; + delta = { x: 0, y: increment, z: 0 }; } else { - delta = { x: 0, y: 0, z: -1 }; + delta = { x: 0, y: 0, z: -increment }; } } else if (event.text == 'DOWN') { if (event.isControl || event.isAlt) { - delta = { x: 0, y: -1, z: 0 }; + delta = { x: 0, y: -increment, z: 0 }; } else { - delta = { x: 0, y: 0, z: 1 }; + delta = { x: 0, y: 0, z: increment }; } } else if (event.text == 'LEFT') { - delta = { x: -1, y: 0, z: 0 }; + delta = { x: -increment, y: 0, z: 0 }; } else if (event.text == 'RIGHT') { - delta = { x: 1, y: 0, z: 0 }; + delta = { x: increment, y: 0, z: 0 }; } if (delta != null) { diff --git a/examples/walk.js b/examples/walk.js index ac0a2b1d39..5a0df72f26 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,3853 +1,2613 @@ // // walk.js // -// version 1.007b +// version 1.1 // -// Created by Davedub, August / September 2014 +// Created by David Wooldridge, Autumn 2014 +// +// Animates an avatar using procedural animation techniques // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// path to the animation files -var pathToAnimFiles = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/animation-files/'; // working (but only without https) - -// path to the images used for the overlays -var pathToOverlays = 'http://s3-us-west-1.amazonaws.com/highfidelity-public/procedural-animator/overlays/'; // working (but only without https) - -// path to the sounds used for the footsteps -var pathToSounds = 'http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Footsteps/'; - -// load the animation datafiles -Script.include(pathToAnimFiles+"dd-female-strut-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-female-flying-up-animation.js"); -Script.include(pathToAnimFiles+"dd-female-flying-animation.js"); -Script.include(pathToAnimFiles+"dd-female-flying-down-animation.js"); -Script.include(pathToAnimFiles+"dd-female-standing-one-animation.js"); -Script.include(pathToAnimFiles+"dd-female-sidestep-left-animation.js"); -Script.include(pathToAnimFiles+"dd-female-sidestep-right-animation.js"); -Script.include(pathToAnimFiles+"dd-male-strut-walk-animation.js"); -Script.include(pathToAnimFiles+"dd-male-flying-up-animation.js"); -Script.include(pathToAnimFiles+"dd-male-flying-animation.js"); -Script.include(pathToAnimFiles+"dd-male-flying-down-animation.js"); -Script.include(pathToAnimFiles+"dd-male-standing-one-animation.js"); -Script.include(pathToAnimFiles+"dd-male-sidestep-left-animation.js"); -Script.include(pathToAnimFiles+"dd-male-sidestep-right-animation.js"); - -// read in the data from the animation files -var FemaleStrutWalkFile = new FemaleStrutWalk(); -var femaleStrutWalk = FemaleStrutWalkFile.loadAnimation(); -var FemaleFlyingUpFile = new FemaleFlyingUp(); -var femaleFlyingUp = FemaleFlyingUpFile.loadAnimation(); -var FemaleFlyingFile = new FemaleFlying(); -var femaleFlying = FemaleFlyingFile.loadAnimation(); -var FemaleFlyingDownFile = new FemaleFlyingDown(); -var femaleFlyingDown = FemaleFlyingDownFile.loadAnimation(); -var FemaleStandOneFile = new FemaleStandingOne(); -var femaleStandOne = FemaleStandOneFile.loadAnimation(); -var FemaleSideStepLeftFile = new FemaleSideStepLeft(); -var femaleSideStepLeft = FemaleSideStepLeftFile.loadAnimation(); -var FemaleSideStepRightFile = new FemaleSideStepRight(); -var femaleSideStepRight = FemaleSideStepRightFile.loadAnimation(); -var MaleStrutWalkFile = new MaleStrutWalk(); -var maleStrutWalk = MaleStrutWalkFile.loadAnimation(); -var MaleFlyingUpFile = new MaleFlyingUp(); -var maleFlyingUp = MaleFlyingUpFile.loadAnimation(); -var MaleFlyingFile = new MaleFlying(); -var maleFlying = MaleFlyingFile.loadAnimation(); -var MaleFlyingDownFile = new MaleFlyingDown(); -var maleFlyingDown = MaleFlyingDownFile.loadAnimation(); -var MaleStandOneFile = new MaleStandingOne(); -var maleStandOne = MaleStandOneFile.loadAnimation(); -var MaleSideStepLeftFile = new MaleSideStepLeft(); -var maleSideStepLeft = MaleSideStepLeftFile.loadAnimation(); -var MaleSideStepRightFile = new MaleSideStepRight(); -var maleSideStepRight = MaleSideStepRightFile.loadAnimation(); - -// read in the sounds -var footsteps = []; -footsteps.push(new Sound(pathToSounds+"FootstepW2Left-12db.wav")); -footsteps.push(new Sound(pathToSounds+"FootstepW2Right-12db.wav")); -footsteps.push(new Sound(pathToSounds+"FootstepW3Left-12db.wav")); -footsteps.push(new Sound(pathToSounds+"FootstepW3Right-12db.wav")); -footsteps.push(new Sound(pathToSounds+"FootstepW5Left-12db.wav")); -footsteps.push(new Sound(pathToSounds+"FootstepW5Right-12db.wav")); - -// all slider controls have a range (with the exception of phase controls that are always +-180) so we store them all here -var sliderRanges = {"joints":[{"name":"hips","pitchRange":25,"yawRange":25,"rollRange":25,"pitchOffsetRange":25,"yawOffsetRange":25,"rollOffsetRange":25,"thrustRange":0.01,"bobRange":0.02,"swayRange":0.01},{"name":"upperLegs","pitchRange":90,"yawRange":35,"rollRange":35,"pitchOffsetRange":60,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"lowerLegs","pitchRange":90,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"feet","pitchRange":60,"yawRange":20,"rollRange":20,"pitchOffsetRange":60,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"toes","pitchRange":90,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":20,"rollOffsetRange":20},{"name":"spine","pitchRange":40,"yawRange":40,"rollRange":40,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"spine1","pitchRange":20,"yawRange":40,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"spine2","pitchRange":20,"yawRange":40,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":50,"rollOffsetRange":50},{"name":"shoulders","pitchRange":35,"yawRange":40,"rollRange":20,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"upperArms","pitchRange":90,"yawRange":90,"rollRange":90,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"lowerArms","pitchRange":90,"yawRange":90,"rollRange":120,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"hands","pitchRange":90,"yawRange":180,"rollRange":90,"pitchOffsetRange":180,"yawOffsetRange":180,"rollOffsetRange":180},{"name":"head","pitchRange":20,"yawRange":20,"rollRange":20,"pitchOffsetRange":90,"yawOffsetRange":90,"rollOffsetRange":90}]}; - -// internal state (FSM based) constants -var STANDING = 1; -var WALKING = 2; -var SIDE_STEPPING = 3; -var FLYING = 4; -var CONFIG_WALK_STYLES = 5; -var CONFIG_WALK_TWEAKS = 6; -var CONFIG_WALK_JOINTS = 7; -var CONFIG_STANDING = 8; -var CONFIG_FLYING = 9; -var CONFIG_FLYING_UP = 10; -var CONFIG_FLYING_DOWN = 11; -var CONFIG_SIDESTEP_LEFT = 12; -var CONFIG_SIDESTEP_RIGHT = 14; -var INTERNAL_STATE = STANDING; - -// status -var powerOn = true; -var paused = false; // pause animation playback whilst adjusting certain parameters -var minimised = true; -var armsFree = true; // set true for hydra support - temporary fix for Hydras -var statsOn = false; -var playFootStepSounds = true; - // constants -var MAX_WALK_SPEED = 1257; // max oscillation speed -var FLYING_SPEED = 6.4;// 12.4; // m/s - real humans can't run any faster than 12.4 m/s -var TERMINAL_VELOCITY = 300; // max speed imposed by Interface -var DIRECTION_UP = 1; -var DIRECTION_DOWN = 2; -var DIRECTION_LEFT = 4; -var DIRECTION_RIGHT = 8; -var DIRECTION_FORWARDS = 16; -var DIRECTION_BACKWARDS = 32; -var DIRECTION_NONE = 64; var MALE = 1; var FEMALE = 2; +var MAX_WALK_SPEED = 2.5;//3.919; +var TAKE_FLIGHT_SPEED = 4.55; +var TOP_SPEED = 300; +var UP = 1; +var DOWN = 2; +var LEFT = 4; +var RIGHT = 8; +var FORWARDS = 16; +var BACKWARDS = 32; -// start of animation control section -var cumulativeTime = 0.0; -var lastOrientation; +// location of animation files and overlay images +var pathToAssets = 'http://s3.amazonaws.com/hifi-public/WalkScript/'; -// avi gender and default animations -var avatarGender = MALE; -var selectedWalk = maleStrutWalk; // the currently selected animation walk file (to edit any animation, paste it's name here and select walk editing mode) -var selectedStand = maleStandOne; -var selectedFlyUp = maleFlyingUp; -var selectedFly = maleFlying; -var selectedFlyDown = maleFlyingDown; -var selectedSideStepLeft = maleSideStepLeft; -var selectedSideStepRight = maleSideStepRight; -if(avatarGender===FEMALE) { +// load the UI +Script.include("./libraries/walkInterface.js"); - // to make toggling the default quick - selectedWalk = femaleStrutWalk; - selectedStand = femaleStandOne; - selectedFlyUp = femaleFlyingUp; - selectedFly = femaleFlying; - selectedFlyDown = femaleFlyingDown; - selectedSideStepLeft = femaleSideStepLeft; - selectedSideStepRight = femaleSideStepRight; -} -var currentAnimation = selectedStand; // the current animation -var selectedJointIndex = 0; // the index of the joint currently selected for editing -var currentTransition = null; // used as a pointer to a Transition +// load filters (Bezier, Butterworth, add harmonics, averaging) +Script.include("./libraries/walkFilters.js"); -// walkwheel (foot / ground speed matching) -var sideStepCycleStartLeft = 270; -var sideStepCycleStartRight = 90; -var walkWheelPosition = 0; -var nextStep = DIRECTION_RIGHT; // first step is always right, because the sine waves say so. Unless you're mirrored. -var nFrames = 0; // counts number of frames -var strideLength = 0; // stride calibration -var aviFootSize = {x:0.1, y:0.1, z:0.25}; // experimental values for addition to stride length - TODO: analyse and confirm is increasing smaller stride lengths accuracy once we have better ground detection +// load objects, constructors and assets (state, Motion, Transition, walkAssets) +Script.include("./libraries/walkApi.js"); -// stats -var frameStartTime = 0; // when the frame first starts we take a note of the time -var frameExecutionTimeMax = 0; // keep track of the longest frame execution time +// initialise the motion state / history object +var motion = new Motion(); -// constructor for recent RecentMotion (i.e. frame data) class -function RecentMotion(velocity, acceleration, principleDirection, state) { - this.velocity = velocity; - this.acceleration = acceleration; - this.principleDirection = principleDirection; - this.state = state; -} +// initialise Transitions +var nullTransition = new Transition(); +motion.curTransition = nullTransition; -// constructor for the FramesHistory object -function FramesHistory() { - this.recentMotions = []; - for(var i = 0 ; i < 10 ; i++) { - var blank = new RecentMotion({ x:0, y:0, z:0 }, { x:0, y:0, z:0 }, DIRECTION_FORWARDS, STANDING ); - this.recentMotions.push(blank); - } +// initialise the UI +walkInterface.initialise(state, motion, walkAssets); - // recentDirection 'method' args: (direction enum, number of steps back to compare) - this.recentDirection = function () { +// wave shapes +var SAWTOOTH = 1; +var TRIANGLE = 2; +var SQUARE = 4; - if( arguments[0] && arguments[1] ) { +// various filters for synthesising more complex, natural waveforms +var leanPitchFilter = filter.createAveragingFilter(15); +var leanRollFilter = filter.createAveragingFilter(15); +var hipsYawShaper = filter.createWaveSynth(TRIANGLE, 3, 2); +var hipsBobLPFilter = filter.createButterworthFilter(5); - var directionCount = 0; - if( arguments[1] > this.recentMotions.length ) - arguments[1] = this.recentMotions.length; - - for(var i = 0 ; i < arguments[1] ; i++ ) { - if( this.recentMotions[i].principleDirection === arguments[0] ) - directionCount++; - } - return directionCount / arguments[1] === 1 ? true : false; - } - return false; - } - - // recentState 'method' args: (state enum, number of steps back to compare) - this.recentState = function () { - - if( arguments[0] && arguments[1] ) { - - var stateCount = 0; - if( arguments[1] > this.recentMotions.length ) - arguments[1] = this.recentMotions.length; - - for(var i = 0 ; i < arguments[1] ; i++ ) { - if( this.recentMotions[i].state === arguments[0] ) - stateCount++; - } - return stateCount / arguments[1] === 1 ? true : false; - } - return false; - } - this.lastWalkStartTime = 0; // short walks and long walks need different handling -} -var framesHistory = new FramesHistory(); - -// constructor for animation Transition class -function Transition(lastAnimation, nextAnimation, reachPoses, transitionDuration, easingLower, easingUpper) { - this.lastAnimation = lastAnimation; // name of last animation - if(lastAnimation === selectedWalk || - nextAnimation === selectedSideStepLeft || - nextAnimation === selectedSideStepRight) - this.walkingAtStart = true; // boolean - is the last animation a walking animation? - else - this.walkingAtStart = false; // boolean - is the last animation a walking animation? - this.nextAnimation = nextAnimation; // name of next animation - if(nextAnimation === selectedWalk || - nextAnimation === selectedSideStepLeft || - nextAnimation === selectedSideStepRight) - this.walkingAtEnd = true; // boolean - is the next animation a walking animation? - else - this.walkingAtEnd = false; // boolean - is the next animation a walking animation? - this.reachPoses = reachPoses; // array of reach poses - am very much looking forward to putting these in! - this.transitionDuration = transitionDuration; // length of transition (seconds) - this.easingLower = easingLower; // Bezier curve handle (normalised) - this.easingUpper = easingUpper; // Bezier curve handle (normalised) - this.startTime = new Date().getTime(); // Starting timestamp (seconds) - this.progress = 0; // how far are we through the transition? - this.walkWheelIncrement = 3; // how much to turn the walkwheel each frame when coming to a halt. Get's set to 0 once the feet are under the avi - this.walkWheelAdvance = 0; // how many degrees the walk wheel has been advanced during the transition - this.walkStopAngle = 0; // what angle should we stop the walk cycle? (calculated on the fly) -} - -// convert a local (to the avi) translation to a global one -function localToGlobal(localTranslation) { - - var aviOrientation = MyAvatar.orientation; - var front = Quat.getFront(aviOrientation); - var right = Quat.getRight(aviOrientation); - var up = Quat.getUp (aviOrientation); - var aviFront = Vec3.multiply(front,localTranslation.z); - var aviRight = Vec3.multiply(right,localTranslation.x); - var aviUp = Vec3.multiply(up ,localTranslation.y); - var globalTranslation = {x:0,y:0,z:0}; // final value - globalTranslation = Vec3.sum(globalTranslation, aviFront); - globalTranslation = Vec3.sum(globalTranslation, aviRight); - globalTranslation = Vec3.sum(globalTranslation, aviUp); - return globalTranslation; -} - -// similar ot above - convert hips translations to global and apply -function translateHips(localHipsTranslation) { - - var aviOrientation = MyAvatar.orientation; - var front = Quat.getFront(aviOrientation); - var right = Quat.getRight(aviOrientation); - var up = Quat.getUp (aviOrientation); - var aviFront = Vec3.multiply(front,localHipsTranslation.y); - var aviRight = Vec3.multiply(right,localHipsTranslation.x); - var aviUp = Vec3.multiply(up ,localHipsTranslation.z); - var AviTranslationOffset = {x:0,y:0,z:0}; // final value - AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviFront); - AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviRight); - AviTranslationOffset = Vec3.sum(AviTranslationOffset, aviUp); - MyAvatar.position = {x: MyAvatar.position.x + AviTranslationOffset.x, - y: MyAvatar.position.y + AviTranslationOffset.y, - z: MyAvatar.position.z + AviTranslationOffset.z }; -} - -// clear all joint data -function resetJoints() { - - var avatarJointNames = MyAvatar.getJointNames(); - for (var i = 0; i < avatarJointNames.length; i++) { - MyAvatar.clearJointData(avatarJointNames[i]); - } -} - -// play footstep sound -function playFootstep(side) { - - var options = { - position: Camera.getPosition(), - volume: 0.5 - } - - var walkNumber = 2; // 0 to 2 - if(side===DIRECTION_RIGHT && playFootStepSounds) { - Audio.playSound(footsteps[walkNumber+1], options); - } - else if(side===DIRECTION_LEFT && playFootStepSounds) { - Audio.playSound(footsteps[walkNumber], options); - } -} - -// put the fingers into a relaxed pose -function curlFingers() { - - // left hand fingers - for(var i = 18 ; i < 34 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(8,0,0)); - } - // left hand thumb - for(var i = 34 ; i < 38 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,0,0)); - } - // right hand fingers - for(var i = 42 ; i < 58 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(8,0,0)); - } - // right hand thumb - for(var i = 58 ; i < 62 ; i++) { - MyAvatar.setJointData(jointList[i], Quat.fromPitchYawRollDegrees(0,0,0)); - } -} - -// additional maths functions -function degToRad( degreesValue ) { return degreesValue * Math.PI / 180; } -function radToDeg( radiansValue ) { return radiansValue * 180 / Math.PI; } - -// animateAvatar - sine wave generators working like clockwork -function animateAvatar( deltaTime, velocity, principleDirection ) { - - // adjusting the walk speed in edit mode causes a nasty flicker. pausing the animation stops this - if(paused) return; - - var cycle = cumulativeTime; - var transitionProgress = 1; - var adjustedFrequency = currentAnimation.settings.baseFrequency; - - // upper legs phase reversal for walking backwards - var forwardModifier = 1; - if(principleDirection===DIRECTION_BACKWARDS) - forwardModifier = -1; - - // don't want to lean forwards if going directly upwards - var leanPitchModifier = 1; - if(principleDirection===DIRECTION_UP) - leanPitchModifier = 0; - - // is there a Transition to include? - if(currentTransition!==null) { - - // if is a new transiton - if(currentTransition.progress===0) { - - if( currentTransition.walkingAtStart ) { - - if( INTERNAL_STATE !== SIDE_STEPPING ) { - - // work out where we want the walk cycle to stop - var leftStop = selectedWalk.settings.stopAngleForwards + 180; - var rightStop = selectedWalk.settings.stopAngleForwards; - if( principleDirection === DIRECTION_BACKWARDS ) { - leftStop = selectedWalk.settings.stopAngleBackwards + 180; - rightStop = selectedWalk.settings.stopAngleBackwards; - } - - // find the closest stop point from the walk wheel's angle - var angleToLeftStop = 180 - Math.abs( Math.abs( walkWheelPosition - leftStop ) - 180); - var angleToRightStop = 180 - Math.abs( Math.abs( walkWheelPosition - rightStop ) - 180); - if( walkWheelPosition > angleToLeftStop ) angleToLeftStop = 360 - angleToLeftStop; - if( walkWheelPosition > angleToRightStop ) angleToRightStop = 360 - angleToRightStop; - - currentTransition.walkWheelIncrement = 6; - - // keep the walkwheel turning by setting the walkWheelIncrement until our feet are tucked nicely underneath us. - if( angleToLeftStop < angleToRightStop ) { - - currentTransition.walkStopAngle = leftStop; - - } else { - - currentTransition.walkStopAngle = rightStop; - } - - } else { - - // freeze wheel for sidestepping transitions - currentTransition.walkWheelIncrement = 0; - } - } - } // end if( currentTransition.walkingAtStart ) - - // calculate the Transition progress - var elapasedTime = (new Date().getTime() - currentTransition.startTime) / 1000; - currentTransition.progress = elapasedTime / currentTransition.transitionDuration; - transitionProgress = getBezier((1-currentTransition.progress), {x:0,y:0}, currentTransition.easingLower, currentTransition.easingUpper, {x:1,y:1}).y; - - if(currentTransition.progress>=1) { - - // time to kill off the transition - delete currentTransition; - currentTransition = null; - - } else { - - if( currentTransition.walkingAtStart ) { - - if( INTERNAL_STATE !== SIDE_STEPPING ) { - - // if at a stop angle, hold the walk wheel position for remainder of transition - var tolerance = 7; // must be greater than the walkWheel increment - if(( walkWheelPosition > (currentTransition.walkStopAngle - tolerance )) && - ( walkWheelPosition < (currentTransition.walkStopAngle + tolerance ))) { - - currentTransition.walkWheelIncrement = 0; - } - // keep turning walk wheel until both feet are below the avi - walkWheelPosition += currentTransition.walkWheelIncrement; - currentTransition.walkWheelAdvance += currentTransition.walkWheelIncrement; - } - } - } - } - - // will we need to use the walk wheel this frame? - if(currentAnimation === selectedWalk || - currentAnimation === selectedSideStepLeft || - currentAnimation === selectedSideStepRight || - currentTransition !== null) { - - // set the stride length - if( INTERNAL_STATE!==SIDE_STEPPING && - INTERNAL_STATE!==CONFIG_SIDESTEP_LEFT && - INTERNAL_STATE!==CONFIG_SIDESTEP_RIGHT && - currentTransition===null ) { - - // if the timing's right, take a snapshot of the stride max and recalibrate - var tolerance = 1.0; // higher the number, the higher the chance of a calibration taking place, but is traded off with lower accuracy - var strideOne = 40; - var strideTwo = 220; - - if( principleDirection === DIRECTION_BACKWARDS ) { - strideOne = 130; - strideTwo = 300; - } - - if(( walkWheelPosition < (strideOne+tolerance) && walkWheelPosition > (strideOne-tolerance) ) || - ( walkWheelPosition < (strideTwo+tolerance) && walkWheelPosition > (strideTwo-tolerance) )) { - - // calculate the feet's offset from each other (in local Z only) - var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot")); - var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot")); - var footOffsetZ = Math.abs(footRPos.z - footLPos.z); - if(footOffsetZ>1) strideLength = 2 * footOffsetZ + aviFootSize.z; // sometimes getting very low value here - just ignore for now - if(statsOn) print('Stride length calibrated to '+strideLength.toFixed(4)+' metres at '+walkWheelPosition.toFixed(1)+' degrees'); - if(principleDirection===DIRECTION_FORWARDS) { - currentAnimation.calibration.strideLengthForwards = strideLength; - } else if (principleDirection===DIRECTION_BACKWARDS) { - currentAnimation.calibration.strideLengthBackwards = strideLength; - } - - } else { - - if(principleDirection===DIRECTION_FORWARDS) - strideLength = currentAnimation.calibration.strideLengthForwards; - else if (principleDirection===DIRECTION_BACKWARDS) - strideLength = currentAnimation.calibration.strideLengthBackwards; - } - } - else if(( INTERNAL_STATE===SIDE_STEPPING || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) ) { - - // calculate lateral stride - same same, but different - // if the timing's right, take a snapshot of the stride max and recalibrate the stride length - var tolerance = 1.0; // higher the number, the higher the chance of a calibration taking place, but is traded off with lower accuracy - if(principleDirection===DIRECTION_LEFT) { - - if( walkWheelPosition < (3+tolerance) && walkWheelPosition > (3-tolerance) ) { - - // calculate the feet's offset from the hips (in local X only) - var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot")); - var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot")); - var footOffsetX = Math.abs(footRPos.x - footLPos.x); - strideLength = footOffsetX; - if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees'); - currentAnimation.calibration.strideLengthLeft = strideLength; - - } else { - - strideLength = currentAnimation.calibration.strideLengthLeft; - } - } - else if (principleDirection===DIRECTION_RIGHT) { - - if( walkWheelPosition < (170+tolerance) && walkWheelPosition > (170-tolerance) ) { - - // calculate the feet's offset from the hips (in local X only) - var footRPos = localToGlobal(MyAvatar.getJointPosition("RightFoot")); - var footLPos = localToGlobal(MyAvatar.getJointPosition("LeftFoot")); - var footOffsetX = Math.abs(footRPos.x - footLPos.x); - strideLength = footOffsetX; - if(statsOn) print('Stride width calibrated to '+strideLength.toFixed(4)+ ' metres at '+walkWheelPosition.toFixed(1)+' degrees'); - currentAnimation.calibration.strideLengthRight = strideLength; - - } else { - - strideLength = currentAnimation.calibration.strideLengthRight; - } - } - } // end stride length calculations - - // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular velocity at the given (linear) velocity - // omega = v / r , where r = circumference / 2 PI , where circumference = 2 * stride length - var wheelRadius = strideLength / Math.PI; - var angularVelocity = velocity / wheelRadius; - - // calculate the degrees turned (at this angular velocity) since last frame - var radiansTurnedSinceLastFrame = deltaTime * angularVelocity; - var degreesTurnedSinceLastFrame = radToDeg(radiansTurnedSinceLastFrame); - - // if we are in an edit mode, we will need fake time to turn the wheel - if( INTERNAL_STATE!==WALKING && - INTERNAL_STATE!==SIDE_STEPPING ) - degreesTurnedSinceLastFrame = currentAnimation.settings.baseFrequency / 70; - - if( walkWheelPosition >= 360 ) - walkWheelPosition = walkWheelPosition % 360; - - // advance the walk wheel the appropriate amount - if( currentTransition===null || currentTransition.walkingAtEnd ) - walkWheelPosition += degreesTurnedSinceLastFrame; - - // set the new values for the exact correct walk cycle speed at this velocity - adjustedFrequency = 1; - cycle = walkWheelPosition; - - // show stats and walk wheel? - if(statsOn) { - - var distanceTravelled = velocity * deltaTime; - var deltaTimeMS = deltaTime * 1000; - - if( INTERNAL_STATE===SIDE_STEPPING || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - - // draw the walk wheel turning around the z axis for sidestepping - var directionSign = 1; - if(principleDirection===DIRECTION_RIGHT) directionSign = -1; - var yOffset = hipsToFeetDistance - (wheelRadius/1.2); // /1.2 is a visual kludge, probably necessary because of either the 'avi feet penetrate floor' issue - TODO - once ground plane following is in Interface, lock this down - var sinWalkWheelPosition = wheelRadius * Math.sin(degToRad( directionSign * walkWheelPosition )); - var cosWalkWheelPosition = wheelRadius * Math.cos(degToRad( directionSign * -walkWheelPosition )); - var wheelXPos = {x: cosWalkWheelPosition, y:-sinWalkWheelPosition - yOffset, z: 0}; - var wheelXEnd = {x: -cosWalkWheelPosition, y:sinWalkWheelPosition - yOffset, z: 0}; - sinWalkWheelPosition = wheelRadius * Math.sin(degToRad( -directionSign * walkWheelPosition+90 )); - cosWalkWheelPosition = wheelRadius * Math.cos(degToRad( -directionSign * walkWheelPosition+90 )); - var wheelYPos = {x:cosWalkWheelPosition, y:sinWalkWheelPosition - yOffset, z: 0}; - var wheelYEnd = {x:-cosWalkWheelPosition, y:-sinWalkWheelPosition - yOffset, z: 0}; - Overlays.editOverlay(walkWheelYLine, {visible: true, position:wheelYPos, end:wheelYEnd}); - Overlays.editOverlay(walkWheelZLine, {visible: true, position:wheelXPos, end:wheelXEnd}); - - } else { - - // draw the walk wheel turning around the x axis for walking forwards or backwards - var yOffset = hipsToFeetDistance - (wheelRadius/1.2); // /1.2 is a visual kludge, probably necessary because of either the 'avi feet penetrate floor' issue - TODO - once ground plane following is in Interface, lock this down - var sinWalkWheelPosition = wheelRadius * Math.sin(degToRad((forwardModifier*-1) * walkWheelPosition)); - var cosWalkWheelPosition = wheelRadius * Math.cos(degToRad((forwardModifier*-1) * -walkWheelPosition)); - var wheelZPos = {x:0, y:-sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition}; - var wheelZEnd = {x:0, y:sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition}; - sinWalkWheelPosition = wheelRadius * Math.sin(degToRad(forwardModifier * walkWheelPosition+90)); - cosWalkWheelPosition = wheelRadius * Math.cos(degToRad(forwardModifier * walkWheelPosition+90)); - var wheelYPos = {x:0, y:sinWalkWheelPosition - yOffset, z: cosWalkWheelPosition}; - var wheelYEnd = {x:0, y:-sinWalkWheelPosition - yOffset, z: -cosWalkWheelPosition}; - Overlays.editOverlay(walkWheelYLine, { visible: true, position:wheelYPos, end:wheelYEnd }); - Overlays.editOverlay(walkWheelZLine, { visible: true, position:wheelZPos, end:wheelZEnd }); - } - - // populate stats overlay - var walkWheelInfo = - ' Walk Wheel Stats\n--------------------------------------\n \n \n' - + '\nFrame time: '+deltaTimeMS.toFixed(2) - + ' mS\nVelocity: '+velocity.toFixed(2) - + ' m/s\nDistance: '+distanceTravelled.toFixed(3) - + ' m\nOmega: '+angularVelocity.toFixed(3) - + ' rad / s\nDeg to turn: '+degreesTurnedSinceLastFrame.toFixed(2) - + ' deg\nWheel position: '+cycle.toFixed(1) - + ' deg\nWheel radius: '+wheelRadius.toFixed(3) - + ' m\nHips To Feet: '+hipsToFeetDistance.toFixed(3) - + ' m\nStride: '+strideLength.toFixed(3) - + ' m\n'; - Overlays.editOverlay(walkWheelStats, {text: walkWheelInfo}); - } - } // end of walk wheel and stride length calculation - - - // Start applying motion - var pitchOscillation = 0; - var yawOscillation = 0; - var rollOscillation = 0; - var pitchOscillationLast = 0; - var yawOscillationLast = 0; - var rollOscillationLast = 0; - var pitchOffset = 0; - var yawOffset = 0; - var rollOffset = 0; - var pitchOffsetLast = 0; - var yawOffsetLast = 0; - var rollOffsetLast = 0; - - // calcualte any hips translation - // Note: can only apply hips translations whilst in a config (edit) mode at present, not whilst under locomotion - if( INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT || - INTERNAL_STATE===CONFIG_FLYING || - INTERNAL_STATE===CONFIG_FLYING_UP || - INTERNAL_STATE===CONFIG_FLYING_DOWN ) { - - // calculate hips translation - var motorOscillation = Math.sin(degToRad((cycle * adjustedFrequency * 2) + currentAnimation.joints[0].thrustPhase)) + currentAnimation.joints[0].thrustOffset; - var swayOscillation = Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[0].swayPhase)) + currentAnimation.joints[0].swayOffset; - var bobOscillation = Math.sin(degToRad((cycle * adjustedFrequency * 2) + currentAnimation.joints[0].bobPhase)) + currentAnimation.joints[0].bobOffset; - - // apply hips translation - translateHips({x:swayOscillation*currentAnimation.joints[0].sway, y:motorOscillation*currentAnimation.joints[0].thrust, z:bobOscillation*currentAnimation.joints[0].bob}); - } - - // hips rotation - // apply the current Transition? - if(currentTransition!==null) { - - if( currentTransition.walkingAtStart ) { - - pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) - + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; - - yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset; - - rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset); - - pitchOscillationLast = currentTransition.lastAnimation.joints[0].pitch * Math.sin(degToRad(( walkWheelPosition * 2) - + currentTransition.lastAnimation.joints[0].pitchPhase)) + currentTransition.lastAnimation.joints[0].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[0].yaw * Math.sin(degToRad(( walkWheelPosition ) - + currentTransition.lastAnimation.joints[0].yawPhase)) + currentTransition.lastAnimation.joints[0].yawOffset; - - rollOscillationLast = (currentTransition.lastAnimation.joints[0].roll * Math.sin(degToRad(( walkWheelPosition ) - + currentTransition.lastAnimation.joints[0].rollPhase)) + currentTransition.lastAnimation.joints[0].rollOffset); - - } else { - - pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2) - + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; - - yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) - + currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset; - - rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad((cycle * adjustedFrequency ) - + currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset); - - pitchOscillationLast = currentTransition.lastAnimation.joints[0].pitch * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2) - + currentTransition.lastAnimation.joints[0].pitchPhase)) + currentTransition.lastAnimation.joints[0].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[0].yaw * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[0].yawPhase)) + currentTransition.lastAnimation.joints[0].yawOffset; - - rollOscillationLast = (currentTransition.lastAnimation.joints[0].roll * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[0].rollPhase)) + currentTransition.lastAnimation.joints[0].rollOffset); - - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - } else { - - pitchOscillation = currentAnimation.joints[0].pitch * Math.sin(degToRad((cycle * adjustedFrequency * 2) - + currentAnimation.joints[0].pitchPhase)) + currentAnimation.joints[0].pitchOffset; - - yawOscillation = currentAnimation.joints[0].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) - + currentAnimation.joints[0].yawPhase)) + currentAnimation.joints[0].yawOffset; - - rollOscillation = (currentAnimation.joints[0].roll * Math.sin(degToRad((cycle * adjustedFrequency ) - + currentAnimation.joints[0].rollPhase)) + currentAnimation.joints[0].rollOffset); - } - - // apply hips rotation - MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees(-pitchOscillation + (leanPitchModifier * getLeanPitch(velocity)), // getLeanPitch - lean forwards as velocity increases - yawOscillation, // Yup, that's correct ;-) - rollOscillation + getLeanRoll(deltaTime, velocity))); // getLeanRoll - banking on cornering - - // upper legs - if( INTERNAL_STATE!==SIDE_STEPPING && - INTERNAL_STATE!==CONFIG_SIDESTEP_LEFT && - INTERNAL_STATE!==CONFIG_SIDESTEP_RIGHT ) { - - // apply the current Transition to the upper legs? - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase))); - yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[1].yawPhase)); - rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[1].rollPhase)); - - pitchOffset = currentAnimation.joints[1].pitchOffset; - yawOffset = currentAnimation.joints[1].yawOffset; - rollOffset = currentAnimation.joints[1].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[1].pitch - * Math.sin(degToRad( walkWheelPosition + (forwardModifier * currentTransition.lastAnimation.joints[1].pitchPhase ))); - - yawOscillationLast = currentTransition.lastAnimation.joints[1].yaw - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[1].yawPhase )); - - rollOscillationLast = currentTransition.lastAnimation.joints[1].roll - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[1].rollPhase )); - - pitchOffsetLast = currentTransition.lastAnimation.joints[1].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[1].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[1].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase))); - yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase)); - rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase)); - - pitchOffset = currentAnimation.joints[1].pitchOffset; - yawOffset = currentAnimation.joints[1].yawOffset; - rollOffset = currentAnimation.joints[1].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[1].pitch - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + (forwardModifier * currentTransition.lastAnimation.joints[1].pitchPhase ))); - - yawOscillationLast = currentTransition.lastAnimation.joints[1].yaw - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[1].yawPhase )); - - rollOscillationLast = currentTransition.lastAnimation.joints[1].roll - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[1].rollPhase )); - - pitchOffsetLast = currentTransition.lastAnimation.joints[1].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[1].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[1].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast); - - pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast); - yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast); - rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + (forwardModifier * currentAnimation.joints[1].pitchPhase))); - yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase)); - rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase)); - - pitchOffset = currentAnimation.joints[1].pitchOffset; - yawOffset = currentAnimation.joints[1].yawOffset; - rollOffset = currentAnimation.joints[1].rollOffset; - } - - // apply the upper leg rotations - MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, -rollOscillation - rollOffset )); - MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, -rollOscillation + rollOffset )); - - - // lower leg - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].pitchPhase)); - yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].yawPhase)); - rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[2].rollPhase)); - - pitchOffset = currentAnimation.joints[2].pitchOffset; - yawOffset = currentAnimation.joints[2].yawOffset; - rollOffset = currentAnimation.joints[2].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[2].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].pitchPhase)); - yawOscillationLast = currentTransition.lastAnimation.joints[2].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].yawPhase)); - rollOscillationLast = currentTransition.lastAnimation.joints[2].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[2].rollPhase)); - - pitchOffsetLast = currentTransition.lastAnimation.joints[2].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[2].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[2].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase)); - yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase)); - rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase)); - - pitchOffset = currentAnimation.joints[2].pitchOffset; - yawOffset = currentAnimation.joints[2].yawOffset; - rollOffset = currentAnimation.joints[2].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[2].pitch - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[2].pitchPhase)); - yawOscillationLast = currentTransition.lastAnimation.joints[2].yaw - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[2].yawPhase)); - rollOscillationLast = currentTransition.lastAnimation.joints[2].roll - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[2].rollPhase)); - - pitchOffsetLast = currentTransition.lastAnimation.joints[2].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[2].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[2].rollOffset; - } - - pitchOscillation = ( transitionProgress * pitchOscillation ) + ( (1-transitionProgress) * pitchOscillationLast ); - yawOscillation = ( transitionProgress * yawOscillation ) + ( (1-transitionProgress) * yawOscillationLast ); - rollOscillation = ( transitionProgress * rollOscillation ) + ( (1-transitionProgress) * rollOscillationLast ); - - pitchOffset = ( transitionProgress * pitchOffset ) + ( (1-transitionProgress) * pitchOffsetLast ); - yawOffset = ( transitionProgress * yawOffset ) + ( (1-transitionProgress) * yawOffsetLast ); - rollOffset = ( transitionProgress * rollOffset ) + ( (1-transitionProgress) * rollOffsetLast ); - - } else { - - pitchOscillation = currentAnimation.joints[2].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase )); - yawOscillation = currentAnimation.joints[2].yaw * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase )); - rollOscillation = currentAnimation.joints[2].roll * Math.sin( degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase )); - - pitchOffset = currentAnimation.joints[2].pitchOffset; - yawOffset = currentAnimation.joints[2].yawOffset; - rollOffset = currentAnimation.joints[2].rollOffset; - } - - // apply lower leg joint rotations - MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation - rollOffset )); - MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, rollOscillation + rollOffset )); - - } // end if !SIDE_STEPPING - - else if( INTERNAL_STATE===SIDE_STEPPING || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - - // sidestepping uses the sinewave generators slightly differently for the legs - pitchOscillation = currentAnimation.joints[1].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].pitchPhase)); - yawOscillation = currentAnimation.joints[1].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].yawPhase)); - rollOscillation = currentAnimation.joints[1].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[1].rollPhase)); - - // apply upper leg rotations for sidestepping - MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( - -pitchOscillation + currentAnimation.joints[1].pitchOffset, - yawOscillation + currentAnimation.joints[1].yawOffset, - rollOscillation + currentAnimation.joints[1].rollOffset )); - MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( - pitchOscillation + currentAnimation.joints[1].pitchOffset, - yawOscillation - currentAnimation.joints[1].yawOffset, - -rollOscillation - currentAnimation.joints[1].rollOffset )); - - // calculate lower leg joint rotations for sidestepping - pitchOscillation = currentAnimation.joints[2].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].pitchPhase)); - yawOscillation = currentAnimation.joints[2].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].yawPhase)); - rollOscillation = currentAnimation.joints[2].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[2].rollPhase)); - - // apply lower leg joint rotations - MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( - -pitchOscillation + currentAnimation.joints[2].pitchOffset, - yawOscillation - currentAnimation.joints[2].yawOffset, - rollOscillation - currentAnimation.joints[2].rollOffset)); // TODO: needs a kick just before fwd peak - MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( - pitchOscillation + currentAnimation.joints[2].pitchOffset, - yawOscillation + currentAnimation.joints[2].yawOffset, - rollOscillation + currentAnimation.joints[2].rollOffset)); - } - - // feet - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].pitchPhase)); - yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].yawPhase)); - rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[3].rollPhase)); - - pitchOffset = currentAnimation.joints[3].pitchOffset; - yawOffset = currentAnimation.joints[3].yawOffset; - rollOffset = currentAnimation.joints[3].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[3].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].pitchPhase)); - yawOscillationLast = currentTransition.lastAnimation.joints[3].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].yawPhase)); - rollOscillationLast = currentTransition.lastAnimation.joints[3].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[3].rollPhase)); - - pitchOffsetLast = currentTransition.lastAnimation.joints[3].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[3].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[3].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase)); - yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].yawPhase)); - rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].rollPhase)); - - pitchOffset = currentAnimation.joints[3].pitchOffset; - yawOffset = currentAnimation.joints[3].yawOffset; - rollOffset = currentAnimation.joints[3].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[3].pitch - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[3].pitchPhase)); - - yawOscillationLast = currentTransition.lastAnimation.joints[3].yaw - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[3].yawPhase)); - - rollOscillationLast = currentTransition.lastAnimation.joints[3].roll - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[3].rollPhase)); - - pitchOffsetLast = currentTransition.lastAnimation.joints[3].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[3].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[3].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast); - - pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast); - yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast); - rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[3].pitch * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase)); - yawOscillation = currentAnimation.joints[3].yaw * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].yawPhase)); - rollOscillation = currentAnimation.joints[3].roll * Math.sin(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].rollPhase)); - - pitchOffset = currentAnimation.joints[3].pitchOffset; - yawOffset = currentAnimation.joints[3].yawOffset; - rollOffset = currentAnimation.joints[3].rollOffset; - } - - // apply foot rotations - MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, rollOscillation + rollOffset )); - MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation - rollOffset )); - - // play footfall sound yet? To determine this, we take the differential of the foot's pitch curve to decide when the foot hits the ground. - if( INTERNAL_STATE===WALKING || - INTERNAL_STATE===SIDE_STEPPING || - INTERNAL_STATE===CONFIG_WALK_STYLES || - INTERNAL_STATE===CONFIG_WALK_TWEAKS || - INTERNAL_STATE===CONFIG_WALK_JOINTS || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - - // finding dy/dx is as simple as determining the cosine wave for the foot's pitch function. - var feetPitchDifferential = Math.cos(degToRad((cycle * adjustedFrequency ) + currentAnimation.joints[3].pitchPhase)); - var threshHold = 0.9; // sets the audio trigger point. with accuracy. - if(feetPitchDifferential<-threshHold && - nextStep===DIRECTION_LEFT && - principleDirection!==DIRECTION_UP && - principleDirection!==DIRECTION_DOWN) { - - playFootstep(DIRECTION_LEFT); - nextStep = DIRECTION_RIGHT; - } - else if(feetPitchDifferential>threshHold && - nextStep===DIRECTION_RIGHT && - principleDirection!==DIRECTION_UP && - principleDirection!==DIRECTION_DOWN) { - - playFootstep(DIRECTION_RIGHT); - nextStep = DIRECTION_LEFT; - } - } - - // toes - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].pitchPhase)); - yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset; - rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset; - - pitchOffset = currentAnimation.joints[4].pitchOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[4].pitch * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].pitchPhase)); - yawOscillationLast = currentTransition.lastAnimation.joints[4].yaw * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].yawPhase)) + currentTransition.lastAnimation.joints[4].yawOffset;; - rollOscillationLast = currentTransition.lastAnimation.joints[4].roll * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[4].rollPhase))+ currentTransition.lastAnimation.joints[4].rollOffset; - - pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset; - - } else { - - pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].pitchPhase)); - yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset; - rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset; - - pitchOffset = currentAnimation.joints[4].pitchOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[4].pitch - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[4].pitchPhase)); - - yawOscillationLast = currentTransition.lastAnimation.joints[4].yaw - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[4].yawPhase)) + currentTransition.lastAnimation.joints[4].yawOffset;; - - rollOscillationLast = currentTransition.lastAnimation.joints[4].roll - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[4].rollPhase))+ currentTransition.lastAnimation.joints[4].rollOffset; - - pitchOffsetLast = currentTransition.lastAnimation.joints[4].pitchOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[4].pitch * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].pitchPhase)); - yawOscillation = currentAnimation.joints[4].yaw * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].yawPhase)) + currentAnimation.joints[4].yawOffset; - rollOscillation = currentAnimation.joints[4].roll * Math.sin(degToRad((cycle * adjustedFrequency) + currentAnimation.joints[4].rollPhase)) + currentAnimation.joints[4].rollOffset; - - pitchOffset = currentAnimation.joints[4].pitchOffset; - } - - // apply toe rotations - MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees(-pitchOscillation + pitchOffset, yawOscillation, rollOscillation)); - MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation, rollOscillation)); - - // spine - if( currentTransition !== null ) { - - if( currentTransition.walkingAtStart ) { - - pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2 ) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; - yawOscillation = currentAnimation.joints[5].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset; - rollOscillation = currentAnimation.joints[5].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset; - - // calculate where we would have been if we'd continued in the last state - pitchOscillationLast = currentTransition.lastAnimation.joints[5].pitch - * Math.sin(degToRad(( walkWheelPosition * 2 ) + currentTransition.lastAnimation.joints[5].pitchPhase)) - + currentTransition.lastAnimation.joints[5].pitchOffset; - yawOscillationLast = currentTransition.lastAnimation.joints[5].yaw - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[5].yawPhase)) - + currentTransition.lastAnimation.joints[5].yawOffset; - rollOscillationLast = currentTransition.lastAnimation.joints[5].roll - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[5].rollPhase)) - + currentTransition.lastAnimation.joints[5].rollOffset; - } else { - - pitchOscillation = currentAnimation.joints[5].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; - - yawOscillation = currentAnimation.joints[5].yaw * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset; - - rollOscillation = currentAnimation.joints[5].roll * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[5].pitch - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2 ) - + currentTransition.lastAnimation.joints[5].pitchPhase)) - + currentTransition.lastAnimation.joints[5].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[5].yaw - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[5].yawPhase)) - + currentTransition.lastAnimation.joints[5].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[5].roll - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[5].rollPhase)) - + currentTransition.lastAnimation.joints[5].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast); - - } else { - - pitchOscillation = currentAnimation.joints[5].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[5].pitchPhase)) + currentAnimation.joints[5].pitchOffset; - yawOscillation = currentAnimation.joints[5].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[5].yawPhase)) + currentAnimation.joints[5].yawOffset; - rollOscillation = currentAnimation.joints[5].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[5].rollPhase)) + currentAnimation.joints[5].rollOffset; - } - - // apply spine joint rotations - MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - - // spine 1 - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; - yawOscillation = currentAnimation.joints[6].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset; - rollOscillation = currentAnimation.joints[6].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[6].pitch - * Math.sin(degToRad(( walkWheelPosition * 2 ) + currentTransition.lastAnimation.joints[6].pitchPhase)) - + currentTransition.lastAnimation.joints[6].pitchOffset; - yawOscillationLast = currentTransition.lastAnimation.joints[6].yaw - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[6].yawPhase)) - + currentTransition.lastAnimation.joints[6].yawOffset; - rollOscillationLast = currentTransition.lastAnimation.joints[6].roll - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[6].rollPhase)) - + currentTransition.lastAnimation.joints[6].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[6].pitch * Math.sin( degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; - - yawOscillation = currentAnimation.joints[6].yaw * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset; - - rollOscillation = currentAnimation.joints[6].roll * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[6].pitch - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2 ) - + currentTransition.lastAnimation.joints[6].pitchPhase)) - + currentTransition.lastAnimation.joints[6].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[6].yaw - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[6].yawPhase)) - + currentTransition.lastAnimation.joints[6].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[6].roll - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[6].rollPhase)) - + currentTransition.lastAnimation.joints[6].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - } else { - - pitchOscillation = currentAnimation.joints[6].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[6].pitchPhase)) + currentAnimation.joints[6].pitchOffset; - yawOscillation = currentAnimation.joints[6].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[6].yawPhase)) + currentAnimation.joints[6].yawOffset; - rollOscillation = currentAnimation.joints[6].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[6].rollPhase)) + currentAnimation.joints[6].rollOffset; - } - // apply spine1 joint rotations - MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - - // spine 2 - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[7].pitchPhase)) + currentAnimation.joints[7].pitchOffset; - yawOscillation = currentAnimation.joints[7].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[7].yawPhase)) + currentAnimation.joints[7].yawOffset; - rollOscillation = currentAnimation.joints[7].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[7].rollPhase)) + currentAnimation.joints[7].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[7].pitch - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].pitchPhase)) - + currentTransition.lastAnimation.joints[7].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[7].yaw - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].yawPhase)) - + currentTransition.lastAnimation.joints[7].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[7].roll - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[7].rollPhase)) - + currentTransition.lastAnimation.joints[7].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[7].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[7].pitchPhase)) - + currentAnimation.joints[7].pitchOffset; - - yawOscillation = currentAnimation.joints[7].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[7].yawPhase)) - + currentAnimation.joints[7].yawOffset; - - rollOscillation = currentAnimation.joints[7].roll - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[7].rollPhase)) - + currentAnimation.joints[7].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[7].pitch - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[7].pitchPhase)) - + currentTransition.lastAnimation.joints[7].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[7].yaw - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[7].yawPhase)) - + currentTransition.lastAnimation.joints[7].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[7].roll - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[7].rollPhase)) - + currentTransition.lastAnimation.joints[7].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation ) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation ) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation ) + ((1-transitionProgress) * rollOscillationLast); - - } else { - - pitchOscillation = currentAnimation.joints[7].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[7].pitchPhase)) - + currentAnimation.joints[7].pitchOffset; - - yawOscillation = currentAnimation.joints[7].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[7].yawPhase)) - + currentAnimation.joints[7].yawOffset; - - rollOscillation = currentAnimation.joints[7].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[7].rollPhase)) - + currentAnimation.joints[7].rollOffset; - } - // apply spine2 joint rotations - MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - - if(!armsFree) { - - // shoulders - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; - - yawOscillation = currentAnimation.joints[8].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[8].yawPhase)); - - rollOscillation = currentAnimation.joints[8].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) - + currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset; - - yawOffset = currentAnimation.joints[8].yawOffset; - - - pitchOscillationLast = currentTransition.lastAnimation.joints[8].pitch - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].pitchPhase)) - + currentTransition.lastAnimation.joints[8].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[8].yaw - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].yawPhase)) - - rollOscillationLast = currentTransition.lastAnimation.joints[8].roll - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[8].rollPhase)) - + currentTransition.lastAnimation.joints[8].rollOffset; - - yawOffsetLast = currentTransition.lastAnimation.joints[8].yawOffset; - - } else { - - pitchOscillation = currentAnimation.joints[8].pitch * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; - - yawOscillation = currentAnimation.joints[8].yaw * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[8].yawPhase)); - - rollOscillation = currentAnimation.joints[8].roll * Math.sin( degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset; - - yawOffset = currentAnimation.joints[8].yawOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[8].pitch - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[8].pitchPhase)) - + currentTransition.lastAnimation.joints[8].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[8].yaw - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[8].yawPhase)) - - rollOscillationLast = currentTransition.lastAnimation.joints[8].roll - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[8].rollPhase)) - + currentTransition.lastAnimation.joints[8].rollOffset; - - yawOffsetLast = currentTransition.lastAnimation.joints[8].yawOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[8].pitch * Math.sin(degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[8].pitchPhase)) + currentAnimation.joints[8].pitchOffset; - - yawOscillation = currentAnimation.joints[8].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[8].yawPhase)); - - rollOscillation = currentAnimation.joints[8].roll * Math.sin(degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[8].rollPhase)) + currentAnimation.joints[8].rollOffset; - - yawOffset = currentAnimation.joints[8].yawOffset; - } - - MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation + yawOffset, rollOscillation )); - MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOscillation, yawOscillation - yawOffset, -rollOscillation )); - - // upper arms - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[9].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[9].pitchPhase)); - yawOscillation = currentAnimation.joints[9].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[9].yawPhase)); - rollOscillation = currentAnimation.joints[9].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) + currentAnimation.joints[9].rollPhase)) + currentAnimation.joints[9].rollOffset; - - pitchOffset = currentAnimation.joints[9].pitchOffset; - yawOffset = currentAnimation.joints[9].yawOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[9].pitch - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].pitchPhase)) - - yawOscillationLast = currentTransition.lastAnimation.joints[9].yaw - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].yawPhase)) - - rollOscillationLast = currentTransition.lastAnimation.joints[9].roll - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[9].rollPhase)) - + currentTransition.lastAnimation.joints[9].rollOffset; - - pitchOffsetLast = currentTransition.lastAnimation.joints[9].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[9].yawOffset; - - } else { - - pitchOscillation = currentAnimation.joints[9].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[9].pitchPhase)); - - yawOscillation = currentAnimation.joints[9].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[9].yawPhase)); - - rollOscillation = currentAnimation.joints[9].roll - * Math.sin(degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[9].rollPhase)) - + currentAnimation.joints[9].rollOffset; - - pitchOffset = currentAnimation.joints[9].pitchOffset; - yawOffset = currentAnimation.joints[9].yawOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[9].pitch - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[9].pitchPhase)) - - yawOscillationLast = currentTransition.lastAnimation.joints[9].yaw - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[9].yawPhase)) - - rollOscillationLast = currentTransition.lastAnimation.joints[9].roll - * Math.sin( degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[9].rollPhase)) - + currentTransition.lastAnimation.joints[9].rollOffset; - - pitchOffsetLast = currentTransition.lastAnimation.joints[9].pitchOffset; - yawOffsetLast = currentTransition.lastAnimation.joints[9].yawOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - pitchOffset = (transitionProgress * pitchOffset) + ((1-transitionProgress) * pitchOffsetLast); - yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[9].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[9].pitchPhase)); - - yawOscillation = currentAnimation.joints[9].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[9].yawPhase)); - - rollOscillation = currentAnimation.joints[9].roll - * Math.sin( degToRad(( cycle * adjustedFrequency * 2) - + currentAnimation.joints[9].rollPhase)) - + currentAnimation.joints[9].rollOffset; - - pitchOffset = currentAnimation.joints[9].pitchOffset; - yawOffset = currentAnimation.joints[9].yawOffset; - - } - MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( -pitchOscillation + pitchOffset, yawOscillation - yawOffset, rollOscillation )); - MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( pitchOscillation + pitchOffset, yawOscillation + yawOffset, -rollOscillation )); - - // forearms - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[10].pitch - * Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[10].pitchPhase )) - + currentAnimation.joints[10].pitchOffset; - - yawOscillation = currentAnimation.joints[10].yaw - * Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[10].yawPhase )); - - rollOscillation = currentAnimation.joints[10].roll - * Math.sin( degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[10].rollPhase )); - - yawOffset = currentAnimation.joints[10].yawOffset; - rollOffset = currentAnimation.joints[10].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[10].pitch - * Math.sin( degToRad(( walkWheelPosition ) - + currentTransition.lastAnimation.joints[10].pitchPhase)) - + currentTransition.lastAnimation.joints[10].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[10].yaw - * Math.sin( degToRad(( walkWheelPosition ) - + currentTransition.lastAnimation.joints[10].yawPhase)); - - rollOscillationLast = currentTransition.lastAnimation.joints[10].roll - * Math.sin( degToRad(( walkWheelPosition ) - + currentTransition.lastAnimation.joints[10].rollPhase)); - - yawOffsetLast = currentTransition.lastAnimation.joints[10].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[10].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[10].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].pitchPhase )) - + currentAnimation.joints[10].pitchOffset; - - yawOscillation = currentAnimation.joints[10].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].yawPhase )); - - rollOscillation = currentAnimation.joints[10].roll - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].rollPhase )); - - yawOffset = currentAnimation.joints[10].yawOffset; - rollOffset = currentAnimation.joints[10].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[10].pitch - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[10].pitchPhase)) - + currentTransition.lastAnimation.joints[10].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[10].yaw - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[10].yawPhase)); - - rollOscillationLast = currentTransition.lastAnimation.joints[10].roll - * Math.sin( degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[10].rollPhase)); - - yawOffsetLast = currentTransition.lastAnimation.joints[10].yawOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[10].rollOffset; - } - - // blend the previous and next - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = -(transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - yawOffset = (transitionProgress * yawOffset) + ((1-transitionProgress) * yawOffsetLast); - rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[10].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].pitchPhase )) - + currentAnimation.joints[10].pitchOffset; - - yawOscillation = currentAnimation.joints[10].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].yawPhase )); - - rollOscillation = currentAnimation.joints[10].roll - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[10].rollPhase )); - - yawOffset = currentAnimation.joints[10].yawOffset; - rollOffset = currentAnimation.joints[10].rollOffset; - } - - // apply forearms rotations - MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation + yawOffset, rollOscillation + rollOffset )); - MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation - yawOffset, rollOscillation - rollOffset )); - - // hands - var sideStepSign = 1; - if(INTERNAL_STATE===SIDE_STEPPING) { - sideStepSign = 1; - } - if(currentTransition!==null) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset; - yawOscillation = currentAnimation.joints[11].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset; - rollOscillation = currentAnimation.joints[11].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) + currentAnimation.joints[11].rollPhase)) ; - - pitchOscillationLast = currentTransition.lastAnimation.joints[11].pitch - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].pitchPhase)) - + currentTransition.lastAnimation.joints[11].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[11].yaw - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].yawPhase)) - + currentTransition.lastAnimation.joints[11].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[11].roll - * Math.sin(degToRad( walkWheelPosition + currentTransition.lastAnimation.joints[11].rollPhase)) - - rollOffset = currentAnimation.joints[11].rollOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[11].rollOffset; - - } else { - - pitchOscillation = currentAnimation.joints[11].pitch - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[11].pitchPhase)) - + currentAnimation.joints[11].pitchOffset; - - yawOscillation = currentAnimation.joints[11].yaw - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[11].yawPhase)) - + currentAnimation.joints[11].yawOffset; - - rollOscillation = currentAnimation.joints[11].roll - * Math.sin( degToRad(( cycle * adjustedFrequency ) - + currentAnimation.joints[11].rollPhase)); - - rollOffset = currentAnimation.joints[11].rollOffset; - - pitchOscillationLast = currentTransition.lastAnimation.joints[11].pitch - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[11].pitchPhase)) - + currentTransition.lastAnimation.joints[11].pitchOffset; - - yawOscillationLast = currentTransition.lastAnimation.joints[11].yaw - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[11].yawPhase)) - + currentTransition.lastAnimation.joints[11].yawOffset; - - rollOscillationLast = currentTransition.lastAnimation.joints[11].roll - * Math.sin(degToRad( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency - + currentTransition.lastAnimation.joints[11].rollPhase)) - - rollOffset = currentAnimation.joints[11].rollOffset; - rollOffsetLast = currentTransition.lastAnimation.joints[11].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - rollOffset = (transitionProgress * rollOffset) + ((1-transitionProgress) * rollOffsetLast); - - } else { - - pitchOscillation = currentAnimation.joints[11].pitch * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].pitchPhase)) + currentAnimation.joints[11].pitchOffset; - yawOscillation = currentAnimation.joints[11].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].yawPhase)) + currentAnimation.joints[11].yawOffset; - rollOscillation = currentAnimation.joints[11].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[11].rollPhase)); - - rollOffset = currentAnimation.joints[11].rollOffset; - } - - // set the hand rotations - MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees( sideStepSign * pitchOscillation, yawOscillation, rollOscillation + rollOffset)); - MyAvatar.setJointData("LeftHand", Quat.fromPitchYawRollDegrees( pitchOscillation, -yawOscillation, rollOscillation - rollOffset)); - - } // end if(!armsFree) - - // head (includes neck joint) - currently zeroed out in STANDING animation files by request - if( currentTransition !== null ) { - - if(currentTransition.walkingAtStart) { - - pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency * 2) - + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset; - - yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset; - - rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cumulativeTime * currentAnimation.settings.baseFrequency ) - + currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset; - - pitchOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].pitch - * Math.sin(degToRad(( walkWheelPosition * 2) + currentTransition.lastAnimation.joints[12].pitchPhase)) - + currentTransition.lastAnimation.joints[12].pitchOffset; - - yawOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].yaw - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[12].yawPhase)) - + currentTransition.lastAnimation.joints[12].yawOffset; - - rollOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].roll - * Math.sin(degToRad(( walkWheelPosition ) + currentTransition.lastAnimation.joints[12].rollPhase)) - + currentTransition.lastAnimation.joints[12].rollOffset; - - } else { - - pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset; - yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset; - rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset; - - pitchOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].pitch - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency * 2) - + currentTransition.lastAnimation.joints[12].pitchPhase)) - + currentTransition.lastAnimation.joints[12].pitchOffset; - - yawOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].yaw - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[12].yawPhase)) - + currentTransition.lastAnimation.joints[12].yawOffset; - - rollOscillationLast = 0.5 * currentTransition.lastAnimation.joints[12].roll - * Math.sin(degToRad(( cumulativeTime * currentTransition.lastAnimation.settings.baseFrequency ) - + currentTransition.lastAnimation.joints[12].rollPhase)) - + currentTransition.lastAnimation.joints[12].rollOffset; - } - - pitchOscillation = (transitionProgress * pitchOscillation) + ((1-transitionProgress) * pitchOscillationLast); - yawOscillation = (transitionProgress * yawOscillation) + ((1-transitionProgress) * yawOscillationLast); - rollOscillation = (transitionProgress * rollOscillation) + ((1-transitionProgress) * rollOscillationLast); - - } else { - - pitchOscillation = 0.5 * currentAnimation.joints[12].pitch * Math.sin(degToRad(( cycle * adjustedFrequency * 2) + currentAnimation.joints[12].pitchPhase)) + currentAnimation.joints[12].pitchOffset; - yawOscillation = 0.5 * currentAnimation.joints[12].yaw * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].yawPhase)) + currentAnimation.joints[12].yawOffset; - rollOscillation = 0.5 * currentAnimation.joints[12].roll * Math.sin(degToRad(( cycle * adjustedFrequency ) + currentAnimation.joints[12].rollPhase)) + currentAnimation.joints[12].rollOffset; - } - - MyAvatar.setJointData( "Head", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); - MyAvatar.setJointData( "Neck", Quat.fromPitchYawRollDegrees( pitchOscillation, yawOscillation, rollOscillation )); -} - - - -// Bezier function for applying to transitions - src: Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/ -Coord = function (x,y) { - if(!x) var x=0; - if(!y) var y=0; - return {x: x, y: y}; -} - -function B1(t) { return t*t*t } -function B2(t) { return 3*t*t*(1-t) } -function B3(t) { return 3*t*(1-t)*(1-t) } -function B4(t) { return (1-t)*(1-t)*(1-t) } - -function getBezier(percent,C1,C2,C3,C4) { - var pos = new Coord(); - pos.x = C1.x*B1(percent) + C2.x*B2(percent) + C3.x*B3(percent) + C4.x*B4(percent); - pos.y = C1.y*B1(percent) + C2.y*B2(percent) + C3.y*B3(percent) + C4.y*B4(percent); - return pos; -} - -// Butterworth LP filter - coeffs calculated using: http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html -var NZEROS = 8; -var NPOLES = 8; -var GAIN = 17.40692157; -var xv = [0,0,0,0,0,0,0,0,0]; //xv.length = NZEROS+1; -var yv = [0,0,0,0,0,0,0,0,0]; //yv.length = NPOLES+1; - -function filterButterworth(nextInputValue) -{ - xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; - xv[8] = nextInputValue / GAIN; - yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; - yv[8] = (xv[0] + xv[8]) + 8 * (xv[1] + xv[7]) + 28 * (xv[2] + xv[6]) - + 56 * (xv[3] + xv[5]) + 70 * xv[4] - + ( -0.0033008230 * yv[0]) + ( -0.0440409341 * yv[1]) - + ( -0.2663485333 * yv[2]) + ( -0.9570250765 * yv[3]) - + ( -2.2596729000 * yv[4]) + ( -3.6088345059 * yv[5]) - + ( -3.9148571397 * yv[6]) + ( -2.6527135283 * yv[7]); - return yv[8]; -} - -// the faster we go, the further we lean forward. the angle is calcualted here -var leanAngles = []; // smooth out and add damping with simple averaging filter. -leanAngles.length = 15; - -function getLeanPitch(velocity) { - - if(velocity>TERMINAL_VELOCITY) velocity=TERMINAL_VELOCITY; - var leanProgress = velocity / TERMINAL_VELOCITY; - var responseSharpness = 1.8; - if(principleDirection==DIRECTION_BACKWARDS) responseSharpness = 3.6; // lean back a bit extra when walking backwards - var leanProgressBezier = getBezier((1-leanProgress),{x:0,y:0},{x:0,y:responseSharpness},{x:0,y:1},{x:1,y:1}).y; - - // simple averaging filter seems to give best results - leanAngles.push(leanProgressBezier); - leanAngles.shift(); // FIFO - var totalLeanAngles = 0; - for(ea in leanAngles) totalLeanAngles += leanAngles[ea]; - var leanProgressAverageFiltered = totalLeanAngles / leanAngles.length; - - // calculate final return value - var leanPitchFinal = 0; - if(principleDirection===DIRECTION_BACKWARDS) { - leanPitchFinal = -currentAnimation.settings.flyingHipsPitch * leanProgressAverageFiltered;// + finalAccelerationResponse; - } else { - leanPitchFinal = currentAnimation.settings.flyingHipsPitch * leanProgressAverageFiltered;// + finalAccelerationResponse; - } - return leanPitchFinal; -} - -// calculate the angle at which to bank into corners when turning -var leanRollAngles = []; // smooth out and add damping with simple averaging filter -leanRollAngles.length = 25; - -var angularVelocities = []; // keep a record of the last few so can filter out spurious values -angularVelocities.length = 5; - -function getLeanRoll(deltaTime, velocity) { - - // what's our current anglular velocity? - var angularVelocityMax = 70; // from observation - var currentOrientationVec3 = Quat.safeEulerAngles(MyAvatar.orientation); - var lastOrientationVec3 = Quat.safeEulerAngles(lastOrientation); - var deltaYaw = lastOrientationVec3.y-currentOrientationVec3.y; - lastOrientation = MyAvatar.orientation; - - var angularVelocity = deltaYaw / deltaTime; - if(angularVelocity>angularVelocityMax) angularVelocity = angularVelocityMax; - if(angularVelocity<-angularVelocityMax) angularVelocity = -angularVelocityMax; - - // filter the angular velocity for a nicer response and a bit of wobble (intentional overshoot / ringing) - angularVelocity = filterButterworth(angularVelocity); - - var turnSign = 1; - if(angularVelocity<0) turnSign = -1; - if(principleDirection===DIRECTION_BACKWARDS) - turnSign *= -1; - - // calculate the amount of roll based on both angular and linear velocities - if(velocity>TERMINAL_VELOCITY) velocity = TERMINAL_VELOCITY; - var leanRollProgress = (velocity / TERMINAL_VELOCITY) * (Math.abs(angularVelocity) / angularVelocityMax); - - // apply our response curve - var leanRollProgressBezier = getBezier((1-leanRollProgress),{x:0,y:0},{x:0,y:2.5},{x:0,y:1},{x:1,y:1}).y; - - // simple averaging filter - leanRollAngles.push(turnSign * leanRollProgressBezier); - leanRollAngles.shift(); // FIFO - var totalLeanRollAngles = 0; - for(var ea in leanRollAngles) totalLeanRollAngles += leanRollAngles[ea]; - var leanRollProgressAverageFiltered = totalLeanRollAngles / leanRollAngles.length; - - return currentAnimation.settings.maxBankingAngle * leanRollProgressAverageFiltered; -} - -// set up the interface components, update the internal state and kick off any transitions -function setInternalState(newInternalState) { - - switch(newInternalState) { - - case WALKING: - - if(!minimised) doStandardMenu(); - INTERNAL_STATE = WALKING; - return; - - case FLYING: - - if(!minimised) doStandardMenu(); - INTERNAL_STATE = FLYING; - return; - - case SIDE_STEPPING: - - if(!minimised) doStandardMenu(); - INTERNAL_STATE = SIDE_STEPPING; - return; - - case CONFIG_WALK_STYLES: - - INTERNAL_STATE = CONFIG_WALK_STYLES; - currentAnimation = selectedWalk; - if(!minimised) { - hidebuttonOverlays(); - hideJointControls(); - showFrontPanelButtons(false); - showWalkStyleButtons(true); - setBackground(controlsBackgroundWalkEditStyles); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configWalkStylesButtonSelected); - setButtonOverlayVisible(configWalkTweaksButton); - setButtonOverlayVisible(configWalkJointsButton); - setButtonOverlayVisible(backButton); - setSliderThumbsVisible(false); - } - return; - - case CONFIG_WALK_TWEAKS: - - INTERNAL_STATE = CONFIG_WALK_TWEAKS; - currentAnimation = selectedWalk; - if(!minimised) { - hidebuttonOverlays(); - hideJointControls(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditTweaks); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configWalkStylesButton); - setButtonOverlayVisible(configWalkTweaksButtonSelected); - setButtonOverlayVisible(configWalkJointsButton); - setButtonOverlayVisible(backButton); - initialiseWalkTweaks(); - } - return; - - case CONFIG_WALK_JOINTS: - - INTERNAL_STATE = CONFIG_WALK_JOINTS; - currentAnimation = selectedWalk; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configWalkStylesButton); - setButtonOverlayVisible(configWalkTweaksButton); - setButtonOverlayVisible(configWalkJointsButtonSelected); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_STANDING: - - INTERNAL_STATE = CONFIG_STANDING; - currentAnimation = selectedStand; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configSideStepRightButton); - setButtonOverlayVisible(configSideStepLeftButton); - setButtonOverlayVisible(configStandButtonSelected); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_SIDESTEP_LEFT: - - INTERNAL_STATE = CONFIG_SIDESTEP_LEFT; - currentAnimation = selectedSideStepLeft; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configSideStepRightButton); - setButtonOverlayVisible(configSideStepLeftButtonSelected); - setButtonOverlayVisible(configStandButton); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_SIDESTEP_RIGHT: - - INTERNAL_STATE = CONFIG_SIDESTEP_RIGHT; - currentAnimation = selectedSideStepRight; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configSideStepRightButtonSelected); - setButtonOverlayVisible(configSideStepLeftButton); - setButtonOverlayVisible(configStandButton); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_FLYING: - - INTERNAL_STATE = CONFIG_FLYING; - currentAnimation = selectedFly; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configFlyingUpButton); - setButtonOverlayVisible(configFlyingDownButton); - setButtonOverlayVisible(configFlyingButtonSelected); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_FLYING_UP: - - INTERNAL_STATE = CONFIG_FLYING_UP; - currentAnimation = selectedFlyUp; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configFlyingUpButtonSelected); - setButtonOverlayVisible(configFlyingDownButton); - setButtonOverlayVisible(configFlyingButton); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case CONFIG_FLYING_DOWN: - - INTERNAL_STATE = CONFIG_FLYING_DOWN; - currentAnimation = selectedFlyDown; - if(!minimised) { - hidebuttonOverlays(); - showFrontPanelButtons(false); - showWalkStyleButtons(false); - setBackground(controlsBackgroundWalkEditJoints); - setButtonOverlayVisible(onButton); - setButtonOverlayVisible(configFlyingUpButton); - setButtonOverlayVisible(configFlyingDownButtonSelected); - setButtonOverlayVisible(configFlyingButton); - setButtonOverlayVisible(backButton); - initialiseJointsEditingPanel(selectedJointIndex); - } - return; - - case STANDING: - default: - - INTERNAL_STATE = STANDING; - if(!minimised) doStandardMenu(); - - // initialisation - runs at script startup only - if(strideLength===0) { - - if(principleDirection===DIRECTION_BACKWARDS) - strideLength = selectedWalk.calibration.strideLengthBackwards; - else - strideLength = selectedWalk.calibration.strideLengthForwards; - - curlFingers(); - } - return; - } -} // Main loop - -// stabilising vars - most state changes are preceded by a couple of hints that they are about to happen rather than -// momentarilly switching between states (causes flicker), we count the number of hints in a row before actually changing state -var standHints = 0; -var walkHints = 0; -var flyHints = 0; -var requiredHints = 2; // tweakable - debounce state changes - how many times do we get a state change request in a row before we actually change state? (used to be 4 or 5) -var principleDirection = 0; - -// helper function for stats output -function directionAsString(directionEnum) { - - switch(directionEnum) { - case DIRECTION_UP: return 'Up'; - case DIRECTION_DOWN: return 'Down'; - case DIRECTION_LEFT: return 'Left'; - case DIRECTION_RIGHT: return 'Right'; - case DIRECTION_FORWARDS: return 'Forwards'; - case DIRECTION_BACKWARDS: return 'Backwards'; - default: return 'Unknown'; - } -} -// helper function for stats output -function internalStateAsString(internalState) { - - switch(internalState) { - case STANDING: return 'Standing'; - case WALKING: return 'Walking'; - case SIDE_STEPPING: return 'Side Stepping'; - case FLYING: return 'Flying'; - default: return 'Editing'; - } -} - Script.update.connect(function(deltaTime) { - if(powerOn) { + if (state.powerOn) { - frameStartTime = new Date().getTime(); - cumulativeTime += deltaTime; - nFrames++; - var speed = 0; + motion.frameStartTime = new Date().getTime(); + motion.cumulativeTime += deltaTime; + motion.nFrames++; + var speed = 0; - // firstly check for editing modes, as these require no positioning calculations - var editing = false; - switch(INTERNAL_STATE) { + // check for editing modes first, as these require no positioning calculations + switch (state.currentState) { - case CONFIG_WALK_STYLES: - currentAnimation = selectedWalk; - animateAvatar(deltaTime, speed, principleDirection); - editing = true; - break; - case CONFIG_WALK_TWEAKS: - currentAnimation = selectedWalk; - animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); - editing = true; - break; - case CONFIG_WALK_JOINTS: - currentAnimation = selectedWalk; - animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); - editing = true; - break; - case CONFIG_STANDING: - currentAnimation = selectedStand; - animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); - editing = true; - break; - case CONFIG_SIDESTEP_LEFT: - currentAnimation = selectedSideStepLeft; - animateAvatar(deltaTime, speed, DIRECTION_LEFT); - editing = true; - break; - case CONFIG_SIDESTEP_RIGHT: - currentAnimation = selectedSideStepRight; - animateAvatar(deltaTime, speed, DIRECTION_RIGHT); - editing = true; - break; - case CONFIG_FLYING: - currentAnimation = selectedFly; - animateAvatar(deltaTime, speed, DIRECTION_FORWARDS); - editing = true; - break; - case CONFIG_FLYING_UP: - currentAnimation = selectedFlyUp; - animateAvatar(deltaTime, speed, DIRECTION_UP); - editing = true; - break; - case CONFIG_FLYING_DOWN: - currentAnimation = selectedFlyDown; - animateAvatar(deltaTime, speed, DIRECTION_DOWN); - editing = true; - break; - default: - break; - } - - // we have to declare these vars here ( outside 'if(!editing)' ), so they are still in scope - // when we record the frame's data and when we do the stats update at the end - var deltaX = 0; - var deltaY = 0; - var deltaZ = 0; - var acceleration = { x:0, y:0, z:0 }; - var accelerationJS = MyAvatar.getAcceleration(); - - // calculate overriding (local) direction of translation for use later when decide which animation should be played - var inverseRotation = Quat.inverse(MyAvatar.orientation); - var localVelocity = Vec3.multiplyQbyV(inverseRotation, MyAvatar.getVelocity()); - - if(!editing) { - - // the first thing to do is find out how fast we're going, - // what our acceleration is and which direction we're principly moving in - - // calcualte (local) change in velocity - var velocity = MyAvatar.getVelocity(); - speed = Vec3.length(velocity); - - // determine the candidate animation to play - var actionToTake = 0; - if( speed < 0.5) { - actionToTake = STANDING; - standHints++; - } - else if( speed < FLYING_SPEED ) { - actionToTake = WALKING; - walkHints++; - } - else if( speed >= FLYING_SPEED ) { - actionToTake = FLYING; - flyHints++; + case state.EDIT_WALK_STYLES: { + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; } - deltaX = localVelocity.x; - deltaY = localVelocity.y; - deltaZ = -localVelocity.z; + case state.EDIT_WALK_TWEAKS: { + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_WALK_JOINTS: { + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); + break; + } + case state.EDIT_STANDING: { + motion.curAnim = motion.selStand; + motion.direction = FORWARDS; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_SIDESTEP_LEFT: { + motion.curAnim = motion.selSideStepLeft; + motion.direction = LEFT; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_SIDESTEP_RIGHT: { + motion.curAnim = motion.selSideStepRight; + motion.direction = RIGHT; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_FLYING: { + motion.curAnim = motion.selFly; + motion.direction = FORWARDS; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_FLYING_UP: { + motion.curAnim = motion.selFlyUp; + motion.direction = UP; + animateAvatar(deltaTime, speed); + break; + } + + case state.EDIT_FLYING_DOWN: { + motion.curAnim = motion.selFlyDown; + motion.direction = DOWN; + animateAvatar(deltaTime, speed); + break; + } + + default: + break; + } + + // calcualte velocity and speed + var velocity = MyAvatar.getVelocity(); + speed = Vec3.length(velocity); + + if (motion.curTransition !== nullTransition) { + + // finish any live transition before changing state + animateAvatar(deltaTime, speed); + return; + } + var localVelocity = {x: 0, y: 0, z: 0}; + if (speed > 0) { + localVelocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), velocity); + } + + if (!state.editing) { + + // determine the candidate animation state + var actionToTake = undefined; + if (speed < 0.05) { + actionToTake = state.STANDING; + } else if (speed < TAKE_FLIGHT_SPEED) { + actionToTake = state.WALKING; + } else if (speed >= TAKE_FLIGHT_SPEED) { + actionToTake = state.FLYING; + } // determine the principle direction - if(Math.abs(deltaX)>Math.abs(deltaY) - &&Math.abs(deltaX)>Math.abs(deltaZ)) { - if(deltaX<0) { - principleDirection = DIRECTION_RIGHT; - } else { - principleDirection = DIRECTION_LEFT; - } - } - else if(Math.abs(deltaY)>Math.abs(deltaX) - &&Math.abs(deltaY)>Math.abs(deltaZ)) { - if(deltaY>0) { - principleDirection = DIRECTION_UP; - } - else { - principleDirection = DIRECTION_DOWN; - } - } - else if(Math.abs(deltaZ)>Math.abs(deltaX) - &&Math.abs(deltaZ)>Math.abs(deltaY)) { - if(deltaZ>0) { - principleDirection = DIRECTION_FORWARDS; - } else { - principleDirection = DIRECTION_BACKWARDS; - } - } + if (Math.abs(localVelocity.x) > Math.abs(localVelocity.y) && + Math.abs(localVelocity.x) > Math.abs(localVelocity.z)) { - // NB: this section will change significantly once we are ground plane aware - // it will change even more once we have uneven surfaces to deal with + if (localVelocity.x < 0) { + motion.direction = LEFT; + } else { + motion.direction = RIGHT; + } + + } else if (Math.abs(localVelocity.y) > Math.abs(localVelocity.x) && + Math.abs(localVelocity.y) > Math.abs(localVelocity.z)) { + + if (localVelocity.y > 0) { + motion.direction = UP; + } else { + motion.direction = DOWN; + } + + } else if (Math.abs(localVelocity.z) > Math.abs(localVelocity.x) && + Math.abs(localVelocity.z) > Math.abs(localVelocity.y)) { + + if (localVelocity.z < 0) { + motion.direction = FORWARDS; + } else { + motion.direction = BACKWARDS; + } + } // maybe at walking speed, but sideways? - if( actionToTake === WALKING && - ( principleDirection === DIRECTION_LEFT || - principleDirection === DIRECTION_RIGHT )) { - - actionToTake = SIDE_STEPPING; + if (actionToTake === state.WALKING && + (motion.direction === LEFT || + motion.direction === RIGHT)) { + actionToTake = state.SIDE_STEP; } - // maybe at walking speed, but flying up? - if( actionToTake === WALKING && - ( principleDirection === DIRECTION_UP )) { - - actionToTake = FLYING; - standHints--; - flyHints++; + // maybe at walking speed, but flying up or down? + if (actionToTake === state.WALKING && + (motion.direction === UP || + motion.direction === DOWN)) { + actionToTake = state.FLYING; } - // 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) { + // note: The transitions are not compete, and are the most likely + // candidate for the next worklist item + switch (actionToTake) { - case STANDING: + case state.STANDING: { - if( standHints > requiredHints || INTERNAL_STATE===STANDING) { // wait for a few consecutive hints (17mS each) + // do we need to change state? + if (state.currentState !== state.STANDING) { - standHints = 0; - walkHints = 0; - flyHints = 0; + switch (motion.curAnim) { - // do we need to change state? - if( INTERNAL_STATE!==STANDING ) { + case motion.selWalk: { - // initiate the transition - if(currentTransition) { - delete currentTransition; - currentTransition = null; + // Walking to standing + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.25, + {x: 0.1, y: 0.5}, + {x: -0.25, y: 1.22}); + break; } - switch(currentAnimation) { + case motion.selFly: + case motion.selFlyUp: + case motion.selFlyDown: { - case selectedWalk: - - // Walking to Standing - var timeWalking = new Date().getTime() - framesHistory.lastWalkStartTime; - - var bezierCoeffsOne = {x:0.0, y:1.0}; - var bezierCoeffsTwo = {x:0.0, y:1.0}; - var transitionTime = 0.4; - - // very different curves for incremental steps - if( timeWalking < 550 ) { - bezierCoeffsOne = {x:0.63, y:0.17}; - bezierCoeffsTwo = {x:0.77, y:0.3}; - transitionTime = 0.75; - } - currentTransition = new Transition( currentAnimation, selectedStand, [], transitionTime, bezierCoeffsOne, bezierCoeffsTwo ); - break; - - - case selectedSideStepLeft: - case selectedSideStepRight: - - break; - - default: - - currentTransition = new Transition(currentAnimation, selectedStand, [], 0.3, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; + // Flying to Standing + motion.curTransition = new Transition( + motion.curAnim, + motion.selStand, + [], 0.5, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; } - setInternalState(STANDING); - currentAnimation = selectedStand; + default: + break; } - animateAvatar(1,0,principleDirection); + state.setInternalState(state.STANDING); + motion.curAnim = motion.selStand; } + animateAvatar(deltaTime, speed); break; + } - case WALKING: - case SIDE_STEPPING: - if( walkHints > requiredHints || - INTERNAL_STATE===WALKING || - INTERNAL_STATE===SIDE_STEPPING ) { // wait for few consecutive hints (17mS each) + case state.WALKING: { - standHints = 0; - walkHints = 0; - flyHints = 0; - - if( actionToTake === WALKING && INTERNAL_STATE !== WALKING) { - - // initiate the transition - if(currentTransition) { - delete currentTransition; - currentTransition = null; - } - - // set the appropriate start position for the walk wheel - if( principleDirection === DIRECTION_BACKWARDS ) { - - walkWheelPosition = selectedWalk.settings.startAngleBackwards; - - } else { - - walkWheelPosition = selectedWalk.settings.startAngleForwards; - } - - switch(currentAnimation) { - - case selectedStand: - - // Standing to Walking - currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.25, {x:0.5,y:0.08}, {x:0.05,y:0.75}); - break; - - case selectedSideStepLeft: - case selectedSideStepRight: - - break; - - default: - - currentTransition = new Transition(currentAnimation, selectedWalk, [], 0.3, {x:0.5,y:0.08}, {x:0.05,y:0.75}); - break; - } - framesHistory.lastWalkStartTime = new Date().getTime(); - setInternalState(WALKING); - currentAnimation = selectedWalk; - } - else if(actionToTake===SIDE_STEPPING) { - - var selectedSideStep = selectedSideStepRight; - if( principleDirection === DIRECTION_LEFT ) { - - selectedSideStep = selectedSideStepLeft; - - } else { - - selectedSideStep = selectedSideStepRight; - } - - if( INTERNAL_STATE !== SIDE_STEPPING ) { - - if( principleDirection === DIRECTION_LEFT ) { - - walkWheelPosition = sideStepCycleStartLeft; - - } else { - - walkWheelPosition = sideStepCycleStartRight; - } - switch(currentAnimation) { - - case selectedStand: - - break; - - default: - - break; - } - setInternalState(SIDE_STEPPING); - } - - currentAnimation = selectedSideStep; - } - animateAvatar( deltaTime, speed, principleDirection ); - } - break; - - case FLYING: - - if( flyHints > requiredHints - 1 || INTERNAL_STATE===FLYING ) { // wait for a few consecutive hints (17mS each) - - standHints = 0; - walkHints = 0; - flyHints = 0; - - if(INTERNAL_STATE!==FLYING) setInternalState(FLYING); - - // change animation for flying directly up or down. TODO - check RecentMotions, if is a change then put a transition on it - if(principleDirection===DIRECTION_UP) { - - if(currentAnimation !== selectedFlyUp) { - - // initiate a Transition - if(currentTransition && currentTransition.nextAnimation!==selectedFlyUp) { - delete currentTransition; - currentTransition = null; - } - switch(currentAnimation) { - - case selectedStand: - - currentTransition = new Transition(currentAnimation, selectedFlyUp, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; - - case selectedSideStepLeft: - case selectedSideStepRight: - - break; - - default: - - currentTransition = new Transition(currentAnimation, selectedFlyUp, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; - } - currentAnimation = selectedFlyUp; - } - - } else if(principleDirection==DIRECTION_DOWN) { - - if(currentAnimation !== selectedFlyDown) { // TODO: as the locomotion gets cleaner (i.e. less false reports from Interface) this value can be reduced - - // initiate a Transition - if(currentTransition && currentTransition.nextAnimation!==selectedFlyDown) { - delete currentTransition; - currentTransition = null; - } - switch(currentAnimation) { - - case selectedStand: - - currentTransition = new Transition(currentAnimation, selectedFlyDown, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; - - case selectedSideStepLeft: - case selectedSideStepRight: - - break; - - default: - - currentTransition = new Transition(currentAnimation, selectedFlyDown, [], 0.35, {x:0.5,y:0.08}, {x:0.28,y:1}); - break; - } - currentAnimation = selectedFlyDown; - } + if (state.currentState !== state.WALKING) { + if (motion.direction === BACKWARDS) { + motion.walkWheelPos = motion.selWalk.calibration.startAngleBackwards; } 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; - } + motion.walkWheelPos = motion.selWalk.calibration.startAngleForwards; } - animateAvatar(deltaTime, speed, principleDirection); + + switch (motion.curAnim) { + + case motion.selStand: { + + // Standing to Walking + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.25, + {x: 0.5, y: 0.5}, + {x: 0.5, y: 0.5}); + break; + } + + case motion.selFly: + case motion.selFlyUp: + case motion.selFlyDown: { + + // Flying to Walking + motion.curTransition = new Transition( + motion.curAnim, + motion.selWalk, + [], 0.1, + {x: 0.24, y: 0.03}, + {x: 0.42, y: 1.0}); + break; + } + + default: + + break; + } + state.setInternalState(state.WALKING); } + motion.curAnim = motion.selWalk; + animateAvatar(deltaTime, speed); break; + } + + case state.SIDE_STEP: { + + var selSideStep = 0; + if (motion.direction === LEFT) { + + if (motion.lastDirection !== LEFT) { + motion.walkWheelPos = motion.selSideStepLeft.calibration.cycleStart; + } + selSideStep = motion.selSideStepLeft; + + } else { + + if (motion.lastDirection !== RIGHT) { + motion.walkWheelPos = motion.selSideStepRight.calibration.cycleStart; + } + selSideStep = motion.selSideStepRight; + } + + if (state.currentState !== state.SIDE_STEP) { + + if (motion.direction === LEFT) { + motion.walkWheelPos = motion.selSideStepLeft.calibration.cycleStart; + } else { + motion.walkWheelPos = motion.selSideStepRight.calibration.cycleStart; + } + state.setInternalState(state.SIDE_STEP); + } + motion.curAnim = selSideStep; + animateAvatar(deltaTime, speed); + break; + } + + case state.FLYING: { + + if (state.currentState !== state.FLYING) { + state.setInternalState(state.FLYING); + } + + // change animation for flying directly up or down + if (motion.direction === UP) { + + if (motion.curAnim !== motion.selFlyUp) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: { + + // standing | walking to flying up + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyUp, + [], 0.35, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + + case motion.selFly: + case motion.selFlyUp: + case motion.selFlyDown: { + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyUp, + [], 0.35, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + + default: + + break; + } + motion.curAnim = motion.selFlyUp; + } + + } else if (motion.direction == DOWN) { + + if (motion.curAnim !== motion.selFlyDown) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: { + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyDown, + [], 0.35, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + + case motion.selFly: + case motion.selFlyUp: + case motion.selFlyDown: { + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFlyDown, + [], 0.45, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + + default: + + break; + } + motion.curAnim = motion.selFlyDown; + } + + } else { + + if (motion.curAnim !== motion.selFly) { + + switch (motion.curAnim) { + + case motion.selStand: + case motion.selWalk: { + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFly, + [], 0.35, + {x: 1.44, y:0.24}, + {x: 0.61, y:0.92}); + break; + } + + case motion.selFly: + case motion.selFlyUp: + case motion.selFlyDown: { + + motion.curTransition = new Transition( + motion.curAnim, + motion.selFly, + [], 0.75, + {x: 0.5, y: 0.08}, + {x: 0.28, y: 1}); + break; + } + + default: + + break; + } + motion.curAnim = motion.selFly; + } + } + animateAvatar(deltaTime, speed); + break; + }// end case state.FLYING } // end switch(actionToTake) - } // end if(!editing) + } // end if (!state.editing) + + // record the frame's direction and local avatar's local velocity for future reference + motion.lastDirection = motion.direction; + motion.lastVelocity = localVelocity; + } +}); + +// the faster we go, the further we lean forward. the angle is calcualted here +function getLeanPitch(speed) { + + if (speed > TOP_SPEED) { + speed = TOP_SPEED; + } + var leanProgress = speed / TOP_SPEED; + + if (motion.direction === LEFT || + motion.direction === RIGHT) { + leanProgress = 0; + } else { + + var responseSharpness = 1.5; + if (motion.direction == BACKWARDS) { + responseSharpness = 3.0; + } + + leanProgress = filter.bezier((1 - leanProgress), + {x: 0, y: 0.0}, + {x: 0, y: responseSharpness}, + {x: 0, y: 1.5}, + {x: 1, y: 1}).y; + + // determine final pitch and adjust for direction of momentum + if (motion.direction === BACKWARDS) { + leanProgress = -motion.motionPitchMax * leanProgress; + } else { + leanProgress = motion.motionPitchMax * leanProgress; + } + } + + // return the smoothed response + return leanPitchFilter.process(leanProgress); +} + +// calculate the angle at which to bank into corners when turning +function getLeanRoll(deltaTime, speed) { + + var leanRollProgress = 0; + if (speed > TOP_SPEED) { + speed = TOP_SPEED; + } + + // what's our our anglular velocity? + var angularVelocityMax = 70; // from observation + var angularVelocity = filter.radToDeg(MyAvatar.getAngularVelocity().y); + if (angularVelocity > angularVelocityMax) { + angularVelocity = angularVelocityMax; + } + if (angularVelocity < -angularVelocityMax) { + angularVelocity = -angularVelocityMax; + } + + leanRollProgress = speed / TOP_SPEED; + + if (motion.direction !== LEFT && + motion.direction !== RIGHT) { + leanRollProgress *= (Math.abs(angularVelocity) / angularVelocityMax); + } + + // apply our response curve + leanRollProgress = filter.bezier((1 - leanRollProgress), + {x: 0, y: 0}, + {x: 0, y: 1}, + {x: 0, y: 1}, + {x: 1, y: 1}).y; + // which way to lean? + var turnSign = -1; + if (angularVelocity < 0.001) { + turnSign = 1; + } + if (motion.direction === BACKWARDS || + motion.direction === LEFT) { + turnSign *= -1; + } + if (motion.direction === LEFT || + motion.direction === RIGHT) { + leanRollProgress *= 2; + } + + // add damping with simple averaging filter + leanRollProgress = leanRollFilter.process(turnSign * leanRollProgress); + return motion.motionRollMax * leanRollProgress; +} + +function playFootstep(side) { + + options = { + position: Camera.getPosition(), + volume: 0.3 + } + + var soundNumber = 2; // 0 to 2 + if (side === RIGHT && motion.makesFootStepSounds) { + Audio.playSound(walkAssets.footsteps[soundNumber + 1], options); + } else if (side === LEFT && motion.makesFootStepSounds) { + Audio.playSound(walkAssets.footsteps[soundNumber], options); + } +} + +// animate the avatar using sine wave generators. inspired by Victorian clockwork dolls +function animateAvatar(deltaTime, speed) { + + var cycle = motion.cumulativeTime; + var transProgress = 1; + var adjFreq = motion.curAnim.calibration.frequency; + + // legs phase and cycle reversal for walking backwards + var reverseModifier = 0; + var reverseSignModifier = 1; + if (motion.direction === BACKWARDS) { + reverseModifier = -180; + reverseSignModifier = -1; + } + + // don't lean into the direction of travel if going up + var leanMod = 1; + if (motion.direction === UP) { + leanMod = 0; + } + + // adjust leaning direction for flying + var flyingModifier = 1; + if (state.currentState.FLYING) { + flyingModifier = -1; + } + + if (motion.curTransition !== nullTransition) { + + // new transiton? + if (motion.curTransition.progress === 0 && + motion.curTransition.walkingAtStart) { + + if (state.currentState !== state.SIDE_STEP) { + + // work out where we want the walk cycle to stop + var leftStop = motion.selWalk.calibration.stopAngleForwards + 180; + var rightStop = motion.selWalk.calibration.stopAngleForwards; + + if (motion.direction === BACKWARDS) { + leftStop = motion.selWalk.calibration.stopAngleBackwards + 180; + rightStop = motion.selWalk.calibration.stopAngleBackwards; + } + + // find the closest stop point from the walk wheel's angle + var angleToLeftStop = 180 - Math.abs(Math.abs(motion.walkWheelPos - leftStop) - 180); + var angleToRightStop = 180 - Math.abs(Math.abs(motion.walkWheelPos - rightStop) - 180); + if (motion.walkWheelPos > angleToLeftStop) { + angleToLeftStop = 360 - angleToLeftStop; + } + if (motion.walkWheelPos > angleToRightStop) { + angleToRightStop = 360 - angleToRightStop; + } + + motion.curTransition.walkWheelIncrement = 3; + + // keep the walkwheel turning by setting the walkWheelIncrement + // until our feet are tucked nicely underneath us. + if (angleToLeftStop < angleToRightStop) { + motion.curTransition.walkStopAngle = leftStop; + } else { + motion.curTransition.walkStopAngle = rightStop; + } + + } else { + + // freeze wheel for sidestepping transitions (for now) + motion.curTransition.walkWheelIncrement = 0; + } + } // end if (new transition and curTransition.walkingAtStart) + + // update the Transition progress + var elapasedTime = (new Date().getTime() - motion.curTransition.startTime) / 1000; + motion.curTransition.progress = elapasedTime / motion.curTransition.transitionDuration; + transProgress = filter.bezier((1 - motion.curTransition.progress), {x: 0, y: 0}, + motion.curTransition.easingLower, + motion.curTransition.easingUpper, {x: 1, y: 1}).y; + + if (motion.curTransition.progress >= 1) { + + // time to kill off the transition + delete motion.curTransition; + motion.curTransition = nullTransition; + + } else { + + if (motion.curTransition.walkingAtStart) { + + if (state.currentState !== state.SIDE_STEP) { + + // if at a stop angle, hold the walk wheel position for remainder of transition + var tolerance = 7; // must be greater than the walkWheel increment + if ((motion.walkWheelPos > (motion.curTransition.walkStopAngle - tolerance)) && + (motion.walkWheelPos < (motion.curTransition.walkStopAngle + tolerance))) { + + motion.curTransition.walkWheelIncrement = 0; + } + // keep turning walk wheel until both feet are below the avi + motion.advanceWalkWheel(motion.curTransition.walkWheelIncrement); + + } else motion.curTransition.walkWheelIncrement = 0; // sidestep + } + } } // end motion.curTransition !== nullTransition - // record the frame's stats for later reference - var thisMotion = new RecentMotion(localVelocity, acceleration, principleDirection, INTERNAL_STATE); - framesHistory.recentMotions.push(thisMotion); - framesHistory.recentMotions.shift(); + // walking? then get the stride length + if (motion.curAnim === motion.selWalk) { + // if the timing's right, take a snapshot of the stride max and recalibrate + var strideMaxAt = motion.curAnim.calibration.forwardStrideMaxAt; + if (motion.direction === BACKWARDS) { + strideMaxAt = motion.curAnim.calibration.backwardsStrideMaxAt; + } - // before we go, populate the stats overlay - if( statsOn ) { + var tolerance = 1.0; + if (motion.walkWheelPos < (strideMaxAt + tolerance) && + motion.walkWheelPos > (strideMaxAt - tolerance)) { - var cumulativeTimeMS = Math.floor(cumulativeTime*1000); - var deltaTimeMS = deltaTime * 1000; - var frameExecutionTime = new Date().getTime() - frameStartTime; - if(frameExecutionTime>frameExecutionTimeMax) frameExecutionTimeMax = frameExecutionTime; + // measure and save stride length + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); - var angluarVelocity = Vec3.length(MyAvatar.getAngularVelocity()); + if (motion.direction === FORWARDS) { + motion.curAnim.calibration.strideLengthForwards = motion.strideLength; + } else if (motion.direction === BACKWARDS) { + motion.curAnim.calibration.strideLengthBackwards = motion.strideLength; + } - 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}); + } else { - // 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; + // use the saved value for stride length + if (motion.direction === FORWARDS) { + motion.strideLength = motion.curAnim.calibration.strideLengthForwards; + } else if (motion.direction === BACKWARDS) { + motion.strideLength = motion.curAnim.calibration.strideLengthBackwards; } } - } -}); + } // end get walk stride length + // sidestepping? get the stride length + if (motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight) { -// overlays start + // if the timing's right, take a snapshot of the stride max and recalibrate the stride length + var tolerance = 1.0; + if (motion.direction === LEFT) { -// controller dimensions -var backgroundWidth = 350; -var backgroundHeight = 700; -var backgroundX = Window.innerWidth-backgroundWidth-58; -var backgroundY = Window.innerHeight/2 - backgroundHeight/2; -var minSliderX = backgroundX + 30; -var maxSliderX = backgroundX + 295; -var sliderRangeX = 295 - 30; -var jointsControlWidth = 200; -var jointsControlHeight = 300; -var jointsControlX = backgroundX + backgroundWidth/2 - jointsControlWidth/2; -var jointsControlY = backgroundY + 242 - jointsControlHeight/2; -var buttonsY = 20; // distance from top of panel to buttons + if (motion.walkWheelPos < motion.curAnim.calibration.strideMaxAt + tolerance && + motion.walkWheelPos > motion.curAnim.calibration.strideMaxAt - tolerance) { -// arrays of overlay names -var sliderThumbOverlays = []; // thumb sliders -var backgroundOverlays = []; -var buttonOverlays = []; -var jointsControlOverlays = []; -var bigButtonOverlays = []; + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); + motion.curAnim.calibration.strideLength = motion.strideLength; + } else motion.strideLength = motion.selSideStepLeft.calibration.strideLength; -// load UI backgrounds -var controlsBackground = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, - imageURL: pathToOverlays+"ddao-background.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -backgroundOverlays.push(controlsBackground); + } else if (motion.direction === RIGHT) { -var controlsBackgroundWalkEditStyles = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, - imageURL: pathToOverlays+"ddao-background-edit-styles.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -backgroundOverlays.push(controlsBackgroundWalkEditStyles); + if (motion.walkWheelPos < motion.curAnim.calibration.strideMaxAt + tolerance && + motion.walkWheelPos > motion.curAnim.calibration.strideMaxAt - tolerance) { -var controlsBackgroundWalkEditTweaks = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, - imageURL: pathToOverlays+"ddao-background-edit-tweaks.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -backgroundOverlays.push(controlsBackgroundWalkEditTweaks); + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + motion.strideLength = Vec3.distance(footRPos, footLPos); + motion.curAnim.calibration.strideLength = motion.strideLength; -var controlsBackgroundWalkEditJoints = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, - imageURL: pathToOverlays+"ddao-background-edit-joints.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -backgroundOverlays.push(controlsBackgroundWalkEditJoints); + } else motion.strideLength = motion.selSideStepRight.calibration.strideLength; + } + } // end get sidestep stride length -var controlsBackgroundFlyingEdit = Overlays.addOverlay("image", { - bounds: { x: backgroundX, y: backgroundY, width: backgroundWidth, height: backgroundHeight }, - imageURL: pathToOverlays+"ddao-background-flying-edit.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -backgroundOverlays.push(controlsBackgroundFlyingEdit); + // turn the walk wheel + if (motion.curAnim === motion.selWalk || + motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight || + motion.curTransition.walkingAtStart) { -// minimised tab - not put in array, as is a one off -var controlsMinimisedTab = Overlays.addOverlay("image", { - x: Window.innerWidth-58, y: Window.innerHeight -145, width: 50, height: 50, - //subImage: { x: 0, y: 50, width: 50, height: 50 }, - imageURL: pathToOverlays + 'ddao-minimise-tab.png', - visible: minimised, - alpha: 0.9 - }); + // wrap the stride length around a 'surveyor's wheel' twice and calculate + // the angular speed at the given (linear) speed: + // omega = v / r , where r = circumference / 2 PI , where circumference = 2 * stride length + var strideLength = motion.strideLength; + var wheelRadius = strideLength / Math.PI; + var angularVelocity = speed / wheelRadius; -// load character joint selection control images -var hipsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-hips.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(hipsJointControl); + // calculate the degrees turned (at this angular speed) since last frame + var radiansTurnedSinceLastFrame = deltaTime * angularVelocity; + var degreesTurnedSinceLastFrame = filter.radToDeg(radiansTurnedSinceLastFrame); -var upperLegsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-upper-legs.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(upperLegsJointControl); + // if we are in an edit mode, we will need fake time to turn the wheel + if (state.currentState !== state.WALKING && + state.currentState !== state.SIDE_STEP) { + degreesTurnedSinceLastFrame = motion.curAnim.calibration.frequency / 70; + } -var lowerLegsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-lower-legs.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(lowerLegsJointControl); + // advance the walk wheel the appropriate amount + motion.advanceWalkWheel(degreesTurnedSinceLastFrame); -var feetJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-feet.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(feetJointControl); + // set the new values for the exact correct walk cycle speed + adjFreq = 1; + cycle = motion.walkWheelPos; -var toesJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-toes.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(toesJointControl); + } // end of walk wheel and stride length calculation -var spineJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-spine.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(spineJointControl); + // motion vars + var pitchOsc = 0; + var pitchOscLeft = 0; + var pitchOscRight = 0; + var yawOsc = 0; + var yawOscLeft = 0; + var yawOscRight = 0; + var rollOsc = 0; + var pitchOffset = 0; + var yawOffset = 0; + var rollOffset = 0; + var swayOsc = 0; + var bobOsc = 0; + var thrustOsc = 0; + var swayOscLast = 0; + var bobOscLast = 0; + var thrustOscLast = 0; -var spine1JointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-spine1.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(spine1JointControl); + // historical (for transitions) + var pitchOscLast = 0; + var pitchOscLeftLast = 0; + var pitchOscRightLast = 0; + var yawOscLast = 0; + var rollOscLast = 0; + var pitchOffsetLast = 0; + var yawOffsetLast = 0; + var rollOffsetLast = 0; -var spine2JointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-spine2.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(spine2JointControl); + // feet + var sideStepFootPitchModifier = 1; + var sideStepHandPitchSign = 1; -var shouldersJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-shoulders.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(shouldersJointControl); + // calculate hips translation + if (motion.curTransition !== nullTransition) { -var upperArmsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-upper-arms.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(upperArmsJointControl); + if (motion.curTransition.walkingAtStart) { -var forearmsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-forearms.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(forearmsJointControl); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].swayPhase)) + motion.curAnim.joints[0].swayOffset; -var handsJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-hands.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(handsJointControl); + var bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) { + bobPhase += 90; + } + bobOsc = motion.curAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + bobPhase)) + + motion.curAnim.joints[0].bobOffset; -var headJointControl = Overlays.addOverlay("image", { - bounds: { x: jointsControlX, y: jointsControlY, width: 200, height: 300}, - imageURL: pathToOverlays+"ddao-background-edit-head.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -jointsControlOverlays.push(headJointControl); + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; + swayOscLast = motion.curTransition.lastAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].swayPhase)) + + motion.curTransition.lastAnim.joints[0].swayOffset; -// sider thumb overlays -var sliderOne = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderOne); -var sliderTwo = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderTwo); -var sliderThree = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderThree); -var sliderFour = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderFour); -var sliderFive = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderFive); -var sliderSix = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderSix); -var sliderSeven = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderSeven); -var sliderEight = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderEight); -var sliderNine = Overlays.addOverlay("image", { - bounds: { x: 0, y: 0, width: 25, height: 25 }, - imageURL: pathToOverlays+"ddao-slider-handle.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -sliderThumbOverlays.push(sliderNine); + var bobPhaseLast = motion.curTransition.lastAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) { + bobPhaseLast +=90; + } + bobOscLast = motion.curTransition.lastAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.walkWheelPos + bobPhaseLast)); + bobOscLast = filter.clipTrough(bobOscLast, motion.curTransition.lastAnim.joints[0].bob , 2); + bobOscLast = hipsBobLPFilter.process(bobOscLast); + bobOscLast += motion.curTransition.lastAnim.joints[0].bobOffset; + thrustOscLast = motion.curTransition.lastAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[0].thrustPhase)) + + motion.curTransition.lastAnim.joints[0].thrustOffset; -// button overlays -var onButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-on-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(onButton); -var offButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+20, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-off-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(offButton); -var configWalkButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-walk-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkButton); -var configWalkButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-walk-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkButtonSelected); -var configStandButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-stand-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configStandButton); -var configStandButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-stand-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configStandButtonSelected); + // end if walking at start of transition -var configFlyingButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingButton); -var configFlyingButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingButtonSelected); + } else { -var configFlyingUpButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-up-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingUpButton); -var configFlyingUpButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-up-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingUpButtonSelected); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(cycle * adjFreq + motion.curAnim.joints[0].swayPhase)) + + motion.curAnim.joints[0].swayOffset; -var configFlyingDownButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-down-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingDownButton); -var configFlyingDownButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-fly-down-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configFlyingDownButtonSelected); + var bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) { + bobPhase += 90; + } + bobOsc = motion.curAnim.joints[0].bob * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + bobPhase)); + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { -var hideButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-hide-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(hideButton); -var hideButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-hide-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(hideButtonSelected); -var configWalkStylesButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-walk-styles-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkStylesButton); -var configWalkStylesButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-walk-styles-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkStylesButtonSelected); -var configWalkTweaksButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-walk-tweaks-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkTweaksButton); -var configWalkTweaksButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+146, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-walk-tweaks-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkTweaksButtonSelected); + // apply clipping filter to flatten the curve's peaks (inputValue, peak, strength) + bobOsc = filter.clipTrough(bobOsc, motion.curAnim.joints[0].bob , 2); + bobOsc = hipsBobLPFilter.process(bobOsc); + } + bobOsc += motion.curAnim.joints[0].bobOffset; -var configSideStepLeftButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-sidestep-left-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configSideStepLeftButton); -var configSideStepLeftButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+83, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-sidestep-left-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configSideStepLeftButtonSelected); + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; -var configSideStepRightButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-sidestep-right-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configSideStepRightButton); -var configSideStepRightButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-edit-sidestep-right-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configSideStepRightButtonSelected); + swayOscLast = motion.curTransition.lastAnim.joints[0].sway * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].swayPhase)) + + motion.curTransition.lastAnim.joints[0].swayOffset; -var configWalkJointsButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-bones-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkJointsButton); -var configWalkJointsButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+209, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-bones-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(configWalkJointsButtonSelected); + bobOscLast = motion.curTransition.lastAnim.joints[0].bob * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].bobPhase)) + + motion.curTransition.lastAnim.joints[0].bobOffset; -var backButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-back-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(backButton); -var backButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX+272, y: backgroundY+buttonsY, width: 60, height: 47 }, - imageURL: pathToOverlays+"ddao-back-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -buttonOverlays.push(backButtonSelected); + thrustOscLast = motion.curTransition.lastAnim.joints[0].thrust * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].thrustPhase)) + + motion.curTransition.lastAnim.joints[0].thrustOffset; + } -// big button overlays - front panel -var bigButtonYOffset = 408; // distance from top of panel to top of first button + swayOsc = (transProgress * swayOsc) + ((1 - transProgress) * swayOscLast); + bobOsc = (transProgress * bobOsc) + ((1 - transProgress) * bobOscLast); + thrustOsc = (transProgress * thrustOsc) + ((1 - transProgress) * thrustOscLast); -var femaleBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-female-big-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(femaleBigButton); + // end if walking at start of transition -var femaleBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-female-big-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(femaleBigButtonSelected); + } else { -var maleBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-male-big-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(maleBigButton); + swayOsc = motion.curAnim.joints[0].sway * + Math.sin(filter.degToRad(cycle * adjFreq + motion.curAnim.joints[0].swayPhase)) + + motion.curAnim.joints[0].swayOffset; -var maleBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 60, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-male-big-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(maleBigButtonSelected); + bobPhase = motion.curAnim.joints[0].bobPhase; + if (motion.direction === motion.BACKWARDS) bobPhase += 90; + bobOsc = motion.curAnim.joints[0].bob * Math.sin(filter.degToRad(cycle * adjFreq * 2 + bobPhase)); + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { -var armsFreeBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-arms-free-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(armsFreeBigButton); + // apply clipping filter to flatten the curve's peaks (inputValue, peak, strength) + bobOsc = filter.clipTrough(bobOsc, motion.curAnim.joints[0].bob , 2); + bobOsc = hipsBobLPFilter.process(bobOsc); + } + bobOsc += motion.curAnim.joints[0].bobOffset; -var armsFreeBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 120, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-arms-free-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(armsFreeBigButtonSelected); + thrustOsc = motion.curAnim.joints[0].thrust * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].thrustPhase)) + + motion.curAnim.joints[0].thrustOffset; + } -var footstepsBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-footsteps-big-button.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(footstepsBigButton); + // convert local hips translations to global and apply + var aviOrientation = MyAvatar.orientation; + var front = Quat.getFront(aviOrientation); + var right = Quat.getRight(aviOrientation); + var up = Quat.getUp(aviOrientation); + var aviFront = Vec3.multiply(front, thrustOsc); + var aviRight = Vec3.multiply(right, swayOsc); + var aviUp = Vec3.multiply(up, bobOsc); + var aviTranslationOffset = {x: 0, y: 0, z: 0}; -var footstepsBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset + 180, width: 230, height: 36}, - imageURL: pathToOverlays+"ddao-footsteps-big-button-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(footstepsBigButtonSelected); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviFront); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviRight); + aviTranslationOffset = Vec3.sum(aviTranslationOffset, aviUp); + MyAvatar.setSkeletonOffset({ + x: aviTranslationOffset.x, + y: aviTranslationOffset.y, + z: aviTranslationOffset.z + }); -// walk styles -bigButtonYOffset = 121; -var strutWalkBigButton = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-strut.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(strutWalkBigButton); + // hips rotation + if (motion.curTransition !== nullTransition) { -var strutWalkBigButtonSelected = Overlays.addOverlay("image", { - bounds: { x: backgroundX + backgroundWidth/2 - 115, y: backgroundY + bigButtonYOffset, width: 230, height: 36 }, - imageURL: pathToOverlays+"ddao-walk-select-button-strut-selected.png", - color: { red: 255, green: 255, blue: 255}, - alpha: 1, - visible: false - }); -bigButtonOverlays.push(strutWalkBigButtonSelected); + if (motion.curTransition.walkingAtStart) { -// overlays to show the walk wheel stats -var walkWheelZLine = Overlays.addOverlay("line3d", { - position: { x: 0, y: 0, z:hipsToFeetDistance }, - end: { x: 0, y: 0, z: -hipsToFeetDistance }, - color: { red: 0, green: 255, blue: 255}, - alpha: 1, - lineWidth: 5, - visible: statsOn, - anchor: "MyAvatar" - }); -var walkWheelYLine = Overlays.addOverlay("line3d", { - position: { x: 0, y: hipsToFeetDistance, z:0 }, - end: { x: 0, y: -hipsToFeetDistance, z:0 }, - color: { red: 255, green: 0, blue: 255}, - alpha: 1, - lineWidth: 5, - visible: statsOn, - anchor: "MyAvatar" - }); -var debugStats = Overlays.addOverlay("text", { - x: backgroundX-199, y: backgroundY, - width: 200, - height: 180, - color: { red: 204, green: 204, blue: 204}, - topMargin: 10, - leftMargin: 15, - visible: statsOn, - backgroundColor: { red: 34, green: 34, blue: 34}, - alpha: 1.0, - text: "Debug Stats\n\n\nNothing to report yet." - }); -var debugStatsPeriodic = Overlays.addOverlay("text", { - x: backgroundX-199, y: backgroundY+179, - width: 200, - height: 392, - color: { red: 204, green: 204, blue: 204}, - topMargin: 5, - leftMargin: 15, - visible: statsOn, - backgroundColor: { red: 34, green: 34, blue: 34}, - alpha: 1.0, - text: "Debug Stats\n\n\nNothing to report yet." - }); -var walkWheelStats = Overlays.addOverlay("text", { - x: backgroundX-199, y: backgroundY+510, - width: 200, - height: 190, - color: { red: 204, green: 204, blue: 204}, - topMargin: 5, - leftMargin: 15, - visible: statsOn, - backgroundColor: { red: 34, green: 34, blue: 34}, - alpha: 1.0, - text: "WalkWheel Stats\n\n\nNothing to report yet.\n\n\nPlease start walking\nto see the walkwheel." - }); + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[0].pitchPhase)) + motion.curAnim.joints[0].pitchOffset; -// 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) { + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].yawPhase - reverseModifier)) + motion.curAnim.joints[0].yawOffset; + + rollOsc = motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * motion.curAnim.calibration.frequency + + motion.curAnim.joints[0].rollPhase)) + motion.curAnim.joints[0].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[0].pitchPhase)) + + motion.curTransition.lastAnim.joints[0].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].yawPhase)); + + yawOscLast += motion.curTransition.lastAnim.joints[0].yaw * + hipsYawShaper.shapeWave(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].yawPhase - reverseModifier)) + + motion.curTransition.lastAnim.joints[0].yawOffset; + + rollOscLast = (motion.curTransition.lastAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[0].rollPhase)) + + motion.curTransition.lastAnim.joints[0].rollOffset); + + } else { + + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[0].pitchPhase)) + + motion.curAnim.joints[0].pitchOffset; + + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[0].yawPhase - reverseModifier)) + + motion.curAnim.joints[0].yawOffset; + + rollOsc = motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[0].rollPhase)) + + motion.curAnim.joints[0].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[0].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2 + + motion.curTransition.lastAnim.joints[0].pitchPhase)) + + motion.curTransition.lastAnim.joints[0].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[0].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].yawPhase - reverseModifier)) + + motion.curTransition.lastAnim.joints[0].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[0].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[0].rollPhase)) + + motion.curTransition.lastAnim.joints[0].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); - if(avatarGender===FEMALE) { - Overlays.editOverlay(femaleBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(femaleBigButton, { visible: false } ); - Overlays.editOverlay(maleBigButtonSelected, { visible: false } ); - Overlays.editOverlay(maleBigButton, { visible: showButtons } ); } else { - Overlays.editOverlay(femaleBigButtonSelected, { visible: false } ); - Overlays.editOverlay(femaleBigButton, { visible: showButtons } ); - Overlays.editOverlay(maleBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(maleBigButton, { visible: false } ); + + pitchOsc = motion.curAnim.joints[0].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[0].pitchPhase)) + + motion.curAnim.joints[0].pitchOffset; + + yawOsc = motion.curAnim.joints[0].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[0].yawPhase)); + + yawOsc += motion.curAnim.joints[0].yaw * + hipsYawShaper.shapeWave(filter.degToRad(cycle * adjFreq) + + motion.curAnim.joints[0].yawPhase - reverseModifier)+ + motion.curAnim.joints[0].yawOffset; + + rollOsc = (motion.curAnim.joints[0].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[0].rollPhase)) + + motion.curAnim.joints[0].rollOffset); } - if(armsFree) { - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(armsFreeBigButton, { visible: false } ); + + // apply hips rotation + MyAvatar.setJointData("Hips", Quat.fromPitchYawRollDegrees( + pitchOsc + (leanMod * getLeanPitch(speed)), + yawOsc, + rollOsc + getLeanRoll(deltaTime, speed))); + + // upper legs + if (state.currentState !== state.SIDE_STEP && + state.currentState !== state.EDIT_SIDESTEP_LEFT && + state.currentState !== state.EDIT_SIDESTEP_RIGHT) { + + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + reverseModifier * motion.curAnim.joints[1].pitchPhase)); + + pitchOscRight = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + reverseModifier * motion.curAnim.joints[1].pitchPhase)); + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[1].pitch * + motion.curTransition.lastAnim.harmonics.leftUpperLeg.calculate( + filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].pitchPhase + 180 + reverseModifier)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[1].pitch * + motion.curTransition.lastAnim.harmonics.rightUpperLeg.calculate( + filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].pitchPhase + reverseModifier)); + + yawOscLast = motion.curTransition.lastAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[1].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[1].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[1].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[1].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.leftUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + 180 + reverseModifier)); + pitchOscRight = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.rightUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + reverseModifier)); + } else { + + pitchOscLeft = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + pitchOscRight = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + } + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + reverseModifier * motion.curTransition.lastAnim.joints[1].pitchPhase)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[1].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + reverseModifier * motion.curTransition.lastAnim.joints[1].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[1].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[1].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[1].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[1].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[1].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[1].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[1].rollOffset; + } + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.leftUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + 180 + reverseModifier)); + pitchOscRight = motion.curAnim.joints[1].pitch * + motion.curAnim.harmonics.rightUpperLeg.calculate(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase + reverseModifier)); + } else { + + pitchOscLeft = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + pitchOscRight = motion.curAnim.joints[1].pitch * Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[1].pitchPhase)); + } + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].rollPhase)); + + pitchOffset = motion.curAnim.joints[1].pitchOffset; + yawOffset = motion.curAnim.joints[1].yawOffset; + rollOffset = motion.curAnim.joints[1].rollOffset; + } + + // apply the upper leg rotations + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( + pitchOscLeft + pitchOffset, + yawOsc - yawOffset, + -rollOsc + rollOffset)); + + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( + pitchOscRight + pitchOffset, + yawOsc + yawOffset, + -rollOsc - rollOffset)); + + // lower leg + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].pitchPhase)); + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[2].rollPhase)); + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[2].pitch * + motion.curTransition.lastAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[2].pitch * + motion.curTransition.lastAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[2].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[2].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[2].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[2].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase + 180)); + pitchOscRight = motion.curAnim.harmonics.rightLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + } + pitchOscLeft *= motion.curAnim.joints[2].pitch; + pitchOscRight *= motion.curAnim.joints[2].pitch; + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[2].rollPhase)); + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[2].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[2].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[2].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[2].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[2].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[2].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[2].rollOffset; + } + + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + rollOscLeft = rollOsc; + rollOscRight = rollOsc; + + } else { // end if transitioning + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase + 180)); + pitchOscRight = motion.curAnim.harmonics.rightLowerLeg.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[2].pitchPhase)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase + 180)); + + pitchOscRight = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + } + + pitchOscLeft *= motion.curAnim.joints[2].pitch; + pitchOscRight *= motion.curAnim.joints[2].pitch; + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].rollPhase)); + + rollOsc = motion.curAnim.joints[2].roll; + + pitchOffset = motion.curAnim.joints[2].pitchOffset; + yawOffset = motion.curAnim.joints[2].yawOffset; + rollOffset = motion.curAnim.joints[2].rollOffset; + } + + pitchOscLeft += pitchOffset; + pitchOscRight += pitchOffset; + + // apply lower leg joint rotations + MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( + pitchOscLeft, + yawOsc + yawOffset, + rollOsc + rollOffset)); + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + pitchOscRight, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + } // end if !state.SIDE_STEP + + else if (state.currentState === state.SIDE_STEP || + state.currentState === state.EDIT_SIDESTEP_LEFT || + state.currentState === state.EDIT_SIDESTEP_RIGHT) { + + // sidestepping uses the sinewave generators slightly differently for the legs + pitchOsc = motion.curAnim.joints[1].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].pitchPhase)); + + yawOsc = motion.curAnim.joints[1].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].yawPhase)); + + rollOsc = motion.curAnim.joints[1].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[1].rollPhase)); + + // apply upper leg rotations for sidestepping + MyAvatar.setJointData("RightUpLeg", Quat.fromPitchYawRollDegrees( + -pitchOsc + motion.curAnim.joints[1].pitchOffset, + yawOsc + motion.curAnim.joints[1].yawOffset, + rollOsc + motion.curAnim.joints[1].rollOffset)); + + MyAvatar.setJointData("LeftUpLeg", Quat.fromPitchYawRollDegrees( + pitchOsc + motion.curAnim.joints[1].pitchOffset, + yawOsc - motion.curAnim.joints[1].yawOffset, + -rollOsc - motion.curAnim.joints[1].rollOffset)); + + // calculate lower leg joint rotations for sidestepping + pitchOsc = motion.curAnim.joints[2].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].pitchPhase)); + + yawOsc = motion.curAnim.joints[2].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].yawPhase)); + + rollOsc = motion.curAnim.joints[2].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[2].rollPhase)); + + // apply lower leg joint rotations + MyAvatar.setJointData("RightLeg", Quat.fromPitchYawRollDegrees( + -pitchOsc + motion.curAnim.joints[2].pitchOffset, + yawOsc - motion.curAnim.joints[2].yawOffset, + rollOsc - motion.curAnim.joints[2].rollOffset)); + + MyAvatar.setJointData("LeftLeg", Quat.fromPitchYawRollDegrees( + pitchOsc + motion.curAnim.joints[2].pitchOffset, + yawOsc + motion.curAnim.joints[2].yawOffset, + rollOsc + motion.curAnim.joints[2].rollOffset)); + } + + // feet + if (motion.curAnim === motion.selSideStepLeft || + motion.curAnim === motion.selSideStepRight ) { + + sideStepHandPitchSign = -1; + sideStepFootPitchModifier = 0.5; + } + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOscLeft = motion.curAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].pitchPhase) + 180); + + pitchOscRight = motion.curAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].pitchPhase)); + + yawOsc = motion.curAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].yawPhase)); + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[3].pitch * + motion.curTransition.lastAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * motion.walkWheelPos + + motion.curTransition.lastAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[3].pitch * + motion.curTransition.lastAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * motion.walkWheelPos + + motion.curTransition.lastAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + yawOscLast = motion.curTransition.lastAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[3].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[3].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[3].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[3].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[3].rollOffset; + + } else { + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRight = motion.curAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase)); + + pitchOscRight = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase + 180)); + } + + yawOsc = motion.curAnim.joints[3].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].yawPhase)); + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; + + pitchOscLeftLast = motion.curTransition.lastAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].pitchPhase + 180)); + + pitchOscRightLast = motion.curTransition.lastAnim.joints[3].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[3].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[3].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[3].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[3].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[3].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[3].rollOffset; + } + + pitchOscLeft = (transProgress * pitchOscLeft) + ((1 - transProgress) * pitchOscLeftLast); + pitchOscRight = (transProgress * pitchOscRight) + ((1 - transProgress) * pitchOscRightLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + } else { - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } ); - Overlays.editOverlay(armsFreeBigButton, { visible: showButtons } ); + + if (state.currentState === state.WALKING || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS) { + + pitchOscLeft = motion.curAnim.harmonics.leftFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + reverseModifier)); + + pitchOscRight = motion.curAnim.harmonics.rightFoot.calculate(filter.degToRad(reverseSignModifier * cycle * adjFreq + + motion.curAnim.joints[3].pitchPhase + 180 + reverseModifier)); + + } else { + + pitchOscLeft = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase)); + + pitchOscRight = Math.sin(filter.degToRad(cycle * adjFreq * sideStepFootPitchModifier + + motion.curAnim.joints[3].pitchPhase + 180)); + } + + yawOsc = Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].yawPhase)); + + pitchOscLeft *= motion.curAnim.joints[3].pitch; + pitchOscRight *= motion.curAnim.joints[3].pitch; + + yawOsc *= motion.curAnim.joints[3].yaw; + + rollOsc = motion.curAnim.joints[3].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[3].rollPhase)); + + pitchOffset = motion.curAnim.joints[3].pitchOffset; + yawOffset = motion.curAnim.joints[3].yawOffset; + rollOffset = motion.curAnim.joints[3].rollOffset; } - if(playFootStepSounds) { - Overlays.editOverlay(footstepsBigButtonSelected, { visible: showButtons } ); - Overlays.editOverlay(footstepsBigButton, { visible: false } ); + + // apply foot rotations + MyAvatar.setJointData("LeftFoot", Quat.fromPitchYawRollDegrees( + pitchOscLeft + pitchOffset, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + MyAvatar.setJointData("RightFoot", Quat.fromPitchYawRollDegrees( + pitchOscRight + pitchOffset, + yawOsc + yawOffset, + rollOsc + rollOffset)); + + // play footfall sound yet? To determine this, we take the differential of the + // foot's pitch curve to decide when the foot hits the ground. + if (state.currentState === state.WALKING || + state.currentState === state.SIDE_STEP || + state.currentState === state.EDIT_WALK_STYLES || + state.currentState === state.EDIT_WALK_TWEAKS || + state.currentState === state.EDIT_WALK_JOINTS || + state.currentState === state.EDIT_SIDESTEP_LEFT || + state.currentState === state.EDIT_SIDESTEP_RIGHT) { + + // find dy/dx by determining the cosine wave for the foot's pitch function. + var feetPitchDifferential = Math.cos(filter.degToRad((cycle * adjFreq) + motion.curAnim.joints[3].pitchPhase)); + var threshHold = 0.9; // sets the audio trigger point. with accuracy. + if (feetPitchDifferential < -threshHold && + motion.nextStep === LEFT && + motion.direction !== UP && + motion.direction !== DOWN) { + + playFootstep(LEFT); + motion.nextStep = RIGHT; + } else if (feetPitchDifferential > threshHold && + motion.nextStep === RIGHT && + motion.direction !== UP && + motion.direction !== DOWN) { + + playFootstep(RIGHT); + motion.nextStep = LEFT; + } + } + + // toes + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].pitchPhase)); + + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].yawPhase)); + + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[4].rollPhase)); + + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[4].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[4].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[4].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[4].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * cycle * adjFreq) + + motion.curAnim.joints[4].pitchPhase)); + + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].yawPhase)); + + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].rollPhase)); + + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[4].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[4].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[4].rollPhase)); + + pitchOffsetLast = motion.curTransition.lastAnim.joints[4].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[4].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[4].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + } else { - Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } ); - Overlays.editOverlay(footstepsBigButton, { visible: showButtons } ); - } -} -function minimiseDialog() { - if(minimised) { - setBackground(); - hidebuttonOverlays(); - setSliderThumbsVisible(false); - hideJointControls(); - showFrontPanelButtons(false); - Overlays.editOverlay(controlsMinimisedTab, { visible: true } ); - } else { - setInternalState(STANDING); // show all the controls again - Overlays.editOverlay(controlsMinimisedTab, { visible: false } ); - } -} -function setBackground(backgroundName) { - for(var i in backgroundOverlays) { - if(backgroundOverlays[i] === backgroundName) - Overlays.editOverlay(backgroundName, { visible: true } ); - else Overlays.editOverlay(backgroundOverlays[i], { visible: false } ); - } -} -function setButtonOverlayVisible(buttonOverlayName) { - for(var i in buttonOverlays) { - if(buttonOverlays[i] === buttonOverlayName) { - Overlays.editOverlay(buttonOverlayName, { visible: true } ); - } - } -} -// top row menu type buttons (smaller) -function hidebuttonOverlays() { - for(var i in buttonOverlays) { - Overlays.editOverlay(buttonOverlays[i], { visible: false } ); - } -} -function hideJointControls() { - for(var i in jointsControlOverlays) { - Overlays.editOverlay(jointsControlOverlays[i], { visible: false } ); - } -} -function setSliderThumbsVisible(thumbsVisible) { - for(var i = 0 ; i < sliderThumbOverlays.length ; i++) { - Overlays.editOverlay(sliderThumbOverlays[i], { visible: thumbsVisible } ); - } -} -function initialiseJointsEditingPanel(propertyIndex) { + pitchOsc = motion.curAnim.joints[4].pitch * + Math.sin(filter.degToRad((2 * cycle * adjFreq) + + motion.curAnim.joints[4].pitchPhase)); - selectedJointIndex = propertyIndex; + yawOsc = motion.curAnim.joints[4].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].yawPhase)); - // set the image for the selected joint on the character control - hideJointControls(); - switch (selectedJointIndex) { - case 0: - Overlays.editOverlay(hipsJointControl, { visible: true }); - break; - case 1: - Overlays.editOverlay(upperLegsJointControl, { visible: true }); - break; - case 2: - Overlays.editOverlay(lowerLegsJointControl, { visible: true }); - break; - case 3: - Overlays.editOverlay(feetJointControl, { visible: true }); - break; - case 4: - Overlays.editOverlay(toesJointControl, { visible: true }); - break; - case 5: - Overlays.editOverlay(spineJointControl, { visible: true }); - break; - case 6: - Overlays.editOverlay(spine1JointControl, { visible: true }); - break; - case 7: - Overlays.editOverlay(spine2JointControl, { visible: true }); - break; - case 8: - Overlays.editOverlay(shouldersJointControl, { visible: true }); - break; - case 9: - Overlays.editOverlay(upperArmsJointControl, { visible: true }); - break; - case 10: - Overlays.editOverlay(forearmsJointControl, { visible: true }); - break; - case 11: - Overlays.editOverlay(handsJointControl, { visible: true }); - break; - case 12: - Overlays.editOverlay(headJointControl, { visible: true }); - break; - } + rollOsc = motion.curAnim.joints[4].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[4].rollPhase)); - // set sliders to adjust individual joint properties - var i = 0; - var yLocation = backgroundY+359; - - // pitch your role - var sliderXPos = currentAnimation.joints[selectedJointIndex].pitch - / sliderRanges.joints[selectedJointIndex].pitchRange * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = currentAnimation.joints[selectedJointIndex].yaw - / sliderRanges.joints[selectedJointIndex].yawRange * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = currentAnimation.joints[selectedJointIndex].roll - / sliderRanges.joints[selectedJointIndex].rollRange * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - - // set phases (full range, -180 to 180) - sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].pitchPhase/2)/180 * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].yawPhase/2)/180 * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = (90 + currentAnimation.joints[selectedJointIndex].rollPhase/2)/180 * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - - // offset ranges are also -ve thr' zero to +ve, so have to offset - sliderXPos = (((sliderRanges.joints[selectedJointIndex].pitchOffsetRange+currentAnimation.joints[selectedJointIndex].pitchOffset)/2) - /sliderRanges.joints[selectedJointIndex].pitchOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = (((sliderRanges.joints[selectedJointIndex].yawOffsetRange+currentAnimation.joints[selectedJointIndex].yawOffset)/2) - /sliderRanges.joints[selectedJointIndex].yawOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); - sliderXPos = (((sliderRanges.joints[selectedJointIndex].rollOffsetRange+currentAnimation.joints[selectedJointIndex].rollOffset)/2) - /sliderRanges.joints[selectedJointIndex].rollOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=30, visible: true }); -} - -function initialiseWalkTweaks() { - - // set sliders to adjust walk properties - var i = 0; - var yLocation = backgroundY+71; - - var sliderXPos = currentAnimation.settings.baseFrequency / MAX_WALK_SPEED * sliderRangeX; // walk speed - Overlays.editOverlay(sliderThumbOverlays[i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = 0 * sliderRangeX; // start flying speed - depricated - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = currentAnimation.joints[0].sway / sliderRanges.joints[0].swayRange * sliderRangeX; // Hips sway - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = currentAnimation.joints[0].bob / sliderRanges.joints[0].bobRange * sliderRangeX; // Hips bob - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = currentAnimation.joints[0].thrust / sliderRanges.joints[0].thrustRange * sliderRangeX; // Hips thrust - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = (((sliderRanges.joints[1].rollOffsetRange+currentAnimation.joints[1].rollOffset)/2) // legs separation - is upper legs roll offset - / sliderRanges.joints[1].rollOffsetRange) * sliderRangeX; - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = currentAnimation.joints[1].pitch / sliderRanges.joints[1].pitchRange * sliderRangeX; // stride - is upper legs pitch - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = currentAnimation.joints[9].yaw / sliderRanges.joints[9].yawRange * sliderRangeX; // arms swing - is upper arms yaw - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); - sliderXPos = (((sliderRanges.joints[9].pitchOffsetRange-currentAnimation.joints[9].pitchOffset)/2) - / sliderRanges.joints[9].pitchOffsetRange) * sliderRangeX; // arms out - is upper arms pitch offset - Overlays.editOverlay(sliderThumbOverlays[++i], { x: minSliderX + sliderXPos, y: yLocation+=60, visible: true }); -} - -function showWalkStyleButtons(showButtons) { - - // set all big buttons to hidden, but skip the first 8, as are for the front panel - for(var i = 8 ; i < bigButtonOverlays.length ; i++) { - Overlays.editOverlay(bigButtonOverlays[i], { visible: false }); + pitchOffset = motion.curAnim.joints[4].pitchOffset; + yawOffset = motion.curAnim.joints[4].yawOffset; + rollOffset = motion.curAnim.joints[4].rollOffset; } - if(!showButtons) return; + // apply toe rotations + MyAvatar.setJointData("RightToeBase", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc + yawOffset, + rollOsc + rollOffset)); - // set all the non-selected ones to showing - for(var i = 8 ; i < bigButtonOverlays.length ; i+=2) { - Overlays.editOverlay(bigButtonOverlays[i], { visible: showButtons }); + MyAvatar.setJointData("LeftToeBase", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc - yawOffset, + rollOsc - rollOffset)); + + // spine + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim + .joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[5].pitchPhase)) + + motion.curTransition.lastAnim.joints[5].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[5].yawPhase)) + + motion.curTransition.lastAnim.joints[5].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[5].rollPhase)) + + motion.curTransition.lastAnim.joints[5].rollOffset; + } else { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim.joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[5].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[5].pitchPhase)) + + motion.curTransition.lastAnim.joints[5].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[5].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[5].yawPhase)) + + motion.curTransition.lastAnim.joints[5].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[5].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[5].rollPhase)) + + motion.curTransition.lastAnim.joints[5].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[5].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[5].pitchPhase)) + + motion.curAnim.joints[5].pitchOffset; + + yawOsc = motion.curAnim.joints[5].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].yawPhase)) + + motion.curAnim.joints[5].yawOffset; + + rollOsc = motion.curAnim.joints[5].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[5].rollPhase)) + + motion.curAnim.joints[5].rollOffset; } - // set the currently selected one - if(selectedWalk === femaleStrutWalk || selectedWalk === maleStrutWalk) { - Overlays.editOverlay(strutWalkBigButtonSelected, { visible: showButtons }); - Overlays.editOverlay(strutWalkBigButton, {visible: false}); + // apply spine joint rotations + MyAvatar.setJointData("Spine", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + // spine 1 + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[6].pitchPhase)) + + motion.curTransition.lastAnim.joints[6].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[6].yawPhase)) + + motion.curTransition.lastAnim.joints[6].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[6].rollPhase)) + + motion.curTransition.lastAnim.joints[6].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[6].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[6].pitchPhase)) + + motion.curTransition.lastAnim.joints[6].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[6].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[6].yawPhase)) + + motion.curTransition.lastAnim.joints[6].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[6].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[6].rollPhase)) + + motion.curTransition.lastAnim.joints[6].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[6].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[6].pitchPhase)) + + motion.curAnim.joints[6].pitchOffset; + + yawOsc = motion.curAnim.joints[6].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].yawPhase)) + + motion.curAnim.joints[6].yawOffset; + + rollOsc = motion.curAnim.joints[6].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[6].rollPhase)) + + motion.curAnim.joints[6].rollOffset; } + + // apply spine1 joint rotations + MyAvatar.setJointData("Spine1", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + // spine 2 + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos * 2 + + motion.curTransition.lastAnim.joints[7].pitchPhase)) + + motion.curTransition.lastAnim.joints[7].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[7].yawPhase)) + + motion.curTransition.lastAnim.joints[7].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[7].rollPhase)) + + motion.curTransition.lastAnim.joints[7].rollOffset; + } else { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[7].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * 2 * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].pitchPhase)) + + motion.curTransition.lastAnim.joints[7].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[7].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].yawPhase)) + + motion.curTransition.lastAnim.joints[7].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[7].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[7].rollPhase)) + + motion.curTransition.lastAnim.joints[7].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = motion.curAnim.joints[7].pitch * + Math.sin(filter.degToRad(cycle * adjFreq * 2 + + motion.curAnim.joints[7].pitchPhase)) + + motion.curAnim.joints[7].pitchOffset; + + yawOsc = motion.curAnim.joints[7].yaw * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].yawPhase)) + + motion.curAnim.joints[7].yawOffset; + + rollOsc = motion.curAnim.joints[7].roll * + Math.sin(filter.degToRad(cycle * adjFreq + + motion.curAnim.joints[7].rollPhase)) + + motion.curAnim.joints[7].rollOffset; + } + + // apply spine2 joint rotations + MyAvatar.setJointData("Spine2", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + + if (!motion.armsFree) { + + // shoulders + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curAnim.calibration.frequency + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].pitchPhase)) + + motion.curTransition.lastAnim.joints[8].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[8].rollPhase)) + + motion.curTransition.lastAnim.joints[8].rollOffset; + + yawOffsetLast = motion.curTransition.lastAnim.joints[8].yawOffset; + + } else { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[8].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].pitchPhase)) + + motion.curTransition.lastAnim.joints[8].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[8].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[8].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[8].rollPhase)) + + motion.curTransition.lastAnim.joints[8].rollOffset; + + yawOffsetLast = motion.curTransition.lastAnim.joints[8].yawOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[8].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].pitchPhase)) + + motion.curAnim.joints[8].pitchOffset; + + yawOsc = motion.curAnim.joints[8].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].yawPhase)); + + rollOsc = motion.curAnim.joints[8].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[8].rollPhase)) + + motion.curAnim.joints[8].rollOffset; + + yawOffset = motion.curAnim.joints[8].yawOffset; + } + + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc + yawOffset, rollOsc)); + MyAvatar.setJointData("LeftShoulder", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc - yawOffset, -rollOsc)); + + // upper arms + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[9].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].pitchPhase)); + + yawOscLast = motion.curTransition.lastAnim.joints[9].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[9].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[9].rollPhase)) + + motion.curTransition.lastAnim.joints[9].rollOffset; + + pitchOffsetLast = motion.curTransition.lastAnim.joints[9].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[9].yawOffset; + + } else { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[9].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].pitchPhase)) + + yawOscLast = motion.curTransition.lastAnim.joints[9].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].yawPhase)) + + rollOscLast = motion.curTransition.lastAnim.joints[9].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[9].rollPhase)) + + motion.curTransition.lastAnim.joints[9].rollOffset; + + pitchOffsetLast = motion.curTransition.lastAnim.joints[9].pitchOffset; + yawOffsetLast = motion.curTransition.lastAnim.joints[9].yawOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + pitchOffset = (transProgress * pitchOffset) + ((1 - transProgress) * pitchOffsetLast); + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[9].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].pitchPhase)); + + yawOsc = motion.curAnim.joints[9].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[9].yawPhase)); + + rollOsc = motion.curAnim.joints[9].roll * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[9].rollPhase)) + + motion.curAnim.joints[9].rollOffset; + + pitchOffset = motion.curAnim.joints[9].pitchOffset; + yawOffset = motion.curAnim.joints[9].yawOffset; + + } + + MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( + (-1 * flyingModifier) * pitchOsc + pitchOffset, + yawOsc - yawOffset, + rollOsc)); + + MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees( + pitchOsc + pitchOffset, + yawOsc + yawOffset, + -rollOsc)); + + // forearms + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].pitchPhase)) + + motion.curTransition.lastAnim.joints[10].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[10].rollPhase)); + + yawOffsetLast = motion.curTransition.lastAnim.joints[10].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[10].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[10].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].pitchPhase)) + + motion.curTransition.lastAnim.joints[10].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[10].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].yawPhase)); + + rollOscLast = motion.curTransition.lastAnim.joints[10].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[10].rollPhase)); + + yawOffsetLast = motion.curTransition.lastAnim.joints[10].yawOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[10].rollOffset; + } + + // blend the animations + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = -(transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + yawOffset = (transProgress * yawOffset) + ((1 - transProgress) * yawOffsetLast); + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[10].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].pitchPhase)) + + motion.curAnim.joints[10].pitchOffset; + + yawOsc = motion.curAnim.joints[10].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].yawPhase)); + + rollOsc = motion.curAnim.joints[10].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[10].rollPhase)); + + yawOffset = motion.curAnim.joints[10].yawOffset; + rollOffset = motion.curAnim.joints[10].rollOffset; + } + + // apply forearms rotations + MyAvatar.setJointData("RightForeArm", + Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc + yawOffset, rollOsc + rollOffset)); + MyAvatar.setJointData("LeftForeArm", + Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc - yawOffset, rollOsc - rollOffset)); + + // hands + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[11].rollPhase)); + + pitchOscLast = motion.curTransition.lastAnim.joints[11].pitch * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].pitchPhase)) + + motion.curTransition.lastAnim.joints[11].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[11].yaw * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].yawPhase)) + + motion.curTransition.lastAnim.joints[11].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[11].roll * + Math.sin(filter.degToRad(motion.walkWheelPos + + motion.curTransition.lastAnim.joints[11].rollPhase)) + + rollOffset = motion.curAnim.joints[11].rollOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[11].rollOffset; + + } else { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].rollPhase)); + + rollOffset = motion.curAnim.joints[11].rollOffset; + + pitchOscLast = motion.curTransition.lastAnim.joints[11].pitch * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].pitchPhase)) + + motion.curTransition.lastAnim.joints[11].pitchOffset; + + yawOscLast = motion.curTransition.lastAnim.joints[11].yaw * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].yawPhase)) + + motion.curTransition.lastAnim.joints[11].yawOffset; + + rollOscLast = motion.curTransition.lastAnim.joints[11].roll * + Math.sin(filter.degToRad(motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency + + motion.curTransition.lastAnim.joints[11].rollPhase)) + + rollOffset = motion.curAnim.joints[11].rollOffset; + rollOffsetLast = motion.curTransition.lastAnim.joints[11].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + rollOffset = (transProgress * rollOffset) + ((1 - transProgress) * rollOffsetLast); + + } else { + + pitchOsc = motion.curAnim.joints[11].pitch * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].pitchPhase)) + + motion.curAnim.joints[11].pitchOffset; + + yawOsc = motion.curAnim.joints[11].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].yawPhase)) + + motion.curAnim.joints[11].yawOffset; + + rollOsc = motion.curAnim.joints[11].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[11].rollPhase)); + + rollOffset = motion.curAnim.joints[11].rollOffset; + } + + // set the hand rotations + MyAvatar.setJointData("RightHand", + Quat.fromPitchYawRollDegrees(sideStepHandPitchSign * pitchOsc, yawOsc, rollOsc + rollOffset)); + MyAvatar.setJointData("LeftHand", + Quat.fromPitchYawRollDegrees(pitchOsc, -yawOsc, rollOsc - rollOffset)); + + } // end if (!motion.armsFree) + + // head and neck + if (motion.curTransition !== nullTransition) { + + if (motion.curTransition.walkingAtStart) { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curAnim.calibration.frequency) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + + pitchOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.walkWheelPos * 2) + + motion.curTransition.lastAnim.joints[12].pitchPhase)) + + motion.curTransition.lastAnim.joints[12].pitchOffset; + + yawOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[12].yawPhase)) + + motion.curTransition.lastAnim.joints[12].yawOffset; + + rollOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.walkWheelPos) + + motion.curTransition.lastAnim.joints[12].rollPhase)) + + motion.curTransition.lastAnim.joints[12].rollOffset; + + } else { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + + pitchOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].pitch * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency * 2) + + motion.curTransition.lastAnim.joints[12].pitchPhase)) + + motion.curTransition.lastAnim.joints[12].pitchOffset; + + yawOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].yaw * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[12].yawPhase)) + + motion.curTransition.lastAnim.joints[12].yawOffset; + + rollOscLast = 0.5 * motion.curTransition.lastAnim.joints[12].roll * + Math.sin(filter.degToRad((motion.cumulativeTime * + motion.curTransition.lastAnim.calibration.frequency) + + motion.curTransition.lastAnim.joints[12].rollPhase)) + + motion.curTransition.lastAnim.joints[12].rollOffset; + } + + pitchOsc = (transProgress * pitchOsc) + ((1 - transProgress) * pitchOscLast); + yawOsc = (transProgress * yawOsc) + ((1 - transProgress) * yawOscLast); + rollOsc = (transProgress * rollOsc) + ((1 - transProgress) * rollOscLast); + + } else { + + pitchOsc = 0.5 * motion.curAnim.joints[12].pitch * + Math.sin(filter.degToRad((cycle * adjFreq * 2) + + motion.curAnim.joints[12].pitchPhase)) + + motion.curAnim.joints[12].pitchOffset; + + yawOsc = 0.5 * motion.curAnim.joints[12].yaw * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].yawPhase)) + + motion.curAnim.joints[12].yawOffset; + + rollOsc = 0.5 * motion.curAnim.joints[12].roll * + Math.sin(filter.degToRad((cycle * adjFreq) + + motion.curAnim.joints[12].rollPhase)) + + motion.curAnim.joints[12].rollOffset; + } + + MyAvatar.setJointData("Head", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); + MyAvatar.setJointData("Neck", Quat.fromPitchYawRollDegrees(pitchOsc, yawOsc, rollOsc)); } -// mouse event handlers -var movingSliderOne = false; -var movingSliderTwo = false; -var movingSliderThree = false; -var movingSliderFour = false; -var movingSliderFive = false; -var movingSliderSix = false; -var movingSliderSeven = false; -var movingSliderEight = false; -var movingSliderNine = false; - -function mousePressEvent(event) { - - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - - // check for a character joint control click - switch (clickedOverlay) { - - case hideButton: - Overlays.editOverlay(hideButton, { visible: false } ); - Overlays.editOverlay(hideButtonSelected, { visible: true } ); - return; - - case backButton: - Overlays.editOverlay(backButton, { visible: false } ); - Overlays.editOverlay(backButtonSelected, { visible: true } ); - return; - - case controlsMinimisedTab: - // TODO: add visual user feedback for tab click - return; - - case footstepsBigButton: - playFootStepSounds = true; - Overlays.editOverlay(footstepsBigButtonSelected, { visible: true } ); - Overlays.editOverlay(footstepsBigButton, { visible: false } ); - return; - - case footstepsBigButtonSelected: - playFootStepSounds = false; - Overlays.editOverlay(footstepsBigButton, { visible: true } ); - Overlays.editOverlay(footstepsBigButtonSelected, { visible: false } ); - return; - - case femaleBigButton: - case maleBigButtonSelected: - avatarGender = FEMALE; - selectedWalk = femaleStrutWalk; - selectedStand = femaleStandOne; - selectedFlyUp = femaleFlyingUp; - selectedFly = femaleFlying; - selectedFlyDown = femaleFlyingDown; - selectedSideStepLeft = femaleSideStepLeft; - selectedSideStepRight = femaleSideStepRight; - Overlays.editOverlay(femaleBigButtonSelected, { visible: true } ); - Overlays.editOverlay(femaleBigButton, { visible: false } ); - Overlays.editOverlay(maleBigButton, { visible: true } ); - Overlays.editOverlay(maleBigButtonSelected, { visible: false } ); - return; - - case armsFreeBigButton: - armsFree = true; - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: true } ); - Overlays.editOverlay(armsFreeBigButton, { visible: false } ); - return; - - case armsFreeBigButtonSelected: - armsFree = false; - Overlays.editOverlay(armsFreeBigButtonSelected, { visible: false } ); - Overlays.editOverlay(armsFreeBigButton, { visible: true } ); - return; - - case maleBigButton: - case femaleBigButtonSelected: - avatarGender = MALE; - selectedWalk = maleStrutWalk; - selectedStand = maleStandOne; - selectedFlyUp = maleFlyingUp; - selectedFly = maleFlying; - selectedFlyDown = maleFlyingDown; - selectedSideStepLeft = maleSideStepLeft; - selectedSideStepRight = maleSideStepRight; - Overlays.editOverlay(femaleBigButton, { visible: true } ); - Overlays.editOverlay(femaleBigButtonSelected, { visible: false } ); - Overlays.editOverlay(maleBigButtonSelected, { visible: true } ); - Overlays.editOverlay(maleBigButton, { visible: false } ); - return; - - - case strutWalkBigButton: - if(avatarGender===FEMALE) selectedWalk = femaleStrutWalk; - else selectedWalk = maleStrutWalk; - currentAnimation = selectedWalk; - showWalkStyleButtons(true); - return; - - case strutWalkBigButtonSelected: - - // toggle forwards / backwards walk display - if(principleDirection===DIRECTION_FORWARDS) { - principleDirection=DIRECTION_BACKWARDS; - } else principleDirection=DIRECTION_FORWARDS; - return; - - case sliderOne: - movingSliderOne = true; - return; - - case sliderTwo: - movingSliderTwo = true; - return; - - case sliderThree: - movingSliderThree = true; - return; - - case sliderFour: - movingSliderFour = true; - return; - - case sliderFive: - movingSliderFive = true; - return; - - case sliderSix: - movingSliderSix = true; - return; - - case sliderSeven: - movingSliderSeven = true; - return; - - case sliderEight: - movingSliderEight = true; - return; - - case sliderNine: - movingSliderNine = true; - return; - } - - if( INTERNAL_STATE===CONFIG_WALK_JOINTS || - INTERNAL_STATE===CONFIG_STANDING || - INTERNAL_STATE===CONFIG_FLYING || - INTERNAL_STATE===CONFIG_FLYING_UP || - INTERNAL_STATE===CONFIG_FLYING_DOWN || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - - // check for new joint selection and update display accordingly - var clickX = event.x - backgroundX - 75; - var clickY = event.y - backgroundY - 92; - - if(clickX>60&&clickX<120&&clickY>123&&clickY<155) { - initialiseJointsEditingPanel(0); - return; - } - else if(clickX>63&&clickX<132&&clickY>156&&clickY<202) { - initialiseJointsEditingPanel(1); - return; - } - else if(clickX>58&&clickX<137&&clickY>203&&clickY<250) { - initialiseJointsEditingPanel(2); - return; - } - else if(clickX>58&&clickX<137&&clickY>250&&clickY<265) { - initialiseJointsEditingPanel(3); - return; - } - else if(clickX>58&&clickX<137&&clickY>265&&clickY<280) { - initialiseJointsEditingPanel(4); - return; - } - else if(clickX>78&&clickX<121&&clickY>111&&clickY<128) { - initialiseJointsEditingPanel(5); - return; - } - else if(clickX>78&&clickX<128&&clickY>89&&clickY<111) { - initialiseJointsEditingPanel(6); - return; - } - else if(clickX>85&&clickX<118&&clickY>77&&clickY<94) { - initialiseJointsEditingPanel(7); - return; - } - else if(clickX>64&&clickX<125&&clickY>55&&clickY<77) { - initialiseJointsEditingPanel(8); - return; - } - else if((clickX>44&&clickX<73&&clickY>71&&clickY<94) - ||(clickX>125&&clickX<144&&clickY>71&&clickY<94)) { - initialiseJointsEditingPanel(9); - return; - } - else if((clickX>28&&clickX<57&&clickY>94&&clickY<119) - ||(clickX>137&&clickX<170&&clickY>97&&clickY<114)) { - initialiseJointsEditingPanel(10); - return; - } - else if((clickX>18&&clickX<37&&clickY>115&&clickY<136) - ||(clickX>157&&clickX<182&&clickY>115&&clickY<136)) { - initialiseJointsEditingPanel(11); - return; - } - else if(clickX>81&&clickX<116&&clickY>12&&clickY<53) { - initialiseJointsEditingPanel(12); - return; - } - } -} -function mouseMoveEvent(event) { - - // only need deal with slider changes - if(powerOn) { - - if( INTERNAL_STATE===CONFIG_WALK_JOINTS || - INTERNAL_STATE===CONFIG_STANDING || - INTERNAL_STATE===CONFIG_FLYING || - INTERNAL_STATE===CONFIG_FLYING_UP || - INTERNAL_STATE===CONFIG_FLYING_DOWN || - INTERNAL_STATE===CONFIG_SIDESTEP_LEFT || - INTERNAL_STATE===CONFIG_SIDESTEP_RIGHT ) { - - var thumbClickOffsetX = event.x - minSliderX; - var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; - if(thumbPositionNormalised<0) thumbPositionNormalised = 0; - if(thumbPositionNormalised>1) thumbPositionNormalised = 1; - var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range - - if(movingSliderOne) { // currently selected joint pitch - Overlays.editOverlay(sliderOne, { x: sliderX + minSliderX} ); - currentAnimation.joints[selectedJointIndex].pitch = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].pitchRange; - } - else if(movingSliderTwo) { // currently selected joint yaw - Overlays.editOverlay(sliderTwo, { x: sliderX + minSliderX} ); - currentAnimation.joints[selectedJointIndex].yaw = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].yawRange; - } - else if(movingSliderThree) { // currently selected joint roll - Overlays.editOverlay(sliderThree, { x: sliderX + minSliderX} ); - currentAnimation.joints[selectedJointIndex].roll = thumbPositionNormalised * sliderRanges.joints[selectedJointIndex].rollRange; - } - else if(movingSliderFour) { // currently selected joint pitch phase - Overlays.editOverlay(sliderFour, { x: sliderX + minSliderX} ); - var newPhase = 360 * thumbPositionNormalised - 180; - currentAnimation.joints[selectedJointIndex].pitchPhase = newPhase; - } - else if(movingSliderFive) { // currently selected joint yaw phase; - Overlays.editOverlay(sliderFive, { x: sliderX + minSliderX} ); - var newPhase = 360 * thumbPositionNormalised - 180; - currentAnimation.joints[selectedJointIndex].yawPhase = newPhase; - } - else if(movingSliderSix) { // currently selected joint roll phase - Overlays.editOverlay(sliderSix, { x: sliderX + minSliderX} ); - var newPhase = 360 * thumbPositionNormalised - 180; - currentAnimation.joints[selectedJointIndex].rollPhase = newPhase; - } - else if(movingSliderSeven) { // currently selected joint pitch offset - Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} ); // currently selected joint pitch offset - var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].pitchOffsetRange; - currentAnimation.joints[selectedJointIndex].pitchOffset = newOffset; - } - else if(movingSliderEight) { // currently selected joint yaw offset - Overlays.editOverlay(sliderEight, { x: sliderX + minSliderX} ); // currently selected joint yaw offset - var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].yawOffsetRange; - currentAnimation.joints[selectedJointIndex].yawOffset = newOffset; - } - else if(movingSliderNine) { // currently selected joint roll offset - Overlays.editOverlay(sliderNine, { x: sliderX + minSliderX} ); // currently selected joint roll offset - var newOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[selectedJointIndex].rollOffsetRange; - currentAnimation.joints[selectedJointIndex].rollOffset = newOffset; - } - } - else if(INTERNAL_STATE===CONFIG_WALK_TWEAKS) { - - var thumbClickOffsetX = event.x - minSliderX; - var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; - if(thumbPositionNormalised<0) thumbPositionNormalised = 0; - if(thumbPositionNormalised>1) thumbPositionNormalised = 1; - var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range - - if(movingSliderOne) { // walk speed - paused = true; // avoid nasty jittering - Overlays.editOverlay(sliderOne, { x: sliderX + minSliderX} ); - currentAnimation.settings.baseFrequency = thumbPositionNormalised * MAX_WALK_SPEED; - } - else if(movingSliderTwo) { // take flight speed - Overlays.editOverlay(sliderTwo, { x: sliderX + minSliderX} ); - //currentAnimation.settings.takeFlightVelocity = thumbPositionNormalised * 300; - } - else if(movingSliderThree) { // hips sway - Overlays.editOverlay(sliderThree, { x: sliderX + minSliderX} ); - currentAnimation.joints[0].sway = thumbPositionNormalised * sliderRanges.joints[0].swayRange; - } - else if(movingSliderFour) { // hips bob - Overlays.editOverlay(sliderFour, { x: sliderX + minSliderX} ); - currentAnimation.joints[0].bob = thumbPositionNormalised * sliderRanges.joints[0].bobRange; - } - else if(movingSliderFive) { // hips thrust - Overlays.editOverlay(sliderFive, { x: sliderX + minSliderX} ); - currentAnimation.joints[0].thrust = thumbPositionNormalised * sliderRanges.joints[0].thrustRange; - } - else if(movingSliderSix) { // legs separation - Overlays.editOverlay(sliderSix, { x: sliderX + minSliderX} ); - currentAnimation.joints[1].rollOffset = (thumbPositionNormalised-0.5) * 2 * sliderRanges.joints[1].rollOffsetRange; - } - else if(movingSliderSeven) { // stride - Overlays.editOverlay(sliderSeven, { x: sliderX + minSliderX} ); - currentAnimation.joints[1].pitch = thumbPositionNormalised * sliderRanges.joints[1].pitchRange; - } - else if(movingSliderEight) { // arms swing = upper arms yaw - Overlays.editOverlay(sliderEight, { x: sliderX + minSliderX} ); - currentAnimation.joints[9].yaw = thumbPositionNormalised * sliderRanges.joints[9].yawRange; - } - else if(movingSliderNine) { // arms out = upper arms pitch offset - Overlays.editOverlay(sliderNine, { x: sliderX + minSliderX} ); - currentAnimation.joints[9].pitchOffset = (thumbPositionNormalised-0.5) * -2 * sliderRanges.joints[9].pitchOffsetRange; - } - } - } -} -function mouseReleaseEvent(event) { - - var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); - - if(paused) paused = false; - - if(clickedOverlay === offButton) { - powerOn = true; - Overlays.editOverlay(offButton, { visible: false } ); - Overlays.editOverlay(onButton, { visible: true } ); - stand(); - } - else if(clickedOverlay === hideButton || clickedOverlay === hideButtonSelected){ - Overlays.editOverlay(hideButton, { visible: true } ); - Overlays.editOverlay(hideButtonSelected, { visible: false } ); - minimised = true; - minimiseDialog(); - } - else if(clickedOverlay === controlsMinimisedTab) { - minimised = false; - minimiseDialog(); - } - else if(powerOn) { - - if(movingSliderOne) movingSliderOne = false; - else if(movingSliderTwo) movingSliderTwo = false; - else if(movingSliderThree) movingSliderThree = false; - else if(movingSliderFour) movingSliderFour = false; - else if(movingSliderFive) movingSliderFive = false; - else if(movingSliderSix) movingSliderSix = false; - else if(movingSliderSeven) movingSliderSeven = false; - else if(movingSliderEight) movingSliderEight = false; - else if(movingSliderNine) movingSliderNine = false; - else { - - switch(clickedOverlay) { - - case configWalkButtonSelected: - case configStandButtonSelected: - case configSideStepLeftButtonSelected: - case configSideStepRightButtonSelected: - case configFlyingButtonSelected: - case configFlyingUpButtonSelected: - case configFlyingDownButtonSelected: - case configWalkStylesButtonSelected: - case configWalkTweaksButtonSelected: - case configWalkJointsButtonSelected: - setInternalState(STANDING); - break; - - case onButton: - powerOn = false; - setInternalState(STANDING); - Overlays.editOverlay(offButton, { visible: true } ); - Overlays.editOverlay(onButton, { visible: false } ); - resetJoints(); - break; - - case backButton: - case backButtonSelected: - Overlays.editOverlay(backButton, { visible: false } ); - Overlays.editOverlay(backButtonSelected, { visible: false } ); - setInternalState(STANDING); - break; - - case configWalkStylesButton: - setInternalState(CONFIG_WALK_STYLES); - break; - - case configWalkTweaksButton: - setInternalState(CONFIG_WALK_TWEAKS); - break; - - case configWalkJointsButton: - setInternalState(CONFIG_WALK_JOINTS); - break; - - case configWalkButton: - setInternalState(CONFIG_WALK_STYLES); // set the default walk adjustment panel here (i.e. first panel shown when Walk button clicked) - break; - - case configStandButton: - setInternalState(CONFIG_STANDING); - break; - - case configSideStepLeftButton: - setInternalState(CONFIG_SIDESTEP_LEFT); - break; - - case configSideStepRightButton: - setInternalState(CONFIG_SIDESTEP_RIGHT); - break; - - case configFlyingButton: - setInternalState(CONFIG_FLYING); - break; - - case configFlyingUpButton: - setInternalState(CONFIG_FLYING_UP); - break; - - case configFlyingDownButton: - setInternalState(CONFIG_FLYING_DOWN); - break; - } - } - } -} -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - -// Script ending -Script.scriptEnding.connect(function() { - - // remove the background overlays - for(var i in backgroundOverlays) { - Overlays.deleteOverlay(backgroundOverlays[i]); - } - // remove the button overlays - for(var i in buttonOverlays) { - Overlays.deleteOverlay(buttonOverlays[i]); - } - // remove the slider thumb overlays - for(var i in sliderThumbOverlays) { - Overlays.deleteOverlay(sliderThumbOverlays[i]); - } - // remove the character joint control overlays - for(var i in bigButtonOverlays) { - Overlays.deleteOverlay(jointsControlOverlays[i]); - } - // remove the big button overlays - for(var i in bigButtonOverlays) { - Overlays.deleteOverlay(bigButtonOverlays[i]); - } - // remove the mimimised tab - Overlays.deleteOverlay(controlsMinimisedTab); - - // remove the walk wheel overlays - Overlays.deleteOverlay(walkWheelYLine); - Overlays.deleteOverlay(walkWheelZLine); - Overlays.deleteOverlay(walkWheelStats); - - // remove the debug stats overlays - Overlays.deleteOverlay(debugStats); - Overlays.deleteOverlay(debugStatsPeriodic); -}); - -var sideStep = 0.002; // i.e. 2mm increments whilst sidestepping - JS movement keys don't work well :-( -function keyPressEvent(event) { - - if (event.text == "q") { - // export currentAnimation as json string when q key is pressed. reformat result at http://www.freeformatter.com/json-formatter.html - print('\n'); - print('walk.js dumping animation: '+currentAnimation.name+'\n'); - print('\n'); - print(JSON.stringify(currentAnimation), null, '\t'); - } - else if (event.text == "t") { - statsOn = !statsOn; - Overlays.editOverlay(debugStats, {visible: statsOn}); - Overlays.editOverlay(debugStatsPeriodic, {visible: statsOn}); - Overlays.editOverlay(walkWheelStats, {visible: statsOn}); - Overlays.editOverlay(walkWheelYLine, {visible: statsOn}); - Overlays.editOverlay(walkWheelZLine, {visible: statsOn}); - } -} -Controller.keyPressEvent.connect(keyPressEvent); - -// get the list of joint names -var jointList = MyAvatar.getJointNames(); - -// clear the joint data so can calculate hips to feet distance -for(var i = 0 ; i < 5 ; i++) { - MyAvatar.setJointData(i, Quat.fromPitchYawRollDegrees(0,0,0)); -} -// used to position the visual representation of the walkwheel only -var hipsToFeetDistance = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightFoot").y; - -// This script is designed around the Finite State Machine (FSM) model, so to start things up we just select the STANDING state. -setInternalState(STANDING); \ No newline at end of file +// Begin by setting an internal state +state.setInternalState(state.STANDING); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d2d5ff2480..e4ab3994ff 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -92,6 +92,7 @@ #include "scripting/MenuScriptingInterface.h" #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" +#include "scripting/WebWindowClass.h" #include "ui/DataWebDialog.h" #include "ui/InfoView.h" @@ -723,11 +724,11 @@ void Application::paintGL() { displaySide(*whichCamera); glPopMatrix(); - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - renderRearViewMirror(_mirrorViewRect); - - } else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { _rearMirrorTools->render(true); + + } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + renderRearViewMirror(_mirrorViewRect); } _glowEffect.render(); @@ -785,7 +786,7 @@ void Application::updateProjectionMatrix(Camera& camera, bool updateViewFrustum) // Tell our viewFrustum about this change, using the application camera if (updateViewFrustum) { loadViewFrustum(camera, _viewFrustum); - computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); // If we're in Display Frustum mode, then we want to use the slightly adjust near/far clip values of the // _viewFrustumOffsetCamera, so that we can see more of the application content in the application's frustum @@ -2008,25 +2009,17 @@ void Application::init() { void Application::closeMirrorView() { if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - Menu::getInstance()->triggerOption(MenuOption::Mirror);; + Menu::getInstance()->triggerOption(MenuOption::Mirror); } } void Application::restoreMirrorView() { - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - Menu::getInstance()->triggerOption(MenuOption::Mirror);; - } - if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } } void Application::shrinkMirrorView() { - if (!Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - Menu::getInstance()->triggerOption(MenuOption::Mirror);; - } - if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } @@ -3904,6 +3897,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri // register `location` on the global object. scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, LocationScriptingInterface::locationSetter); + + scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); @@ -4313,8 +4308,6 @@ bool Application::isVSyncOn() const { if (wglewGetExtension("WGL_EXT_swap_control")) { int swapInterval = wglGetSwapIntervalEXT(); return (swapInterval > 0); - } else { - return true; } #elif defined(Q_OS_LINUX) // TODO: write the poper code for linux @@ -4325,10 +4318,9 @@ bool Application::isVSyncOn() const { } else { return true; } - */ -#else - return true; + */ #endif + return true; } bool Application::isVSyncEditable() const { @@ -4343,7 +4335,6 @@ bool Application::isVSyncEditable() const { return true; } */ -#else #endif return false; } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a5f6bd897f..2dc94e6027 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -518,6 +518,33 @@ void Audio::initGverb() { gverb_set_taillevel(_gverb, DB_CO(_reverbOptions->getTailLevel())); } +void Audio::updateGverbOptions() { + bool reverbChanged = false; + if (_receivedAudioStream.hasReverb()) { + + if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { + _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); + reverbChanged = true; + } + if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { + _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); + reverbChanged = true; + } + + if (_reverbOptions != &_zoneReverbOptions) { + _reverbOptions = &_zoneReverbOptions; + reverbChanged = true; + } + } else if (_reverbOptions != &_scriptReverbOptions) { + _reverbOptions = &_scriptReverbOptions; + reverbChanged = true; + } + + if (reverbChanged) { + initGverb(); + } +} + void Audio::setReverbOptions(const AudioEffectOptions* options) { // Save the new options _scriptReverbOptions.setMaxRoomSize(options->getMaxRoomSize()); @@ -549,14 +576,14 @@ void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioF gverb_do(_gverb, value, &lValue, &rValue); // Mix, accounting for clipping, the left and right channels. Ignore the rest. - for (unsigned int j = sample; j < sample + audioFormat.channelCount(); j++) { + for (int j = sample; j < sample + audioFormat.channelCount(); j++) { if (j == sample) { // left channel - int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -32768, 32767); + int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); samplesData[j] = (int16_t)lResult; } else if (j == (sample + 1)) { // right channel - int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -32768, 32767); + int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); samplesData[j] = (int16_t)rResult; } else { // ignore channels above 2 @@ -565,6 +592,60 @@ void Audio::addReverb(int16_t* samplesData, int numSamples, QAudioFormat& audioF } } +void Audio::handleLocalEchoAndReverb(QByteArray& inputByteArray) { + bool hasEcho = Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio); + // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. + bool hasLocalReverb = (_reverb || _receivedAudioStream.hasReverb()) && + !Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio); + if (_muted || !_audioOutput || (!hasEcho && !hasLocalReverb)) { + return; + } + + // if this person wants local loopback add that to the locally injected audio + // if there is reverb apply it to local audio and substract the origin samples + + if (!_loopbackOutputDevice && _loopbackAudioOutput) { + // we didn't have the loopback output device going so set that up now + _loopbackOutputDevice = _loopbackAudioOutput->start(); + } + + QByteArray loopBackByteArray(inputByteArray); + if (_inputFormat != _outputFormat) { + float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate()) * + (_outputFormat.channelCount() / _inputFormat.channelCount()); + loopBackByteArray.resize(inputByteArray.size() * loopbackOutputToInputRatio); + loopBackByteArray.fill(0); + linearResampling(reinterpret_cast<int16_t*>(inputByteArray.data()), + reinterpret_cast<int16_t*>(loopBackByteArray.data()), + inputByteArray.size() / sizeof(int16_t), loopBackByteArray.size() / sizeof(int16_t), + _inputFormat, _outputFormat); + } + + if (hasLocalReverb) { + QByteArray loopbackCopy; + if (!hasEcho) { + loopbackCopy = loopBackByteArray; + } + + int16_t* loopbackSamples = reinterpret_cast<int16_t*>(loopBackByteArray.data()); + int numLoopbackSamples = loopBackByteArray.size() / sizeof(int16_t); + updateGverbOptions(); + addReverb(loopbackSamples, numLoopbackSamples, _outputFormat); + + if (!hasEcho) { + int16_t* loopbackCopySamples = reinterpret_cast<int16_t*>(loopbackCopy.data()); + for (int i = 0; i < numLoopbackSamples; ++i) { + loopbackSamples[i] = glm::clamp((int)loopbackSamples[i] - loopbackCopySamples[i], + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); + } + } + } + + if (_loopbackOutputDevice) { + _loopbackOutputDevice->write(loopBackByteArray); + } +} + void Audio::handleAudioInput() { static char audioDataPacket[MAX_PACKET_SIZE]; @@ -609,34 +690,8 @@ void Audio::handleAudioInput() { _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/); } - - if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { - // if this person wants local loopback add that to the locally injected audio - - if (!_loopbackOutputDevice && _loopbackAudioOutput) { - // we didn't have the loopback output device going so set that up now - _loopbackOutputDevice = _loopbackAudioOutput->start(); - } - - if (_inputFormat == _outputFormat) { - if (_loopbackOutputDevice) { - _loopbackOutputDevice->write(inputByteArray); - } - } else { - float loopbackOutputToInputRatio = (_outputFormat.sampleRate() / (float) _inputFormat.sampleRate()) - * (_outputFormat.channelCount() / _inputFormat.channelCount()); - - QByteArray loopBackByteArray(inputByteArray.size() * loopbackOutputToInputRatio, 0); - - linearResampling((int16_t*) inputByteArray.data(), (int16_t*) loopBackByteArray.data(), - inputByteArray.size() / sizeof(int16_t), - loopBackByteArray.size() / sizeof(int16_t), _inputFormat, _outputFormat); - - if (_loopbackOutputDevice) { - _loopbackOutputDevice->write(loopBackByteArray); - } - } - } + + handleLocalEchoAndReverb(inputByteArray); _inputRingBuffer.writeData(inputByteArray.data(), inputByteArray.size()); @@ -973,30 +1028,7 @@ void Audio::processReceivedSamples(const QByteArray& inputBuffer, QByteArray& ou _desiredOutputFormat, _outputFormat); if(_reverb || _receivedAudioStream.hasReverb()) { - bool reverbChanged = false; - if (_receivedAudioStream.hasReverb()) { - - if (_zoneReverbOptions.getReverbTime() != _receivedAudioStream.getRevebTime()) { - _zoneReverbOptions.setReverbTime(_receivedAudioStream.getRevebTime()); - reverbChanged = true; - } - if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { - _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - reverbChanged = true; - } - - if (_reverbOptions != &_zoneReverbOptions) { - _reverbOptions = &_zoneReverbOptions; - reverbChanged = true; - } - } else if (_reverbOptions != &_scriptReverbOptions) { - _reverbOptions = &_scriptReverbOptions; - reverbChanged = true; - } - - if (reverbChanged) { - initGverb(); - } + updateGverbOptions(); addReverb((int16_t*)outputBuffer.data(), numDeviceOutputSamples, _outputFormat); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index d6e26864e6..d8e5c5386c 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -268,8 +268,11 @@ private: // Adds Reverb void initGverb(); + void updateGverbOptions(); void addReverb(int16_t* samples, int numSamples, QAudioFormat& format); + void handleLocalEchoAndReverb(QByteArray& inputByteArray); + // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal void addProceduralSounds(int16_t* monoInput, int numSamples); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 21c1cded88..cd074805b6 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -386,7 +386,7 @@ Menu::Menu() : #if defined(Q_OS_MAC) #else - QAction* vsyncAction = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, this, SLOT(changeVSync())); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true, this, SLOT(changeVSync())); #endif } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5329ff5c1d..9ceb073167 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -49,7 +49,7 @@ const float PITCH_SPEED = 100.0f; // degrees/sec const float COLLISION_RADIUS_SCALAR = 1.2f; // pertains to avatar-to-avatar collisions const float COLLISION_RADIUS_SCALE = 0.125f; -const float MAX_WALKING_SPEED = 4.5f; +const float MAX_WALKING_SPEED = 2.5f; // human walking speed const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // keyboard motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; // speed is set to zero below this diff --git a/interface/src/entities/EntityTreeRenderer.cpp b/interface/src/entities/EntityTreeRenderer.cpp index 2f8ddb1095..1876b6c624 100644 --- a/interface/src/entities/EntityTreeRenderer.cpp +++ b/interface/src/entities/EntityTreeRenderer.cpp @@ -81,6 +81,9 @@ void EntityTreeRenderer::init() { _lastAvatarPosition = avatarPosition + glm::vec3(1.f, 1.f, 1.f); connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity); + connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::checkAndCallPreload); + connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::checkAndCallPreload); + connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID); } QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID) { @@ -770,3 +773,20 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { _entityScripts.remove(entityID); } +void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID) { + // load the entity script if needed... + QScriptValue entityScript = loadEntityScript(entityID); + if (entityScript.property("preload").isValid()) { + QScriptValueList entityArgs = createEntityArgs(entityID); + entityScript.property("preload").call(entityScript, entityArgs); + } +} + +void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID) { + if (_entityScripts.contains(oldEntityID)) { + EntityScriptDetails details = _entityScripts[oldEntityID]; + _entityScripts.remove(oldEntityID); + _entityScripts[newEntityID] = details; + } +} + diff --git a/interface/src/entities/EntityTreeRenderer.h b/interface/src/entities/EntityTreeRenderer.h index ff9066dd6d..7c1c81b6c9 100644 --- a/interface/src/entities/EntityTreeRenderer.h +++ b/interface/src/entities/EntityTreeRenderer.h @@ -104,6 +104,8 @@ signals: public slots: void deletingEntity(const EntityItemID& entityID); + void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); + void checkAndCallPreload(const EntityItemID& entityID); private: QList<Model*> _releasedModels; diff --git a/interface/src/gpu/Batch.cpp b/interface/src/gpu/Batch.cpp index e02a0a551e..e176e1641a 100644 --- a/interface/src/gpu/Batch.cpp +++ b/interface/src/gpu/Batch.cpp @@ -106,7 +106,7 @@ void Batch::setInputStream(Slot startChannel, const BufferStream& stream) { const Buffers& buffers = stream.getBuffers(); const Offsets& offsets = stream.getOffsets(); const Offsets& strides = stream.getStrides(); - for (int i = 0; i < buffers.size(); i++) { + for (unsigned int i = 0; i < buffers.size(); i++) { setInputBuffer(startChannel + i, buffers[i], offsets[i], strides[i]); } } diff --git a/interface/src/gpu/GLBackend.cpp b/interface/src/gpu/GLBackend.cpp index 5e13d03ff4..5c2451d81f 100644 --- a/interface/src/gpu/GLBackend.cpp +++ b/interface/src/gpu/GLBackend.cpp @@ -31,15 +31,15 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glEnable), (&::gpu::GLBackend::do_glDisable), - + (&::gpu::GLBackend::do_glEnableClientState), (&::gpu::GLBackend::do_glDisableClientState), (&::gpu::GLBackend::do_glCullFace), (&::gpu::GLBackend::do_glAlphaFunc), - (&::gpu::GLBackend::do_glDepthFunc), - (&::gpu::GLBackend::do_glDepthMask), + (&::gpu::GLBackend::do_glDepthFunc), + (&::gpu::GLBackend::do_glDepthMask), (&::gpu::GLBackend::do_glDepthRange), (&::gpu::GLBackend::do_glBindBuffer), @@ -57,18 +57,18 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glPushMatrix), (&::gpu::GLBackend::do_glPopMatrix), (&::gpu::GLBackend::do_glMultMatrixf), - (&::gpu::GLBackend::do_glLoadMatrixf), - (&::gpu::GLBackend::do_glLoadIdentity), - (&::gpu::GLBackend::do_glRotatef), - (&::gpu::GLBackend::do_glScalef), - (&::gpu::GLBackend::do_glTranslatef), + (&::gpu::GLBackend::do_glLoadMatrixf), + (&::gpu::GLBackend::do_glLoadIdentity), + (&::gpu::GLBackend::do_glRotatef), + (&::gpu::GLBackend::do_glScalef), + (&::gpu::GLBackend::do_glTranslatef), - (&::gpu::GLBackend::do_glDrawArrays), + (&::gpu::GLBackend::do_glDrawArrays), (&::gpu::GLBackend::do_glDrawRangeElements), - - (&::gpu::GLBackend::do_glColorPointer), - (&::gpu::GLBackend::do_glNormalPointer), - (&::gpu::GLBackend::do_glTexCoordPointer), + + (&::gpu::GLBackend::do_glColorPointer), + (&::gpu::GLBackend::do_glNormalPointer), + (&::gpu::GLBackend::do_glTexCoordPointer), (&::gpu::GLBackend::do_glVertexPointer), (&::gpu::GLBackend::do_glVertexAttribPointer), @@ -77,7 +77,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::GLBackend::do_glColor4f), - (&::gpu::GLBackend::do_glMaterialf), + (&::gpu::GLBackend::do_glMaterialf), (&::gpu::GLBackend::do_glMaterialfv), }; @@ -112,9 +112,8 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { GLBackend::GLBackend() : - _inputFormat(0), - _inputAttributeActivation(0), _needInputFormatUpdate(true), + _inputFormat(0), _inputBuffersState(0), _inputBuffers(_inputBuffersState.size(), BufferPointer(0)), @@ -122,7 +121,8 @@ GLBackend::GLBackend() : _inputBufferStrides(_inputBuffersState.size(), 0), _indexBuffer(0), - _indexBufferOffset(0) + _indexBufferOffset(0), + _inputAttributeActivation(0) { } @@ -138,7 +138,7 @@ void GLBackend::renderBatch(Batch& batch) { GLBackend backend; - for (int i = 0; i < numCommands; i++) { + for (unsigned int i = 0; i < numCommands; i++) { CommandCall call = _commandCalls[(*command)]; (backend.*(call))(batch, *offset); command++; @@ -203,7 +203,7 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { GLenum glType = _elementTypeToGLType[_indexBufferType]; - glDrawElements(mode, numIndices, glType, (GLvoid*)(startIndex + _indexBufferOffset)); + glDrawElements(mode, numIndices, glType, reinterpret_cast<GLvoid*>(startIndex + _indexBufferOffset)); CHECK_GL_ERROR(); } @@ -265,7 +265,7 @@ void GLBackend::updateInput() { } // Manage Activation what was and what is expected now - for (int i = 0; i < newActivation.size(); i++) { + for (unsigned int i = 0; i < newActivation.size(); i++) { bool newState = newActivation[i]; if (newState != _inputAttributeActivation[i]) { #if defined(SUPPORT_LEGACY_OPENGL) @@ -314,7 +314,7 @@ void GLBackend::updateInput() { CHECK_GL_ERROR(); _inputBuffersState[bufferNum] = false; - for (int i = 0; i < channel._slots.size(); i++) { + for (unsigned int i = 0; i < channel._slots.size(); i++) { const Stream::Attribute& attrib = attributes.at(channel._slots[i]); GLuint slot = attrib._slot; GLuint count = attrib._element.getDimensionCount(); @@ -325,16 +325,16 @@ void GLBackend::updateInput() { if (slot < NUM_CLASSIC_ATTRIBS) { switch (slot) { case Stream::POSITION: - glVertexPointer(count, type, stride, (GLvoid*)pointer); + glVertexPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::NORMAL: - glNormalPointer(type, stride, (GLvoid*)pointer); + glNormalPointer(type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::COLOR: - glColorPointer(count, type, stride, (GLvoid*)pointer); + glColorPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; case Stream::TEXCOORD: - glTexCoordPointer(count, type, stride, (GLvoid*)pointer); + glTexCoordPointer(count, type, stride, reinterpret_cast<GLvoid*>(pointer)); break; }; } else { @@ -342,7 +342,8 @@ void GLBackend::updateInput() { { #endif GLboolean isNormalized = attrib._element.isNormalized(); - glVertexAttribPointer(slot, count, type, isNormalized, stride, (GLvoid*)pointer); + glVertexAttribPointer(slot, count, type, isNormalized, stride, + reinterpret_cast<GLvoid*>(pointer)); } CHECK_GL_ERROR(); } diff --git a/interface/src/gpu/Resource.cpp b/interface/src/gpu/Resource.cpp index cd1b4ef84b..3a6e47a7ba 100644 --- a/interface/src/gpu/Resource.cpp +++ b/interface/src/gpu/Resource.cpp @@ -8,6 +8,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include "Context.h" #include "Resource.h" #include <QDebug> diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 38562df696..8d426d067b 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -479,9 +479,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g float bestDistance = std::numeric_limits<float>::max(); float distanceToSubMesh; BoxFace subMeshFace; - BoxFace bestSubMeshFace; int subMeshIndex = 0; - int bestSubMeshIndex = -1; // If we hit the models box, then consider the submeshes... foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { @@ -489,10 +487,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { if (distanceToSubMesh < bestDistance) { - bestSubMeshIndex = subMeshIndex; bestDistance = distanceToSubMesh; - bestSubMeshFace = subMeshFace; intersectedSomething = true; + face = subMeshFace; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } } diff --git a/interface/src/scripting/JoystickScriptingInterface.cpp b/interface/src/scripting/JoystickScriptingInterface.cpp index 68affeda5b..40109703d6 100644 --- a/interface/src/scripting/JoystickScriptingInterface.cpp +++ b/interface/src/scripting/JoystickScriptingInterface.cpp @@ -52,9 +52,12 @@ JoystickScriptingInterface::JoystickScriptingInterface() : for (int i = 0; i < joystickCount; i++) { SDL_GameController* controller = SDL_GameControllerOpen(i); - SDL_JoystickID id = getInstanceId(controller); - Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); - _openJoysticks[id] = joystick; + + if (controller) { + SDL_JoystickID id = getInstanceId(controller); + Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + _openJoysticks[id] = joystick; + } } _isInitialized = true; diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp new file mode 100644 index 0000000000..d280d8eecf --- /dev/null +++ b/interface/src/scripting/WebWindowClass.cpp @@ -0,0 +1,68 @@ +// +// WebWindowClass.cpp +// interface/src/scripting +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include <QVBoxLayout> +#include <QApplication> +#include <QWebFrame> +#include <QWebView> + +#include "WindowScriptingInterface.h" +#include "WebWindowClass.h" + +ScriptEventBridge::ScriptEventBridge(QObject* parent) : QObject(parent) { +} + +void ScriptEventBridge::emitWebEvent(const QString& data) { + emit webEventReceived(data); +} + +void ScriptEventBridge::emitScriptEvent(const QString& data) { + emit scriptEventReceived(data); +} + +WebWindowClass::WebWindowClass(const QString& url, int width, int height) + : QObject(NULL), + _window(new QWidget(NULL, Qt::Tool)), + _eventBridge(new ScriptEventBridge(this)) { + + QWebView* webView = new QWebView(_window); + webView->page()->mainFrame()->addToJavaScriptWindowObject("EventBridge", _eventBridge); + webView->setUrl(url); + QVBoxLayout* layout = new QVBoxLayout(_window); + _window->setLayout(layout); + layout->addWidget(webView); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + _window->setGeometry(0, 0, width, height); + + connect(this, &WebWindowClass::destroyed, _window, &QWidget::deleteLater); +} + +WebWindowClass::~WebWindowClass() { +} + +void WebWindowClass::setVisible(bool visible) { + QMetaObject::invokeMethod(_window, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); +} + +QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { + WebWindowClass* retVal; + QString file = context->argument(0).toString(); + QMetaObject::invokeMethod(WindowScriptingInterface::getInstance(), "doCreateWebWindow", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(WebWindowClass*, retVal), + Q_ARG(const QString&, file), + Q_ARG(int, context->argument(1).toInteger()), + Q_ARG(int, context->argument(2).toInteger())); + + connect(engine, &QScriptEngine::destroyed, retVal, &WebWindowClass::deleteLater); + + return engine->newQObject(retVal); +} diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h new file mode 100644 index 0000000000..7b77299774 --- /dev/null +++ b/interface/src/scripting/WebWindowClass.h @@ -0,0 +1,51 @@ +// +// WebWindowClass.h +// interface/src/scripting +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_WebWindowClass_h +#define hifi_WebWindowClass_h + +#include <QScriptContext> +#include <QScriptEngine> + +class ScriptEventBridge : public QObject { + Q_OBJECT +public: + ScriptEventBridge(QObject* parent = NULL); + +public slots: + void emitWebEvent(const QString& data); + void emitScriptEvent(const QString& data); + +signals: + void webEventReceived(const QString& data); + void scriptEventReceived(const QString& data); + +}; + +class WebWindowClass : public QObject { + Q_OBJECT + Q_PROPERTY(QObject* eventBridge READ getEventBridge) +public: + WebWindowClass(const QString& url, int width, int height); + ~WebWindowClass(); + + static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine); + +public slots: + void setVisible(bool visible); + ScriptEventBridge* getEventBridge() const { return _eventBridge; } + +private: + QWidget* _window; + ScriptEventBridge* _eventBridge; +}; + +#endif diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index ed6f0cf600..8c2066f253 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -34,6 +34,10 @@ WindowScriptingInterface::WindowScriptingInterface() : { } +WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& url, int width, int height) { + return new WebWindowClass(url, width, height); +} + QScriptValue WindowScriptingInterface::hasFocus() { return Application::getInstance()->getGLWidget()->hasFocus(); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 24c21765b5..5529d31efd 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -15,6 +15,11 @@ #include <QObject> #include <QScriptValue> #include <QString> +#include <QFileDialog> +#include <QComboBox> +#include <QLineEdit> + +#include "WebWindowClass.h" class WindowScriptingInterface : public QObject { Q_OBJECT @@ -72,6 +77,8 @@ private slots: void nonBlockingFormAccepted() { _nonBlockingFormActive = false; _formResult = QDialog::Accepted; emit nonBlockingFormClosed(); } void nonBlockingFormRejected() { _nonBlockingFormActive = false; _formResult = QDialog::Rejected; emit nonBlockingFormClosed(); } + + WebWindowClass* doCreateWebWindow(const QString& url, int width, int height); private: WindowScriptingInterface(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 4d2c710be7..e0aa1f3020 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -984,7 +984,9 @@ void ApplicationOverlay::renderAudioMeter() { const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP; int audioMeterY; - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + bool boxed = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) && + !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror); + if (boxed) { audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; } else { audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; @@ -1022,9 +1024,7 @@ void ApplicationOverlay::renderAudioMeter() { renderCollisionOverlay(glWidget->width(), glWidget->height(), magnitude, 1.0f); } - audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, - audioMeterY, - Menu::getInstance()->isOptionChecked(MenuOption::Mirror)); + audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, boxed); audio->renderScope(glWidget->width(), glWidget->height()); diff --git a/interface/src/ui/RearMirrorTools.cpp b/interface/src/ui/RearMirrorTools.cpp index f4b0bb82b5..fb6ef63647 100644 --- a/interface/src/ui/RearMirrorTools.cpp +++ b/interface/src/ui/RearMirrorTools.cpp @@ -156,6 +156,9 @@ void RearMirrorTools::displayIcon(QRect bounds, QRect iconBounds, GLuint texture } glEnd(); glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 69df609ba9..fed041d6ea 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -129,7 +129,7 @@ int TextRenderer::draw(int x, int y, const char* str) { leftBottom.x, rightTop.y, ls, tt, }; const int NUM_COLOR_SCALARS_PER_GLYPH = 4; - unsigned int colorBuffer[NUM_COLOR_SCALARS_PER_GLYPH] = { compactColor, compactColor, compactColor, compactColor }; + int colorBuffer[NUM_COLOR_SCALARS_PER_GLYPH] = { compactColor, compactColor, compactColor, compactColor }; gpu::Buffer::Size offset = sizeof(vertexBuffer) * _numGlyphsBatched; gpu::Buffer::Size colorOffset = sizeof(colorBuffer) * _numGlyphsBatched; @@ -181,9 +181,9 @@ TextRenderer::TextRenderer(const Properties& properties) : _color(properties.color), _glyphsBuffer(new gpu::Buffer()), _glyphsColorBuffer(new gpu::Buffer()), - _numGlyphsBatched(0), _glyphsStreamFormat(new gpu::Stream::Format()), - _glyphsStream(new gpu::BufferStream()) + _glyphsStream(new gpu::BufferStream()), + _numGlyphsBatched(0) { _glyphsStreamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::POS_XYZ), 0); const int NUM_POS_COORDS = 2; diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp new file mode 100644 index 0000000000..c628199fe3 --- /dev/null +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -0,0 +1,118 @@ +// +// Grid3DOverlay.cpp +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "Grid3DOverlay.h" + +#include "Application.h" + +ProgramObject Grid3DOverlay::_gridProgram; + +Grid3DOverlay::Grid3DOverlay() : Base3DOverlay(), + _minorGridWidth(1.0), + _majorGridEvery(5) { +} + +Grid3DOverlay::~Grid3DOverlay() { +} + +void Grid3DOverlay::render(RenderArgs* args) { + if (!_visible) { + return; // do nothing if we're not visible + } + + if (!_gridProgram.isLinked()) { + if (!_gridProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/grid.frag")) { + qDebug() << "Failed to compile: " + _gridProgram.log(); + return; + } + if (!_gridProgram.link()) { + qDebug() << "Failed to link: " + _gridProgram.log(); + return; + } + } + + // Render code largely taken from MetavoxelEditor::render() + glDisable(GL_LIGHTING); + + glDepthMask(GL_FALSE); + + glPushMatrix(); + + glm::quat rotation = getRotation(); + + glm::vec3 axis = glm::axis(rotation); + + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + + glLineWidth(1.5f); + + // center the grid around the camera position on the plane + glm::vec3 rotated = glm::inverse(rotation) * Application::getInstance()->getCamera()->getPosition(); + float spacing = _minorGridWidth; + + float alpha = getAlpha(); + xColor color = getColor(); + glm::vec3 position = getPosition(); + + const int GRID_DIVISIONS = 300; + const float MAX_COLOR = 255.0f; + float scale = GRID_DIVISIONS * spacing; + + glColor4f(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); + + _gridProgram.bind(); + + // Minor grid + glPushMatrix(); + { + glTranslatef(_minorGridWidth * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2), + spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position.z); + + glScalef(scale, scale, scale); + + Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS); + } + glPopMatrix(); + + // Major grid + glPushMatrix(); + { + glLineWidth(4.0f); + spacing *= _majorGridEvery; + glTranslatef(spacing * (floorf(rotated.x / spacing) - GRID_DIVISIONS / 2), + spacing * (floorf(rotated.y / spacing) - GRID_DIVISIONS / 2), position.z); + + scale *= _majorGridEvery; + glScalef(scale, scale, scale); + + Application::getInstance()->getGeometryCache()->renderGrid(GRID_DIVISIONS, GRID_DIVISIONS); + } + glPopMatrix(); + + _gridProgram.release(); + + glPopMatrix(); + + glEnable(GL_LIGHTING); + glDepthMask(GL_TRUE); +} + +void Grid3DOverlay::setProperties(const QScriptValue& properties) { + Base3DOverlay::setProperties(properties); + + if (properties.property("minorGridWidth").isValid()) { + _minorGridWidth = properties.property("minorGridWidth").toVariant().toFloat(); + } + + if (properties.property("majorGridEvery").isValid()) { + _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); + } +} diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h new file mode 100644 index 0000000000..b1675f15d7 --- /dev/null +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -0,0 +1,44 @@ +// +// Grid3DOverlay.h +// interface/src/ui/overlays +// +// Created by Ryan Huffman on 11/06/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_Grid3DOverlay_h +#define hifi_Grid3DOverlay_h + +// include this before QGLWidget, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include <glm/glm.hpp> + +#include <QGLWidget> +#include <SharedUtil.h> + +#include "Base3DOverlay.h" + +#include "renderer/ProgramObject.h" + +class Grid3DOverlay : public Base3DOverlay { + Q_OBJECT + +public: + Grid3DOverlay(); + ~Grid3DOverlay(); + + virtual void render(RenderArgs* args); + virtual void setProperties(const QScriptValue& properties); + +private: + float _minorGridWidth; + int _majorGridEvery; + + static ProgramObject _gridProgram; +}; + +#endif // hifi_Grid3DOverlay_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index df7a5fbcea..0192f9c216 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -23,6 +23,7 @@ #include "Overlays.h" #include "Rectangle3DOverlay.h" #include "Sphere3DOverlay.h" +#include "Grid3DOverlay.h" #include "TextOverlay.h" #include "Text3DOverlay.h" @@ -155,6 +156,8 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope thisOverlay = new Rectangle3DOverlay(); } else if (type == "line3d") { thisOverlay = new Line3DOverlay(); + } else if (type == "grid") { + thisOverlay = new Grid3DOverlay(); } else if (type == "localvoxels") { thisOverlay = new LocalVoxelsOverlay(); } else if (type == "localmodels") { diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 709591b62b..63384371bd 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -297,7 +297,7 @@ void Player::play() { _injector->setOptions(_options); } -void Player::setCurrentFrame(unsigned int currentFrame) { +void Player::setCurrentFrame(int currentFrame) { if (_recording && currentFrame >= _recording->getFrameNumber()) { stopPlaying(); return; @@ -314,7 +314,7 @@ void Player::setCurrentFrame(unsigned int currentFrame) { } } -void Player::setCurrentTime(unsigned int currentTime) { +void Player::setCurrentTime(int currentTime) { if (currentTime >= _recording->getLength()) { stopPlaying(); return; @@ -393,7 +393,7 @@ bool Player::computeCurrentFrame() { _currentFrame = 0; } - quint64 elapsed = glm::clamp(Player::elapsed() - _audioOffset, (qint64)0, (qint64)_recording->getLength()); + qint64 elapsed = glm::clamp(Player::elapsed() - _audioOffset, (qint64)0, (qint64)_recording->getLength()); while(_currentFrame >= 0 && _recording->getFrameTimestamp(_currentFrame) > elapsed) { --_currentFrame; diff --git a/libraries/avatars/src/Player.h b/libraries/avatars/src/Player.h index 043fcc4a25..7ed76fa495 100644 --- a/libraries/avatars/src/Player.h +++ b/libraries/avatars/src/Player.h @@ -44,8 +44,8 @@ public slots: void loadRecording(RecordingPointer recording); void play(); - void setCurrentFrame(unsigned int currentFrame); - void setCurrentTime(unsigned int currentTime); + void setCurrentFrame(int currentFrame); + void setCurrentTime(int currentTime); void setVolume(float volume); void setAudioOffset(int audioOffset); @@ -87,4 +87,4 @@ private: bool _useSkeletonURL; }; -#endif // hifi_Player_h \ No newline at end of file +#endif // hifi_Player_h diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ae44e3931b..adf72198be 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -145,14 +145,14 @@ public: float getLargestDimension() const { return glm::length(_dimensions); } /// get the largest possible dimension /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - void setDimensions(const glm::vec3& value) { _dimensions = value; ; recalculateCollisionShape(); } + void setDimensions(const glm::vec3& value) { _dimensions = value; recalculateCollisionShape(); } /// set dimensions in meter units (0.0 - TREE_SCALE) this will also reset radius appropriately void setDimensionsInMeters(const glm::vec3& value) { setDimensions(value / (float) TREE_SCALE); } static const glm::quat DEFAULT_ROTATION; const glm::quat& getRotation() const { return _rotation; } - void setRotation(const glm::quat& rotation) { _rotation = rotation; ; recalculateCollisionShape(); } + void setRotation(const glm::quat& rotation) { _rotation = rotation; recalculateCollisionShape(); } static const float DEFAULT_GLOW_LEVEL; float getGlowLevel() const { return _glowLevel; } @@ -169,7 +169,7 @@ public: static const glm::vec3 DEFAULT_VELOCITY; static const glm::vec3 NO_VELOCITY; static const float EPSILON_VELOCITY_LENGTH; - const glm::vec3 getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second + const glm::vec3& getVelocity() const { return _velocity; } /// velocity in domain scale units (0.0-1.0) per second glm::vec3 getVelocityInMeters() const { return _velocity * (float) TREE_SCALE; } /// get velocity in meters void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in domain scale units (0.0-1.0) per second void setVelocityInMeters(const glm::vec3& value) { _velocity = value / (float) TREE_SCALE; } /// velocity in meters diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 199bd92030..bc2823e15c 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -124,6 +124,7 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp } else { // check to see if we need to simulate this entity... EntityItem::SimulationState oldState = existingEntity->getSimulationState(); + QString entityScriptBefore = existingEntity->getScript(); UpdateEntityOperator theOperator(this, containingElement, existingEntity, properties); recurseTreeWithOperator(&theOperator); @@ -131,6 +132,12 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp EntityItem::SimulationState newState = existingEntity->getSimulationState(); changeEntityState(existingEntity, oldState, newState); + + QString entityScriptAfter = existingEntity->getScript(); + if (entityScriptBefore != entityScriptAfter) { + emitEntityScriptChanging(entityID); // the entity script has changed + } + } containingElement = getContainingElement(entityID); @@ -168,6 +175,7 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem if (result) { // this does the actual adding of the entity addEntityItem(result); + emitAddingEntity(entityID); } return result; } @@ -184,6 +192,14 @@ void EntityTree::trackDeletedEntity(const EntityItemID& entityID) { } } +void EntityTree::emitAddingEntity(const EntityItemID& entityItemID) { + emit addingEntity(entityItemID); +} + +void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) { + emit entityScriptChanging(entityItemID); +} + void EntityTree::deleteEntity(const EntityItemID& entityID) { emit deletingEntity(entityID); @@ -290,6 +306,7 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) { EntityItemID creatorTokenVersion = searchEntityID.convertToCreatorTokenVersion(); EntityItemID knownIDVersion = searchEntityID.convertToKnownIDVersion(); + // First look for and find the "viewed version" of this entity... it's possible we got // the known ID version sent to us between us creating our local version, and getting this // remapping message. If this happened, we actually want to find and delete that version of @@ -310,6 +327,10 @@ void EntityTree::handleAddEntityResponse(const QByteArray& packet) { creatorTokenContainingElement->updateEntityItemID(creatorTokenVersion, knownIDVersion); setContainingElement(creatorTokenVersion, NULL); setContainingElement(knownIDVersion, creatorTokenContainingElement); + + // because the ID of the entity is switching, we need to emit these signals for any + // listeners who care about the changing of IDs + emit changingEntityID(creatorTokenVersion, knownIDVersion); } } unlock(); @@ -981,7 +1002,6 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons return processedBytes; } - EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ { // TODO: do we need to make this thread safe? Or is it acceptable as is if (_entityToElementMap.contains(entityItemID)) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8d1acc0d01..6fe2d256c2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -140,10 +140,16 @@ public: void trackDeletedEntity(const EntityItemID& entityID); + void emitAddingEntity(const EntityItemID& entityItemID); + void emitEntityScriptChanging(const EntityItemID& entityItemID); + QList<EntityItem*>& getMovingEntities() { return _movingEntities; } signals: void deletingEntity(const EntityItemID& entityID); + void addingEntity(const EntityItemID& entityID); + void entityScriptChanging(const EntityItemID& entityItemID); + void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID); private: diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 079fb1bba7..1dea2bcd85 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -726,7 +726,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int entityItemID = EntityItemID::readEntityItemIDFromBuffer(dataAt, bytesLeftToRead); entityItem = _myTree->findEntityByEntityItemID(entityItemID); } - + // If the item already exists in our tree, we want do the following... // 1) allow the existing item to read from the databuffer // 2) check to see if after reading the item, the containing element is still correct, fix it if needed @@ -734,10 +734,13 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int // TODO: Do we need to also do this? // 3) remember the old cube for the entity so we can mark it as dirty if (entityItem) { + QString entityScriptBefore = entityItem->getScript(); bool bestFitBefore = bestFitEntityBounds(entityItem); EntityTreeElement* currentContainingElement = _myTree->getContainingElement(entityItemID); EntityItem::SimulationState oldState = entityItem->getSimulationState(); + bytesForThisEntity = entityItem->readEntityDataFromBuffer(dataAt, bytesLeftToRead, args); + EntityItem::SimulationState newState = entityItem->getSimulationState(); if (oldState != newState) { _myTree->changeEntityState(entityItem, oldState, newState); @@ -755,6 +758,12 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } } + + QString entityScriptAfter = entityItem->getScript(); + if (entityScriptBefore != entityScriptAfter) { + _myTree->emitEntityScriptChanging(entityItemID); // the entity script has changed + } + } else { entityItem = EntityTypes::constructEntityItem(dataAt, bytesLeftToRead, args); if (entityItem) { @@ -762,6 +771,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int addEntityItem(entityItem); // add this new entity to this elements entities entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); + _myTree->emitAddingEntity(entityItemID); // we just added an entity EntityItem::SimulationState newState = entityItem->getSimulationState(); _myTree->changeEntityState(entityItem, EntityItem::Static, newState); } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 043f0621bb..0c18c82962 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -209,8 +209,15 @@ bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { if (hashFromPacketHeader(packet) == hashForPacketAndConnectionUUID(packet, sendingNode->getConnectionSecret())) { return true; } else { - qDebug() << "Packet hash mismatch on" << checkType << "- Sender" + static QMultiMap<QUuid, PacketType> hashDebugSuppressMap; + + QUuid senderUUID = uuidFromPacketHeader(packet); + if (!hashDebugSuppressMap.contains(senderUUID, checkType)) { + qDebug() << "Packet hash mismatch on" << checkType << "- Sender" << uuidFromPacketHeader(packet); + + hashDebugSuppressMap.insert(senderUUID, checkType); + } } } else { static QString repeatedMessage diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 3f89cdf9ba..2691b10273 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -311,6 +311,11 @@ QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* ob return QScriptValue::NullValue; } +void ScriptEngine::registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments) { + QScriptValue scriptFun = newFunction(fun, numArguments); + globalObject().setProperty(name, scriptFun); +} + void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, QScriptValue object) { QScriptValue setterFunction = newFunction(setter, 1); @@ -625,7 +630,7 @@ void ScriptEngine::stopTimer(QTimer *timer) { } } -QUrl ScriptEngine::resolveInclude(const QString& include) const { +QUrl ScriptEngine::resolvePath(const QString& include) const { // first lets check to see if it's already a full URL QUrl url(include); if (!url.scheme().isEmpty()) { @@ -651,7 +656,7 @@ void ScriptEngine::print(const QString& message) { } void ScriptEngine::include(const QString& includeFile) { - QUrl url = resolveInclude(includeFile); + QUrl url = resolvePath(includeFile); QString includeContents; if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "ftp") { @@ -689,7 +694,7 @@ void ScriptEngine::include(const QString& includeFile) { } void ScriptEngine::load(const QString& loadFile) { - QUrl url = resolveInclude(loadFile); + QUrl url = resolvePath(loadFile); emit loadScript(url.toString(), false); } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f96b4655a9..bb279b8887 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -65,6 +65,7 @@ public: QScriptValue registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name void registerGetterSetter(const QString& name, QScriptEngine::FunctionSignature getter, QScriptEngine::FunctionSignature setter, QScriptValue object = QScriptValue::NullValue); + void registerFunction(const QString& name, QScriptEngine::FunctionSignature fun, int numArguments = -1); Q_INVOKABLE void setIsAvatar(bool isAvatar); bool isAvatar() const { return _isAvatar; } @@ -103,6 +104,7 @@ public slots: void include(const QString& includeFile); void load(const QString& loadfile); void print(const QString& message); + QUrl resolvePath(const QString& path) const; void nodeKilled(SharedNodePointer node); @@ -131,7 +133,6 @@ protected: int _numAvatarSoundSentBytes; private: - QUrl resolveInclude(const QString& include) const; void sendAvatarIdentityPacket(); void sendAvatarBillboardPacket();