mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into newPropertySliders
This commit is contained in:
commit
a0d5b1117a
27 changed files with 680 additions and 348 deletions
BIN
interface/resources/avatar/animations/teleport.fbx
Normal file
BIN
interface/resources/avatar/animations/teleport.fbx
Normal file
Binary file not shown.
|
@ -1,70 +1,138 @@
|
|||
{
|
||||
"version": "1.1",
|
||||
"root": {
|
||||
"id": "userAnimStateMachine",
|
||||
"id": "networkAnimStateMachine",
|
||||
"type": "stateMachine",
|
||||
"data": {
|
||||
"currentState": "idleAnim",
|
||||
"currentState": "transitAnimStateMachine",
|
||||
"states": [
|
||||
{
|
||||
"id": "idleAnim",
|
||||
"id": "transitAnimStateMachine",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "postTransitAnim", "state": "postTransitAnim" },
|
||||
{ "var": "preTransitAnim", "state": "preTransitAnim" }
|
||||
{ "var": "userNetworkAnimA", "state": "userNetworkAnimA" },
|
||||
{ "var": "userNetworkAnimB", "state": "userNetworkAnimB" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "preTransitAnim",
|
||||
"id": "userNetworkAnimA",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "idleAnim", "state": "idleAnim" },
|
||||
{ "var": "transitAnim", "state": "transitAnim" }
|
||||
{ "var": "transitAnimStateMachine", "state": "transitAnimStateMachine" },
|
||||
{ "var": "userNetworkAnimB", "state": "userNetworkAnimB" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitAnim",
|
||||
"id": "userNetworkAnimB",
|
||||
"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" }
|
||||
{ "var": "transitAnimStateMachine", "state": "transitAnimStateMachine" },
|
||||
{ "var": "userNetworkAnimA", "state": "userNetworkAnimA" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "idleAnim",
|
||||
"id": "transitAnimStateMachine",
|
||||
"type": "stateMachine",
|
||||
"data": {
|
||||
"currentState": "idleAnim",
|
||||
"states": [
|
||||
{
|
||||
"id": "idleAnim",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "postTransitAnim", "state": "postTransitAnim" },
|
||||
{ "var": "preTransitAnim", "state": "preTransitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "preTransitAnim",
|
||||
"interpTarget": 4,
|
||||
"interpDuration": 4,
|
||||
"transitions": [
|
||||
{ "var": "idleAnim", "state": "idleAnim" },
|
||||
{ "var": "transitAnim", "state": "transitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitAnim",
|
||||
"interpTarget": 2,
|
||||
"interpDuration": 2,
|
||||
"transitions": [
|
||||
{ "var": "preTransitAnim", "state": "preTransitAnim" },
|
||||
{ "var": "postTransitAnim", "state": "postTransitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "postTransitAnim",
|
||||
"interpTarget": 4,
|
||||
"interpDuration": 4,
|
||||
"transitions": [
|
||||
{ "var": "transitAnim", "state": "transitAnim" },
|
||||
{ "var": "idleAnim", "state": "idleAnim" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"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": "qrc:///avatar/animations/teleport.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 10.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "transitAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/teleport.fbx",
|
||||
"startFrame": 11.0,
|
||||
"endFrame": 18.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "postTransitAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/teleport.fbx",
|
||||
"startFrame": 19.0,
|
||||
"endFrame": 44.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "userNetworkAnimA",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/idle.fbx",
|
||||
|
@ -76,55 +144,7 @@
|
|||
"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",
|
||||
"id": "userNetworkAnimB",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/idle.fbx",
|
||||
|
|
|
@ -2809,6 +2809,7 @@ void Application::initializeGL() {
|
|||
}
|
||||
|
||||
// Build a shared canvas / context for the QML rendering
|
||||
#if !defined(DISABLE_QML)
|
||||
{
|
||||
_qmlShareContext = new OffscreenGLCanvas();
|
||||
_qmlShareContext->setObjectName("QmlShareContext");
|
||||
|
@ -2822,6 +2823,8 @@ void Application::initializeGL() {
|
|||
qCWarning(interfaceapp, "Unable to make window context current");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
_renderEventHandler = new RenderEventHandler();
|
||||
|
||||
|
|
|
@ -127,16 +127,16 @@ void AvatarManager::setSpace(workload::SpacePointer& space ) {
|
|||
void AvatarManager::handleTransitAnimations(AvatarTransit::Status status) {
|
||||
switch (status) {
|
||||
case AvatarTransit::Status::STARTED:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("preTransitAnim");
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkRole("preTransitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::START_TRANSIT:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("transitAnim");
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkRole("transitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::END_TRANSIT:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("postTransitAnim");
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkRole("postTransitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::ENDED:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("idleAnim");
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkRole("idleAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::PRE_TRANSIT:
|
||||
break;
|
||||
|
|
|
@ -135,30 +135,6 @@ void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firs
|
|||
_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() {
|
||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||
_userAnimState.clipNodeEnum = UserAnimState::None;
|
||||
|
@ -170,13 +146,87 @@ void Rig::restoreAnimation() {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::restoreNetworkAnimation() {
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::Idle;
|
||||
void Rig::overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||
|
||||
NetworkAnimState::ClipNodeEnum clipNodeEnum = NetworkAnimState::None;
|
||||
if (_networkAnimState.clipNodeEnum == NetworkAnimState::None || _networkAnimState.clipNodeEnum == NetworkAnimState::B) {
|
||||
clipNodeEnum = NetworkAnimState::A;
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::A) {
|
||||
clipNodeEnum = NetworkAnimState::B;
|
||||
}
|
||||
|
||||
if (_networkNode) {
|
||||
// find an unused AnimClip clipNode
|
||||
std::shared_ptr<AnimClip> clip;
|
||||
if (clipNodeEnum == NetworkAnimState::A) {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("userNetworkAnimA"));
|
||||
} else {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("userNetworkAnimB"));
|
||||
}
|
||||
if (clip) {
|
||||
// set parameters
|
||||
clip->setLoopFlag(loop);
|
||||
clip->setStartFrame(firstFrame);
|
||||
clip->setEndFrame(lastFrame);
|
||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
||||
float timeScale = fps / REFERENCE_FRAMES_PER_SECOND;
|
||||
clip->setTimeScale(timeScale);
|
||||
clip->loadURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
// store current user anim state.
|
||||
_networkAnimState = { clipNodeEnum, url, fps, loop, firstFrame, lastFrame };
|
||||
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_networkVars.set("transitAnimStateMachine", false);
|
||||
_networkVars.set("userNetworkAnimA", clipNodeEnum == NetworkAnimState::A);
|
||||
_networkVars.set("userNetworkAnimB", clipNodeEnum == NetworkAnimState::B);
|
||||
if (!_computeNetworkAnimation) {
|
||||
_networkAnimState.blendTime = 0.0f;
|
||||
_computeNetworkAnimation = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::triggerNetworkRole(const QString& role) {
|
||||
_networkVars.set("transitAnimStateMachine", false);
|
||||
_networkVars.set("idleAnim", false);
|
||||
_networkVars.set("userNetworkAnimA", false);
|
||||
_networkVars.set("userNetworkAnimB", false);
|
||||
_networkVars.set("preTransitAnim", false);
|
||||
_networkVars.set("preTransitAnim", false);
|
||||
_networkVars.set("transitAnim", false);
|
||||
_networkVars.set("postTransitAnim", false);
|
||||
_computeNetworkAnimation = true;
|
||||
if (role == "idleAnim") {
|
||||
_networkVars.set("idleAnim", true);
|
||||
_networkVars.set("preTransitAnim", false);
|
||||
_networkVars.set("transitAnim", false);
|
||||
_networkVars.set("postTransitAnim", false);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::None;
|
||||
_computeNetworkAnimation = false;
|
||||
_networkAnimState.blendTime = 0.0f;
|
||||
} else if (role == "preTransitAnim") {
|
||||
_networkVars.set("preTransitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::PreTransit;
|
||||
_networkAnimState.blendTime = 0.0f;
|
||||
} else if (role == "transitAnim") {
|
||||
_networkVars.set("transitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::Transit;
|
||||
} else if (role == "postTransitAnim") {
|
||||
_networkVars.set("postTransitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::PostTransit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Rig::restoreNetworkAnimation() {
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::None) {
|
||||
if (_computeNetworkAnimation) {
|
||||
_networkAnimState.blendTime = 0.0f;
|
||||
_computeNetworkAnimation = false;
|
||||
}
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::None;
|
||||
_networkVars.set("transitAnimStateMachine", true);
|
||||
_networkVars.set("userNetworkAnimA", false);
|
||||
_networkVars.set("userNetworkAnimB", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1131,24 +1181,19 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
|
|||
AnimVariantMap networkTriggersOut;
|
||||
_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;
|
||||
// Manually blending networkPoseSet with internalPoseSet.
|
||||
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;
|
||||
}
|
||||
}
|
||||
const float FRAMES_PER_SECOND = 30.0f;
|
||||
const float TOTAL_BLEND_FRAMES = 6.0f;
|
||||
const float TOTAL_BLEND_TIME = TOTAL_BLEND_FRAMES / FRAMES_PER_SECOND;
|
||||
_sendNetworkNode = _computeNetworkAnimation || _networkAnimState.blendTime < TOTAL_BLEND_TIME;
|
||||
if (_sendNetworkNode) {
|
||||
_networkPoseSet._relativePoses = _networkNode->evaluate(_networkVars, context, deltaTime, networkTriggersOut);
|
||||
_networkAnimState.blendTime += deltaTime;
|
||||
alpha = _computeNetworkAnimation ? (_networkAnimState.blendTime / TOTAL_BLEND_TIME) : (1.0f - (_networkAnimState.blendTime / TOTAL_BLEND_TIME));
|
||||
alpha = glm::clamp(alpha, 0.0f, 1.0f);
|
||||
for (size_t i = 0; i < _networkPoseSet._relativePoses.size(); i++) {
|
||||
_networkPoseSet._relativePoses[i].blend(_internalPoseSet._relativePoses[i], (alpha > 1.0f ? 1.0f : alpha));
|
||||
_networkPoseSet._relativePoses[i].blend(_internalPoseSet._relativePoses[i], alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1840,16 +1885,16 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
return;
|
||||
}
|
||||
_networkNode->setSkeleton(sharedSkeletonPtr);
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::None) {
|
||||
// restore the user animation we had before reset.
|
||||
NetworkAnimState origState = _networkAnimState;
|
||||
_networkAnimState = { NetworkAnimState::Idle, "", 30.0f, false, 0.0f, 0.0f };
|
||||
_networkAnimState = { NetworkAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
||||
if (_networkAnimState.clipNodeEnum == NetworkAnimState::PreTransit) {
|
||||
triggerNetworkAnimation("preTransitAnim");
|
||||
triggerNetworkRole("preTransitAnim");
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::Transit) {
|
||||
triggerNetworkAnimation("transitAnim");
|
||||
triggerNetworkRole("transitAnim");
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::PostTransit) {
|
||||
triggerNetworkAnimation("postTransitAnim");
|
||||
triggerNetworkRole("postTransitAnim");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,8 +114,10 @@ public:
|
|||
void destroyAnimGraph();
|
||||
|
||||
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void triggerNetworkAnimation(const QString& animName);
|
||||
void restoreAnimation();
|
||||
|
||||
void overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void triggerNetworkRole(const QString& role);
|
||||
void restoreNetworkAnimation();
|
||||
|
||||
QStringList getAnimationRoles() const;
|
||||
|
@ -327,12 +329,14 @@ protected:
|
|||
|
||||
struct NetworkAnimState {
|
||||
enum ClipNodeEnum {
|
||||
Idle = 0,
|
||||
None = 0,
|
||||
PreTransit,
|
||||
Transit,
|
||||
PostTransit
|
||||
PostTransit,
|
||||
A,
|
||||
B
|
||||
};
|
||||
NetworkAnimState() : clipNodeEnum(NetworkAnimState::Idle) {}
|
||||
NetworkAnimState() : clipNodeEnum(NetworkAnimState::None) {}
|
||||
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) {}
|
||||
|
||||
|
@ -342,6 +346,7 @@ protected:
|
|||
bool loop;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
float blendTime;
|
||||
};
|
||||
|
||||
struct UserAnimState {
|
||||
|
@ -411,6 +416,7 @@ protected:
|
|||
|
||||
int _rigId;
|
||||
bool _headEnabled { false };
|
||||
bool _computeNetworkAnimation { false };
|
||||
bool _sendNetworkNode { false };
|
||||
|
||||
AnimContext _lastContext;
|
||||
|
|
|
@ -341,10 +341,10 @@ 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 int AVATAR_TRANSIT_FRAME_COUNT = 5;
|
||||
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 bool AVATAR_TRANSIT_DISTANCE_BASED = false;
|
||||
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;
|
||||
|
|
|
@ -49,7 +49,7 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro
|
|||
const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, names);
|
||||
for (const auto& resourceBuffer : resourceBufferUniforms) {
|
||||
const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name);
|
||||
glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT);
|
||||
glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@ class GLESBackend : public GLBackend {
|
|||
|
||||
public:
|
||||
static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 };
|
||||
static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 };
|
||||
static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 };
|
||||
static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 35 };
|
||||
|
||||
explicit GLESBackend(bool syncCache) : Parent(syncCache) {}
|
||||
GLESBackend() : Parent() {}
|
||||
virtual ~GLESBackend() {
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
namespace gpu {
|
||||
namespace gles {
|
||||
|
||||
class GLESBuffer : public gpu::gl::GLBuffer {
|
||||
using Parent = gpu::gl::GLBuffer;
|
||||
static GLuint allocate() {
|
||||
|
@ -19,11 +18,20 @@ namespace gpu {
|
|||
return result;
|
||||
}
|
||||
|
||||
~GLESBuffer() {
|
||||
if (_texBuffer) {
|
||||
auto backend = _backend.lock();
|
||||
if (backend) {
|
||||
backend->releaseTexture(_texBuffer, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GLESBuffer(const std::weak_ptr<gl::GLBackend>& backend, const Buffer& buffer, GLESBuffer* original) : Parent(backend, buffer, allocate()) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
|
||||
glBufferData(GL_COPY_WRITE_BUFFER, _size, nullptr, GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
||||
|
||||
if (original && original->_size) {
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
|
||||
|
@ -37,20 +45,34 @@ namespace gpu {
|
|||
}
|
||||
|
||||
void transfer() override {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, _buffer);
|
||||
(void)CHECK_GL_ERROR();
|
||||
Size offset;
|
||||
Size size;
|
||||
Size currentPage { 0 };
|
||||
auto data = _gpuObject._renderSysmem.readData();
|
||||
while (_gpuObject._renderPages.getNextTransferBlock(offset, size, currentPage)) {
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data + offset);
|
||||
glBufferSubData(GL_COPY_WRITE_BUFFER, offset, size, data + offset);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
_gpuObject._renderPages._flags &= ~PageManager::DIRTY;
|
||||
}
|
||||
|
||||
// REsource BUffer are implemented with TextureBuffer
|
||||
GLuint _texBuffer { 0 };
|
||||
GLuint getTexBufferId() {
|
||||
if (!_texBuffer) {
|
||||
glGenTextures(1, &_texBuffer);
|
||||
glActiveTexture(GL_TEXTURE0 + GLESBackend::RESOURCE_BUFFER_TEXBUF_TEX_UNIT);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, _texBuffer);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _buffer);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
return _texBuffer;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -68,14 +90,24 @@ GLuint GLESBackend::getBufferIDUnsynced(const Buffer& buffer) {
|
|||
return GLESBuffer::getIdUnsynced<GLESBuffer>(*this, buffer);
|
||||
}
|
||||
|
||||
GLuint GLESBackend::getResourceBufferID(const Buffer& buffer) {
|
||||
auto* object = GLESBuffer::sync<GLESBuffer>(*this, buffer);
|
||||
if (object) {
|
||||
return object->getTexBufferId();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLBuffer* GLESBackend::syncGPUObject(const Buffer& buffer) {
|
||||
return GLESBuffer::sync<GLESBuffer>(*this, buffer);
|
||||
}
|
||||
|
||||
bool GLESBackend::bindResourceBuffer(uint32_t slot, const BufferPointer& buffer) {
|
||||
GLBuffer* object = syncGPUObject((*buffer));
|
||||
if (object) {
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, object->_id);
|
||||
GLuint texBuffer = GLESBackend::getResourceBufferID((*buffer));
|
||||
if (texBuffer) {
|
||||
glActiveTexture(GL_TEXTURE0 + GLESBackend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, texBuffer);
|
||||
|
||||
(void)CHECK_GL_ERROR();
|
||||
|
||||
|
@ -89,9 +121,10 @@ bool GLESBackend::bindResourceBuffer(uint32_t slot, const BufferPointer& buffer)
|
|||
|
||||
void GLESBackend::releaseResourceBuffer(uint32_t slot) {
|
||||
auto& bufferReference = _resource._buffers[slot];
|
||||
if (valid(bufferReference)) {
|
||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot, 0);
|
||||
auto buffer = acquire(bufferReference);
|
||||
if (buffer) {
|
||||
glActiveTexture(GL_TEXTURE0 + GLESBackend::RESOURCE_BUFFER_SLOT0_TEX_UNIT + slot);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, 0);
|
||||
reset(bufferReference);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
|
||||
#define GPU_TEXTURE_TRANSFORM_OBJECT 31
|
||||
|
||||
|
||||
#define GPU_RESOURCE_BUFFER_SLOT0_TEXTURE 35
|
||||
#define GPU_RESOURCE_BUFFER_SLOT1_TEXTURE 36
|
||||
#define GPU_RESOURCE_BUFFER_SLOT0_STORAGE 0
|
||||
#define GPU_RESOURCE_BUFFER_SLOT1_STORAGE 1
|
||||
|
||||
// Mip creation
|
||||
#define GPU_TEXTURE_MIP_CREATION_INPUT 30
|
||||
|
||||
|
|
|
@ -149,11 +149,11 @@ void AnimDebugDraw::shutdown() {
|
|||
}
|
||||
|
||||
void AnimDebugDraw::addAbsolutePoses(const std::string& key, AnimSkeleton::ConstPointer skeleton, const AnimPoseVec& poses, const AnimPose& rootPose, const glm::vec4& color) {
|
||||
_absolutePoses[key] = PosesInfo(skeleton, poses, rootPose, color);
|
||||
_posesInfoMap[key] = PosesInfo(skeleton, poses, rootPose, color);
|
||||
}
|
||||
|
||||
void AnimDebugDraw::removeAbsolutePoses(const std::string& key) {
|
||||
_absolutePoses.erase(key);
|
||||
_posesInfoMap.erase(key);
|
||||
}
|
||||
|
||||
static const uint32_t red = toRGBA(255, 0, 0, 255);
|
||||
|
@ -320,7 +320,12 @@ void AnimDebugDraw::update() {
|
|||
return;
|
||||
}
|
||||
render::Transaction transaction;
|
||||
transaction.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {
|
||||
|
||||
// Make a copy of the _posesInfoMap member variable, and pass the copy into the lambda.
|
||||
// This allows the body of the lambda, which executes on the render thread, to safely iterate over the map.
|
||||
std::shared_ptr<PosesInfoMap> posesInfoMapCopy;
|
||||
posesInfoMapCopy = std::make_shared<PosesInfoMap>(_posesInfoMap);
|
||||
transaction.updateItem<AnimDebugDrawData>(_itemID, [posesInfoMapCopy](AnimDebugDrawData& data) {
|
||||
|
||||
const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3);
|
||||
const size_t VERTICES_PER_LINK = 8 * 2;
|
||||
|
@ -332,7 +337,7 @@ void AnimDebugDraw::update() {
|
|||
// figure out how many verts we will need.
|
||||
int numVerts = 0;
|
||||
|
||||
for (auto& iter : _absolutePoses) {
|
||||
for (auto& iter : *posesInfoMapCopy) {
|
||||
AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
|
||||
numVerts += skeleton->getNumJoints() * VERTICES_PER_BONE;
|
||||
for (auto i = 0; i < skeleton->getNumJoints(); i++) {
|
||||
|
@ -362,7 +367,7 @@ void AnimDebugDraw::update() {
|
|||
}
|
||||
|
||||
// draw absolute poses
|
||||
for (auto& iter : _absolutePoses) {
|
||||
for (auto& iter : *posesInfoMapCopy) {
|
||||
AnimSkeleton::ConstPointer& skeleton = std::get<0>(iter.second);
|
||||
AnimPoseVec& absPoses = std::get<1>(iter.second);
|
||||
AnimPose rootPose = std::get<2>(iter.second);
|
||||
|
@ -421,7 +426,7 @@ void AnimDebugDraw::update() {
|
|||
|
||||
data._indexBuffer->resize(sizeof(uint32_t) * numVerts);
|
||||
for (int i = 0; i < numVerts; i++) {
|
||||
data._indexBuffer->setSubData<uint32_t>(i, (uint32_t)i);;
|
||||
data._indexBuffer->setSubData<uint32_t>(i, (uint32_t)i);
|
||||
}
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
|
|
|
@ -44,7 +44,8 @@ protected:
|
|||
|
||||
typedef std::tuple<AnimSkeleton::ConstPointer, AnimPoseVec, AnimPose, glm::vec4> PosesInfo;
|
||||
|
||||
std::unordered_map<std::string, PosesInfo> _absolutePoses;
|
||||
typedef std::unordered_map<std::string, PosesInfo> PosesInfoMap;
|
||||
PosesInfoMap _posesInfoMap;
|
||||
|
||||
// no copies
|
||||
AnimDebugDraw(const AnimDebugDraw&) = delete;
|
||||
|
|
|
@ -11,12 +11,12 @@
|
|||
<@func declareBlendshape(USE_NORMAL, USE_TANGENT)@>
|
||||
|
||||
#if !defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||
LAYOUT(binding=0) uniform samplerBuffer blendshapeOffsetsBuffer;
|
||||
LAYOUT(binding=GPU_RESOURCE_BUFFER_SLOT0_TEXTURE) uniform samplerBuffer blendshapeOffsetsBuffer;
|
||||
uvec4 getPackedBlendshapeOffset(int i) {
|
||||
return floatBitsToUint(texelFetch(blendshapeOffsetsBuffer, i));
|
||||
}
|
||||
#else
|
||||
LAYOUT_STD140(binding=0) buffer blendshapeOffsetsBuffer {
|
||||
LAYOUT_STD140(binding=GPU_RESOURCE_BUFFER_SLOT0_STORAGE) buffer blendshapeOffsetsBuffer {
|
||||
uvec4 _packedBlendshapeOffsets[];
|
||||
};
|
||||
uvec4 getPackedBlendshapeOffset(int i) {
|
||||
|
|
|
@ -23,7 +23,7 @@ struct ItemBound {
|
|||
};
|
||||
|
||||
#if !defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||
LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer;
|
||||
LAYOUT(binding=GPU_RESOURCE_BUFFER_SLOT0_TEXTURE) uniform samplerBuffer ssbo0Buffer;
|
||||
ItemBound getItemBound(int i) {
|
||||
int offset = 2 * i;
|
||||
ItemBound bound;
|
||||
|
@ -32,7 +32,7 @@ ItemBound getItemBound(int i) {
|
|||
return bound;
|
||||
}
|
||||
#else
|
||||
LAYOUT_STD140(binding=0) buffer ssbo0Buffer {
|
||||
LAYOUT_STD140(binding=GPU_RESOURCE_BUFFER_SLOT0_STORAGE) buffer ssbo0Buffer {
|
||||
ItemBound bounds[];
|
||||
};
|
||||
ItemBound getItemBound(int i) {
|
||||
|
|
|
@ -239,7 +239,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
|
|||
|
||||
initCache(model);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_ANDROID)
|
||||
// On mac AMD, we specifically need to have a _meshBlendshapeBuffer bound when using a deformed mesh pipeline
|
||||
// it cannot be null otherwise we crash in the drawcall using a deformed pipeline with a skinned only (not blendshaped) mesh
|
||||
if (_isBlendShaped) {
|
||||
|
|
|
@ -26,7 +26,7 @@ struct WorkloadProxy {
|
|||
};
|
||||
|
||||
#if !defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||
LAYOUT(binding=0) uniform samplerBuffer workloadProxiesBuffer;
|
||||
LAYOUT(binding=GPU_RESOURCE_BUFFER_SLOT0_TEXTURE) uniform samplerBuffer workloadProxiesBuffer;
|
||||
WorkloadProxy getWorkloadProxy(int i) {
|
||||
int offset = 2 * i;
|
||||
WorkloadProxy proxy;
|
||||
|
@ -35,7 +35,7 @@ WorkloadProxy getWorkloadProxy(int i) {
|
|||
return proxy;
|
||||
}
|
||||
#else
|
||||
LAYOUT_STD140(binding=0) buffer workloadProxiesBuffer {
|
||||
LAYOUT_STD140(binding=GPU_RESOURCE_BUFFER_SLOT0_STORAGE) buffer workloadProxiesBuffer {
|
||||
WorkloadProxy _proxies[];
|
||||
};
|
||||
WorkloadProxy getWorkloadProxy(int i) {
|
||||
|
@ -58,7 +58,7 @@ struct WorkloadView {
|
|||
};
|
||||
|
||||
#if !defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||
LAYOUT(binding=1) uniform samplerBuffer workloadViewsBuffer;
|
||||
LAYOUT(binding=GPU_RESOURCE_BUFFER_SLOT1_TEXTURE) uniform samplerBuffer workloadViewsBuffer;
|
||||
WorkloadView getWorkloadView(int i) {
|
||||
int offset = 8 * i;
|
||||
WorkloadView view;
|
||||
|
@ -73,7 +73,7 @@ WorkloadView getWorkloadView(int i) {
|
|||
return view;
|
||||
}
|
||||
#else
|
||||
LAYOUT_STD140(binding=1) buffer workloadViewsBuffer {
|
||||
LAYOUT_STD140(binding=GPU_RESOURCE_BUFFER_SLOT1_STORAGE) buffer workloadViewsBuffer {
|
||||
WorkloadView _views[];
|
||||
};
|
||||
WorkloadView getWorkloadView(int i) {
|
||||
|
|
|
@ -35,7 +35,7 @@ struct ItemBound {
|
|||
};
|
||||
|
||||
#if !defined(GPU_SSBO_TRANSFORM_OBJECT)
|
||||
LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer;
|
||||
LAYOUT(binding=GPU_RESOURCE_BUFFER_SLOT0_TEXTURE) uniform samplerBuffer ssbo0Buffer;
|
||||
ItemBound getItemBound(int i) {
|
||||
int offset = 2 * i;
|
||||
ItemBound bound;
|
||||
|
@ -44,7 +44,7 @@ ItemBound getItemBound(int i) {
|
|||
return bound;
|
||||
}
|
||||
#else
|
||||
LAYOUT_STD140(binding=0) buffer ssbo0Buffer {
|
||||
LAYOUT_STD140(binding=GPU_RESOURCE_BUFFER_SLOT0_STORAGE) buffer ssbo0Buffer {
|
||||
ItemBound bounds[];
|
||||
};
|
||||
ItemBound getItemBound(int i) {
|
||||
|
|
|
@ -294,12 +294,21 @@
|
|||
"position": {
|
||||
"tooltip": "The global position of this entity."
|
||||
},
|
||||
"localPosition": {
|
||||
"tooltip": "The local position of this entity."
|
||||
},
|
||||
"rotation": {
|
||||
"tooltip": "The rotation of the entity with respect to world coordinates."
|
||||
"tooltip": "The global rotation of this entity."
|
||||
},
|
||||
"localRotation": {
|
||||
"tooltip": "The local rotation of this entity."
|
||||
},
|
||||
"dimensions": {
|
||||
"tooltip": "The global dimensions of this entity."
|
||||
},
|
||||
"localDimensions": {
|
||||
"tooltip": "The local dimensions of this entity."
|
||||
},
|
||||
"scale": {
|
||||
"tooltip": "The global scaling of this entity.",
|
||||
"skipJSProperty": true
|
||||
|
@ -398,13 +407,13 @@
|
|||
"userData": {
|
||||
"tooltip": "Used to store extra data about the entity in JSON format."
|
||||
},
|
||||
"velocity": {
|
||||
"localVelocity": {
|
||||
"tooltip": "The linear velocity vector of the entity. The velocity at which this entity moves forward in space."
|
||||
},
|
||||
"damping": {
|
||||
"tooltip": "The linear damping to slow down the linear velocity of an entity over time."
|
||||
},
|
||||
"angularVelocity": {
|
||||
"localAngularVelocity": {
|
||||
"tooltip": "The angular velocity of the entity in rad/s with respect to its axes, about its pivot point."
|
||||
},
|
||||
"angularDamping": {
|
||||
|
|
|
@ -493,9 +493,9 @@ var toolBar = (function () {
|
|||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.All);
|
||||
|
||||
var type = requestedProperties.type;
|
||||
if (type == "Box" || type == "Sphere") {
|
||||
if (type === "Box" || type === "Sphere") {
|
||||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Shape);
|
||||
} else if (type == "Image") {
|
||||
} else if (type === "Image") {
|
||||
requestedProperties.type = "Model";
|
||||
applyProperties(properties, DEFAULT_ENTITY_PROPERTIES.Image);
|
||||
} else {
|
||||
|
@ -1217,7 +1217,7 @@ function mouseClickEvent(event) {
|
|||
var result, properties, tabletClicked;
|
||||
if (isActive && event.isLeftButton) {
|
||||
result = findClickedEntity(event);
|
||||
tabletOrEditHandleClicked = wasTabletOrEditHandleClicked(event);
|
||||
var tabletOrEditHandleClicked = wasTabletOrEditHandleClicked(event);
|
||||
if (tabletOrEditHandleClicked) {
|
||||
return;
|
||||
}
|
||||
|
@ -1540,7 +1540,7 @@ function insideBox(center, dimensions, point) {
|
|||
(Math.abs(point.z - center.z) <= (dimensions.z / 2.0));
|
||||
}
|
||||
|
||||
function selectAllEtitiesInCurrentSelectionBox(keepIfTouching) {
|
||||
function selectAllEntitiesInCurrentSelectionBox(keepIfTouching) {
|
||||
if (selectionManager.hasSelection()) {
|
||||
// Get all entities touching the bounding box of the current selection
|
||||
var boundingBoxCorner = Vec3.subtract(selectionManager.worldPosition,
|
||||
|
@ -1819,9 +1819,9 @@ function handleMenuEvent(menuItem) {
|
|||
Window.promptAsync("URL of SVO to import", "");
|
||||
}
|
||||
} else if (menuItem === "Select All Entities In Box") {
|
||||
selectAllEtitiesInCurrentSelectionBox(false);
|
||||
selectAllEntitiesInCurrentSelectionBox(false);
|
||||
} else if (menuItem === "Select All Entities Touching Box") {
|
||||
selectAllEtitiesInCurrentSelectionBox(true);
|
||||
selectAllEntitiesInCurrentSelectionBox(true);
|
||||
} else if (menuItem === MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE) {
|
||||
entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE));
|
||||
} else if (menuItem === MENU_SHOW_ZONES_IN_EDIT_MODE) {
|
||||
|
@ -2107,14 +2107,14 @@ var DELETED_ENTITY_MAP = {};
|
|||
function applyEntityProperties(data) {
|
||||
var editEntities = data.editEntities;
|
||||
var selectedEntityIDs = [];
|
||||
var selectEdits = data.createEntities.length == 0 || !data.selectCreated;
|
||||
var i, entityID;
|
||||
var selectEdits = data.createEntities.length === 0 || !data.selectCreated;
|
||||
var i, entityID, entityProperties;
|
||||
for (i = 0; i < editEntities.length; i++) {
|
||||
var entityID = editEntities[i].entityID;
|
||||
entityID = editEntities[i].entityID;
|
||||
if (DELETED_ENTITY_MAP[entityID] !== undefined) {
|
||||
entityID = DELETED_ENTITY_MAP[entityID];
|
||||
}
|
||||
var entityProperties = editEntities[i].properties;
|
||||
entityProperties = editEntities[i].properties;
|
||||
if (entityProperties !== null) {
|
||||
Entities.editEntity(entityID, entityProperties);
|
||||
}
|
||||
|
@ -2124,7 +2124,7 @@ function applyEntityProperties(data) {
|
|||
}
|
||||
for (i = 0; i < data.createEntities.length; i++) {
|
||||
entityID = data.createEntities[i].entityID;
|
||||
var entityProperties = data.createEntities[i].properties;
|
||||
entityProperties = data.createEntities[i].properties;
|
||||
var newEntityID = Entities.addEntity(entityProperties);
|
||||
recursiveAdd(newEntityID, data.createEntities[i]);
|
||||
DELETED_ENTITY_MAP[entityID] = newEntityID;
|
||||
|
@ -2260,9 +2260,17 @@ var PropertiesTool = function (opts) {
|
|||
});
|
||||
}
|
||||
|
||||
that.setSpaceMode = function(spaceMode) {
|
||||
emitScriptEvent({
|
||||
type: 'setSpaceMode',
|
||||
spaceMode: spaceMode
|
||||
})
|
||||
};
|
||||
|
||||
function updateSelections(selectionUpdated) {
|
||||
var data = {
|
||||
type: 'update'
|
||||
type: 'update',
|
||||
spaceMode: selectionDisplay.getSpaceMode()
|
||||
};
|
||||
|
||||
if (selectionUpdated) {
|
||||
|
@ -2292,6 +2300,9 @@ var PropertiesTool = function (opts) {
|
|||
if (entity.properties.rotation !== undefined) {
|
||||
entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
|
||||
}
|
||||
if (entity.properties.localRotation !== undefined) {
|
||||
entity.properties.localRotation = Quat.safeEulerAngles(entity.properties.localRotation);
|
||||
}
|
||||
if (entity.properties.emitOrientation !== undefined) {
|
||||
entity.properties.emitOrientation = Quat.safeEulerAngles(entity.properties.emitOrientation);
|
||||
}
|
||||
|
@ -2328,12 +2339,15 @@ var PropertiesTool = function (opts) {
|
|||
} else if (data.properties) {
|
||||
if (data.properties.dynamic === false) {
|
||||
// this object is leaving dynamic, so we zero its velocities
|
||||
data.properties.velocity = Vec3.ZERO;
|
||||
data.properties.angularVelocity = Vec3.ZERO;
|
||||
data.properties.localVelocity = Vec3.ZERO;
|
||||
data.properties.localAngularVelocity = Vec3.ZERO;
|
||||
}
|
||||
if (data.properties.rotation !== undefined) {
|
||||
data.properties.rotation = Quat.fromVec3Degrees(data.properties.rotation);
|
||||
}
|
||||
if (data.properties.localRotation !== undefined) {
|
||||
data.properties.localRotation = Quat.fromVec3Degrees(data.properties.localRotation);
|
||||
}
|
||||
if (data.properties.emitOrientation !== undefined) {
|
||||
data.properties.emitOrientation = Quat.fromVec3Degrees(data.properties.emitOrientation);
|
||||
}
|
||||
|
@ -2582,7 +2596,7 @@ var PopupMenu = function () {
|
|||
y: event.y
|
||||
});
|
||||
if (!pressingOverlay) {
|
||||
if (hoveringOverlay !== null && hoveringOverlay !== null && overlay !== hoveringOverlay) {
|
||||
if (hoveringOverlay !== null && overlay !== hoveringOverlay) {
|
||||
Overlays.editOverlay(hoveringOverlay, {
|
||||
backgroundColor: upColor
|
||||
});
|
||||
|
@ -2724,4 +2738,10 @@ entityListTool.webView.webEventReceived.connect(function(data) {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
selectionDisplay.onSpaceModeChange = function(spaceMode) {
|
||||
entityListTool.setSpaceMode(spaceMode);
|
||||
propertiesTool.setSpaceMode(spaceMode);
|
||||
};
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -102,7 +102,7 @@ thead {
|
|||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
background-color: #1c1c1c;
|
||||
padding: 1px 0px;
|
||||
padding: 1px 0;
|
||||
border-bottom: 1px solid #575757;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ input::-webkit-input-placeholder {
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus {
|
||||
input:focus, textarea:focus, button:focus {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
outline: 1px solid #00b4ef;
|
||||
|
@ -282,7 +282,7 @@ input[type=number]::-webkit-inner-spin-button {
|
|||
width: 10px;
|
||||
height: 90%;
|
||||
overflow: hidden;
|
||||
font-family: hifi-glyphs;
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 32px;
|
||||
color: #afafaf;
|
||||
cursor: pointer;
|
||||
|
@ -367,14 +367,14 @@ input.no-spin::-webkit-inner-spin-button {
|
|||
padding-right: 12px;
|
||||
}
|
||||
|
||||
input[type=button] {
|
||||
input[type=button], button.hifi-edit-button {
|
||||
font-family: Raleway-Bold;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
vertical-align: top;
|
||||
height: 28px;
|
||||
min-width: 120px;
|
||||
padding: 0px 18px;
|
||||
padding: 0 18px;
|
||||
margin-right: 6px;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
|
@ -384,7 +384,7 @@ input[type=button] {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type=button].glyph {
|
||||
input[type=button].glyph, button.hifi-edit-button.glyph {
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 20px;
|
||||
text-transform: none;
|
||||
|
@ -392,58 +392,58 @@ input[type=button].glyph {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
input[type=button].red {
|
||||
input[type=button].red, button.hifi-edit-button.red {
|
||||
color: #fff;
|
||||
background-color: #94132e;
|
||||
background: linear-gradient(#d42043 20%, #94132e 100%);
|
||||
}
|
||||
input[type=button].blue {
|
||||
input[type=button].blue, button.hifi-edit-button.blue {
|
||||
color: #fff;
|
||||
background-color: #1080b8;
|
||||
background: linear-gradient(#00b4ef 20%, #1080b8 100%);
|
||||
}
|
||||
input[type=button].white {
|
||||
input[type=button].white, button.hifi-edit-button.white {
|
||||
color: #121212;
|
||||
background-color: #afafaf;
|
||||
background: linear-gradient(#fff 20%, #afafaf 100%);
|
||||
}
|
||||
|
||||
input[type=button]:enabled:hover {
|
||||
input[type=button]:enabled:hover, button.hifi-edit-button:enabled:hover {
|
||||
background: linear-gradient(#000, #000);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].red:enabled:hover {
|
||||
input[type=button].red:enabled:hover, button.hifi-edit-button.red:enabled:hover {
|
||||
background: linear-gradient(#d42043, #d42043);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].blue:enabled:hover {
|
||||
input[type=button].blue:enabled:hover, button.hifi-edit-button.blue:enabled:hover {
|
||||
background: linear-gradient(#00b4ef, #00b4ef);
|
||||
border: none;
|
||||
}
|
||||
input[type=button].white:enabled:hover {
|
||||
input[type=button].white:enabled:hover, button.hifi-edit-button.white:enabled:hover {
|
||||
background: linear-gradient(#fff, #fff);
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type=button]:active {
|
||||
input[type=button]:active, button.hifi-edit-button:active {
|
||||
background: linear-gradient(#343434, #343434);
|
||||
}
|
||||
input[type=button].red:active {
|
||||
input[type=button].red:active, button.hifi-edit-button.red:active {
|
||||
background: linear-gradient(#94132e, #94132e);
|
||||
}
|
||||
input[type=button].blue:active {
|
||||
input[type=button].blue:active, button.hifi-edit-button.blue:active {
|
||||
background: linear-gradient(#1080b8, #1080b8);
|
||||
}
|
||||
input[type=button].white:active {
|
||||
input[type=button].white:active, button.hifi-edit-button.white:active {
|
||||
background: linear-gradient(#afafaf, #afafaf);
|
||||
}
|
||||
|
||||
input[type=button]:disabled {
|
||||
input[type=button]:disabled, button.hifi-edit-button:disabled {
|
||||
color: #252525;
|
||||
background: linear-gradient(#575757 20%, #252525 100%);
|
||||
}
|
||||
|
||||
input[type=button][pressed=pressed] {
|
||||
input[type=button][pressed=pressed], button.hifi-edit-button[pressed=pressed] {
|
||||
color: #00b4ef;
|
||||
}
|
||||
|
||||
|
@ -474,7 +474,7 @@ input[type=checkbox]:checked + label:hover {
|
|||
position: absolute;
|
||||
left: 6px;
|
||||
top: -2px;
|
||||
font-family: hifi-glyphs;
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 30px;
|
||||
color: #afafaf;
|
||||
}
|
||||
|
@ -1073,7 +1073,6 @@ body#entity-list-body {
|
|||
float: right;
|
||||
margin-right: 0;
|
||||
background-color: #ff0000;
|
||||
min-width: 90px;
|
||||
}
|
||||
|
||||
#entity-list {
|
||||
|
@ -1102,7 +1101,7 @@ body#entity-list-body {
|
|||
#filter-type-checkboxes span {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-family: hifi-glyphs;
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 13px;
|
||||
color: #000000;
|
||||
padding-left: 6px;
|
||||
|
@ -1146,7 +1145,7 @@ body#entity-list-body {
|
|||
|
||||
#filter-in-view {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
top: 0;
|
||||
right: 126px;
|
||||
}
|
||||
|
||||
|
@ -1425,7 +1424,7 @@ th#entity-hasScript {
|
|||
}
|
||||
|
||||
#properties-base #property-type-icon {
|
||||
font-family: hifi-glyphs;
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 31px;
|
||||
color: #00b4ef;
|
||||
margin: -4px 12px -4px -2px;
|
||||
|
@ -1682,3 +1681,20 @@ input.number-slider {
|
|||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#toggle-space-mode::before {
|
||||
font-family: HiFi-Glyphs;
|
||||
font-size: 20px;
|
||||
text-transform: none;
|
||||
min-width: 32px;
|
||||
padding-right: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#toggle-space-mode.space-mode-local::before {
|
||||
content: "m";
|
||||
}
|
||||
|
||||
#toggle-space-mode.space-mode-world::before {
|
||||
content: "\e02c";
|
||||
}
|
||||
|
|
|
@ -139,9 +139,9 @@ input[type=radio]:active + label > span > span{
|
|||
font-family: Raleway-Bold;
|
||||
font-size: 13px;
|
||||
color: black;
|
||||
padding: 0px 10px;
|
||||
padding: 0 10px;
|
||||
border-radius: 3px;
|
||||
border-width: 0px;
|
||||
border-width: 0;
|
||||
background-image: linear-gradient(#FFFFFF, #AFAFAF);
|
||||
min-height: 30px;
|
||||
}
|
||||
|
@ -158,9 +158,9 @@ input[type=radio]:active + label > span > span{
|
|||
font-family: Raleway-Bold;
|
||||
font-size: 13px;
|
||||
color: white;
|
||||
padding: 0px 10px;
|
||||
padding: 0 10px;
|
||||
border-radius: 3px;
|
||||
border-width: 0px;
|
||||
border-width: 0;
|
||||
background-image: linear-gradient(#00B4EF, #1080B8);
|
||||
min-height: 30px;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Entity List</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/edit-style.css">
|
||||
<script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
|
@ -27,7 +28,8 @@
|
|||
<input type="button" id="visible" class="glyph" value="" />
|
||||
</div>
|
||||
<input type="button" id="pal" class="glyph" value="" />
|
||||
<input type="button" class="red" id="delete" value="Delete" />
|
||||
<button id="toggle-space-mode" class="hifi-edit-button space-mode-local">Local</button>
|
||||
<input type="button" class="red glyph" id="delete" value="{" />
|
||||
</div>
|
||||
<div id="entity-list">
|
||||
<div id="filter-area">
|
||||
|
|
|
@ -23,7 +23,6 @@ const FILTER_IN_VIEW_ATTRIBUTE = "pressed";
|
|||
const WINDOW_NONVARIABLE_HEIGHT = 227;
|
||||
const NUM_COLUMNS = 12;
|
||||
const EMPTY_ENTITY_ID = "0";
|
||||
const MAX_LENGTH_RADIUS = 9;
|
||||
const DELETE = 46; // Key code for the delete key.
|
||||
const KEY_P = 80; // Key code for letter p used for Parenting hotkey.
|
||||
|
||||
|
@ -85,29 +84,52 @@ const ICON_FOR_TYPE = {
|
|||
};
|
||||
|
||||
// List of all entities
|
||||
var entities = [];
|
||||
let entities = [];
|
||||
// List of all entities, indexed by Entity ID
|
||||
var entitiesByID = {};
|
||||
let entitiesByID = {};
|
||||
// The filtered and sorted list of entities passed to ListView
|
||||
var visibleEntities = [];
|
||||
let visibleEntities = [];
|
||||
// List of all entities that are currently selected
|
||||
var selectedEntities = [];
|
||||
let selectedEntities = [];
|
||||
|
||||
var entityList = null; // The ListView
|
||||
let entityList = null; // The ListView
|
||||
|
||||
/**
|
||||
* @type EntityListContextMenu
|
||||
*/
|
||||
var entityListContextMenu = null;
|
||||
let entityListContextMenu = null;
|
||||
|
||||
var currentSortColumn = 'type';
|
||||
var currentSortOrder = ASCENDING_SORT;
|
||||
var typeFilters = [];
|
||||
var isFilterInView = false;
|
||||
var showExtraInfo = false;
|
||||
let currentSortColumn = 'type';
|
||||
let currentSortOrder = ASCENDING_SORT;
|
||||
let typeFilters = [];
|
||||
let isFilterInView = false;
|
||||
let showExtraInfo = false;
|
||||
|
||||
let elEntityTable,
|
||||
elEntityTableBody,
|
||||
elEntityTableScroll,
|
||||
elEntityTableHeaderRow,
|
||||
elRefresh,
|
||||
elToggleLocked,
|
||||
elToggleVisible,
|
||||
elDelete,
|
||||
elFilterTypeSelectBox,
|
||||
elFilterTypeText,
|
||||
elFilterTypeCheckboxes,
|
||||
elFilterSearch,
|
||||
elFilterInView,
|
||||
elFilterRadius,
|
||||
elExport,
|
||||
elPal,
|
||||
elInfoToggle,
|
||||
elInfoToggleGlyph,
|
||||
elSelectedEntitiesCount,
|
||||
elVisibleEntitiesCount,
|
||||
elNoEntitiesMessage,
|
||||
elToggleSpaceMode;
|
||||
|
||||
const ENABLE_PROFILING = false;
|
||||
var profileIndent = '';
|
||||
let profileIndent = '';
|
||||
const PROFILE_NOOP = function(_name, fn, args) {
|
||||
fn.apply(this, args);
|
||||
} ;
|
||||
|
@ -140,7 +162,7 @@ function loaded() {
|
|||
elFilterTypeText = document.getElementById("filter-type-text");
|
||||
elFilterTypeCheckboxes = document.getElementById("filter-type-checkboxes");
|
||||
elFilterSearch = document.getElementById("filter-search");
|
||||
elFilterInView = document.getElementById("filter-in-view")
|
||||
elFilterInView = document.getElementById("filter-in-view");
|
||||
elFilterRadius = document.getElementById("filter-radius");
|
||||
elExport = document.getElementById("export");
|
||||
elPal = document.getElementById("pal");
|
||||
|
@ -149,6 +171,7 @@ function loaded() {
|
|||
elSelectedEntitiesCount = document.getElementById("selected-entities-count");
|
||||
elVisibleEntitiesCount = document.getElementById("visible-entities-count");
|
||||
elNoEntitiesMessage = document.getElementById("no-entities");
|
||||
elToggleSpaceMode = document.getElementById('toggle-space-mode');
|
||||
|
||||
document.body.onclick = onBodyClick;
|
||||
document.getElementById("entity-name").onclick = function() {
|
||||
|
@ -205,6 +228,10 @@ function loaded() {
|
|||
elDelete.onclick = function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
};
|
||||
elToggleSpaceMode.onclick = function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'toggleSpaceMode' }));
|
||||
};
|
||||
|
||||
elFilterTypeSelectBox.onclick = onToggleTypeDropdown;
|
||||
elFilterSearch.onkeyup = refreshEntityList;
|
||||
elFilterSearch.onsearch = refreshEntityList;
|
||||
|
@ -646,6 +673,8 @@ function loaded() {
|
|||
}
|
||||
}
|
||||
|
||||
elToggleSpaceMode.disabled = selectedIDs.length > 1;
|
||||
|
||||
refreshFooter();
|
||||
|
||||
return notFound;
|
||||
|
@ -827,6 +856,16 @@ function loaded() {
|
|||
entityList.resize();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
function setSpaceMode(spaceMode) {
|
||||
if (spaceMode === "local") {
|
||||
elToggleSpaceMode.className = "space-mode-local hifi-edit-button";
|
||||
elToggleSpaceMode.innerText = "Local";
|
||||
} else {
|
||||
elToggleSpaceMode.className = "space-mode-world hifi-edit-button";
|
||||
elToggleSpaceMode.innerText = "World";
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (keyDownEvent) {
|
||||
if (keyDownEvent.target.nodeName === "INPUT") {
|
||||
|
@ -866,12 +905,15 @@ function loaded() {
|
|||
updateSelectedEntities(data.selectedIDs, true);
|
||||
}
|
||||
}
|
||||
setSpaceMode(data.spaceMode);
|
||||
});
|
||||
} else if (data.type === "removeEntities" && data.deletedIDs !== undefined && data.selectedIDs !== undefined) {
|
||||
removeEntities(data.deletedIDs);
|
||||
updateSelectedEntities(data.selectedIDs, true);
|
||||
} else if (data.type === "deleted" && data.ids) {
|
||||
removeEntities(data.ids);
|
||||
} else if (data.type === "setSpaceMode") {
|
||||
setSpaceMode(data.spaceMode);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -31,6 +31,12 @@ const DEGREES_TO_RADIANS = Math.PI / 180.0;
|
|||
|
||||
const NO_SELECTION = "w";
|
||||
|
||||
const PROPERTY_SPACE_MODE = {
|
||||
ALL: 0,
|
||||
LOCAL: 1,
|
||||
WORLD: 2
|
||||
};
|
||||
|
||||
const GROUPS = [
|
||||
{
|
||||
id: "base",
|
||||
|
@ -671,7 +677,7 @@ const GROUPS = [
|
|||
propertyID: "speedSpread",
|
||||
},
|
||||
{
|
||||
label: "Emit Dimension",
|
||||
label: "Emit Dimensions",
|
||||
type: "vec3",
|
||||
vec3Type: "xyz",
|
||||
min: 0,
|
||||
|
@ -1008,6 +1014,17 @@ const GROUPS = [
|
|||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "m",
|
||||
propertyID: "position",
|
||||
spaceMode: PROPERTY_SPACE_MODE.WORLD,
|
||||
},
|
||||
{
|
||||
label: "Local Position",
|
||||
type: "vec3",
|
||||
vec3Type: "xyz",
|
||||
decimals: 4,
|
||||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "m",
|
||||
propertyID: "localPosition",
|
||||
spaceMode: PROPERTY_SPACE_MODE.LOCAL,
|
||||
},
|
||||
{
|
||||
label: "Rotation",
|
||||
|
@ -1018,9 +1035,21 @@ const GROUPS = [
|
|||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "deg",
|
||||
propertyID: "rotation",
|
||||
spaceMode: PROPERTY_SPACE_MODE.WORLD,
|
||||
},
|
||||
{
|
||||
label: "Dimension",
|
||||
label: "Local Rotation",
|
||||
type: "vec3",
|
||||
vec3Type: "pyr",
|
||||
step: 0.1,
|
||||
decimals: 4,
|
||||
subLabels: [ "pitch", "yaw", "roll" ],
|
||||
unit: "deg",
|
||||
propertyID: "localRotation",
|
||||
spaceMode: PROPERTY_SPACE_MODE.LOCAL,
|
||||
},
|
||||
{
|
||||
label: "Dimensions",
|
||||
type: "vec3",
|
||||
vec3Type: "xyz",
|
||||
min: 0,
|
||||
|
@ -1029,6 +1058,19 @@ const GROUPS = [
|
|||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "m",
|
||||
propertyID: "dimensions",
|
||||
spaceMode: PROPERTY_SPACE_MODE.WORLD,
|
||||
},
|
||||
{
|
||||
label: "Local Dimensions",
|
||||
type: "vec3",
|
||||
vec3Type: "xyz",
|
||||
min: 0,
|
||||
step: 0.1,
|
||||
decimals: 4,
|
||||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "m",
|
||||
propertyID: "localDimensions",
|
||||
spaceMode: PROPERTY_SPACE_MODE.LOCAL,
|
||||
},
|
||||
{
|
||||
label: "Scale",
|
||||
|
@ -1229,7 +1271,7 @@ const GROUPS = [
|
|||
decimals: 4,
|
||||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "m/s",
|
||||
propertyID: "velocity",
|
||||
propertyID: "localVelocity",
|
||||
},
|
||||
{
|
||||
label: "Linear Damping",
|
||||
|
@ -1245,7 +1287,7 @@ const GROUPS = [
|
|||
decimals: 4,
|
||||
subLabels: [ "x", "y", "z" ],
|
||||
unit: "deg/s",
|
||||
propertyID: "angularVelocity",
|
||||
propertyID: "localAngularVelocity",
|
||||
},
|
||||
{
|
||||
label: "Angular Damping",
|
||||
|
@ -1367,6 +1409,7 @@ var particlePropertyUpdates = {};
|
|||
var selectedEntityProperties;
|
||||
var lastEntityID = null;
|
||||
var createAppTooltip = new CreateAppTooltip();
|
||||
let currentSpaceMode = PROPERTY_SPACE_MODE.LOCAL;
|
||||
|
||||
function debugPrint(message) {
|
||||
EventBridge.emitWebEvent(
|
||||
|
@ -1572,6 +1615,18 @@ function getPropertyValue(originalPropertyName) {
|
|||
return propertyValue;
|
||||
}
|
||||
|
||||
function updateVisibleSpaceModeProperties() {
|
||||
for (let propertyID in properties) {
|
||||
if (properties.hasOwnProperty(propertyID)) {
|
||||
let property = properties[propertyID];
|
||||
let propertySpaceMode = property.spaceMode;
|
||||
if (propertySpaceMode !== PROPERTY_SPACE_MODE.ALL) {
|
||||
showPropertyElement(propertyID, propertySpaceMode === currentSpaceMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PROPERTY UPDATE FUNCTIONS
|
||||
|
@ -2085,6 +2140,87 @@ function addButtons(elProperty, propertyID, buttons, newRow) {
|
|||
}
|
||||
}
|
||||
|
||||
function createProperty(propertyData, propertyElementID, propertyName, propertyID, elProperty) {
|
||||
let property = {
|
||||
data: propertyData,
|
||||
elementID: propertyElementID,
|
||||
name: propertyName,
|
||||
elProperty: elProperty,
|
||||
};
|
||||
let propertyType = propertyData.type;
|
||||
|
||||
switch (propertyType) {
|
||||
case 'string': {
|
||||
property.elInput = createStringProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'bool': {
|
||||
property.elInput = createBoolProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'number': {
|
||||
property.elInput = createNumberProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'vec3': {
|
||||
let elVec3 = createVec3Property(property, elProperty);
|
||||
property.elInputX = elVec3[VECTOR_ELEMENTS.X_INPUT];
|
||||
property.elInputY = elVec3[VECTOR_ELEMENTS.Y_INPUT];
|
||||
property.elInputZ = elVec3[VECTOR_ELEMENTS.Z_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'vec2': {
|
||||
let elVec2 = createVec2Property(property, elProperty);
|
||||
property.elInputX = elVec2[VECTOR_ELEMENTS.X_INPUT];
|
||||
property.elInputY = elVec2[VECTOR_ELEMENTS.Y_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'color': {
|
||||
let elColor = createColorProperty(property, elProperty);
|
||||
property.elColorPicker = elColor[COLOR_ELEMENTS.COLOR_PICKER];
|
||||
property.elInputR = elColor[COLOR_ELEMENTS.RED_INPUT];
|
||||
property.elInputG = elColor[COLOR_ELEMENTS.GREEN_INPUT];
|
||||
property.elInputB = elColor[COLOR_ELEMENTS.BLUE_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'dropdown': {
|
||||
property.elInput = createDropdownProperty(property, propertyID, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'textarea': {
|
||||
property.elInput = createTextareaProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'icon': {
|
||||
let elIcon = createIconProperty(property, elProperty);
|
||||
property.elSpan = elIcon[ICON_ELEMENTS.ICON];
|
||||
property.elLabel = elIcon[ICON_ELEMENTS.LABEL];
|
||||
break;
|
||||
}
|
||||
case 'texture': {
|
||||
let elTexture = createTextureProperty(property, elProperty);
|
||||
property.elImage = elTexture[TEXTURE_ELEMENTS.IMAGE];
|
||||
property.elInput = elTexture[TEXTURE_ELEMENTS.TEXT_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'buttons': {
|
||||
property.elProperty = createButtonsProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'placeholder':
|
||||
case 'sub-header': {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log("EntityProperties - Unknown property type " +
|
||||
propertyType + " set to property " + propertyID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BUTTON CALLBACKS
|
||||
|
@ -2604,88 +2740,6 @@ function showParentMaterialNameBox(number, elNumber, elString) {
|
|||
}
|
||||
}
|
||||
|
||||
function createProperty(propertyData, propertyElementID, propertyName, propertyID, elProperty) {
|
||||
let property = {
|
||||
data: propertyData,
|
||||
elementID: propertyElementID,
|
||||
name: propertyName,
|
||||
elProperty: elProperty,
|
||||
};
|
||||
let propertyType = propertyData.type;
|
||||
|
||||
switch (propertyType) {
|
||||
case 'string': {
|
||||
property.elInput = createStringProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'bool': {
|
||||
property.elInput = createBoolProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'number': {
|
||||
property.elInput = createNumberProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'vec3': {
|
||||
let elVec3 = createVec3Property(property, elProperty);
|
||||
property.elInputX = elVec3[VECTOR_ELEMENTS.X_INPUT];
|
||||
property.elInputY = elVec3[VECTOR_ELEMENTS.Y_INPUT];
|
||||
property.elInputZ = elVec3[VECTOR_ELEMENTS.Z_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'vec2': {
|
||||
let elVec2 = createVec2Property(property, elProperty);
|
||||
property.elInputX = elVec2[VECTOR_ELEMENTS.X_INPUT];
|
||||
property.elInputY = elVec2[VECTOR_ELEMENTS.Y_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'color': {
|
||||
let elColor = createColorProperty(property, elProperty);
|
||||
property.elColorPicker = elColor[COLOR_ELEMENTS.COLOR_PICKER];
|
||||
property.elInputR = elColor[COLOR_ELEMENTS.RED_INPUT];
|
||||
property.elInputG = elColor[COLOR_ELEMENTS.GREEN_INPUT];
|
||||
property.elInputB = elColor[COLOR_ELEMENTS.BLUE_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'dropdown': {
|
||||
property.elInput = createDropdownProperty(property, propertyID, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'textarea': {
|
||||
property.elInput = createTextareaProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'icon': {
|
||||
let elIcon = createIconProperty(property, elProperty);
|
||||
property.elSpan = elIcon[ICON_ELEMENTS.ICON];
|
||||
property.elLabel = elIcon[ICON_ELEMENTS.LABEL];
|
||||
break;
|
||||
}
|
||||
case 'texture': {
|
||||
let elTexture = createTextureProperty(property, elProperty);
|
||||
property.elImage = elTexture[TEXTURE_ELEMENTS.IMAGE];
|
||||
property.elInput = elTexture[TEXTURE_ELEMENTS.TEXT_INPUT];
|
||||
break;
|
||||
}
|
||||
case 'buttons': {
|
||||
property.elProperty = createButtonsProperty(property, elProperty);
|
||||
break;
|
||||
}
|
||||
case 'placeholder':
|
||||
case 'sub-header': {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log("EntityProperties - Unknown property type " +
|
||||
propertyType + " set to property " + propertyID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function loaded() {
|
||||
openEventBridge(function() {
|
||||
|
@ -2723,6 +2777,7 @@ function loaded() {
|
|||
let propertyType = propertyData.type;
|
||||
let propertyID = propertyData.propertyID;
|
||||
let propertyName = propertyData.propertyName !== undefined ? propertyData.propertyName : propertyID;
|
||||
let propertySpaceMode = propertyData.spaceMode !== undefined ? propertyData.spaceMode : PROPERTY_SPACE_MODE.ALL;
|
||||
let propertyElementID = "property-" + propertyID;
|
||||
propertyElementID = propertyElementID.replace('.', '-');
|
||||
|
||||
|
@ -2775,7 +2830,7 @@ function loaded() {
|
|||
} else {
|
||||
elContainer = document.getElementById(propertyData.replaceID);
|
||||
}
|
||||
|
||||
|
||||
if (elLabel) {
|
||||
createAppTooltip.registerTooltipElement(elLabel, propertyID);
|
||||
}
|
||||
|
@ -2837,6 +2892,8 @@ function loaded() {
|
|||
|
||||
let minorSections = document.querySelectorAll(".section.minor");
|
||||
minorSections[minorSections.length - 1].className += " last";
|
||||
|
||||
updateVisibleSpaceModeProperties();
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
|
@ -2857,6 +2914,9 @@ function loaded() {
|
|||
elServerScriptStatus.innerText = NOT_RUNNING_SCRIPT_STATUS;
|
||||
}
|
||||
} else if (data.type === "update" && data.selections) {
|
||||
if (data.spaceMode !== undefined) {
|
||||
currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD;
|
||||
}
|
||||
if (data.selections.length === 0) {
|
||||
if (lastEntityID !== null) {
|
||||
if (editor !== null) {
|
||||
|
@ -3082,7 +3142,9 @@ function loaded() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateVisibleSpaceModeProperties();
|
||||
|
||||
if (selectedEntityProperties.type === "Image") {
|
||||
let imageLink = JSON.parse(selectedEntityProperties.textures)["tex.picture"];
|
||||
getPropertyInputElement("image").value = imageLink;
|
||||
|
@ -3167,6 +3229,9 @@ function loaded() {
|
|||
createAppTooltip.setTooltipData(data.tooltips);
|
||||
} else if (data.type === 'hmdActiveChanged') {
|
||||
createAppTooltip.setIsEnabled(!data.hmdActive);
|
||||
} else if (data.type === 'setSpaceMode') {
|
||||
currentSpaceMode = data.spaceMode === "local" ? PROPERTY_SPACE_MODE.LOCAL : PROPERTY_SPACE_MODE.WORLD;
|
||||
updateVisibleSpaceModeProperties();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -115,6 +115,13 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
|||
});
|
||||
});
|
||||
|
||||
that.setSpaceMode = function(spaceMode) {
|
||||
emitJSONScriptEvent({
|
||||
type: 'setSpaceMode',
|
||||
spaceMode: spaceMode
|
||||
});
|
||||
};
|
||||
|
||||
that.clearEntityList = function() {
|
||||
emitJSONScriptEvent({
|
||||
type: 'clearEntityList'
|
||||
|
@ -200,6 +207,7 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
|||
type: "update",
|
||||
entities: entities,
|
||||
selectedIDs: selectedIDs,
|
||||
spaceMode: SelectionDisplay.getSpaceMode(),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -288,6 +296,8 @@ EntityListTool = function(shouldUseEditTabletApp) {
|
|||
Entities.editEntity(data.entityID, {name: data.name});
|
||||
// make sure that the name also gets updated in the properties window
|
||||
SelectionManager._update();
|
||||
} else if (data.type === "toggleSpaceMode") {
|
||||
SelectionDisplay.toggleSpaceMode();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ SelectionManager = (function() {
|
|||
var actionArguments = Entities.getActionArguments(properties.id, actionID);
|
||||
if (actionArguments) {
|
||||
var type = actionArguments.type;
|
||||
if (type == 'hold' || type == 'far-grab') {
|
||||
if (type === 'hold' || type === 'far-grab') {
|
||||
continue;
|
||||
}
|
||||
delete actionArguments.ttl;
|
||||
|
@ -500,7 +500,7 @@ SelectionManager = (function() {
|
|||
that.entityType = properties.type;
|
||||
|
||||
if (selectionUpdated) {
|
||||
SelectionDisplay.setSpaceMode(SPACE_LOCAL);
|
||||
SelectionDisplay.useDesiredSpaceMode();
|
||||
}
|
||||
} else {
|
||||
properties = Entities.getEntityProperties(that.selections[0], ['type', 'boundingBox']);
|
||||
|
@ -537,7 +537,7 @@ SelectionManager = (function() {
|
|||
};
|
||||
|
||||
// For 1+ selections we can only modify selections in world space
|
||||
SelectionDisplay.setSpaceMode(SPACE_WORLD);
|
||||
SelectionDisplay.setSpaceMode(SPACE_WORLD, false);
|
||||
}
|
||||
|
||||
for (var j = 0; j < listeners.length; j++) {
|
||||
|
@ -633,24 +633,26 @@ SelectionDisplay = (function() {
|
|||
ALL: 3
|
||||
};
|
||||
|
||||
const SCALE_DIRECTION = {
|
||||
LBN: 0,
|
||||
RBN: 1,
|
||||
LBF: 2,
|
||||
RBF: 3,
|
||||
LTN: 4,
|
||||
RTN: 5,
|
||||
LTF: 6,
|
||||
RTF: 7
|
||||
};
|
||||
|
||||
const ROTATE_DIRECTION = {
|
||||
PITCH: 0,
|
||||
YAW: 1,
|
||||
ROLL: 2
|
||||
};
|
||||
|
||||
/**
|
||||
* The current space mode, this could have been a forced space mode since we do not support multi selection while in
|
||||
* local space mode.
|
||||
* @type {string} - should only be set to SPACE_LOCAL or SPACE_WORLD
|
||||
*/
|
||||
var spaceMode = SPACE_LOCAL;
|
||||
|
||||
/**
|
||||
* The desired space mode, this is the user set space mode, which should be respected whenever it is possible. In the case
|
||||
* of multi entity selection this space mode may differ from the actual spaceMode.
|
||||
* @type {string} - should only be set to SPACE_LOCAL or SPACE_WORLD
|
||||
*/
|
||||
var desiredSpaceMode = SPACE_LOCAL;
|
||||
|
||||
var overlayNames = [];
|
||||
var lastControllerPoses = [
|
||||
getControllerWorldLocation(Controller.Standard.LeftHand, true),
|
||||
|
@ -1340,7 +1342,7 @@ SelectionDisplay = (function() {
|
|||
}
|
||||
};
|
||||
|
||||
function controllerComputePickRay(hand) {
|
||||
function controllerComputePickRay() {
|
||||
var hand = that.triggered() ? that.triggeredHand : that.pressedHand;
|
||||
var controllerPose = getControllerWorldLocation(hand, true);
|
||||
if (controllerPose.valid) {
|
||||
|
@ -1400,8 +1402,21 @@ SelectionDisplay = (function() {
|
|||
that.updateHandles();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This callback is used for spaceMode changes.
|
||||
* @callback spaceModeChangedCallback
|
||||
* @param {string} spaceMode
|
||||
*/
|
||||
|
||||
/**
|
||||
* set this property with a callback to keep track of spaceMode changes.
|
||||
* @type {spaceModeChangedCallback}
|
||||
*/
|
||||
that.onSpaceModeChange = null;
|
||||
|
||||
// FUNCTION: SET SPACE MODE
|
||||
that.setSpaceMode = function(newSpaceMode) {
|
||||
that.setSpaceMode = function(newSpaceMode, isDesiredChange) {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("======> SetSpaceMode called. ========");
|
||||
|
@ -1411,7 +1426,15 @@ SelectionDisplay = (function() {
|
|||
if (wantDebug) {
|
||||
print(" Updating SpaceMode From: " + spaceMode + " To: " + newSpaceMode);
|
||||
}
|
||||
if (isDesiredChange) {
|
||||
desiredSpaceMode = newSpaceMode;
|
||||
}
|
||||
spaceMode = newSpaceMode;
|
||||
|
||||
if (that.onSpaceModeChange !== null) {
|
||||
that.onSpaceModeChange(newSpaceMode);
|
||||
}
|
||||
|
||||
that.updateHandles();
|
||||
} else if (wantDebug) {
|
||||
print("WARNING: entitySelectionTool.setSpaceMode - Can't update SpaceMode. CurrentMode: " +
|
||||
|
@ -1437,14 +1460,36 @@ SelectionDisplay = (function() {
|
|||
if (wantDebug) {
|
||||
print("PreToggle: " + spaceMode);
|
||||
}
|
||||
spaceMode = (spaceMode === SPACE_LOCAL) ? SPACE_WORLD : SPACE_LOCAL;
|
||||
that.updateHandles();
|
||||
that.setSpaceMode((spaceMode === SPACE_LOCAL) ? SPACE_WORLD : SPACE_LOCAL, true);
|
||||
if (wantDebug) {
|
||||
print("PostToggle: " + spaceMode);
|
||||
print("======== ToggleSpaceMode called. <=========");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Switches the display mode back to the set desired display mode
|
||||
*/
|
||||
that.useDesiredSpaceMode = function() {
|
||||
var wantDebug = false;
|
||||
if (wantDebug) {
|
||||
print("========> UseDesiredSpaceMode called. =========");
|
||||
}
|
||||
that.setSpaceMode(desiredSpaceMode, false);
|
||||
if (wantDebug) {
|
||||
print("PostToggle: " + spaceMode);
|
||||
print("======== UseDesiredSpaceMode called. <=========");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the currently set SpaceMode
|
||||
* @returns {string} spaceMode
|
||||
*/
|
||||
that.getSpaceMode = function() {
|
||||
return spaceMode;
|
||||
};
|
||||
|
||||
function addHandleTool(overlay, tool) {
|
||||
handleTools[overlay] = tool;
|
||||
return tool;
|
||||
|
@ -1787,7 +1832,7 @@ SelectionDisplay = (function() {
|
|||
!isActiveTool(handleRotateYawRing) &&
|
||||
!isActiveTool(handleRotateRollRing)));
|
||||
|
||||
// keep duplicator always hidden for now since you can hold Alt to duplciate while
|
||||
// keep duplicator always hidden for now since you can hold Alt to duplicate while
|
||||
// translating an entity - we may bring duplicator back for HMD only later
|
||||
// that.setHandleDuplicatorVisible(!activeTool || isActiveTool(handleDuplicator));
|
||||
|
||||
|
|
Loading…
Reference in a new issue