Merge branch 'master' of github.com:highfidelity/hifi

This commit is contained in:
Babiuch, Ryan Nicholas 2016-02-03 14:52:08 -06:00
commit d7951f4300
21 changed files with 520 additions and 238 deletions

View file

@ -22,41 +22,44 @@ var MINIMUM_DROP_DISTANCE_FROM_JOINT = 0.4;
var ATTACHED_ENTITY_SEARCH_DISTANCE = 10.0;
var ATTACHED_ENTITIES_SETTINGS_KEY = "ATTACHED_ENTITIES";
var DRESSING_ROOM_DISTANCE = 2.0;
var SHOW_TOOL_BAR = false;
// tool bar
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var BUTTON_SIZE = 32;
var PADDING = 3;
Script.include(["libraries/toolBars.js"]);
var toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.attachedEntities.toolbar", function(screenSize) {
return {
x: (BUTTON_SIZE + PADDING),
y: (screenSize.y / 2 - BUTTON_SIZE * 2 + PADDING)
};
});
var saveButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: "http://headache.hungry.com/~seth/hifi/save.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
var loadButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: "http://headache.hungry.com/~seth/hifi/load.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
if (SHOW_TOOL_BAR) {
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var BUTTON_SIZE = 32;
var PADDING = 3;
Script.include(["libraries/toolBars.js"]);
var toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.attachedEntities.toolbar", function(screenSize) {
return {
x: (BUTTON_SIZE + PADDING),
y: (screenSize.y / 2 - BUTTON_SIZE * 2 + PADDING)
};
});
var saveButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: ".../save.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
var loadButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: ".../load.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
}
function mousePressEvent(event) {
@ -73,10 +76,14 @@ function mousePressEvent(event) {
}
function scriptEnding() {
toolBar.cleanup();
if (SHOW_TOOL_BAR) {
toolBar.cleanup();
}
}
Controller.mousePressEvent.connect(mousePressEvent);
if (SHOW_TOOL_BAR) {
Controller.mousePressEvent.connect(mousePressEvent);
}
Script.scriptEnding.connect(scriptEnding);
@ -116,6 +123,7 @@ function AttachedEntitiesManager() {
manager.checkIfWearable(parsedMessage.grabbedEntity, parsedMessage.joint)
// manager.saveAttachedEntities();
} else if (parsedMessage.action === 'shared-release') {
manager.updateRelativeOffsets(parsedMessage.grabbedEntity);
// manager.saveAttachedEntities();
} else if (parsedMessage.action === 'equip') {
// manager.saveAttachedEntities();
@ -173,11 +181,12 @@ function AttachedEntitiesManager() {
parentJointIndex: bestJointIndex
};
if (!this.avatarIsInDressingRoom() &&
bestJointOffset && bestJointOffset.constructor === Array && bestJointOffset.length > 1) {
// don't snap the entity to the preferred position if the avatar is in the dressing room.
wearProps.localPosition = bestJointOffset[0];
wearProps.localRotation = bestJointOffset[1];
if (bestJointOffset && bestJointOffset.constructor === Array && bestJointOffset.length > 1) {
if (!this.avatarIsInDressingRoom()) {
// don't snap the entity to the preferred position if the avatar is in the dressing room.
wearProps.localPosition = bestJointOffset[0];
wearProps.localRotation = bestJointOffset[1];
}
}
Entities.editEntity(grabbedEntity, wearProps);
} else if (props.parentID != NULL_UUID) {
@ -189,12 +198,19 @@ function AttachedEntitiesManager() {
}
}
this.updateRelativeOffsets = function(entityID, props) {
this.updateRelativeOffsets = function(entityID) {
// save the preferred (current) relative position and rotation into the user-data of the entity
var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA);
var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex];
wearableData.joints[currentJointName] = [props.localPosition, props.localRotation];
setEntityCustomData('wearable', entityID, wearableData);
var props = Entities.getEntityProperties(entityID);
if (props.parentID == MyAvatar.sessionUUID) {
grabData = getEntityCustomData('grabKey', entityID, {});
grabbableData = getEntityCustomData('grabbableKey', entityID, {});
var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA);
var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex];
wearableData.joints[currentJointName] = [props.localPosition, props.localRotation];
setEntityCustomData('wearable', entityID, wearableData);
return true;
}
return false;
}
this.saveAttachedEntities = function() {
@ -203,12 +219,8 @@ function AttachedEntitiesManager() {
var nearbyEntities = Entities.findEntities(MyAvatar.position, ATTACHED_ENTITY_SEARCH_DISTANCE);
for (i = 0; i < nearbyEntities.length; i++) {
var entityID = nearbyEntities[i];
var props = Entities.getEntityProperties(entityID);
if (props.parentID == MyAvatar.sessionUUID) {
grabData = getEntityCustomData('grabKey', entityID, {});
grabbableData = getEntityCustomData('grabbableKey', entityID, {});
this.updateRelativeOffsets(entityID, props);
props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them
if (this.updateRelativeOffsets(entityID)) {
var props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them
this.scrubProperties(props);
saveData.push(props);
}

View file

@ -1259,11 +1259,14 @@ function MyController(hand) {
this.hasPresetOffsets = function() {
var wearableData = getEntityCustomData('wearable', this.grabbedEntity, {joints: {}});
var allowedJoints = wearableData.joints;
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
if (handJointName in allowedJoints) {
return true;
if ("joints" in wearableData) {
var allowedJoints = wearableData.joints;
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
if (handJointName in allowedJoints) {
return true;
}
}
return false;
}
this.getPresetPosition = function() {

View file

@ -21,3 +21,4 @@ Script.load("controllers/squeezeHands.js");
Script.load("grab.js");
Script.load("directory.js");
Script.load("dialTone.js");
Script.load("attachedEntitiesManager.js");

View file

@ -235,7 +235,12 @@ var usersWindow = (function () {
FRIENDS_BUTTON_HEIGHT = FRIENDS_BUTTON_SVG_HEIGHT,
FRIENDS_BUTTON_COLOR = { red: 225, green: 225, blue: 225 },
FRIENDS_BUTTON_ALPHA = 0.95,
FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends",
FRIENDS_WINDOW_WIDTH = 290,
FRIENDS_WINDOW_HEIGHT = 500,
FRIENDS_WINDOW_TITLE = "Add/Remove Friends",
friendsButton,
friendsWindow,
OPTION_BACKGROUND_COLOR = { red: 60, green: 60, blue: 60 },
OPTION_BACKGROUND_ALPHA = 0.1,
@ -643,7 +648,17 @@ var usersWindow = (function () {
}
if (clickedOverlay === friendsButton) {
GlobalServices.editFriends();
if (!friendsWindow) {
friendsWindow = new OverlayWebWindow({
title: FRIENDS_WINDOW_TITLE,
width: FRIENDS_WINDOW_WIDTH,
height: FRIENDS_WINDOW_HEIGHT,
visible: false
});
}
friendsWindow.setURL(FRIENDS_WINDOW_URL);
friendsWindow.setVisible(true);
friendsWindow.raise();
}
}

View file

@ -247,7 +247,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -263,7 +265,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -278,7 +282,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -293,7 +299,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -308,7 +316,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -323,7 +333,9 @@
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -338,7 +350,9 @@
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningLeft", "state": "turnLeft" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -353,7 +367,9 @@
{ "var": "isMovingLeft", "state": "strafeLeft" },
{ "var": "isTurningRight", "state": "turnRight" },
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isFlying", "state": "fly" }
{ "var": "isFlying", "state": "fly" },
{ "var": "isTakeoff", "state": "takeoff" },
{ "var": "isInAir", "state": "inAir" }
]
},
{
@ -361,6 +377,7 @@
"interpTarget": 30,
"interpDuration": 30,
"transitions": [
{ "var": "isNotAway", "state": "awayOutro" },
{ "var": "awayIntroOnDone", "state": "away"}
]
},
@ -385,8 +402,27 @@
"interpTarget": 6,
"interpDuration": 6,
"transitions": [
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isNotFlying", "state": "idle" }
]
},
{
"id": "takeoff",
"interpTarget": 0,
"interpDuration": 6,
"transitions": [
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isNotTakeoff", "state": "inAir" }
]
},
{
"id": "inAir",
"interpTarget": 0,
"interpDuration": 6,
"transitions": [
{ "var": "isAway", "state": "awayIntro" },
{ "var": "isNotInAir", "state": "idle" }
]
}
]
},
@ -685,6 +721,64 @@
"loopFlag": true
},
"children": []
},
{
"id": "takeoff",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_takeoff.fbx",
"startFrame": 1.0,
"endFrame": 2.5,
"timeScale": 1.0,
"loopFlag": false
},
"children": []
},
{
"id": "inAir",
"type": "blendLinear",
"data": {
"alpha": 0.0,
"alphaVar": "inAirAlpha"
},
"children": [
{
"id": "inAirPreApex",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"startFrame": 0.0,
"endFrame": 0.0,
"timeScale": 0.0,
"loopFlag": false
},
"children": []
},
{
"id": "inAirApex",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"startFrame": 6.0,
"endFrame": 6.0,
"timeScale": 1.0,
"loopFlag": false
},
"children": []
},
{
"id": "inAirPostApex",
"type": "clip",
"data": {
"url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/jump_in_air.fbx",
"startFrame": 11.0,
"endFrame": 11.0,
"timeScale": 1.0,
"loopFlag": false
},
"children": []
}
]
}
]
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtWebEngine 1.1;
import "../desktop"
import ".."
@ -7,6 +8,13 @@ import ".."
Desktop {
id: desktop
Component.onCompleted: {
WebEngine.settings.javascriptCanOpenWindows = false;
WebEngine.settings.javascriptCanAccessClipboard = false;
WebEngine.settings.spatialNavigationEnabled = true;
WebEngine.settings.localContentCanAccessRemoteUrls = true;
}
// The tool window, one instance
property alias toolWindow: toolWindow
ToolWindow { id: toolWindow }

View file

@ -6,8 +6,10 @@ import "../controls"
Frame {
id: frame
property bool wideTopMargin: (window && (window.closable || window.title));
Rectangle {
anchors { margins: -iconSize; topMargin: -iconSize * ((window && window.closable) ? 2 : 1); }
anchors { margins: -iconSize; topMargin: -iconSize * (wideTopMargin ? 2 : 1); }
anchors.fill: parent;
color: "#7f7f7f7f";
radius: 3;

View file

@ -4615,22 +4615,6 @@ void Application::activeChanged(Qt::ApplicationState state) {
break;
}
}
void Application::showFriendsWindow() {
const QString FRIENDS_WINDOW_OBJECT_NAME = "FriendsWindow";
const QString FRIENDS_WINDOW_TITLE = "Add/Remove Friends";
const QString FRIENDS_WINDOW_URL = "https://metaverse.highfidelity.com/user/friends";
const int FRIENDS_WINDOW_WIDTH = 290;
const int FRIENDS_WINDOW_HEIGHT = 500;
auto webWindowClass = _window->findChildren<WebWindowClass>(FRIENDS_WINDOW_OBJECT_NAME);
if (webWindowClass.empty()) {
auto friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH,
FRIENDS_WINDOW_HEIGHT);
friendsWindow->setParent(_window);
friendsWindow->setObjectName(FRIENDS_WINDOW_OBJECT_NAME);
connect(friendsWindow, &WebWindowClass::closed, &WebWindowClass::deleteLater);
friendsWindow->setVisible(true);
}
}
void Application::postLambdaEvent(std::function<void()> f) {
if (this->thread() == QThread::currentThread()) {

View file

@ -245,8 +245,6 @@ public slots:
void handleLocalServerConnection();
void readArgumentsFromLocalSocket();
void showFriendsWindow();
void packageModel();
void openUrl(const QUrl& url);

View file

@ -1323,21 +1323,22 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
_prevShouldDrawHead = shouldDrawHead;
}
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.5f;
bool MyAvatar::cameraInsideHead() const {
const Head* head = getHead();
const glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
return glm::length(cameraPosition - getDefaultEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
}
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
return ((renderArgs->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) ||
(qApp->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
!cameraInsideHead());
bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE;
bool firstPerson = qApp->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON;
bool insideHead = cameraInsideHead();
return !defaultMode || !firstPerson || !insideHead;
}
void MyAvatar::updateOrientation(float deltaTime) {
// Smoothly rotate body with arrow keys
float targetSpeed = _driveKeys[YAW] * _yawSpeed;
if (targetSpeed != 0.0f) {
@ -1522,7 +1523,8 @@ void MyAvatar::updatePosition(float deltaTime) {
// rotate velocity into camera frame
glm::quat rotation = getHead()->getCameraOrientation();
glm::vec3 localVelocity = glm::inverse(rotation) * _targetVelocity;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering());
bool isHovering = _characterController.getState() == CharacterController::State::Hover;
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isHovering);
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
// rotate back into world-frame
@ -1591,10 +1593,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
return false;
}
bool MyAvatar::isHovering() const {
return _characterController.isHovering();
}
void MyAvatar::increaseSize() {
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
_targetScale *= (1.0f + SCALING_RATIO);

View file

@ -240,8 +240,6 @@ public:
glm::quat getCustomListenOrientation() { return _customListenOrientation; }
void setCustomListenOrientation(glm::quat customListenOrientation) { _customListenOrientation = customListenOrientation; }
bool isHovering() const;
public slots:
void increaseSize();
void decreaseSize();

View file

@ -67,7 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() {
_rigidBody->setAngularFactor(0.0f);
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
glmToBullet(_avatar->getPosition())));
if (_isHovering) {
if (_state == State::Hover) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);

View file

@ -72,6 +72,20 @@ void SkeletonModel::initJointStates() {
emit skeletonLoaded();
}
Rig::CharacterControllerState convertCharacterControllerState(CharacterController::State state) {
switch (state) {
default:
case CharacterController::State::Ground:
return Rig::CharacterControllerState::Ground;
case CharacterController::State::Takeoff:
return Rig::CharacterControllerState::Takeoff;
case CharacterController::State::InAir:
return Rig::CharacterControllerState::InAir;
case CharacterController::State::Hover:
return Rig::CharacterControllerState::Hover;
};
}
// Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Head* head = _owningAvatar->getHead();
@ -133,7 +147,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_rig->updateFromHandParameters(handParams, deltaTime);
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), myAvatar->isHovering());
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
// evaluate AnimGraph animation and update jointStates.
Model::updateRig(deltaTime, parentTransform);

View file

@ -144,6 +144,3 @@ void GlobalServicesScriptingInterface::updateDownloadInfo() {
emit downloadInfoChanged(getDownloadInfo());
}
void GlobalServicesScriptingInterface::editFriends() {
QMetaObject::invokeMethod(qApp, "showFriendsWindow");
}

View file

@ -45,8 +45,7 @@ public:
public slots:
DownloadInfoResult getDownloadInfo();
void updateDownloadInfo();
void editFriends();
private slots:
void loggedOut();
void checkDownloadInfo();

View file

@ -504,7 +504,7 @@ static const std::vector<float> FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s
static const std::vector<float> BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s
static const std::vector<float> LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering) {
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState) {
glm::vec3 front = worldRotation * IDENTITY_FRONT;
@ -572,11 +572,21 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
const float TURN_ENTER_SPEED_THRESHOLD = 0.5f; // rad/sec
const float TURN_EXIT_SPEED_THRESHOLD = 0.2f; // rad/sec
if (isHovering) {
if (ccState == CharacterControllerState::Hover) {
if (_desiredState != RigRole::Hover) {
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Hover;
} else if (ccState == CharacterControllerState::InAir) {
if (_desiredState != RigRole::InAir) {
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::InAir;
} else if (ccState == CharacterControllerState::Takeoff) {
if (_desiredState != RigRole::Takeoff) {
_desiredStateAge = 0.0f;
}
_desiredState = RigRole::Takeoff;
} else {
float moveThresh;
if (_state != RigRole::Move) {
@ -614,6 +624,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
const float STATE_CHANGE_HYSTERESIS_TIMER = 0.1f;
// Skip hystersis timer for jump transitions.
if (_desiredState == RigRole::Takeoff) {
_desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER;
} else if (_state == RigRole::InAir && _desiredState != RigRole::InAir) {
_desiredStateAge = STATE_CHANGE_HYSTERESIS_TIMER;
}
if ((_desiredStateAge >= STATE_CHANGE_HYSTERESIS_TIMER) && _desiredState != _state) {
_state = _desiredState;
_desiredStateAge = 0.0f;
@ -662,6 +679,10 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
_animVars.set("isTakeoff", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAir", false);
_animVars.set("isNotInAir", true);
}
} else if (_state == RigRole::Turn) {
if (turningSpeed > 0.0f) {
@ -682,6 +703,11 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotMoving", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
_animVars.set("isTakeoff", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAir", false);
_animVars.set("isNotInAir", true);
} else if (_state == RigRole::Idle ) {
// default anim vars to notMoving and notTurning
_animVars.set("isMovingForward", false);
@ -694,7 +720,12 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
} else {
_animVars.set("isTakeoff", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAir", false);
_animVars.set("isNotInAir", true);
} else if (_state == RigRole::Hover) {
// flying.
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);
@ -706,15 +737,61 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", true);
_animVars.set("isNotFlying", false);
_animVars.set("isTakeoff", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAir", false);
_animVars.set("isNotInAir", true);
} else if (_state == RigRole::Takeoff) {
// jumping in-air
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);
_animVars.set("isMovingLeft", false);
_animVars.set("isMovingRight", false);
_animVars.set("isNotMoving", true);
_animVars.set("isTurningLeft", false);
_animVars.set("isTurningRight", false);
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
_animVars.set("isTakeoff", true);
_animVars.set("isNotTakeoff", false);
_animVars.set("isInAir", true);
_animVars.set("isNotInAir", false);
} else if (_state == RigRole::InAir) {
// jumping in-air
_animVars.set("isMovingForward", false);
_animVars.set("isMovingBackward", false);
_animVars.set("isMovingLeft", false);
_animVars.set("isMovingRight", false);
_animVars.set("isNotMoving", true);
_animVars.set("isTurningLeft", false);
_animVars.set("isTurningRight", false);
_animVars.set("isNotTurning", true);
_animVars.set("isFlying", false);
_animVars.set("isNotFlying", true);
_animVars.set("isTakeoff", false);
_animVars.set("isNotTakeoff", true);
_animVars.set("isInAir", true);
_animVars.set("isNotInAir", false);
// compute blend based on velocity
const float JUMP_SPEED = 3.5f;
float alpha = glm::clamp(-worldVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f;
_animVars.set("inAirAlpha", alpha);
}
t += deltaTime;
if (_enableInverseKinematics) {
_animVars.set("ikOverlayAlpha", 1.0f);
} else {
_animVars.set("ikOverlayAlpha", 0.0f);
if (_enableInverseKinematics != _lastEnableInverseKinematics) {
if (_enableInverseKinematics) {
_animVars.set("ikOverlayAlpha", 1.0f);
} else {
_animVars.set("ikOverlayAlpha", 0.0f);
}
}
_lastEnableInverseKinematics = _enableInverseKinematics;
}
_lastFront = front;

View file

@ -73,6 +73,13 @@ public:
glm::quat rightOrientation = glm::quat(); // rig space (z forward)
};
enum class CharacterControllerState {
Ground = 0,
Takeoff,
InAir,
Hover
};
virtual ~Rig() {}
void destroyAnimGraph();
@ -141,7 +148,7 @@ public:
glm::mat4 getJointTransform(int jointIndex) const;
// Start or stop animations as needed.
void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, bool isHovering);
void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState);
// Regardless of who started the animations or how many, update the joints.
void updateAnimations(float deltaTime, glm::mat4 rootTransform);
@ -271,7 +278,9 @@ public:
Idle = 0,
Turn,
Move,
Hover
Hover,
Takeoff,
InAir
};
RigRole _state { RigRole::Idle };
RigRole _desiredState { RigRole::Idle };
@ -292,6 +301,7 @@ public:
std::map<QString, AnimNode::Pointer> _origRoleAnimations;
std::vector<AnimNode::Pointer> _prefetchedAnimations;
bool _lastEnableInverseKinematics { false };
bool _enableInverseKinematics { true };
private:

View file

@ -15,11 +15,18 @@
#include "PhysicsCollisionGroups.h"
#include "ObjectMotionState.h"
#include "PhysicsLogging.h"
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
const float JUMP_SPEED = 3.5f;
const float MAX_FALL_HEIGHT = 20.0f;
#ifdef DEBUG_STATE_CHANGE
#define SET_STATE(desiredState, reason) setState(desiredState, reason)
#else
#define SET_STATE(desiredState, reason) setState(desiredState)
#endif
// helper class for simple ray-traces from character
class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback {
public:
@ -51,19 +58,17 @@ CharacterController::CharacterController() {
_followDesiredBodyTransform.setIdentity();
_followTimeRemaining = 0.0f;
_jumpSpeed = JUMP_SPEED;
_isOnGround = false;
_isJumping = false;
_isFalling = false;
_isHovering = true;
_state = State::Hover;
_isPushingUp = false;
_jumpToHoverStart = 0;
_jumpButtonDownStart = 0;
_jumpButtonDownCount = 0;
_takeoffToInAirStart = 0;
_followTime = 0.0f;
_followLinearDisplacement = btVector3(0, 0, 0);
_followAngularDisplacement = btQuaternion::getIdentity();
_hasSupport = false;
_pendingFlags = PENDING_FLAG_UPDATE_SHAPE;
}
bool CharacterController::needsRemoval() const {
@ -107,6 +112,8 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
}
}
static const float COS_PI_OVER_THREE = cosf(PI / 3.0f);
bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) const {
int numManifolds = collisionWorld->getDispatcher()->getNumManifolds();
for (int i = 0; i < numManifolds; i++) {
@ -119,8 +126,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld) cons
btManifoldPoint& pt = contactManifold->getContactPoint(j);
// check to see if contact point is touching the bottom sphere of the capsule.
// and the contact normal is not slanted too much.
float contactPointY = (obA == _rigidBody) ? pt.m_localPointA.getY() : pt.m_localPointB.getY();
if (contactPointY < -_halfHeight) {
btVector3 normal = (obA == _rigidBody) ? pt.m_normalWorldOnB : -pt.m_normalWorldOnB;
if (contactPointY < -_halfHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) {
return true;
}
}
@ -153,72 +162,61 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) {
}
void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
btScalar actualSpeed = actualVelocity.length();
btVector3 desiredVelocity = _walkVelocity;
btScalar desiredSpeed = desiredVelocity.length();
const btScalar MIN_UP_PUSH = 0.1f;
if (desiredVelocity.dot(_currentUp) < MIN_UP_PUSH) {
_isPushingUp = false;
}
const btScalar MIN_SPEED = 0.001f;
if (_isHovering) {
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = glm::max(dt / HOVER_BRAKING_TIMESCALE, 1.0f);
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
const btScalar HOVER_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_ACCELERATION_TIMESCALE;
_rigidBody->setLinearVelocity(actualVelocity - tau * (actualVelocity - desiredVelocity));
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
if (actualVelocity.length() < MIN_SPEED) {
actualVelocity = btVector3(0.0f, 0.0f, 0.0f);
}
btVector3 desiredVelocity = _walkVelocity;
if (desiredVelocity.length() < MIN_SPEED) {
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
}
// decompose into horizontal and vertical components.
btVector3 actualVertVelocity = actualVelocity.dot(_currentUp) * _currentUp;
btVector3 actualHorizVelocity = actualVelocity - actualVertVelocity;
btVector3 desiredVertVelocity = desiredVelocity.dot(_currentUp) * _currentUp;
btVector3 desiredHorizVelocity = desiredVelocity - desiredVertVelocity;
btVector3 finalVelocity;
switch (_state) {
case State::Ground:
case State::Takeoff:
{
// horizontal ground control
const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / WALK_ACCELERATION_TIMESCALE;
finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity;
}
} else {
if (onGround()) {
// walking on ground
if (desiredSpeed < MIN_SPEED) {
if (actualSpeed < MIN_SPEED) {
_rigidBody->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
} else {
const btScalar HOVER_BRAKING_TIMESCALE = 0.1f;
btScalar tau = dt / HOVER_BRAKING_TIMESCALE;
_rigidBody->setLinearVelocity((1.0f - tau) * actualVelocity);
}
} else {
// TODO: modify desiredVelocity using floor normal
const btScalar WALK_ACCELERATION_TIMESCALE = 0.1f;
btScalar tau = dt / WALK_ACCELERATION_TIMESCALE;
btVector3 velocityCorrection = tau * (desiredVelocity - actualVelocity);
// subtract vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
_rigidBody->setLinearVelocity(actualVelocity + velocityCorrection);
}
} else {
// transitioning to flying
btVector3 velocityCorrection = desiredVelocity - actualVelocity;
break;
case State::InAir:
{
// horizontal air control
const btScalar IN_AIR_ACCELERATION_TIMESCALE = 2.0f;
btScalar tau = dt / IN_AIR_ACCELERATION_TIMESCALE;
finalVelocity = tau * desiredHorizVelocity + (1.0f - tau) * actualHorizVelocity + actualVertVelocity;
}
break;
case State::Hover:
{
// vertical and horizontal air control
const btScalar FLY_ACCELERATION_TIMESCALE = 0.2f;
btScalar tau = dt / FLY_ACCELERATION_TIMESCALE;
if (!_isPushingUp) {
// actually falling --> compute a different velocity attenuation factor
const btScalar FALL_ACCELERATION_TIMESCALE = 2.0f;
tau = dt / FALL_ACCELERATION_TIMESCALE;
// zero vertical component
velocityCorrection -= velocityCorrection.dot(_currentUp) * _currentUp;
}
_rigidBody->setLinearVelocity(actualVelocity + tau * velocityCorrection);
finalVelocity = tau * desiredVelocity + (1.0f - tau) * actualVelocity;
}
break;
}
_rigidBody->setLinearVelocity(finalVelocity);
// Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform.
// Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
// This mirrors the computation done in MyAvatar::FollowHelper::postPhysicsUpdate().
// These two computations must be kept in sync.
const float MINIMUM_TIME_REMAINING = 0.005f;
const float MAX_DISPLACEMENT = 0.5f * _radius;
_followTimeRemaining -= dt;
@ -254,21 +252,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
}
void CharacterController::jump() {
// check for case where user is holding down "jump" key...
// we'll eventually tansition to "hover"
if (!_isJumping) {
if (!_isHovering) {
_jumpToHoverStart = usecTimestampNow();
_pendingFlags |= PENDING_FLAG_JUMP;
}
} else {
quint64 now = usecTimestampNow();
const quint64 JUMP_TO_HOVER_PERIOD = 75 * (USECS_PER_SECOND / 100);
if (now - _jumpToHoverStart > JUMP_TO_HOVER_PERIOD) {
_isPushingUp = true;
setHovering(true);
}
}
_pendingFlags |= PENDING_FLAG_JUMP;
}
bool CharacterController::onGround() const {
@ -276,18 +260,44 @@ bool CharacterController::onGround() const {
return _floorDistance < FLOOR_PROXIMITY_THRESHOLD || _hasSupport;
}
void CharacterController::setHovering(bool hover) {
if (hover != _isHovering) {
_isHovering = hover;
_isJumping = false;
#ifdef DEBUG_STATE_CHANGE
static const char* stateToStr(CharacterController::State state) {
switch (state) {
case CharacterController::State::Ground:
return "Ground";
case CharacterController::State::Takeoff:
return "Takeoff";
case CharacterController::State::InAir:
return "InAir";
case CharacterController::State::Hover:
return "Hover";
default:
return "Unknown";
}
}
#endif // #ifdef DEBUG_STATE_CHANGE
if (_rigidBody) {
if (hover) {
#ifdef DEBUG_STATE_CHANGE
void CharacterController::setState(State desiredState, const char* reason) {
#else
void CharacterController::setState(State desiredState) {
#endif
if (desiredState != _state) {
#ifdef DEBUG_STATE_CHANGE
qCDebug(physics) << "CharacterController::setState" << stateToStr(desiredState) << "from" << stateToStr(_state) << "," << reason;
#endif
if (desiredState == State::Hover && _state != State::Hover) {
// hover enter
if (_rigidBody) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {
}
} else if (_state == State::Hover && desiredState != State::Hover) {
// hover exit
if (_rigidBody) {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
}
}
_state = desiredState;
}
}
@ -335,9 +345,8 @@ void CharacterController::setEnabled(bool enabled) {
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
}
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
_isOnGround = false;
}
setHovering(true);
SET_STATE(State::Hover, "setEnabled");
_enabled = enabled;
}
}
@ -345,7 +354,7 @@ void CharacterController::setEnabled(bool enabled) {
void CharacterController::updateUpAxis(const glm::quat& rotation) {
btVector3 oldUp = _currentUp;
_currentUp = quatRotate(glmToBullet(rotation), LOCAL_UP_AXIS);
if (!_isHovering) {
if (_state != State::Hover) {
const btScalar MIN_UP_ERROR = 0.01f;
if (oldUp.distance(_currentUp) > MIN_UP_ERROR) {
_rigidBody->setGravity(DEFAULT_CHARACTER_GRAVITY * _currentUp);
@ -410,6 +419,10 @@ void CharacterController::preSimulation() {
if (_enabled && _dynamicsWorld) {
// slam body to where it is supposed to be
_rigidBody->setWorldTransform(_characterBodyTransform);
btVector3 velocity = _rigidBody->getLinearVelocity();
btVector3 actualVertVelocity = velocity.dot(_currentUp) * _currentUp;
btVector3 actualHorizVelocity = velocity - actualVertVelocity;
// scan for distant floor
// rayStart is at center of bottom sphere
@ -424,32 +437,72 @@ void CharacterController::preSimulation() {
_dynamicsWorld->rayTest(rayStart, rayEnd, rayCallback);
if (rayCallback.hasHit()) {
_floorDistance = rayLength * rayCallback.m_closestHitFraction - _radius;
const btScalar MIN_HOVER_HEIGHT = 3.0f;
if (_isHovering && _floorDistance < MIN_HOVER_HEIGHT && !_isPushingUp) {
setHovering(false);
}
// TODO: use collision events rather than ray-trace test to disable jumping
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
if (_floorDistance < JUMP_PROXIMITY_THRESHOLD) {
_isJumping = false;
}
} else if (!_hasSupport) {
} else {
_floorDistance = FLT_MAX;
setHovering(true);
}
if (_pendingFlags & PENDING_FLAG_JUMP) {
_pendingFlags &= ~ PENDING_FLAG_JUMP;
if (onGround()) {
_isJumping = true;
btVector3 velocity = _rigidBody->getLinearVelocity();
const btScalar JUMP_PROXIMITY_THRESHOLD = 0.1f * _radius;
const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 200 * MSECS_PER_SECOND;
const btScalar MIN_HOVER_HEIGHT = 2.5f;
const quint64 JUMP_TO_HOVER_PERIOD = 750 * MSECS_PER_SECOND;
const btScalar MAX_WALKING_SPEED = 2.5f;
quint64 now = usecTimestampNow();
// record a time stamp when the jump button was first pressed.
if ((_previousFlags & PENDING_FLAG_JUMP) != (_pendingFlags & PENDING_FLAG_JUMP)) {
if (_pendingFlags & PENDING_FLAG_JUMP) {
_jumpButtonDownStart = now;
_jumpButtonDownCount++;
}
}
bool jumpButtonHeld = _pendingFlags & PENDING_FLAG_JUMP;
bool flyingFast = _state == State::Hover && actualHorizVelocity.length() > (MAX_WALKING_SPEED * 0.75f);
switch (_state) {
case State::Ground:
if (!rayCallback.hasHit() && !_hasSupport) {
SET_STATE(State::Hover, "no ground");
} else if (_pendingFlags & PENDING_FLAG_JUMP) {
_takeOffJumpButtonID = _jumpButtonDownCount;
SET_STATE(State::Takeoff, "jump pressed");
}
break;
case State::Takeoff:
if (!rayCallback.hasHit() && !_hasSupport) {
SET_STATE(State::Hover, "no ground");
} else if ((now - _takeoffToInAirStart) > TAKE_OFF_TO_IN_AIR_PERIOD) {
SET_STATE(State::InAir, "takeoff done");
_takeoffToInAirStart = now + USECS_PER_SECOND * 86500.0f;
velocity += _jumpSpeed * _currentUp;
_rigidBody->setLinearVelocity(velocity);
}
break;
case State::InAir: {
if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport)) {
SET_STATE(State::Ground, "hit ground");
} else if (jumpButtonHeld && (_takeOffJumpButtonID != _jumpButtonDownCount)) {
SET_STATE(State::Hover, "double jump button");
} else if (jumpButtonHeld && (now - _jumpButtonDownStart) > JUMP_TO_HOVER_PERIOD) {
SET_STATE(State::Hover, "jump button held");
}
break;
}
case State::Hover:
if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) {
SET_STATE(State::InAir, "near ground");
} else if (((_floorDistance < JUMP_PROXIMITY_THRESHOLD) || _hasSupport) && !flyingFast) {
SET_STATE(State::Ground, "touching ground");
}
break;
}
}
_followTime = 0.0f;
_previousFlags = _pendingFlags;
_pendingFlags &= ~PENDING_FLAG_JUMP;
_followTime = 0.0f;
_followLinearDisplacement = btVector3(0, 0, 0);
_followAngularDisplacement = btQuaternion::getIdentity();
}

View file

@ -31,6 +31,8 @@ class btRigidBody;
class btCollisionWorld;
class btDynamicsWorld;
//#define DEBUG_STATE_CHANGE
class CharacterController : public btCharacterControllerInterface {
public:
CharacterController();
@ -75,8 +77,14 @@ public:
glm::vec3 getLinearVelocity() const;
bool isHovering() const { return _isHovering; }
void setHovering(bool enabled);
enum class State {
Ground = 0,
Takeoff,
InAir,
Hover
};
State getState() const { return _state; }
void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale);
@ -86,6 +94,12 @@ public:
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
protected:
#ifdef DEBUG_STATE_CHANGE
void setState(State state, const char* reason);
#else
void setState(State state);
#endif
void updateUpAxis(const glm::quat& rotation);
bool checkForSupport(btCollisionWorld* collisionWorld) const;
@ -100,7 +114,10 @@ protected:
glm::vec3 _boxScale; // used to compute capsule shape
quint64 _jumpToHoverStart;
quint64 _takeoffToInAirStart;
quint64 _jumpButtonDownStart;
quint32 _jumpButtonDownCount;
quint32 _takeOffJumpButtonID;
btScalar _halfHeight;
btScalar _radius;
@ -116,16 +133,13 @@ protected:
btQuaternion _followAngularDisplacement;
bool _enabled;
bool _isOnGround;
bool _isJumping;
bool _isFalling;
bool _isHovering;
State _state;
bool _isPushingUp;
btDynamicsWorld* _dynamicsWorld { nullptr };
btRigidBody* _rigidBody { nullptr };
uint32_t _pendingFlags { 0 };
uint32_t _previousFlags { 0 };
};
#endif // hifi_CharacterControllerInterface_h

View file

@ -45,6 +45,20 @@ private:
bool _navigationFocused { false };
};
QString fixupHifiUrl(const QString& urlString) {
static const QString ACCESS_TOKEN_PARAMETER = "access_token";
static const QString ALLOWED_HOST = "metaverse.highfidelity.com";
QUrl url(urlString);
QUrlQuery query(url);
if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) {
AccountManager& accountManager = AccountManager::getInstance();
query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token);
url.setQuery(query.query());
return url.toString();
}
return urlString;
}
class UrlHandler : public QObject {
Q_OBJECT
public:
@ -60,20 +74,7 @@ public:
// FIXME hack for authentication, remove when we migrate to Qt 5.6
Q_INVOKABLE QString fixupUrl(const QString& originalUrl) {
static const QString ACCESS_TOKEN_PARAMETER = "access_token";
static const QString ALLOWED_HOST = "metaverse.highfidelity.com";
QString result = originalUrl;
QUrl url(originalUrl);
QUrlQuery query(url);
if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) {
qDebug() << "Updating URL with auth token";
AccountManager& accountManager = AccountManager::getInstance();
query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager.getAccountInfo().getAccessToken().token);
url.setQuery(query.query());
result = url.toString();
}
return result;
return fixupHifiUrl(originalUrl);
}
};

View file

@ -49,8 +49,11 @@ QString QmlWebWindowClass::getURL() const {
return result.toString();
}
// HACK find a good place to declare and store this
extern QString fixupHifiUrl(const QString& urlString);
void QmlWebWindowClass::setURL(const QString& urlString) {
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
_qmlWindow->setProperty(URL_PROPERTY, urlString);
_qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString));
});
}