mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 20:36:38 +02:00
merging with dante's PR
This commit is contained in:
commit
c47788efe4
22 changed files with 713 additions and 100 deletions
BIN
interface/resources/images/loadingBar_placard.png
Normal file
BIN
interface/resources/images/loadingBar_placard.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
interface/resources/images/loadingBar_progress.png
Normal file
BIN
interface/resources/images/loadingBar_progress.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -1387,6 +1387,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
});
|
});
|
||||||
connect(this, &Application::activeDisplayPluginChanged,
|
connect(this, &Application::activeDisplayPluginChanged,
|
||||||
reinterpret_cast<scripting::Audio*>(audioScriptingInterface.data()), &scripting::Audio::onContextChanged);
|
reinterpret_cast<scripting::Audio*>(audioScriptingInterface.data()), &scripting::Audio::onContextChanged);
|
||||||
|
connect(this, &Application::interstitialModeChanged, audioIO, &AudioClient::setInterstitialStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the rendering engine. This can be slow on some machines due to lots of
|
// Create the rendering engine. This can be slow on some machines due to lots of
|
||||||
|
@ -1645,7 +1646,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
audioClient->setMuted(!audioClient->isMuted());
|
audioClient->setMuted(!audioClient->isMuted());
|
||||||
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
|
||||||
cycleCamera();
|
cycleCamera();
|
||||||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU) && !isInterstitialMode()) {
|
||||||
toggleTabletUI();
|
toggleTabletUI();
|
||||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||||
auto oldPos = getApplicationCompositor().getReticlePosition();
|
auto oldPos = getApplicationCompositor().getReticlePosition();
|
||||||
|
@ -2294,6 +2295,25 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
// Preload Tablet sounds
|
// Preload Tablet sounds
|
||||||
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
|
DependencyManager::get<TabletScriptingInterface>()->preloadSounds();
|
||||||
|
|
||||||
|
connect(this, &Application::interstitialModeChanged, this, [this] (bool interstitialMode) {
|
||||||
|
if (!interstitialMode) {
|
||||||
|
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||||
|
_queryExpiry = SteadyClock::now();
|
||||||
|
if (_avatarOverrideUrl.isValid()) {
|
||||||
|
getMyAvatar()->useFullAvatarURL(_avatarOverrideUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getMyAvatar()->getFullAvatarURLFromPreferences() != getMyAvatar()->getSkeletonModelURL()) {
|
||||||
|
getMyAvatar()->resetFullAvatarURL();
|
||||||
|
}
|
||||||
|
getMyAvatar()->markIdentityDataChanged();
|
||||||
|
getMyAvatar()->resetLastSent();
|
||||||
|
|
||||||
|
// transmit a "sendAll" packet to the AvatarMixer we just connected to.
|
||||||
|
getMyAvatar()->sendAvatarDataPacket(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
_pendingIdleEvent = false;
|
_pendingIdleEvent = false;
|
||||||
_pendingRenderEvent = false;
|
_pendingRenderEvent = false;
|
||||||
|
|
||||||
|
@ -2994,6 +3014,9 @@ void Application::initializeUi() {
|
||||||
if (_window && _window->isFullScreen()) {
|
if (_window && _window->isFullScreen()) {
|
||||||
setFullscreen(nullptr, true);
|
setFullscreen(nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setIsInterstitialMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3470,6 +3493,22 @@ bool Application::isServerlessMode() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Application::isInterstitialMode() const {
|
||||||
|
bool interstitialModeEnabled = Menu::getInstance()->isOptionChecked("Enable Interstitial");
|
||||||
|
return interstitialModeEnabled ? _interstitialMode : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::setIsInterstitialMode(bool interstitialMode) {
|
||||||
|
auto menu = Menu::getInstance();
|
||||||
|
bool interstitialModeEnabled = menu->isOptionChecked("Enable Interstitial");
|
||||||
|
if (_interstitialMode != interstitialMode && interstitialModeEnabled) {
|
||||||
|
_interstitialMode = interstitialMode;
|
||||||
|
|
||||||
|
DependencyManager::get<OffscreenUi>()->setPinned(_interstitialMode);
|
||||||
|
emit interstitialModeChanged(_interstitialMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setIsServerlessMode(bool serverlessDomain) {
|
void Application::setIsServerlessMode(bool serverlessDomain) {
|
||||||
auto tree = getEntities()->getTree();
|
auto tree = getEntities()->getTree();
|
||||||
if (tree) {
|
if (tree) {
|
||||||
|
@ -3750,7 +3789,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|
||||||
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts
|
||||||
// if one of our scripts have asked to capture this event, then stop processing it
|
// if one of our scripts have asked to capture this event, then stop processing it
|
||||||
if (_controllerScriptingInterface->isKeyCaptured(event)) {
|
if (_controllerScriptingInterface->isKeyCaptured(event) || isInterstitialMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5308,6 +5347,7 @@ void Application::resetPhysicsReadyInformation() {
|
||||||
_fullSceneCounterAtLastPhysicsCheck = 0;
|
_fullSceneCounterAtLastPhysicsCheck = 0;
|
||||||
_nearbyEntitiesCountAtLastPhysicsCheck = 0;
|
_nearbyEntitiesCountAtLastPhysicsCheck = 0;
|
||||||
_nearbyEntitiesStabilityCount = 0;
|
_nearbyEntitiesStabilityCount = 0;
|
||||||
|
_nearbyEntitiesReadyCount = 0;
|
||||||
_physicsEnabled = false;
|
_physicsEnabled = false;
|
||||||
_octreeProcessor.startEntitySequence();
|
_octreeProcessor.startEntitySequence();
|
||||||
}
|
}
|
||||||
|
@ -5535,6 +5575,7 @@ void Application::update(float deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!_physicsEnabled) {
|
if (!_physicsEnabled) {
|
||||||
if (!domainLoadingInProgress) {
|
if (!domainLoadingInProgress) {
|
||||||
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
|
||||||
|
@ -5544,7 +5585,8 @@ void Application::update(float deltaTime) {
|
||||||
// we haven't yet enabled physics. we wait until we think we have all the collision information
|
// we haven't yet enabled physics. we wait until we think we have all the collision information
|
||||||
// for nearby entities before starting bullet up.
|
// for nearby entities before starting bullet up.
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
if (isServerlessMode() || _octreeProcessor.isLoadSequenceComplete()) {
|
bool renderReady = _octreeProcessor.isEntitiesRenderReady();
|
||||||
|
if (isServerlessMode() || (_octreeProcessor.isLoadSequenceComplete() && renderReady)) {
|
||||||
// we've received a new full-scene octree stats packet, or it's been long enough to try again anyway
|
// we've received a new full-scene octree stats packet, or it's been long enough to try again anyway
|
||||||
_lastPhysicsCheckTime = now;
|
_lastPhysicsCheckTime = now;
|
||||||
_fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;
|
_fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;
|
||||||
|
@ -5555,6 +5597,7 @@ void Application::update(float deltaTime) {
|
||||||
// scene is ready to compute its collision shape.
|
// scene is ready to compute its collision shape.
|
||||||
if (getMyAvatar()->isReadyForPhysics()) {
|
if (getMyAvatar()->isReadyForPhysics()) {
|
||||||
_physicsEnabled = true;
|
_physicsEnabled = true;
|
||||||
|
setIsInterstitialMode(false);
|
||||||
getMyAvatar()->updateMotionBehaviorFromMenu();
|
getMyAvatar()->updateMotionBehaviorFromMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5634,7 +5677,7 @@ void Application::update(float deltaTime) {
|
||||||
// Transfer the user inputs to the driveKeys
|
// Transfer the user inputs to the driveKeys
|
||||||
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
// FIXME can we drop drive keys and just have the avatar read the action states directly?
|
||||||
myAvatar->clearDriveKeys();
|
myAvatar->clearDriveKeys();
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) {
|
if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT && !isInterstitialMode()) {
|
||||||
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
if (!_controllerScriptingInterface->areActionsCaptured() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z));
|
||||||
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
myAvatar->setDriveKey(MyAvatar::TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y));
|
||||||
|
@ -5952,7 +5995,7 @@ void Application::update(float deltaTime) {
|
||||||
// send packet containing downstream audio stats to the AudioMixer
|
// send packet containing downstream audio stats to the AudioMixer
|
||||||
{
|
{
|
||||||
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
|
||||||
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {
|
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS && !isInterstitialMode()) {
|
||||||
_lastSendDownstreamAudioStats = now;
|
_lastSendDownstreamAudioStats = now;
|
||||||
|
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection);
|
||||||
|
@ -6115,21 +6158,23 @@ void Application::updateRenderArgs(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::queryAvatars() {
|
void Application::queryAvatars() {
|
||||||
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
if (!isInterstitialMode()) {
|
||||||
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
auto avatarPacket = NLPacket::create(PacketType::AvatarQuery);
|
||||||
unsigned char* bufferStart = destinationBuffer;
|
auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload());
|
||||||
|
unsigned char* bufferStart = destinationBuffer;
|
||||||
|
|
||||||
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
uint8_t numFrustums = (uint8_t)_conicalViews.size();
|
||||||
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums));
|
||||||
destinationBuffer += sizeof(numFrustums);
|
destinationBuffer += sizeof(numFrustums);
|
||||||
|
|
||||||
for (const auto& view : _conicalViews) {
|
for (const auto& view : _conicalViews) {
|
||||||
destinationBuffer += view.serialize(destinationBuffer);
|
destinationBuffer += view.serialize(destinationBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
||||||
|
|
||||||
|
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPacket->setPayloadSize(destinationBuffer - bufferStart);
|
|
||||||
|
|
||||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6352,6 +6397,7 @@ void Application::clearDomainOctreeDetails() {
|
||||||
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
qCDebug(interfaceapp) << "Clearing domain octree details...";
|
||||||
|
|
||||||
resetPhysicsReadyInformation();
|
resetPhysicsReadyInformation();
|
||||||
|
setIsInterstitialMode(true);
|
||||||
|
|
||||||
_octreeServerSceneStats.withWriteLock([&] {
|
_octreeServerSceneStats.withWriteLock([&] {
|
||||||
_octreeServerSceneStats.clear();
|
_octreeServerSceneStats.clear();
|
||||||
|
@ -6437,11 +6483,11 @@ void Application::nodeActivated(SharedNodePointer node) {
|
||||||
_octreeQuery.incrementConnectionID();
|
_octreeQuery.incrementConnectionID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getType() == NodeType::AudioMixer) {
|
if (node->getType() == NodeType::AudioMixer && !isInterstitialMode()) {
|
||||||
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
DependencyManager::get<AudioClient>()->negotiateAudioFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->getType() == NodeType::AvatarMixer) {
|
if (node->getType() == NodeType::AvatarMixer && !isInterstitialMode()) {
|
||||||
_queryExpiry = SteadyClock::now();
|
_queryExpiry = SteadyClock::now();
|
||||||
|
|
||||||
// new avatar mixer, send off our identity packet on next update loop
|
// new avatar mixer, send off our identity packet on next update loop
|
||||||
|
@ -6558,6 +6604,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() {
|
||||||
_nearbyEntitiesCountAtLastPhysicsCheck = nearbyCount;
|
_nearbyEntitiesCountAtLastPhysicsCheck = nearbyCount;
|
||||||
|
|
||||||
const uint32_t MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT = 3;
|
const uint32_t MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT = 3;
|
||||||
|
uint32_t readyNearbyEntities = 0;
|
||||||
if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) {
|
if (_nearbyEntitiesStabilityCount >= MINIMUM_NEARBY_ENTITIES_STABILITY_COUNT) {
|
||||||
// We've seen the same number of nearby entities for several stats packets in a row. assume we've got all
|
// We've seen the same number of nearby entities for several stats packets in a row. assume we've got all
|
||||||
// the local entities.
|
// the local entities.
|
||||||
|
@ -6567,8 +6614,11 @@ bool Application::nearbyEntitiesAreReadyForPhysics() {
|
||||||
HIFI_FCDEBUG(interfaceapp(), "Physics disabled until entity loads: " << entity->getID() << entity->getName());
|
HIFI_FCDEBUG(interfaceapp(), "Physics disabled until entity loads: " << entity->getID() << entity->getName());
|
||||||
// don't break here because we want all the relevant entities to start their downloads
|
// don't break here because we want all the relevant entities to start their downloads
|
||||||
result = false;
|
result = false;
|
||||||
|
} else {
|
||||||
|
readyNearbyEntities++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_nearbyEntitiesReadyCount = readyNearbyEntities;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -7809,7 +7859,7 @@ float Application::getRenderResolutionScale() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::notifyPacketVersionMismatch() {
|
void Application::notifyPacketVersionMismatch() {
|
||||||
if (!_notifiedPacketVersionMismatchThisDomain) {
|
if (!_notifiedPacketVersionMismatchThisDomain && !isInterstitialMode()) {
|
||||||
_notifiedPacketVersionMismatchThisDomain = true;
|
_notifiedPacketVersionMismatchThisDomain = true;
|
||||||
|
|
||||||
QString message = "The location you are visiting is running an incompatible server version.\n";
|
QString message = "The location you are visiting is running an incompatible server version.\n";
|
||||||
|
|
|
@ -224,11 +224,17 @@ public:
|
||||||
void setHmdTabletBecomesToolbarSetting(bool value);
|
void setHmdTabletBecomesToolbarSetting(bool value);
|
||||||
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||||
void setPreferStylusOverLaser(bool value);
|
void setPreferStylusOverLaser(bool value);
|
||||||
|
|
||||||
|
uint32_t getEntitiesStabilityCount() { return _nearbyEntitiesStabilityCount; }
|
||||||
|
uint32_t getNearbyEntitiesReadyCount() { return _nearbyEntitiesReadyCount; }
|
||||||
|
uint32_t getNearbyEntitiesCount() { return _nearbyEntitiesCountAtLastPhysicsCheck; }
|
||||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||||
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||||
bool getPreferAvatarFingerOverStylus() { return false; }
|
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||||
void setPreferAvatarFingerOverStylus(bool value);
|
void setPreferAvatarFingerOverStylus(bool value);
|
||||||
|
|
||||||
|
float getDomainLoadingProgress() { return _octreeProcessor.domainLoadingProgress(); }
|
||||||
|
|
||||||
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||||
void setSettingConstrainToolbarPosition(bool setting);
|
void setSettingConstrainToolbarPosition(bool setting);
|
||||||
|
|
||||||
|
@ -304,6 +310,7 @@ public:
|
||||||
void saveNextPhysicsStats(QString filename);
|
void saveNextPhysicsStats(QString filename);
|
||||||
|
|
||||||
bool isServerlessMode() const;
|
bool isServerlessMode() const;
|
||||||
|
bool isInterstitialMode() const;
|
||||||
|
|
||||||
void replaceDomainContent(const QString& url);
|
void replaceDomainContent(const QString& url);
|
||||||
|
|
||||||
|
@ -330,6 +337,7 @@ signals:
|
||||||
void activeDisplayPluginChanged();
|
void activeDisplayPluginChanged();
|
||||||
|
|
||||||
void uploadRequest(QString path);
|
void uploadRequest(QString path);
|
||||||
|
void interstitialModeChanged(bool interstitialMode);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
QVector<EntityItemID> pasteEntities(float x, float y, float z);
|
||||||
|
@ -427,6 +435,8 @@ public slots:
|
||||||
|
|
||||||
void setIsServerlessMode(bool serverlessDomain);
|
void setIsServerlessMode(bool serverlessDomain);
|
||||||
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
|
void loadServerlessDomain(QUrl domainURL, bool errorDomain = false);
|
||||||
|
void setIsInterstitialMode(bool interstialMode);
|
||||||
|
void loadServerlessDomain(QUrl domainURL);
|
||||||
|
|
||||||
void updateVerboseLogging();
|
void updateVerboseLogging();
|
||||||
|
|
||||||
|
@ -627,6 +637,7 @@ private:
|
||||||
QHash<int, QKeyEvent> _keysPressed;
|
QHash<int, QKeyEvent> _keysPressed;
|
||||||
|
|
||||||
bool _enableProcessOctreeThread;
|
bool _enableProcessOctreeThread;
|
||||||
|
bool _interstitialMode { false };
|
||||||
|
|
||||||
OctreePacketProcessor _octreeProcessor;
|
OctreePacketProcessor _octreeProcessor;
|
||||||
EntityEditPacketSender _entityEditSender;
|
EntityEditPacketSender _entityEditSender;
|
||||||
|
@ -722,6 +733,7 @@ private:
|
||||||
uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready
|
uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready
|
||||||
uint32_t _nearbyEntitiesCountAtLastPhysicsCheck { 0 }; // how many in-range entities last time we checked physics ready
|
uint32_t _nearbyEntitiesCountAtLastPhysicsCheck { 0 }; // how many in-range entities last time we checked physics ready
|
||||||
uint32_t _nearbyEntitiesStabilityCount { 0 }; // how many times has _nearbyEntitiesCountAtLastPhysicsCheck been the same
|
uint32_t _nearbyEntitiesStabilityCount { 0 }; // how many times has _nearbyEntitiesCountAtLastPhysicsCheck been the same
|
||||||
|
uint32_t _nearbyEntitiesReadyCount { 0 };
|
||||||
quint64 _lastPhysicsCheckTime { usecTimestampNow() }; // when did we last check to see if physics was ready
|
quint64 _lastPhysicsCheckTime { usecTimestampNow() }; // when did we last check to see if physics was ready
|
||||||
|
|
||||||
bool _keyboardDeviceHasFocus { true };
|
bool _keyboardDeviceHasFocus { true };
|
||||||
|
|
|
@ -787,6 +787,7 @@ Menu::Menu() {
|
||||||
|
|
||||||
// Developer > Show Overlays
|
// Developer > Show Overlays
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Overlays, 0, true);
|
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Overlays, 0, true);
|
||||||
|
addCheckableActionToQMenuAndActionHash(developerMenu, "Enable Interstitial", 0, false);
|
||||||
|
|
||||||
#if 0 /// -------------- REMOVED FOR NOW --------------
|
#if 0 /// -------------- REMOVED FOR NOW --------------
|
||||||
addDisabledActionAndSeparator(navigateMenu, "History");
|
addDisabledActionAndSeparator(navigateMenu, "History");
|
||||||
|
|
|
@ -137,7 +137,7 @@ 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) {
|
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !qApp->isInterstitialMode()) {
|
||||||
// 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");
|
||||||
_myAvatar->sendAvatarDataPacket();
|
_myAvatar->sendAvatarDataPacket();
|
||||||
|
@ -808,13 +808,13 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
|
||||||
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
QString currentSessionUUID = avatar->getSessionUUID().toString();
|
||||||
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
if (specificAvatarIdentifiers.isEmpty() || specificAvatarIdentifiers.contains(currentSessionUUID)) {
|
||||||
QJsonObject thisAvatarPalData;
|
QJsonObject thisAvatarPalData;
|
||||||
|
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
|
||||||
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
if (currentSessionUUID == myAvatar->getSessionUUID().toString()) {
|
||||||
currentSessionUUID = "";
|
currentSessionUUID = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
thisAvatarPalData.insert("sessionUUID", currentSessionUUID);
|
||||||
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
thisAvatarPalData.insert("sessionDisplayName", avatar->getSessionDisplayName());
|
||||||
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
thisAvatarPalData.insert("audioLoudness", avatar->getAudioLoudness());
|
||||||
|
|
|
@ -137,3 +137,11 @@ void OctreePacketProcessor::startEntitySequence() {
|
||||||
bool OctreePacketProcessor::isLoadSequenceComplete() const {
|
bool OctreePacketProcessor::isLoadSequenceComplete() const {
|
||||||
return _safeLanding->isLoadSequenceComplete();
|
return _safeLanding->isLoadSequenceComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OctreePacketProcessor::isEntitiesRenderReady() const {
|
||||||
|
return _safeLanding->entitiesRenderReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
float OctreePacketProcessor::domainLoadingProgress() {
|
||||||
|
return _safeLanding->loadingProgressPercentage();
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ public:
|
||||||
|
|
||||||
void startEntitySequence();
|
void startEntitySequence();
|
||||||
bool isLoadSequenceComplete() const;
|
bool isLoadSequenceComplete() const;
|
||||||
|
bool isEntitiesRenderReady() const;
|
||||||
|
float domainLoadingProgress();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void packetVersionMismatch();
|
void packetVersionMismatch();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityT
|
||||||
if (entityTree) {
|
if (entityTree) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
_entityTree = entityTree;
|
_entityTree = entityTree;
|
||||||
|
_trackedEntitiesRenderStatus.clear();
|
||||||
_trackedEntities.clear();
|
_trackedEntities.clear();
|
||||||
_trackingEntities = true;
|
_trackingEntities = true;
|
||||||
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
|
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
|
||||||
|
@ -53,6 +55,7 @@ void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityT
|
||||||
void SafeLanding::stopEntitySequence() {
|
void SafeLanding::stopEntitySequence() {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
_trackingEntities = false;
|
_trackingEntities = false;
|
||||||
|
_maxTrackedEntityCount = 0;
|
||||||
_initialStart = INVALID_SEQUENCE;
|
_initialStart = INVALID_SEQUENCE;
|
||||||
_initialEnd = INVALID_SEQUENCE;
|
_initialEnd = INVALID_SEQUENCE;
|
||||||
_trackedEntities.clear();
|
_trackedEntities.clear();
|
||||||
|
@ -79,12 +82,20 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_trackedEntitiesRenderStatus.emplace(entityID, entity);
|
||||||
|
float trackedEntityCount = (float)_trackedEntitiesRenderStatus.size();
|
||||||
|
|
||||||
|
if (trackedEntityCount > _maxTrackedEntityCount) {
|
||||||
|
_maxTrackedEntityCount = trackedEntityCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafeLanding::deleteTrackedEntity(const EntityItemID& entityID) {
|
void SafeLanding::deleteTrackedEntity(const EntityItemID& entityID) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
_trackedEntities.erase(entityID);
|
_trackedEntities.erase(entityID);
|
||||||
|
_trackedEntitiesRenderStatus.erase(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafeLanding::setCompletionSequenceNumbers(int first, int last) {
|
void SafeLanding::setCompletionSequenceNumbers(int first, int last) {
|
||||||
|
@ -116,6 +127,16 @@ bool SafeLanding::isLoadSequenceComplete() {
|
||||||
return !_trackingEntities;
|
return !_trackingEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SafeLanding::loadingProgressPercentage() {
|
||||||
|
Locker lock(_lock);
|
||||||
|
if (_maxTrackedEntityCount > 0) {
|
||||||
|
float trackedEntityCount = (float)_trackedEntitiesRenderStatus.size();
|
||||||
|
return ((_maxTrackedEntityCount - trackedEntityCount) / _maxTrackedEntityCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
bool SafeLanding::isSequenceNumbersComplete() {
|
bool SafeLanding::isSequenceNumbersComplete() {
|
||||||
if (_initialStart != INVALID_SEQUENCE) {
|
if (_initialStart != INVALID_SEQUENCE) {
|
||||||
Locker lock(_lock);
|
Locker lock(_lock);
|
||||||
|
@ -148,6 +169,24 @@ bool SafeLanding::isEntityPhysicsComplete() {
|
||||||
return _trackedEntities.empty();
|
return _trackedEntities.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SafeLanding::entitiesRenderReady() {
|
||||||
|
Locker lock(_lock);
|
||||||
|
auto entityTree = qApp->getEntities();
|
||||||
|
for (auto entityMapIter = _trackedEntitiesRenderStatus.begin(); entityMapIter != _trackedEntitiesRenderStatus.end(); ++entityMapIter) {
|
||||||
|
auto entity = entityMapIter->second;
|
||||||
|
bool visuallyReady = entity->isVisuallyReady();
|
||||||
|
if (visuallyReady || !entityTree->renderableForEntityId(entityMapIter->first)) {
|
||||||
|
entityMapIter = _trackedEntitiesRenderStatus.erase(entityMapIter);
|
||||||
|
if (entityMapIter == _trackedEntitiesRenderStatus.end()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entity->requestRenderUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _trackedEntitiesRenderStatus.empty();
|
||||||
|
}
|
||||||
|
|
||||||
float SafeLanding::ElevatedPriority(const EntityItem& entityItem) {
|
float SafeLanding::ElevatedPriority(const EntityItem& entityItem) {
|
||||||
return entityItem.getCollisionless() ? 0.0f : 10.0f;
|
return entityItem.getCollisionless() ? 0.0f : 10.0f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
|
|
||||||
#include "EntityItem.h"
|
#include "EntityItem.h"
|
||||||
|
#include "EntityDynamicInterface.h"
|
||||||
|
|
||||||
class EntityTreeRenderer;
|
class EntityTreeRenderer;
|
||||||
class EntityItemID;
|
class EntityItemID;
|
||||||
|
@ -29,6 +30,8 @@ public:
|
||||||
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
||||||
void noteReceivedsequenceNumber(int sequenceNumber);
|
void noteReceivedsequenceNumber(int sequenceNumber);
|
||||||
bool isLoadSequenceComplete();
|
bool isLoadSequenceComplete();
|
||||||
|
bool entitiesRenderReady();
|
||||||
|
float loadingProgressPercentage();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addTrackedEntity(const EntityItemID& entityID);
|
void addTrackedEntity(const EntityItemID& entityID);
|
||||||
|
@ -45,10 +48,12 @@ private:
|
||||||
EntityTreePointer _entityTree;
|
EntityTreePointer _entityTree;
|
||||||
using EntityMap = std::map<EntityItemID, EntityItemPointer>;
|
using EntityMap = std::map<EntityItemID, EntityItemPointer>;
|
||||||
EntityMap _trackedEntities;
|
EntityMap _trackedEntities;
|
||||||
|
EntityMap _trackedEntitiesRenderStatus;
|
||||||
|
|
||||||
static constexpr int INVALID_SEQUENCE = -1;
|
static constexpr int INVALID_SEQUENCE = -1;
|
||||||
int _initialStart { INVALID_SEQUENCE };
|
int _initialStart { INVALID_SEQUENCE };
|
||||||
int _initialEnd { INVALID_SEQUENCE };
|
int _initialEnd { INVALID_SEQUENCE };
|
||||||
|
float _maxTrackedEntityCount { 0.0f };
|
||||||
|
|
||||||
struct SequenceLessThan {
|
struct SequenceLessThan {
|
||||||
bool operator()(const int& a, const int& b) const;
|
bool operator()(const int& a, const int& b) const;
|
||||||
|
|
|
@ -584,3 +584,8 @@ void WindowScriptingInterface::onMessageBoxSelected(int button) {
|
||||||
_messageBoxes.remove(id);
|
_messageBoxes.remove(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float WindowScriptingInterface::domainLoadingProgress() {
|
||||||
|
return qApp->getDomainLoadingProgress();
|
||||||
|
}
|
||||||
|
|
|
@ -561,6 +561,8 @@ public slots:
|
||||||
*/
|
*/
|
||||||
void closeMessageBox(int id);
|
void closeMessageBox(int id);
|
||||||
|
|
||||||
|
float domainLoadingProgress();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onWindowGeometryChanged(const QRect& geometry);
|
void onWindowGeometryChanged(const QRect& geometry);
|
||||||
void onMessageBoxSelected(int button);
|
void onMessageBoxSelected(int button);
|
||||||
|
|
|
@ -106,6 +106,10 @@ extern std::atomic<size_t> DECIMATED_TEXTURE_COUNT;
|
||||||
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
extern std::atomic<size_t> RECTIFIED_TEXTURE_COUNT;
|
||||||
|
|
||||||
void Stats::updateStats(bool force) {
|
void Stats::updateStats(bool force) {
|
||||||
|
|
||||||
|
if (qApp->isInterstitialMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
QQuickItem* parent = parentItem();
|
QQuickItem* parent = parentItem();
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||||
|
|
|
@ -651,7 +651,6 @@ void AudioClient::stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
char bitset;
|
char bitset;
|
||||||
message->readPrimitive(&bitset);
|
message->readPrimitive(&bitset);
|
||||||
|
|
||||||
|
@ -664,11 +663,10 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer<ReceivedMessag
|
||||||
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
_receivedAudioStream.setReverb(reverbTime, wetLevel);
|
||||||
} else {
|
} else {
|
||||||
_receivedAudioStream.clearReverb();
|
_receivedAudioStream.clearReverb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
void AudioClient::handleAudioDataPacket(QSharedPointer<ReceivedMessage> message) {
|
||||||
|
|
||||||
if (message->getType() == PacketType::SilentAudioFrame) {
|
if (message->getType() == PacketType::SilentAudioFrame) {
|
||||||
_silentInbound.increment();
|
_silentInbound.increment();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1026,80 +1024,82 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
|
||||||
if (_muted) {
|
if (!_interstitialMode) {
|
||||||
_lastInputLoudness = 0.0f;
|
if (_muted) {
|
||||||
_timeSinceLastClip = 0.0f;
|
_lastInputLoudness = 0.0f;
|
||||||
} else {
|
|
||||||
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
|
||||||
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
|
||||||
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
|
||||||
|
|
||||||
if (_isNoiseGateEnabled) {
|
|
||||||
// The audio gate includes DC removal
|
|
||||||
_audioGate->render(samples, samples, numFrames);
|
|
||||||
} else {
|
|
||||||
_audioGate->removeDC(samples, samples, numFrames);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t loudness = 0;
|
|
||||||
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
|
||||||
bool didClip = false;
|
|
||||||
for (int i = 0; i < numSamples; ++i) {
|
|
||||||
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
|
||||||
int32_t sample = std::abs((int32_t)samples[i]);
|
|
||||||
loudness += sample;
|
|
||||||
didClip |= (sample > CLIPPING_THRESHOLD);
|
|
||||||
}
|
|
||||||
_lastInputLoudness = (float)loudness / numSamples;
|
|
||||||
|
|
||||||
if (didClip) {
|
|
||||||
_timeSinceLastClip = 0.0f;
|
_timeSinceLastClip = 0.0f;
|
||||||
} else if (_timeSinceLastClip >= 0.0f) {
|
} else {
|
||||||
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
int16_t* samples = reinterpret_cast<int16_t*>(audioBuffer.data());
|
||||||
|
int numSamples = audioBuffer.size() / AudioConstants::SAMPLE_SIZE;
|
||||||
|
int numFrames = numSamples / (_isStereoInput ? AudioConstants::STEREO : AudioConstants::MONO);
|
||||||
|
|
||||||
|
if (_isNoiseGateEnabled) {
|
||||||
|
// The audio gate includes DC removal
|
||||||
|
_audioGate->render(samples, samples, numFrames);
|
||||||
|
} else {
|
||||||
|
_audioGate->removeDC(samples, samples, numFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t loudness = 0;
|
||||||
|
assert(numSamples < 65536); // int32_t loudness cannot overflow
|
||||||
|
bool didClip = false;
|
||||||
|
for (int i = 0; i < numSamples; ++i) {
|
||||||
|
const int32_t CLIPPING_THRESHOLD = (int32_t)(AudioConstants::MAX_SAMPLE_VALUE * 0.9f);
|
||||||
|
int32_t sample = std::abs((int32_t)samples[i]);
|
||||||
|
loudness += sample;
|
||||||
|
didClip |= (sample > CLIPPING_THRESHOLD);
|
||||||
|
}
|
||||||
|
_lastInputLoudness = (float)loudness / numSamples;
|
||||||
|
|
||||||
|
if (didClip) {
|
||||||
|
_timeSinceLastClip = 0.0f;
|
||||||
|
} else if (_timeSinceLastClip >= 0.0f) {
|
||||||
|
_timeSinceLastClip += (float)numSamples / (float)AudioConstants::SAMPLE_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit inputReceived(audioBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit inputReceived(audioBuffer);
|
emit inputLoudnessChanged(_lastInputLoudness);
|
||||||
|
|
||||||
|
// state machine to detect gate opening and closing
|
||||||
|
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
||||||
|
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||||
|
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||||
|
_audioGateOpen = audioGateOpen;
|
||||||
|
|
||||||
|
if (openedInLastBlock) {
|
||||||
|
emit noiseGateOpened();
|
||||||
|
} else if (closedInLastBlock) {
|
||||||
|
emit noiseGateClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// the codec must be flushed to silence before sending silent packets,
|
||||||
|
// so delay the transition to silent packets by one packet after becoming silent.
|
||||||
|
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
||||||
|
if (!audioGateOpen && !closedInLastBlock) {
|
||||||
|
packetType = PacketType::SilentAudioFrame;
|
||||||
|
_silentOutbound.increment();
|
||||||
|
} else {
|
||||||
|
_audioOutbound.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform audioTransform;
|
||||||
|
audioTransform.setTranslation(_positionGetter());
|
||||||
|
audioTransform.setRotation(_orientationGetter());
|
||||||
|
|
||||||
|
QByteArray encodedBuffer;
|
||||||
|
if (_encoder) {
|
||||||
|
_encoder->encode(audioBuffer, encodedBuffer);
|
||||||
|
} else {
|
||||||
|
encodedBuffer = audioBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
||||||
|
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
||||||
|
packetType, _selectedCodecName);
|
||||||
|
_stats.sentPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit inputLoudnessChanged(_lastInputLoudness);
|
|
||||||
|
|
||||||
// state machine to detect gate opening and closing
|
|
||||||
bool audioGateOpen = (_lastInputLoudness != 0.0f);
|
|
||||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
|
||||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
|
||||||
_audioGateOpen = audioGateOpen;
|
|
||||||
|
|
||||||
if (openedInLastBlock) {
|
|
||||||
emit noiseGateOpened();
|
|
||||||
} else if (closedInLastBlock) {
|
|
||||||
emit noiseGateClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// the codec must be flushed to silence before sending silent packets,
|
|
||||||
// so delay the transition to silent packets by one packet after becoming silent.
|
|
||||||
auto packetType = _shouldEchoToServer ? PacketType::MicrophoneAudioWithEcho : PacketType::MicrophoneAudioNoEcho;
|
|
||||||
if (!audioGateOpen && !closedInLastBlock) {
|
|
||||||
packetType = PacketType::SilentAudioFrame;
|
|
||||||
_silentOutbound.increment();
|
|
||||||
} else {
|
|
||||||
_audioOutbound.increment();
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform audioTransform;
|
|
||||||
audioTransform.setTranslation(_positionGetter());
|
|
||||||
audioTransform.setRotation(_orientationGetter());
|
|
||||||
|
|
||||||
QByteArray encodedBuffer;
|
|
||||||
if (_encoder) {
|
|
||||||
_encoder->encode(audioBuffer, encodedBuffer);
|
|
||||||
} else {
|
|
||||||
encodedBuffer = audioBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), _outgoingAvatarAudioSequenceNumber, _isStereoInput,
|
|
||||||
audioTransform, avatarBoundingBoxCorner, avatarBoundingBoxScale,
|
|
||||||
packetType, _selectedCodecName);
|
|
||||||
_stats.sentPacket();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleMicAudioInput() {
|
void AudioClient::handleMicAudioInput() {
|
||||||
|
|
|
@ -187,6 +187,7 @@ public slots:
|
||||||
void handleRecordedAudioInput(const QByteArray& audio);
|
void handleRecordedAudioInput(const QByteArray& audio);
|
||||||
void reset();
|
void reset();
|
||||||
void audioMixerKilled();
|
void audioMixerKilled();
|
||||||
|
void setInterstitialStatus(bool interstitialMode) { _interstitialMode = interstitialMode; }
|
||||||
|
|
||||||
void setMuted(bool muted, bool emitSignal = true);
|
void setMuted(bool muted, bool emitSignal = true);
|
||||||
bool isMuted() { return _muted; }
|
bool isMuted() { return _muted; }
|
||||||
|
@ -416,6 +417,7 @@ private:
|
||||||
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
QVector<AudioInjectorPointer> _activeLocalAudioInjectors;
|
||||||
|
|
||||||
bool _isPlayingBackRecording { false };
|
bool _isPlayingBackRecording { false };
|
||||||
|
bool _interstitialMode { true };
|
||||||
|
|
||||||
CodecPluginPointer _codec;
|
CodecPluginPointer _codec;
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
|
|
|
@ -1297,9 +1297,20 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for removal
|
|
||||||
ModelPointer model;
|
ModelPointer model;
|
||||||
withReadLock([&] { model = _model; });
|
withReadLock([&] { model = _model; });
|
||||||
|
|
||||||
|
withWriteLock([&] {
|
||||||
|
bool visuallyReady = true;
|
||||||
|
if (_hasModel) {
|
||||||
|
if (model && _didLastVisualGeometryRequestSucceed) {
|
||||||
|
visuallyReady = (_prevModelLoaded && _texturesLoaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity->setVisuallyReady(visuallyReady);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check for removal
|
||||||
if (!_hasModel) {
|
if (!_hasModel) {
|
||||||
if (model) {
|
if (model) {
|
||||||
model->removeFromScene(scene, transaction);
|
model->removeFromScene(scene, transaction);
|
||||||
|
@ -1441,11 +1452,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
// That is where _currentFrame and _lastAnimated were updated.
|
// That is where _currentFrame and _lastAnimated were updated.
|
||||||
if (_animating) {
|
if (_animating) {
|
||||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||||
|
|
||||||
if (!jointsMapped()) {
|
if (!jointsMapped()) {
|
||||||
mapJoints(entity, model->getJointNames());
|
mapJoints(entity, model->getJointNames());
|
||||||
//else the joint have been mapped before but we have a new animation to load
|
//else the joint have been mapped before but we have a new animation to load
|
||||||
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
} else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) {
|
||||||
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURL());
|
_animation = DependencyManager::get<AnimationCache>()->getAnimation(entity->getAnimationURL());
|
||||||
_jointMappingCompleted = false;
|
_jointMappingCompleted = false;
|
||||||
mapJoints(entity, model->getJointNames());
|
mapJoints(entity, model->getJointNames());
|
||||||
|
|
|
@ -288,6 +288,17 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
||||||
updateHazeFromEntity(entity);
|
updateHazeFromEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool visuallyReady = true;
|
||||||
|
uint32_t skyboxMode = entity->getSkyboxMode();
|
||||||
|
if (skyboxMode == COMPONENT_MODE_ENABLED && !_skyboxTextureURL.isEmpty()) {
|
||||||
|
bool skyboxLoadedOrFailed = (_skyboxTexture && (_skyboxTexture->isLoaded() || _skyboxTexture->isFailed()));
|
||||||
|
|
||||||
|
visuallyReady = skyboxLoadedOrFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity->setVisuallyReady(visuallyReady);
|
||||||
|
|
||||||
if (bloomChanged) {
|
if (bloomChanged) {
|
||||||
updateBloomFromEntity(entity);
|
updateBloomFromEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,7 @@ public:
|
||||||
void setDynamic(bool value);
|
void setDynamic(bool value);
|
||||||
|
|
||||||
virtual bool shouldBePhysical() const { return false; }
|
virtual bool shouldBePhysical() const { return false; }
|
||||||
|
bool isVisuallyReady() const { return _visuallyReady; }
|
||||||
|
|
||||||
bool getLocked() const;
|
bool getLocked() const;
|
||||||
void setLocked(bool value);
|
void setLocked(bool value);
|
||||||
|
@ -527,6 +528,7 @@ public:
|
||||||
void removeCloneID(const QUuid& cloneID);
|
void removeCloneID(const QUuid& cloneID);
|
||||||
const QVector<QUuid> getCloneIDs() const;
|
const QVector<QUuid> getCloneIDs() const;
|
||||||
void setCloneIDs(const QVector<QUuid>& cloneIDs);
|
void setCloneIDs(const QVector<QUuid>& cloneIDs);
|
||||||
|
void setVisuallyReady(bool visuallyReady) { _visuallyReady = visuallyReady; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestRenderUpdate();
|
void requestRenderUpdate();
|
||||||
|
@ -639,6 +641,7 @@ protected:
|
||||||
EntityTreeElementPointer _element; // set by EntityTreeElement
|
EntityTreeElementPointer _element; // set by EntityTreeElement
|
||||||
void* _physicsInfo { nullptr }; // set by EntitySimulation
|
void* _physicsInfo { nullptr }; // set by EntitySimulation
|
||||||
bool _simulated { false }; // set by EntitySimulation
|
bool _simulated { false }; // set by EntitySimulation
|
||||||
|
bool _visuallyReady { true };
|
||||||
|
|
||||||
bool addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action);
|
bool addActionInternal(EntitySimulationPointer simulation, EntityDynamicPointer action);
|
||||||
bool removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation = nullptr);
|
bool removeActionInternal(const QUuid& actionID, EntitySimulationPointer simulation = nullptr);
|
||||||
|
|
|
@ -40,6 +40,7 @@ ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(
|
||||||
_type = EntityTypes::Model;
|
_type = EntityTypes::Model;
|
||||||
_lastKnownCurrentFrame = -1;
|
_lastKnownCurrentFrame = -1;
|
||||||
_color[0] = _color[1] = _color[2] = 0;
|
_color[0] = _color[1] = _color[2] = 0;
|
||||||
|
_visuallyReady = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString ModelEntityItem::getTextures() const {
|
const QString ModelEntityItem::getTextures() const {
|
||||||
|
|
|
@ -42,6 +42,7 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
|
||||||
|
|
||||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||||
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
||||||
|
_visuallyReady = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||||
|
|
|
@ -34,7 +34,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
||||||
"system/emote.js"
|
"system/emote.js"
|
||||||
];
|
];
|
||||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||||
"system/controllers/controllerScripts.js",
|
"system/controllers/controllerScripts.js"
|
||||||
//"system/chat.js"
|
//"system/chat.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
456
scripts/system/interstitialPage.js
Normal file
456
scripts/system/interstitialPage.js
Normal file
|
@ -0,0 +1,456 @@
|
||||||
|
//
|
||||||
|
// interstitialPage.js
|
||||||
|
// scripts/system
|
||||||
|
//
|
||||||
|
// Created by Dante Ruiz on 08/02/2018.
|
||||||
|
// Copyright 2012 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
|
||||||
|
//
|
||||||
|
|
||||||
|
/* global Script, Controller, Overlays, Quat, MyAvatar, Entities, print, Vec3, AddressManager, Render, Window, Toolbars,
|
||||||
|
Camera, HMD, location, Account, Xform*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
Script.include("/~/system/libraries/Xform.js");
|
||||||
|
var DEBUG = false;
|
||||||
|
var MAX_X_SIZE = 3.8;
|
||||||
|
var EPSILON = 0.01;
|
||||||
|
var isVisible = false;
|
||||||
|
var VOLUME = 0.4;
|
||||||
|
var tune = SoundCache.getSound("http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/crystals_and_voices.wav");
|
||||||
|
var sample = null;
|
||||||
|
var MAX_LEFT_MARGIN = 1.9;
|
||||||
|
var INNER_CIRCLE_WIDTH = 4.7;
|
||||||
|
var DEFAULT_Z_OFFSET = 5.45;
|
||||||
|
var previousCameraMode = Camera.mode;
|
||||||
|
|
||||||
|
var renderViewTask = Render.getConfig("RenderMainView");
|
||||||
|
var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||||
|
var request = Script.require('request').request;
|
||||||
|
var BUTTON_PROPERTIES = {
|
||||||
|
text: "Interstitial"
|
||||||
|
};
|
||||||
|
|
||||||
|
var tablet = null;
|
||||||
|
var button = null;
|
||||||
|
|
||||||
|
// Tips have a character limit of 69
|
||||||
|
var userTips = [
|
||||||
|
"Tip: Visit TheSpot to explore featured domains!",
|
||||||
|
"Tip: Visit our docs online to learn more about scripting!",
|
||||||
|
"Tip: Don't want others invading your personal space? Turn on the Bubble!",
|
||||||
|
"Tip: Want to make a friend? Shake hands with them in VR!",
|
||||||
|
"Tip: Enjoy live music? Visit Rust to dance your heart out!",
|
||||||
|
"Tip: Have you visited BodyMart to check out the new avatars recently?",
|
||||||
|
"Tip: Use the Create app to import models and create custom entities.",
|
||||||
|
"Tip: We're open source! Feel free to contribute to our code on GitHub!",
|
||||||
|
"Tip: What emotes have you used in the Emote app?",
|
||||||
|
"Tip: Take and share your snapshots with the everyone using the Snap app.",
|
||||||
|
"Tip: Did you know you can show websites in-world by creating a web entity?",
|
||||||
|
"Tip: Find out more information about domains by visiting our website!",
|
||||||
|
"Tip: Did you know you can get cool new apps from the Marketplace?",
|
||||||
|
"Tip: Print your snapshots from the Snap app to share with others!",
|
||||||
|
"Tip: Log in to make friends, visit new domains, and save avatars!"
|
||||||
|
];
|
||||||
|
|
||||||
|
var DEFAULT_DIMENSIONS = { x: 20, y: 20, z: 20 };
|
||||||
|
|
||||||
|
var loadingSphereID = Overlays.addOverlay("model", {
|
||||||
|
name: "Loading-Sphere",
|
||||||
|
position: Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0.0, y: -1.0, z: 0.0}), Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.95, z: 0})),
|
||||||
|
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||||
|
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/black-sphere.fbx",
|
||||||
|
dimensions: DEFAULT_DIMENSIONS,
|
||||||
|
alpha: 1,
|
||||||
|
visible: isVisible,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
parentID: MyAvatar.SELF_ID
|
||||||
|
});
|
||||||
|
|
||||||
|
var anchorOverlay = Overlays.addOverlay("cube", {
|
||||||
|
dimensions: {x: 0.2, y: 0.2, z: 0.2},
|
||||||
|
visible: false,
|
||||||
|
grabbable: false,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
localPosition: {x: 0.0, y: getAnchorLocalYOffset(), z: DEFAULT_Z_OFFSET },
|
||||||
|
orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation),
|
||||||
|
solid: true,
|
||||||
|
drawInFront: true,
|
||||||
|
parentID: loadingSphereID
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var domainName = "";
|
||||||
|
var domainNameTextID = Overlays.addOverlay("text3d", {
|
||||||
|
name: "Loading-Destination-Card-Text",
|
||||||
|
localPosition: { x: 0.0, y: 0.8, z: 0.0 },
|
||||||
|
text: domainName,
|
||||||
|
textAlpha: 1,
|
||||||
|
backgroundAlpha: 0,
|
||||||
|
lineHeight: 0.42,
|
||||||
|
visible: isVisible,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var domainText = "";
|
||||||
|
var domainDescription = Overlays.addOverlay("text3d", {
|
||||||
|
name: "Loading-Hostname",
|
||||||
|
localPosition: { x: 0.0, y: 0.32, z: 0.0 },
|
||||||
|
text: domainText,
|
||||||
|
textAlpha: 1,
|
||||||
|
backgroundAlpha: 0,
|
||||||
|
lineHeight: 0.13,
|
||||||
|
visible: isVisible,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var toolTip = "";
|
||||||
|
|
||||||
|
var domainToolTip = Overlays.addOverlay("text3d", {
|
||||||
|
name: "Loading-Tooltip",
|
||||||
|
localPosition: { x: 0.0 , y: -1.6, z: 0.0 },
|
||||||
|
text: toolTip,
|
||||||
|
textAlpha: 1,
|
||||||
|
backgroundAlpha: 0,
|
||||||
|
lineHeight: 0.13,
|
||||||
|
visible: isVisible,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadingToTheSpotID = Overlays.addOverlay("image3d", {
|
||||||
|
name: "Loading-Destination-Card-Text",
|
||||||
|
localPosition: { x: 0.0 , y: -1.8, z: 0.0 },
|
||||||
|
url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/goTo_button.png",
|
||||||
|
alpha: 1,
|
||||||
|
dimensions: { x: 1.2, y: 0.6},
|
||||||
|
visible: isVisible,
|
||||||
|
emissive: true,
|
||||||
|
ignoreRayIntersection: false,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadingBarPlacard = Overlays.addOverlay("image3d", {
|
||||||
|
name: "Loading-Bar-Placard",
|
||||||
|
localPosition: { x: 0.0, y: -0.99, z: 0.3 },
|
||||||
|
url: Script.resourcesPath() + "images/loadingBar_placard.png",
|
||||||
|
alpha: 1,
|
||||||
|
dimensions: { x: 4, y: 2.8},
|
||||||
|
visible: isVisible,
|
||||||
|
emissive: true,
|
||||||
|
ignoreRayIntersection: false,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadingBarProgress = Overlays.addOverlay("image3d", {
|
||||||
|
name: "Loading-Bar-Progress",
|
||||||
|
localPosition: { x: 0.0, y: -0.90, z: 0.0 },
|
||||||
|
url: Script.resourcesPath() + "images/loadingBar_progress.png",
|
||||||
|
alpha: 1,
|
||||||
|
dimensions: {x: 3.8, y: 2.8},
|
||||||
|
visible: isVisible,
|
||||||
|
emissive: true,
|
||||||
|
ignoreRayIntersection: false,
|
||||||
|
drawInFront: true,
|
||||||
|
grabbable: false,
|
||||||
|
localOrientation: Quat.fromVec3Degrees({ x: 0.0, y: 180.0, z: 0.0 }),
|
||||||
|
parentID: anchorOverlay
|
||||||
|
});
|
||||||
|
|
||||||
|
var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update
|
||||||
|
var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ;
|
||||||
|
var lastInterval = Date.now();
|
||||||
|
var currentDomain = "no domain";
|
||||||
|
var timer = null;
|
||||||
|
var target = 0;
|
||||||
|
|
||||||
|
var connectionToDomainFailed = false;
|
||||||
|
|
||||||
|
|
||||||
|
function getAnchorLocalYOffset() {
|
||||||
|
var loadingSpherePosition = Overlays.getProperty(loadingSphereID, "position");
|
||||||
|
var loadingSphereOrientation = Overlays.getProperty(loadingSphereID, "rotation");
|
||||||
|
var overlayXform = new Xform(loadingSphereOrientation, loadingSpherePosition);
|
||||||
|
var worldToOverlayXform = overlayXform.inv();
|
||||||
|
var headPosition = MyAvatar.getHeadPosition();
|
||||||
|
var headPositionInOverlaySpace = worldToOverlayXform.xformPoint(headPosition);
|
||||||
|
return headPositionInOverlaySpace.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLeftMargin(overlayID, text) {
|
||||||
|
var textSize = Overlays.textSize(overlayID, text);
|
||||||
|
var sizeDifference = ((INNER_CIRCLE_WIDTH - textSize.width) / 2);
|
||||||
|
var leftMargin = -(MAX_LEFT_MARGIN - sizeDifference);
|
||||||
|
return leftMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function lerp(a, b, t) {
|
||||||
|
return ((1 - t) * a + t * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetValues() {
|
||||||
|
var properties = {
|
||||||
|
localPosition: { x: 1.85, y: -0.935, z: 0.0 },
|
||||||
|
dimensions: {
|
||||||
|
x: 0.1,
|
||||||
|
y: 2.8
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Overlays.editOverlay(loadingBarProgress, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
function startInterstitialPage() {
|
||||||
|
if (timer === null) {
|
||||||
|
updateOverlays(false);
|
||||||
|
startAudio();
|
||||||
|
target = 0;
|
||||||
|
currentProgress = 0.1;
|
||||||
|
connectionToDomainFailed = false;
|
||||||
|
previousCameraMode = Camera.mode;
|
||||||
|
Camera.mode = "first person";
|
||||||
|
timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startAudio() {
|
||||||
|
sample = Audio.playSound(tune, {
|
||||||
|
localOnly: true,
|
||||||
|
position: MyAvatar.getHeadPosition(),
|
||||||
|
volume: VOLUME
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function endAudio() {
|
||||||
|
sample.stop();
|
||||||
|
sample = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function domainChanged(domain) {
|
||||||
|
print("domain changed: " + domain);
|
||||||
|
if (domain !== currentDomain) {
|
||||||
|
MyAvatar.restoreAnimation();
|
||||||
|
var name = location.placename;
|
||||||
|
domainName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||||
|
var doRequest = true;
|
||||||
|
if (name.length === 0 && location.href === "file:///~/serverless/tutorial.json") {
|
||||||
|
domainName = "Serveless Domain (Tutorial)";
|
||||||
|
doRequest = false;
|
||||||
|
}
|
||||||
|
var domainNameLeftMargin = getLeftMargin(domainNameTextID, domainName);
|
||||||
|
var textProperties = {
|
||||||
|
text: domainName,
|
||||||
|
leftMargin: domainNameLeftMargin
|
||||||
|
};
|
||||||
|
|
||||||
|
if (doRequest) {
|
||||||
|
var url = Account.metaverseServerURL + '/api/v1/places/' + domain;
|
||||||
|
request({
|
||||||
|
uri: url
|
||||||
|
}, function(error, data) {
|
||||||
|
if (data.status === "success") {
|
||||||
|
var domainInfo = data.data;
|
||||||
|
var domainDescriptionText = domainInfo.place.description;
|
||||||
|
print("domainText: " + domainDescriptionText);
|
||||||
|
var leftMargin = getLeftMargin(domainDescription, domainDescriptionText);
|
||||||
|
var domainDescriptionProperties = {
|
||||||
|
text: domainDescriptionText,
|
||||||
|
leftMargin: leftMargin
|
||||||
|
};
|
||||||
|
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var domainDescriptionProperties = {
|
||||||
|
text: ""
|
||||||
|
};
|
||||||
|
Overlays.editOverlay(domainDescription, domainDescriptionProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
var randomIndex = Math.floor(Math.random() * userTips.length);
|
||||||
|
var tip = userTips[randomIndex];
|
||||||
|
var tipLeftMargin = getLeftMargin(domainToolTip, tip);
|
||||||
|
var toolTipProperties = {
|
||||||
|
text: tip,
|
||||||
|
leftMargin: tipLeftMargin
|
||||||
|
};
|
||||||
|
|
||||||
|
Overlays.editOverlay(domainNameTextID, textProperties);
|
||||||
|
Overlays.editOverlay(domainToolTip, toolTipProperties);
|
||||||
|
|
||||||
|
|
||||||
|
startInterstitialPage();
|
||||||
|
currentDomain = domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var THE_PLACE = "hifi://TheSpot-dev";
|
||||||
|
function clickedOnOverlay(overlayID, event) {
|
||||||
|
print(overlayID + " other: " + loadingToTheSpotID);
|
||||||
|
if (loadingToTheSpotID === overlayID) {
|
||||||
|
location.handleLookupString(THE_PLACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentProgress = 0.1;
|
||||||
|
|
||||||
|
function updateOverlays(physicsEnabled) {
|
||||||
|
var properties = {
|
||||||
|
visible: !physicsEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
var mainSphereProperties = {
|
||||||
|
visible: !physicsEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
var domainTextProperties = {
|
||||||
|
text: domainText,
|
||||||
|
visible: !physicsEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
var loadingBarProperties = {
|
||||||
|
dimensions: { x: 0.0, y: 2.8 },
|
||||||
|
visible: !physicsEnabled
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!HMD.active) {
|
||||||
|
MyAvatar.headOrientation = Quat.multiply(Quat.cancelOutRollAndPitch(MyAvatar.headOrientation), Quat.fromPitchYawRollDegrees(-3.0, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = physicsEnabled;
|
||||||
|
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = physicsEnabled;
|
||||||
|
renderViewTask.getConfig("LightingModel")["enablePointLight"] = physicsEnabled;
|
||||||
|
Overlays.editOverlay(loadingSphereID, mainSphereProperties);
|
||||||
|
Overlays.editOverlay(loadingToTheSpotID, properties);
|
||||||
|
Overlays.editOverlay(domainNameTextID, properties);
|
||||||
|
Overlays.editOverlay(domainDescription, domainTextProperties);
|
||||||
|
Overlays.editOverlay(domainToolTip, properties);
|
||||||
|
Overlays.editOverlay(loadingBarPlacard, properties);
|
||||||
|
Overlays.editOverlay(loadingBarProgress, loadingBarProperties);
|
||||||
|
|
||||||
|
if (physicsEnabled && !HMD.active) {
|
||||||
|
toolbar.writeProperty("visible", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetValues();
|
||||||
|
|
||||||
|
if (physicsEnabled) {
|
||||||
|
Camera.mode = previousCameraMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function scaleInterstitialPage(sensorToWorldScale) {
|
||||||
|
var yOffset = getAnchorLocalYOffset();
|
||||||
|
var localPosition = {
|
||||||
|
x: 0.0,
|
||||||
|
y: yOffset,
|
||||||
|
z: 5.45
|
||||||
|
};
|
||||||
|
|
||||||
|
Overlays.editOverlay(anchorOverlay, { localPosition: localPosition });
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var physicsEnabled = Window.isPhysicsEnabled();
|
||||||
|
var thisInterval = Date.now();
|
||||||
|
var deltaTime = (thisInterval - lastInterval);
|
||||||
|
lastInterval = thisInterval;
|
||||||
|
|
||||||
|
var domainLoadingProgressPercentage = Window.domainLoadingProgress();
|
||||||
|
|
||||||
|
var progress = MAX_X_SIZE * domainLoadingProgressPercentage;
|
||||||
|
if (progress >= target) {
|
||||||
|
target = progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((physicsEnabled && (currentProgress < MAX_X_SIZE))) {
|
||||||
|
target = MAX_X_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentProgress = lerp(currentProgress, target, 0.2);
|
||||||
|
var properties = {
|
||||||
|
localPosition: { x: (1.85 - (currentProgress / 2) - (-0.029 * (currentProgress / MAX_X_SIZE))), y: -0.935, z: 0.0 },
|
||||||
|
dimensions: {
|
||||||
|
x: currentProgress,
|
||||||
|
y: 2.8
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Overlays.editOverlay(loadingBarProgress, properties);
|
||||||
|
if ((physicsEnabled && (currentProgress >= (MAX_X_SIZE - EPSILON)))) {
|
||||||
|
updateOverlays((physicsEnabled || connectionToDomainFailed));
|
||||||
|
endAudio();
|
||||||
|
timer = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Overlays.mouseReleaseOnOverlay.connect(clickedOnOverlay);
|
||||||
|
location.hostChanged.connect(domainChanged);
|
||||||
|
location.lookupResultsFinished.connect(function() {
|
||||||
|
Script.setTimeout(function() {
|
||||||
|
connectionToDomainFailed = !location.isConnected;
|
||||||
|
}, 1200);
|
||||||
|
});
|
||||||
|
|
||||||
|
MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage);
|
||||||
|
|
||||||
|
var toggle = true;
|
||||||
|
if (DEBUG) {
|
||||||
|
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
button = tablet.addButton(BUTTON_PROPERTIES);
|
||||||
|
|
||||||
|
button.clicked.connect(function() {
|
||||||
|
toggle = !toggle;
|
||||||
|
updateOverlays(toggle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
Overlays.deleteOverlay(loadingSphereID);
|
||||||
|
Overlays.deleteOverlay(loadingToTheSpotID);
|
||||||
|
Overlays.deleteOverlay(domainNameTextID);
|
||||||
|
Overlays.deleteOverlay(domainDescription);
|
||||||
|
Overlays.deleteOverlay(domainToolTip);
|
||||||
|
Overlays.deleteOverlay(loadingBarPlacard);
|
||||||
|
Overlays.deleteOverlay(loadingBarProgress);
|
||||||
|
Overlays.deleteOverlay(anchorOverlay);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
tablet.removeButton(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderViewTask.getConfig("LightingModel")["enableAmbientLight"] = true;
|
||||||
|
renderViewTask.getConfig("LightingModel")["enableDirectionalLight"] = true;
|
||||||
|
renderViewTask.getConfig("LightingModel")["enablePointLight"] = true;
|
||||||
|
if (!HMD.active) {
|
||||||
|
toolbar.writeProperty("visible", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
||||||
|
}());
|
Loading…
Reference in a new issue