diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp
index d763d1abe7..48ffc2fdbc 100644
--- a/assignment-client/src/octree/OctreeServer.cpp
+++ b/assignment-client/src/octree/OctreeServer.cpp
@@ -1063,6 +1063,12 @@ void OctreeServer::readConfiguration() {
_wantBackup = !noBackup;
qDebug() << "wantBackup=" << _wantBackup;
+ if (!readOptionString("backupDirectoryPath", settingsSectionObject, _backupDirectoryPath)) {
+ _backupDirectoryPath = "";
+ }
+
+ qDebug() << "backupDirectoryPath=" << _backupDirectoryPath;
+
readOptionBool(QString("persistFileDownload"), settingsSectionObject, _persistFileDownload);
qDebug() << "persistFileDownload=" << _persistFileDownload;
@@ -1160,25 +1166,25 @@ void OctreeServer::domainSettingsRequestComplete() {
// If persist filename does not exist, let's see if there is one beside the application binary
// If there is, let's copy it over to our target persist directory
QDir persistPath { _persistFilePath };
- QString absoluteFilePath = persistPath.absolutePath();
+ QString persistAbsoluteFilePath = persistPath.absolutePath();
if (persistPath.isRelative()) {
// if the domain settings passed us a relative path, make an absolute path that is relative to the
// default data directory
- absoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath);
+ persistAbsoluteFilePath = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_persistFilePath);
}
static const QString ENTITY_PERSIST_EXTENSION = ".json.gz";
// force the persist file to end with .json.gz
- if (!absoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
- absoluteFilePath += ENTITY_PERSIST_EXTENSION;
+ if (!persistAbsoluteFilePath.endsWith(ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive)) {
+ persistAbsoluteFilePath += ENTITY_PERSIST_EXTENSION;
} else {
// make sure the casing of .json.gz is correct
- absoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive);
+ persistAbsoluteFilePath.replace(ENTITY_PERSIST_EXTENSION, ENTITY_PERSIST_EXTENSION, Qt::CaseInsensitive);
}
- if (!QFile::exists(absoluteFilePath)) {
+ if (!QFile::exists(persistAbsoluteFilePath)) {
qDebug() << "Persist file does not exist, checking for existence of persist file next to application";
static const QString OLD_DEFAULT_PERSIST_FILENAME = "resources/models.json.gz";
@@ -1204,7 +1210,7 @@ void OctreeServer::domainSettingsRequestComplete() {
pathToCopyFrom = oldDefaultPersistPath;
}
- QDir persistFileDirectory { QDir::cleanPath(absoluteFilePath + "/..") };
+ QDir persistFileDirectory { QDir::cleanPath(persistAbsoluteFilePath + "/..") };
if (!persistFileDirectory.exists()) {
qDebug() << "Creating data directory " << persistFileDirectory.absolutePath();
@@ -1212,16 +1218,46 @@ void OctreeServer::domainSettingsRequestComplete() {
}
if (shouldCopy) {
- qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << absoluteFilePath;
+ qDebug() << "Old persist file found, copying from " << pathToCopyFrom << " to " << persistAbsoluteFilePath;
- QFile::copy(pathToCopyFrom, absoluteFilePath);
+ QFile::copy(pathToCopyFrom, persistAbsoluteFilePath);
} else {
qDebug() << "No existing persist file found";
}
}
+
+ auto persistFileDirectory = QFileInfo(persistAbsoluteFilePath).absolutePath();
+ if (_backupDirectoryPath.isEmpty()) {
+ // Use the persist file's directory to store backups
+ _backupDirectoryPath = persistFileDirectory;
+ } else {
+ // The backup directory has been set.
+ // If relative, make it relative to the entities directory in the application data directory
+ // If absolute, no resolution is necessary
+ QDir backupDirectory { _backupDirectoryPath };
+ QString absoluteBackupDirectory;
+ if (backupDirectory.isRelative()) {
+ absoluteBackupDirectory = QDir(ServerPathUtils::getDataFilePath("entities/")).absoluteFilePath(_backupDirectoryPath);
+ absoluteBackupDirectory = QDir(absoluteBackupDirectory).absolutePath();
+ } else {
+ absoluteBackupDirectory = backupDirectory.absolutePath();
+ }
+ backupDirectory = QDir(absoluteBackupDirectory);
+ if (!backupDirectory.exists()) {
+ if (backupDirectory.mkpath(".")) {
+ qDebug() << "Created backup directory";
+ } else {
+ qDebug() << "ERROR creating backup directory, using persist file directory";
+ _backupDirectoryPath = persistFileDirectory;
+ }
+ } else {
+ _backupDirectoryPath = absoluteBackupDirectory;
+ }
+ }
+ qDebug() << "Backups will be stored in: " << _backupDirectoryPath;
// now set up PersistThread
- _persistThread = new OctreePersistThread(_tree, absoluteFilePath, _persistInterval,
+ _persistThread = new OctreePersistThread(_tree, persistAbsoluteFilePath, _backupDirectoryPath, _persistInterval,
_wantBackup, _settings, _debugTimestampNow, _persistAsFileType);
_persistThread->initialize(true);
}
diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h
index d153f31154..35436997a6 100644
--- a/assignment-client/src/octree/OctreeServer.h
+++ b/assignment-client/src/octree/OctreeServer.h
@@ -172,6 +172,7 @@ protected:
QString _persistFilePath;
QString _persistAsFileType;
+ QString _backupDirectoryPath;
int _packetsPerClientPerInterval;
int _packetsTotalPerInterval;
OctreePointer _tree; // this IS a reaveraging tree
diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index c888fa301b..c9d7ea77d5 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -1108,6 +1108,14 @@
"default": "models.json.gz",
"advanced": true
},
+ {
+ "name": "backupDirectoryPath",
+ "label": "Entities Backup Directory Path",
+ "help": "The path to the directory to store backups in. If this path is relative it will be relative to the application data directory.",
+ "placeholder": "",
+ "default": "",
+ "advanced": true
+ },
{
"name": "persistInterval",
"label": "Save Check Interval",
diff --git a/interface/resources/controllers/oculus_touch.json b/interface/resources/controllers/oculus_touch.json
index ef5d8c59a8..c50f7681d9 100644
--- a/interface/resources/controllers/oculus_touch.json
+++ b/interface/resources/controllers/oculus_touch.json
@@ -22,7 +22,11 @@
},
{ "from": "OculusTouch.LT", "to": "Standard.LT" },
{ "from": "OculusTouch.LS", "to": "Standard.LS" },
- { "from": "OculusTouch.LeftGrip", "to": "Standard.LeftGrip" },
+ { "from": "OculusTouch.LeftGrip", "to": "Standard.LTClick",
+ "peek": true,
+ "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
+ },
+ { "from": "OculusTouch.LeftGrip", "to": "Standard.LT" },
{ "from": "OculusTouch.LeftHand", "to": "Standard.LeftHand" },
{ "from": "OculusTouch.RY", "to": "Standard.RY",
@@ -38,7 +42,11 @@
},
{ "from": "OculusTouch.RT", "to": "Standard.RT" },
{ "from": "OculusTouch.RS", "to": "Standard.RS" },
- { "from": "OculusTouch.RightGrip", "to": "Standard.RightGrip" },
+ { "from": "OculusTouch.RightGrip", "to": "Standard.LTClick",
+ "peek": true,
+ "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
+ },
+ { "from": "OculusTouch.RightGrip", "to": "Standard.RT" },
{ "from": "OculusTouch.RightHand", "to": "Standard.RightHand" },
{ "from": "OculusTouch.LeftApplicationMenu", "to": "Standard.Back" },
@@ -59,4 +67,3 @@
]
}
-
diff --git a/interface/resources/qml/LoginDialog/SignInBody.qml b/interface/resources/qml/LoginDialog/SignInBody.qml
index 2da0ea856d..7bbba683c3 100644
--- a/interface/resources/qml/LoginDialog/SignInBody.qml
+++ b/interface/resources/qml/LoginDialog/SignInBody.qml
@@ -48,7 +48,7 @@ Item {
}
}
- MenuItem {
+ InfoItem {
id: mainTextContainer
anchors {
top: parent.top
diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
index 7e22b11f8b..b949c660d6 100644
--- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
+++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml
@@ -78,7 +78,7 @@ Item {
placeholderText: "Choose your own"
}
- MenuItem {
+ InfoItem {
id: termsContainer
anchors {
top: textField.bottom
diff --git a/interface/resources/qml/LoginDialog/WelcomeBody.qml b/interface/resources/qml/LoginDialog/WelcomeBody.qml
index ecc848cdc0..5fed9addf8 100644
--- a/interface/resources/qml/LoginDialog/WelcomeBody.qml
+++ b/interface/resources/qml/LoginDialog/WelcomeBody.qml
@@ -44,7 +44,7 @@ Item {
}
}
- MenuItem {
+ InfoItem {
id: mainTextContainer
anchors {
top: parent.top
diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml
index fe88899658..180e5e1bcc 100644
--- a/interface/resources/qml/Stats.qml
+++ b/interface/resources/qml/Stats.qml
@@ -99,6 +99,12 @@ Item {
font.pixelSize: root.fontSize
text: "Mbps In/Out: " + root.mbpsIn.toFixed(2) + "/" + root.mbpsOut.toFixed(2)
}
+ Text {
+ color: root.fontColor;
+ font.pixelSize: root.fontSize
+ visible: root.expanded
+ text: "Asset Mbps In/Out: " + root.assetMbpsIn.toFixed(2) + "/" + root.assetMbpsOut.toFixed(2)
+ }
}
}
diff --git a/interface/resources/qml/styles-uit/MenuItem.qml b/interface/resources/qml/styles-uit/InfoItem.qml
similarity index 95%
rename from interface/resources/qml/styles-uit/MenuItem.qml
rename to interface/resources/qml/styles-uit/InfoItem.qml
index 4431c357bf..83781a4ef5 100644
--- a/interface/resources/qml/styles-uit/MenuItem.qml
+++ b/interface/resources/qml/styles-uit/InfoItem.qml
@@ -1,5 +1,5 @@
//
-// MenuItem.qml
+// InfoItem.qml
//
// Created by Clement on 7/18/16
// Copyright 2016 High Fidelity, Inc.
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 59ec1c0641..d1b9b952d4 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -838,7 +838,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
QSharedPointer bandwidthRecorder = DependencyManager::get();
connect(nodeList.data(), &LimitedNodeList::dataSent,
bandwidthRecorder.data(), &BandwidthRecorder::updateOutboundData);
- connect(&nodeList->getPacketReceiver(), &PacketReceiver::dataReceived,
+ connect(nodeList.data(), &LimitedNodeList::dataReceived,
bandwidthRecorder.data(), &BandwidthRecorder::updateInboundData);
// FIXME -- I'm a little concerned about this.
@@ -1138,10 +1138,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
static int SEND_STATS_INTERVAL_MS = 10000;
static int NEARBY_AVATAR_RADIUS_METERS = 10;
+ static glm::vec3 lastAvatarPosition = getMyAvatar()->getPosition();
+ static glm::mat4 lastHMDHeadPose = getHMDSensorPose();
+ static controller::Pose lastLeftHandPose = getMyAvatar()->getLeftHandPose();
+ static controller::Pose lastRightHandPose = getMyAvatar()->getRightHandPose();
+
// Periodically send fps as a user activity event
QTimer* sendStatsTimer = new QTimer(this);
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
+
QJsonObject properties = {};
MemoryInfo memInfo;
if (getMemoryInfo(memInfo)) {
@@ -1183,6 +1189,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
+ glm::vec3 avatarPosition = getMyAvatar()->getPosition();
+ properties["avatar_has_moved"] = lastAvatarPosition != avatarPosition;
+ lastAvatarPosition = avatarPosition;
+
+ auto entityScriptingInterface = DependencyManager::get();
+ auto entityActivityTracking = entityScriptingInterface->getActivityTracking();
+ entityScriptingInterface->resetActivityTracking();
+ properties["added_entity_cnt"] = entityActivityTracking.addedEntityCount;
+ properties["deleted_entity_cnt"] = entityActivityTracking.deletedEntityCount;
+ properties["edited_entity_cnt"] = entityActivityTracking.editedEntityCount;
+
+ auto hmdHeadPose = getHMDSensorPose();
+ properties["hmd_head_pose_changed"] = isHMDMode() && (hmdHeadPose != lastHMDHeadPose);
+ lastHMDHeadPose = hmdHeadPose;
+
+ auto leftHandPose = getMyAvatar()->getLeftHandPose();
+ auto rightHandPose = getMyAvatar()->getRightHandPose();
+ // controller::Pose considers two poses to be different if either are invalid. In our case, we actually
+ // want to consider the pose to be unchanged if it was invalid and still is invalid, so we check that first.
+ properties["hand_pose_changed"] =
+ ((leftHandPose.valid || lastLeftHandPose.valid) && (leftHandPose != lastLeftHandPose))
+ || ((rightHandPose.valid || lastRightHandPose.valid) && (rightHandPose != lastRightHandPose));
+ lastLeftHandPose = leftHandPose;
+ lastRightHandPose = rightHandPose;
+
UserActivityLogger::getInstance().logAction("stats", properties);
});
sendStatsTimer->start();
@@ -1237,6 +1268,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_defaultSkybox->setCubemap(_defaultSkyboxTexture);
_defaultSkybox->setColor({ 1.0, 1.0, 1.0 });
+ EntityItem::setEntitiesShouldFadeFunction([this]() {
+ SharedNodePointer entityServerNode = DependencyManager::get()->soloNodeOfType(NodeType::EntityServer);
+ return entityServerNode && !isPhysicsEnabled();
+ });
+
// After all of the constructor is completed, then set firstRun to false.
Setting::Handle firstRun{ Settings::firstRun, true };
firstRun.set(false);
@@ -4253,6 +4289,21 @@ namespace render {
auto backgroundMode = skyStage->getBackgroundMode();
switch (backgroundMode) {
+ case model::SunSkyStage::SKY_DEFAULT: {
+ static const glm::vec3 DEFAULT_SKYBOX_COLOR{ 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f };
+ static const float DEFAULT_SKYBOX_INTENSITY{ 0.2f };
+ static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY{ 2.0f };
+ static const glm::vec3 DEFAULT_SKYBOX_DIRECTION{ 0.0f, 0.0f, -1.0f };
+
+ auto scene = DependencyManager::get()->getStage();
+ auto sceneKeyLight = scene->getKeyLight();
+ scene->setSunModelEnable(false);
+ sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR);
+ sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
+ sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
+ sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
+ // fall through: render a skybox, if available
+ }
case model::SunSkyStage::SKY_BOX: {
auto skybox = skyStage->getSkybox();
if (skybox) {
@@ -4260,33 +4311,22 @@ namespace render {
skybox->render(batch, args->getViewFrustum());
break;
}
+ // fall through: render defaults, if available
}
-
- // Fall through: if no skybox is available, render the SKY_DOME
- case model::SunSkyStage::SKY_DOME: {
- if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
- static const glm::vec3 DEFAULT_SKYBOX_COLOR { 255.0f / 255.0f, 220.0f / 255.0f, 194.0f / 255.0f };
- static const float DEFAULT_SKYBOX_INTENSITY { 0.2f };
- static const float DEFAULT_SKYBOX_AMBIENT_INTENSITY { 2.0f };
- static const glm::vec3 DEFAULT_SKYBOX_DIRECTION { 0.0f, 0.0f, -1.0f };
-
- auto scene = DependencyManager::get()->getStage();
- auto sceneKeyLight = scene->getKeyLight();
- scene->setSunModelEnable(false);
- sceneKeyLight->setColor(DEFAULT_SKYBOX_COLOR);
- sceneKeyLight->setIntensity(DEFAULT_SKYBOX_INTENSITY);
- sceneKeyLight->setAmbientIntensity(DEFAULT_SKYBOX_AMBIENT_INTENSITY);
- sceneKeyLight->setDirection(DEFAULT_SKYBOX_DIRECTION);
-
- auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
- sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance());
- sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
-
- qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
- }
+ case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: {
+ if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
+ auto scene = DependencyManager::get()->getStage();
+ auto sceneKeyLight = scene->getKeyLight();
+ auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture();
+ // do not set the ambient sphere - it peaks too high, and causes flashing when turning
+ sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture);
+ }
+ // fall through: render defaults, if available
}
- break;
-
+ case model::SunSkyStage::SKY_DEFAULT_TEXTURE:
+ if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) {
+ qApp->getDefaultSkybox()->render(batch, args->getViewFrustum());
+ }
case model::SunSkyStage::NO_BACKGROUND:
default:
// this line intentionally left blank
@@ -4503,7 +4543,7 @@ void Application::clearDomainOctreeDetails() {
auto skyStage = DependencyManager::get()->getSkyStage();
- skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
+ skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
_recentlyClearedDomain = true;
}
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 57e379a9ac..782ecbcc64 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -516,13 +516,23 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
return _sensorToWorldMatrixCache.get();
}
+// As far as I know no HMD system supports a play area of a kilometer in radius.
+static const float MAX_HMD_ORIGIN_DISTANCE = 1000.0f;
// Pass a recent sample of the HMD to the avatar.
// This can also update the avatar's position to follow the HMD
// as it moves through the world.
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
// update the sensorMatrices based on the new hmd pose
_hmdSensorMatrix = hmdSensorMatrix;
- _hmdSensorPosition = extractTranslation(hmdSensorMatrix);
+ auto newHmdSensorPosition = extractTranslation(hmdSensorMatrix);
+
+ if (newHmdSensorPosition != _hmdSensorPosition &&
+ glm::length(newHmdSensorPosition) > MAX_HMD_ORIGIN_DISTANCE) {
+ qWarning() << "Invalid HMD sensor position " << newHmdSensorPosition;
+ // Ignore unreasonable HMD sensor data
+ return;
+ }
+ _hmdSensorPosition = newHmdSensorPosition;
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
_hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);
}
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index ec4b2280b6..7fdf5cd57d 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -136,6 +136,9 @@ void Stats::updateStats(bool force) {
STAT_UPDATE_FLOAT(mbpsIn, (float)bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond() / 1000.0f, 0.01f);
STAT_UPDATE_FLOAT(mbpsOut, (float)bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond() / 1000.0f, 0.01f);
+ STAT_UPDATE_FLOAT(assetMbpsIn, (float)bandwidthRecorder->getAverageInputKilobitsPerSecond(NodeType::AssetServer) / 1000.0f, 0.01f);
+ STAT_UPDATE_FLOAT(assetMbpsOut, (float)bandwidthRecorder->getAverageOutputKilobitsPerSecond(NodeType::AssetServer) / 1000.0f, 0.01f);
+
// Second column: ping
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index f6643a1a7a..4be2d88d9e 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -43,6 +43,8 @@ class Stats : public QQuickItem {
STATS_PROPERTY(int, packetOutCount, 0)
STATS_PROPERTY(float, mbpsIn, 0)
STATS_PROPERTY(float, mbpsOut, 0)
+ STATS_PROPERTY(float, assetMbpsIn, 0)
+ STATS_PROPERTY(float, assetMbpsOut, 0)
STATS_PROPERTY(int, audioPing, 0)
STATS_PROPERTY(int, avatarPing, 0)
STATS_PROPERTY(int, entitiesPing, 0)
@@ -128,6 +130,8 @@ signals:
void packetOutCountChanged();
void mbpsInChanged();
void mbpsOutChanged();
+ void assetMbpsInChanged();
+ void assetMbpsOutChanged();
void audioPingChanged();
void avatarPingChanged();
void entitiesPingChanged();
diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp
index 6b46b5b884..c3a6c5920e 100644
--- a/interface/src/ui/overlays/Line3DOverlay.cpp
+++ b/interface/src/ui/overlays/Line3DOverlay.cpp
@@ -23,6 +23,7 @@ Line3DOverlay::Line3DOverlay() :
Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
Base3DOverlay(line3DOverlay),
+ _start(line3DOverlay->_start),
_end(line3DOverlay->_end),
_geometryCacheID(DependencyManager::get()->allocateID())
{
@@ -31,6 +32,40 @@ Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
Line3DOverlay::~Line3DOverlay() {
}
+glm::vec3 Line3DOverlay::getStart() const {
+ bool success;
+ glm::vec3 worldStart = localToWorld(_start, _parentID, _parentJointIndex, success);
+ if (!success) {
+ qDebug() << "Line3DOverlay::getStart failed";
+ }
+ return worldStart;
+}
+
+glm::vec3 Line3DOverlay::getEnd() const {
+ bool success;
+ glm::vec3 worldEnd = localToWorld(_end, _parentID, _parentJointIndex, success);
+ if (!success) {
+ qDebug() << "Line3DOverlay::getEnd failed";
+ }
+ return worldEnd;
+}
+
+void Line3DOverlay::setStart(const glm::vec3& start) {
+ bool success;
+ _start = worldToLocal(start, _parentID, _parentJointIndex, success);
+ if (!success) {
+ qDebug() << "Line3DOverlay::setStart failed";
+ }
+}
+
+void Line3DOverlay::setEnd(const glm::vec3& end) {
+ bool success;
+ _end = worldToLocal(end, _parentID, _parentJointIndex, success);
+ if (!success) {
+ qDebug() << "Line3DOverlay::setEnd failed";
+ }
+}
+
AABox Line3DOverlay::getBounds() const {
auto extents = Extents{};
extents.addPoint(_start);
@@ -76,8 +111,8 @@ const render::ShapeKey Line3DOverlay::getShapeKey() {
return builder.build();
}
-void Line3DOverlay::setProperties(const QVariantMap& properties) {
- Base3DOverlay::setProperties(properties);
+void Line3DOverlay::setProperties(const QVariantMap& originalProperties) {
+ QVariantMap properties = originalProperties;
auto start = properties["start"];
// if "start" property was not there, check to see if they included aliases: startPoint
@@ -87,6 +122,7 @@ void Line3DOverlay::setProperties(const QVariantMap& properties) {
if (start.isValid()) {
setStart(vec3FromVariant(start));
}
+ properties.remove("start"); // so that Base3DOverlay doesn't respond to it
auto end = properties["end"];
// if "end" property was not there, check to see if they included aliases: endPoint
@@ -109,14 +145,16 @@ void Line3DOverlay::setProperties(const QVariantMap& properties) {
if (glowWidth.isValid()) {
setGlow(glowWidth.toFloat());
}
+
+ Base3DOverlay::setProperties(properties);
}
QVariant Line3DOverlay::getProperty(const QString& property) {
if (property == "start" || property == "startPoint" || property == "p1") {
- return vec3toVariant(_start);
+ return vec3toVariant(getStart());
}
if (property == "end" || property == "endPoint" || property == "p2") {
- return vec3toVariant(_end);
+ return vec3toVariant(getEnd());
}
return Base3DOverlay::getProperty(property);
@@ -125,3 +163,8 @@ QVariant Line3DOverlay::getProperty(const QString& property) {
Line3DOverlay* Line3DOverlay::createClone() const {
return new Line3DOverlay(this);
}
+
+
+void Line3DOverlay::locationChanged(bool tellPhysics) {
+ // do nothing
+}
diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h
index d066677c70..b4e2ba8168 100644
--- a/interface/src/ui/overlays/Line3DOverlay.h
+++ b/interface/src/ui/overlays/Line3DOverlay.h
@@ -28,14 +28,15 @@ public:
virtual AABox getBounds() const override;
// getters
- const glm::vec3& getStart() const { return _start; }
- const glm::vec3& getEnd() const { return _end; }
+ glm::vec3 getStart() const;
+ glm::vec3 getEnd() const;
const float& getGlow() const { return _glow; }
const float& getGlowWidth() const { return _glowWidth; }
// setters
- void setStart(const glm::vec3& start) { _start = start; }
- void setEnd(const glm::vec3& end) { _end = end; }
+ void setStart(const glm::vec3& start);
+ void setEnd(const glm::vec3& end);
+
void setGlow(const float& glow) { _glow = glow; }
void setGlowWidth(const float& glowWidth) { _glowWidth = glowWidth; }
@@ -44,6 +45,8 @@ public:
virtual Line3DOverlay* createClone() const override;
+ virtual void locationChanged(bool tellPhysics = true) override;
+
protected:
glm::vec3 _start;
glm::vec3 _end;
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 476e64e642..e36563681a 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -346,15 +346,13 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetStage();
auto skyStage = scene->getSkyStage();
auto sceneKeyLight = sceneStage->getKeyLight();
- auto sceneLocation = sceneStage->getLocation();
- auto sceneTime = sceneStage->getTime();
// Skybox and procedural skybox data
auto skybox = std::dynamic_pointer_cast(skyStage->getSkybox());
- static QString userData;
+ // If there is no zone, use the default background
if (!zone) {
- userData = QString();
+ _zoneUserData = QString();
skybox->clear();
_pendingSkyboxTexture = false;
@@ -363,50 +361,33 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrresetAmbientSphere();
- sceneKeyLight->setAmbientMap(nullptr);
- sceneKeyLight->setColor(_previousKeyLightColor);
- sceneKeyLight->setIntensity(_previousKeyLightIntensity);
- sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity);
- sceneKeyLight->setDirection(_previousKeyLightDirection);
- sceneStage->setSunModelEnable(_previousStageSunModelEnabled);
- sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude,
- _previousStageAltitude);
- sceneTime->setHour(_previousStageHour);
- sceneTime->setDay(_previousStageDay);
+ sceneKeyLight->resetAmbientSphere();
+ sceneKeyLight->setAmbientMap(nullptr);
- _hasPreviousZone = false;
- }
-
- skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application background through
- return; // Early exit
- }
-
- if (!_hasPreviousZone) {
- _previousKeyLightColor = sceneKeyLight->getColor();
- _previousKeyLightIntensity = sceneKeyLight->getIntensity();
- _previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity();
- _previousKeyLightDirection = sceneKeyLight->getDirection();
- _previousStageSunModelEnabled = sceneStage->isSunModelEnabled();
- _previousStageLongitude = sceneLocation->getLongitude();
- _previousStageLatitude = sceneLocation->getLatitude();
- _previousStageAltitude = sceneLocation->getAltitude();
- _previousStageHour = sceneTime->getHour();
- _previousStageDay = sceneTime->getDay();
- _hasPreviousZone = true;
+ skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
+ return;
}
+ // Set the keylight
sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor()));
sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity());
sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity());
sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection());
- sceneStage->setSunModelEnable(zone->getStageProperties().getSunModelEnabled());
- sceneStage->setLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(),
- zone->getStageProperties().getAltitude());
- sceneTime->setHour(zone->getStageProperties().calculateHour());
- sceneTime->setDay(zone->getStageProperties().calculateDay());
+ // Set the stage
+ bool isSunModelEnabled = zone->getStageProperties().getSunModelEnabled();
+ sceneStage->setSunModelEnable(isSunModelEnabled);
+ if (isSunModelEnabled) {
+ sceneStage->setLocation(zone->getStageProperties().getLongitude(),
+ zone->getStageProperties().getLatitude(),
+ zone->getStageProperties().getAltitude());
+
+ auto sceneTime = sceneStage->getTime();
+ sceneTime->setHour(zone->getStageProperties().calculateHour());
+ sceneTime->setDay(zone->getStageProperties().calculateDay());
+ }
+
+ // Set the ambient texture
bool isAmbientTextureSet = false;
if (zone->getKeyLightProperties().getAmbientURL().isEmpty()) {
_pendingAmbientTexture = false;
@@ -429,12 +410,13 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrgetBackgroundMode()) {
case BACKGROUND_MODE_SKYBOX: {
skybox->setColor(zone->getSkyboxProperties().getColorVec3());
- if (userData != zone->getUserData()) {
- userData = zone->getUserData();
- skybox->parse(userData);
+ if (_zoneUserData != zone->getUserData()) {
+ _zoneUserData = zone->getUserData();
+ skybox->parse(_zoneUserData);
}
if (zone->getSkyboxProperties().getURL().isEmpty()) {
skybox->setCubemap(nullptr);
@@ -471,14 +453,18 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptrclear();
_skyboxTexture.clear();
_pendingSkyboxTexture = false;
// Let the application background through
- skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
+ if (isAmbientTextureSet) {
+ skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_TEXTURE);
+ } else {
+ skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE);
+ }
break;
}
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h
index 99c62ab5f6..cfd8595f78 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.h
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.h
@@ -185,25 +185,15 @@ private:
QMultiMap _waitingOnPreload;
- bool _hasPreviousZone { false };
std::shared_ptr _bestZone;
float _bestZoneVolume;
+ QString _zoneUserData;
+
quint64 _lastZoneCheck { 0 };
const quint64 ZONE_CHECK_INTERVAL = USECS_PER_MSEC * 100; // ~10hz
const float ZONE_CHECK_DISTANCE = 0.001f;
- glm::vec3 _previousKeyLightColor;
- float _previousKeyLightIntensity;
- float _previousKeyLightAmbientIntensity;
- glm::vec3 _previousKeyLightDirection;
- bool _previousStageSunModelEnabled;
- float _previousStageLongitude;
- float _previousStageLatitude;
- float _previousStageAltitude;
- float _previousStageHour;
- int _previousStageDay;
-
QHash _entitiesInScene;
// For Scene.shouldRenderEntities
QList _entityIDsLastInScene;
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index e14def114d..c3e097382c 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -91,6 +91,11 @@ void RenderableShapeEntityItem::render(RenderArgs* args) {
_procedural.reset(new Procedural(getUserData()));
_procedural->_vertexSource = simple_vert;
_procedural->_fragmentSource = simple_frag;
+ _procedural->_opaqueState->setCullMode(gpu::State::CULL_NONE);
+ _procedural->_opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL);
+ _procedural->_opaqueState->setBlendFunction(false,
+ gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
}
gpu::Batch& batch = *args->_batch;
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index b9f384f013..29cbfd79e6 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -35,6 +35,7 @@
int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
+std::function EntityItem::_entitiesShouldFadeFunction = [](){ return true; };
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID),
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 3677a0bbc8..c0772cbc01 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -432,6 +432,8 @@ public:
QUuid getOwningAvatarID() const { return _owningAvatarID; }
void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
+ static void setEntitiesShouldFadeFunction(std::function func) { _entitiesShouldFadeFunction = func; }
+ static std::function getEntitiesShouldFadeFunction() { return _entitiesShouldFadeFunction; }
virtual bool isTransparent() { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; }
protected:
@@ -564,7 +566,8 @@ protected:
quint64 _lastUpdatedAccelerationTimestamp { 0 };
quint64 _fadeStartTime { usecTimestampNow() };
- bool _isFading { true };
+ static std::function _entitiesShouldFadeFunction;
+ bool _isFading { _entitiesShouldFadeFunction() };
};
#endif // hifi_EntityItem_h
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index dcd7e25bc1..b3d810c0eb 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -325,6 +325,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_POSITION, localPosition);
CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation);
+ CHECK_PROPERTY_CHANGE(PROP_LOCAL_VELOCITY, localVelocity);
+ CHECK_PROPERTY_CHANGE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed);
CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed);
@@ -570,6 +572,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_VELOCITY, localVelocity);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLIENT_ONLY, clientOnly);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID);
@@ -707,6 +711,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition);
COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, glmVec3, setLocalVelocity);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, glmVec3, setLocalAngularVelocity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations);
@@ -864,6 +870,8 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_LOCAL_POSITION, LocalPosition, localPosition, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glm::quat);
+ ADD_PROPERTY_TO_MAP(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glm::vec3);
+ ADD_PROPERTY_TO_MAP(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glm::vec3);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector);
@@ -1982,7 +1990,9 @@ QList EntityItemProperties::listChangedProperties() {
}
bool EntityItemProperties::parentDependentPropertyChanged() const {
- return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged();
+ return localPositionChanged() || positionChanged() ||
+ localRotationChanged() || rotationChanged() ||
+ localVelocityChanged() || localAngularVelocityChanged();
}
bool EntityItemProperties::parentRelatedPropertyChanged() const {
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 6018ba793f..22d740e0dd 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -201,6 +201,8 @@ public:
// these are used when bouncing location data into and out of scripts
DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION);
+ DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
+ DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glmVec3, ENTITY_ITEM_ZERO_VEC3);
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector, QVector());
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector, QVector());
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index 36bb37c8f3..0baef0fa25 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -177,6 +177,9 @@ enum EntityPropertyList {
PROP_SHAPE,
+ PROP_LOCAL_VELOCITY, // only used to convert values to and from scripts
+ PROP_LOCAL_ANGULAR_VELOCITY, // only used to convert values to and from scripts
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp
index 653b37c3bb..1961742c2e 100644
--- a/libraries/entities/src/EntityScriptingInterface.cpp
+++ b/libraries/entities/src/EntityScriptingInterface.cpp
@@ -40,6 +40,12 @@ void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);
}
+void EntityScriptingInterface::resetActivityTracking() {
+ _activityTracking.addedEntityCount = 0;
+ _activityTracking.deletedEntityCount = 0;
+ _activityTracking.editedEntityCount = 0;
+}
+
bool EntityScriptingInterface::canAdjustLocks() {
auto nodeList = DependencyManager::get();
return nodeList->isAllowedEditor();
@@ -78,6 +84,8 @@ EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties
EntityItemProperties scriptSideProperties = entitySideProperties;
scriptSideProperties.setLocalPosition(entitySideProperties.getPosition());
scriptSideProperties.setLocalRotation(entitySideProperties.getRotation());
+ scriptSideProperties.setLocalVelocity(entitySideProperties.getLocalVelocity());
+ scriptSideProperties.setLocalAngularVelocity(entitySideProperties.getLocalAngularVelocity());
bool success;
glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(),
@@ -88,10 +96,19 @@ EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties
entitySideProperties.getParentID(),
entitySideProperties.getParentJointIndex(),
success);
- // TODO -- handle velocity and angularVelocity
+ glm::vec3 worldVelocity = SpatiallyNestable::localToWorldVelocity(entitySideProperties.getVelocity(),
+ entitySideProperties.getParentID(),
+ entitySideProperties.getParentJointIndex(),
+ success);
+ glm::vec3 worldAngularVelocity = SpatiallyNestable::localToWorldAngularVelocity(entitySideProperties.getAngularVelocity(),
+ entitySideProperties.getParentID(),
+ entitySideProperties.getParentJointIndex(),
+ success);
scriptSideProperties.setPosition(worldPosition);
scriptSideProperties.setRotation(worldRotation);
+ scriptSideProperties.setVelocity(worldVelocity);
+ scriptSideProperties.setAngularVelocity(worldAngularVelocity);
return scriptSideProperties;
}
@@ -125,11 +142,34 @@ EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperti
entitySideProperties.setRotation(localRotation);
}
+ if (scriptSideProperties.localVelocityChanged()) {
+ entitySideProperties.setVelocity(scriptSideProperties.getLocalVelocity());
+ } else if (scriptSideProperties.velocityChanged()) {
+ glm::vec3 localVelocity = SpatiallyNestable::worldToLocalVelocity(entitySideProperties.getVelocity(),
+ entitySideProperties.getParentID(),
+ entitySideProperties.getParentJointIndex(),
+ success);
+ entitySideProperties.setVelocity(localVelocity);
+ }
+
+ if (scriptSideProperties.localAngularVelocityChanged()) {
+ entitySideProperties.setAngularVelocity(scriptSideProperties.getLocalAngularVelocity());
+ } else if (scriptSideProperties.angularVelocityChanged()) {
+ glm::vec3 localAngularVelocity =
+ SpatiallyNestable::worldToLocalAngularVelocity(entitySideProperties.getAngularVelocity(),
+ entitySideProperties.getParentID(),
+ entitySideProperties.getParentJointIndex(),
+ success);
+ entitySideProperties.setAngularVelocity(localAngularVelocity);
+ }
+
return entitySideProperties;
}
QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties, bool clientOnly) {
+ _activityTracking.addedEntityCount++;
+
EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties);
propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged());
@@ -200,6 +240,8 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QString& modelUrl, const QString& shapeType,
bool dynamic, const glm::vec3& position, const glm::vec3& gravity) {
+ _activityTracking.addedEntityCount++;
+
EntityItemProperties properties;
properties.setType(EntityTypes::Model);
properties.setName(name);
@@ -263,6 +305,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
}
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) {
+ _activityTracking.editedEntityCount++;
+
EntityItemProperties properties = scriptSideProperties;
auto dimensions = properties.getDimensions();
@@ -406,6 +450,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
}
void EntityScriptingInterface::deleteEntity(QUuid id) {
+ _activityTracking.deletedEntityCount++;
+
EntityItemID entityID(id);
bool shouldDelete = true;
diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h
index 5aa0f5907e..ce5b332b2a 100644
--- a/libraries/entities/src/EntityScriptingInterface.h
+++ b/libraries/entities/src/EntityScriptingInterface.h
@@ -65,6 +65,13 @@ class EntityScriptingInterface : public OctreeScriptingInterface, public Depende
public:
EntityScriptingInterface(bool bidOnSimulationOwnership);
+ class ActivityTracking {
+ public:
+ int addedEntityCount { 0 };
+ int deletedEntityCount { 0 };
+ int editedEntityCount { 0 };
+ };
+
EntityEditPacketSender* getEntityPacketSender() const { return (EntityEditPacketSender*)getPacketSender(); }
virtual NodeType_t getServerNodeType() const { return NodeType::EntityServer; }
virtual OctreeEditPacketSender* createPacketSender() { return new EntityEditPacketSender(); }
@@ -73,6 +80,9 @@ public:
EntityTreePointer getEntityTree() { return _entityTree; }
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine);
float calculateCost(float mass, float oldVelocity, float newVelocity);
+
+ void resetActivityTracking();
+ ActivityTracking getActivityTracking() const { return _activityTracking; }
public slots:
// returns true if the DomainServer will allow this Node/Avatar to make changes
@@ -226,6 +236,8 @@ private:
float _currentAvatarEnergy = { FLT_MAX };
float getCurrentAvatarEnergy() { return _currentAvatarEnergy; }
void setCurrentAvatarEnergy(float energy);
+
+ ActivityTracking _activityTracking;
float costMultiplier = { 0.01f };
float getCostMultiplier();
diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp
index eb25f1d8a2..8c0f4b34ac 100644
--- a/libraries/fbx/src/FBXReader_Material.cpp
+++ b/libraries/fbx/src/FBXReader_Material.cpp
@@ -9,7 +9,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include "FBXReader.h"
+
#include
+#include
+
#include
#include
#include
@@ -20,9 +24,8 @@
#include
#include
#include
-#include "FBXReader.h"
-#include
+#include "ModelFormatLogging.h"
bool FBXMaterial::needTangentSpace() const {
return !normalTexture.isNull();
@@ -258,11 +261,11 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
}
}
}
- qDebug() << " fbx material Name:" << material.name;
+ qCDebug(modelformat) << " fbx material Name:" << material.name;
if (materialMap.contains(material.name)) {
QJsonObject materialOptions = materialMap.value(material.name).toObject();
- qDebug() << "Mapping fbx material:" << material.name << " with HifiMaterial: " << materialOptions;
+ qCDebug(modelformat) << "Mapping fbx material:" << material.name << " with HifiMaterial: " << materialOptions;
if (materialOptions.contains("scattering")) {
float scattering = (float) materialOptions.value("scattering").toDouble();
diff --git a/libraries/gpu/src/gpu/Buffer.h b/libraries/gpu/src/gpu/Buffer.h
index da1a987bee..8160f648fc 100644
--- a/libraries/gpu/src/gpu/Buffer.h
+++ b/libraries/gpu/src/gpu/Buffer.h
@@ -293,10 +293,18 @@ public:
template Iterator end() { return Iterator(&edit(getNum()), _stride); }
#else
template Iterator begin() const { return Iterator(&get(), _stride); }
- template Iterator end() const { return Iterator(&get(getNum()), _stride); }
+ template Iterator end() const {
+ // reimplement get without bounds checking
+ Resource::Size elementOffset = getNum() * _stride + _offset;
+ return Iterator((reinterpret_cast (_buffer->getData() + elementOffset)), _stride);
+ }
#endif
template Iterator cbegin() const { return Iterator(&get(), _stride); }
- template Iterator cend() const { return Iterator(&get(getNum()), _stride); }
+ template Iterator cend() const {
+ // reimplement get without bounds checking
+ Resource::Size elementOffset = getNum() * _stride + _offset;
+ return Iterator((reinterpret_cast (_buffer->getData() + elementOffset)), _stride);
+ }
// the number of elements of the specified type fitting in the view size
template Index getNum() const {
diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp
index 23503ef6fb..6cfb77f2b2 100644
--- a/libraries/model/src/model/Stage.cpp
+++ b/libraries/model/src/model/Stage.cpp
@@ -244,21 +244,6 @@ void SunSkyStage::updateGraphicsObject() const {
double originAlt = _earthSunModel.getAltitude();
_sunLight->setPosition(Vec3(0.0f, originAlt, 0.0f));
}
-
- // Background
- switch (getBackgroundMode()) {
- case NO_BACKGROUND: {
- break;
- }
- case SKY_DOME: {
- break;
- }
- case SKY_BOX: {
- break;
- }
- case NUM_BACKGROUND_MODES:
- Q_UNREACHABLE();
- };
}
void SunSkyStage::setBackgroundMode(BackgroundMode mode) {
diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h
index 335fb1c758..5f48824568 100644
--- a/libraries/model/src/model/Stage.h
+++ b/libraries/model/src/model/Stage.h
@@ -160,8 +160,10 @@ public:
enum BackgroundMode {
NO_BACKGROUND = 0,
- SKY_DOME,
+ SKY_DEFAULT,
SKY_BOX,
+ SKY_DEFAULT_AMBIENT_TEXTURE,
+ SKY_DEFAULT_TEXTURE,
NUM_BACKGROUND_MODES,
};
@@ -173,7 +175,7 @@ public:
const SkyboxPointer& getSkybox() const { valid(); return _skybox; }
protected:
- BackgroundMode _backgroundMode = SKY_DOME;
+ BackgroundMode _backgroundMode = SKY_DEFAULT;
LightPointer _sunLight;
mutable SkyboxPointer _skybox;
diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp
index 431d372089..6d9de2dbc1 100644
--- a/libraries/networking/src/LimitedNodeList.cpp
+++ b/libraries/networking/src/LimitedNodeList.cpp
@@ -175,7 +175,11 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() {
}
bool LimitedNodeList::isPacketVerified(const udt::Packet& packet) {
- return packetVersionMatch(packet) && packetSourceAndHashMatch(packet);
+ // We track bandwidth when doing packet verification to avoid needing to do a node lookup
+ // later when we already do it in packetSourceAndHashMatchAndTrackBandwidth. A node lookup
+ // incurs a lock, so it is ideal to avoid needing to do it 2+ times for each packet
+ // received.
+ return packetVersionMatch(packet) && packetSourceAndHashMatchAndTrackBandwidth(packet);
}
bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
@@ -224,11 +228,12 @@ bool LimitedNodeList::packetVersionMatch(const udt::Packet& packet) {
}
}
-bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) {
+bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet) {
PacketType headerType = NLPacket::typeInHeader(packet);
if (NON_SOURCED_PACKETS.contains(headerType)) {
+ emit dataReceived(NodeType::Unassigned, packet.getPayloadSize());
return true;
} else {
QUuid sourceID = NLPacket::sourceIDInHeader(packet);
@@ -260,6 +265,8 @@ bool LimitedNodeList::packetSourceAndHashMatch(const udt::Packet& packet) {
// from this sending node
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
+ emit dataReceived(matchingNode->getType(), packet.getPayloadSize());
+
return true;
} else {
diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h
index 48379b5e39..49a3a155a2 100644
--- a/libraries/networking/src/LimitedNodeList.h
+++ b/libraries/networking/src/LimitedNodeList.h
@@ -243,6 +243,7 @@ public slots:
signals:
void dataSent(quint8 channelType, int bytes);
+ void dataReceived(quint8 channelType, int bytes);
// QUuid might be zero for non-sourced packet types.
void packetVersionMismatch(PacketType type, const HifiSockAddr& senderSockAddr, const QUuid& senderUUID);
@@ -279,7 +280,7 @@ protected:
void setLocalSocket(const HifiSockAddr& sockAddr);
- bool packetSourceAndHashMatch(const udt::Packet& packet);
+ bool packetSourceAndHashMatchAndTrackBandwidth(const udt::Packet& packet);
void processSTUNResponse(std::unique_ptr packet);
void handleNodeKill(const SharedNodePointer& node);
diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp
index 530efc5fb3..21ba7129d4 100644
--- a/libraries/networking/src/PacketReceiver.cpp
+++ b/libraries/networking/src/PacketReceiver.cpp
@@ -294,7 +294,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei
PacketType packetType = receivedMessage->getType();
if (matchingNode) {
- emit dataReceived(matchingNode->getType(), receivedMessage->getSize());
matchingNode->recordBytesReceived(receivedMessage->getSize());
QMetaMethod metaMethod = listener.method;
@@ -326,7 +325,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei
}
} else {
// qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage());
- emit dataReceived(NodeType::Unassigned, receivedMessage->getSize());
// one final check on the QPointer before we invoke
if (listener.object) {
diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h
index ff4ab3e15c..4b4d260409 100644
--- a/libraries/networking/src/PacketReceiver.h
+++ b/libraries/networking/src/PacketReceiver.h
@@ -67,9 +67,6 @@ public:
void handleVerifiedPacket(std::unique_ptr packet);
void handleVerifiedMessagePacket(std::unique_ptr message);
void handleMessageFailure(HifiSockAddr from, udt::Packet::MessageNumber messageNumber);
-
-signals:
- void dataReceived(quint8 channelType, int bytes);
private:
struct Listener {
diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp
index d48c35d542..7034790eaf 100644
--- a/libraries/octree/src/OctreePersistThread.cpp
+++ b/libraries/octree/src/OctreePersistThread.cpp
@@ -34,11 +34,12 @@
const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
-OctreePersistThread::OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval,
+OctreePersistThread::OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory, int persistInterval,
bool wantBackup, const QJsonObject& settings, bool debugTimestampNow,
QString persistAsFileType) :
_tree(tree),
_filename(filename),
+ _backupDirectory(backupDirectory),
_persistInterval(persistInterval),
_initialLoadComplete(false),
_loadTimeUSecs(0),
@@ -316,7 +317,7 @@ bool OctreePersistThread::getMostRecentBackup(const QString& format,
// Based on our backup file name, determine the path and file name pattern for backup files
QFileInfo persistFileInfo(_filename);
- QString path = persistFileInfo.path();
+ QString path = _backupDirectory;
QString fileNamePart = persistFileInfo.fileName();
QStringList filters;
@@ -369,10 +370,12 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
if (rule.maxBackupVersions > 0) {
qCDebug(octree) << "Rolling old backup versions for rule" << rule.name << "...";
+ QString backupFileName = _backupDirectory + "/" + QUrl(_filename).fileName();
+
// Delete maximum rolling file because rename() fails on Windows if target exists
QString backupMaxExtensionN = rule.extensionFormat;
backupMaxExtensionN.replace(QString("%N"), QString::number(rule.maxBackupVersions));
- QString backupMaxFilenameN = _filename + backupMaxExtensionN;
+ QString backupMaxFilenameN = backupFileName + backupMaxExtensionN;
QFile backupMaxFileN(backupMaxFilenameN);
if (backupMaxFileN.exists()) {
int result = remove(qPrintable(backupMaxFilenameN));
@@ -387,8 +390,8 @@ void OctreePersistThread::rollOldBackupVersions(const BackupRule& rule) {
backupExtensionN.replace(QString("%N"), QString::number(n));
backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1));
- QString backupFilenameN = findMostRecentFileExtension(_filename, PERSIST_EXTENSIONS) + backupExtensionN;
- QString backupFilenameNplusOne = _filename + backupExtensionNplusOne;
+ QString backupFilenameN = findMostRecentFileExtension(backupFileName, PERSIST_EXTENSIONS) + backupExtensionN;
+ QString backupFilenameNplusOne = backupFileName + backupExtensionNplusOne;
QFile backupFileN(backupFilenameN);
@@ -434,21 +437,20 @@ void OctreePersistThread::backup() {
struct tm* localTime = localtime(&_lastPersistTime);
- QString backupFileName;
+ QString backupFileName = _backupDirectory + "/" + QUrl(_filename).fileName();
// check to see if they asked for version rolling format
if (rule.extensionFormat.contains("%N")) {
rollOldBackupVersions(rule); // rename all the old backup files accordingly
QString backupExtension = rule.extensionFormat;
backupExtension.replace(QString("%N"), QString("1"));
- backupFileName = _filename + backupExtension;
+ backupFileName += backupExtension;
} else {
char backupExtension[256];
strftime(backupExtension, sizeof(backupExtension), qPrintable(rule.extensionFormat), localTime);
- backupFileName = _filename + backupExtension;
+ backupFileName += backupExtension;
}
-
if (rule.maxBackupVersions > 0) {
QFile persistFile(_filename);
if (persistFile.exists()) {
diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h
index 061a7a0e15..2a939216c4 100644
--- a/libraries/octree/src/OctreePersistThread.h
+++ b/libraries/octree/src/OctreePersistThread.h
@@ -33,9 +33,9 @@ public:
static const int DEFAULT_PERSIST_INTERVAL;
- OctreePersistThread(OctreePointer tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL,
- bool wantBackup = false, const QJsonObject& settings = QJsonObject(),
- bool debugTimestampNow = false, QString persistAsFileType="svo");
+ OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory,
+ int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false,
+ const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false, QString persistAsFileType="svo");
bool isInitialLoadComplete() const { return _initialLoadComplete; }
quint64 getLoadElapsedTime() const { return _loadTimeUSecs; }
@@ -64,6 +64,7 @@ protected:
private:
OctreePointer _tree;
QString _filename;
+ QString _backupDirectory;
int _persistInterval;
bool _initialLoadComplete;
diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp
index 38d181e748..63082a8995 100644
--- a/libraries/render-utils/src/MeshPartPayload.cpp
+++ b/libraries/render-utils/src/MeshPartPayload.cpp
@@ -15,6 +15,7 @@
#include "DeferredLightingEffect.h"
#include "Model.h"
+#include "EntityItem.h"
using namespace render;
@@ -517,10 +518,16 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
}
void ModelMeshPartPayload::startFade() {
- _fadeStartTime = usecTimestampNow();
- _hasStartedFade = true;
- _prevHasStartedFade = false;
- _hasFinishedFade = false;
+ bool shouldFade = EntityItem::getEntitiesShouldFadeFunction()();
+ if (shouldFade) {
+ _fadeStartTime = usecTimestampNow();
+ _hasStartedFade = true;
+ _hasFinishedFade = false;
+ } else {
+ _isFading = true;
+ _hasStartedFade = true;
+ _hasFinishedFade = true;
+ }
}
void ModelMeshPartPayload::render(RenderArgs* args) const {
@@ -533,10 +540,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
// When an individual mesh parts like this finishes its fade, we will mark the Model as
// having render items that need updating
bool nextIsFading = _isFading ? isStillFading() : false;
- if (_isFading != nextIsFading || _prevHasStartedFade != _hasStartedFade) {
- _isFading = nextIsFading || _prevHasStartedFade != _hasStartedFade;
- _hasFinishedFade = _prevHasStartedFade == _hasStartedFade && !_isFading;
- _prevHasStartedFade = _hasStartedFade;
+ bool startFading = !_isFading && !_hasFinishedFade && _hasStartedFade;
+ bool endFading = _isFading && !nextIsFading;
+ if (startFading || endFading) {
+ _isFading = startFading;
+ _hasFinishedFade = endFading;
_model->setRenderItemsNeedUpdate();
}
diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h
index 67fb660f8b..29478b3b4e 100644
--- a/libraries/render-utils/src/MeshPartPayload.h
+++ b/libraries/render-utils/src/MeshPartPayload.h
@@ -110,7 +110,6 @@ public:
private:
quint64 _fadeStartTime { 0 };
bool _hasStartedFade { false };
- mutable bool _prevHasStartedFade{ false };
mutable bool _hasFinishedFade { false };
mutable bool _isFading { false };
};
diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp
index c3dbafa0d9..453035de0f 100644
--- a/libraries/shared/src/SpatiallyNestable.cpp
+++ b/libraries/shared/src/SpatiallyNestable.cpp
@@ -224,6 +224,38 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
return result.getRotation();
}
+glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID,
+ int parentJointIndex, bool& success) {
+ SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success);
+ if (!success || !parent) {
+ return velocity;
+ }
+ Transform parentTransform = parent->getTransform(success);
+ if (!success) {
+ return velocity;
+ }
+ glm::vec3 parentVelocity = parent->getVelocity(success);
+ if (!success) {
+ return velocity;
+ }
+
+ return glm::inverse(parentTransform.getRotation()) * (velocity - parentVelocity);
+}
+
+glm::vec3 SpatiallyNestable::worldToLocalAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID,
+ int parentJointIndex, bool& success) {
+ SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success);
+ if (!success || !parent) {
+ return angularVelocity;
+ }
+ Transform parentTransform = parent->getTransform(success);
+ if (!success) {
+ return angularVelocity;
+ }
+
+ return glm::inverse(parentTransform.getRotation()) * angularVelocity;
+}
+
glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position,
const QUuid& parentID, int parentJointIndex,
bool& success) {
@@ -298,6 +330,38 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation,
return result.getRotation();
}
+glm::vec3 SpatiallyNestable::localToWorldVelocity(const glm::vec3& velocity, const QUuid& parentID,
+ int parentJointIndex, bool& success) {
+ SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success);
+ if (!success || !parent) {
+ return velocity;
+ }
+ Transform parentTransform = parent->getTransform(success);
+ if (!success) {
+ return velocity;
+ }
+ glm::vec3 parentVelocity = parent->getVelocity(success);
+ if (!success) {
+ return velocity;
+ }
+
+ return parentVelocity + parentTransform.getRotation() * velocity;
+}
+
+glm::vec3 SpatiallyNestable::localToWorldAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID,
+ int parentJointIndex, bool& success) {
+ SpatiallyNestablePointer parent = SpatiallyNestable::findByID(parentID, success);
+ if (!success || !parent) {
+ return angularVelocity;
+ }
+ Transform parentTransform = parent->getTransform(success);
+ if (!success) {
+ return angularVelocity;
+ }
+
+ return parentTransform.getRotation() * angularVelocity;
+}
+
glm::vec3 SpatiallyNestable::getPosition(bool& success) const {
return getTransform(success).getTranslation();
}
@@ -1004,3 +1068,15 @@ void SpatiallyNestable::setLocalTransformAndVelocities(
locationChanged(false);
}
}
+
+SpatiallyNestablePointer SpatiallyNestable::findByID(QUuid id, bool& success) {
+ QSharedPointer parentFinder = DependencyManager::get();
+ if (!parentFinder) {
+ return nullptr;
+ }
+ SpatiallyNestableWeakPointer parentWP = parentFinder->find(id, success);
+ if (!success) {
+ return nullptr;
+ }
+ return parentWP.lock();
+}
diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h
index 391f13cc27..5605cc0031 100644
--- a/libraries/shared/src/SpatiallyNestable.h
+++ b/libraries/shared/src/SpatiallyNestable.h
@@ -48,9 +48,17 @@ public:
static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success);
static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
+ static glm::vec3 worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID,
+ int parentJointIndex, bool& success);
+ static glm::vec3 worldToLocalAngularVelocity(const glm::vec3& angularVelocity, const QUuid& parentID,
+ int parentJointIndex, bool& success);
static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex, bool& success);
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
+ static glm::vec3 localToWorldVelocity(const glm::vec3& velocity,
+ const QUuid& parentID, int parentJointIndex, bool& success);
+ static glm::vec3 localToWorldAngularVelocity(const glm::vec3& angularVelocity,
+ const QUuid& parentID, int parentJointIndex, bool& success);
// world frame
virtual const Transform getTransform(bool& success, int depth = 0) const;
@@ -151,6 +159,8 @@ public:
virtual SpatialParentTree* getParentTree() const { return nullptr; }
bool hasAncestorOfType(NestableType nestableType);
+ SpatiallyNestablePointer getParentPointer(bool& success) const;
+ static SpatiallyNestablePointer findByID(QUuid id, bool& success);
void getLocalTransformAndVelocities(Transform& localTransform,
glm::vec3& localVelocity,
@@ -166,7 +176,6 @@ protected:
QUuid _id;
QUuid _parentID; // what is this thing's transform relative to?
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?
- SpatiallyNestablePointer getParentPointer(bool& success) const;
mutable SpatiallyNestableWeakPointer _parent;
diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
index b5f360ad8d..e751427ce2 100644
--- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp
+++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp
@@ -108,19 +108,20 @@ public:
}
void updateSource() {
- Lock lock(_plugin._presentMutex);
- while (!_queue.empty()) {
- auto& front = _queue.front();
- auto result = glClientWaitSync(front.fence, 0, 0);
- if (GL_TIMEOUT_EXPIRED == result && GL_WAIT_FAILED == result) {
- break;
- }
+ _plugin.withNonPresentThreadLock([&] {
+ while (!_queue.empty()) {
+ auto& front = _queue.front();
+ auto result = glClientWaitSync(front.fence, 0, 0);
+ if (GL_TIMEOUT_EXPIRED == result && GL_WAIT_FAILED == result) {
+ break;
+ }
- glDeleteSync(front.fence);
- front.fence = 0;
- _current = front;
- _queue.pop();
- }
+ glDeleteSync(front.fence);
+ front.fence = 0;
+ _current = front;
+ _queue.pop();
+ }
+ });
}
void run() override {
@@ -170,15 +171,28 @@ public:
PoseData nextRender, nextSim;
nextRender.frameIndex = _plugin.presentCount();
vr::VRCompositor()->WaitGetPoses(nextRender.vrPoses, vr::k_unMaxTrackedDeviceCount, nextSim.vrPoses, vr::k_unMaxTrackedDeviceCount);
- {
- Lock lock(_plugin._presentMutex);
- _presentCount++;
- _presented.notify_one();
- _nextRender = nextRender;
- _nextRender.update(_plugin._sensorResetMat);
- _nextSim = nextSim;
- _nextSim.update(_plugin._sensorResetMat);
+
+ // Copy invalid poses in nextSim from nextRender
+ for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i) {
+ if (!nextSim.vrPoses[i].bPoseIsValid) {
+ nextSim.vrPoses[i] = nextRender.vrPoses[i];
+ }
}
+
+ mat4 sensorResetMat;
+ _plugin.withNonPresentThreadLock([&] {
+ sensorResetMat = _plugin._sensorResetMat;
+ });
+
+ nextRender.update(sensorResetMat);
+ nextSim.update(sensorResetMat);
+
+ _plugin.withNonPresentThreadLock([&] {
+ _nextRender = nextRender;
+ _nextSim = nextSim;
+ ++_presentCount;
+ _presented.notify_one();
+ });
}
_canvas.doneCurrent();
}
@@ -366,19 +380,20 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
}
_currentRenderFrameInfo = FrameInfo();
+ PoseData nextSimPoseData;
withNonPresentThreadLock([&] {
- _currentRenderFrameInfo.renderPose = _nextSimPoseData.poses[vr::k_unTrackedDeviceIndex_Hmd];
+ nextSimPoseData = _nextSimPoseData;
});
// HACK: when interface is launched and steam vr is NOT running, openvr will return bad HMD poses for a few frames
// To workaround this, filter out any hmd poses that are obviously bad, i.e. beneath the floor.
- if (isBadPose(&_nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking)) {
+ if (isBadPose(&nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking)) {
qDebug() << "WARNING: ignoring bad hmd pose from openvr";
// use the last known good HMD pose
- _nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking = _lastGoodHMDPose;
+ nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking = _lastGoodHMDPose;
} else {
- _lastGoodHMDPose = _nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking;
+ _lastGoodHMDPose = nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking;
}
vr::TrackedDeviceIndex_t handIndices[2] { vr::k_unTrackedDeviceIndexInvalid, vr::k_unTrackedDeviceIndexInvalid };
@@ -387,7 +402,7 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
auto trackedCount = _system->GetSortedTrackedDeviceIndicesOfClass(vr::TrackedDeviceClass_Controller, controllerIndices, 2);
// Find the left and right hand controllers, if they exist
for (uint32_t i = 0; i < std::min(trackedCount, 2); ++i) {
- if (_nextSimPoseData.vrPoses[i].bPoseIsValid) {
+ if (nextSimPoseData.vrPoses[i].bPoseIsValid) {
auto role = _system->GetControllerRoleForTrackedDeviceIndex(controllerIndices[i]);
if (vr::TrackedControllerRole_LeftHand == role) {
handIndices[0] = controllerIndices[i];
@@ -398,8 +413,7 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
}
}
- _currentRenderFrameInfo.renderPose = _nextSimPoseData.poses[vr::k_unTrackedDeviceIndex_Hmd];
-
+ _currentRenderFrameInfo.renderPose = nextSimPoseData.poses[vr::k_unTrackedDeviceIndex_Hmd];
bool keyboardVisible = isOpenVrKeyboardShown();
std::array handPoses;
@@ -409,9 +423,9 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
continue;
}
auto deviceIndex = handIndices[i];
- const mat4& mat = _nextSimPoseData.poses[deviceIndex];
- const vec3& linearVelocity = _nextSimPoseData.linearVelocities[deviceIndex];
- const vec3& angularVelocity = _nextSimPoseData.angularVelocities[deviceIndex];
+ const mat4& mat = nextSimPoseData.poses[deviceIndex];
+ const vec3& linearVelocity = nextSimPoseData.linearVelocities[deviceIndex];
+ const vec3& angularVelocity = nextSimPoseData.angularVelocities[deviceIndex];
auto correctedPose = openVrControllerPoseToHandPose(i == 0, mat, linearVelocity, angularVelocity);
static const glm::quat HAND_TO_LASER_ROTATION = glm::rotation(Vectors::UNIT_Z, Vectors::UNIT_NEG_Y);
handPoses[i] = glm::translate(glm::mat4(), correctedPose.translation) * glm::mat4_cast(correctedPose.rotation * HAND_TO_LASER_ROTATION);
diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h
index 368b14cb1a..4279e6a6ac 100644
--- a/plugins/openvr/src/OpenVrHelpers.h
+++ b/plugins/openvr/src/OpenVrHelpers.h
@@ -66,8 +66,15 @@ struct PoseData {
vec3 linearVelocities[vr::k_unMaxTrackedDeviceCount];
vec3 angularVelocities[vr::k_unMaxTrackedDeviceCount];
+ PoseData() {
+ memset(vrPoses, 0, sizeof(vr::TrackedDevicePose_t) * vr::k_unMaxTrackedDeviceCount);
+ }
+
void update(const glm::mat4& resetMat) {
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
+ if (!vrPoses[i].bPoseIsValid) {
+ continue;
+ }
poses[i] = resetMat * toGlm(vrPoses[i].mDeviceToAbsoluteTracking);
linearVelocities[i] = transformVectorFast(resetMat, toGlm(vrPoses[i].vVelocity));
angularVelocities[i] = transformVectorFast(resetMat, toGlm(vrPoses[i].vAngularVelocity));
diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js
index f29fdfb00a..1264502aa7 100644
--- a/scripts/system/controllers/handControllerGrab.js
+++ b/scripts/system/controllers/handControllerGrab.js
@@ -96,7 +96,9 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray
//
var EQUIP_RADIUS = 0.1; // radius used for palm vs equip-hotspot for equipping.
-var EQUIP_HOTSPOT_RENDER_RADIUS = 0.3; // radius used for palm vs equip-hotspot for rendering hot-spots
+// if EQUIP_HOTSPOT_RENDER_RADIUS is greater than zero, the hotspot will appear before the hand
+// has reached the required position, and then grow larger once the hand is close enough to equip.
+var EQUIP_HOTSPOT_RENDER_RADIUS = 0.0; // radius used for palm vs equip-hotspot for rendering hot-spots
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
@@ -110,13 +112,11 @@ var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-g
// if an equipped item is "adjusted" to be too far from the hand it's in, it will be unequipped.
var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks
-var AUTO_UNEQUIP_DISTANCE_FACTOR = 1.2; // multiplied by maximum dimension of held item, > this means drop
//
// other constants
//
-var HOTSPOT_DRAW_DISTANCE = 10;
var RIGHT_HAND = 1;
var LEFT_HAND = 0;
@@ -1619,7 +1619,7 @@ function MyController(hand) {
z: 0
};
- var DROP_ANGLE = Math.PI / 7;
+ var DROP_ANGLE = Math.PI / 6;
var HYSTERESIS_FACTOR = 1.1;
var ROTATION_ENTER_THRESHOLD = Math.cos(DROP_ANGLE);
var ROTATION_EXIT_THRESHOLD = Math.cos(DROP_ANGLE * HYSTERESIS_FACTOR);
@@ -2204,28 +2204,13 @@ function MyController(hand) {
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity", "dynamic", "shapeType"]);
var parentID = props.parentID;
- var doSetVelocity = false;
- if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID && propsArePhysical(props)) {
- // TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
- // props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
- // is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab
- // can be thrown.
- doSetVelocity = true;
- }
-
if (!noVelocity &&
- !doSetVelocity &&
parentID == MyAvatar.sessionUUID &&
Vec3.length(data["gravity"]) > 0.0 &&
data["dynamic"] &&
data["parentID"] == NULL_UUID &&
!data["collisionless"]) {
- deactiveProps["velocity"] = {
- x: 0.0,
- y: 0.1,
- z: 0.0
- };
- doSetVelocity = false;
+ deactiveProps["velocity"] = this.currentVelocity;
}
if (noVelocity) {
deactiveProps["velocity"] = {
@@ -2238,21 +2223,9 @@ function MyController(hand) {
y: 0.0,
z: 0.0
};
- doSetVelocity = false;
}
Entities.editEntity(entityID, deactiveProps);
-
- if (doSetVelocity) {
- // this is a continuation of the TODO above -- we shouldn't need to set this here.
- // do this after the parent has been reset. setting this at the same time as
- // the parent causes it to go off in the wrong direction. This is a bug that should
- // be fixed.
- Entities.editEntity(entityID, {
- velocity: this.currentVelocity
- // angularVelocity: this.currentAngularVelocity
- });
- }
data = null;
} else if (this.shouldResetParentOnRelease) {
// we parent-grabbed this from another parent grab. try to put it back where we found it.
diff --git a/scripts/system/edit.js b/scripts/system/edit.js
index 19460b409b..a3e5476bf9 100644
--- a/scripts/system/edit.js
+++ b/scripts/system/edit.js
@@ -1128,37 +1128,40 @@ function handeMenuEvent(menuItem) {
}
tooltip.show(false);
}
-
-// This function tries to find a reasonable position to place a new entity based on the camera
-// position. If a reasonable position within the world bounds can't be found, `null` will
-// be returned. The returned position will also take into account grid snapping settings.
function getPositionToCreateEntity() {
- var distance = cameraManager.enabled ? cameraManager.zoomDistance : DEFAULT_ENTITY_DRAG_DROP_DISTANCE;
- var direction = Quat.getFront(Camera.orientation);
- var offset = Vec3.multiply(distance, direction);
- var placementPosition = Vec3.sum(Camera.position, offset);
-
- var cameraPosition = Camera.position;
-
var HALF_TREE_SCALE = 16384;
+ var direction = Quat.getFront(MyAvatar.orientation);
+ var distance = 1;
+ var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, distance));
- var cameraOutOfBounds = Math.abs(cameraPosition.x) > HALF_TREE_SCALE || Math.abs(cameraPosition.y) > HALF_TREE_SCALE ||
- Math.abs(cameraPosition.z) > HALF_TREE_SCALE;
- var placementOutOfBounds = Math.abs(placementPosition.x) > HALF_TREE_SCALE ||
- Math.abs(placementPosition.y) > HALF_TREE_SCALE ||
- Math.abs(placementPosition.z) > HALF_TREE_SCALE;
-
- if (cameraOutOfBounds && placementOutOfBounds) {
- return null;
+ if (Camera.mode === "entity" || Camera.mode === "independent") {
+ position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), distance))
}
-
- placementPosition.x = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.x));
- placementPosition.y = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.y));
- placementPosition.z = Math.min(HALF_TREE_SCALE, Math.max(-HALF_TREE_SCALE, placementPosition.z));
-
- return placementPosition;
+ position.y += 0.5;
+ if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
+ return null
+ }
+ return position;
}
+function getPositionToImportEntity() {
+ var dimensions = Clipboard.getContentsDimensions();
+ var HALF_TREE_SCALE = 16384;
+ var direction = Quat.getFront(MyAvatar.orientation);
+ var longest = 1;
+ longest = Math.sqrt(Math.pow(dimensions.x, 2) + Math.pow(dimensions.z, 2));
+ var position = Vec3.sum(MyAvatar.position, Vec3.multiply(direction, longest));
+
+ if (Camera.mode === "entity" || Camera.mode === "independent") {
+ position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getFront(Camera.orientation), longest))
+ }
+
+ if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) {
+ return null
+ }
+
+ return position;
+}
function importSVO(importURL) {
print("Import URL requested: " + importURL);
if (!Entities.canAdjustLocks()) {
@@ -1183,7 +1186,7 @@ function importSVO(importURL) {
z: 0
};
if (Clipboard.getClipboardContentsLargestDimension() < VERY_LARGE) {
- position = getPositionToCreateEntity();
+ position = getPositionToImportEntity();
}
if (position !== null && position !== undefined) {
var pastedEntityIDs = Clipboard.pasteEntities(position);
diff --git a/server-console/src/log.html b/server-console/src/log.html
index f704f3e35f..3ccf8112e8 100644
--- a/server-console/src/log.html
+++ b/server-console/src/log.html
@@ -8,6 +8,7 @@
+
diff --git a/server-console/src/log.js b/server-console/src/log.js
index 3634eaeaa7..455b6828d8 100644
--- a/server-console/src/log.js
+++ b/server-console/src/log.js
@@ -43,6 +43,7 @@ ready = function() {
var domainServer = remote.getGlobal('domainServer');
var acMonitor = remote.getGlobal('acMonitor');
+ var openLogDirectory = remote.getGlobal('openLogDirectory');
var pendingLines = {
'ds': new Array(),
@@ -218,6 +219,12 @@ ready = function() {
appendLogMessages('ac');
}
+ // Binding a remote function directly does not work, so bind to a function
+ // that calls the remote function.
+ $('#view-logs').on('click', function() {
+ openLogDirectory();
+ });
+
// handle filtering of table rows on input change
$('#search-input').on('input', function() {
filter = $(this).val().toLowerCase();
diff --git a/server-console/src/main.js b/server-console/src/main.js
index 8f85872d0b..c47308aed6 100644
--- a/server-console/src/main.js
+++ b/server-console/src/main.js
@@ -285,6 +285,10 @@ function openFileBrowser(path) {
}
}
+function openLogDirectory() {
+ openFileBrowser(logPath);
+}
+
// NOTE: this looks like it does nothing, but it's very important.
// Without it the default behaviour is to quit the app once all windows closed
// which is absolutely not what we want for a taskbar application.
@@ -309,6 +313,7 @@ global.homeServer = null;
global.domainServer = null;
global.acMonitor = null;
global.userConfig = userConfig;
+global.openLogDirectory = openLogDirectory;
var LogWindow = function(ac, ds) {
this.ac = ac;
diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp
index 19dd875026..eec7e994ae 100644
--- a/tests/render-perf/src/main.cpp
+++ b/tests/render-perf/src/main.cpp
@@ -345,10 +345,6 @@ namespace render {
break;
}
}
-
- // Fall through: if no skybox is available, render the SKY_DOME
- case model::SunSkyStage::SKY_DOME:
- case model::SunSkyStage::NO_BACKGROUND:
default:
// this line intentionally left blank
break;