mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 13:26:28 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into update-discovery-from-master2
This commit is contained in:
commit
b8b345fb43
47 changed files with 579 additions and 258 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -172,6 +172,7 @@ protected:
|
|||
|
||||
QString _persistFilePath;
|
||||
QString _persistAsFileType;
|
||||
QString _backupDirectoryPath;
|
||||
int _packetsPerClientPerInterval;
|
||||
int _packetsTotalPerInterval;
|
||||
OctreePointer _tree; // this IS a reaveraging tree
|
||||
|
|
|
@ -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.<br/>If this path is relative it will be relative to the application data directory.",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "persistInterval",
|
||||
"label": "Save Check Interval",
|
||||
|
|
|
@ -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 @@
|
|||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
InfoItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
|
|
|
@ -78,7 +78,7 @@ Item {
|
|||
placeholderText: "Choose your own"
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
InfoItem {
|
||||
id: termsContainer
|
||||
anchors {
|
||||
top: textField.bottom
|
||||
|
|
|
@ -44,7 +44,7 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
InfoItem {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: parent.top
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// MenuItem.qml
|
||||
// InfoItem.qml
|
||||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2016 High Fidelity, Inc.
|
|
@ -838,7 +838,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
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<EntityScriptingInterface>();
|
||||
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<NodeList>()->soloNodeOfType(NodeType::EntityServer);
|
||||
return entityServerNode && !isPhysicsEnabled();
|
||||
});
|
||||
|
||||
// After all of the constructor is completed, then set firstRun to false.
|
||||
Setting::Handle<bool> 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<SceneScriptingInterface>()->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<SceneScriptingInterface>()->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<SceneScriptingInterface>()->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<SceneScriptingInterface>()->getSkyStage();
|
||||
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||
skyStage->setBackgroundMode(model::SunSkyStage::SKY_DEFAULT);
|
||||
|
||||
_recentlyClearedDomain = true;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -23,6 +23,7 @@ Line3DOverlay::Line3DOverlay() :
|
|||
|
||||
Line3DOverlay::Line3DOverlay(const Line3DOverlay* line3DOverlay) :
|
||||
Base3DOverlay(line3DOverlay),
|
||||
_start(line3DOverlay->_start),
|
||||
_end(line3DOverlay->_end),
|
||||
_geometryCacheID(DependencyManager::get<GeometryCache>()->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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -346,15 +346,13 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
auto sceneStage = scene->getStage();
|
||||
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<ProceduralSkybox>(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_ptr<ZoneEntityIt
|
|||
_pendingAmbientTexture = false;
|
||||
_ambientTexture.clear();
|
||||
|
||||
if (_hasPreviousZone) {
|
||||
sceneKeyLight->resetAmbientSphere();
|
||||
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_ptr<ZoneEntityIt
|
|||
}
|
||||
}
|
||||
|
||||
// Set the skybox texture
|
||||
switch (zone->getBackgroundMode()) {
|
||||
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_ptr<ZoneEntityIt
|
|||
case BACKGROUND_MODE_INHERIT:
|
||||
default:
|
||||
// Clear the skybox to release its textures
|
||||
userData = QString();
|
||||
_zoneUserData = QString();
|
||||
skybox->clear();
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
|
|
|
@ -185,25 +185,15 @@ private:
|
|||
|
||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||
|
||||
bool _hasPreviousZone { false };
|
||||
std::shared_ptr<ZoneEntityItem> _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<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||
// For Scene.shouldRenderEntities
|
||||
QList<EntityItemID> _entityIDsLastInScene;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
int EntityItem::_maxActionsDataSize = 800;
|
||||
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
|
||||
std::function<bool()> EntityItem::_entitiesShouldFadeFunction = [](){ return true; };
|
||||
|
||||
EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||
SpatiallyNestable(NestableType::Entity, entityItemID),
|
||||
|
|
|
@ -432,6 +432,8 @@ public:
|
|||
QUuid getOwningAvatarID() const { return _owningAvatarID; }
|
||||
void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
|
||||
|
||||
static void setEntitiesShouldFadeFunction(std::function<bool()> func) { _entitiesShouldFadeFunction = func; }
|
||||
static std::function<bool()> 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<bool()> _entitiesShouldFadeFunction;
|
||||
bool _isFading { _entitiesShouldFadeFunction() };
|
||||
};
|
||||
|
||||
#endif // hifi_EntityItem_h
|
||||
|
|
|
@ -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<bool>);
|
||||
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>);
|
||||
|
@ -1982,7 +1990,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
}
|
||||
|
||||
bool EntityItemProperties::parentDependentPropertyChanged() const {
|
||||
return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged();
|
||||
return localPositionChanged() || positionChanged() ||
|
||||
localRotationChanged() || rotationChanged() ||
|
||||
localVelocityChanged() || localAngularVelocityChanged();
|
||||
}
|
||||
|
||||
bool EntityItemProperties::parentRelatedPropertyChanged() const {
|
||||
|
|
|
@ -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<bool>, QVector<bool>());
|
||||
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>, QVector<glm::quat>());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<NodeList>();
|
||||
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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "FBXReader.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QDataStream>
|
||||
#include <QIODevice>
|
||||
|
@ -20,9 +24,8 @@
|
|||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include "FBXReader.h"
|
||||
|
||||
#include <memory>
|
||||
#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();
|
||||
|
|
|
@ -293,10 +293,18 @@ public:
|
|||
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); }
|
||||
#else
|
||||
template <typename T> Iterator<const T> begin() const { return Iterator<const T>(&get<T>(), _stride); }
|
||||
template <typename T> Iterator<const T> end() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
|
||||
template <typename T> Iterator<const T> end() const {
|
||||
// reimplement get<T> without bounds checking
|
||||
Resource::Size elementOffset = getNum<T>() * _stride + _offset;
|
||||
return Iterator<const T>((reinterpret_cast<const T*> (_buffer->getData() + elementOffset)), _stride);
|
||||
}
|
||||
#endif
|
||||
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(), _stride); }
|
||||
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
|
||||
template <typename T> Iterator<const T> cend() const {
|
||||
// reimplement get<T> without bounds checking
|
||||
Resource::Size elementOffset = getNum<T>() * _stride + _offset;
|
||||
return Iterator<const T>((reinterpret_cast<const T*> (_buffer->getData() + elementOffset)), _stride);
|
||||
}
|
||||
|
||||
// the number of elements of the specified type fitting in the view size
|
||||
template <typename T> Index getNum() const {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<udt::BasePacket> packet);
|
||||
|
||||
void handleNodeKill(const SharedNodePointer& node);
|
||||
|
|
|
@ -294,7 +294,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer<ReceivedMessage> 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<ReceivedMessage> 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) {
|
||||
|
|
|
@ -67,9 +67,6 @@ public:
|
|||
void handleVerifiedPacket(std::unique_ptr<udt::Packet> packet);
|
||||
void handleVerifiedMessagePacket(std::unique_ptr<udt::Packet> message);
|
||||
void handleMessageFailure(HifiSockAddr from, udt::Packet::MessageNumber messageNumber);
|
||||
|
||||
signals:
|
||||
void dataReceived(quint8 channelType, int bytes);
|
||||
|
||||
private:
|
||||
struct Listener {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,6 @@ public:
|
|||
private:
|
||||
quint64 _fadeStartTime { 0 };
|
||||
bool _hasStartedFade { false };
|
||||
mutable bool _prevHasStartedFade{ false };
|
||||
mutable bool _hasFinishedFade { false };
|
||||
mutable bool _isFading { false };
|
||||
};
|
||||
|
|
|
@ -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<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
if (!parentFinder) {
|
||||
return nullptr;
|
||||
}
|
||||
SpatiallyNestableWeakPointer parentWP = parentFinder->find(id, success);
|
||||
if (!success) {
|
||||
return nullptr;
|
||||
}
|
||||
return parentWP.lock();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<uint32_t>(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<mat4, 2> 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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<body onload="ready()">
|
||||
<div class="search">
|
||||
<input id="search-input" placeholder="filter" />
|
||||
<button id="view-logs">Open Log Directory</button>
|
||||
</div>
|
||||
|
||||
<ul class="tabs top">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue