Merge pull request #16305 from highfidelity/master

Merge master into instancing
This commit is contained in:
Sabrina Shanman 2019-10-07 15:44:42 -07:00 committed by GitHub
commit 2fcb526a5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 918 additions and 230 deletions

View file

@ -556,7 +556,51 @@ void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool
}
void EntityScriptServer::sendStatsPacket() {
QJsonObject statsObject;
QJsonObject octreeStats;
octreeStats["elementCount"] = (double)OctreeElement::getNodeCount();
octreeStats["internalElementCount"] = (double)OctreeElement::getInternalNodeCount();
octreeStats["leafElementCount"] = (double)OctreeElement::getLeafNodeCount();
statsObject["octree_stats"] = octreeStats;
QJsonObject scriptEngineStats;
int numberRunningScripts = 0;
const auto scriptEngine = _entitiesScriptEngine;
if (scriptEngine) {
numberRunningScripts = scriptEngine->getNumRunningEntityScripts();
}
scriptEngineStats["number_running_scripts"] = numberRunningScripts;
statsObject["script_engine_stats"] = scriptEngineStats;
auto nodeList = DependencyManager::get<NodeList>();
QJsonObject nodesObject;
nodeList->eachNode([&](const SharedNodePointer& node) {
QJsonObject clientStats;
const QString uuidString(uuidStringWithoutCurlyBraces(node->getUUID()));
clientStats["node_type"] = NodeType::getNodeTypeName(node->getType());
auto& nodeStats = node->getConnectionStats();
static const QString NODE_OUTBOUND_KBPS_STAT_KEY("outbound_kbit/s");
static const QString NODE_INBOUND_KBPS_STAT_KEY("inbound_kbit/s");
// add the key to ask the domain-server for a username replacement, if it has it
clientStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuidString;
clientStats[NODE_OUTBOUND_KBPS_STAT_KEY] = node->getOutboundKbps();
clientStats[NODE_INBOUND_KBPS_STAT_KEY] = node->getInboundKbps();
using namespace std::chrono;
const float statsPeriod = duration<float, seconds::period>(nodeStats.endTime - nodeStats.startTime).count();
clientStats["unreliable_packet/s"] = (nodeStats.sentUnreliablePackets + nodeStats.receivedUnreliablePackets) / statsPeriod;
clientStats["reliable_packet/s"] = (nodeStats.sentPackets + nodeStats.receivedPackets) / statsPeriod;
nodesObject[uuidString] = clientStats;
});
statsObject["nodes"] = nodesObject;
addPacketStatsAndSendStatsPacket(statsObject);
}
void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {

View file

@ -136,6 +136,23 @@ function getCurrentDomainIDType() {
return DOMAIN_ID_TYPE_UNKNOWN;
}
function isCloudDomain() {
if (!domainIDIsSet()) {
return false;
}
if (typeof DomainInfo === 'undefined') {
return false;
}
if (DomainInfo === null) {
return false;
}
if (typeof DomainInfo.cloud_domain !== "boolean") {
return false;
}
return DomainInfo.cloud_domain;
}
function showLoadingDialog(msg) {
var message = '<div class="text-center">';
message += '<span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> ' + msg;

View file

@ -606,6 +606,9 @@ $(document).ready(function(){
var address = DomainInfo.network_address === null ? '' : DomainInfo.network_address;
var port = DomainInfo.network_port === null ? '' : DomainInfo.network_port;
var modal_body = "<div class='form-group'>";
if (isCloudDomain()) {
modal_body += '<div style="color:red;font-weight: bold">Changing the network settings may actually break your domain.</div>';
}
if (includeAddress) {
modal_body += "<label class='control-label'>Address</label>";
modal_body += "<input type='text' id='network-address-input' class='form-control' value='" + address + "'>";
@ -867,6 +870,10 @@ $(document).ready(function(){
}
}
if (getCurrentDomainIDType() === DOMAIN_ID_TYPE_TEMP) {
$(Settings.DOMAIN_ID_SELECTOR).siblings('span').append(" <b>This is a temporary domain and will not be visible in your domain list.</b>");
}
if (accessTokenIsSet()) {
appendAddButtonToPlacesTable();
}

View file

@ -385,7 +385,7 @@ void DomainServer::parseCommandLine(int argc, char* argv[]) {
}
if (_iceServerAddr.isEmpty()) {
qCWarning(domain_server_ice) << "Could not parse an IP address and port combination from" << hostnamePortString;
qCWarning(domain_server_ice) << "ALERT: Could not parse an IP address and port combination from" << hostnamePortString;
::exit(0);
}
}
@ -876,7 +876,7 @@ void DomainServer::setupAutomaticNetworking() {
nodeList->startSTUNPublicSocketUpdate();
}
} else {
qDebug() << "Cannot enable domain-server automatic networking without a domain ID."
qCCritical(domain_server) << "PAGE: Cannot enable domain-server automatic networking without a domain ID."
<< "Please add an ID to your config file or via the web interface.";
return;
}
@ -1635,8 +1635,9 @@ void DomainServer::handleFailedICEServerAddressUpdate(QNetworkReply* requestRepl
} else {
const int ICE_SERVER_UPDATE_RETRY_MS = 2 * 1000;
qCWarning(domain_server_ice) << "Failed to update ice-server address (" << _iceServerSocket << ") with High Fidelity Metaverse - error was"
<< requestReply->errorString();
qCWarning(domain_server_ice) << "PAGE: Failed to update ice-server address (" << _iceServerSocket <<
") with Metaverse (" << requestReply->url() << ") (critical error for auto-networking) error:" <<
requestReply->errorString();
qCWarning(domain_server_ice) << "\tRe-attempting in" << ICE_SERVER_UPDATE_RETRY_MS / 1000 << "seconds";
QTimer::singleShot(ICE_SERVER_UPDATE_RETRY_MS, this, SLOT(sendICEServerAddressToMetaverseAPI()));
@ -3450,8 +3451,9 @@ void DomainServer::randomizeICEServerAddress(bool shouldTriggerHostLookup) {
// we ended up with an empty list since everything we've tried has failed
// so clear the set of failed addresses and start going through them again
qCWarning(domain_server_ice) << "All current ice-server addresses have failed - re-attempting all current addresses for"
<< _iceServerAddr;
qCWarning(domain_server_ice) <<
"PAGE: All current ice-server addresses have failed - re-attempting all current addresses for"
<< _iceServerAddr;
_failedIceServerAddresses.clear();
candidateICEAddresses = _iceServerAddresses;

View file

@ -640,8 +640,8 @@
{
"easingType": "easeInOutQuad",
"id": "seatedTalk02",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
@ -651,8 +651,8 @@
{
"easingType": "easeInOutQuad",
"id": "seatedTalk03",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
@ -662,8 +662,8 @@
{
"easingType": "easeInOutQuad",
"id": "seatedTalk04",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
@ -680,84 +680,414 @@
"children": [
{
"children": [
{
"children": [
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 0,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle.fbx"
},
"id": "seatedIdle01",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle02.fbx"
},
"id": "seatedIdle02",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 0,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle03.fbx"
},
"id": "seatedIdle03",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle04.fbx"
},
"id": "seatedIdle04",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 332,
"loopFlag": true,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle05.fbx"
},
"id": "seatedIdle05",
"type": "clip"
}
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 0,
"currentState": "seatedIdle01",
"endFrame": 30,
"randomSwitchTimeMax": 40,
"randomSwitchTimeMin": 10,
"startFrame": 10,
"states": [
{
"easingType": "easeInOutQuad",
"id": "seatedIdle01",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle02",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle03",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle04",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle05",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
}
],
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle.fbx"
"triggerRandomSwitch": "seatedIdleSwitch",
"triggerTimeMax": 10
},
"id": "seatedIdle01",
"type": "clip"
"id": "masterSeatedIdle",
"type": "randomSwitchStateMachine"
},
{
"children": [
{
"children": [
],
"data": {
"endFrame": 744,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_shifting.fbx"
},
"id": "seatedFidgetShifting",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 420,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_lookfidget.fbx"
},
"id": "seatedFidgetLookFidget",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 282,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_shiftweight.fbx"
},
"id": "seatedFidgetShiftWeight",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 428,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_fidget.fbx"
},
"id": "seatedFidgeting",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 324,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_lookaround.fbx"
},
"id": "seatedFidgetLookAround",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 120,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_lookleftright.fbx"
},
"id": "seatedFidgetLookLeftRight",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 178,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_leanforward.fbx"
},
"id": "seatedFidgetLeanForward",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 140,
"loopFlag": false,
"startFrame": 1,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle_once_shakelegs.fbx"
},
"id": "seatedFidgetShakeLegs",
"type": "clip"
}
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 0,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle02.fbx"
"currentState": "seatedFidgetShifting",
"states": [
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetShifting",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetLookFidget",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetShiftWeight",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgeting",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetLookAround",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetLookLeftRight",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetLeanForward",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedFidgetShakeLegs",
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 1,
"resume": false,
"transitions": [
]
}
]
},
"id": "seatedIdle02",
"type": "clip"
},
{
"children": [
],
"data": {
"endFrame": 800,
"loopFlag": true,
"startFrame": 0,
"timeScale": 1,
"url": "qrc:///avatar/animations/sitting_idle03.fbx"
},
"id": "seatedIdle03",
"type": "clip"
"id": "seatedFidget",
"type": "randomSwitchStateMachine"
}
],
"data": {
"currentState": "seatedIdle01",
"currentState": "masterSeatedIdle",
"randomSwitchTimeMax": 20,
"randomSwitchTimeMin": 10,
"states": [
{
"easingType": "easeInOutQuad",
"id": "seatedIdle01",
"interpDuration": 15,
"interpTarget": 15,
"id": "masterSeatedIdle",
"interpDuration": 20,
"interpTarget": 20,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"resume": false,
"transitions": [
{
"randomSwitchState": "seatedFidget",
"var": "timeToSeatedFidget"
}
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle02",
"interpDuration": 15,
"interpTarget": 15,
"id": "seatedFidget",
"interpDuration": 30,
"interpTarget": 30,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"transitions": [
]
},
{
"easingType": "easeInOutQuad",
"id": "seatedIdle03",
"interpDuration": 15,
"interpTarget": 15,
"interpType": "evaluateBoth",
"priority": 1,
"resume": true,
"priority": -1,
"resume": false,
"transitions": [
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetShiftingOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetLookFidgetOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetShiftWeightOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetingOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetLookAroundOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetLookLeftRightOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetLeanForwardOnDone"
},
{
"randomSwitchState": "masterSeatedIdle",
"var": "seatedFidgetShakeLegsOnDone"
}
]
}
],
"triggerRandomSwitch": "seatedIdleSwitch"
"transitionVar": "timeToSeatedFidget",
"triggerRandomSwitch": "",
"triggerTimeMax": 45,
"triggerTimeMin": 10
},
"id": "seatedIdle",
"type": "randomSwitchStateMachine"
@ -1544,9 +1874,9 @@
"type": "randomSwitchStateMachine"
},
{
"children": [
"children": [
{
"children": [
"children": [
{
"children": [
{
@ -1653,7 +1983,7 @@
"blendType": "addAbsolute"
},
"id": "seatedReactionPointBase",
"type": "blendLinear"
"type": "blendLinear"
},
{
"children": [
@ -2148,8 +2478,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2159,8 +2489,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk02",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2170,8 +2500,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk03",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2181,8 +2511,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk04",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2192,8 +2522,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk_armsdown",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2203,8 +2533,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk_lefthand",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2214,8 +2544,8 @@
{
"easingType": "easeInOutQuad",
"id": "talk_righthand",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 1,
"interpTarget": 1,
"interpType": "evaluateBoth",
"priority": 0.33,
"resume": true,
@ -2773,8 +3103,8 @@
{
"easingType": "easeInOutQuad",
"id": "fidget",
"interpDuration": 15,
"interpTarget": 15,
"interpDuration": 20,
"interpTarget": 20,
"interpType": "evaluateBoth",
"priority": -1,
"resume": false,
@ -3997,8 +4327,8 @@
{
"easingType": "easeInOutQuad",
"id": "idleTalkOverlay",
"interpDuration": 20,
"interpTarget": 20,
"interpDuration": 25,
"interpTarget": 25,
"interpType": "evaluateBoth",
"transitions": [
{

View file

@ -3610,10 +3610,9 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
_myCamera.setPosition(extractTranslation(camMat));
_myCamera.setOrientation(glmExtractRotation(camMat));
}
else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
} else {
_myCamera.setPosition(myAvatar->getLookAtPivotPoint());
_myCamera.setOrientation(myAvatar->getLookAtRotation());
}
} else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
if (isHMDMode()) {
@ -3647,9 +3646,9 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
if (mode == CAMERA_MODE_SELFIE) {
lookAtRotation = lookAtRotation * glm::angleAxis(PI, myAvatar->getWorldOrientation() * Vectors::UP);
}
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
_myCamera.setPosition(myAvatar->getLookAtPivotPoint()
+ lookAtRotation * boomOffset);
_myCamera.lookAt(myAvatar->getDefaultEyePosition());
_myCamera.lookAt(myAvatar->getLookAtPivotPoint());
}
}
} else if (mode == CAMERA_MODE_MIRROR) {
@ -3677,8 +3676,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
+ glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0)
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
+ mirrorBodyOrientation * hmdOffset);
}
else {
} else {
auto userInputMapper = DependencyManager::get<UserInputMapper>();
const float YAW_SPEED = TWO_PI / 5.0f;
float deltaYaw = userInputMapper->getActionState(controller::Action::YAW) * YAW_SPEED * deltaTime;
@ -3699,8 +3697,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setOrientation(cameraEntity->getWorldOrientation() * hmdRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
_myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset));
}
else {
} else {
_myCamera.setOrientation(cameraEntity->getWorldOrientation());
_myCamera.setPosition(cameraEntity->getWorldPosition());
}

View file

@ -958,7 +958,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
head->setScale(getModelScale());
head->simulate(deltaTime);
CameraMode mode = qApp->getCamera().getMode();
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
if (!_pointAtActive || !_isPointTargetValid) {
updateHeadLookAt(deltaTime);
} else {
@ -2718,7 +2718,8 @@ void MyAvatar::updateMotors() {
if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) {
if (_characterController.getState() == CharacterController::State::Hover ||
_characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_SELFIE) {
CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
motorRotation = getLookAtRotation();
} else {
motorRotation = getMyHead()->getHeadOrientation();
@ -3442,8 +3443,10 @@ void MyAvatar::updateOrientation(float deltaTime) {
// Smoothly rotate body with arrow keys
float targetSpeed = getDriveKey(YAW) * _yawSpeed;
CameraMode mode = qApp->getCamera().getMode();
bool computeLookAt = (mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) && isReadyForPhysics() && !qApp->isHMDMode();
if (computeLookAt) {
bool computeLookAt = isReadyForPhysics() && !qApp->isHMDMode() &&
(mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE);
bool smoothCameraYaw = computeLookAt && mode != CAMERA_MODE_FIRST_PERSON;
if (smoothCameraYaw) {
// For "Look At" and "Selfie" camera modes we also smooth the yaw rotation from right-click mouse movement.
float speedFromDeltaYaw = deltaTime > FLT_EPSILON ? getDriveKey(DELTA_YAW) / deltaTime : 0.0f;
speedFromDeltaYaw *= _yawSpeed / YAW_SPEED_DEFAULT;
@ -3472,7 +3475,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
}
}
float totalBodyYaw = _bodyYawDelta * deltaTime;
if (!computeLookAt) {
if (!smoothCameraYaw) {
// Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement.
totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT;
}
@ -3563,12 +3566,16 @@ void MyAvatar::updateOrientation(float deltaTime) {
blend = 1.0f;
}
glm::quat faceRotation = _lookAtYaw;
if (isMovingFwdBwd && isMovingSideways) {
// Reorient avatar to face camera diagonal
blend = DIAGONAL_TURN_BLEND;
float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f;
turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign;
faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP);
if (isMovingFwdBwd) {
if (isMovingSideways) {
// Reorient avatar to face camera diagonal
blend = mode == CAMERA_MODE_FIRST_PERSON ? 1.0f : DIAGONAL_TURN_BLEND;
float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f;
turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign;
faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP);
} else if (mode == CAMERA_MODE_FIRST_PERSON) {
blend = 1.0f;
}
}
setWorldOrientation(glm::slerp(getWorldOrientation(), faceRotation, blend));
} else if (isRotatingWhileSeated) {
@ -3630,20 +3637,32 @@ void MyAvatar::updateOrientation(float deltaTime) {
glm::vec3 avatarVectorRight = getWorldOrientation() * Vectors::RIGHT;
float leftRightDot = glm::dot(cameraYawVector, avatarVectorRight);
const float REORIENT_ANGLE = 65.0f;
const float DEFAULT_REORIENT_ANGLE = 65.0f;
const float FIRST_PERSON_REORIENT_ANGLE = 95.0f;
const float TRIGGER_REORIENT_ANGLE = 45.0f;
const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 65.0f;
glm::vec3 ajustedYawVector = cameraYawVector;
if (frontBackDot < 0.0f) {
ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight);
cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT;
float limitAngle = 0.0f;
float triggerAngle = -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE));
if (mode == CAMERA_MODE_FIRST_PERSON) {
limitAngle = glm::sin(glm::radians(90.0f - FIRST_PERSON_TRIGGER_REORIENT_ANGLE));
triggerAngle = limitAngle;
}
float reorientAngle = mode == CAMERA_MODE_FIRST_PERSON ? FIRST_PERSON_REORIENT_ANGLE : DEFAULT_REORIENT_ANGLE;
if (frontBackDot < limitAngle) {
if (frontBackDot < 0.0f) {
ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight);
cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT;
}
if (!isRotatingWhileSeated) {
if (frontBackDot < -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE))) {
if (frontBackDot < triggerAngle) {
_shouldTurnToFaceCamera = true;
_firstPersonSteadyHeadTimer = 0.0f;
}
} else {
setWorldOrientation(previousOrientation);
}
} else if (frontBackDot > glm::sin(glm::radians(REORIENT_ANGLE))) {
} else if (frontBackDot > glm::sin(glm::radians(reorientAngle))) {
_shouldTurnToFaceCamera = false;
}
@ -3664,6 +3683,22 @@ void MyAvatar::updateOrientation(float deltaTime) {
_lookAtCameraTarget = targetPoint;
}
_headLookAtActive = true;
const float FIRST_PERSON_RECENTER_SECONDS = 15.0f;
if (mode == CAMERA_MODE_FIRST_PERSON) {
if (getDriveKey(YAW) + getDriveKey(STEP_YAW) + getDriveKey(DELTA_YAW) == 0.0f) {
if (_firstPersonSteadyHeadTimer < FIRST_PERSON_RECENTER_SECONDS) {
if (_firstPersonSteadyHeadTimer > 0.0f) {
_firstPersonSteadyHeadTimer += deltaTime;
}
} else {
_shouldTurnToFaceCamera = true;
_firstPersonSteadyHeadTimer = 0.0f;
}
} else {
_firstPersonSteadyHeadTimer = deltaTime;
}
}
} else {
head->setBaseYaw(0.0f);
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime
@ -3736,7 +3771,8 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig
} else {
// Desktop mode.
direction = (zSpeed * forward) + (xSpeed * right);
if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT && zSpeed != 0.0f && xSpeed != 0.0f){
CameraMode mode = qApp->getCamera().getMode();
if ((mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_SELFIE) && zSpeed != 0.0f && xSpeed != 0.0f){
direction = (zSpeed * forward);
}
@ -4351,7 +4387,8 @@ bool MyAvatar::isFlying() {
bool MyAvatar::isInAir() {
// If Avatar is Hover, Falling, or Taking off, they are in Air.
return _characterController.getState() != CharacterController::State::Ground;
return _characterController.getState() != CharacterController::State::Ground &&
_characterController.getState() != CharacterController::State::Seated;
}
bool MyAvatar::getFlyingEnabled() {
@ -5399,7 +5436,7 @@ glm::quat MyAvatar::getOrientationForAudio() {
case AudioListenerMode::FROM_HEAD: {
// Using the camera's orientation instead, when the current mode is controlling the avatar's head.
CameraMode mode = qApp->getCamera().getMode();
bool headFollowsCamera = mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE;
bool headFollowsCamera = mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE;
result = headFollowsCamera ? qApp->getCamera().getOrientation() : getHead()->getFinalOrientationInWorldFrame();
break;
}
@ -6768,6 +6805,12 @@ void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) {
_lookAtScriptTarget = lookAtTarget;
}
glm::vec3 MyAvatar::getLookAtPivotPoint() {
glm::vec3 avatarUp = getWorldOrientation() * Vectors::UP;
glm::vec3 yAxisEyePosition = getWorldPosition() + avatarUp * glm::dot(avatarUp, _skeletonModel->getDefaultEyeModelPosition());
return yAxisEyePosition;
}
bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) {
if (QThread::currentThread() != thread()) {
bool result = false;
@ -6794,3 +6837,4 @@ void MyAvatar::resetPointAt() {
POINT_BLEND_LINEAR_ALPHA_NAME, POINT_ALPHA_BLENDING);
}
}

View file

@ -272,11 +272,12 @@ class MyAvatar : public Avatar {
* the value.</p>
* @property {number} analogPlusSprintSpeed - The sprint (run) speed of your avatar for the "AnalogPlus" control scheme.
* @property {MyAvatar.SitStandModelType} userRecenterModel - Controls avatar leaning and recentering behavior.
* @property {number} isInSittingState - <code>true</code> if your avatar is sitting (avatar leaning is disabled,
* recenntering is enabled), <code>false</code> if it is standing (avatar leaning is enabled, and avatar recenters if it
* leans too far). If <code>userRecenterModel == 2</code> (i.e., auto) the property value automatically updates as the
* user sits or stands, unless <code>isSitStandStateLocked == true</code>. Setting the property value overrides the
* current siting / standing state, which is updated when the user next sits or stands unless
* @property {number} isInSittingState - <code>true</code> if the user wearing the HMD is determined to be sitting
* (avatar leaning is disabled, recenntering is enabled), <code>false</code> if the user wearing the HMD is
* determined to be standing (avatar leaning is enabled, and avatar recenters if it leans too far).
* If <code>userRecenterModel == 2</code> (i.e., auto) the property value automatically updates as the user sits
* or stands, unless <code>isSitStandStateLocked == true</code>. Setting the property value overrides the current
* siting / standing state, which is updated when the user next sits or stands unless
* <code>isSitStandStateLocked == true</code>.
* @property {boolean} isSitStandStateLocked - <code>true</code> to lock the avatar sitting/standing state, i.e., use this
* to disable automatically changing state.
@ -1890,6 +1891,14 @@ public:
*/
Q_INVOKABLE void endSit(const glm::vec3& position, const glm::quat& rotation);
/**jsdoc
* Gets whether the avatar is in a seated pose. The seated pose is set by calling the
* MyAvatar::beginSit method.
* @function MyAvatar.isSeated
* @returns {boolean} <code>true</code> if the avatar is in a seated pose.
*/
Q_INVOKABLE bool isSeated() { return _characterController.getSeated(); }
int getOverrideJointCount() const;
bool getFlowActive() const;
bool getNetworkGraphActive() const;
@ -1906,6 +1915,7 @@ public:
void debugDrawPose(controller::Action action, const char* channelName, float size);
bool getIsJointOverridden(int jointIndex) const;
glm::vec3 getLookAtPivotPoint();
public slots:
@ -2663,6 +2673,7 @@ private:
bool _shouldTurnToFaceCamera { false };
bool _scriptControlsHeadLookAt { false };
float _scriptHeadControlTimer { 0.0f };
float _firstPersonSteadyHeadTimer { 0.0f };
bool _pointAtActive { false };
bool _isPointTargetValid { true };

View file

@ -6,5 +6,7 @@
<array>
<string>high-fidelity.hifi</string>
</array>
<key>com.apple.security.device.audio-input</key>
<true/>
</dict>
</plist>

View file

@ -92,22 +92,23 @@ void Head::simulate(float deltaTime) {
} else if (_timeWithoutTalking - deltaTime < BLINK_AFTER_TALKING && _timeWithoutTalking >= BLINK_AFTER_TALKING) {
forceBlink = true;
}
if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
// no blinking when brows are raised; blink less with increasing loudness
const float BASE_BLINK_RATE = 15.0f / 60.0f;
const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(fabs(_averageLoudness - _longTermAverageLoudness)) *
ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
_leftEyeBlinkVelocity = BLINK_SPEED + randFloat() * BLINK_SPEED_VARIABILITY;
_rightEyeBlinkVelocity = BLINK_SPEED + randFloat() * BLINK_SPEED_VARIABILITY;
float randSpeedVariability = randFloat();
float eyeBlinkVelocity = BLINK_SPEED + randSpeedVariability * BLINK_SPEED_VARIABILITY;
_leftEyeBlinkVelocity = eyeBlinkVelocity;
_rightEyeBlinkVelocity = eyeBlinkVelocity;
if (randFloat() < 0.5f) {
_leftEyeBlink = BLINK_START_VARIABILITY;
} else {
_rightEyeBlink = BLINK_START_VARIABILITY;
}
}
} else {
_leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
_rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);

View file

@ -96,6 +96,21 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent);
connect(entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent);
connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent);
// Handle mouse-clicking or laser-clicking on entities with the `href` property set
connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
if (!EntityTree::areEntityClicksCaptured() && (event.getButtons() & PointerEvent::PrimaryButton)) {
auto entity = getEntity(entityID);
if (!entity) {
return;
}
auto properties = entity->getProperties();
QString urlString = properties.getHref();
QUrl url = QUrl(urlString, QUrl::StrictMode);
if (url.isValid() && !url.isEmpty()) {
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
}
}
});
connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, [&](const QUuid& entityID, const PointerEvent& event) {
std::shared_ptr<render::entities::WebEntityRenderer> thisEntity;
auto entity = getEntity(entityID);
@ -800,15 +815,6 @@ QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
EntityItemPointer entity;
if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) {
if (!EntityTree::areEntityClicksCaptured() && event->button() == Qt::MouseButton::LeftButton) {
auto properties = entity->getProperties();
QString urlString = properties.getHref();
QUrl url = QUrl(urlString, QUrl::StrictMode);
if (url.isValid() && !url.isEmpty()) {
DependencyManager::get<AddressManager>()->handleLookupString(urlString);
}
}
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID,
pos2D, rayPickResult.intersection,

View file

@ -706,15 +706,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
*
* @property {Vec3} gravity=0,0,0 - The acceleration due to gravity in m/s<sup>2</sup> that the entity should move with, in
* world coordinates. Use a value of <code>{ x: 0, y: -9.8, z: 0 }</code> to simulate Earth's gravity. Gravity is applied
* to an entity's motion only if its <code>dynamic</code> property is <code>true</code>. The <code>gravity</code> value is
* applied in addition to the <code>acceleration</code> value.
* to an entity's motion only if its <code>dynamic</code> property is <code>true</code>.
* <p>If changing an entity's <code>gravity</code> from {@link Vec3(0)|Vec3.ZERO}, you need to give it a small
* <code>velocity</code> in order to kick off physics simulation.</p>
* @property {Vec3} acceleration=0,0,0 - A general acceleration in m/s<sup>2</sup> that the entity should move with, in world
* coordinates. The acceleration is applied to an entity's motion only if its <code>dynamic</code> property is
* <code>true</code>. The <code>acceleration</code> value is applied in addition to the <code>gravity</code> value.
* <p>If changing an entity's <code>acceleration</code> from {@link Vec3(0)|Vec3.ZERO}, you need to give it a small
* <code>velocity</code> in order to kick off physics simulation.<p>
* @property {Vec3} acceleration - The current, measured acceleration of the entity, in m/s<sup>2</sup>.
* <p class="important">Deprecated: This property is deprecated and will be removed.</p>
* @property {number} restitution=0.5 - The "bounciness" of an entity when it collides, range <code>0.0</code> &ndash;
* <code>0.99</code>. The higher the value, the more bouncy.
* @property {number} friction=0.5 - How much an entity slows down when it's moving against another, range <code>0.0</code>

View file

@ -728,7 +728,8 @@ public slots:
* Finds all domain and avatar entities whose axis-aligned boxes intersect a search frustum.
* @function Entities.findEntitiesInFrustum
* @param {ViewFrustum} frustum - The frustum to search in. The <code>position</code>, <code>orientation</code>,
* <code>projection</code>, and <code>centerRadius</code> properties must be specified.
* <code>projection</code>, and <code>centerRadius</code> properties must be specified. The <code>fieldOfView</code>
* and <code>aspectRatio</code> properties are not used; these values are specified by the <code>projection</code>.
* @returns {Uuid[]} An array of entity IDs whose axis-aligned boxes intersect the search frustum. The array is empty if no
* entities could be found.
* @example <caption>Report the number of entities in view.</caption>

View file

@ -1035,7 +1035,7 @@ void AccountManager::publicKeyUploadSucceeded(QNetworkReply* reply) {
void AccountManager::publicKeyUploadFailed(QNetworkReply* reply) {
// the public key upload has failed
qWarning() << "Public key upload failed from AccountManager" << reply->errorString();
qCritical() << "PAGE: Public key upload failed from AccountManager to" << reply->url() << reply->errorString();
// we aren't waiting for a response any longer
_isWaitingForKeypairResponse = false;

View file

@ -234,14 +234,38 @@ const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
return callbackParams;
}
bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
bool AddressManager::handleUrl(const QUrl& lookupUrlIn, LookupTrigger trigger) {
static QString URL_TYPE_USER = "user";
static QString URL_TYPE_DOMAIN_ID = "domain_id";
static QString URL_TYPE_PLACE = "place";
static QString URL_TYPE_NETWORK_ADDRESS = "network_address";
if (lookupUrl.scheme() == URL_SCHEME_HIFI) {
qCDebug(networking) << "Trying to go to URL" << lookupUrl.toString();
QUrl lookupUrl = lookupUrlIn;
qCDebug(networking) << "Trying to go to URL" << lookupUrl.toString();
if (lookupUrl.scheme().isEmpty() && !lookupUrl.path().startsWith("/")) {
// 'urls' without schemes are taken as domain names, as opposed to
// simply a path portion of a url, so we need to set the scheme
lookupUrl.setScheme(URL_SCHEME_HIFI);
}
static const QRegExp PORT_REGEX = QRegExp("\\d{1,5}(\\/.*)?");
if(!lookupUrl.scheme().isEmpty() && lookupUrl.host().isEmpty() && PORT_REGEX.exactMatch(lookupUrl.path())) {
// this is in the form somewhere:<port>, convert it to hifi://somewhere:<port>
lookupUrl = QUrl(URL_SCHEME_HIFI + "://" + lookupUrl.toString());
}
// it should be noted that url's in the form
// somewhere:<port> are not valid, as that
// would indicate that the scheme is 'somewhere'
// use hifi://somewhere:<port> instead
if (lookupUrl.scheme() == URL_SCHEME_HIFI) {
if (lookupUrl.host().isEmpty()) {
// this was in the form hifi:/somewhere or hifi:somewhere. Fix it by making it hifi://somewhere
static const QRegExp HIFI_SCHEME_REGEX = QRegExp(URL_SCHEME_HIFI + ":\\/?", Qt::CaseInsensitive);
lookupUrl = QUrl(lookupUrl.toString().replace(HIFI_SCHEME_REGEX, URL_SCHEME_HIFI + "://"));
}
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::LookupAddress);
@ -379,25 +403,11 @@ bool isPossiblePlaceName(QString possiblePlaceName) {
}
void AddressManager::handleLookupString(const QString& lookupString, bool fromSuggestions) {
if (!lookupString.isEmpty()) {
QString sanitizedString = lookupString.trimmed();
if (!sanitizedString.isEmpty()) {
// make this a valid hifi URL and handle it off to handleUrl
QString sanitizedString = lookupString.trimmed();
QUrl lookupURL;
if (!lookupString.startsWith('/')) {
// sometimes we need to handle lookupStrings like hifi:/somewhere
const QRegExp HIFI_SCHEME_REGEX = QRegExp(URL_SCHEME_HIFI + ":\\/{1,2}", Qt::CaseInsensitive);
sanitizedString = sanitizedString.remove(HIFI_SCHEME_REGEX);
lookupURL = QUrl(sanitizedString);
if (lookupURL.scheme().isEmpty() || lookupURL.scheme().toLower() == LOCALHOST) {
lookupURL = QUrl("hifi://" + sanitizedString);
}
} else {
lookupURL = QUrl(sanitizedString);
}
handleUrl(lookupURL, fromSuggestions ? Suggestions : UserInput);
handleUrl(sanitizedString, fromSuggestions ? Suggestions : UserInput);
}
}

View file

@ -52,7 +52,7 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) :
_nodeSocket.bind(QHostAddress::AnyIPv4, port);
quint16 assignedPort = _nodeSocket.localPort();
if (socketListenPort != INVALID_PORT && socketListenPort != 0 && socketListenPort != assignedPort) {
qCCritical(networking) << "NodeList is unable to assign requested port of" << socketListenPort;
qCCritical(networking) << "PAGE: NodeList is unable to assign requested port of" << socketListenPort;
}
qCDebug(networking) << "NodeList socket is listening on" << assignedPort;
@ -1155,6 +1155,7 @@ void LimitedNodeList::startSTUNPublicSocketUpdate() {
void LimitedNodeList::possiblyTimeoutSTUNAddressLookup() {
if (_stunSockAddr.getAddress().isNull()) {
// our stun address is still NULL, but we've been waiting for long enough - time to force a fail
qCCritical(networking) << "PAGE: Failed to lookup address of STUN server" << STUN_SERVER_HOSTNAME;
stopInitialSTUNUpdate(false);
}
}
@ -1170,7 +1171,7 @@ void LimitedNodeList::stopInitialSTUNUpdate(bool success) {
if (!success) {
// if we're here this was the last failed STUN request
// use our DS as our stun server
qCDebug(networking, "Failed to lookup public address via STUN server at %s:%hu.",
qCWarning(networking, "PAGE: Failed to lookup public address via STUN server at %s:%hu (likely a critical error for auto-networking).",
STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
qCDebug(networking) << "LimitedNodeList public socket will be set with local port and null QHostAddress.";
@ -1212,7 +1213,8 @@ void LimitedNodeList::updateLocalSocket() {
QTcpSocket* localIPTestSocket = new QTcpSocket;
connect(localIPTestSocket, &QTcpSocket::connected, this, &LimitedNodeList::connectedForLocalSocketTest);
connect(localIPTestSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorTestingLocalSocket()));
connect(localIPTestSocket, static_cast<void(QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error),
this, &LimitedNodeList::errorTestingLocalSocket);
// attempt to connect to our reliable host
localIPTestSocket->connectToHost(RELIABLE_LOCAL_IP_CHECK_HOST, RELIABLE_LOCAL_IP_CHECK_PORT);
@ -1242,6 +1244,8 @@ void LimitedNodeList::errorTestingLocalSocket() {
// then use our possibly updated guessed local address as fallback
if (!_hasTCPCheckedLocalSocket) {
setLocalSocket(HifiSockAddr { getGuessedLocalAddress(), _nodeSocket.localPort() });
qCCritical(networking) << "PAGE: Can't connect to Google DNS service via TCP, falling back to guessed local address"
<< getLocalSockAddr();
}
localIPTestSocket->deleteLater();
@ -1325,7 +1329,7 @@ void LimitedNodeList::putLocalPortIntoSharedMemory(const QString key, QObject* p
qCDebug(networking) << "Wrote local listening port" << localPort << "to shared memory at key" << key;
} else {
qWarning() << "Failed to create and attach to shared memory to share local port with assignment-client children.";
qWarning() << "ALERT: Failed to create and attach to shared memory to share local port with assignment-client children.";
}
}

View file

@ -29,6 +29,8 @@
#include <shared/QtHelpers.h>
#include <Gzip.h>
#include <future>
using Promise = MiniPromise::Promise;
AssetScriptingInterface::AssetScriptingInterface(QObject* parent) : BaseAssetScriptingInterface(parent) {
@ -38,6 +40,25 @@ AssetScriptingInterface::AssetScriptingInterface(QObject* parent) : BaseAssetScr
#define JS_VERIFY(cond, error) { if (!this->jsVerify(cond, error)) { return; } }
bool AssetScriptingInterface::initializeCache() {
if (!Parent::initializeCache()) {
if (assetClient()) {
std::promise<bool> cacheStatusResult;
Promise assetClientPromise(makePromise(__func__));
assetClientPromise->moveToThread(qApp->thread()); // To ensure the finally() is processed.
assetClient()->cacheInfoRequestAsync(assetClientPromise);
assetClientPromise->finally([&](QString, QVariantMap result)
{ cacheStatusResult.set_value(!result.isEmpty()); });
return cacheStatusResult.get_future().get();
} else {
return false;
}
} else {
return true;
}
}
void AssetScriptingInterface::uploadData(QString data, QScriptValue callback) {
auto handler = jsBindCallback(thisObject(), callback);
QByteArray dataByteArray = data.toUtf8();

View file

@ -356,7 +356,7 @@ public:
* @function Assets.initializeCache
* @returns {boolean} <code>true</code> if the cache is initialized, <code>false</code> if it isn't.
*/
Q_INVOKABLE bool initializeCache() { return Parent::initializeCache(); }
Q_INVOKABLE bool initializeCache();
/**jsdoc
* Checks whether the script can write to the cache.

View file

@ -70,15 +70,16 @@ glm::mat4 Mat4::inverse(const glm::mat4& m) const {
}
glm::vec3 Mat4::getForward(const glm::mat4& m) const {
return glm::vec3(-m[0][2], -m[1][2], -m[2][2]);
// -z is forward
return -glm::normalize(glm::vec3(m[2]));
}
glm::vec3 Mat4::getRight(const glm::mat4& m) const {
return glm::vec3(m[0][0], m[1][0], m[2][0]);
return glm::normalize(glm::vec3(m[0]));
}
glm::vec3 Mat4::getUp(const glm::mat4& m) const {
return glm::vec3(m[0][1], m[1][1], m[2][1]);
return glm::normalize(glm::vec3(m[1]));
}
void Mat4::print(const QString& label, const glm::mat4& m, bool transpose) const {

View file

@ -22,6 +22,10 @@
#include "RegisteredMetaTypes.h"
/**jsdoc
* The <code>Mat4</code> API provides facilities for generating and using 4 x 4 matrices. These matrices are typically used to
* represent transforms (scale, rotate, and translate) that convert one coordinate system into another, or perspective
* transforms that convert 3D points into screen coordinates.
*
* @namespace Mat4
* @variation 0
*
@ -39,130 +43,279 @@ class Mat4 : public QObject, protected QScriptable {
public slots:
/**jsdoc
* Multiplies two matrices.
* @function Mat4(0).multiply
* @param {Mat4} m1
* @param {Mat4} m2
* @returns {Mat4}
* @param {Mat4} m1 - The first matrix.
* @param {Mat4} m2 - The second matrix.
* @returns {Mat4} <code>m1</code> multiplied with <code>m2</code>.
*/
glm::mat4 multiply(const glm::mat4& m1, const glm::mat4& m2) const;
/**jsdoc
* Creates a matrix that represents a rotation and translation.
* @function Mat4(0).createFromRotAndTrans
* @param {Quat} rot
* @param {Vec3} trans
* @returns {Mat4}
* @param {Quat} rot - The rotation.
* @param {Vec3} trans - The translation.
* @returns {Mat4} The matrix that represents the rotation and translation.
* @example <caption>Create a matrix with rotation and translation.</caption>
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromRotAndTrans(rot, trans);
* Mat4.print("Matrix:", matrix);
* // Matrix: dmat4x4((0.353553, 0.612372, -0.707107, 0.000000),
* // (-0.573223, 0.739199, 0.353553, 0.000000),
* // (0.739199, 0.280330, 0.612372, 0.000000),
* // (10.000000, 11.000000, 12.000000, 1.000000))
*/
glm::mat4 createFromRotAndTrans(const glm::quat& rot, const glm::vec3& trans) const;
/**jsdoc
* Creates a matrix that represents a scale, rotation, and translation.
* @function Mat4(0).createFromScaleRotAndTrans
* @param {Vec3} scale
* @param {Quat} rot
* @param {Vec3} trans
* @returns {Mat4}
* @param {Vec3} scale - The scale.
* @param {Quat} rot - The rotation.
* @param {Vec3} trans - The translation.
* @returns {Mat4} The matrix that represents the scale, rotation, and translation.
* @example <caption>Create a matrix with scale, rotation, and translation.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
* Mat4.print("Matrix:", matrix);
* // Matrix: dmat4x4((0.707107, 1.224745, -1.414214, 0.000000),
* // (-1.146447, 1.478398, 0.707107, 0.000000),
* // (1.478398, 0.560660, 1.224745, 0.000000),
* // (10.000000, 11.000000, 12.000000, 1.000000))
*/
glm::mat4 createFromScaleRotAndTrans(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) const;
/**jsdoc
* Creates a matrix from columns of values.
* @function Mat4(0).createFromColumns
* @param {Vec4} col0
* @param {Vec4} col1
* @param {Vec4} col2
* @param {Vec4} col
* @returns {Mat4}
* @param {Vec4} col0 - Column 0 values.
* @param {Vec4} col1 - Column 1 values.
* @param {Vec4} col2 - Column 2 values.
* @param {Vec4} col3 - Column 3 valuse.
* @returns {Mat4} The matrix with the specified columns values.
* @example <caption>Create a matrix from columns.</caption>
* var col0 = { x: 0.707107, y: 1.224745, z: -1.414214, w: 0.0 };
* var col1 = { x: -1.146447, y: 1.478398, z: 0.707107, w: 0.0 };
* var col2 = { x: 1.478398, y: 0.560660, z: 1.224745, w: 0.0 };
* var col3 = { x: 10.0, y: 11.0, z: 12.0, w: 1.0 };
* var matrix = Mat4.createFromColumns(col0, col1, col2, col3);
* Mat4.print("Matrix:", matrix);
* //Matrix: dmat4x4((0.707107, 1.224745, -1.414214, 0.000000),
* // (-1.146447, 1.478398, 0.707107, 0.000000),
* // (1.478398, 0.560660, 1.224745, 0.000000),
* // (10.000000, 11.000000, 12.000000, 1.000000))
*/
glm::mat4 createFromColumns(const glm::vec4& col0, const glm::vec4& col1, const glm::vec4& col2, const glm::vec4& col3) const;
/**jsdoc
* Creates a matrix from an array of values.
* @function Mat4(0).createFromArray
* @param {number[]} numbers
* @returns {Mat4}
* @param {number[]} arr - The array of values, starting with column 0.
* @returns {Mat4} The matrix with the specified values.
* @example <caption>Create a matrix from an array.</caption>
* var arr = [
* 0.707107, 1.224745, -1.414214, 0.0,
* -1.146447, 1.478398, 0.707107, 0.0,
* 1.478398, 0.560660, 1.224745, 0.0,
* 10.0, 11.0, 12.0, 1.00
* ];
* var matrix = Mat4.createFromArray(arr);
* Mat4.print("Matrix:", matrix);
* //Matrix: dmat4x4((0.707107, 1.224745, -1.414214, 0.000000),
* // (-1.146447, 1.478398, 0.707107, 0.000000),
* // (1.478398, 0.560660, 1.224745, 0.000000),
* // (10.000000, 11.000000, 12.000000, 1.000000))
*/
glm::mat4 createFromArray(const QVector<float>& floats) const;
/**jsdoc
* Extracts the translation from a matrix.
* @function Mat4(0).extractTranslation
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The translation contained in the matrix.
* @example <caption>Extract the translation from a matrix.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* trans = Mat4.extractTranslation(matrix);
* print("Translation: " + JSON.stringify(trans));
* // Translation: {"x":10,"y":11,"z":12}
*/
glm::vec3 extractTranslation(const glm::mat4& m) const;
/**jsdoc
* Extracts the rotation from a matrix.
* @function Mat4(0).extractRotation
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Quat} The rotation contained in the matrix.
* @example <caption>Extract the rotation from a matrix.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* rot = Mat4.extractRotation(matrix);
* print("Rotation: " + JSON.stringify(Quat.safeEulerAngles(rot)));
* // Rotation: {"x":29.999998092651367,"y":45.00000762939453,"z":60.000003814697266}
*/
glm::quat extractRotation(const glm::mat4& m) const;
/**jsdoc
* Extracts the scale from a matrix.
* @function Mat4(0).extractScale
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The scale contained in the matrix.
* @example <caption>Extract the scale from a matrix.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* scale = Mat4.extractScale(matrix);
* print("Scale: " + JSON.stringify(scale));
* // Scale: {"x":1.9999998807907104,"y":1.9999998807907104,"z":1.9999998807907104}
*/
glm::vec3 extractScale(const glm::mat4& m) const;
/**jsdoc
* Transforms a point into a new coordinate system: the point value is scaled, rotated, and translated.
* @function Mat4(0).transformPoint
* @param {Mat4} m
* @param {Vec3} point
* @returns {Vec3}
* @param {Mat4} m - The transform to the new coordinate system.
* @param {Vec3} point - The point to transform.
* @returns {Vec3} The point in the new coordinate system.
* @example <caption>Transform a point.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(0, 45, 0);
* var trans = { x: 0, y: 10, z: 0 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* var point = { x: 1, y: 1, z: 1 };
* var transformedPoint = Mat4.transformPoint(matrix, point);
* print("Transformed point: " + JSON.stringify(transformedPoint));
* // Transformed point: { "x": 2.8284270763397217, "y": 12, "z": -2.384185791015625e-7 }
*/
glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& point) const;
/**jsdoc
* Transforms a vector into a new coordinate system: the vector is scaled and rotated.
* @function Mat4(0).transformVector
* @param {Mat4} m
* @param {Vec3} vector
* @returns {Vec3}
* @param {Mat4} m - The transform to the new coordinate system.
* @param {Vec3} vector - The vector to transform.
* @returns {Vec3} The vector in the new coordinate system.
* @example <caption>Transform a vector.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(0, 45, 0);
* var trans = { x: 0, y: 10, z: 0 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* var vector = { x: 1, y: 1, z: 1 };
* var transformedVector = Mat4.transformVector(matrix, vector);
* print("Transformed vector: " + JSON.stringify(transformedVector));
* // Transformed vector: { "x": 2.8284270763397217, "y": 2, "z": -2.384185791015625e-7 }
*/
glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& vector) const;
/**jsdoc
* Calculates the inverse of a matrix.
* @function Mat4(0).inverse
* @param {Mat4} m
* @returns {Mat4}
* @param {Mat4} m - The matrix.
* @returns {Mat4} The inverse of the matrix.
* @example <caption>A matrix multiplied with its inverse is the unit matrix.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
* var inverse = Mat4.inverse(matrix);
* var multiplied = Mat4.multiply(matrix, inverse);
* Mat4.print("Multiplied:", multiplied);
* //Multiplied: dmat4x4((1.000000, 0.000000, 0.000000, 0.000000),
* // (0.000000, 1.000000, -0.000000, 0.000000),
* // (0.000000, 0.000000, 1.000000, 0.000000),
* // (0.000000, 0.000000, 0.000001, 1.000000))
*/
glm::mat4 inverse(const glm::mat4& m) const;
/**jsdoc
* Gets the "forward" direction that the camera would face if its orientation was set to the rotation contained in a
* matrix. The High Fidelity camera has axes x = right, y = up, -z = forward.
* <p>Synonym for {@link Mat4(0).getForward|getForward}.</p>
* @function Mat4(0).getFront
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The negative z-axis rotated by orientation.
*/
// redundant, calls getForward which better describes the returned vector as a direction
glm::vec3 getFront(const glm::mat4& m) const { return getForward(m); }
/**jsdoc
* Gets the "forward" direction that the camera would face if its orientation was set to the rotation contained in a
* matrix. The High Fidelity camera has axes x = right, y = up, -z = forward.
* @function Mat4(0).getForward
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The negative z-axis rotated by the rotation in the matrix.
* @example <caption>Demonstrate that the "forward" direction is the negative z-axis.</caption>
* var rot = Quat.IDENTITY;
* var trans = Vec3.ZERO;
* var matrix = Mat4.createFromRotAndTrans(rot, trans);
* var forward = Mat4.getForward(matrix);
* print("Forward: " + JSON.stringify(forward));
* // Forward: {"x":0,"y":0,"z":-1}
*/
glm::vec3 getForward(const glm::mat4& m) const;
/**jsdoc
* Gets the "right" direction that the camera would have if its orientation was set to the rotation contained in a matrix.
* The High Fidelity camera has axes x = right, y = up, -z = forward.
* @function Mat4(0).getRight
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The x-axis rotated by the rotation in the matrix.
*/
glm::vec3 getRight(const glm::mat4& m) const;
/**jsdoc
* Gets the "up" direction that the camera would have if its orientation was set to the rotation contained in a matrix. The
* High Fidelity camera has axes x = right, y = up, -z = forward.
* @function Mat4(0).getUp
* @param {Mat4} m
* @returns {Vec3}
* @param {Mat4} m - The matrix.
* @returns {Vec3} The y-axis rotated by the rotation in the matrix.
*/
glm::vec3 getUp(const glm::mat4& m) const;
/**jsdoc
* Prints a matrix to the program log as a label followed by the matrix's values.
* @function Mat4(0).print
* @param {string} label
* @param {Mat4} m
* @param {boolean} [transpose=false]
* @param {string} label - The label to print.
* @param {Mat4} m - The matrix to print.
* @param {boolean} [transpose=false] - <code>true</code> to transpose the matrix before printing (so that it prints the
* matrix's rows), <code>false</code> to not transpose the matrix (so that it prints the matrix's columns).
* @example <caption>Two ways of printing a label and matrix value.</caption>
* var scale = Vec3.multiply(2, Vec3.ONE);
* var rot = Quat.fromPitchYawRollDegrees(30, 45, 60);
* var trans = { x: 10, y: 11, z: 12 };
* var matrix = Mat4.createFromScaleRotAndTrans(scale, rot, trans);
*
* Mat4.print("Matrix:", matrix);
* // Matrix: dmat4x4((0.707107, 1.224745, -1.414214, 0.000000),
* // (-1.146447, 1.478398, 0.707107, 0.000000),
* // (1.478398, 0.560660, 1.224745, 0.000000),
* // (10.000000, 11.000000, 12.000000, 1.000000))
*
* print("Matrix: " + JSON.stringify(matrix));
* // Matrix: {"r0c0":0.7071067094802856,"r1c0":1.2247446775436401,"r2c0":-1.4142136573791504,"r3c0":0,
* // "r0c1": -1.1464465856552124, "r1c1": 1.4783978462219238, "r2c1": 0.7071066498756409, "r3c1": 0,
* // "r0c2": 1.4783978462219238, "r1c2": 0.5606603026390076, "r2c2": 1.2247447967529297, "r3c2": 0,
* // "r0c3": 10, "r1c3": 11, "r2c3": 12, "r3c3": 1}
*/
void print(const QString& label, const glm::mat4& m, bool transpose = false) const;
};

View file

@ -9,14 +9,25 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var IDENTITY = {r0c0: 1, r0c1: 0, r0c2: 0, r0c3: 0,
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 0,
r2c0: 0, r2c1: 0, r2c2: 1, r2c3: 0,
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1};
var X = {x: 1, y: 0, z: 0};
var Y = {x: 0, y: 1, z: 0};
var Z = {x: 0, y: 0, z: 1};
var IDENTITY = {
r0c0: 1, r0c1: 0, r0c2: 0, r0c3: 0,
r1c0: 0, r1c1: 1, r1c2: 0, r1c3: 0,
r2c0: 0, r2c1: 0, r2c2: 1, r2c3: 0,
r3c0: 0, r3c1: 0, r3c2: 0, r3c3: 1
};
var ROT_ZERO = {x: 0, y: 0, z: 0, w: 1};
var ROT_Y_180 = {x: 0, y: 1, z: 0, w: 0};
var DEG_45 = Math.PI / 4;
var ROT_X_45 = Quat.angleAxis(DEG_45, X);
var ROT_Y_45 = Quat.angleAxis(DEG_45, Y);
var ROT_Z_45 = Quat.angleAxis(DEG_45, Z);
var ONE = {x: 1, y: 1, z: 1};
var ZERO = {x: 0, y: 0, z: 0};
var ONE_TWO_THREE = {x: 1, y: 2, z: 3};
@ -24,6 +35,7 @@ var ONE_HALF = {x: 0.5, y: 0.5, z: 0.5};
var EPSILON = 0.000001;
function mat4FuzzyEqual(a, b) {
var r, c;
for (r = 0; r < 4; r++) {
@ -141,12 +153,45 @@ function testInverse() {
assert(mat4FuzzyEqual(IDENTITY, Mat4.multiply(test2, Mat4.inverse(test2))));
}
function testForward() {
var test0 = IDENTITY;
assert(mat4FuzzyEqual({x: 0, y: 0, z: -1}, Mat4.getForward(test0)));
function columnsFromQuat(q) {
var axes = [Vec3.multiplyQbyV(q, X), Vec3.multiplyQbyV(q, Y), Vec3.multiplyQbyV(q, Z)];
axes[0].w = 0;
axes[1].w = 0;
axes[2].w = 0;
axes[3] = {x: 0, y: 0, z: 0, w: 1};
return axes;
}
var test1 = Mat4.createFromScaleRotAndTrans(ONE_HALF, ROT_Y_180, ONE_TWO_THREE);
assert(mat4FuzzyEqual({x: 0, y: 0, z: 1}, Mat4.getForward(test1)));
function matrixFromColumns(cols) {
return Mat4.createFromColumns(cols[0], cols[1], cols[2], cols[3]);
}
function testMatForwardRightUpFromQuat(q) {
var cols = columnsFromQuat(q);
var mat = matrixFromColumns(cols);
assert(vec3FuzzyEqual(Mat4.getForward(mat), Vec3.multiply(cols[2], -1)));
assert(vec3FuzzyEqual(Mat4.getForward(mat), Quat.getForward(q)));
assert(vec3FuzzyEqual(Mat4.getRight(mat), cols[0]));
assert(vec3FuzzyEqual(Mat4.getRight(mat), Quat.getRight(q)));
assert(vec3FuzzyEqual(Mat4.getUp(mat), cols[1]));
assert(vec3FuzzyEqual(Mat4.getUp(mat), Quat.getUp(q)));
}
function testForwardRightUp() {
// test several variations of rotations
testMatForwardRightUpFromQuat(ROT_X_45);
testMatForwardRightUpFromQuat(ROT_Y_45);
testMatForwardRightUpFromQuat(ROT_Z_45);
testMatForwardRightUpFromQuat(Quat.multiply(ROT_X_45, ROT_Y_45));
testMatForwardRightUpFromQuat(Quat.multiply(ROT_Y_45, ROT_X_45));
testMatForwardRightUpFromQuat(Quat.multiply(ROT_X_45, ROT_Z_45));
testMatForwardRightUpFromQuat(Quat.multiply(ROT_Z_45, ROT_X_45));
testMatForwardRightUpFromQuat(Quat.multiply(ROT_X_45, ROT_Z_45));
testMatForwardRightUpFromQuat(Quat.multiply(ROT_Z_45, ROT_X_45));
}
function testMat4() {
@ -157,7 +202,7 @@ function testMat4() {
testTransformPoint();
testTransformVector();
testInverse();
testForward();
testForwardRightUp();
print("MAT4 TEST complete! (" + (testCount - failureCount) + "/" + testCount + ") tests passed!");
}

View file

@ -296,7 +296,7 @@ function updateOutputDeviceMutedOverlay(isMuted) {
props.y = Window.innerHeight / 2 - overlayDims / 2;
var outputDeviceMutedOverlayBottomY = props.y + overlayDims;
var inputDeviceMutedOverlayTopY = getInputDeviceMutedOverlayTopY();
var inputDeviceMutedOverlayTopY = INPUT_DEVICE_MUTED_MARGIN_TOP_PX;
if (outputDeviceMutedOverlayBottomY + OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX > inputDeviceMutedOverlayTopY) {
overlayDims = 2 * (inputDeviceMutedOverlayTopY - Window.innerHeight / 2 - OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX);
}
@ -473,15 +473,11 @@ function maybeDeleteInputDeviceMutedOverlay() {
}
function getInputDeviceMutedOverlayTopY() {
return (Window.innerHeight - INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX - INPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX);
}
var inputDeviceMutedOverlay = false;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX = 353;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX = 95;
var INPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX = 20 + TOP_BAR_HEIGHT_PX;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX = 237;
var INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX = 64;
var INPUT_DEVICE_MUTED_MARGIN_LEFT_PX = 20;
var INPUT_DEVICE_MUTED_MARGIN_TOP_PX = 20;
function updateInputDeviceMutedOverlay(isMuted) {
if (isMuted) {
var props = {
@ -490,8 +486,8 @@ function updateInputDeviceMutedOverlay(isMuted) {
};
props.width = INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX;
props.height = INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_Y_PX;
props.x = Window.innerWidth / 2 - INPUT_DEVICE_MUTED_OVERLAY_DEFAULT_X_PX / 2;
props.y = getInputDeviceMutedOverlayTopY();
props.x = INPUT_DEVICE_MUTED_MARGIN_LEFT_PX;
props.y = INPUT_DEVICE_MUTED_MARGIN_TOP_PX;
if (inputDeviceMutedOverlay) {
Overlays.editOverlay(inputDeviceMutedOverlay, props);
} else {