mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 13:49:23 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into ambient
This commit is contained in:
commit
2d35f95930
36 changed files with 404 additions and 200 deletions
|
@ -33,6 +33,7 @@
|
||||||
#include <SoundCache.h>
|
#include <SoundCache.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Deck.h>
|
#include <recording/Deck.h>
|
||||||
#include <recording/Recorder.h>
|
#include <recording/Recorder.h>
|
||||||
#include <recording/Frame.h>
|
#include <recording/Frame.h>
|
||||||
|
@ -53,7 +54,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
||||||
|
|
||||||
Agent::Agent(ReceivedMessage& message) :
|
Agent::Agent(ReceivedMessage& message) :
|
||||||
ThreadedAssignment(message),
|
ThreadedAssignment(message),
|
||||||
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
|
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES)
|
||||||
|
{
|
||||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||||
|
|
||||||
ResourceManager::init();
|
ResourceManager::init();
|
||||||
|
@ -64,12 +66,16 @@ Agent::Agent(ReceivedMessage& message) :
|
||||||
DependencyManager::set<SoundCache>();
|
DependencyManager::set<SoundCache>();
|
||||||
DependencyManager::set<AudioScriptingInterface>();
|
DependencyManager::set<AudioScriptingInterface>();
|
||||||
DependencyManager::set<AudioInjectorManager>();
|
DependencyManager::set<AudioInjectorManager>();
|
||||||
|
|
||||||
DependencyManager::set<recording::Deck>();
|
DependencyManager::set<recording::Deck>();
|
||||||
DependencyManager::set<recording::Recorder>();
|
DependencyManager::set<recording::Recorder>();
|
||||||
DependencyManager::set<RecordingScriptingInterface>();
|
DependencyManager::set<recording::ClipCache>();
|
||||||
|
|
||||||
DependencyManager::set<ScriptCache>();
|
DependencyManager::set<ScriptCache>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
|
||||||
|
|
||||||
|
DependencyManager::set<RecordingScriptingInterface>();
|
||||||
|
|
||||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||||
|
|
||||||
packetReceiver.registerListenerForTypes(
|
packetReceiver.registerListenerForTypes(
|
||||||
|
@ -327,6 +333,8 @@ void Agent::executeScript() {
|
||||||
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
||||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||||
|
|
||||||
|
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine.get());
|
||||||
|
|
||||||
// setup an Avatar for the script to use
|
// setup an Avatar for the script to use
|
||||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||||
|
|
||||||
|
@ -470,6 +478,8 @@ void Agent::executeScript() {
|
||||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||||
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
||||||
|
|
||||||
|
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||||
|
|
||||||
setFinished(true);
|
setFinished(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,8 +763,19 @@ void Agent::aboutToFinish() {
|
||||||
|
|
||||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||||
DependencyManager::destroy<AudioInjectorManager>();
|
DependencyManager::destroy<AudioInjectorManager>();
|
||||||
|
|
||||||
|
// destroy all other created dependencies
|
||||||
|
DependencyManager::destroy<ScriptCache>();
|
||||||
DependencyManager::destroy<ScriptEngines>();
|
DependencyManager::destroy<ScriptEngines>();
|
||||||
|
|
||||||
|
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||||
|
DependencyManager::destroy<SoundCache>();
|
||||||
|
DependencyManager::destroy<AudioScriptingInterface>();
|
||||||
|
|
||||||
|
DependencyManager::destroy<recording::Deck>();
|
||||||
|
DependencyManager::destroy<recording::Recorder>();
|
||||||
|
DependencyManager::destroy<recording::ClipCache>();
|
||||||
|
|
||||||
emit stopAvatarAudioTimer();
|
emit stopAvatarAudioTimer();
|
||||||
_avatarAudioTimerThread.quit();
|
_avatarAudioTimerThread.quit();
|
||||||
|
|
||||||
|
|
|
@ -46,9 +46,6 @@ class Agent : public ThreadedAssignment {
|
||||||
public:
|
public:
|
||||||
Agent(ReceivedMessage& message);
|
Agent(ReceivedMessage& message);
|
||||||
|
|
||||||
void setIsAvatar(bool isAvatar);
|
|
||||||
bool isAvatar() const { return _isAvatar; }
|
|
||||||
|
|
||||||
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
||||||
|
|
||||||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||||
|
@ -65,6 +62,9 @@ public:
|
||||||
public slots:
|
public slots:
|
||||||
void run() override;
|
void run() override;
|
||||||
void playAvatarSound(SharedSoundPointer avatarSound);
|
void playAvatarSound(SharedSoundPointer avatarSound);
|
||||||
|
|
||||||
|
void setIsAvatar(bool isAvatar);
|
||||||
|
bool isAvatar() const { return _isAvatar; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void requestScript();
|
void requestScript();
|
||||||
|
|
|
@ -67,15 +67,13 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) {
|
||||||
|
|
||||||
|
|
||||||
int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
|
||||||
int bytesSent = 0;
|
|
||||||
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
|
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
|
||||||
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
|
||||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
|
||||||
bytesSent += individualData.size();
|
auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
|
||||||
identityPacket->write(individualData);
|
identityPackets->write(individualData);
|
||||||
DependencyManager::get<NodeList>()->sendPacket(std::move(identityPacket), *destinationNode);
|
DependencyManager::get<NodeList>()->sendPacketList(std::move(identityPackets), *destinationNode);
|
||||||
_stats.numIdentityPackets++;
|
_stats.numIdentityPackets++;
|
||||||
return bytesSent;
|
return individualData.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
|
||||||
|
@ -265,8 +263,16 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
// make sure we haven't already sent this data from this sender to this receiver
|
// make sure we haven't already sent this data from this sender to this receiver
|
||||||
// or that somehow we haven't sent
|
// or that somehow we haven't sent
|
||||||
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
|
||||||
++numAvatarsHeldBack;
|
// don't ignore this avatar if we haven't sent any update for a long while
|
||||||
shouldIgnore = true;
|
// in an effort to prevent other interfaces from deleting a stale avatar instance
|
||||||
|
uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
||||||
|
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||||
|
const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND;
|
||||||
|
if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() &&
|
||||||
|
lastBroadcastTime + AVATAR_UPDATE_STALE > startIgnoreCalculation) {
|
||||||
|
++numAvatarsHeldBack;
|
||||||
|
shouldIgnore = true;
|
||||||
|
}
|
||||||
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
} else if (lastSeqFromSender - lastSeqToReceiver > 1) {
|
||||||
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening
|
||||||
++numAvatarsWithSkippedFrames;
|
++numAvatarsWithSkippedFrames;
|
||||||
|
@ -325,7 +331,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||||
_stats.overBudgetAvatars++;
|
_stats.overBudgetAvatars++;
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
||||||
} else if (!isInView) {
|
} else if (!isInView) {
|
||||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData;
|
||||||
nodeData->incrementAvatarOutOfView();
|
nodeData->incrementAvatarOutOfView();
|
||||||
} else {
|
} else {
|
||||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
||||||
|
|
BIN
interface/resources/icons/loadingDark.gif
Normal file
BIN
interface/resources/icons/loadingDark.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
|
@ -91,7 +91,7 @@ Item {
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: (selected || isMyCard) && activeTab == "nearbyTab";
|
enabled: (selected && activeTab == "nearbyTab") || isMyCard;
|
||||||
hoverEnabled: enabled
|
hoverEnabled: enabled
|
||||||
onClicked: {
|
onClicked: {
|
||||||
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
|
userInfoViewer.url = defaultBaseUrl + "/users/" + userName;
|
||||||
|
|
|
@ -1401,6 +1401,13 @@ Rectangle {
|
||||||
var selectedIDs = getSelectedConnectionsUserNames();
|
var selectedIDs = getSelectedConnectionsUserNames();
|
||||||
connectionsUserModelData.sort(function (a, b) {
|
connectionsUserModelData.sort(function (a, b) {
|
||||||
var aValue = a[sortProperty].toString().toLowerCase(), bValue = b[sortProperty].toString().toLowerCase();
|
var aValue = a[sortProperty].toString().toLowerCase(), bValue = b[sortProperty].toString().toLowerCase();
|
||||||
|
if (!aValue && !bValue) {
|
||||||
|
return 0;
|
||||||
|
} else if (!aValue) {
|
||||||
|
return after;
|
||||||
|
} else if (!bValue) {
|
||||||
|
return before;
|
||||||
|
}
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case (aValue < bValue): return before;
|
case (aValue < bValue): return before;
|
||||||
case (aValue > bValue): return after;
|
case (aValue > bValue): return after;
|
||||||
|
|
|
@ -118,6 +118,7 @@
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
#include <UserActivityLogger.h>
|
#include <UserActivityLogger.h>
|
||||||
#include <UsersScriptingInterface.h>
|
#include <UsersScriptingInterface.h>
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Deck.h>
|
#include <recording/Deck.h>
|
||||||
#include <recording/Recorder.h>
|
#include <recording/Recorder.h>
|
||||||
#include <shared/StringHelpers.h>
|
#include <shared/StringHelpers.h>
|
||||||
|
@ -467,6 +468,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<StatTracker>();
|
DependencyManager::set<StatTracker>();
|
||||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
||||||
DependencyManager::set<Preferences>();
|
DependencyManager::set<Preferences>();
|
||||||
|
DependencyManager::set<recording::ClipCache>();
|
||||||
DependencyManager::set<recording::Deck>();
|
DependencyManager::set<recording::Deck>();
|
||||||
DependencyManager::set<recording::Recorder>();
|
DependencyManager::set<recording::Recorder>();
|
||||||
DependencyManager::set<AddressManager>();
|
DependencyManager::set<AddressManager>();
|
||||||
|
@ -5439,6 +5441,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
// AvatarManager has some custom types
|
// AvatarManager has some custom types
|
||||||
AvatarManager::registerMetaTypes(scriptEngine);
|
AvatarManager::registerMetaTypes(scriptEngine);
|
||||||
|
|
||||||
|
// give the script engine to the RecordingScriptingInterface for its callbacks
|
||||||
|
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
|
||||||
|
|
||||||
if (property(hifi::properties::TEST).isValid()) {
|
if (property(hifi::properties::TEST).isValid()) {
|
||||||
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
||||||
}
|
}
|
||||||
|
@ -6417,7 +6422,7 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa
|
||||||
// If we're not doing an animated snapshot as well...
|
// If we're not doing an animated snapshot as well...
|
||||||
if (!includeAnimated || !(SnapshotAnimated::alsoTakeAnimatedSnapshot.get())) {
|
if (!includeAnimated || !(SnapshotAnimated::alsoTakeAnimatedSnapshot.get())) {
|
||||||
// Tell the dependency manager that the capture of the still snapshot has taken place.
|
// Tell the dependency manager that the capture of the still snapshot has taken place.
|
||||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotTaken(path, "", notify);
|
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(path, notify);
|
||||||
} else {
|
} else {
|
||||||
// Get an animated GIF snapshot and save it
|
// Get an animated GIF snapshot and save it
|
||||||
SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get<WindowScriptingInterface>());
|
SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get<WindowScriptingInterface>());
|
||||||
|
|
|
@ -77,7 +77,7 @@ void Head::simulate(float deltaTime, bool isMine) {
|
||||||
float audioLoudness = 0.0f;
|
float audioLoudness = 0.0f;
|
||||||
|
|
||||||
if (_owningAvatar) {
|
if (_owningAvatar) {
|
||||||
_owningAvatar->getAudioLoudness();
|
audioLoudness = _owningAvatar->getAudioLoudness();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update audio trailing average for rendering facial animations
|
// Update audio trailing average for rendering facial animations
|
||||||
|
|
|
@ -240,8 +240,8 @@ void SkeletonModel::updateAttitude() {
|
||||||
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
|
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
|
||||||
// but just before head has been simulated.
|
// but just before head has been simulated.
|
||||||
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
|
updateAttitude();
|
||||||
if (fullUpdate) {
|
if (fullUpdate) {
|
||||||
updateAttitude();
|
|
||||||
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
||||||
|
|
||||||
Model::simulate(deltaTime, fullUpdate);
|
Model::simulate(deltaTime, fullUpdate);
|
||||||
|
|
|
@ -71,9 +71,10 @@ signals:
|
||||||
void domainChanged(const QString& domainHostname);
|
void domainChanged(const QString& domainHostname);
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
void domainConnectionRefused(const QString& reasonMessage, int reasonCode, const QString& extraInfo);
|
void domainConnectionRefused(const QString& reasonMessage, int reasonCode, const QString& extraInfo);
|
||||||
void snapshotTaken(const QString& pathStillSnapshot, const QString& pathAnimatedSnapshot, bool notify);
|
void stillSnapshotTaken(const QString& pathStillSnapshot, bool notify);
|
||||||
void snapshotShared(const QString& error);
|
void snapshotShared(const QString& error);
|
||||||
void processingGif();
|
void processingGifStarted(const QString& pathStillSnapshot);
|
||||||
|
void processingGifCompleted(const QString& pathAnimatedSnapshot);
|
||||||
|
|
||||||
void connectionAdded(const QString& connectionName);
|
void connectionAdded(const QString& connectionName);
|
||||||
void connectionError(const QString& errorString);
|
void connectionError(const QString& errorString);
|
||||||
|
|
|
@ -86,7 +86,8 @@ void SnapshotAnimated::captureFrames() {
|
||||||
SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
SnapshotAnimated::snapshotAnimatedTimerRunning = false;
|
||||||
|
|
||||||
// Notify the user that we're processing the snapshot
|
// Notify the user that we're processing the snapshot
|
||||||
emit SnapshotAnimated::snapshotAnimatedDM->processingGif();
|
// This also pops up the "Share" dialog. The unprocessed GIF will be visualized as a loading icon until processingGifCompleted() is called.
|
||||||
|
emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath);
|
||||||
|
|
||||||
// Kick off the thread that'll pack the frames into the GIF
|
// Kick off the thread that'll pack the frames into the GIF
|
||||||
QtConcurrent::run(processFrames);
|
QtConcurrent::run(processFrames);
|
||||||
|
@ -132,7 +133,7 @@ void SnapshotAnimated::processFrames() {
|
||||||
// Reset the current frame timestamp
|
// Reset the current frame timestamp
|
||||||
SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
SnapshotAnimated::snapshotAnimatedTimestamp = 0;
|
||||||
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0;
|
||||||
|
|
||||||
// Let the window scripting interface know that the snapshots have been taken.
|
// Update the "Share" dialog with the processed GIF.
|
||||||
emit SnapshotAnimated::snapshotAnimatedDM->snapshotTaken(SnapshotAnimated::snapshotStillPath, SnapshotAnimated::snapshotAnimatedPath, false);
|
emit SnapshotAnimated::snapshotAnimatedDM->processingGifCompleted(SnapshotAnimated::snapshotAnimatedPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,8 @@ const char LEFT_HAND_POINTING_FLAG = 1;
|
||||||
const char RIGHT_HAND_POINTING_FLAG = 2;
|
const char RIGHT_HAND_POINTING_FLAG = 2;
|
||||||
const char IS_FINGER_POINTING_FLAG = 4;
|
const char IS_FINGER_POINTING_FLAG = 4;
|
||||||
|
|
||||||
|
const qint64 AVATAR_UPDATE_TIMEOUT = 5 * USECS_PER_SECOND;
|
||||||
|
|
||||||
// AvatarData state flags - we store the details about the packet encoding in the first byte,
|
// AvatarData state flags - we store the details about the packet encoding in the first byte,
|
||||||
// before the "header" structure
|
// before the "header" structure
|
||||||
const char AVATARDATA_FLAGS_MINIMUM = 0;
|
const char AVATARDATA_FLAGS_MINIMUM = 0;
|
||||||
|
@ -599,10 +601,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool shouldDie() const {
|
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_UPDATE_TIMEOUT; }
|
||||||
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
|
|
||||||
return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const float OUT_OF_VIEW_PENALTY;
|
static const float OUT_OF_VIEW_PENALTY;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
|
||||||
QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
||||||
if (!networkAccessManagers.hasLocalData()) {
|
if (!networkAccessManagers.hasLocalData()) {
|
||||||
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *networkAccessManagers.localData();
|
return *networkAccessManagers.localData();
|
||||||
|
|
|
@ -5,8 +5,12 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "ClipCache.h"
|
#include "ClipCache.h"
|
||||||
#include "impl/PointerClip.h"
|
#include "impl/PointerClip.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
NetworkClipLoader::NetworkClipLoader(const QUrl& url) :
|
NetworkClipLoader::NetworkClipLoader(const QUrl& url) :
|
||||||
|
@ -21,18 +25,28 @@ void NetworkClip::init(const QByteArray& clipData) {
|
||||||
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
||||||
_clip->init(data);
|
_clip->init(data);
|
||||||
finishedLoading(true);
|
finishedLoading(true);
|
||||||
|
emit clipLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
ClipCache& ClipCache::instance() {
|
ClipCache::ClipCache(QObject* parent) :
|
||||||
static ClipCache _instance;
|
ResourceCache(parent)
|
||||||
return _instance;
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
||||||
return ResourceCache::getResource(url, QUrl(), nullptr).staticCast<NetworkClipLoader>();
|
if (QThread::currentThread() != thread()) {
|
||||||
|
NetworkClipLoaderPointer result;
|
||||||
|
QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getResource(url).staticCast<NetworkClipLoader>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
||||||
|
qCDebug(recordingLog) << "Loading recording at" << url;
|
||||||
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
|
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,26 +30,34 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetworkClipLoader : public Resource {
|
class NetworkClipLoader : public Resource {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NetworkClipLoader(const QUrl& url);
|
NetworkClipLoader(const QUrl& url);
|
||||||
virtual void downloadFinished(const QByteArray& data) override;
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
ClipPointer getClip() { return _clip; }
|
ClipPointer getClip() { return _clip; }
|
||||||
bool completed() { return _failedToLoad || isLoaded(); }
|
bool completed() { return _failedToLoad || isLoaded(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void clipLoaded();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const NetworkClip::Pointer _clip;
|
const NetworkClip::Pointer _clip;
|
||||||
};
|
};
|
||||||
|
|
||||||
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
|
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
|
||||||
|
|
||||||
class ClipCache : public ResourceCache {
|
class ClipCache : public ResourceCache, public Dependency {
|
||||||
public:
|
Q_OBJECT
|
||||||
static ClipCache& instance();
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
|
public slots:
|
||||||
NetworkClipLoaderPointer getClipLoader(const QUrl& url);
|
NetworkClipLoaderPointer getClipLoader(const QUrl& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClipCache(QObject* parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,32 +52,49 @@ float RecordingScriptingInterface::playerLength() const {
|
||||||
return _player->length();
|
return _player->length();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RecordingScriptingInterface::loadRecording(const QString& url) {
|
void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) {
|
||||||
using namespace recording;
|
auto clipLoader = DependencyManager::get<recording::ClipCache>()->getClipLoader(url);
|
||||||
|
|
||||||
auto loader = ClipCache::instance().getClipLoader(url);
|
// hold a strong pointer to the loading clip so that it has a chance to load
|
||||||
if (!loader) {
|
_clipLoaders.insert(clipLoader);
|
||||||
qWarning() << "Clip failed to load from " << url;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loader->isLoaded()) {
|
auto weakClipLoader = clipLoader.toWeakRef();
|
||||||
QEventLoop loop;
|
|
||||||
QObject::connect(loader.data(), &Resource::loaded, &loop, &QEventLoop::quit);
|
|
||||||
QObject::connect(loader.data(), &Resource::failed, &loop, &QEventLoop::quit);
|
|
||||||
loop.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loader->isLoaded()) {
|
// when clip loaded, call the callback with the URL and success boolean
|
||||||
qWarning() << "Clip failed to load from " << url;
|
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this,
|
||||||
return false;
|
[this, weakClipLoader, url, callback]() mutable {
|
||||||
}
|
|
||||||
|
|
||||||
_player->queueClip(loader->getClip());
|
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||||
return true;
|
qCDebug(scriptengine) << "Loaded recording from" << url;
|
||||||
|
|
||||||
|
_player->queueClip(clipLoader->getClip());
|
||||||
|
|
||||||
|
if (callback.isFunction()) {
|
||||||
|
QScriptValueList args { true, url };
|
||||||
|
callback.call(_scriptEngine->globalObject(), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop our strong pointer to this clip so it is cleaned up
|
||||||
|
_clipLoaders.remove(clipLoader);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// when clip load fails, call the callback with the URL and failure boolean
|
||||||
|
connect(clipLoader.data(), &recording::NetworkClipLoader::failed, this, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable {
|
||||||
|
qCDebug(scriptengine) << "Failed to load recording from" << url;
|
||||||
|
|
||||||
|
if (callback.isFunction()) {
|
||||||
|
QScriptValueList args { false, url };
|
||||||
|
callback.call(_scriptEngine->currentContext()->thisObject(), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||||
|
// drop out strong pointer to this clip so it is cleaned up
|
||||||
|
_clipLoaders.remove(clipLoader);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RecordingScriptingInterface::startPlaying() {
|
void RecordingScriptingInterface::startPlaying() {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);
|
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
#include <recording/ClipCache.h>
|
||||||
#include <recording/Forward.h>
|
#include <recording/Forward.h>
|
||||||
#include <recording/Frame.h>
|
#include <recording/Frame.h>
|
||||||
|
|
||||||
|
class QScriptEngine;
|
||||||
class QScriptValue;
|
class QScriptValue;
|
||||||
|
|
||||||
class RecordingScriptingInterface : public QObject, public Dependency {
|
class RecordingScriptingInterface : public QObject, public Dependency {
|
||||||
|
@ -26,8 +28,10 @@ class RecordingScriptingInterface : public QObject, public Dependency {
|
||||||
public:
|
public:
|
||||||
RecordingScriptingInterface();
|
RecordingScriptingInterface();
|
||||||
|
|
||||||
|
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool loadRecording(const QString& url);
|
void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
|
||||||
|
|
||||||
void startPlaying();
|
void startPlaying();
|
||||||
void pausePlayer();
|
void pausePlayer();
|
||||||
|
@ -79,6 +83,9 @@ protected:
|
||||||
Flag _useAttachments { false };
|
Flag _useAttachments { false };
|
||||||
Flag _useSkeletonModel { false };
|
Flag _useSkeletonModel { false };
|
||||||
recording::ClipPointer _lastClip;
|
recording::ClipPointer _lastClip;
|
||||||
|
|
||||||
|
QScriptEngine* _scriptEngine;
|
||||||
|
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RecordingScriptingInterface_h
|
#endif // hifi_RecordingScriptingInterface_h
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#define SINGLETON_DEPENDENCY \
|
#define SINGLETON_DEPENDENCY \
|
||||||
friend class DependencyManager;
|
friend class ::DependencyManager;
|
||||||
|
|
||||||
class Dependency {
|
class Dependency {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -769,7 +769,7 @@ bool similarStrings(const QString& stringA, const QString& stringB) {
|
||||||
|
|
||||||
void disableQtBearerPoll() {
|
void disableQtBearerPoll() {
|
||||||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
||||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
|
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit();
|
||||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
|
|
||||||
void addSample(T sample) {
|
void addSample(T sample) {
|
||||||
if (numSamples > 0) {
|
if (numSamples > 0) {
|
||||||
average = ((float)sample * WEIGHTING) + ((float)average * ONE_MINUS_WEIGHTING);
|
average = (sample * WEIGHTING) + (average * ONE_MINUS_WEIGHTING);
|
||||||
} else {
|
} else {
|
||||||
average = sample;
|
average = sample;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
|
Q_DECLARE_LOGGING_CATEGORY(inputplugins)
|
||||||
Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
|
Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins")
|
||||||
|
|
||||||
|
|
||||||
const char* KinectPlugin::NAME = "Kinect";
|
const char* KinectPlugin::NAME = "Kinect";
|
||||||
const char* KinectPlugin::KINECT_ID_STRING = "Kinect";
|
const char* KinectPlugin::KINECT_ID_STRING = "Kinect";
|
||||||
|
|
||||||
|
@ -493,11 +492,23 @@ void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) {
|
||||||
//_joints[j].orientation = jointOrientation;
|
//_joints[j].orientation = jointOrientation;
|
||||||
if (joints[j].JointType == JointType_HandRight) {
|
if (joints[j].JointType == JointType_HandRight) {
|
||||||
static const quat kinectToHandRight = glm::angleAxis(-PI / 2.0f, Vectors::UNIT_Y);
|
static const quat kinectToHandRight = glm::angleAxis(-PI / 2.0f, Vectors::UNIT_Y);
|
||||||
_joints[j].orientation = jointOrientation * kinectToHandRight;
|
// add moving average of orientation quaternion
|
||||||
|
glm::quat jointSample = jointOrientation * kinectToHandRight;
|
||||||
|
if (glm::dot(jointSample, _RightHandOrientationAverage.getAverage()) < 0) {
|
||||||
|
jointSample = -jointSample;
|
||||||
|
}
|
||||||
|
_RightHandOrientationAverage.addSample(jointSample);
|
||||||
|
_joints[j].orientation = glm::normalize(_RightHandOrientationAverage.getAverage());
|
||||||
} else if (joints[j].JointType == JointType_HandLeft) {
|
} else if (joints[j].JointType == JointType_HandLeft) {
|
||||||
// To transform from Kinect to our LEFT Hand.... Postive 90 deg around Y
|
// To transform from Kinect to our LEFT Hand.... Postive 90 deg around Y
|
||||||
static const quat kinectToHandLeft = glm::angleAxis(PI / 2.0f, Vectors::UNIT_Y);
|
static const quat kinectToHandLeft = glm::angleAxis(PI / 2.0f, Vectors::UNIT_Y);
|
||||||
_joints[j].orientation = jointOrientation * kinectToHandLeft;
|
// add moving average of orientation quaternion
|
||||||
|
glm::quat jointSample = jointOrientation * kinectToHandLeft;
|
||||||
|
if (glm::dot(jointSample, _LeftHandOrientationAverage.getAverage()) < 0) {
|
||||||
|
jointSample = -jointSample;
|
||||||
|
}
|
||||||
|
_LeftHandOrientationAverage.addSample(jointSample);
|
||||||
|
_joints[j].orientation = glm::normalize(_LeftHandOrientationAverage.getAverage());
|
||||||
} else {
|
} else {
|
||||||
_joints[j].orientation = jointOrientation;
|
_joints[j].orientation = jointOrientation;
|
||||||
}
|
}
|
||||||
|
@ -643,4 +654,4 @@ void KinectPlugin::InputDevice::clearState() {
|
||||||
int poseIndex = KinectJointIndexToPoseIndex((KinectJointIndex)i);
|
int poseIndex = KinectJointIndexToPoseIndex((KinectJointIndex)i);
|
||||||
_poseStateMap[poseIndex] = controller::Pose();
|
_poseStateMap[poseIndex] = controller::Pose();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
// Kinect Header files
|
// Kinect Header files
|
||||||
#include <Kinect.h>
|
#include <Kinect.h>
|
||||||
|
#include <SimpleMovingAverage.h>
|
||||||
|
|
||||||
// Safe release for interfaces
|
// Safe release for interfaces
|
||||||
template<class Interface> inline void SafeRelease(Interface *& pInterfaceToRelease) {
|
template<class Interface> inline void SafeRelease(Interface *& pInterfaceToRelease) {
|
||||||
|
@ -58,6 +59,11 @@ public:
|
||||||
virtual void saveSettings() const override;
|
virtual void saveSettings() const override;
|
||||||
virtual void loadSettings() override;
|
virtual void loadSettings() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// add variables for moving average
|
||||||
|
ThreadSafeMovingAverage<glm::quat, 2> _LeftHandOrientationAverage;
|
||||||
|
ThreadSafeMovingAverage<glm::quat, 2> _RightHandOrientationAverage;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct KinectJoint {
|
struct KinectJoint {
|
||||||
|
|
|
@ -138,7 +138,13 @@ Agent.isAvatar = true;
|
||||||
Agent.isListeningToAudioStream = true;
|
Agent.isListeningToAudioStream = true;
|
||||||
Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored
|
Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored
|
||||||
|
|
||||||
Recording.loadRecording(RECORDING_URL);
|
Recording.loadRecording(RECORDING_URL, function(success) {
|
||||||
|
if (success) {
|
||||||
|
Script.update.connect(update);
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + RECORDING_URL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
count = 300; // This is necessary to wait for the audio mixer to connect
|
count = 300; // This is necessary to wait for the audio mixer to connect
|
||||||
function update(event) {
|
function update(event) {
|
||||||
|
@ -174,10 +180,8 @@ function update(event) {
|
||||||
+" FT: " + Avatar.getDataRate("faceTrackerOutbound").toFixed(2) + "\n"
|
+" FT: " + Avatar.getDataRate("faceTrackerOutbound").toFixed(2) + "\n"
|
||||||
+" JD: " + Avatar.getDataRate("jointDataOutbound").toFixed(2));
|
+" JD: " + Avatar.getDataRate("jointDataOutbound").toFixed(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Recording.isPlaying()) {
|
if (!Recording.isPlaying()) {
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
|
||||||
|
|
|
@ -20,7 +20,13 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||||
Avatar.scale = 1.0;
|
Avatar.scale = 1.0;
|
||||||
Agent.isAvatar = true;
|
Agent.isAvatar = true;
|
||||||
|
|
||||||
Recording.loadRecording(recordingFile);
|
Recording.loadRecording(recordingFile, function(success) {
|
||||||
|
if (success) {
|
||||||
|
Script.update.connect(update);
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + recordingFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
count = 300; // This is necessary to wait for the audio mixer to connect
|
count = 300; // This is necessary to wait for the audio mixer to connect
|
||||||
function update(event) {
|
function update(event) {
|
||||||
|
@ -39,10 +45,8 @@ function update(event) {
|
||||||
Vec3.print("Playing from ", Avatar.position);
|
Vec3.print("Playing from ", Avatar.position);
|
||||||
count--;
|
count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Recording.isPlaying()) {
|
if (!Recording.isPlaying()) {
|
||||||
Script.update.disconnect(update);
|
Script.update.disconnect(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Script.update.connect(update);
|
|
||||||
|
|
|
@ -42,10 +42,15 @@ var playRecording = function() {
|
||||||
Recording.setPlayerLoop(false);
|
Recording.setPlayerLoop(false);
|
||||||
Recording.setPlayerTime(STARTING_TIME);
|
Recording.setPlayerTime(STARTING_TIME);
|
||||||
Recording.setPlayerAudioOffset(AUDIO_OFFSET);
|
Recording.setPlayerAudioOffset(AUDIO_OFFSET);
|
||||||
Recording.loadRecording(CLIP_URL);
|
Recording.loadRecording(CLIP_URL, function(success) {
|
||||||
Recording.startPlaying();
|
if (success) {
|
||||||
isPlaying = true;
|
Recording.startPlaying();
|
||||||
isPlayable = false; // Set this true again after the cooldown period
|
isPlaying = true;
|
||||||
|
isPlayable = false; // Set this true again after the cooldown period
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + CLIP_URL);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.update.connect(function(deltaTime) {
|
Script.update.connect(function(deltaTime) {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
var origin = {x: 512, y: 512, z: 512};
|
var origin = {x: 512, y: 512, z: 512};
|
||||||
var millisecondsToWaitBeforeStarting = 2 * 1000; // To give the various servers a chance to start.
|
var millisecondsToWaitBeforeStarting = 2 * 1000; // To give the various servers a chance to start.
|
||||||
var millisecondsToWaitBeforeEnding = 30 * 1000;
|
var millisecondsToWaitBeforeEnding = 30 * 1000;
|
||||||
|
|
||||||
Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/dd03b8e3-52fb-4ab3-9ac9-3b17e00cd85d/98baa90b3b66803c5d7bd4537fca6993.fst"; //lovejoy
|
Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/dd03b8e3-52fb-4ab3-9ac9-3b17e00cd85d/98baa90b3b66803c5d7bd4537fca6993.fst"; //lovejoy
|
||||||
Avatar.displayName = "AC Avatar";
|
Avatar.displayName = "AC Avatar";
|
||||||
|
@ -10,9 +10,15 @@ Agent.isAvatar = true;
|
||||||
|
|
||||||
Script.setTimeout(function () {
|
Script.setTimeout(function () {
|
||||||
Avatar.position = origin;
|
Avatar.position = origin;
|
||||||
Recording.loadRecording("d:/hifi.rec");
|
Recording.loadRecording("d:/hifi.rec", function(success) {
|
||||||
Recording.setPlayerLoop(true);
|
if (success) {
|
||||||
Recording.startPlaying();
|
Recording.setPlayerLoop(true);
|
||||||
|
Recording.startPlaying();
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}, millisecondsToWaitBeforeStarting);
|
}, millisecondsToWaitBeforeStarting);
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,4 +27,4 @@ Script.setTimeout(function () {
|
||||||
Agent.isAvatar = false;
|
Agent.isAvatar = false;
|
||||||
Recording.stopPlaying();
|
Recording.stopPlaying();
|
||||||
Script.stop();
|
Script.stop();
|
||||||
}, millisecondsToWaitBeforeEnding);
|
}, millisecondsToWaitBeforeEnding);
|
||||||
|
|
|
@ -26,7 +26,7 @@ var PLAY = "Play";
|
||||||
function getAction(channel, message, senderID) {
|
function getAction(channel, message, senderID) {
|
||||||
if(subscribed) {
|
if(subscribed) {
|
||||||
print("I'm the agent and I received this: " + message);
|
print("I'm the agent and I received this: " + message);
|
||||||
|
|
||||||
switch(message) {
|
switch(message) {
|
||||||
case PLAY:
|
case PLAY:
|
||||||
print("Play");
|
print("Play");
|
||||||
|
@ -35,7 +35,7 @@ function getAction(channel, message, senderID) {
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print("Unknown action: " + action);
|
print("Unknown action: " + action);
|
||||||
break;
|
break;
|
||||||
|
@ -49,16 +49,21 @@ function update(deltaTime) {
|
||||||
totalTime += deltaTime;
|
totalTime += deltaTime;
|
||||||
|
|
||||||
if (totalTime > WAIT_FOR_AUDIO_MIXER) {
|
if (totalTime > WAIT_FOR_AUDIO_MIXER) {
|
||||||
if (!subscribed) {
|
if (!subscribed) {
|
||||||
Messages.subscribe(PLAYBACK_CHANNEL);
|
Messages.subscribe(PLAYBACK_CHANNEL);
|
||||||
subscribed = true;
|
subscribed = true;
|
||||||
Recording.loadRecording(clip_url);
|
Recording.loadRecording(clip_url, function(success) {
|
||||||
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
if (success) {
|
||||||
Recording.setPlayerUseDisplayName(useDisplayName);
|
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||||
Recording.setPlayerUseAttachments(useAttachments);
|
Recording.setPlayerUseDisplayName(useDisplayName);
|
||||||
Recording.setPlayerUseHeadModel(false);
|
Recording.setPlayerUseAttachments(useAttachments);
|
||||||
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
Recording.setPlayerUseHeadModel(false);
|
||||||
Agent.isAvatar = true;
|
Recording.setPlayerUseSkeletonModel(useAvatarModel);
|
||||||
|
Agent.isAvatar = true;
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + clip_url);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,4 +75,4 @@ Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
|
|
||||||
var command = null;
|
var command = null;
|
||||||
var clip_url = null;
|
var clip_url = null;
|
||||||
|
|
||||||
var REVIEW_CHANNEL = "reviewChannel";
|
var REVIEW_CHANNEL = "reviewChannel";
|
||||||
var playFromCurrentLocation = true;
|
var playFromCurrentLocation = true;
|
||||||
|
@ -28,16 +28,16 @@ var HIDE = "Hide";
|
||||||
function getAction(channel, message, senderID) {
|
function getAction(channel, message, senderID) {
|
||||||
if(subscribed) {
|
if(subscribed) {
|
||||||
print("I'm the agent and I received this: " + message);
|
print("I'm the agent and I received this: " + message);
|
||||||
|
|
||||||
if (Recording.isPlaying()) {
|
if (Recording.isPlaying()) {
|
||||||
Recording.stopPlaying();
|
Recording.stopPlaying();
|
||||||
}
|
}
|
||||||
|
|
||||||
m = JSON.parse(message);
|
m = JSON.parse(message);
|
||||||
|
|
||||||
command = m.command;
|
command = m.command;
|
||||||
clip_url = m.clip_url;
|
clip_url = m.clip_url;
|
||||||
|
|
||||||
switch(command) {
|
switch(command) {
|
||||||
case PLAY:
|
case PLAY:
|
||||||
print("Play");
|
print("Play");
|
||||||
|
@ -46,21 +46,25 @@ function getAction(channel, message, senderID) {
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SHOW:
|
case SHOW:
|
||||||
print("Show");
|
print("Show");
|
||||||
Recording.loadRecording(clip_url);
|
Recording.loadRecording(clip_url, function(success) {
|
||||||
Agent.isAvatar = true;
|
if (success) {
|
||||||
Recording.setPlayerTime(0.0);
|
Agent.isAvatar = true;
|
||||||
Recording.startPlaying();
|
Recording.setPlayerTime(0.0);
|
||||||
Recording.stopPlaying();
|
Recording.startPlaying();
|
||||||
|
Recording.stopPlaying();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HIDE:
|
case HIDE:
|
||||||
print("Hide");
|
print("Hide");
|
||||||
Agent.isAvatar = false;
|
Agent.isAvatar = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print("Unknown action: " + action);
|
print("Unknown action: " + action);
|
||||||
break;
|
break;
|
||||||
|
@ -74,7 +78,7 @@ function update(deltaTime) {
|
||||||
totalTime += deltaTime;
|
totalTime += deltaTime;
|
||||||
|
|
||||||
if (totalTime > WAIT_FOR_AUDIO_MIXER) {
|
if (totalTime > WAIT_FOR_AUDIO_MIXER) {
|
||||||
if (!subscribed) {
|
if (!subscribed) {
|
||||||
Messages.subscribe(REVIEW_CHANNEL);
|
Messages.subscribe(REVIEW_CHANNEL);
|
||||||
subscribed = true;
|
subscribed = true;
|
||||||
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||||
|
@ -93,4 +97,4 @@ Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Script.update.connect(update);
|
Script.update.connect(update);
|
||||||
|
|
|
@ -55,13 +55,13 @@ function setupToolBar() {
|
||||||
}
|
}
|
||||||
Tool.IMAGE_HEIGHT /= 2;
|
Tool.IMAGE_HEIGHT /= 2;
|
||||||
Tool.IMAGE_WIDTH /= 2;
|
Tool.IMAGE_WIDTH /= 2;
|
||||||
|
|
||||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||||
|
|
||||||
toolBar.onMove = onToolbarMove;
|
toolBar.onMove = onToolbarMove;
|
||||||
|
|
||||||
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
||||||
|
|
||||||
recordIcon = toolBar.addTool({
|
recordIcon = toolBar.addTool({
|
||||||
imageURL: TOOL_ICON_URL + "recording-record.svg",
|
imageURL: TOOL_ICON_URL + "recording-record.svg",
|
||||||
subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||||
|
@ -71,7 +71,7 @@ function setupToolBar() {
|
||||||
alpha: Recording.isPlaying() ? ALPHA_OFF : ALPHA_ON,
|
alpha: Recording.isPlaying() ? ALPHA_OFF : ALPHA_ON,
|
||||||
visible: true
|
visible: true
|
||||||
}, true, !Recording.isRecording());
|
}, true, !Recording.isRecording());
|
||||||
|
|
||||||
var playLoopWidthFactor = 1.65;
|
var playLoopWidthFactor = 1.65;
|
||||||
playIcon = toolBar.addTool({
|
playIcon = toolBar.addTool({
|
||||||
imageURL: TOOL_ICON_URL + "play-pause.svg",
|
imageURL: TOOL_ICON_URL + "play-pause.svg",
|
||||||
|
@ -80,7 +80,7 @@ function setupToolBar() {
|
||||||
alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
||||||
visible: true
|
visible: true
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
playLoopIcon = toolBar.addTool({
|
playLoopIcon = toolBar.addTool({
|
||||||
imageURL: TOOL_ICON_URL + "play-and-loop.svg",
|
imageURL: TOOL_ICON_URL + "play-and-loop.svg",
|
||||||
subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||||
|
@ -89,10 +89,10 @@ function setupToolBar() {
|
||||||
alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
||||||
visible: true
|
visible: true
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
timerOffset = toolBar.width + ToolBar.SPACING;
|
timerOffset = toolBar.width + ToolBar.SPACING;
|
||||||
spacing = toolBar.addSpacing(0);
|
spacing = toolBar.addSpacing(0);
|
||||||
|
|
||||||
saveIcon = toolBar.addTool({
|
saveIcon = toolBar.addTool({
|
||||||
imageURL: TOOL_ICON_URL + "recording-save.svg",
|
imageURL: TOOL_ICON_URL + "recording-save.svg",
|
||||||
width: Tool.IMAGE_WIDTH,
|
width: Tool.IMAGE_WIDTH,
|
||||||
|
@ -100,7 +100,7 @@ function setupToolBar() {
|
||||||
alpha: (Recording.isRecording() || Recording.isPlaying() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
alpha: (Recording.isRecording() || Recording.isPlaying() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON,
|
||||||
visible: true
|
visible: true
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
loadIcon = toolBar.addTool({
|
loadIcon = toolBar.addTool({
|
||||||
imageURL: TOOL_ICON_URL + "recording-upload.svg",
|
imageURL: TOOL_ICON_URL + "recording-upload.svg",
|
||||||
width: Tool.IMAGE_WIDTH,
|
width: Tool.IMAGE_WIDTH,
|
||||||
|
@ -153,10 +153,10 @@ function onToolbarMove(newX, newY, deltaX, deltaY) {
|
||||||
x: newX + timerOffset - ToolBar.SPACING,
|
x: newX + timerOffset - ToolBar.SPACING,
|
||||||
y: newY
|
y: newY
|
||||||
});
|
});
|
||||||
|
|
||||||
slider.x = newX - ToolBar.SPACING;
|
slider.x = newX - ToolBar.SPACING;
|
||||||
slider.y = newY - slider.h - ToolBar.SPACING;
|
slider.y = newY - slider.h - ToolBar.SPACING;
|
||||||
|
|
||||||
Overlays.editOverlay(slider.background, {
|
Overlays.editOverlay(slider.background, {
|
||||||
x: slider.x,
|
x: slider.x,
|
||||||
y: slider.y
|
y: slider.y
|
||||||
|
@ -182,13 +182,13 @@ function updateTimer() {
|
||||||
width: timerWidth
|
width: timerWidth
|
||||||
});
|
});
|
||||||
toolBar.changeSpacing(timerWidth + ToolBar.SPACING, spacing);
|
toolBar.changeSpacing(timerWidth + ToolBar.SPACING, spacing);
|
||||||
|
|
||||||
if (Recording.isRecording()) {
|
if (Recording.isRecording()) {
|
||||||
slider.pos = 1.0;
|
slider.pos = 1.0;
|
||||||
} else if (Recording.playerLength() > 0) {
|
} else if (Recording.playerLength() > 0) {
|
||||||
slider.pos = Recording.playerElapsed() / Recording.playerLength();
|
slider.pos = Recording.playerElapsed() / Recording.playerLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlays.editOverlay(slider.foreground, {
|
Overlays.editOverlay(slider.foreground, {
|
||||||
width: slider.pos * slider.w
|
width: slider.pos * slider.w
|
||||||
});
|
});
|
||||||
|
@ -221,7 +221,7 @@ function moveUI() {
|
||||||
|
|
||||||
function mousePressEvent(event) {
|
function mousePressEvent(event) {
|
||||||
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
|
||||||
if (recordIcon === toolBar.clicked(clickedOverlay, false) && !Recording.isPlaying()) {
|
if (recordIcon === toolBar.clicked(clickedOverlay, false) && !Recording.isPlaying()) {
|
||||||
if (!Recording.isRecording()) {
|
if (!Recording.isRecording()) {
|
||||||
Recording.startRecording();
|
Recording.startRecording();
|
||||||
|
@ -281,8 +281,13 @@ function mousePressEvent(event) {
|
||||||
if (!Recording.isRecording() && !Recording.isPlaying()) {
|
if (!Recording.isRecording() && !Recording.isPlaying()) {
|
||||||
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
|
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
|
||||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||||
Recording.loadRecording(recordingFile);
|
Recording.loadRecording(recordingFile, function(success) {
|
||||||
setDefaultPlayerOptions();
|
if (success) {
|
||||||
|
setDefaultPlayerOptions();
|
||||||
|
} else {
|
||||||
|
print("Failed to load recording from " + recordingFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (Recording.playerLength() > 0) {
|
if (Recording.playerLength() > 0) {
|
||||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||||
|
@ -323,7 +328,7 @@ function update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTimer();
|
updateTimer();
|
||||||
|
|
||||||
if (watchStop && !Recording.isPlaying()) {
|
if (watchStop && !Recording.isPlaying()) {
|
||||||
watchStop = false;
|
watchStop = false;
|
||||||
toolBar.setAlpha(ALPHA_ON, recordIcon);
|
toolBar.setAlpha(ALPHA_ON, recordIcon);
|
||||||
|
|
|
@ -1051,8 +1051,6 @@ function MyController(hand) {
|
||||||
this.homeButtonTouched = false;
|
this.homeButtonTouched = false;
|
||||||
this.editTriggered = false;
|
this.editTriggered = false;
|
||||||
|
|
||||||
this.controllerJointIndex = getControllerJointIndex(this.hand);
|
|
||||||
|
|
||||||
// Until there is some reliable way to keep track of a "stack" of parentIDs, we'll have problems
|
// Until there is some reliable way to keep track of a "stack" of parentIDs, we'll have problems
|
||||||
// when more than one avatar does parenting grabs on things. This script tries to work
|
// when more than one avatar does parenting grabs on things. This script tries to work
|
||||||
// around this with two associative arrays: previousParentID and previousParentJointIndex. If
|
// around this with two associative arrays: previousParentID and previousParentJointIndex. If
|
||||||
|
@ -1736,6 +1734,7 @@ function MyController(hand) {
|
||||||
|
|
||||||
this.off = function(deltaTime, timestamp) {
|
this.off = function(deltaTime, timestamp) {
|
||||||
|
|
||||||
|
this.controllerJointIndex = getControllerJointIndex(this.hand);
|
||||||
this.checkForUnexpectedChildren();
|
this.checkForUnexpectedChildren();
|
||||||
|
|
||||||
if (this.editTriggered) {
|
if (this.editTriggered) {
|
||||||
|
|
|
@ -29,13 +29,13 @@ var COLORS_TELEPORT_SEAT = {
|
||||||
red: 255,
|
red: 255,
|
||||||
green: 0,
|
green: 0,
|
||||||
blue: 170
|
blue: 170
|
||||||
}
|
};
|
||||||
|
|
||||||
var COLORS_TELEPORT_CAN_TELEPORT = {
|
var COLORS_TELEPORT_CAN_TELEPORT = {
|
||||||
red: 97,
|
red: 97,
|
||||||
green: 247,
|
green: 247,
|
||||||
blue: 255
|
blue: 255
|
||||||
}
|
};
|
||||||
|
|
||||||
var COLORS_TELEPORT_CANNOT_TELEPORT = {
|
var COLORS_TELEPORT_CANNOT_TELEPORT = {
|
||||||
red: 0,
|
red: 0,
|
||||||
|
@ -52,7 +52,7 @@ var COLORS_TELEPORT_CANCEL = {
|
||||||
var TELEPORT_CANCEL_RANGE = 1;
|
var TELEPORT_CANCEL_RANGE = 1;
|
||||||
var COOL_IN_DURATION = 500;
|
var COOL_IN_DURATION = 500;
|
||||||
|
|
||||||
const handInfo = {
|
var handInfo = {
|
||||||
right: {
|
right: {
|
||||||
controllerInput: Controller.Standard.RightHand
|
controllerInput: Controller.Standard.RightHand
|
||||||
},
|
},
|
||||||
|
@ -80,7 +80,7 @@ function Trigger(hand) {
|
||||||
|
|
||||||
this.down = function() {
|
this.down = function() {
|
||||||
var down = _this.buttonValue === 1 ? 1.0 : 0.0;
|
var down = _this.buttonValue === 1 ? 1.0 : 0.0;
|
||||||
return down
|
return down;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +90,9 @@ var ignoredEntities = [];
|
||||||
var TELEPORTER_STATES = {
|
var TELEPORTER_STATES = {
|
||||||
IDLE: 'idle',
|
IDLE: 'idle',
|
||||||
COOL_IN: 'cool_in',
|
COOL_IN: 'cool_in',
|
||||||
|
TARGETTING: 'targetting',
|
||||||
TARGETTING_INVALID: 'targetting_invalid',
|
TARGETTING_INVALID: 'targetting_invalid',
|
||||||
}
|
};
|
||||||
|
|
||||||
var TARGET = {
|
var TARGET = {
|
||||||
NONE: 'none', // Not currently targetting anything
|
NONE: 'none', // Not currently targetting anything
|
||||||
|
@ -99,7 +100,7 @@ var TARGET = {
|
||||||
INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.)
|
INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.)
|
||||||
SURFACE: 'surface', // The current target is a valid surface
|
SURFACE: 'surface', // The current target is a valid surface
|
||||||
SEAT: 'seat', // The current target is a seat
|
SEAT: 'seat', // The current target is a seat
|
||||||
}
|
};
|
||||||
|
|
||||||
function Teleporter() {
|
function Teleporter() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
@ -114,8 +115,8 @@ function Teleporter() {
|
||||||
this.updateConnected = null;
|
this.updateConnected = null;
|
||||||
this.activeHand = null;
|
this.activeHand = null;
|
||||||
|
|
||||||
this.telporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random();
|
this.teleporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random();
|
||||||
this.teleportMappingInternal = Controller.newMapping(this.telporterMappingInternalName);
|
this.teleportMappingInternal = Controller.newMapping(this.teleporterMappingInternalName);
|
||||||
|
|
||||||
// Setup overlays
|
// Setup overlays
|
||||||
this.cancelOverlay = Overlays.addOverlay("model", {
|
this.cancelOverlay = Overlays.addOverlay("model", {
|
||||||
|
@ -135,11 +136,11 @@ function Teleporter() {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.enableMappings = function() {
|
this.enableMappings = function() {
|
||||||
Controller.enableMapping(this.telporterMappingInternalName);
|
Controller.enableMapping(this.teleporterMappingInternalName);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.disableMappings = function() {
|
this.disableMappings = function() {
|
||||||
Controller.disableMapping(teleporter.telporterMappingInternalName);
|
Controller.disableMapping(teleporter.teleporterMappingInternalName);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.cleanup = function() {
|
this.cleanup = function() {
|
||||||
|
@ -179,7 +180,7 @@ function Teleporter() {
|
||||||
if (_this.state === TELEPORTER_STATES.COOL_IN) {
|
if (_this.state === TELEPORTER_STATES.COOL_IN) {
|
||||||
_this.state = TELEPORTER_STATES.TARGETTING;
|
_this.state = TELEPORTER_STATES.TARGETTING;
|
||||||
}
|
}
|
||||||
}, COOL_IN_DURATION)
|
}, COOL_IN_DURATION);
|
||||||
|
|
||||||
this.activeHand = hand;
|
this.activeHand = hand;
|
||||||
this.enableMappings();
|
this.enableMappings();
|
||||||
|
@ -203,13 +204,13 @@ function Teleporter() {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.deleteOverlayBeams = function() {
|
this.deleteOverlayBeams = function() {
|
||||||
for (key in this.overlayLines) {
|
for (var key in this.overlayLines) {
|
||||||
if (this.overlayLines[key] !== null) {
|
if (this.overlayLines[key] !== null) {
|
||||||
Overlays.deleteOverlay(this.overlayLines[key]);
|
Overlays.deleteOverlay(this.overlayLines[key]);
|
||||||
this.overlayLines[key] = null;
|
this.overlayLines[key] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
this.update = function() {
|
this.update = function() {
|
||||||
if (_this.state === TELEPORTER_STATES.IDLE) {
|
if (_this.state === TELEPORTER_STATES.IDLE) {
|
||||||
|
@ -272,7 +273,8 @@ function Teleporter() {
|
||||||
this.hideCancelOverlay();
|
this.hideCancelOverlay();
|
||||||
this.hideSeatOverlay();
|
this.hideSeatOverlay();
|
||||||
|
|
||||||
this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection, COLORS_TELEPORT_CAN_TELEPORT);
|
this.updateLineOverlay(_this.activeHand, pickRay.origin, intersection.intersection,
|
||||||
|
COLORS_TELEPORT_CAN_TELEPORT);
|
||||||
this.updateDestinationOverlay(this.targetOverlay, intersection);
|
this.updateDestinationOverlay(this.targetOverlay, intersection);
|
||||||
}
|
}
|
||||||
} else if (teleportLocationType === TARGET.SEAT) {
|
} else if (teleportLocationType === TARGET.SEAT) {
|
||||||
|
@ -284,13 +286,15 @@ function Teleporter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (((_this.activeHand == 'left' ? leftPad : rightPad).buttonValue === 0) && inTeleportMode === true) {
|
if (((_this.activeHand === 'left' ? leftPad : rightPad).buttonValue === 0) && inTeleportMode === true) {
|
||||||
|
// remember the state before we exit teleport mode and set it back to IDLE
|
||||||
|
var previousState = this.state;
|
||||||
this.exitTeleportMode();
|
this.exitTeleportMode();
|
||||||
this.hideCancelOverlay();
|
this.hideCancelOverlay();
|
||||||
this.hideTargetOverlay();
|
this.hideTargetOverlay();
|
||||||
this.hideSeatOverlay();
|
this.hideSeatOverlay();
|
||||||
|
|
||||||
if (teleportLocationType === TARGET.NONE || teleportLocationType === TARGET.INVALID || this.state === TELEPORTER_STATES.COOL_IN) {
|
if (teleportLocationType === TARGET.NONE || teleportLocationType === TARGET.INVALID || previousState === TELEPORTER_STATES.COOL_IN) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if (teleportLocationType === TARGET.SEAT) {
|
} else if (teleportLocationType === TARGET.SEAT) {
|
||||||
Entities.callEntityMethod(intersection.entityID, 'sit');
|
Entities.callEntityMethod(intersection.entityID, 'sit');
|
||||||
|
@ -321,7 +325,7 @@ function Teleporter() {
|
||||||
this.overlayLines[hand] = Overlays.addOverlay("line3d", lineProperties);
|
this.overlayLines[hand] = Overlays.addOverlay("line3d", lineProperties);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var success = Overlays.editOverlay(this.overlayLines[hand], {
|
Overlays.editOverlay(this.overlayLines[hand], {
|
||||||
start: closePoint,
|
start: closePoint,
|
||||||
end: farPoint,
|
end: farPoint,
|
||||||
color: color
|
color: color
|
||||||
|
@ -361,7 +365,7 @@ function Teleporter() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//related to repositioning the avatar after you teleport
|
// related to repositioning the avatar after you teleport
|
||||||
function getAvatarFootOffset() {
|
function getAvatarFootOffset() {
|
||||||
var data = getJointData();
|
var data = getJointData();
|
||||||
var upperLeg, lowerLeg, foot, toe, toeTop;
|
var upperLeg, lowerLeg, foot, toe, toeTop;
|
||||||
|
@ -384,14 +388,14 @@ function getAvatarFootOffset() {
|
||||||
var offset = upperLeg + lowerLeg + foot + toe + toeTop;
|
var offset = upperLeg + lowerLeg + foot + toe + toeTop;
|
||||||
offset = offset / 100;
|
offset = offset / 100;
|
||||||
return offset;
|
return offset;
|
||||||
};
|
}
|
||||||
|
|
||||||
function getJointData() {
|
function getJointData() {
|
||||||
var allJointData = [];
|
var allJointData = [];
|
||||||
var jointNames = MyAvatar.jointNames;
|
var jointNames = MyAvatar.jointNames;
|
||||||
jointNames.forEach(function(joint, index) {
|
jointNames.forEach(function(joint, index) {
|
||||||
var translation = MyAvatar.getJointTranslation(index);
|
var translation = MyAvatar.getJointTranslation(index);
|
||||||
var rotation = MyAvatar.getJointRotation(index)
|
var rotation = MyAvatar.getJointRotation(index);
|
||||||
allJointData.push({
|
allJointData.push({
|
||||||
joint: joint,
|
joint: joint,
|
||||||
index: index,
|
index: index,
|
||||||
|
@ -401,7 +405,7 @@ function getJointData() {
|
||||||
});
|
});
|
||||||
|
|
||||||
return allJointData;
|
return allJointData;
|
||||||
};
|
}
|
||||||
|
|
||||||
var leftPad = new ThumbPad('left');
|
var leftPad = new ThumbPad('left');
|
||||||
var rightPad = new ThumbPad('right');
|
var rightPad = new ThumbPad('right');
|
||||||
|
@ -420,7 +424,7 @@ function isMoving() {
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function parseJSON(json) {
|
function parseJSON(json) {
|
||||||
try {
|
try {
|
||||||
|
@ -433,7 +437,7 @@ function parseJSON(json) {
|
||||||
// point that is being intersected with is looked at. If this normal is more
|
// point that is being intersected with is looked at. If this normal is more
|
||||||
// than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then
|
// than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from <0, 1, 0> (straight up), then
|
||||||
// you can't teleport there.
|
// you can't teleport there.
|
||||||
const MAX_ANGLE_FROM_UP_TO_TELEPORT = 70;
|
var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70;
|
||||||
function getTeleportTargetType(intersection) {
|
function getTeleportTargetType(intersection) {
|
||||||
if (!intersection.intersects) {
|
if (!intersection.intersects) {
|
||||||
return TARGET.NONE;
|
return TARGET.NONE;
|
||||||
|
@ -465,7 +469,7 @@ function getTeleportTargetType(intersection) {
|
||||||
} else {
|
} else {
|
||||||
return TARGET.SURFACE;
|
return TARGET.SURFACE;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function registerMappings() {
|
function registerMappings() {
|
||||||
mappingName = 'Hifi-Teleporter-Dev-' + Math.random();
|
mappingName = 'Hifi-Teleporter-Dev-' + Math.random();
|
||||||
|
@ -487,7 +491,7 @@ function registerMappings() {
|
||||||
if (isMoving() === true) {
|
if (isMoving() === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
teleporter.enterTeleportMode('left')
|
teleporter.enterTeleportMode('left');
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
teleportMapping.from(Controller.Standard.RightPrimaryThumb)
|
teleportMapping.from(Controller.Standard.RightPrimaryThumb)
|
||||||
|
@ -502,10 +506,10 @@ function registerMappings() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
teleporter.enterTeleportMode('right')
|
teleporter.enterTeleportMode('right');
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
registerMappings();
|
registerMappings();
|
||||||
|
|
||||||
|
@ -521,7 +525,6 @@ Script.scriptEnding.connect(cleanup);
|
||||||
|
|
||||||
var isDisabled = false;
|
var isDisabled = false;
|
||||||
var handleTeleportMessages = function(channel, message, sender) {
|
var handleTeleportMessages = function(channel, message, sender) {
|
||||||
var data;
|
|
||||||
if (sender === MyAvatar.sessionUUID) {
|
if (sender === MyAvatar.sessionUUID) {
|
||||||
if (channel === 'Hifi-Teleport-Disabler') {
|
if (channel === 'Hifi-Teleport-Disabler') {
|
||||||
if (message === 'both') {
|
if (message === 'both') {
|
||||||
|
@ -531,7 +534,7 @@ var handleTeleportMessages = function(channel, message, sender) {
|
||||||
isDisabled = 'left';
|
isDisabled = 'left';
|
||||||
}
|
}
|
||||||
if (message === 'right') {
|
if (message === 'right') {
|
||||||
isDisabled = 'right'
|
isDisabled = 'right';
|
||||||
}
|
}
|
||||||
if (message === 'none') {
|
if (message === 'none') {
|
||||||
isDisabled = false;
|
isDisabled = false;
|
||||||
|
@ -545,7 +548,7 @@ var handleTeleportMessages = function(channel, message, sender) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Messages.subscribe('Hifi-Teleport-Disabler');
|
Messages.subscribe('Hifi-Teleport-Disabler');
|
||||||
Messages.subscribe('Hifi-Teleport-Ignore-Add');
|
Messages.subscribe('Hifi-Teleport-Ignore-Add');
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index",
|
HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index",
|
||||||
HIFI_GRAB_DISABLE_MESSAGE_CHANNEL = "Hifi-Grab-Disable",
|
HIFI_GRAB_DISABLE_MESSAGE_CHANNEL = "Hifi-Grab-Disable",
|
||||||
HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable";
|
HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable";
|
||||||
|
HOW_TO_EXIT_MESSAGE = "Press B on your controller to exit FingerPainting mode";
|
||||||
|
|
||||||
function paintBrush(name) {
|
function paintBrush(name) {
|
||||||
// Paints in 3D.
|
// Paints in 3D.
|
||||||
|
@ -319,6 +320,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function howToExitTutorial() {
|
||||||
|
HMD.requestShowHandControllers();
|
||||||
|
setControllerPartLayer('button_b', 'highlight');
|
||||||
|
messageWindow = Window.alert(HOW_TO_EXIT_MESSAGE);
|
||||||
|
setControllerPartLayer('button_b', 'blank');
|
||||||
|
HMD.requestHideHandControllers();
|
||||||
|
Settings.setValue("FingerPaintTutorialComplete", true);
|
||||||
|
}
|
||||||
|
|
||||||
function enableProcessing() {
|
function enableProcessing() {
|
||||||
// Connect controller API to handController objects.
|
// Connect controller API to handController objects.
|
||||||
leftHand = handController("left");
|
leftHand = handController("left");
|
||||||
|
@ -328,7 +338,12 @@
|
||||||
controllerMapping.from(Controller.Standard.LeftGrip).to(leftHand.onGripPress);
|
controllerMapping.from(Controller.Standard.LeftGrip).to(leftHand.onGripPress);
|
||||||
controllerMapping.from(Controller.Standard.RT).to(rightHand.onTriggerPress);
|
controllerMapping.from(Controller.Standard.RT).to(rightHand.onTriggerPress);
|
||||||
controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress);
|
controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress);
|
||||||
|
controllerMapping.from(Controller.Standard.B).to(onButtonClicked);
|
||||||
Controller.enableMapping(CONTROLLER_MAPPING_NAME);
|
Controller.enableMapping(CONTROLLER_MAPPING_NAME);
|
||||||
|
|
||||||
|
if (!Settings.getValue("FingerPaintTutorialComplete")) {
|
||||||
|
howToExitTutorial();
|
||||||
|
}
|
||||||
|
|
||||||
// Connect handController outputs to paintBrush objects.
|
// Connect handController outputs to paintBrush objects.
|
||||||
leftBrush = paintBrush("left");
|
leftBrush = paintBrush("left");
|
||||||
|
@ -433,6 +448,17 @@
|
||||||
button.clicked.disconnect(onButtonClicked);
|
button.clicked.disconnect(onButtonClicked);
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A controller is made up of parts, and each part can have multiple "layers,"
|
||||||
|
* which are really just different texures. For example, the "trigger" part
|
||||||
|
* has "normal" and "highlight" layers.
|
||||||
|
*/
|
||||||
|
function setControllerPartLayer(part, layer) {
|
||||||
|
data = {};
|
||||||
|
data[part] = layer;
|
||||||
|
Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
setUp();
|
setUp();
|
||||||
Script.scriptEnding.connect(tearDown);
|
Script.scriptEnding.connect(tearDown);
|
||||||
|
|
|
@ -21,6 +21,7 @@ function addImage(data) {
|
||||||
img = document.createElement("IMG"),
|
img = document.createElement("IMG"),
|
||||||
div2 = document.createElement("DIV"),
|
div2 = document.createElement("DIV"),
|
||||||
id = "p" + idCounter++;
|
id = "p" + idCounter++;
|
||||||
|
img.id = id + "img";
|
||||||
function toggle() { data.share = input.checked; }
|
function toggle() { data.share = input.checked; }
|
||||||
div.style.height = "" + Math.floor(100 / imageCount) + "%";
|
div.style.height = "" + Math.floor(100 / imageCount) + "%";
|
||||||
if (imageCount > 1) {
|
if (imageCount > 1) {
|
||||||
|
@ -33,7 +34,7 @@ function addImage(data) {
|
||||||
label.setAttribute('for', id); // cannot do label.for =
|
label.setAttribute('for', id); // cannot do label.for =
|
||||||
input.id = id;
|
input.id = id;
|
||||||
input.type = "checkbox";
|
input.type = "checkbox";
|
||||||
input.checked = (id === "p0");
|
input.checked = false;
|
||||||
data.share = input.checked;
|
data.share = input.checked;
|
||||||
input.addEventListener('change', toggle);
|
input.addEventListener('change', toggle);
|
||||||
div2.setAttribute("class", "property checkbox");
|
div2.setAttribute("class", "property checkbox");
|
||||||
|
@ -46,9 +47,9 @@ function addImage(data) {
|
||||||
document.getElementById("snapshot-images").appendChild(div);
|
document.getElementById("snapshot-images").appendChild(div);
|
||||||
paths.push(data);
|
paths.push(data);
|
||||||
}
|
}
|
||||||
function handleShareButtons(shareMsg) {
|
function handleShareButtons(messageOptions) {
|
||||||
var openFeed = document.getElementById('openFeed');
|
var openFeed = document.getElementById('openFeed');
|
||||||
openFeed.checked = shareMsg.openFeedAfterShare;
|
openFeed.checked = messageOptions.openFeedAfterShare;
|
||||||
openFeed.onchange = function () {
|
openFeed.onchange = function () {
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "snapshot",
|
type: "snapshot",
|
||||||
|
@ -56,7 +57,7 @@ function handleShareButtons(shareMsg) {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!shareMsg.canShare) {
|
if (!messageOptions.canShare) {
|
||||||
// this means you may or may not be logged in, but can't share
|
// this means you may or may not be logged in, but can't share
|
||||||
// because you are not in a public place.
|
// because you are not in a public place.
|
||||||
document.getElementById("sharing").innerHTML = "<p class='prompt'>Snapshots can be shared when they're taken in shareable places.";
|
document.getElementById("sharing").innerHTML = "<p class='prompt'>Snapshots can be shared when they're taken in shareable places.";
|
||||||
|
@ -74,13 +75,28 @@ window.onload = function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// last element of list contains a bool for whether or not we can share stuff
|
// The last element of the message contents list contains a bunch of options,
|
||||||
var shareMsg = message.action.pop();
|
// including whether or not we can share stuff
|
||||||
handleShareButtons(shareMsg);
|
// The other elements of the list contain image paths.
|
||||||
|
var messageOptions = message.action.pop();
|
||||||
// rest are image paths which we add
|
handleShareButtons(messageOptions);
|
||||||
imageCount = message.action.length;
|
|
||||||
message.action.forEach(addImage);
|
if (messageOptions.containsGif) {
|
||||||
|
if (messageOptions.processingGif) {
|
||||||
|
imageCount = message.action.length + 1; // "+1" for the GIF that'll finish processing soon
|
||||||
|
message.action.unshift({ localPath: messageOptions.loadingGifPath });
|
||||||
|
message.action.forEach(addImage);
|
||||||
|
document.getElementById('p0').disabled = true;
|
||||||
|
} else {
|
||||||
|
var gifPath = message.action[0].localPath;
|
||||||
|
document.getElementById('p0').disabled = false;
|
||||||
|
document.getElementById('p0img').src = gifPath;
|
||||||
|
paths[0].localPath = gifPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
imageCount = message.action.length;
|
||||||
|
message.action.forEach(addImage);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "snapshot",
|
type: "snapshot",
|
||||||
|
|
|
@ -532,7 +532,7 @@ function onNotify(msg) {
|
||||||
createNotification(wordWrap(msg), NotificationType.UNKNOWN); // Needs a generic notification system for user feedback, thus using this
|
createNotification(wordWrap(msg), NotificationType.UNKNOWN); // Needs a generic notification system for user feedback, thus using this
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSnapshotTaken(pathStillSnapshot, pathAnimatedSnapshot, notify) {
|
function onSnapshotTaken(pathStillSnapshot, notify) {
|
||||||
if (notify) {
|
if (notify) {
|
||||||
var imageProperties = {
|
var imageProperties = {
|
||||||
path: "file:///" + pathStillSnapshot,
|
path: "file:///" + pathStillSnapshot,
|
||||||
|
@ -656,8 +656,8 @@ Script.update.connect(update);
|
||||||
Script.scriptEnding.connect(scriptEnding);
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
Menu.menuItemEvent.connect(menuItemEvent);
|
Menu.menuItemEvent.connect(menuItemEvent);
|
||||||
Window.domainConnectionRefused.connect(onDomainConnectionRefused);
|
Window.domainConnectionRefused.connect(onDomainConnectionRefused);
|
||||||
Window.snapshotTaken.connect(onSnapshotTaken);
|
Window.stillSnapshotTaken.connect(onSnapshotTaken);
|
||||||
Window.processingGif.connect(processingGif);
|
Window.processingGifStarted.connect(processingGif);
|
||||||
Window.connectionAdded.connect(connectionAdded);
|
Window.connectionAdded.connect(connectionAdded);
|
||||||
Window.connectionError.connect(connectionError);
|
Window.connectionError.connect(connectionError);
|
||||||
Window.notifyEditError = onEditError;
|
Window.notifyEditError = onEditError;
|
||||||
|
|
|
@ -90,12 +90,12 @@ function onMessage(message) {
|
||||||
needsLogin = true;
|
needsLogin = true;
|
||||||
submessage.share = false;
|
submessage.share = false;
|
||||||
shareAfterLogin = true;
|
shareAfterLogin = true;
|
||||||
snapshotToShareAfterLogin = {path: submessage.localPath, href: submessage.href};
|
snapshotToShareAfterLogin = {path: submessage.localPath, href: submessage.href || href};
|
||||||
}
|
}
|
||||||
if (submessage.share) {
|
if (submessage.share) {
|
||||||
print('sharing', submessage.localPath);
|
print('sharing', submessage.localPath);
|
||||||
outstanding = true;
|
outstanding = true;
|
||||||
Window.shareSnapshot(submessage.localPath, submessage.href);
|
Window.shareSnapshot(submessage.localPath, submessage.href || href);
|
||||||
} else {
|
} else {
|
||||||
print('not sharing', submessage.localPath);
|
print('not sharing', submessage.localPath);
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,9 @@ function onClicked() {
|
||||||
resetOverlays = Menu.isOptionChecked("Overlays"); // For completness. Certainly true if the button is visible to be clicke.
|
resetOverlays = Menu.isOptionChecked("Overlays"); // For completness. Certainly true if the button is visible to be clicke.
|
||||||
reticleVisible = Reticle.visible;
|
reticleVisible = Reticle.visible;
|
||||||
Reticle.visible = false;
|
Reticle.visible = false;
|
||||||
Window.snapshotTaken.connect(resetButtons);
|
Window.stillSnapshotTaken.connect(stillSnapshotTaken);
|
||||||
|
Window.processingGifStarted.connect(processingGifStarted);
|
||||||
|
Window.processingGifCompleted.connect(processingGifCompleted);
|
||||||
|
|
||||||
// hide overlays if they are on
|
// hide overlays if they are on
|
||||||
if (resetOverlays) {
|
if (resetOverlays) {
|
||||||
|
@ -193,25 +195,14 @@ function isDomainOpen(id) {
|
||||||
response.total_entries;
|
response.total_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) {
|
function stillSnapshotTaken(pathStillSnapshot, notify) {
|
||||||
// If we're not taking an animated snapshot, we have to show the HUD.
|
// show hud
|
||||||
// If we ARE taking an animated snapshot, we've already re-enabled the HUD by this point.
|
Reticle.visible = reticleVisible;
|
||||||
if (pathAnimatedSnapshot === "") {
|
// show overlays if they were on
|
||||||
// show hud
|
if (resetOverlays) {
|
||||||
|
Menu.setIsOptionChecked("Overlays", true);
|
||||||
Reticle.visible = reticleVisible;
|
|
||||||
// show overlays if they were on
|
|
||||||
if (resetOverlays) {
|
|
||||||
Menu.setIsOptionChecked("Overlays", true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Allow the user to click the snapshot HUD button again
|
|
||||||
if (!buttonConnected) {
|
|
||||||
button.clicked.connect(onClicked);
|
|
||||||
buttonConnected = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Window.snapshotTaken.disconnect(resetButtons);
|
Window.stillSnapshotTaken.disconnect(stillSnapshotTaken);
|
||||||
|
|
||||||
// A Snapshot Review dialog might be left open indefinitely after taking the picture,
|
// A Snapshot Review dialog might be left open indefinitely after taking the picture,
|
||||||
// during which time the user may have moved. So stash that info in the dialog so that
|
// during which time the user may have moved. So stash that info in the dialog so that
|
||||||
|
@ -220,12 +211,11 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) {
|
||||||
var confirmShareContents = [
|
var confirmShareContents = [
|
||||||
{ localPath: pathStillSnapshot, href: href },
|
{ localPath: pathStillSnapshot, href: href },
|
||||||
{
|
{
|
||||||
|
containsGif: false,
|
||||||
|
processingGif: false,
|
||||||
canShare: !!isDomainOpen(domainId),
|
canShare: !!isDomainOpen(domainId),
|
||||||
openFeedAfterShare: shouldOpenFeedAfterShare()
|
openFeedAfterShare: shouldOpenFeedAfterShare()
|
||||||
}];
|
}];
|
||||||
if (pathAnimatedSnapshot !== "") {
|
|
||||||
confirmShareContents.unshift({ localPath: pathAnimatedSnapshot, href: href });
|
|
||||||
}
|
|
||||||
confirmShare(confirmShareContents);
|
confirmShare(confirmShareContents);
|
||||||
if (clearOverlayWhenMoving) {
|
if (clearOverlayWhenMoving) {
|
||||||
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
|
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
|
||||||
|
@ -233,15 +223,52 @@ function resetButtons(pathStillSnapshot, pathAnimatedSnapshot, notify) {
|
||||||
HMD.openTablet();
|
HMD.openTablet();
|
||||||
}
|
}
|
||||||
|
|
||||||
function processingGif() {
|
function processingGifStarted(pathStillSnapshot) {
|
||||||
// show hud
|
Window.processingGifStarted.disconnect(processingGifStarted);
|
||||||
Reticle.visible = reticleVisible;
|
|
||||||
button.clicked.disconnect(onClicked);
|
button.clicked.disconnect(onClicked);
|
||||||
buttonConnected = false;
|
buttonConnected = false;
|
||||||
|
// show hud
|
||||||
|
Reticle.visible = reticleVisible;
|
||||||
// show overlays if they were on
|
// show overlays if they were on
|
||||||
if (resetOverlays) {
|
if (resetOverlays) {
|
||||||
Menu.setIsOptionChecked("Overlays", true);
|
Menu.setIsOptionChecked("Overlays", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var confirmShareContents = [
|
||||||
|
{ localPath: pathStillSnapshot, href: href },
|
||||||
|
{
|
||||||
|
containsGif: true,
|
||||||
|
processingGif: true,
|
||||||
|
loadingGifPath: Script.resolvePath(Script.resourcesPath() + 'icons/loadingDark.gif'),
|
||||||
|
canShare: !!isDomainOpen(domainId),
|
||||||
|
openFeedAfterShare: shouldOpenFeedAfterShare()
|
||||||
|
}];
|
||||||
|
confirmShare(confirmShareContents);
|
||||||
|
if (clearOverlayWhenMoving) {
|
||||||
|
MyAvatar.setClearOverlayWhenMoving(true); // not until after the share dialog
|
||||||
|
}
|
||||||
|
HMD.openTablet();
|
||||||
|
}
|
||||||
|
|
||||||
|
function processingGifCompleted(pathAnimatedSnapshot) {
|
||||||
|
Window.processingGifCompleted.disconnect(processingGifCompleted);
|
||||||
|
button.clicked.connect(onClicked);
|
||||||
|
buttonConnected = true;
|
||||||
|
|
||||||
|
var confirmShareContents = [
|
||||||
|
{ localPath: pathAnimatedSnapshot, href: href },
|
||||||
|
{
|
||||||
|
containsGif: true,
|
||||||
|
processingGif: false,
|
||||||
|
canShare: !!isDomainOpen(domainId),
|
||||||
|
openFeedAfterShare: shouldOpenFeedAfterShare()
|
||||||
|
}];
|
||||||
|
readyData = confirmShareContents;
|
||||||
|
|
||||||
|
tablet.emitScriptEvent(JSON.stringify({
|
||||||
|
type: "snapshot",
|
||||||
|
action: readyData
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTabletScreenChanged(type, url) {
|
function onTabletScreenChanged(type, url) {
|
||||||
|
@ -265,7 +292,6 @@ function onConnected() {
|
||||||
button.clicked.connect(onClicked);
|
button.clicked.connect(onClicked);
|
||||||
buttonConnected = true;
|
buttonConnected = true;
|
||||||
Window.snapshotShared.connect(snapshotShared);
|
Window.snapshotShared.connect(snapshotShared);
|
||||||
Window.processingGif.connect(processingGif);
|
|
||||||
tablet.screenChanged.connect(onTabletScreenChanged);
|
tablet.screenChanged.connect(onTabletScreenChanged);
|
||||||
Account.usernameChanged.connect(onConnected);
|
Account.usernameChanged.connect(onConnected);
|
||||||
Script.scriptEnding.connect(function () {
|
Script.scriptEnding.connect(function () {
|
||||||
|
@ -277,7 +303,6 @@ Script.scriptEnding.connect(function () {
|
||||||
tablet.removeButton(button);
|
tablet.removeButton(button);
|
||||||
}
|
}
|
||||||
Window.snapshotShared.disconnect(snapshotShared);
|
Window.snapshotShared.disconnect(snapshotShared);
|
||||||
Window.processingGif.disconnect(processingGif);
|
|
||||||
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
tablet.screenChanged.disconnect(onTabletScreenChanged);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ function findEntitiesWithTag(tag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A controller in made up of parts, and each part can have multiple "layers,"
|
* A controller is made up of parts, and each part can have multiple "layers,"
|
||||||
* which are really just different texures. For example, the "trigger" part
|
* which are really just different texures. For example, the "trigger" part
|
||||||
* has "normal" and "highlight" layers.
|
* has "normal" and "highlight" layers.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue