From 4da6af96bb808491f6e8fa5765597d7721a7d941 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 25 Feb 2014 22:08:56 -0800 Subject: [PATCH 1/8] Bots will move --- examples/bot.js | 34 +++++++++++++++++++++++++++++----- examples/editVoxels.js | 3 ++- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index c8280e063d..504f16826e 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -17,12 +17,19 @@ function getRandomInt (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } -// choose a random x and y in the range of 0 to 50 -positionX = getRandomFloat(0, 18); -positionZ = getRandomFloat(0, 18); +var CHANCE_OF_MOVING = 0.05; +var isMoving = false; + +var STARTING_RANGE = 18.0; +var MOVE_RANGE = 1.0; +var STOP_TOLERANCE = 0.05; +var MOVE_RATE = 0.10; +var firstPosition = { x: getRandomFloat(0, STARTING_RANGE), y: 0, z: getRandomFloat(0, STARTING_RANGE) }; +var targetPosition = { x: 0, y: 0, z: 0 }; + // change the avatar's position to the random one -Avatar.position = {x: positionX, y: 0, z: positionZ}; +Avatar.position = firstPosition; // pick an integer between 1 and 20 for the face model for this bot botNumber = getRandomInt(1, 100); @@ -52,4 +59,21 @@ Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/me Avatar.skeletonModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/" + newBodyFilePrefix + ".fst"; Avatar.billboardURL = "https://dl.dropboxusercontent.com/u/1864924/bot-billboard.png"; -Agent.isAvatar = true; \ No newline at end of file +Agent.isAvatar = true; + +function updateBehavior() { + if (!isMoving && (Math.random() < CHANCE_OF_MOVING)) { + // Set new target location + targetPosition = { x: Avatar.position.x + getRandomFloat(-MOVE_RANGE, MOVE_RANGE), + y: Avatar.position.y, + z: Avatar.position.z + getRandomFloat(-MOVE_RANGE, MOVE_RANGE) }; + isMoving = true; + } else { + + Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE)); + if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) { + isMoving = false; + } + } +} +Script.willSendVisualDataCallback.connect(updateBehavior); diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 53d3869075..f05cc85816 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -79,7 +79,8 @@ var addSound3 = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-publi var deleteSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+delete+2.raw"); var changeColorSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Voxels/voxel+edit+2.raw"); var clickSound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Switches+and+sliders/toggle+switch+-+medium.raw"); -var audioOptions = new AudioInjectionOptions();
 +var audioOptions = new AudioInjectionOptions(); + audioOptions.volume = 0.5; audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0 } ); // start with audio slightly above the avatar From 8644280eb541918a431005f05aa6781c4fb73970 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 26 Feb 2014 12:11:03 -0800 Subject: [PATCH 2/8] Make sure our mode is fully established before we use the mirror camera to render the billboard. Closes #2103. --- interface/src/Application.cpp | 3 +-- interface/src/Camera.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c34e35dc7..371a9e0c54 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1852,8 +1852,7 @@ void Application::init() { _myCamera.setModeShiftPeriod(1.0f); _mirrorCamera.setMode(CAMERA_MODE_MIRROR); - _mirrorCamera.setAspectRatio((float)MIRROR_VIEW_WIDTH / (float)MIRROR_VIEW_HEIGHT); - _mirrorCamera.setFieldOfView(30); + _mirrorCamera.setModeShiftPeriod(0.0f); OculusManager::connect(); if (OculusManager::isConnected()) { diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index be7e7bac50..6cb44f5919 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -126,7 +126,7 @@ void Camera::setModeShiftPeriod (float period) { // if a zero period was requested, we clearly want to snap immediately to the target if (period == 0.0f) { - update(MIN_PERIOD); + update(MAX_PERIOD); } } From f335bb8171193d1bff2f297c8c15be49fee0a83b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 26 Feb 2014 13:40:09 -0800 Subject: [PATCH 3/8] Preserve joint states when switching between LODs. Closes #2077. --- interface/src/renderer/FBXReader.cpp | 2 +- interface/src/renderer/Model.cpp | 32 ++++++++++++++++++++++------ interface/src/renderer/Model.h | 1 + 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 8b881940ca..c9201f8f51 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1249,7 +1249,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) joint.boneRadius = 0.0f; joint.inverseBindRotation = joint.inverseDefaultRotation; geometry.joints.append(joint); - geometry.jointIndices.insert(model.name, geometry.joints.size() - 1); + geometry.jointIndices.insert(model.name, geometry.joints.size()); } // find our special joints diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index e1780ee9f5..7fc16855e7 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -46,6 +46,17 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati program.release(); } +QVector Model::createJointStates(const FBXGeometry& geometry) { + QVector jointStates; + foreach (const FBXJoint& joint, geometry.joints) { + JointState state; + state.translation = joint.translation; + state.rotation = joint.rotation; + jointStates.append(state); + } + return jointStates; +} + bool Model::isLoadedWithTextures() const { if (!isActive()) { return false; @@ -106,9 +117,23 @@ void Model::reset() { void Model::simulate(float deltaTime) { // update our LOD + QVector newJointStates; if (_geometry) { QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); if (_geometry != geometry) { + if (!_jointStates.isEmpty()) { + // copy the existing joint states + const FBXGeometry& oldGeometry = _geometry->getFBXGeometry(); + const FBXGeometry& newGeometry = geometry->getFBXGeometry(); + newJointStates = createJointStates(newGeometry); + for (QHash::const_iterator it = oldGeometry.jointIndices.constBegin(); + it != oldGeometry.jointIndices.constEnd(); it++) { + int newIndex = newGeometry.jointIndices.value(it.key()); + if (newIndex != 0) { + newJointStates[newIndex - 1] = _jointStates.at(it.value() - 1); + } + } + } deleteGeometry(); _dilatedTextures.clear(); _geometry = geometry; @@ -121,12 +146,7 @@ void Model::simulate(float deltaTime) { // set up world vertices on first simulate after load const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (_jointStates.isEmpty()) { - foreach (const FBXJoint& joint, geometry.joints) { - JointState state; - state.translation = joint.translation; - state.rotation = joint.rotation; - _jointStates.append(state); - } + _jointStates = newJointStates.isEmpty() ? createJointStates(geometry) : newJointStates; foreach (const FBXMesh& mesh, geometry.meshes) { MeshState state; state.clusterMatrices.resize(mesh.clusters.size()); diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index cf6e1fea6d..fd44361a1b 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -269,6 +269,7 @@ private: static SkinLocations _skinNormalMapLocations; static void initSkinProgram(ProgramObject& program, SkinLocations& locations); + static QVector createJointStates(const FBXGeometry& geometry); }; #endif /* defined(__interface__Model__) */ From 7067cf2ab3e68665124db15e93a9436c98586b96 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Feb 2014 13:40:49 -0800 Subject: [PATCH 4/8] fix go to user and address update for new API --- interface/src/Application.cpp | 4 ++-- interface/src/Menu.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fb91a8ef1..e8a7d0dcbc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3367,9 +3367,9 @@ void Application::connectedToDomain(const QString& hostname) { if (accountManager.isLoggedIn()) { // update our domain-server with the data-server we're logged in with - QString domainPutJsonString = "{\"location\":{\"domain\":\"" + hostname + "\"}}"; + QString domainPutJsonString = "{\"address\":{\"domain\":\"" + hostname + "\"}}"; - accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation, + accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation, JSONCallbackParameters(), domainPutJsonString.toUtf8()); } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 89bebefcdd..e333aee2e4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -999,7 +999,7 @@ void Menu::goTo() { callbackParams.jsonCallbackMethod = "goToLocationFromResponse"; // there's a username entered by the user, make a request to the data-server for the associated location - AccountManager::getInstance().authenticatedRequest("/api/v1/users/" + gotoDialog.textValue() + "/location", + AccountManager::getInstance().authenticatedRequest("/api/v1/users/" + gotoDialog.textValue() + "/address", QNetworkAccessManager::GetOperation, callbackParams); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7b22201bfb..96e2cc2221 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1139,10 +1139,10 @@ void MyAvatar::updateLocationInDataServer() { QString orientationString(createByteArray(safeEulerAngles(getOrientation()))); // construct the json to put the user's location - QString locationPutJson = QString() + "{\"location\":{\"position\":\"" + QString locationPutJson = QString() + "{\"address\":{\"position\":\"" + positionString + "\", \"orientation\":\"" + orientationString + "\"}}"; - accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation, + accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation, JSONCallbackParameters(), locationPutJson.toUtf8()); } } @@ -1154,7 +1154,7 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { // send a node kill request, indicating to other clients that they should play the "disappeared" effect sendKillAvatar(); - QJsonObject locationObject = jsonObject["data"].toObject()["location"].toObject(); + QJsonObject locationObject = jsonObject["data"].toObject()["address"].toObject(); QString positionString = locationObject["position"].toString(); QString orientationString = locationObject["orientation"].toString(); QString domainHostnameString = locationObject["domain"].toString(); From 0a1e840d10b34bcb7537876d503b9892309df821 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 26 Feb 2014 13:50:04 -0800 Subject: [PATCH 5/8] Bot.js NPCs wander around and make sounds --- examples/bot.js | 74 +++++++++++++++++++++++++--- interface/src/Util.cpp | 29 ----------- interface/src/Util.h | 2 - libraries/script-engine/src/Quat.cpp | 7 ++- libraries/script-engine/src/Quat.h | 1 + libraries/shared/src/SharedUtil.cpp | 32 ++++++++++++ libraries/shared/src/SharedUtil.h | 2 + 7 files changed, 108 insertions(+), 39 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index 504f16826e..553c18bf92 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -3,6 +3,7 @@ // hifi // // Created by Stephen Birarda on 2/20/14. +// Modified by Philip on 2/26/14 // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // // This is an example script that demonstrates an NPC avatar. @@ -17,16 +18,53 @@ function getRandomInt (min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } -var CHANCE_OF_MOVING = 0.05; +var CHANCE_OF_MOVING = 0.005; +var CHANCE_OF_SOUND = 0.005; +var CHANCE_OF_HEAD_TURNING = 0.05; +var CHANCE_OF_BIG_MOVE = 0.1; + var isMoving = false; +var isTurningHead = false; var STARTING_RANGE = 18.0; -var MOVE_RANGE = 1.0; +var MAX_RANGE = 25.0; +var MOVE_RANGE_SMALL = 0.5; +var MOVE_RANGE_BIG = 5.0; +var TURN_RANGE = 45.0; var STOP_TOLERANCE = 0.05; -var MOVE_RATE = 0.10; +var MOVE_RATE = 0.05; +var TURN_RATE = 0.15; +var PITCH_RATE = 0.20; +var PITCH_RANGE = 30.0; + + var firstPosition = { x: getRandomFloat(0, STARTING_RANGE), y: 0, z: getRandomFloat(0, STARTING_RANGE) }; var targetPosition = { x: 0, y: 0, z: 0 }; +var targetDirection = { x: 0, y: 0, z: 0, w: 0 }; +var currentDirection = { x: 0, y: 0, z: 0, w: 0 }; + +var targetHeadPitch = 0.0; + +var sounds = []; +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh1.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh2.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh3.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh4.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh5.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh6.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh7.raw")); +sounds.push(new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Vocals/sigh8.raw")); + +// Play a random sound from a list of conversational audio clips +function playRandomSound(position) { + var whichSound = Math.floor((Math.random() * sounds.length) % sounds.length); + var audioOptions = new AudioInjectionOptions(); + audioOptions.volume = 0.25 + (Math.random() * 0.75); + audioOptions.position = position; + Audio.playSound(sounds[whichSound], audioOptions); + print("PlaySound " + whichSound); +} // change the avatar's position to the random one Avatar.position = firstPosition; @@ -62,18 +100,40 @@ Avatar.billboardURL = "https://dl.dropboxusercontent.com/u/1864924/bot-billboard Agent.isAvatar = true; function updateBehavior() { + if (Math.random() < CHANCE_OF_SOUND) { + playRandomSound(Avatar.position); + } + + if (!isTurningHead && (Math.random() < CHANCE_OF_HEAD_TURNING)) { + targetHeadPitch = getRandomFloat(-PITCH_RANGE, PITCH_RANGE); + isTurningHead = true; + } else { + Avatar.headPitch = Avatar.headPitch + (targetHeadPitch - Avatar.headPitch) * PITCH_RATE; + if (Math.abs(Avatar.headPitch - targetHeadPitch) < STOP_TOLERANCE) { + isTurningHead = false; + } + } if (!isMoving && (Math.random() < CHANCE_OF_MOVING)) { // Set new target location - targetPosition = { x: Avatar.position.x + getRandomFloat(-MOVE_RANGE, MOVE_RANGE), - y: Avatar.position.y, - z: Avatar.position.z + getRandomFloat(-MOVE_RANGE, MOVE_RANGE) }; + targetDirection = Quat.multiply(Avatar.orientation, Quat.angleAxis(getRandomFloat(-TURN_RANGE, TURN_RANGE), { x:0, y:1, z:0 })); + var front = Quat.getFront(targetDirection); + if (Math.random() < CHANCE_OF_BIG_MOVE) { + targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_BIG))); + } else { + targetPosition = Vec3.sum(Avatar.position, Vec3.multiply(front, getRandomFloat(0.0, MOVE_RANGE_SMALL))); + } isMoving = true; } else { - Avatar.position = Vec3.sum(Avatar.position, Vec3.multiply(Vec3.subtract(targetPosition, Avatar.position), MOVE_RATE)); + Avatar.orientation = Quat.mix(Avatar.orientation, targetDirection, TURN_RATE); if (Vec3.length(Vec3.subtract(Avatar.position, targetPosition)) < STOP_TOLERANCE) { isMoving = false; } } + if (Vec3.length(Avatar.position) > MAX_RANGE) { + // Don't let our happy little person get out of the cage + isMoving = false; + Avatar.position = { x: 0, y: 0, z: 0 }; + } } Script.willSendVisualDataCallback.connect(updateBehavior); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index f601618eae..2e1ed98b87 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -104,36 +104,7 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { return glm::angleAxis(angle, axis); } -// Safe version of glm::mix; based on the code in Nick Bobick's article, -// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, -// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) -glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { - float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; - float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; - // adjust signs if necessary - if (cosa < 0.0f) { - cosa = -cosa; - ox = -ox; - oy = -oy; - oz = -oz; - ow = -ow; - } - - // calculate coefficients; if the angle is too close to zero, we must fall back - // to linear interpolation - if ((1.0f - cosa) > EPSILON) { - float angle = acosf(cosa), sina = sinf(angle); - s0 = sinf((1.0f - proportion) * angle) / sina; - s1 = sinf(proportion * angle) / sina; - - } else { - s0 = 1.0f - proportion; - s1 = proportion; - } - - return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); -} glm::vec3 extractTranslation(const glm::mat4& matrix) { return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); diff --git a/interface/src/Util.h b/interface/src/Util.h index 04403aea16..a89a01e71a 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -45,8 +45,6 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2); glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); -glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); - glm::vec3 extractTranslation(const glm::mat4& matrix); void setTranslation(glm::mat4& matrix, const glm::vec3& translation); diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 2f1c39f9e3..1019276d37 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -13,8 +13,10 @@ #include #include +#include #include "Quat.h" + glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) { return q1 * q2; } @@ -31,7 +33,6 @@ glm::quat Quat::inverse(const glm::quat& q) { return glm::inverse(q); } - glm::vec3 Quat::getFront(const glm::quat& orientation) { return orientation * IDENTITY_FRONT; } @@ -52,3 +53,7 @@ glm::quat Quat::angleAxis(float angle, const glm::vec3& v) { return glm::angleAxis(angle, v); } +glm::quat Quat::mix(const glm::quat& q1, const glm::quat& q2, float alpha) { + return safeMix(q1, q2, alpha); +} + diff --git a/libraries/script-engine/src/Quat.h b/libraries/script-engine/src/Quat.h index 867069d6d6..ac12aaa351 100644 --- a/libraries/script-engine/src/Quat.h +++ b/libraries/script-engine/src/Quat.h @@ -29,6 +29,7 @@ public slots: glm::vec3 getUp(const glm::quat& orientation); glm::vec3 safeEulerAngles(const glm::quat& orientation); glm::quat angleAxis(float angle, const glm::vec3& v); + glm::quat mix(const glm::quat& q1, const glm::quat& q2, float alpha); }; #endif /* defined(__hifi__Quat__) */ diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f22c81a71a..2c531bab91 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -65,6 +65,38 @@ bool shouldDo(float desiredInterval, float deltaTime) { return randFloat() < deltaTime / desiredInterval; } +// Safe version of glm::mix; based on the code in Nick Bobick's article, +// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, +// https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) +glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { + float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; + + // adjust signs if necessary + if (cosa < 0.0f) { + cosa = -cosa; + ox = -ox; + oy = -oy; + oz = -oz; + ow = -ow; + } + + // calculate coefficients; if the angle is too close to zero, we must fall back + // to linear interpolation + if ((1.0f - cosa) > EPSILON) { + float angle = acosf(cosa), sina = sinf(angle); + s0 = sinf((1.0f - proportion) * angle) / sina; + s1 = sinf(proportion * angle) / sina; + + } else { + s0 = 1.0f - proportion; + s1 = proportion; + } + + return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); +} + + void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 603a09a0c3..c18b2fca08 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -75,6 +75,8 @@ float randFloatInRange (float min,float max); unsigned char randomColorValue(int minimum); bool randomBoolean(); +glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); + bool shouldDo(float desiredInterval, float deltaTime); void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL); From b27e9b03d4ae01c33e68c337e4b1d90a75dea86d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 26 Feb 2014 14:15:00 -0800 Subject: [PATCH 6/8] removed bad include --- libraries/script-engine/src/Quat.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 1019276d37..7271f06af6 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -13,7 +13,6 @@ #include #include -#include #include "Quat.h" From 88b46acdeb5df08b84e5ff33a45c77b386a63957 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Feb 2014 16:17:51 -0800 Subject: [PATCH 7/8] repair for wrong body on bots < 20 --- examples/bot.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/bot.js b/examples/bot.js index 553c18bf92..a67167ab5a 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -72,12 +72,10 @@ Avatar.position = firstPosition; // pick an integer between 1 and 20 for the face model for this bot botNumber = getRandomInt(1, 100); -newBodyFilePrefix = "defaultAvatar"; - if (botNumber <= 20) { newFaceFilePrefix = "bot" + botNumber; + newBodyFilePrefix = "defaultAvatar_body" } else { - if (botNumber <= 40) { newFaceFilePrefix = "superhero"; } else if (botNumber <= 60) { From cb45a3242d79d7f518bc73699622b46f1e05673b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 26 Feb 2014 16:29:07 -0800 Subject: [PATCH 8/8] increase size of audio output buffer to match size of ring buffer --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1089eeab70..aa9d1330b5 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -280,6 +280,7 @@ void Audio::start() { // setup our general output device for audio-mixer audio _audioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); + _audioOutput->setBufferSize(_ringBuffer.getSampleCapacity() * sizeof(int16_t)); _outputDevice = _audioOutput->start(); // setup a loopback audio output device @@ -556,7 +557,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { // if there is anything in the ring buffer, decide what to do if (_ringBuffer.samplesAvailable() > 0) { - int numNetworkOutputSamples = _ringBuffer.samplesAvailable(); int numDeviceOutputSamples = numNetworkOutputSamples / networkOutputToOutputRatio;