mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 03:08:00 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into entityPropertiesRefactor
This commit is contained in:
commit
b3e0d51260
23 changed files with 1369 additions and 350 deletions
140
interface/resources/avatar/network-animation.json
Normal file
140
interface/resources/avatar/network-animation.json
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
{
|
||||||
|
"version": "1.1",
|
||||||
|
"root": {
|
||||||
|
"id": "userAnimStateMachine",
|
||||||
|
"type": "stateMachine",
|
||||||
|
"data": {
|
||||||
|
"currentState": "idleAnim",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "idleAnim",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "postTransitAnim", "state": "postTransitAnim" },
|
||||||
|
{ "var": "preTransitAnim", "state": "preTransitAnim" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "preTransitAnim",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "idleAnim", "state": "idleAnim" },
|
||||||
|
{ "var": "transitAnim", "state": "transitAnim" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transitAnim",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "preTransitAnim", "state": "preTransitAnim" },
|
||||||
|
{ "var": "postTransitAnim", "state": "postTransitAnim" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "postTransitAnim",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "transitAnim", "state": "transitAnim" },
|
||||||
|
{ "var": "idleAnim", "state": "idleAnim" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "userAnimA",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "idleAnim", "state": "idleAnim" },
|
||||||
|
{ "var": "userAnimB", "state": "userAnimB" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "userAnimB",
|
||||||
|
"interpTarget": 6,
|
||||||
|
"interpDuration": 6,
|
||||||
|
"transitions": [
|
||||||
|
{ "var": "idleAnim", "state": "idleAnim" },
|
||||||
|
{ "var": "userAnimA", "state": "userAnimA" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "idleAnim",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "qrc:///avatar/animations/idle.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 90.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "preTransitAnim",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 10.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": false
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transitAnim",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||||
|
"startFrame": 11.0,
|
||||||
|
"endFrame": 11.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "postTransitAnim",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||||
|
"startFrame": 22.0,
|
||||||
|
"endFrame": 49.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": false
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "userAnimA",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "qrc:///avatar/animations/idle.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 90.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "userAnimB",
|
||||||
|
"type": "clip",
|
||||||
|
"data": {
|
||||||
|
"url": "qrc:///avatar/animations/idle.fbx",
|
||||||
|
"startFrame": 0.0,
|
||||||
|
"endFrame": 90.0,
|
||||||
|
"timeScale": 1.0,
|
||||||
|
"loopFlag": true
|
||||||
|
},
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ Item {
|
||||||
property int modality: Qt.NonModal
|
property int modality: Qt.NonModal
|
||||||
implicitHeight: row.height
|
implicitHeight: row.height
|
||||||
implicitWidth: row.width
|
implicitWidth: row.width
|
||||||
|
visible: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
stats.parentChanged.connect(fill);
|
stats.parentChanged.connect(fill);
|
||||||
|
|
|
@ -135,7 +135,7 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
||||||
glm::vec3 palmPosition;
|
glm::vec3 palmPosition;
|
||||||
glm::quat palmRotation;
|
glm::quat palmRotation;
|
||||||
|
|
||||||
bool isTransitingWithAvatar = holdingAvatar->getTransit()->isTransiting();
|
bool isTransitingWithAvatar = holdingAvatar->getTransit()->isActive();
|
||||||
if (isTransitingWithAvatar != _isTransitingWithAvatar) {
|
if (isTransitingWithAvatar != _isTransitingWithAvatar) {
|
||||||
_isTransitingWithAvatar = isTransitingWithAvatar;
|
_isTransitingWithAvatar = isTransitingWithAvatar;
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
|
@ -424,7 +424,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
if (ownerEntity) {
|
if (ownerEntity) {
|
||||||
ownerEntity->setDynamicDataDirty(true);
|
ownerEntity->setDynamicDataDirty(true);
|
||||||
ownerEntity->setDynamicDataNeedsTransmit(true);
|
ownerEntity->setDynamicDataNeedsTransmit(true);
|
||||||
ownerEntity->setTransitingWithAvatar(myAvatar->getTransit()->isTransiting());
|
ownerEntity->setTransitingWithAvatar(myAvatar->getTransit()->isActive());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,14 +71,12 @@ AvatarManager::AvatarManager(QObject* parent) :
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const float AVATAR_TRANSIT_TRIGGER_DISTANCE = 1.0f;
|
|
||||||
const int AVATAR_TRANSIT_FRAME_COUNT = 11; // Based on testing
|
|
||||||
const int AVATAR_TRANSIT_FRAMES_PER_METER = 1; // Based on testing
|
|
||||||
|
|
||||||
_transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT;
|
_transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT;
|
||||||
_transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE;
|
_transitConfig._minTriggerDistance = AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE;
|
||||||
|
_transitConfig._maxTriggerDistance = AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE;
|
||||||
_transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER;
|
_transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER;
|
||||||
_transitConfig._isDistanceBased = true;
|
_transitConfig._isDistanceBased = AVATAR_TRANSIT_DISTANCE_BASED;
|
||||||
|
_transitConfig._abortDistance = AVATAR_TRANSIT_ABORT_DISTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||||
|
@ -126,13 +124,39 @@ void AvatarManager::setSpace(workload::SpacePointer& space ) {
|
||||||
_space = space;
|
_space = space;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarManager::handleTransitAnimations(AvatarTransit::Status status) {
|
||||||
|
switch (status) {
|
||||||
|
case AvatarTransit::Status::STARTED:
|
||||||
|
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("preTransitAnim");
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::START_TRANSIT:
|
||||||
|
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("transitAnim");
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::END_TRANSIT:
|
||||||
|
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("postTransitAnim");
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::ENDED:
|
||||||
|
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("idleAnim");
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::PRE_TRANSIT:
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::POST_TRANSIT:
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::IDLE:
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::TRANSITING:
|
||||||
|
break;
|
||||||
|
case AvatarTransit::Status::ABORT_TRANSIT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
||||||
|
|
||||||
AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getNextPosition(), _transitConfig);
|
AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getNextPosition(), _myAvatar->getSensorToWorldScale(), _transitConfig);
|
||||||
bool sendFirstTransitPackage = (status == AvatarTransit::Status::START_TRANSIT);
|
handleTransitAnimations(status);
|
||||||
bool blockTransitData = (status == AvatarTransit::Status::TRANSITING);
|
|
||||||
|
|
||||||
_myAvatar->update(deltaTime);
|
_myAvatar->update(deltaTime);
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
|
@ -142,18 +166,13 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
quint64 dt = now - _lastSendAvatarDataTime;
|
quint64 dt = now - _lastSendAvatarDataTime;
|
||||||
|
|
||||||
|
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
|
||||||
if (sendFirstTransitPackage || (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused && !blockTransitData)) {
|
|
||||||
// send head/hand data to the avatar mixer and voxel server
|
// send head/hand data to the avatar mixer and voxel server
|
||||||
PerformanceTimer perfTimer("send");
|
PerformanceTimer perfTimer("send");
|
||||||
if (sendFirstTransitPackage) {
|
|
||||||
_myAvatar->overrideNextPackagePositionData(_myAvatar->getTransit()->getEndPosition());
|
|
||||||
}
|
|
||||||
_myAvatar->sendAvatarDataPacket();
|
_myAvatar->sendAvatarDataPacket();
|
||||||
_lastSendAvatarDataTime = now;
|
_lastSendAvatarDataTime = now;
|
||||||
_myAvatarSendRate.increment();
|
_myAvatarSendRate.increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,7 +286,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
if (inView && avatar->hasNewJointData()) {
|
if (inView && avatar->hasNewJointData()) {
|
||||||
numAvatarsUpdated++;
|
numAvatarsUpdated++;
|
||||||
}
|
}
|
||||||
auto transitStatus = avatar->_transit.update(deltaTime, avatar->_globalPosition, _transitConfig);
|
auto transitStatus = avatar->_transit.update(deltaTime, avatar->_serverPosition, _transitConfig);
|
||||||
if (avatar->getIsNewAvatar() && (transitStatus == AvatarTransit::Status::START_TRANSIT || transitStatus == AvatarTransit::Status::ABORT_TRANSIT)) {
|
if (avatar->getIsNewAvatar() && (transitStatus == AvatarTransit::Status::START_TRANSIT || transitStatus == AvatarTransit::Status::ABORT_TRANSIT)) {
|
||||||
avatar->_transit.reset();
|
avatar->_transit.reset();
|
||||||
avatar->setIsNewAvatar(false);
|
avatar->setIsNewAvatar(false);
|
||||||
|
|
|
@ -221,6 +221,7 @@ private:
|
||||||
// frequently grabs a read lock on the hash to get a given avatar by ID
|
// frequently grabs a read lock on the hash to get a given avatar by ID
|
||||||
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar,
|
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar,
|
||||||
KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
||||||
|
void handleTransitAnimations(AvatarTransit::Status status);
|
||||||
|
|
||||||
QVector<AvatarSharedPointer> _avatarsToFade;
|
QVector<AvatarSharedPointer> _avatarsToFade;
|
||||||
|
|
||||||
|
|
|
@ -1058,7 +1058,6 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||||
|
|
||||||
if (hasSensorToWorldScaleChanged) {
|
if (hasSensorToWorldScaleChanged) {
|
||||||
setTransitScale(sensorToWorldScale);
|
|
||||||
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@ public:
|
||||||
bool getMirrorFlag() const { return _mirrorFlag; }
|
bool getMirrorFlag() const { return _mirrorFlag; }
|
||||||
void setMirrorFlag(bool mirrorFlag) { _mirrorFlag = mirrorFlag; }
|
void setMirrorFlag(bool mirrorFlag) { _mirrorFlag = mirrorFlag; }
|
||||||
|
|
||||||
|
float getFrame() const { return _frame; }
|
||||||
|
|
||||||
void loadURL(const QString& url);
|
void loadURL(const QString& url);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "AnimSkeleton.h"
|
#include "AnimSkeleton.h"
|
||||||
#include "AnimUtil.h"
|
#include "AnimUtil.h"
|
||||||
#include "IKTarget.h"
|
#include "IKTarget.h"
|
||||||
|
#include "PathUtils.h"
|
||||||
|
|
||||||
|
|
||||||
static int nextRigId = 1;
|
static int nextRigId = 1;
|
||||||
|
@ -133,6 +134,30 @@ void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firs
|
||||||
_animVars.set("userAnimB", clipNodeEnum == UserAnimState::B);
|
_animVars.set("userAnimB", clipNodeEnum == UserAnimState::B);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rig::triggerNetworkAnimation(const QString& animName) {
|
||||||
|
_networkVars.set("idleAnim", false);
|
||||||
|
_networkVars.set("preTransitAnim", false);
|
||||||
|
_networkVars.set("transitAnim", false);
|
||||||
|
_networkVars.set("postTransitAnim", false);
|
||||||
|
_sendNetworkNode = true;
|
||||||
|
|
||||||
|
if (animName == "idleAnim") {
|
||||||
|
_networkVars.set("idleAnim", true);
|
||||||
|
_networkAnimState.clipNodeEnum = NetworkAnimState::Idle;
|
||||||
|
_sendNetworkNode = false;
|
||||||
|
} else if (animName == "preTransitAnim") {
|
||||||
|
_networkVars.set("preTransitAnim", true);
|
||||||
|
_networkAnimState.clipNodeEnum = NetworkAnimState::PreTransit;
|
||||||
|
} else if (animName == "transitAnim") {
|
||||||
|
_networkVars.set("transitAnim", true);
|
||||||
|
_networkAnimState.clipNodeEnum = NetworkAnimState::Transit;
|
||||||
|
} else if (animName == "postTransitAnim") {
|
||||||
|
_networkVars.set("postTransitAnim", true);
|
||||||
|
_networkAnimState.clipNodeEnum = NetworkAnimState::PostTransit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Rig::restoreAnimation() {
|
void Rig::restoreAnimation() {
|
||||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||||
_userAnimState.clipNodeEnum = UserAnimState::None;
|
_userAnimState.clipNodeEnum = UserAnimState::None;
|
||||||
|
@ -144,6 +169,16 @@ void Rig::restoreAnimation() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rig::restoreNetworkAnimation() {
|
||||||
|
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||||
|
_networkAnimState.clipNodeEnum = NetworkAnimState::Idle;
|
||||||
|
_networkVars.set("idleAnim", true);
|
||||||
|
_networkVars.set("preTransitAnim", false);
|
||||||
|
_networkVars.set("transitAnim", false);
|
||||||
|
_networkVars.set("postTransitAnim", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList Rig::getAnimationRoles() const {
|
QStringList Rig::getAnimationRoles() const {
|
||||||
if (_animNode) {
|
if (_animNode) {
|
||||||
QStringList list;
|
QStringList list;
|
||||||
|
@ -208,11 +243,17 @@ void Rig::restoreRoleAnimation(const QString& role) {
|
||||||
void Rig::destroyAnimGraph() {
|
void Rig::destroyAnimGraph() {
|
||||||
_animSkeleton.reset();
|
_animSkeleton.reset();
|
||||||
_animLoader.reset();
|
_animLoader.reset();
|
||||||
|
_networkLoader.reset();
|
||||||
_animNode.reset();
|
_animNode.reset();
|
||||||
_internalPoseSet._relativePoses.clear();
|
_internalPoseSet._relativePoses.clear();
|
||||||
_internalPoseSet._absolutePoses.clear();
|
_internalPoseSet._absolutePoses.clear();
|
||||||
_internalPoseSet._overridePoses.clear();
|
_internalPoseSet._overridePoses.clear();
|
||||||
_internalPoseSet._overrideFlags.clear();
|
_internalPoseSet._overrideFlags.clear();
|
||||||
|
_networkNode.reset();
|
||||||
|
_networkPoseSet._relativePoses.clear();
|
||||||
|
_networkPoseSet._absolutePoses.clear();
|
||||||
|
_networkPoseSet._overridePoses.clear();
|
||||||
|
_networkPoseSet._overrideFlags.clear();
|
||||||
_numOverrides = 0;
|
_numOverrides = 0;
|
||||||
_leftEyeJointChildren.clear();
|
_leftEyeJointChildren.clear();
|
||||||
_rightEyeJointChildren.clear();
|
_rightEyeJointChildren.clear();
|
||||||
|
@ -229,14 +270,24 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
|
||||||
|
|
||||||
_internalPoseSet._relativePoses.clear();
|
_internalPoseSet._relativePoses.clear();
|
||||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
_networkPoseSet._relativePoses.clear();
|
||||||
|
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||||
|
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||||
|
|
||||||
_internalPoseSet._overridePoses.clear();
|
_internalPoseSet._overridePoses.clear();
|
||||||
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
_internalPoseSet._overrideFlags.clear();
|
_internalPoseSet._overrideFlags.clear();
|
||||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||||
|
|
||||||
|
_networkPoseSet._overridePoses.clear();
|
||||||
|
_networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
|
_networkPoseSet._overrideFlags.clear();
|
||||||
|
_networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||||
|
|
||||||
_numOverrides = 0;
|
_numOverrides = 0;
|
||||||
|
|
||||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||||
|
@ -270,6 +321,18 @@ void Rig::reset(const FBXGeometry& geometry) {
|
||||||
|
|
||||||
_internalPoseSet._overrideFlags.clear();
|
_internalPoseSet._overrideFlags.clear();
|
||||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||||
|
|
||||||
|
_networkPoseSet._relativePoses.clear();
|
||||||
|
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
|
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||||
|
|
||||||
|
_networkPoseSet._overridePoses.clear();
|
||||||
|
_networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
|
||||||
|
_networkPoseSet._overrideFlags.clear();
|
||||||
|
_networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||||
|
|
||||||
_numOverrides = 0;
|
_numOverrides = 0;
|
||||||
|
|
||||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||||
|
@ -1049,26 +1112,56 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
|
||||||
|
|
||||||
updateAnimationStateHandlers();
|
updateAnimationStateHandlers();
|
||||||
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
||||||
|
if (_networkNode) {
|
||||||
|
_networkVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
||||||
|
}
|
||||||
AnimContext context(_enableDebugDrawIKTargets, _enableDebugDrawIKConstraints, _enableDebugDrawIKChains,
|
AnimContext context(_enableDebugDrawIKTargets, _enableDebugDrawIKConstraints, _enableDebugDrawIKChains,
|
||||||
getGeometryToRigTransform(), rigToWorldTransform);
|
getGeometryToRigTransform(), rigToWorldTransform);
|
||||||
|
|
||||||
// evaluate the animation
|
// evaluate the animation
|
||||||
AnimVariantMap triggersOut;
|
AnimVariantMap triggersOut;
|
||||||
|
AnimVariantMap networkTriggersOut;
|
||||||
_internalPoseSet._relativePoses = _animNode->evaluate(_animVars, context, deltaTime, triggersOut);
|
_internalPoseSet._relativePoses = _animNode->evaluate(_animVars, context, deltaTime, triggersOut);
|
||||||
|
if (_networkNode) {
|
||||||
|
_networkPoseSet._relativePoses = _networkNode->evaluate(_networkVars, context, deltaTime, networkTriggersOut);
|
||||||
|
const float NETWORK_ANIMATION_BLEND_FRAMES = 6.0f;
|
||||||
|
float alpha = 1.0f;
|
||||||
|
std::shared_ptr<AnimClip> clip;
|
||||||
|
if (_networkAnimState.clipNodeEnum == NetworkAnimState::PreTransit) {
|
||||||
|
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("preTransitAnim"));
|
||||||
|
if (clip) {
|
||||||
|
alpha = (clip->getFrame() - clip->getStartFrame()) / NETWORK_ANIMATION_BLEND_FRAMES;
|
||||||
|
}
|
||||||
|
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::PostTransit) {
|
||||||
|
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("postTransitAnim"));
|
||||||
|
if (clip) {
|
||||||
|
alpha = (clip->getEndFrame() - clip->getFrame()) / NETWORK_ANIMATION_BLEND_FRAMES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_sendNetworkNode) {
|
||||||
|
for (size_t i = 0; i < _networkPoseSet._relativePoses.size(); i++) {
|
||||||
|
_networkPoseSet._relativePoses[i].blend(_internalPoseSet._relativePoses[i], (alpha > 1.0f ? 1.0f : alpha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||||
// animations haven't fully loaded yet.
|
// animations haven't fully loaded yet.
|
||||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
}
|
}
|
||||||
|
if ((int)_networkPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||||
|
// animations haven't fully loaded yet.
|
||||||
|
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||||
|
}
|
||||||
_lastAnimVars = _animVars;
|
_lastAnimVars = _animVars;
|
||||||
_animVars.clearTriggers();
|
_animVars.clearTriggers();
|
||||||
_animVars = triggersOut;
|
_animVars = triggersOut;
|
||||||
|
_networkVars.clearTriggers();
|
||||||
|
_networkVars = networkTriggersOut;
|
||||||
_lastContext = context;
|
_lastContext = context;
|
||||||
}
|
}
|
||||||
applyOverridePoses();
|
applyOverridePoses();
|
||||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||||
|
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||||
// copy internal poses to external poses
|
// copy internal poses to external poses
|
||||||
{
|
{
|
||||||
QWriteLocker writeLock(&_externalPoseSetLock);
|
QWriteLocker writeLock(&_externalPoseSetLock);
|
||||||
|
@ -1672,11 +1765,14 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
_animGraphURL = url;
|
_animGraphURL = url;
|
||||||
|
|
||||||
_animNode.reset();
|
_animNode.reset();
|
||||||
|
_networkNode.reset();
|
||||||
|
|
||||||
// load the anim graph
|
// load the anim graph
|
||||||
_animLoader.reset(new AnimNodeLoader(url));
|
_animLoader.reset(new AnimNodeLoader(url));
|
||||||
|
auto networkUrl = PathUtils::resourcesUrl("avatar/network-animation.json");
|
||||||
|
_networkLoader.reset(new AnimNodeLoader(networkUrl));
|
||||||
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
||||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) {
|
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr, url](AnimNode::Pointer nodeIn) {
|
||||||
_animNode = nodeIn;
|
_animNode = nodeIn;
|
||||||
|
|
||||||
// abort load if the previous skeleton was deleted.
|
// abort load if the previous skeleton was deleted.
|
||||||
|
@ -1703,7 +1799,33 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
emit onLoadComplete();
|
emit onLoadComplete();
|
||||||
});
|
});
|
||||||
connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) {
|
connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) {
|
||||||
qCCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str;
|
qCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str;
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(_networkLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr, networkUrl](AnimNode::Pointer nodeIn) {
|
||||||
|
_networkNode = nodeIn;
|
||||||
|
// abort load if the previous skeleton was deleted.
|
||||||
|
auto sharedSkeletonPtr = weakSkeletonPtr.lock();
|
||||||
|
if (!sharedSkeletonPtr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_networkNode->setSkeleton(sharedSkeletonPtr);
|
||||||
|
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||||
|
// restore the user animation we had before reset.
|
||||||
|
NetworkAnimState origState = _networkAnimState;
|
||||||
|
_networkAnimState = { NetworkAnimState::Idle, "", 30.0f, false, 0.0f, 0.0f };
|
||||||
|
if (_networkAnimState.clipNodeEnum == NetworkAnimState::PreTransit) {
|
||||||
|
triggerNetworkAnimation("preTransitAnim");
|
||||||
|
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::Transit) {
|
||||||
|
triggerNetworkAnimation("transitAnim");
|
||||||
|
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::PostTransit) {
|
||||||
|
triggerNetworkAnimation("postTransitAnim");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) {
|
||||||
|
qCritical(animation) << "Error loading" << networkUrl.toDisplayString() << "code = " << error << "str =" << str;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1782,13 +1904,13 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
||||||
if (isIndexValid(i)) {
|
if (isIndexValid(i)) {
|
||||||
// rotations are in absolute rig frame.
|
// rotations are in absolute rig frame.
|
||||||
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
||||||
data.rotation = _internalPoseSet._absolutePoses[i].rot();
|
data.rotation = !_sendNetworkNode ? _internalPoseSet._absolutePoses[i].rot() : _networkPoseSet._absolutePoses[i].rot();
|
||||||
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
||||||
|
|
||||||
// translations are in relative frame but scaled so that they are in meters,
|
// translations are in relative frame but scaled so that they are in meters,
|
||||||
// instead of geometry units.
|
// instead of geometry units.
|
||||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||||
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
data.translation = _geometryOffset.scale() * (!_sendNetworkNode ? _internalPoseSet._relativePoses[i].trans() : _networkPoseSet._relativePoses[i].trans());
|
||||||
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||||
} else {
|
} else {
|
||||||
data.translationIsDefaultPose = true;
|
data.translationIsDefaultPose = true;
|
||||||
|
|
|
@ -113,7 +113,10 @@ public:
|
||||||
void destroyAnimGraph();
|
void destroyAnimGraph();
|
||||||
|
|
||||||
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||||
|
void triggerNetworkAnimation(const QString& animName);
|
||||||
void restoreAnimation();
|
void restoreAnimation();
|
||||||
|
void restoreNetworkAnimation();
|
||||||
|
|
||||||
QStringList getAnimationRoles() const;
|
QStringList getAnimationRoles() const;
|
||||||
void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||||
void restoreRoleAnimation(const QString& role);
|
void restoreRoleAnimation(const QString& role);
|
||||||
|
@ -269,6 +272,7 @@ protected:
|
||||||
|
|
||||||
// Only accessed by the main thread
|
// Only accessed by the main thread
|
||||||
PoseSet _internalPoseSet;
|
PoseSet _internalPoseSet;
|
||||||
|
PoseSet _networkPoseSet;
|
||||||
|
|
||||||
// Copy of the _poseSet for external threads.
|
// Copy of the _poseSet for external threads.
|
||||||
PoseSet _externalPoseSet;
|
PoseSet _externalPoseSet;
|
||||||
|
@ -300,9 +304,12 @@ protected:
|
||||||
|
|
||||||
QUrl _animGraphURL;
|
QUrl _animGraphURL;
|
||||||
std::shared_ptr<AnimNode> _animNode;
|
std::shared_ptr<AnimNode> _animNode;
|
||||||
|
std::shared_ptr<AnimNode> _networkNode;
|
||||||
std::shared_ptr<AnimSkeleton> _animSkeleton;
|
std::shared_ptr<AnimSkeleton> _animSkeleton;
|
||||||
std::unique_ptr<AnimNodeLoader> _animLoader;
|
std::unique_ptr<AnimNodeLoader> _animLoader;
|
||||||
|
std::unique_ptr<AnimNodeLoader> _networkLoader;
|
||||||
AnimVariantMap _animVars;
|
AnimVariantMap _animVars;
|
||||||
|
AnimVariantMap _networkVars;
|
||||||
|
|
||||||
enum class RigRole {
|
enum class RigRole {
|
||||||
Idle = 0,
|
Idle = 0,
|
||||||
|
@ -315,6 +322,25 @@ protected:
|
||||||
RigRole _state { RigRole::Idle };
|
RigRole _state { RigRole::Idle };
|
||||||
RigRole _desiredState { RigRole::Idle };
|
RigRole _desiredState { RigRole::Idle };
|
||||||
float _desiredStateAge { 0.0f };
|
float _desiredStateAge { 0.0f };
|
||||||
|
|
||||||
|
struct NetworkAnimState {
|
||||||
|
enum ClipNodeEnum {
|
||||||
|
Idle = 0,
|
||||||
|
PreTransit,
|
||||||
|
Transit,
|
||||||
|
PostTransit
|
||||||
|
};
|
||||||
|
NetworkAnimState() : clipNodeEnum(NetworkAnimState::Idle) {}
|
||||||
|
NetworkAnimState(ClipNodeEnum clipNodeEnumIn, const QString& urlIn, float fpsIn, bool loopIn, float firstFrameIn, float lastFrameIn) :
|
||||||
|
clipNodeEnum(clipNodeEnumIn), url(urlIn), fps(fpsIn), loop(loopIn), firstFrame(firstFrameIn), lastFrame(lastFrameIn) {}
|
||||||
|
|
||||||
|
ClipNodeEnum clipNodeEnum;
|
||||||
|
QString url;
|
||||||
|
float fps;
|
||||||
|
bool loop;
|
||||||
|
float firstFrame;
|
||||||
|
float lastFrame;
|
||||||
|
};
|
||||||
|
|
||||||
struct UserAnimState {
|
struct UserAnimState {
|
||||||
enum ClipNodeEnum {
|
enum ClipNodeEnum {
|
||||||
|
@ -349,6 +375,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
UserAnimState _userAnimState;
|
UserAnimState _userAnimState;
|
||||||
|
NetworkAnimState _networkAnimState;
|
||||||
std::map<QString, RoleAnimState> _roleAnimStates;
|
std::map<QString, RoleAnimState> _roleAnimStates;
|
||||||
|
|
||||||
float _leftHandOverlayAlpha { 0.0f };
|
float _leftHandOverlayAlpha { 0.0f };
|
||||||
|
@ -382,6 +409,7 @@ protected:
|
||||||
|
|
||||||
int _rigId;
|
int _rigId;
|
||||||
bool _headEnabled { false };
|
bool _headEnabled { false };
|
||||||
|
bool _sendNetworkNode { false };
|
||||||
|
|
||||||
AnimContext _lastContext;
|
AnimContext _lastContext;
|
||||||
AnimVariantMap _lastAnimVars;
|
AnimVariantMap _lastAnimVars;
|
||||||
|
|
|
@ -114,27 +114,29 @@ void Avatar::setShowNamesAboveHeads(bool show) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
|
AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
|
||||||
glm::vec3 currentPosition = _isTransiting ? _currentPosition : avatarPosition;
|
float oneFrameDistance = _isActive ? glm::length(avatarPosition - _endPosition) : glm::length(avatarPosition - _lastPosition);
|
||||||
float oneFrameDistance = glm::length(currentPosition - _lastPosition);
|
if (oneFrameDistance > (config._minTriggerDistance * _scale)) {
|
||||||
const float MAX_TRANSIT_DISTANCE = 30.0f;
|
if (oneFrameDistance < (config._maxTriggerDistance * _scale)) {
|
||||||
float scaledMaxTransitDistance = MAX_TRANSIT_DISTANCE * _scale;
|
start(deltaTime, _lastPosition, avatarPosition, config);
|
||||||
if (oneFrameDistance > config._triggerDistance && !_isTransiting) {
|
|
||||||
if (oneFrameDistance < scaledMaxTransitDistance) {
|
|
||||||
start(deltaTime, _lastPosition, currentPosition, config);
|
|
||||||
} else {
|
} else {
|
||||||
_lastPosition = currentPosition;
|
_lastPosition = avatarPosition;
|
||||||
return Status::ABORT_TRANSIT;
|
_status = Status::ABORT_TRANSIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_lastPosition = currentPosition;
|
_lastPosition = avatarPosition;
|
||||||
_status = updatePosition(deltaTime);
|
_status = updatePosition(deltaTime);
|
||||||
|
|
||||||
|
if (_isActive && oneFrameDistance > (config._abortDistance * _scale) && _status == Status::POST_TRANSIT) {
|
||||||
|
reset();
|
||||||
|
_status = Status::ENDED;
|
||||||
|
}
|
||||||
return _status;
|
return _status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarTransit::reset() {
|
void AvatarTransit::reset() {
|
||||||
_lastPosition = _endPosition;
|
_lastPosition = _endPosition;
|
||||||
_currentPosition = _endPosition;
|
_currentPosition = _endPosition;
|
||||||
_isTransiting = false;
|
_isActive = false;
|
||||||
}
|
}
|
||||||
void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) {
|
void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) {
|
||||||
_startPosition = startPosition;
|
_startPosition = startPosition;
|
||||||
|
@ -143,12 +145,14 @@ void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const
|
||||||
_transitLine = endPosition - startPosition;
|
_transitLine = endPosition - startPosition;
|
||||||
_totalDistance = glm::length(_transitLine);
|
_totalDistance = glm::length(_transitLine);
|
||||||
_easeType = config._easeType;
|
_easeType = config._easeType;
|
||||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
|
||||||
|
_preTransitTime = AVATAR_PRE_TRANSIT_FRAME_COUNT / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||||
|
_postTransitTime = AVATAR_POST_TRANSIT_FRAME_COUNT / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||||
int transitFrames = (!config._isDistanceBased) ? config._totalFrames : config._framesPerMeter * _totalDistance;
|
int transitFrames = (!config._isDistanceBased) ? config._totalFrames : config._framesPerMeter * _totalDistance;
|
||||||
_totalTime = (float)transitFrames / REFERENCE_FRAMES_PER_SECOND;
|
_transitTime = (float)transitFrames / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||||
_currentTime = 0.0f;
|
_totalTime = _transitTime + _preTransitTime + _postTransitTime;
|
||||||
_isTransiting = true;
|
_currentTime = _isActive ? _preTransitTime : 0.0f;
|
||||||
|
_isActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
|
float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
|
||||||
|
@ -171,31 +175,37 @@ float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
|
||||||
|
|
||||||
AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
|
AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
|
||||||
Status status = Status::IDLE;
|
Status status = Status::IDLE;
|
||||||
if (_isTransiting) {
|
if (_isActive) {
|
||||||
float nextTime = _currentTime + deltaTime;
|
float nextTime = _currentTime + deltaTime;
|
||||||
if (nextTime >= _totalTime) {
|
if (nextTime < _preTransitTime) {
|
||||||
_currentPosition = _endPosition;
|
_currentPosition = _startPosition;
|
||||||
_isTransiting = false;
|
status = Status::PRE_TRANSIT;
|
||||||
status = Status::END_TRANSIT;
|
|
||||||
} else {
|
|
||||||
if (_currentTime == 0) {
|
if (_currentTime == 0) {
|
||||||
|
status = Status::STARTED;
|
||||||
|
}
|
||||||
|
} else if (nextTime < _totalTime - _postTransitTime){
|
||||||
|
status = Status::TRANSITING;
|
||||||
|
if (_currentTime <= _preTransitTime) {
|
||||||
status = Status::START_TRANSIT;
|
status = Status::START_TRANSIT;
|
||||||
} else {
|
} else {
|
||||||
status = Status::TRANSITING;
|
float percentageIntoTransit = (nextTime - _preTransitTime) / _transitTime;
|
||||||
|
_currentPosition = _startPosition + getEaseValue(_easeType, percentageIntoTransit) * _transitLine;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
status = Status::POST_TRANSIT;
|
||||||
|
_currentPosition = _endPosition;
|
||||||
|
if (nextTime >= _totalTime) {
|
||||||
|
_isActive = false;
|
||||||
|
status = Status::ENDED;
|
||||||
|
} else if (_currentTime < _totalTime - _postTransitTime) {
|
||||||
|
status = Status::END_TRANSIT;
|
||||||
}
|
}
|
||||||
float percentageIntoTransit = nextTime / _totalTime;
|
|
||||||
_currentPosition = _startPosition + getEaseValue(_easeType, percentageIntoTransit) * _transitLine;
|
|
||||||
}
|
}
|
||||||
_currentTime = nextTime;
|
_currentTime = nextTime;
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AvatarTransit::getNextPosition(glm::vec3& nextPosition) {
|
|
||||||
nextPosition = _currentPosition;
|
|
||||||
return _isTransiting;
|
|
||||||
}
|
|
||||||
|
|
||||||
Avatar::Avatar(QThread* thread) :
|
Avatar::Avatar(QThread* thread) :
|
||||||
_voiceSphereID(GeometryCache::UNKNOWN_ID)
|
_voiceSphereID(GeometryCache::UNKNOWN_ID)
|
||||||
{
|
{
|
||||||
|
@ -536,16 +546,10 @@ void Avatar::relayJointDataToChildren() {
|
||||||
|
|
||||||
void Avatar::simulate(float deltaTime, bool inView) {
|
void Avatar::simulate(float deltaTime, bool inView) {
|
||||||
PROFILE_RANGE(simulation, "simulate");
|
PROFILE_RANGE(simulation, "simulate");
|
||||||
|
|
||||||
if (_transit.isTransiting()) {
|
_globalPosition = _transit.isActive() ? _transit.getCurrentPosition() : _serverPosition;
|
||||||
glm::vec3 nextPosition;
|
if (!hasParent()) {
|
||||||
if (_transit.getNextPosition(nextPosition)) {
|
setLocalPosition(_globalPosition);
|
||||||
_globalPosition = nextPosition;
|
|
||||||
_globalPositionChanged = usecTimestampNow();
|
|
||||||
if (!hasParent()) {
|
|
||||||
setLocalPosition(nextPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_simulationRate.increment();
|
_simulationRate.increment();
|
||||||
|
@ -558,7 +562,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
||||||
PROFILE_RANGE(simulation, "updateJoints");
|
PROFILE_RANGE(simulation, "updateJoints");
|
||||||
if (inView) {
|
if (inView) {
|
||||||
Head* head = getHead();
|
Head* head = getHead();
|
||||||
if (_hasNewJointData || _transit.isTransiting()) {
|
if (_hasNewJointData || _transit.isActive()) {
|
||||||
_skeletonModel->getRig().copyJointsFromJointData(_jointData);
|
_skeletonModel->getRig().copyJointsFromJointData(_jointData);
|
||||||
glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset());
|
glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset());
|
||||||
_skeletonModel->getRig().computeExternalPoses(rootTransform);
|
_skeletonModel->getRig().computeExternalPoses(rootTransform);
|
||||||
|
@ -1995,22 +1999,12 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
|
AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, float avatarScale, const AvatarTransit::TransitConfig& config) {
|
||||||
std::lock_guard<std::mutex> lock(_transitLock);
|
std::lock_guard<std::mutex> lock(_transitLock);
|
||||||
|
_transit.setScale(avatarScale);
|
||||||
return _transit.update(deltaTime, avatarPosition, config);
|
return _transit.update(deltaTime, avatarPosition, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setTransitScale(float scale) {
|
|
||||||
std::lock_guard<std::mutex> lock(_transitLock);
|
|
||||||
return _transit.setScale(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Avatar::overrideNextPackagePositionData(const glm::vec3& position) {
|
|
||||||
std::lock_guard<std::mutex> lock(_transitLock);
|
|
||||||
_overrideGlobalPosition = true;
|
|
||||||
_globalPositionOverride = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
_materials[parentMaterialName].push(material);
|
_materials[parentMaterialName].push(material);
|
||||||
|
|
|
@ -56,9 +56,13 @@ class AvatarTransit {
|
||||||
public:
|
public:
|
||||||
enum Status {
|
enum Status {
|
||||||
IDLE = 0,
|
IDLE = 0,
|
||||||
|
STARTED,
|
||||||
|
PRE_TRANSIT,
|
||||||
START_TRANSIT,
|
START_TRANSIT,
|
||||||
TRANSITING,
|
TRANSITING,
|
||||||
END_TRANSIT,
|
END_TRANSIT,
|
||||||
|
POST_TRANSIT,
|
||||||
|
ENDED,
|
||||||
ABORT_TRANSIT
|
ABORT_TRANSIT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,20 +76,20 @@ public:
|
||||||
struct TransitConfig {
|
struct TransitConfig {
|
||||||
TransitConfig() {};
|
TransitConfig() {};
|
||||||
int _totalFrames { 0 };
|
int _totalFrames { 0 };
|
||||||
int _framesPerMeter { 0 };
|
float _framesPerMeter { 0.0f };
|
||||||
bool _isDistanceBased { false };
|
bool _isDistanceBased { false };
|
||||||
float _triggerDistance { 0 };
|
float _minTriggerDistance { 0.0f };
|
||||||
|
float _maxTriggerDistance { 0.0f };
|
||||||
|
float _abortDistance{ 0.0f };
|
||||||
EaseType _easeType { EaseType::EASE_OUT };
|
EaseType _easeType { EaseType::EASE_OUT };
|
||||||
};
|
};
|
||||||
|
|
||||||
AvatarTransit() {};
|
AvatarTransit() {};
|
||||||
Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config);
|
Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config);
|
||||||
Status getStatus() { return _status; }
|
Status getStatus() { return _status; }
|
||||||
bool isTransiting() { return _isTransiting; }
|
bool isActive() { return _isActive; }
|
||||||
glm::vec3 getCurrentPosition() { return _currentPosition; }
|
glm::vec3 getCurrentPosition() { return _currentPosition; }
|
||||||
bool getNextPosition(glm::vec3& nextPosition);
|
|
||||||
glm::vec3 getEndPosition() { return _endPosition; }
|
glm::vec3 getEndPosition() { return _endPosition; }
|
||||||
float getTransitTime() { return _totalTime; }
|
|
||||||
void setScale(float scale) { _scale = scale; }
|
void setScale(float scale) { _scale = scale; }
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
@ -93,7 +97,7 @@ private:
|
||||||
Status updatePosition(float deltaTime);
|
Status updatePosition(float deltaTime);
|
||||||
void start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
|
void start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
|
||||||
float getEaseValue(AvatarTransit::EaseType type, float value);
|
float getEaseValue(AvatarTransit::EaseType type, float value);
|
||||||
bool _isTransiting { false };
|
bool _isActive { false };
|
||||||
|
|
||||||
glm::vec3 _startPosition;
|
glm::vec3 _startPosition;
|
||||||
glm::vec3 _endPosition;
|
glm::vec3 _endPosition;
|
||||||
|
@ -103,7 +107,10 @@ private:
|
||||||
|
|
||||||
glm::vec3 _transitLine;
|
glm::vec3 _transitLine;
|
||||||
float _totalDistance { 0.0f };
|
float _totalDistance { 0.0f };
|
||||||
|
float _preTransitTime { 0.0f };
|
||||||
float _totalTime { 0.0f };
|
float _totalTime { 0.0f };
|
||||||
|
float _transitTime { 0.0f };
|
||||||
|
float _postTransitTime { 0.0f };
|
||||||
float _currentTime { 0.0f };
|
float _currentTime { 0.0f };
|
||||||
EaseType _easeType { EaseType::EASE_OUT };
|
EaseType _easeType { EaseType::EASE_OUT };
|
||||||
Status _status { Status::IDLE };
|
Status _status { Status::IDLE };
|
||||||
|
@ -431,11 +438,7 @@ public:
|
||||||
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
||||||
|
|
||||||
std::shared_ptr<AvatarTransit> getTransit() { return std::make_shared<AvatarTransit>(_transit); };
|
std::shared_ptr<AvatarTransit> getTransit() { return std::make_shared<AvatarTransit>(_transit); };
|
||||||
|
AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, float avatarScale, const AvatarTransit::TransitConfig& config);
|
||||||
AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config);
|
|
||||||
void setTransitScale(float scale);
|
|
||||||
|
|
||||||
void overrideNextPackagePositionData(const glm::vec3& position);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void targetScaleChanged(float targetScale);
|
void targetScaleChanged(float targetScale);
|
||||||
|
|
|
@ -375,12 +375,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
||||||
|
|
||||||
if (hasAvatarGlobalPosition) {
|
if (hasAvatarGlobalPosition) {
|
||||||
auto startSection = destinationBuffer;
|
auto startSection = destinationBuffer;
|
||||||
if (_overrideGlobalPosition) {
|
AVATAR_MEMCPY(_globalPosition);
|
||||||
AVATAR_MEMCPY(_globalPositionOverride);
|
|
||||||
} else {
|
|
||||||
AVATAR_MEMCPY(_globalPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int numBytes = destinationBuffer - startSection;
|
int numBytes = destinationBuffer - startSection;
|
||||||
|
|
||||||
|
@ -887,20 +882,22 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS);
|
offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
_serverPosition = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
||||||
if (_globalPosition != newValue) {
|
auto oneStepDistance = glm::length(_globalPosition - _serverPosition);
|
||||||
_globalPosition = newValue;
|
if (oneStepDistance <= AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE || oneStepDistance >= AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE) {
|
||||||
|
_globalPosition = _serverPosition;
|
||||||
|
// if we don't have a parent, make sure to also set our local position
|
||||||
|
if (!hasParent()) {
|
||||||
|
setLocalPosition(_serverPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_globalPosition != _serverPosition) {
|
||||||
_globalPositionChanged = now;
|
_globalPositionChanged = now;
|
||||||
}
|
}
|
||||||
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
||||||
int numBytesRead = sourceBuffer - startSection;
|
int numBytesRead = sourceBuffer - startSection;
|
||||||
_globalPositionRate.increment(numBytesRead);
|
_globalPositionRate.increment(numBytesRead);
|
||||||
_globalPositionUpdateRate.increment();
|
_globalPositionUpdateRate.increment();
|
||||||
|
|
||||||
// if we don't have a parent, make sure to also set our local position
|
|
||||||
if (!hasParent()) {
|
|
||||||
setLocalPosition(newValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasAvatarBoundingBox) {
|
if (hasAvatarBoundingBox) {
|
||||||
|
@ -2115,10 +2112,6 @@ void AvatarData::sendAvatarDataPacket(bool sendAll) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_overrideGlobalPosition) {
|
|
||||||
_overrideGlobalPosition = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
doneEncoding(cullSmallData);
|
doneEncoding(cullSmallData);
|
||||||
|
|
||||||
static AvatarDataSequenceNumber sequenceNumber = 0;
|
static AvatarDataSequenceNumber sequenceNumber = 0;
|
||||||
|
|
|
@ -327,6 +327,17 @@ const float AVATAR_DISTANCE_LEVEL_5 = 200.0f; // meters
|
||||||
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
||||||
const glm::vec3 START_LOCATION(6270, 211, 6000);
|
const glm::vec3 START_LOCATION(6270, 211, 6000);
|
||||||
|
|
||||||
|
// Avatar Transit Constants
|
||||||
|
const float AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE = 1.0f;
|
||||||
|
const float AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE = 30.0f;
|
||||||
|
const int AVATAR_TRANSIT_FRAME_COUNT = 11;
|
||||||
|
const float AVATAR_TRANSIT_FRAMES_PER_METER = 0.5f;
|
||||||
|
const float AVATAR_TRANSIT_ABORT_DISTANCE = 0.1f;
|
||||||
|
const bool AVATAR_TRANSIT_DISTANCE_BASED = true;
|
||||||
|
const float AVATAR_TRANSIT_FRAMES_PER_SECOND = 30.0f;
|
||||||
|
const float AVATAR_PRE_TRANSIT_FRAME_COUNT = 10.0f;
|
||||||
|
const float AVATAR_POST_TRANSIT_FRAME_COUNT = 27.0f;
|
||||||
|
|
||||||
enum KeyState {
|
enum KeyState {
|
||||||
NO_KEY_DOWN = 0,
|
NO_KEY_DOWN = 0,
|
||||||
INSERT_KEY_DOWN,
|
INSERT_KEY_DOWN,
|
||||||
|
@ -1378,8 +1389,7 @@ protected:
|
||||||
// where Entities are located. This is currently only used by the mixer to decide how often to send
|
// where Entities are located. This is currently only used by the mixer to decide how often to send
|
||||||
// updates about one avatar to another.
|
// updates about one avatar to another.
|
||||||
glm::vec3 _globalPosition { 0, 0, 0 };
|
glm::vec3 _globalPosition { 0, 0, 0 };
|
||||||
glm::vec3 _globalPositionOverride { 0, 0, 0 };
|
glm::vec3 _serverPosition { 0, 0, 0 };
|
||||||
bool _overrideGlobalPosition { false };
|
|
||||||
|
|
||||||
quint64 _globalPositionChanged { 0 };
|
quint64 _globalPositionChanged { 0 };
|
||||||
quint64 _avatarBoundingBoxChanged { 0 };
|
quint64 _avatarBoundingBoxChanged { 0 };
|
||||||
|
|
|
@ -41,6 +41,9 @@ var TITLE_OFFSET = 60;
|
||||||
var CREATE_TOOLS_WIDTH = 490;
|
var CREATE_TOOLS_WIDTH = 490;
|
||||||
var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942;
|
var MAX_DEFAULT_ENTITY_LIST_HEIGHT = 942;
|
||||||
|
|
||||||
|
var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx";
|
||||||
|
var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg";
|
||||||
|
|
||||||
var createToolsWindow = new CreateWindow(
|
var createToolsWindow = new CreateWindow(
|
||||||
Script.resourcesPath() + "qml/hifi/tablet/EditTools.qml",
|
Script.resourcesPath() + "qml/hifi/tablet/EditTools.qml",
|
||||||
'Create Tools',
|
'Create Tools',
|
||||||
|
@ -271,6 +274,202 @@ function checkEditPermissionsAndUpdate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_ENTITY_PROPERTIES = {
|
||||||
|
All: {
|
||||||
|
description: "",
|
||||||
|
rotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||||
|
collidesWith: "static,dynamic,kinematic,otherAvatar",
|
||||||
|
collisionSoundURL: "",
|
||||||
|
cloneable: false,
|
||||||
|
ignoreIK: true,
|
||||||
|
canCastShadow: true,
|
||||||
|
href: "",
|
||||||
|
script: "",
|
||||||
|
serverScripts:"",
|
||||||
|
velocity: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
damping: 0,
|
||||||
|
angularVelocity: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
angularDamping: 0,
|
||||||
|
restitution: 0.5,
|
||||||
|
friction: 0.5,
|
||||||
|
density: 1000,
|
||||||
|
gravity: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
acceleration: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
dynamic: false,
|
||||||
|
},
|
||||||
|
Shape: {
|
||||||
|
shape: "Box",
|
||||||
|
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||||
|
color: { red: 0, green: 180, blue: 239 },
|
||||||
|
},
|
||||||
|
Text: {
|
||||||
|
text: "Text",
|
||||||
|
dimensions: {
|
||||||
|
x: 0.65,
|
||||||
|
y: 0.3,
|
||||||
|
z: 0.01
|
||||||
|
},
|
||||||
|
textColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
backgroundColor: { red: 0, green: 0, blue: 0 },
|
||||||
|
lineHeight: 0.06,
|
||||||
|
faceCamera: false,
|
||||||
|
},
|
||||||
|
Zone: {
|
||||||
|
dimensions: {
|
||||||
|
x: 10,
|
||||||
|
y: 10,
|
||||||
|
z: 10
|
||||||
|
},
|
||||||
|
flyingAllowed: true,
|
||||||
|
ghostingAllowed: true,
|
||||||
|
filter: "",
|
||||||
|
keyLightMode: "inherit",
|
||||||
|
keyLightColor: { red: 255, green: 255, blue: 255 },
|
||||||
|
keyLight: {
|
||||||
|
intensity: 1.0,
|
||||||
|
direction: {
|
||||||
|
x: 0.0,
|
||||||
|
y: -0.707106769084930, // 45 degrees
|
||||||
|
z: 0.7071067690849304
|
||||||
|
},
|
||||||
|
castShadows: true
|
||||||
|
},
|
||||||
|
ambientLightMode: "inherit",
|
||||||
|
ambientLight: {
|
||||||
|
ambientIntensity: 0.5,
|
||||||
|
ambientURL: ""
|
||||||
|
},
|
||||||
|
hazeMode: "inherit",
|
||||||
|
haze: {
|
||||||
|
hazeRange: 1000,
|
||||||
|
hazeAltitudeEffect: false,
|
||||||
|
hazeBaseRef: 0,
|
||||||
|
hazeColor: {
|
||||||
|
red: 128,
|
||||||
|
green: 154,
|
||||||
|
blue: 179
|
||||||
|
},
|
||||||
|
hazeBackgroundBlend: 0,
|
||||||
|
hazeEnableGlare: false,
|
||||||
|
hazeGlareColor: {
|
||||||
|
red: 255,
|
||||||
|
green: 229,
|
||||||
|
blue: 179
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bloomMode: "inherit"
|
||||||
|
},
|
||||||
|
Model: {
|
||||||
|
collisionShape: "none",
|
||||||
|
compoundShapeURL: "",
|
||||||
|
animation: {
|
||||||
|
url: "",
|
||||||
|
running: false,
|
||||||
|
allowTranslation: false,
|
||||||
|
loop: true,
|
||||||
|
hold: false,
|
||||||
|
currentFrame: 0,
|
||||||
|
firstFrame: 0,
|
||||||
|
lastFrame: 100000,
|
||||||
|
fps: 30.0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Image: {
|
||||||
|
dimensions: {
|
||||||
|
x: 0.5385,
|
||||||
|
y: 0.2819,
|
||||||
|
z: 0.0092
|
||||||
|
},
|
||||||
|
shapeType: "box",
|
||||||
|
collisionless: true,
|
||||||
|
modelURL: IMAGE_MODEL,
|
||||||
|
textures: JSON.stringify({ "tex.picture": "" })
|
||||||
|
},
|
||||||
|
Web: {
|
||||||
|
dimensions: {
|
||||||
|
x: 1.6,
|
||||||
|
y: 0.9,
|
||||||
|
z: 0.01
|
||||||
|
},
|
||||||
|
sourceUrl: "https://highfidelity.com/",
|
||||||
|
dpi: 30,
|
||||||
|
},
|
||||||
|
ParticleEffect: {
|
||||||
|
lifespan: 1.5,
|
||||||
|
maxParticles: 10,
|
||||||
|
textures: "https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png",
|
||||||
|
emitRate: 5.5,
|
||||||
|
emitSpeed: 0,
|
||||||
|
speedSpread: 0,
|
||||||
|
emitDimensions: { x: 0, y: 0, z: 0 },
|
||||||
|
emitOrientation: { x: 0, y: 0, z: 0, w: 1 },
|
||||||
|
emitterShouldTrail: true,
|
||||||
|
particleRadius: 0.25,
|
||||||
|
radiusStart: 0,
|
||||||
|
radiusFinish: 0.1,
|
||||||
|
radiusSpread: 0,
|
||||||
|
particleColor: {
|
||||||
|
red: 255,
|
||||||
|
green: 255,
|
||||||
|
blue: 255
|
||||||
|
},
|
||||||
|
colorSpread: {
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 0
|
||||||
|
},
|
||||||
|
alpha: 0,
|
||||||
|
alphaStart: 1,
|
||||||
|
alphaFinish: 0,
|
||||||
|
alphaSpread: 0,
|
||||||
|
emitAcceleration: {
|
||||||
|
x: 0,
|
||||||
|
y: 2.5,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
accelerationSpread: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0
|
||||||
|
},
|
||||||
|
particleSpin: 0,
|
||||||
|
spinStart: 0,
|
||||||
|
spinFinish: 0,
|
||||||
|
spinSpread: 0,
|
||||||
|
rotateWithEntity: false,
|
||||||
|
polarStart: 0,
|
||||||
|
polarFinish: 0,
|
||||||
|
azimuthStart: -Math.PI,
|
||||||
|
azimuthFinish: Math.PI
|
||||||
|
},
|
||||||
|
Light: {
|
||||||
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
|
intensity: 5.0,
|
||||||
|
dimensions: DEFAULT_LIGHT_DIMENSIONS,
|
||||||
|
falloffRadius: 1.0,
|
||||||
|
isSpotlight: false,
|
||||||
|
exponent: 1.0,
|
||||||
|
cutoff: 75.0,
|
||||||
|
dimensions: { x: 20, y: 20, z: 20 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
var toolBar = (function () {
|
var toolBar = (function () {
|
||||||
var EDIT_SETTING = "io.highfidelity.isEditing"; // for communication with other scripts
|
var EDIT_SETTING = "io.highfidelity.isEditing"; // for communication with other scripts
|
||||||
var that = {},
|
var that = {},
|
||||||
|
@ -280,11 +479,29 @@ var toolBar = (function () {
|
||||||
dialogWindow = null,
|
dialogWindow = null,
|
||||||
tablet = null;
|
tablet = null;
|
||||||
|
|
||||||
|
function applyProperties(originalProperties, newProperties) {
|
||||||
|
for (var key in newProperties) {
|
||||||
|
originalProperties[key] = newProperties[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
function createNewEntity(properties) {
|
function createNewEntity(properties) {
|
||||||
var dimensions = properties.dimensions ? properties.dimensions : DEFAULT_DIMENSIONS;
|
var dimensions = properties.dimensions ? properties.dimensions : DEFAULT_DIMENSIONS;
|
||||||
var position = getPositionToCreateEntity();
|
var position = getPositionToCreateEntity();
|
||||||
var entityID = null;
|
var entityID = null;
|
||||||
|
|
||||||
|
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
|
||||||
|
|
||||||
|
var type = properties.type;
|
||||||
|
if (type == "Box" || type == "Sphere") {
|
||||||
|
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
|
||||||
|
} else if (type == "Image") {
|
||||||
|
properties.type = "Model";
|
||||||
|
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Image);
|
||||||
|
} else {
|
||||||
|
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (position !== null && position !== undefined) {
|
if (position !== null && position !== undefined) {
|
||||||
var direction;
|
var direction;
|
||||||
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
if (Camera.mode === "entity" || Camera.mode === "independent") {
|
||||||
|
@ -358,7 +575,7 @@ var toolBar = (function () {
|
||||||
Entities.editEntity(entityID, {
|
Entities.editEntity(entityID, {
|
||||||
position: position
|
position: position
|
||||||
});
|
});
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
} else if (dimensionsCheckCount < MAX_DIMENSIONS_CHECKS) {
|
} else if (dimensionsCheckCount < MAX_DIMENSIONS_CHECKS) {
|
||||||
Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
|
Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
@ -370,9 +587,9 @@ var toolBar = (function () {
|
||||||
properties.type + " would be out of bounds.");
|
properties.type + " would be out of bounds.");
|
||||||
}
|
}
|
||||||
|
|
||||||
selectionManager.clearSelections();
|
selectionManager.clearSelections(this);
|
||||||
entityListTool.sendUpdate();
|
entityListTool.sendUpdate();
|
||||||
selectionManager.setSelections([entityID]);
|
selectionManager.setSelections([entityID], this);
|
||||||
|
|
||||||
Window.setFocus();
|
Window.setFocus();
|
||||||
|
|
||||||
|
@ -523,7 +740,7 @@ var toolBar = (function () {
|
||||||
}
|
}
|
||||||
deletedEntityTimer = Script.setTimeout(function () {
|
deletedEntityTimer = Script.setTimeout(function () {
|
||||||
if (entitiesToDelete.length > 0) {
|
if (entitiesToDelete.length > 0) {
|
||||||
selectionManager.removeEntities(entitiesToDelete);
|
selectionManager.removeEntities(entitiesToDelete, this);
|
||||||
}
|
}
|
||||||
entityListTool.removeEntities(entitiesToDelete, selectionManager.selections);
|
entityListTool.removeEntities(entitiesToDelete, selectionManager.selections);
|
||||||
entitiesToDelete = [];
|
entitiesToDelete = [];
|
||||||
|
@ -652,14 +869,12 @@ var toolBar = (function () {
|
||||||
addButton("newLightButton", function () {
|
addButton("newLightButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Light",
|
type: "Light",
|
||||||
dimensions: DEFAULT_LIGHT_DIMENSIONS,
|
|
||||||
isSpotlight: false,
|
isSpotlight: false,
|
||||||
color: {
|
color: {
|
||||||
red: 150,
|
red: 150,
|
||||||
green: 150,
|
green: 150,
|
||||||
blue: 150
|
blue: 150
|
||||||
},
|
},
|
||||||
|
|
||||||
constantAttenuation: 1,
|
constantAttenuation: 1,
|
||||||
linearAttenuation: 0,
|
linearAttenuation: 0,
|
||||||
quadraticAttenuation: 0,
|
quadraticAttenuation: 0,
|
||||||
|
@ -671,116 +886,30 @@ var toolBar = (function () {
|
||||||
addButton("newTextButton", function () {
|
addButton("newTextButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Text",
|
type: "Text",
|
||||||
dimensions: {
|
|
||||||
x: 0.65,
|
|
||||||
y: 0.3,
|
|
||||||
z: 0.01
|
|
||||||
},
|
|
||||||
backgroundColor: {
|
|
||||||
red: 64,
|
|
||||||
green: 64,
|
|
||||||
blue: 64
|
|
||||||
},
|
|
||||||
textColor: {
|
|
||||||
red: 255,
|
|
||||||
green: 255,
|
|
||||||
blue: 255
|
|
||||||
},
|
|
||||||
text: "some text",
|
|
||||||
lineHeight: 0.06
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newImageButton", function () {
|
addButton("newImageButton", function () {
|
||||||
var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx";
|
|
||||||
var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg";
|
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Model",
|
type: "Image",
|
||||||
dimensions: {
|
|
||||||
x: 0.5385,
|
|
||||||
y: 0.2819,
|
|
||||||
z: 0.0092
|
|
||||||
},
|
|
||||||
shapeType: "box",
|
|
||||||
collisionless: true,
|
|
||||||
modelURL: IMAGE_MODEL,
|
|
||||||
textures: JSON.stringify({ "tex.picture": DEFAULT_IMAGE })
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newWebButton", function () {
|
addButton("newWebButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Web",
|
type: "Web",
|
||||||
dimensions: {
|
|
||||||
x: 1.6,
|
|
||||||
y: 0.9,
|
|
||||||
z: 0.01
|
|
||||||
},
|
|
||||||
sourceUrl: "https://highfidelity.com/"
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newZoneButton", function () {
|
addButton("newZoneButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Zone",
|
type: "Zone",
|
||||||
dimensions: {
|
|
||||||
x: 10,
|
|
||||||
y: 10,
|
|
||||||
z: 10
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newParticleButton", function () {
|
addButton("newParticleButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "ParticleEffect",
|
type: "ParticleEffect",
|
||||||
isEmitting: true,
|
|
||||||
emitterShouldTrail: true,
|
|
||||||
color: {
|
|
||||||
red: 200,
|
|
||||||
green: 200,
|
|
||||||
blue: 200
|
|
||||||
},
|
|
||||||
colorSpread: {
|
|
||||||
red: 0,
|
|
||||||
green: 0,
|
|
||||||
blue: 0
|
|
||||||
},
|
|
||||||
colorStart: {
|
|
||||||
red: 200,
|
|
||||||
green: 200,
|
|
||||||
blue: 200
|
|
||||||
},
|
|
||||||
colorFinish: {
|
|
||||||
red: 0,
|
|
||||||
green: 0,
|
|
||||||
blue: 0
|
|
||||||
},
|
|
||||||
emitAcceleration: {
|
|
||||||
x: -0.5,
|
|
||||||
y: 2.5,
|
|
||||||
z: -0.5
|
|
||||||
},
|
|
||||||
accelerationSpread: {
|
|
||||||
x: 0.5,
|
|
||||||
y: 1,
|
|
||||||
z: 0.5
|
|
||||||
},
|
|
||||||
emitRate: 5.5,
|
|
||||||
emitSpeed: 0,
|
|
||||||
speedSpread: 0,
|
|
||||||
lifespan: 1.5,
|
|
||||||
maxParticles: 10,
|
|
||||||
particleRadius: 0.25,
|
|
||||||
radiusStart: 0,
|
|
||||||
radiusFinish: 0.1,
|
|
||||||
radiusSpread: 0,
|
|
||||||
alpha: 0,
|
|
||||||
alphaStart: 1,
|
|
||||||
alphaFinish: 0,
|
|
||||||
polarStart: 0,
|
|
||||||
polarFinish: 0,
|
|
||||||
textures: "https://content.highfidelity.com/DomainContent/production/Particles/wispy-smoke.png"
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -839,7 +968,7 @@ var toolBar = (function () {
|
||||||
gridTool.setVisible(false);
|
gridTool.setVisible(false);
|
||||||
grid.setEnabled(false);
|
grid.setEnabled(false);
|
||||||
propertiesTool.setVisible(false);
|
propertiesTool.setVisible(false);
|
||||||
selectionManager.clearSelections();
|
selectionManager.clearSelections(this);
|
||||||
cameraManager.disable();
|
cameraManager.disable();
|
||||||
selectionDisplay.disableTriggerMapping();
|
selectionDisplay.disableTriggerMapping();
|
||||||
tablet.landscape = false;
|
tablet.landscape = false;
|
||||||
|
@ -967,7 +1096,7 @@ function handleOverlaySelectionToolUpdates(channel, message, sender) {
|
||||||
var entity = entityIconOverlayManager.findEntity(data.overlayID);
|
var entity = entityIconOverlayManager.findEntity(data.overlayID);
|
||||||
|
|
||||||
if (entity !== null) {
|
if (entity !== null) {
|
||||||
selectionManager.setSelections([entity]);
|
selectionManager.setSelections([entity], this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1114,7 +1243,7 @@ function mouseClickEvent(event) {
|
||||||
|
|
||||||
if (result === null || result === undefined) {
|
if (result === null || result === undefined) {
|
||||||
if (!event.isShifted) {
|
if (!event.isShifted) {
|
||||||
selectionManager.clearSelections();
|
selectionManager.clearSelections(this);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1159,9 +1288,9 @@ function mouseClickEvent(event) {
|
||||||
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
|
intersection = rayPlaneIntersection(pickRay, P, Quat.getForward(orientation));
|
||||||
|
|
||||||
if (!event.isShifted) {
|
if (!event.isShifted) {
|
||||||
selectionManager.setSelections([foundEntity]);
|
selectionManager.setSelections([foundEntity], this);
|
||||||
} else {
|
} else {
|
||||||
selectionManager.addEntity(foundEntity, true);
|
selectionManager.addEntity(foundEntity, true, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
|
@ -1459,7 +1588,7 @@ function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectionManager.setSelections(entities);
|
selectionManager.setSelections(entities, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1597,7 +1726,7 @@ function deleteSelectedEntities() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedProperties.length > 0) {
|
if (savedProperties.length > 0) {
|
||||||
SelectionManager.clearSelections();
|
SelectionManager.clearSelections(this);
|
||||||
pushCommandForSelections([], savedProperties);
|
pushCommandForSelections([], savedProperties);
|
||||||
entityListTool.deleteEntities(deletedIDs);
|
entityListTool.deleteEntities(deletedIDs);
|
||||||
}
|
}
|
||||||
|
@ -1614,7 +1743,7 @@ function toggleSelectedEntitiesLocked() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
entityListTool.sendUpdate();
|
entityListTool.sendUpdate();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1757,7 @@ function toggleSelectedEntitiesVisible() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
entityListTool.sendUpdate();
|
entityListTool.sendUpdate();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1825,7 +1954,7 @@ function importSVO(importURL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
selectionManager.setSelections(pastedEntityIDs);
|
selectionManager.setSelections(pastedEntityIDs, this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Window.notifyEditError("Can't import entities: entities would be out of bounds.");
|
Window.notifyEditError("Can't import entities: entities would be out of bounds.");
|
||||||
|
@ -1873,7 +2002,7 @@ function deleteKey(value) {
|
||||||
}
|
}
|
||||||
function deselectKey(value) {
|
function deselectKey(value) {
|
||||||
if (value === 0) { // on release
|
if (value === 0) { // on release
|
||||||
selectionManager.clearSelections();
|
selectionManager.clearSelections(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function toggleKey(value) {
|
function toggleKey(value) {
|
||||||
|
@ -2033,7 +2162,7 @@ function applyEntityProperties(data) {
|
||||||
// We might be getting an undo while edit.js is disabled. If that is the case, don't set
|
// We might be getting an undo while edit.js is disabled. If that is the case, don't set
|
||||||
// our selections, causing the edit widgets to display.
|
// our selections, causing the edit widgets to display.
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
selectionManager.setSelections(selectedEntityIDs);
|
selectionManager.setSelections(selectedEntityIDs, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2244,7 +2373,7 @@ var PropertiesTool = function (opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
} else if (data.type === 'parent') {
|
} else if (data.type === 'parent') {
|
||||||
parentSelectedEntities();
|
parentSelectedEntities();
|
||||||
} else if (data.type === 'unparent') {
|
} else if (data.type === 'unparent') {
|
||||||
|
@ -2273,7 +2402,7 @@ var PropertiesTool = function (opts) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
} else if (data.action === "moveAllToGrid") {
|
} else if (data.action === "moveAllToGrid") {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
|
@ -2293,7 +2422,7 @@ var PropertiesTool = function (opts) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
} else if (data.action === "resetToNaturalDimensions") {
|
} else if (data.action === "resetToNaturalDimensions") {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
|
@ -2314,7 +2443,7 @@ var PropertiesTool = function (opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
} else if (data.action === "previewCamera") {
|
} else if (data.action === "previewCamera") {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
|
@ -2332,7 +2461,7 @@ var PropertiesTool = function (opts) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
pushCommandForSelections();
|
pushCommandForSelections();
|
||||||
selectionManager._update();
|
selectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
} else if (data.action === "reloadClientScripts") {
|
} else if (data.action === "reloadClientScripts") {
|
||||||
if (selectionManager.hasSelection()) {
|
if (selectionManager.hasSelection()) {
|
||||||
|
|
|
@ -198,7 +198,7 @@ td.url {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
input[type="text"], input[type="number"], textarea {
|
input[type="text"], input[type="search"], input[type="number"], textarea {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
color: #afafaf;
|
color: #afafaf;
|
||||||
|
@ -257,12 +257,22 @@ input[type="text"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type="search"] {
|
||||||
|
height: 28px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
input[type="search"]::-webkit-search-cancel-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goNAQIFbBwsbwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAZfSURBVDgRAVQGq/kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9PT0YAwMDBgAAAAD8/Pz5+vr67MrKyv0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAA+Pj4KAgICQgAAAE3///9RAQEBFQAAAAD////pAQEBu/39/ab+/v7BxcXF9gAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAADs7OzMEBASIAQEBRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8AAACm+/v7cMXFxewAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAPT09OwEBAagBAQEcAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAA2f///2XCwsLDAAAAAAAAAAABAAAAAAAAAAA9PT0KAwMDt////z4AAAAAAAAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAcIBAQFJvr6+9gAAAAACAAAAAAAAAAAAAABg////PgEBAQAAAAAAS0tLADg4OAAAAAAAAAAAAP///wADAwMAQEBAACEhIQD///8A////AP7+/j76+vpWAAAAAAAAAAACAAAAAD09PQ8CAgJkAQEBAP///wD///8ACgoKAFhYWAAyMjIAAAAAAAICAgBGRkYAT09PABEREQAAAAAAAAAAAAAAAAACAgJwOjo6EAAAAAAEAAAAAAICAg8BAQExAAAAAAEBAQABAQEAsrKyAAoKCgBaWloA9/f3ABsbGwBISEgAtra2AM7OzgACAgIA////AP///wABAQEuBQUFDgAAAPAEAAAAAPz8/BkEBAQAAQEBAAAAAAAAAAAA+vr6AKioqAALCwsAZWVlAAcHBwC/v78Au7u7AAEBAQD///8AAAAAAAAAAAAAAAABAAAAAAAAAAACAAAAAAQEBOgBAQEAAQEBAAEBAQABAQEAAQEBAPz8/ADT09MADg4OAP39/QDQ0NAA/v7+AP///wAAAAAAAAAAAAEBAQABAQEAAQEBAAAAAAACAAAAAAAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAACkpKQBQUFAAx8fHAObm5gBfX18AFxcXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAP39/fz+/v7z////AP///wD///8AJycnAGFhYQDc3NwApaWlAJaWlgD29vYAZmZmABQUFAACAgIAAQEBAAEBAQABAQH1AAAA/AAAAAACAAAAAPr6+ukBAQGkAAAAAAAAAAABAQEAQEBAAObm5gCmpqYA+fn5APPz8wCdnZ0A////ACwsLAD///8AAAAAAAAAAAD///+k9vb26QAAAAABAAAAAAAAAAA+Pj4uAgICxgAAAAsAAAAAEBAQAPr6+gD29vYAAAAAAAAAAAABAQEAAgICAP///wD+/v4AAAAAAAAAAPL8/Pw/xMTE0AAAAAACAAAAAAAAAAD5+fnV////nQICAgABAQEA8fHxAPX19QABAQEAAAAAAAAAAAD///8A/v7+AP7+/gAAAAAAAAAAAP7+/p36+vrSAAAAAAAAAAADAAAAAAAAAADl5eX/ICAgwQAAAA////8q////BgEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD1/f39mAEBAXrGxsb7AAAAAAAAAAADAAAAAAAAAAAAAAAA4eHh/BgYGLsBAQHDBAQEHAAAACP///8AAQEBAAAAAAAAAAAAAAAA+////7QBAQFu+fn5m8bGxvoAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPz8/Cv7+/iUBAQFMAgICEQICAgD8/PzdAwMDs/j4+OvHx8f5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8TUnpZ7EwQgAAAABJRU5ErkJggg==')
|
||||||
|
}
|
||||||
|
|
||||||
input[type="number"] {
|
input[type="number"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
width: 124px;
|
width: 124px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=number] {
|
input[type=number] {
|
||||||
padding-right: 3px;
|
padding-right: 3px;
|
||||||
}
|
}
|
||||||
|
@ -767,6 +777,29 @@ hr {
|
||||||
color: #252525;
|
color: #252525;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multiselect {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.select-box {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.select-box select {
|
||||||
|
font-family: FiraSans-SemiBold;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #afafaf;
|
||||||
|
background-color: #252525;
|
||||||
|
border: none;
|
||||||
|
height: 28px;
|
||||||
|
width: 107px;
|
||||||
|
text-align-last: center;
|
||||||
|
}
|
||||||
|
.over-select {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
div.refresh {
|
div.refresh {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -1079,26 +1112,94 @@ body#entity-list-body {
|
||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#filter {
|
#filter-type-select-box select {
|
||||||
width: 98%;
|
border-radius: 14.5px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
top: 48px;
|
||||||
|
display: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes div {
|
||||||
|
position: relative;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes span {
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
font-family: hifi-glyphs;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #000000;
|
||||||
|
padding-left: 6px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes label {
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
z-index: 2;
|
||||||
|
display: block;
|
||||||
|
font-family: FiraSans-SemiBold;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #000000;
|
||||||
|
background-color: #afafaf;
|
||||||
|
width: 200px;
|
||||||
|
height: 22px;
|
||||||
|
padding-top: 1px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes label:hover {
|
||||||
|
background-color: #1e90ff;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes input[type=checkbox] + label {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADUOYnF4LQAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIMSURBVFjD7ZmxkqowFIZ/7mwJPen1AezV3t6hFvrQhweAHvrQ8wL2xt4HwD7ppd+tvHOvu0gCYdEZTsmAfpNzzpcTcAB84o3iD94sZuCx4+Pxwvl8dl4JcL1ef84lMQPPwBZDSgkp5XsASylBKUUYhhBCvDbw7XYDpRRKKTRNA8YYOOevC5ymKZRS/13jnHdCTwLMOW8tAc45GGNomuY1gKuq6lxFIQQopdMDXy4X5HmudW8URdMCSynBGNOG3Ww20wHf9dVWl4+wbav7a8CMsW9G+Cm22+1T2F8BzvMc1+u18z5CCJIkseNhKSX2+z2qqjLWl84zhBAURQHXde0A31Oa57nWbqSrLwDwPA9FUcD3fTtb82NKu8QOAHVda+srSRJt2E7gtpQKIXA4HH6csmzpyxj4dDo9TalSCpRS1HX9TV86RujSlxGwlBJpmnY+rJRCGIZ/s2BTX9qnZgBwHAee52mJ/l7nx+PRqr6MVtj3fZRlaVRf/5aGDX0Z17DrusiyrHfqhuqrt9aiKEIcx4OBTfU1aOMIggBlWYIQ0utP+uhr8CyxXC5RFIUxdBAE1srKePgxbcbVamWlnAZNa7rNSAhBlmWv8yLlWTPa0Nco83BbM2ZZZsUIowzwj80YxzEWi8VoB4IPGz9yb0YhBHa73agnGGtHJNd1R4ed9FVV33Awf6ebgd8b+Av9A/rq6s3hjgAAAABJRU5ErkJggg==');
|
||||||
|
background-size: 11px 11px;
|
||||||
|
background-position: top 5px left 14px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes input[type=checkbox]:checked + label {
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAsCAYAAAAehFoBAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4goSADMveELP9QAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAIqSURBVFjD7ZmxkqowFIb/7GwJPfT6APZib+9QC33o4QGghz70vIC9sfcBsE966bPNWlxnlQTDRWc4JUT4hpPz5SQSAAofFF/4sJiBx47v+wun04m8E+B6vVbzlJiBZ2CLIYRQQgj1EcBCCEUpRRRF4Jyrtwa+Xq+glEJKia7rkKYpGGPqbYHzPFdSyn+uMcZ6oScBZowpzvmje0jTVHVd9x7ATdMoxtjTMZxzUErV5MDn81mVZak1No7jab+wEEKlaaoNGwQBmQz4pq9H8/IeNo5jMmnRpWmKeyP8FZvN5insfwEuy1JdLpfecb7vI8uy3tb2Szelu91ONU1jtP9jjKmmabRgq6qC4zh2VrpbSsuy1FqNdPUFAK7roqoqeJ6ntXH4Mk1pn9gBoG1bbX1lWaYN2wv8KKWcc+z3+z+7LFv6MgY+Ho9PUyqlBKUUbduqe33pGKFPX0bAQgiV53nvj6WUiKIIt2K0qS/tXTMAEELguq6W6H/nOQ6Hg1V9GX1hz/NIXdckCALtB7Vta1VfxnPYcRwURUEeNSGmYaqvwVqL45gkSfIysKm+Xlo4wjAkdV3D9/1BLxmir5d7ieVySaqqMoYOw3CwEV5ufkyLcbVaIUkSq2d1xt2abjH6vo+iKKwfLA5uL58Vow19jdIPPyrGoiisGGGUBv6+GJMkwWKxGO2M+dvGQ36LEZxztd1uRz0Qt7ZFchwHY8NOelQ1NAjm/+lm4M8G/gH2zx33BSr7jAAAAABJRU5ErkJggg==');
|
||||||
|
background-size: 11px 11px;
|
||||||
|
background-position: top 5px left 14px;
|
||||||
|
}
|
||||||
|
#filter-type-checkboxes input[type=checkbox]:hover + label {
|
||||||
|
background-color: #1e90ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#in-view {
|
#filter-search-and-icon {
|
||||||
|
position: relative;
|
||||||
|
left: 118px;
|
||||||
|
width: calc(100% - 126px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#filter-in-view {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
right: 126px;
|
right: 126px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#radius-and-unit {
|
#filter-radius-and-unit {
|
||||||
|
position: relative;
|
||||||
float: right;
|
float: right;
|
||||||
margin-right: -168px;
|
margin-right: -168px;
|
||||||
position: relative;
|
top: -45px;
|
||||||
top: -17px;
|
|
||||||
}
|
}
|
||||||
#radius-and-unit label {
|
#filter-radius-and-unit label {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
#radius-and-unit input {
|
#filter-radius-and-unit span {
|
||||||
|
position: relative;
|
||||||
|
top: 25px;
|
||||||
|
right: 9px;
|
||||||
|
z-index: 2;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
#filter-radius-and-unit input {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
|
border-radius: 14.5px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
#filter-radius-and-unit input[type=number]::-webkit-inner-spin-button {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#entity-list-footer {
|
#entity-list-footer {
|
||||||
|
@ -1457,3 +1558,43 @@ input#property-scale-button-reset {
|
||||||
#div-property-collisionSoundURL[style*="display: none"] + .property {
|
#div-property-collisionSoundURL[style*="display: none"] + .property {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.context-menu {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
color: #000000;
|
||||||
|
background-color: #afafaf;
|
||||||
|
padding: 5px 0 5px 0;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.context-menu li {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 4px 18px 4px 18px;
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.context-menu li:hover {
|
||||||
|
background-color: #e3e3e3;
|
||||||
|
}
|
||||||
|
.context-menu li.separator {
|
||||||
|
border-top: 1px solid #333333;
|
||||||
|
margin: 5px 5px;
|
||||||
|
padding: 0 0;
|
||||||
|
}
|
||||||
|
.context-menu li.disabled {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.context-menu li.separator:hover, .context-menu li.disabled:hover {
|
||||||
|
background-color: #afafaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.rename-entity {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
font-family: FiraSans-SemiBold;
|
||||||
|
font-size: 15px;
|
||||||
|
/* need this to show the text cursor when the input field is empty */
|
||||||
|
padding-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
<script type="text/javascript" src="js/eventBridgeLoader.js"></script>
|
<script type="text/javascript" src="js/eventBridgeLoader.js"></script>
|
||||||
<script type="text/javascript" src="js/spinButtons.js"></script>
|
<script type="text/javascript" src="js/spinButtons.js"></script>
|
||||||
<script type="text/javascript" src="js/listView.js"></script>
|
<script type="text/javascript" src="js/listView.js"></script>
|
||||||
|
<script type="text/javascript" src="js/entityListContextMenu.js"></script>
|
||||||
<script type="text/javascript" src="js/entityList.js"></script>
|
<script type="text/javascript" src="js/entityList.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload='loaded();' id="entity-list-body">
|
<body onload='loaded();' id="entity-list-body">
|
||||||
|
@ -29,12 +30,25 @@
|
||||||
<input type="button" class="red" id="delete" value="Delete" />
|
<input type="button" class="red" id="delete" value="Delete" />
|
||||||
</div>
|
</div>
|
||||||
<div id="entity-list">
|
<div id="entity-list">
|
||||||
<div id="search-area">
|
<div id="filter-area">
|
||||||
<span class="icon-input"><input type="text" class="search" id="filter" placeholder="Filter" /><span>Y</span></span>
|
<div class="multiselect">
|
||||||
<input type="button" id="in-view" class="glyph" value="" />
|
<div class="select-box" id="filter-type-select-box">
|
||||||
<div id="radius-and-unit" class="number">
|
<select>
|
||||||
|
<option id="filter-type-text">All Types</option>
|
||||||
|
</select>
|
||||||
|
<div class="over-select"></div>
|
||||||
|
</div>
|
||||||
|
<div id="filter-type-checkboxes">
|
||||||
|
<!-- type options with checkbox, icon, and label are added at runtime in entityList -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="filter-search-and-icon">
|
||||||
|
<span class="icon-input"><input type="search" class="search" id="filter-search" placeholder="Search" /><span>Y</span></span>
|
||||||
|
</div>
|
||||||
|
<input type="button" id="filter-in-view" class="glyph" value="" />
|
||||||
|
<div id="filter-radius-and-unit" class="number">
|
||||||
<label for="radius">Search radius <span class="unit">m</span></label>
|
<label for="radius">Search radius <span class="unit">m</span></label>
|
||||||
<input type="number" id="radius" value="100" />
|
<input type="text" id="filter-radius" maxlength="9" value="100" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="entity-table-scroll">
|
<div id="entity-table-scroll">
|
||||||
|
@ -87,9 +101,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div id="no-entities">
|
<div id="no-entities">
|
||||||
No entities found <span id="no-entities-in-view">in view</span> within a <span id="no-entities-radius">100</span> meter radius. Try moving to a different location and refreshing.
|
There are no entities to display. Please check your filters or create an entity to begin.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@ const DESCENDING_STRING = '▾';
|
||||||
const LOCKED_GLYPH = "";
|
const LOCKED_GLYPH = "";
|
||||||
const VISIBLE_GLYPH = "";
|
const VISIBLE_GLYPH = "";
|
||||||
const TRANSPARENCY_GLYPH = "";
|
const TRANSPARENCY_GLYPH = "";
|
||||||
const BAKED_GLYPH = ""
|
const BAKED_GLYPH = "";
|
||||||
const SCRIPT_GLYPH = "k";
|
const SCRIPT_GLYPH = "k";
|
||||||
const BYTES_PER_MEGABYTE = 1024 * 1024;
|
const BYTES_PER_MEGABYTE = 1024 * 1024;
|
||||||
const IMAGE_MODEL_NAME = 'default-image-model.fbx';
|
const IMAGE_MODEL_NAME = 'default-image-model.fbx';
|
||||||
|
@ -23,6 +23,7 @@ const FILTER_IN_VIEW_ATTRIBUTE = "pressed";
|
||||||
const WINDOW_NONVARIABLE_HEIGHT = 227;
|
const WINDOW_NONVARIABLE_HEIGHT = 227;
|
||||||
const NUM_COLUMNS = 12;
|
const NUM_COLUMNS = 12;
|
||||||
const EMPTY_ENTITY_ID = "0";
|
const EMPTY_ENTITY_ID = "0";
|
||||||
|
const MAX_LENGTH_RADIUS = 9;
|
||||||
const DELETE = 46; // Key code for the delete key.
|
const DELETE = 46; // Key code for the delete key.
|
||||||
const KEY_P = 80; // Key code for letter p used for Parenting hotkey.
|
const KEY_P = 80; // Key code for letter p used for Parenting hotkey.
|
||||||
|
|
||||||
|
@ -54,10 +55,34 @@ const COMPARE_ASCENDING = function(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
};
|
||||||
const COMPARE_DESCENDING = function(a, b) {
|
const COMPARE_DESCENDING = function(a, b) {
|
||||||
return COMPARE_ASCENDING(b, a);
|
return COMPARE_ASCENDING(b, a);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const FILTER_TYPES = [
|
||||||
|
"Shape",
|
||||||
|
"Model",
|
||||||
|
"Image",
|
||||||
|
"Light",
|
||||||
|
"Zone",
|
||||||
|
"Web",
|
||||||
|
"Material",
|
||||||
|
"ParticleEffect",
|
||||||
|
"Text",
|
||||||
|
];
|
||||||
|
|
||||||
|
const ICON_FOR_TYPE = {
|
||||||
|
Shape: "n",
|
||||||
|
Model: "",
|
||||||
|
Image: "",
|
||||||
|
Light: "p",
|
||||||
|
Zone: "o",
|
||||||
|
Web: "q",
|
||||||
|
Material: "",
|
||||||
|
ParticleEffect: "",
|
||||||
|
Text: "l",
|
||||||
|
};
|
||||||
|
|
||||||
// List of all entities
|
// List of all entities
|
||||||
var entities = [];
|
var entities = [];
|
||||||
|
@ -70,8 +95,14 @@ var selectedEntities = [];
|
||||||
|
|
||||||
var entityList = null; // The ListView
|
var entityList = null; // The ListView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type EntityListContextMenu
|
||||||
|
*/
|
||||||
|
var entityListContextMenu = null;
|
||||||
|
|
||||||
var currentSortColumn = 'type';
|
var currentSortColumn = 'type';
|
||||||
var currentSortOrder = ASCENDING_SORT;
|
var currentSortOrder = ASCENDING_SORT;
|
||||||
|
var typeFilters = [];
|
||||||
var isFilterInView = false;
|
var isFilterInView = false;
|
||||||
var showExtraInfo = false;
|
var showExtraInfo = false;
|
||||||
|
|
||||||
|
@ -105,9 +136,12 @@ function loaded() {
|
||||||
elToggleLocked = document.getElementById("locked");
|
elToggleLocked = document.getElementById("locked");
|
||||||
elToggleVisible = document.getElementById("visible");
|
elToggleVisible = document.getElementById("visible");
|
||||||
elDelete = document.getElementById("delete");
|
elDelete = document.getElementById("delete");
|
||||||
elFilter = document.getElementById("filter");
|
elFilterTypeSelectBox = document.getElementById("filter-type-select-box");
|
||||||
elInView = document.getElementById("in-view")
|
elFilterTypeText = document.getElementById("filter-type-text");
|
||||||
elRadius = document.getElementById("radius");
|
elFilterTypeCheckboxes = document.getElementById("filter-type-checkboxes");
|
||||||
|
elFilterSearch = document.getElementById("filter-search");
|
||||||
|
elFilterInView = document.getElementById("filter-in-view")
|
||||||
|
elFilterRadius = document.getElementById("filter-radius");
|
||||||
elExport = document.getElementById("export");
|
elExport = document.getElementById("export");
|
||||||
elPal = document.getElementById("pal");
|
elPal = document.getElementById("pal");
|
||||||
elInfoToggle = document.getElementById("info-toggle");
|
elInfoToggle = document.getElementById("info-toggle");
|
||||||
|
@ -115,9 +149,8 @@ function loaded() {
|
||||||
elSelectedEntitiesCount = document.getElementById("selected-entities-count");
|
elSelectedEntitiesCount = document.getElementById("selected-entities-count");
|
||||||
elVisibleEntitiesCount = document.getElementById("visible-entities-count");
|
elVisibleEntitiesCount = document.getElementById("visible-entities-count");
|
||||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||||
elNoEntitiesInView = document.getElementById("no-entities-in-view");
|
|
||||||
elNoEntitiesRadius = document.getElementById("no-entities-radius");
|
|
||||||
|
|
||||||
|
document.body.onclick = onBodyClick;
|
||||||
document.getElementById("entity-name").onclick = function() {
|
document.getElementById("entity-name").onclick = function() {
|
||||||
setSortColumn('name');
|
setSortColumn('name');
|
||||||
};
|
};
|
||||||
|
@ -127,74 +160,185 @@ function loaded() {
|
||||||
document.getElementById("entity-url").onclick = function() {
|
document.getElementById("entity-url").onclick = function() {
|
||||||
setSortColumn('url');
|
setSortColumn('url');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-locked").onclick = function () {
|
document.getElementById("entity-locked").onclick = function() {
|
||||||
setSortColumn('locked');
|
setSortColumn('locked');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-visible").onclick = function () {
|
document.getElementById("entity-visible").onclick = function() {
|
||||||
setSortColumn('visible');
|
setSortColumn('visible');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-verticesCount").onclick = function () {
|
document.getElementById("entity-verticesCount").onclick = function() {
|
||||||
setSortColumn('verticesCount');
|
setSortColumn('verticesCount');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-texturesCount").onclick = function () {
|
document.getElementById("entity-texturesCount").onclick = function() {
|
||||||
setSortColumn('texturesCount');
|
setSortColumn('texturesCount');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-texturesSize").onclick = function () {
|
document.getElementById("entity-texturesSize").onclick = function() {
|
||||||
setSortColumn('texturesSize');
|
setSortColumn('texturesSize');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-hasTransparent").onclick = function () {
|
document.getElementById("entity-hasTransparent").onclick = function() {
|
||||||
setSortColumn('hasTransparent');
|
setSortColumn('hasTransparent');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-isBaked").onclick = function () {
|
document.getElementById("entity-isBaked").onclick = function() {
|
||||||
setSortColumn('isBaked');
|
setSortColumn('isBaked');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-drawCalls").onclick = function () {
|
document.getElementById("entity-drawCalls").onclick = function() {
|
||||||
setSortColumn('drawCalls');
|
setSortColumn('drawCalls');
|
||||||
};
|
};
|
||||||
document.getElementById("entity-hasScript").onclick = function () {
|
document.getElementById("entity-hasScript").onclick = function() {
|
||||||
setSortColumn('hasScript');
|
setSortColumn('hasScript');
|
||||||
};
|
};
|
||||||
elRefresh.onclick = function() {
|
elRefresh.onclick = function() {
|
||||||
refreshEntities();
|
refreshEntities();
|
||||||
}
|
};
|
||||||
elToggleLocked.onclick = function() {
|
elToggleLocked.onclick = function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleLocked' }));
|
||||||
}
|
};
|
||||||
elToggleVisible.onclick = function() {
|
elToggleVisible.onclick = function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleVisible' }));
|
||||||
}
|
};
|
||||||
elExport.onclick = function() {
|
elExport.onclick = function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'export'}));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'export'}));
|
||||||
}
|
};
|
||||||
elPal.onclick = function() {
|
elPal.onclick = function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'pal' }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'pal' }));
|
||||||
}
|
};
|
||||||
elDelete.onclick = function() {
|
elDelete.onclick = function() {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||||
}
|
};
|
||||||
elFilter.onkeyup = refreshEntityList;
|
elFilterTypeSelectBox.onclick = onToggleTypeDropdown;
|
||||||
elFilter.onpaste = refreshEntityList;
|
elFilterSearch.onkeyup = refreshEntityList;
|
||||||
elFilter.onchange = onFilterChange;
|
elFilterSearch.onsearch = refreshEntityList;
|
||||||
elFilter.onblur = refreshFooter;
|
elFilterInView.onclick = toggleFilterInView;
|
||||||
elInView.onclick = toggleFilterInView;
|
elFilterRadius.onkeyup = onRadiusChange;
|
||||||
elRadius.onchange = onRadiusChange;
|
elFilterRadius.onchange = onRadiusChange;
|
||||||
|
elFilterRadius.onclick = onRadiusChange;
|
||||||
elInfoToggle.onclick = toggleInfo;
|
elInfoToggle.onclick = toggleInfo;
|
||||||
|
|
||||||
elNoEntitiesInView.style.display = "none";
|
// create filter type dropdown checkboxes with label and icon for each type
|
||||||
|
for (let i = 0; i < FILTER_TYPES.length; ++i) {
|
||||||
|
let type = FILTER_TYPES[i];
|
||||||
|
let typeFilterID = "filter-type-" + type;
|
||||||
|
let elDiv = document.createElement('div');
|
||||||
|
let elLabel = document.createElement('label');
|
||||||
|
elLabel.setAttribute("for", typeFilterID);
|
||||||
|
elLabel.innerText = type;
|
||||||
|
let elSpan = document.createElement('span');
|
||||||
|
elSpan.setAttribute("class", "typeIcon");
|
||||||
|
elSpan.innerHTML = ICON_FOR_TYPE[type];
|
||||||
|
let elInput = document.createElement('input');
|
||||||
|
elInput.setAttribute("type", "checkbox");
|
||||||
|
elInput.setAttribute("id", typeFilterID);
|
||||||
|
elInput.setAttribute("filterType", type);
|
||||||
|
elInput.checked = true; // all types are checked initially
|
||||||
|
toggleTypeFilter(elInput, false); // add all types to the initial types filter
|
||||||
|
elDiv.appendChild(elInput);
|
||||||
|
elLabel.insertBefore(elSpan, elLabel.childNodes[0]);
|
||||||
|
elDiv.appendChild(elLabel);
|
||||||
|
elFilterTypeCheckboxes.appendChild(elDiv);
|
||||||
|
elDiv.onclick = onToggleTypeFilter;
|
||||||
|
}
|
||||||
|
|
||||||
entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow,
|
entityList = new ListView(elEntityTableBody, elEntityTableScroll, elEntityTableHeaderRow,
|
||||||
createRow, updateRow, clearRow, WINDOW_NONVARIABLE_HEIGHT);
|
createRow, updateRow, clearRow, WINDOW_NONVARIABLE_HEIGHT);
|
||||||
|
|
||||||
|
entityListContextMenu = new EntityListContextMenu();
|
||||||
|
|
||||||
|
|
||||||
|
function startRenamingEntity(entityID) {
|
||||||
|
let entity = entitiesByID[entityID];
|
||||||
|
if (!entity || entity.locked || !entity.elRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let elCell = entity.elRow.childNodes[COLUMN_INDEX.NAME];
|
||||||
|
let elRenameInput = document.createElement("input");
|
||||||
|
elRenameInput.setAttribute('class', 'rename-entity');
|
||||||
|
elRenameInput.value = entity.name;
|
||||||
|
let ignoreClicks = function(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
elRenameInput.onclick = ignoreClicks;
|
||||||
|
elRenameInput.ondblclick = ignoreClicks;
|
||||||
|
elRenameInput.onkeyup = function(keyEvent) {
|
||||||
|
if (keyEvent.key === "Enter") {
|
||||||
|
elRenameInput.blur();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
elRenameInput.onblur = function(event) {
|
||||||
|
let value = elRenameInput.value;
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
type: 'rename',
|
||||||
|
entityID: entityID,
|
||||||
|
name: value
|
||||||
|
}));
|
||||||
|
entity.name = value;
|
||||||
|
elCell.innerText = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
elCell.innerHTML = "";
|
||||||
|
elCell.appendChild(elRenameInput);
|
||||||
|
|
||||||
|
elRenameInput.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
entityListContextMenu.setOnSelectedCallback(function(optionName, selectedEntityID) {
|
||||||
|
switch (optionName) {
|
||||||
|
case "Cut":
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'cut' }));
|
||||||
|
break;
|
||||||
|
case "Copy":
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'copy' }));
|
||||||
|
break;
|
||||||
|
case "Paste":
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'paste' }));
|
||||||
|
break;
|
||||||
|
case "Rename":
|
||||||
|
startRenamingEntity(selectedEntityID);
|
||||||
|
break;
|
||||||
|
case "Duplicate":
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'duplicate' }));
|
||||||
|
break;
|
||||||
|
case "Delete":
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onRowContextMenu(clickEvent) {
|
||||||
|
let entityID = this.dataset.entityID;
|
||||||
|
|
||||||
|
if (!selectedEntities.includes(entityID)) {
|
||||||
|
let selection = [entityID];
|
||||||
|
updateSelectedEntities(selection);
|
||||||
|
|
||||||
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
|
type: "selectionUpdate",
|
||||||
|
focus: false,
|
||||||
|
entityIds: selection,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let enabledContextMenuItems = ['Copy', 'Paste', 'Duplicate'];
|
||||||
|
if (entitiesByID[entityID] && !entitiesByID[entityID].locked) {
|
||||||
|
enabledContextMenuItems.push('Cut');
|
||||||
|
enabledContextMenuItems.push('Rename');
|
||||||
|
enabledContextMenuItems.push('Delete');
|
||||||
|
}
|
||||||
|
|
||||||
|
entityListContextMenu.open(clickEvent, entityID, enabledContextMenuItems);
|
||||||
|
}
|
||||||
|
|
||||||
function onRowClicked(clickEvent) {
|
function onRowClicked(clickEvent) {
|
||||||
let entityID = this.dataset.entityID;
|
let entityID = this.dataset.entityID;
|
||||||
let selection = [entityID];
|
let selection = [entityID];
|
||||||
|
|
||||||
if (clickEvent.ctrlKey) {
|
if (clickEvent.ctrlKey) {
|
||||||
let selectedIndex = selectedEntities.indexOf(entityID);
|
let selectedIndex = selectedEntities.indexOf(entityID);
|
||||||
if (selectedIndex >= 0) {
|
if (selectedIndex >= 0) {
|
||||||
selection = [];
|
selection = [];
|
||||||
selection = selection.concat(selectedEntities);
|
selection = selection.concat(selectedEntities);
|
||||||
selection.splice(selectedIndex, 1)
|
selection.splice(selectedIndex, 1);
|
||||||
} else {
|
} else {
|
||||||
selection = selection.concat(selectedEntities);
|
selection = selection.concat(selectedEntities);
|
||||||
}
|
}
|
||||||
|
@ -221,28 +365,29 @@ function loaded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!clickEvent.ctrlKey && !clickEvent.shiftKey && selectedEntities.length === 1) {
|
} else if (!clickEvent.ctrlKey && !clickEvent.shiftKey && selectedEntities.length === 1) {
|
||||||
// if reselecting the same entity then deselect it
|
// if reselecting the same entity then start renaming it
|
||||||
if (selectedEntities[0] === entityID) {
|
if (selectedEntities[0] === entityID) {
|
||||||
selection = [];
|
startRenamingEntity(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelectedEntities(selection);
|
updateSelectedEntities(selection, false);
|
||||||
|
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "selectionUpdate",
|
type: "selectionUpdate",
|
||||||
focus: false,
|
focus: false,
|
||||||
entityIds: selection,
|
entityIds: selection,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
refreshFooter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRowDoubleClicked() {
|
function onRowDoubleClicked() {
|
||||||
|
let selection = [this.dataset.entityID];
|
||||||
|
updateSelectedEntities(selection, false);
|
||||||
|
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "selectionUpdate",
|
type: "selectionUpdate",
|
||||||
focus: true,
|
focus: true,
|
||||||
entityIds: [this.dataset.entityID],
|
entityIds: selection,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +434,7 @@ function loaded() {
|
||||||
hasScript: entity.hasScript,
|
hasScript: entity.hasScript,
|
||||||
elRow: null, // if this entity has a visible row element assigned to it
|
elRow: null, // if this entity has a visible row element assigned to it
|
||||||
selected: false // if this entity is selected for edit regardless of having a visible row
|
selected: false // if this entity is selected for edit regardless of having a visible row
|
||||||
}
|
};
|
||||||
|
|
||||||
entities.push(entityData);
|
entities.push(entityData);
|
||||||
entitiesByID[entityData.id] = entityData;
|
entitiesByID[entityData.id] = entityData;
|
||||||
|
@ -302,17 +447,16 @@ function loaded() {
|
||||||
function refreshEntityList() {
|
function refreshEntityList() {
|
||||||
PROFILE("refresh-entity-list", function() {
|
PROFILE("refresh-entity-list", function() {
|
||||||
PROFILE("filter", function() {
|
PROFILE("filter", function() {
|
||||||
let searchTerm = elFilter.value.toLowerCase();
|
let searchTerm = elFilterSearch.value.toLowerCase();
|
||||||
if (searchTerm === '') {
|
visibleEntities = entities.filter(function(e) {
|
||||||
visibleEntities = entities.slice(0);
|
let type = e.type === "Box" || e.type === "Sphere" ? "Shape" : e.type;
|
||||||
} else {
|
let typeFilter = typeFilters.indexOf(type) > -1;
|
||||||
visibleEntities = entities.filter(function(e) {
|
let searchFilter = searchTerm === '' || (e.name.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||||
return e.name.toLowerCase().indexOf(searchTerm) > -1
|
e.type.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||||
|| e.type.toLowerCase().indexOf(searchTerm) > -1
|
e.fullUrl.toLowerCase().indexOf(searchTerm) > -1 ||
|
||||||
|| e.fullUrl.toLowerCase().indexOf(searchTerm) > -1
|
e.id.toLowerCase().indexOf(searchTerm) > -1);
|
||||||
|| e.id.toLowerCase().indexOf(searchTerm) > -1;
|
return typeFilter && searchFilter;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
PROFILE("sort", function() {
|
PROFILE("sort", function() {
|
||||||
|
@ -418,7 +562,7 @@ function loaded() {
|
||||||
isBaked: document.querySelector('#entity-isBaked .sort-order'),
|
isBaked: document.querySelector('#entity-isBaked .sort-order'),
|
||||||
drawCalls: document.querySelector('#entity-drawCalls .sort-order'),
|
drawCalls: document.querySelector('#entity-drawCalls .sort-order'),
|
||||||
hasScript: document.querySelector('#entity-hasScript .sort-order'),
|
hasScript: document.querySelector('#entity-hasScript .sort-order'),
|
||||||
}
|
};
|
||||||
function setSortColumn(column) {
|
function setSortColumn(column) {
|
||||||
PROFILE("set-sort-column", function() {
|
PROFILE("set-sort-column", function() {
|
||||||
if (currentSortColumn === column) {
|
if (currentSortColumn === column) {
|
||||||
|
@ -453,7 +597,7 @@ function loaded() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelectedEntities(selectedIDs) {
|
function updateSelectedEntities(selectedIDs, autoScroll) {
|
||||||
let notFound = false;
|
let notFound = false;
|
||||||
|
|
||||||
// reset all currently selected entities and their rows first
|
// reset all currently selected entities and their rows first
|
||||||
|
@ -482,6 +626,26 @@ function loaded() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (autoScroll && selectedIDs.length > 0) {
|
||||||
|
let firstItem = Number.MAX_VALUE;
|
||||||
|
let lastItem = -1;
|
||||||
|
let itemFound = false;
|
||||||
|
visibleEntities.forEach(function(entity, index) {
|
||||||
|
if (selectedIDs.indexOf(entity.id) !== -1) {
|
||||||
|
if (firstItem > index) {
|
||||||
|
firstItem = index;
|
||||||
|
}
|
||||||
|
if (lastItem < index) {
|
||||||
|
lastItem = index;
|
||||||
|
}
|
||||||
|
itemFound = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (itemFound) {
|
||||||
|
entityList.scrollToRow(firstItem, lastItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
refreshFooter();
|
refreshFooter();
|
||||||
|
|
||||||
return notFound;
|
return notFound;
|
||||||
|
@ -502,6 +666,7 @@ function loaded() {
|
||||||
}
|
}
|
||||||
row.appendChild(column);
|
row.appendChild(column);
|
||||||
}
|
}
|
||||||
|
row.oncontextmenu = onRowContextMenu;
|
||||||
row.onclick = onRowClicked;
|
row.onclick = onRowClicked;
|
||||||
row.ondblclick = onRowDoubleClicked;
|
row.ondblclick = onRowDoubleClicked;
|
||||||
return row;
|
return row;
|
||||||
|
@ -582,29 +747,74 @@ function loaded() {
|
||||||
function toggleFilterInView() {
|
function toggleFilterInView() {
|
||||||
isFilterInView = !isFilterInView;
|
isFilterInView = !isFilterInView;
|
||||||
if (isFilterInView) {
|
if (isFilterInView) {
|
||||||
elInView.setAttribute(FILTER_IN_VIEW_ATTRIBUTE, FILTER_IN_VIEW_ATTRIBUTE);
|
elFilterInView.setAttribute(FILTER_IN_VIEW_ATTRIBUTE, FILTER_IN_VIEW_ATTRIBUTE);
|
||||||
elNoEntitiesInView.style.display = "inline";
|
|
||||||
} else {
|
} else {
|
||||||
elInView.removeAttribute(FILTER_IN_VIEW_ATTRIBUTE);
|
elFilterInView.removeAttribute(FILTER_IN_VIEW_ATTRIBUTE);
|
||||||
elNoEntitiesInView.style.display = "none";
|
|
||||||
}
|
}
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: "filterInView", filterInView: isFilterInView }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: "filterInView", filterInView: isFilterInView }));
|
||||||
refreshEntities();
|
refreshEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onFilterChange() {
|
|
||||||
refreshEntityList();
|
|
||||||
entityList.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRadiusChange() {
|
function onRadiusChange() {
|
||||||
elRadius.value = Math.max(elRadius.value, 0);
|
elFilterRadius.value = elFilterRadius.value.replace(/[^0-9]/g, '');
|
||||||
elNoEntitiesRadius.firstChild.nodeValue = elRadius.value;
|
elFilterRadius.value = Math.max(elFilterRadius.value, 0);
|
||||||
elNoEntitiesMessage.style.display = "none";
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elFilterRadius.value }));
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elRadius.value }));
|
|
||||||
refreshEntities();
|
refreshEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isTypeDropdownVisible() {
|
||||||
|
return elFilterTypeCheckboxes.style.display === "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTypeDropdown() {
|
||||||
|
elFilterTypeCheckboxes.style.display = isTypeDropdownVisible() ? "none" : "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function onToggleTypeDropdown(event) {
|
||||||
|
toggleTypeDropdown();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleTypeFilter(elInput, refresh) {
|
||||||
|
let type = elInput.getAttribute("filterType");
|
||||||
|
let typeChecked = elInput.checked;
|
||||||
|
|
||||||
|
let typeFilterIndex = typeFilters.indexOf(type);
|
||||||
|
if (!typeChecked && typeFilterIndex > -1) {
|
||||||
|
typeFilters.splice(typeFilterIndex, 1);
|
||||||
|
} else if (typeChecked && typeFilterIndex === -1) {
|
||||||
|
typeFilters.push(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeFilters.length === 0) {
|
||||||
|
elFilterTypeText.innerText = "No Types";
|
||||||
|
} else if (typeFilters.length === FILTER_TYPES.length) {
|
||||||
|
elFilterTypeText.innerText = "All Types";
|
||||||
|
} else {
|
||||||
|
elFilterTypeText.innerText = "Types...";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
|
refreshEntityList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onToggleTypeFilter(event) {
|
||||||
|
let elTarget = event.target;
|
||||||
|
if (elTarget instanceof HTMLInputElement) {
|
||||||
|
toggleTypeFilter(elTarget, true);
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBodyClick(event) {
|
||||||
|
// if clicking anywhere outside of the type filter dropdown (since click event bubbled up to onBodyClick and
|
||||||
|
// propagation wasn't stopped by onToggleTypeFilter or onToggleTypeDropdown) and the dropdown is open then close it
|
||||||
|
if (isTypeDropdownVisible()) {
|
||||||
|
toggleTypeDropdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toggleInfo(event) {
|
function toggleInfo(event) {
|
||||||
showExtraInfo = !showExtraInfo;
|
showExtraInfo = !showExtraInfo;
|
||||||
if (showExtraInfo) {
|
if (showExtraInfo) {
|
||||||
|
@ -617,7 +827,7 @@ function loaded() {
|
||||||
entityList.resize();
|
entityList.resize();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("keydown", function (keyDownEvent) {
|
document.addEventListener("keydown", function (keyDownEvent) {
|
||||||
if (keyDownEvent.target.nodeName === "INPUT") {
|
if (keyDownEvent.target.nodeName === "INPUT") {
|
||||||
return;
|
return;
|
||||||
|
@ -641,7 +851,7 @@ function loaded() {
|
||||||
if (data.type === "clearEntityList") {
|
if (data.type === "clearEntityList") {
|
||||||
clearEntities();
|
clearEntities();
|
||||||
} else if (data.type === "selectionUpdate") {
|
} else if (data.type === "selectionUpdate") {
|
||||||
let notFound = updateSelectedEntities(data.selectedIDs);
|
let notFound = updateSelectedEntities(data.selectedIDs, true);
|
||||||
if (notFound) {
|
if (notFound) {
|
||||||
refreshEntities();
|
refreshEntities();
|
||||||
}
|
}
|
||||||
|
@ -653,13 +863,13 @@ function loaded() {
|
||||||
clearEntities();
|
clearEntities();
|
||||||
} else {
|
} else {
|
||||||
updateEntityData(newEntities);
|
updateEntityData(newEntities);
|
||||||
updateSelectedEntities(data.selectedIDs);
|
updateSelectedEntities(data.selectedIDs, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (data.type === "removeEntities" && data.deletedIDs !== undefined && data.selectedIDs !== undefined) {
|
} else if (data.type === "removeEntities" && data.deletedIDs !== undefined && data.selectedIDs !== undefined) {
|
||||||
removeEntities(data.deletedIDs);
|
removeEntities(data.deletedIDs);
|
||||||
updateSelectedEntities(data.selectedIDs);
|
updateSelectedEntities(data.selectedIDs, true);
|
||||||
} else if (data.type === "deleted" && data.ids) {
|
} else if (data.type === "deleted" && data.ids) {
|
||||||
removeEntities(data.ids);
|
removeEntities(data.ids);
|
||||||
}
|
}
|
||||||
|
@ -672,8 +882,15 @@ function loaded() {
|
||||||
|
|
||||||
augmentSpinButtons();
|
augmentSpinButtons();
|
||||||
|
|
||||||
// Disable right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
|
||||||
document.addEventListener("contextmenu", function (event) {
|
document.addEventListener("contextmenu", function (event) {
|
||||||
|
entityListContextMenu.close();
|
||||||
|
|
||||||
|
// Disable default right-click context menu which is not visible in the HMD and makes it seem like the app has locked
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
// close context menu when switching focus to another window
|
||||||
|
$(window).blur(function() {
|
||||||
|
entityListContextMenu.close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
163
scripts/system/html/js/entityListContextMenu.js
Normal file
163
scripts/system/html/js/entityListContextMenu.js
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
//
|
||||||
|
// entityListContextMenu.js
|
||||||
|
//
|
||||||
|
// exampleContextMenus.js was originally created by David Rowe on 22 Aug 2018.
|
||||||
|
// Modified to entityListContextMenu.js by Thijs Wenker on 10 Oct 2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
/* eslint-env browser */
|
||||||
|
const CONTEXT_MENU_CLASS = "context-menu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ContextMenu class for EntityList
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function EntityListContextMenu() {
|
||||||
|
this._elContextMenu = null;
|
||||||
|
this._onSelectedCallback = null;
|
||||||
|
this._listItems = [];
|
||||||
|
this._initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityListContextMenu.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_elContextMenu: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onSelectedCallback: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_selectedEntityID: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_listItems: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the context menu
|
||||||
|
*/
|
||||||
|
close: function() {
|
||||||
|
if (this.isContextMenuOpen()) {
|
||||||
|
this._elContextMenu.style.display = "none";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isContextMenuOpen: function() {
|
||||||
|
return this._elContextMenu.style.display === "block";
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the context menu
|
||||||
|
* @param clickEvent
|
||||||
|
* @param selectedEntityID
|
||||||
|
* @param enabledOptions
|
||||||
|
*/
|
||||||
|
open: function(clickEvent, selectedEntityID, enabledOptions) {
|
||||||
|
this._selectedEntityID = selectedEntityID;
|
||||||
|
|
||||||
|
this._listItems.forEach(function(listItem) {
|
||||||
|
let enabled = enabledOptions.includes(listItem.label);
|
||||||
|
listItem.enabled = enabled;
|
||||||
|
listItem.element.setAttribute('class', enabled ? '' : 'disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
this._elContextMenu.style.display = "block";
|
||||||
|
this._elContextMenu.style.left
|
||||||
|
= Math.min(clickEvent.pageX, document.body.offsetWidth - this._elContextMenu.offsetWidth).toString() + "px";
|
||||||
|
this._elContextMenu.style.top
|
||||||
|
= Math.min(clickEvent.pageY, document.body.clientHeight - this._elContextMenu.offsetHeight).toString() + "px";
|
||||||
|
clickEvent.stopPropagation();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the callback for when a menu item is selected
|
||||||
|
* @param onSelectedCallback
|
||||||
|
*/
|
||||||
|
setOnSelectedCallback: function(onSelectedCallback) {
|
||||||
|
this._onSelectedCallback = onSelectedCallback;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a labeled item to the context menu
|
||||||
|
* @param itemLabel
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_addListItem: function(itemLabel) {
|
||||||
|
let elListItem = document.createElement("li");
|
||||||
|
elListItem.innerText = itemLabel;
|
||||||
|
|
||||||
|
let listItem = {
|
||||||
|
label: itemLabel,
|
||||||
|
element: elListItem,
|
||||||
|
enabled: false
|
||||||
|
};
|
||||||
|
|
||||||
|
elListItem.addEventListener("click", function () {
|
||||||
|
if (listItem.enabled && this._onSelectedCallback) {
|
||||||
|
this._onSelectedCallback.call(this, itemLabel, this._selectedEntityID);
|
||||||
|
}
|
||||||
|
}.bind(this), false);
|
||||||
|
|
||||||
|
elListItem.setAttribute('class', 'disabled');
|
||||||
|
|
||||||
|
this._listItems.push(listItem);
|
||||||
|
this._elContextMenu.appendChild(elListItem);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a separator item to the context menu
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_addListSeparator: function() {
|
||||||
|
let elListItem = document.createElement("li");
|
||||||
|
elListItem.setAttribute('class', 'separator');
|
||||||
|
this._elContextMenu.appendChild(elListItem);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the context menu.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_initialize: function() {
|
||||||
|
this._elContextMenu = document.createElement("ul");
|
||||||
|
this._elContextMenu.setAttribute("class", CONTEXT_MENU_CLASS);
|
||||||
|
document.body.appendChild(this._elContextMenu);
|
||||||
|
|
||||||
|
this._addListItem("Cut");
|
||||||
|
this._addListItem("Copy");
|
||||||
|
this._addListItem("Paste");
|
||||||
|
this._addListSeparator();
|
||||||
|
this._addListItem("Rename");
|
||||||
|
this._addListItem("Duplicate");
|
||||||
|
this._addListItem("Delete");
|
||||||
|
|
||||||
|
// Ignore clicks on context menu background or separator.
|
||||||
|
this._elContextMenu.addEventListener("click", function(event) {
|
||||||
|
// Sink clicks on context menu background or separator but let context menu item clicks through.
|
||||||
|
if (event.target.classList.contains(CONTEXT_MENU_CLASS)) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Provide means to close context menu without clicking menu item.
|
||||||
|
document.body.addEventListener("click", this.close.bind(this));
|
||||||
|
document.body.addEventListener("keydown", function(event) {
|
||||||
|
// Close context menu with Esc key.
|
||||||
|
if (this.isContextMenuOpen() && event.key === "Escape") {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
};
|
|
@ -38,7 +38,7 @@ function ListView(elTableBody, elTableScroll, elTableHeaderRow, createRowFunctio
|
||||||
this.lastRowShiftScrollTop = 0;
|
this.lastRowShiftScrollTop = 0;
|
||||||
|
|
||||||
this.initialize();
|
this.initialize();
|
||||||
};
|
}
|
||||||
|
|
||||||
ListView.prototype = {
|
ListView.prototype = {
|
||||||
getNumRows: function() {
|
getNumRows: function() {
|
||||||
|
@ -152,6 +152,30 @@ ListView.prototype = {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scrolls firstRowIndex with least effort, also tries to make the window include the other selections in case lastRowIndex is set.
|
||||||
|
* In the case that firstRowIndex and lastRowIndex are already within the visible bounds then nothing will happen.
|
||||||
|
* @param {number} firstRowIndex - The row that will be scrolled to.
|
||||||
|
* @param {number} lastRowIndex - The last index of the bound.
|
||||||
|
*/
|
||||||
|
scrollToRow: function (firstRowIndex, lastRowIndex) {
|
||||||
|
lastRowIndex = lastRowIndex ? lastRowIndex : firstRowIndex;
|
||||||
|
let boundingTop = firstRowIndex * this.rowHeight;
|
||||||
|
let boundingBottom = (lastRowIndex * this.rowHeight) + this.rowHeight;
|
||||||
|
if ((boundingBottom - boundingTop) > this.elTableScroll.clientHeight) {
|
||||||
|
boundingBottom = boundingTop + this.elTableScroll.clientHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentVisibleAreaTop = this.elTableScroll.scrollTop;
|
||||||
|
let currentVisibleAreaBottom = currentVisibleAreaTop + this.elTableScroll.clientHeight;
|
||||||
|
|
||||||
|
if (boundingTop < currentVisibleAreaTop) {
|
||||||
|
this.elTableScroll.scrollTop = boundingTop;
|
||||||
|
} else if (boundingBottom > currentVisibleAreaBottom) {
|
||||||
|
this.elTableScroll.scrollTop = boundingBottom - (this.elTableScroll.clientHeight);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
// block refreshing before rows are initialized
|
// block refreshing before rows are initialized
|
||||||
|
|
|
@ -15,7 +15,7 @@ var PROFILING_ENABLED = false;
|
||||||
var profileIndent = '';
|
var profileIndent = '';
|
||||||
const PROFILE_NOOP = function(_name, fn, args) {
|
const PROFILE_NOOP = function(_name, fn, args) {
|
||||||
fn.apply(this, args);
|
fn.apply(this, args);
|
||||||
} ;
|
};
|
||||||
PROFILE = !PROFILING_ENABLED ? PROFILE_NOOP : function(name, fn, args) {
|
PROFILE = !PROFILING_ENABLED ? PROFILE_NOOP : function(name, fn, args) {
|
||||||
console.log("PROFILE-Script " + profileIndent + "(" + name + ") Begin");
|
console.log("PROFILE-Script " + profileIndent + "(" + name + ") Begin");
|
||||||
var previousIndent = profileIndent;
|
var previousIndent = profileIndent;
|
||||||
|
@ -98,7 +98,11 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
that.setVisible(!visible);
|
that.setVisible(!visible);
|
||||||
};
|
};
|
||||||
|
|
||||||
selectionManager.addEventListener(function() {
|
selectionManager.addEventListener(function(isSelectionUpdate, caller) {
|
||||||
|
if (caller === that) {
|
||||||
|
// ignore events that we emitted from the entity list itself
|
||||||
|
return;
|
||||||
|
}
|
||||||
var selectedIDs = [];
|
var selectedIDs = [];
|
||||||
|
|
||||||
for (var i = 0; i < selectionManager.selections.length; i++) {
|
for (var i = 0; i < selectionManager.selections.length; i++) {
|
||||||
|
@ -224,7 +228,7 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
for (var i = 0; i < ids.length; i++) {
|
for (var i = 0; i < ids.length; i++) {
|
||||||
entityIDs.push(ids[i]);
|
entityIDs.push(ids[i]);
|
||||||
}
|
}
|
||||||
selectionManager.setSelections(entityIDs);
|
selectionManager.setSelections(entityIDs, that);
|
||||||
if (data.focus) {
|
if (data.focus) {
|
||||||
cameraManager.enable();
|
cameraManager.enable();
|
||||||
cameraManager.focus(selectionManager.worldPosition,
|
cameraManager.focus(selectionManager.worldPosition,
|
||||||
|
@ -245,7 +249,7 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
Window.saveAsync("Select Where to Save", "", "*.json");
|
Window.saveAsync("Select Where to Save", "", "*.json");
|
||||||
}
|
}
|
||||||
} else if (data.type === "pal") {
|
} else if (data.type === "pal") {
|
||||||
var sessionIds = {}; // Collect the sessionsIds of all selected entitities, w/o duplicates.
|
var sessionIds = {}; // Collect the sessionsIds of all selected entities, w/o duplicates.
|
||||||
selectionManager.selections.forEach(function (id) {
|
selectionManager.selections.forEach(function (id) {
|
||||||
var lastEditedBy = Entities.getEntityProperties(id, 'lastEditedBy').lastEditedBy;
|
var lastEditedBy = Entities.getEntityProperties(id, 'lastEditedBy').lastEditedBy;
|
||||||
if (lastEditedBy) {
|
if (lastEditedBy) {
|
||||||
|
@ -271,6 +275,19 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
||||||
filterInView = data.filterInView === true;
|
filterInView = data.filterInView === true;
|
||||||
} else if (data.type === "radius") {
|
} else if (data.type === "radius") {
|
||||||
searchRadius = data.radius;
|
searchRadius = data.radius;
|
||||||
|
} else if (data.type === "cut") {
|
||||||
|
SelectionManager.cutSelectedEntities();
|
||||||
|
} else if (data.type === "copy") {
|
||||||
|
SelectionManager.copySelectedEntities();
|
||||||
|
} else if (data.type === "paste") {
|
||||||
|
SelectionManager.pasteEntities();
|
||||||
|
} else if (data.type === "duplicate") {
|
||||||
|
SelectionManager.duplicateSelection();
|
||||||
|
that.sendUpdate();
|
||||||
|
} else if (data.type === "rename") {
|
||||||
|
Entities.editEntity(data.entityID, {name: data.name});
|
||||||
|
// make sure that the name also gets updated in the properties window
|
||||||
|
SelectionManager._update();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ SelectionManager = (function() {
|
||||||
Messages.messageReceived.connect(handleEntitySelectionToolUpdates);
|
Messages.messageReceived.connect(handleEntitySelectionToolUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: HANDLE ENTITY SELECTION TOOL UDPATES
|
// FUNCTION: HANDLE ENTITY SELECTION TOOL UPDATES
|
||||||
function handleEntitySelectionToolUpdates(channel, message, sender) {
|
function handleEntitySelectionToolUpdates(channel, message, sender) {
|
||||||
if (channel !== 'entityToolUpdates') {
|
if (channel !== 'entityToolUpdates') {
|
||||||
return;
|
return;
|
||||||
|
@ -63,7 +63,7 @@ SelectionManager = (function() {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print("setting selection to " + messageParsed.entityID);
|
print("setting selection to " + messageParsed.entityID);
|
||||||
}
|
}
|
||||||
that.setSelections([messageParsed.entityID]);
|
that.setSelections([messageParsed.entityID], that);
|
||||||
}
|
}
|
||||||
} else if (messageParsed.method === "clearSelection") {
|
} else if (messageParsed.method === "clearSelection") {
|
||||||
if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) {
|
if (!SelectionDisplay.triggered() || SelectionDisplay.triggeredHand === messageParsed.hand) {
|
||||||
|
@ -136,7 +136,7 @@ SelectionManager = (function() {
|
||||||
return that.selections.length > 0;
|
return that.selections.length > 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
that.setSelections = function(entityIDs) {
|
that.setSelections = function(entityIDs, caller) {
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
for (var i = 0; i < entityIDs.length; i++) {
|
for (var i = 0; i < entityIDs.length; i++) {
|
||||||
var entityID = entityIDs[i];
|
var entityID = entityIDs[i];
|
||||||
|
@ -144,10 +144,10 @@ SelectionManager = (function() {
|
||||||
Selection.addToSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID);
|
Selection.addToSelectedItemsList(HIGHLIGHT_LIST_NAME, "entity", entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
that._update(true);
|
that._update(true, caller);
|
||||||
};
|
};
|
||||||
|
|
||||||
that.addEntity = function(entityID, toggleSelection) {
|
that.addEntity = function(entityID, toggleSelection, caller) {
|
||||||
if (entityID) {
|
if (entityID) {
|
||||||
var idx = -1;
|
var idx = -1;
|
||||||
for (var i = 0; i < that.selections.length; i++) {
|
for (var i = 0; i < that.selections.length; i++) {
|
||||||
|
@ -165,7 +165,7 @@ SelectionManager = (function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
that._update(true);
|
that._update(true, caller);
|
||||||
};
|
};
|
||||||
|
|
||||||
function removeEntityByID(entityID) {
|
function removeEntityByID(entityID) {
|
||||||
|
@ -176,21 +176,21 @@ SelectionManager = (function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
that.removeEntity = function (entityID) {
|
that.removeEntity = function (entityID, caller) {
|
||||||
removeEntityByID(entityID);
|
removeEntityByID(entityID);
|
||||||
that._update(true);
|
that._update(true, caller);
|
||||||
};
|
};
|
||||||
|
|
||||||
that.removeEntities = function(entityIDs) {
|
that.removeEntities = function(entityIDs, caller) {
|
||||||
for (var i = 0, length = entityIDs.length; i < length; i++) {
|
for (var i = 0, length = entityIDs.length; i < length; i++) {
|
||||||
removeEntityByID(entityIDs[i]);
|
removeEntityByID(entityIDs[i]);
|
||||||
}
|
}
|
||||||
that._update(true);
|
that._update(true, caller);
|
||||||
};
|
};
|
||||||
|
|
||||||
that.clearSelections = function() {
|
that.clearSelections = function(caller) {
|
||||||
that.selections = [];
|
that.selections = [];
|
||||||
that._update(true);
|
that._update(true, caller);
|
||||||
};
|
};
|
||||||
|
|
||||||
that.addChildrenEntities = function(parentEntityID, entityList) {
|
that.addChildrenEntities = function(parentEntityID, entityList) {
|
||||||
|
@ -353,12 +353,12 @@ SelectionManager = (function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return createdEntityIDs;
|
return createdEntityIDs;
|
||||||
}
|
};
|
||||||
|
|
||||||
that.cutSelectedEntities = function() {
|
that.cutSelectedEntities = function() {
|
||||||
copySelectedEntities();
|
that.copySelectedEntities();
|
||||||
deleteSelectedEntities();
|
deleteSelectedEntities();
|
||||||
}
|
};
|
||||||
|
|
||||||
that.copySelectedEntities = function() {
|
that.copySelectedEntities = function() {
|
||||||
var entityProperties = Entities.getMultipleEntityProperties(that.selections);
|
var entityProperties = Entities.getMultipleEntityProperties(that.selections);
|
||||||
|
@ -434,7 +434,7 @@ SelectionManager = (function() {
|
||||||
z: brn.z + entityClipboard.dimensions.z / 2
|
z: brn.z + entityClipboard.dimensions.z / 2
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
that.pasteEntities = function() {
|
that.pasteEntities = function() {
|
||||||
var dimensions = entityClipboard.dimensions;
|
var dimensions = entityClipboard.dimensions;
|
||||||
|
@ -442,7 +442,7 @@ SelectionManager = (function() {
|
||||||
var pastePosition = getPositionToCreateEntity(maxDimension);
|
var pastePosition = getPositionToCreateEntity(maxDimension);
|
||||||
var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position);
|
var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position);
|
||||||
|
|
||||||
var copiedProperties = []
|
var copiedProperties = [];
|
||||||
var ids = [];
|
var ids = [];
|
||||||
entityClipboard.entities.forEach(function(originalProperties) {
|
entityClipboard.entities.forEach(function(originalProperties) {
|
||||||
var properties = deepCopy(originalProperties);
|
var properties = deepCopy(originalProperties);
|
||||||
|
@ -475,9 +475,9 @@ SelectionManager = (function() {
|
||||||
|
|
||||||
redo(copiedProperties);
|
redo(copiedProperties);
|
||||||
undoHistory.pushCommand(undo, copiedProperties, redo, copiedProperties);
|
undoHistory.pushCommand(undo, copiedProperties, redo, copiedProperties);
|
||||||
}
|
};
|
||||||
|
|
||||||
that._update = function(selectionUpdated) {
|
that._update = function(selectionUpdated, caller) {
|
||||||
var properties = null;
|
var properties = null;
|
||||||
if (that.selections.length === 0) {
|
if (that.selections.length === 0) {
|
||||||
that.localDimensions = null;
|
that.localDimensions = null;
|
||||||
|
@ -542,7 +542,7 @@ SelectionManager = (function() {
|
||||||
|
|
||||||
for (var j = 0; j < listeners.length; j++) {
|
for (var j = 0; j < listeners.length; j++) {
|
||||||
try {
|
try {
|
||||||
listeners[j](selectionUpdated === true);
|
listeners[j](selectionUpdated === true, caller);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("ERROR: entitySelectionTool.update got exception: " + JSON.stringify(e));
|
print("ERROR: entitySelectionTool.update got exception: " + JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
@ -985,7 +985,7 @@ SelectionDisplay = (function() {
|
||||||
that.pressedHand = NO_HAND;
|
that.pressedHand = NO_HAND;
|
||||||
that.triggered = function() {
|
that.triggered = function() {
|
||||||
return that.triggeredHand !== NO_HAND;
|
return that.triggeredHand !== NO_HAND;
|
||||||
}
|
};
|
||||||
function pointingAtDesktopWindowOrTablet(hand) {
|
function pointingAtDesktopWindowOrTablet(hand) {
|
||||||
var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand &&
|
var pointingAtDesktopWindow = (hand === Controller.Standard.RightHand &&
|
||||||
SelectionManager.pointingAtDesktopWindowRight) ||
|
SelectionManager.pointingAtDesktopWindowRight) ||
|
||||||
|
@ -1032,7 +1032,7 @@ SelectionDisplay = (function() {
|
||||||
that.disableTriggerMapping = function() {
|
that.disableTriggerMapping = function() {
|
||||||
that.triggerClickMapping.disable();
|
that.triggerClickMapping.disable();
|
||||||
that.triggerPressMapping.disable();
|
that.triggerPressMapping.disable();
|
||||||
}
|
};
|
||||||
Script.scriptEnding.connect(that.disableTriggerMapping);
|
Script.scriptEnding.connect(that.disableTriggerMapping);
|
||||||
|
|
||||||
// FUNCTION DEF(s): Intersection Check Helpers
|
// FUNCTION DEF(s): Intersection Check Helpers
|
||||||
|
@ -1234,7 +1234,7 @@ SelectionDisplay = (function() {
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print(" Trigger SelectionManager::update");
|
print(" Trigger SelectionManager::update");
|
||||||
}
|
}
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, that);
|
||||||
|
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print("=============== eST::MouseMoveEvent END =======================");
|
print("=============== eST::MouseMoveEvent END =======================");
|
||||||
|
@ -1299,7 +1299,7 @@ SelectionDisplay = (function() {
|
||||||
lastMouseEvent.isControl = event.isControl;
|
lastMouseEvent.isControl = event.isControl;
|
||||||
lastMouseEvent.isAlt = event.isAlt;
|
lastMouseEvent.isAlt = event.isAlt;
|
||||||
activeTool.onMove(lastMouseEvent);
|
activeTool.onMove(lastMouseEvent);
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1315,7 +1315,7 @@ SelectionDisplay = (function() {
|
||||||
lastMouseEvent.isControl = event.isControl;
|
lastMouseEvent.isControl = event.isControl;
|
||||||
lastMouseEvent.isAlt = event.isAlt;
|
lastMouseEvent.isAlt = event.isAlt;
|
||||||
activeTool.onMove(lastMouseEvent);
|
activeTool.onMove(lastMouseEvent);
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2179,7 +2179,7 @@ SelectionDisplay = (function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2301,7 +2301,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
previousPickRay = pickRay;
|
previousPickRay = pickRay;
|
||||||
|
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2488,7 +2488,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
previousPickRay = pickRay;
|
previousPickRay = pickRay;
|
||||||
|
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2599,7 +2599,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
previousPickRay = pickRay;
|
previousPickRay = pickRay;
|
||||||
|
|
||||||
SelectionManager._update();
|
SelectionManager._update(false, this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -874,10 +874,6 @@ function onContentLoaded() {
|
||||||
hasShownUpdateNotification = true;
|
hasShownUpdateNotification = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
notifier.on('click', function(notifierObject, options) {
|
|
||||||
log.debug("Got click", options.url);
|
|
||||||
shell.openExternal(options.url);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX);
|
deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX);
|
||||||
|
|
|
@ -5,6 +5,8 @@ const process = require('process');
|
||||||
const hfApp = require('./hf-app');
|
const hfApp = require('./hf-app');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const AccountInfo = require('./hf-acctinfo').AccountInfo;
|
const AccountInfo = require('./hf-acctinfo').AccountInfo;
|
||||||
|
const url = require('url');
|
||||||
|
const shell = require('electron').shell;
|
||||||
const GetBuildInfo = hfApp.getBuildInfo;
|
const GetBuildInfo = hfApp.getBuildInfo;
|
||||||
const buildInfo = GetBuildInfo();
|
const buildInfo = GetBuildInfo();
|
||||||
const osType = os.type();
|
const osType = os.type();
|
||||||
|
@ -154,8 +156,13 @@ function HifiNotifications(config, menuNotificationCallback) {
|
||||||
|
|
||||||
var _menuNotificationCallback = menuNotificationCallback;
|
var _menuNotificationCallback = menuNotificationCallback;
|
||||||
notifier.on('click', function (notifierObject, options) {
|
notifier.on('click', function (notifierObject, options) {
|
||||||
StartInterface(options.url);
|
const optUrl = url.parse(options.url);
|
||||||
_menuNotificationCallback(options.notificationType, false);
|
if ((optUrl.protocol === "hifi:") || (optUrl.protocol === "hifiapp:")) {
|
||||||
|
StartInterface(options.url);
|
||||||
|
_menuNotificationCallback(options.notificationType, false);
|
||||||
|
} else {
|
||||||
|
shell.openExternal(options.url);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue