mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 16:18:05 +02:00
Merge pull request #9931 from sethalves/tablet-ui
Tablet ui -- merge from upstream
This commit is contained in:
commit
d45266f28b
33 changed files with 769 additions and 323 deletions
|
@ -371,25 +371,39 @@ void Agent::executeScript() {
|
||||||
using namespace recording;
|
using namespace recording;
|
||||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
||||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||||
const QByteArray& audio = frame->data;
|
|
||||||
static quint16 audioSequenceNumber{ 0 };
|
static quint16 audioSequenceNumber{ 0 };
|
||||||
Transform audioTransform;
|
|
||||||
|
|
||||||
|
QByteArray audio(frame->data);
|
||||||
|
|
||||||
|
if (_isNoiseGateEnabled) {
|
||||||
|
static int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||||
|
_noiseGate.gateSamples(reinterpret_cast<int16_t*>(audio.data()), numSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
computeLoudness(&audio, scriptedAvatar);
|
||||||
|
|
||||||
|
// the codec needs a flush frame before sending silent packets, so
|
||||||
|
// do not send one if the gate closed in this block (eventually this can be crossfaded).
|
||||||
|
auto packetType = PacketType::MicrophoneAudioNoEcho;
|
||||||
|
if (scriptedAvatar->getAudioLoudness() == 0.0f && !_noiseGate.closedInLastBlock()) {
|
||||||
|
packetType = PacketType::SilentAudioFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform audioTransform;
|
||||||
auto headOrientation = scriptedAvatar->getHeadOrientation();
|
auto headOrientation = scriptedAvatar->getHeadOrientation();
|
||||||
audioTransform.setTranslation(scriptedAvatar->getPosition());
|
audioTransform.setTranslation(scriptedAvatar->getPosition());
|
||||||
audioTransform.setRotation(headOrientation);
|
audioTransform.setRotation(headOrientation);
|
||||||
|
|
||||||
computeLoudness(&audio, scriptedAvatar);
|
|
||||||
|
|
||||||
QByteArray encodedBuffer;
|
QByteArray encodedBuffer;
|
||||||
if (_encoder) {
|
if (_encoder) {
|
||||||
_encoder->encode(audio, encodedBuffer);
|
_encoder->encode(audio, encodedBuffer);
|
||||||
} else {
|
} else {
|
||||||
encodedBuffer = audio;
|
encodedBuffer = audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber,
|
AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber,
|
||||||
audioTransform, scriptedAvatar->getPosition(), glm::vec3(0),
|
audioTransform, scriptedAvatar->getPosition(), glm::vec3(0),
|
||||||
PacketType::MicrophoneAudioNoEcho, _selectedCodecName);
|
packetType, _selectedCodecName);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||||
|
@ -483,6 +497,14 @@ void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) {
|
||||||
_isListeningToAudioStream = isListeningToAudioStream;
|
_isListeningToAudioStream = isListeningToAudioStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Agent::setIsNoiseGateEnabled(bool isNoiseGateEnabled) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setIsNoiseGateEnabled", Q_ARG(bool, isNoiseGateEnabled));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isNoiseGateEnabled = isNoiseGateEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
void Agent::setIsAvatar(bool isAvatar) {
|
void Agent::setIsAvatar(bool isAvatar) {
|
||||||
// this must happen on Agent's main thread
|
// this must happen on Agent's main thread
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
|
#include "AudioNoiseGate.h"
|
||||||
#include "MixedAudioStream.h"
|
#include "MixedAudioStream.h"
|
||||||
#include "avatars/ScriptableAvatar.h"
|
#include "avatars/ScriptableAvatar.h"
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ class Agent : public ThreadedAssignment {
|
||||||
Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar)
|
Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar)
|
||||||
Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound)
|
Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound)
|
||||||
Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream)
|
Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream)
|
||||||
|
Q_PROPERTY(bool isNoiseGateEnabled READ isNoiseGateEnabled WRITE setIsNoiseGateEnabled)
|
||||||
Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness)
|
Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness)
|
||||||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||||
|
|
||||||
|
@ -52,6 +54,9 @@ public:
|
||||||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||||
void setIsListeningToAudioStream(bool isListeningToAudioStream);
|
void setIsListeningToAudioStream(bool isListeningToAudioStream);
|
||||||
|
|
||||||
|
bool isNoiseGateEnabled() const { return _isNoiseGateEnabled; }
|
||||||
|
void setIsNoiseGateEnabled(bool isNoiseGateEnabled);
|
||||||
|
|
||||||
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
||||||
QUuid getSessionUUID() const;
|
QUuid getSessionUUID() const;
|
||||||
|
|
||||||
|
@ -106,6 +111,9 @@ private:
|
||||||
QTimer* _avatarIdentityTimer = nullptr;
|
QTimer* _avatarIdentityTimer = nullptr;
|
||||||
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
||||||
|
|
||||||
|
AudioNoiseGate _noiseGate;
|
||||||
|
bool _isNoiseGateEnabled { false };
|
||||||
|
|
||||||
CodecPluginPointer _codec;
|
CodecPluginPointer _codec;
|
||||||
QString _selectedCodecName;
|
QString _selectedCodecName;
|
||||||
Encoder* _encoder { nullptr };
|
Encoder* _encoder { nullptr };
|
||||||
|
|
|
@ -455,13 +455,13 @@ void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
|
||||||
|
|
||||||
void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
|
void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
|
||||||
if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
|
if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
|
||||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID, const bool reload) {
|
void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID, const bool reload) {
|
||||||
if (_entityViewer.getTree() && !_shuttingDown) {
|
if (_entityViewer.getTree() && !_shuttingDown) {
|
||||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||||
checkAndCallPreload(entityID, reload);
|
checkAndCallPreload(entityID, reload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,10 +246,13 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
||||||
_agentPermissions[editorKey]->set(NodePermissions::Permission::canAdjustLocks);
|
_agentPermissions[editorKey]->set(NodePermissions::Permission::canAdjustLocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QHash<NodePermissionsKey, NodePermissionsPointer>> permissionsSets;
|
std::list<std::unordered_map<NodePermissionsKey, NodePermissionsPointer>> permissionsSets{
|
||||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get();
|
_standardAgentPermissions.get(),
|
||||||
|
_agentPermissions.get()
|
||||||
|
};
|
||||||
foreach (auto permissionsSet, permissionsSets) {
|
foreach (auto permissionsSet, permissionsSets) {
|
||||||
foreach (NodePermissionsKey userKey, permissionsSet.keys()) {
|
for (auto entry : permissionsSet) {
|
||||||
|
const auto& userKey = entry.first;
|
||||||
if (onlyEditorsAreRezzers) {
|
if (onlyEditorsAreRezzers) {
|
||||||
if (permissionsSet[userKey]->can(NodePermissions::Permission::canAdjustLocks)) {
|
if (permissionsSet[userKey]->can(NodePermissions::Permission::canAdjustLocks)) {
|
||||||
permissionsSet[userKey]->set(NodePermissions::Permission::canRezPermanentEntities);
|
permissionsSet[userKey]->set(NodePermissions::Permission::canRezPermanentEntities);
|
||||||
|
@ -300,7 +303,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap& DomainServerSettingsManager::getDescriptorsMap() {
|
QVariantMap& DomainServerSettingsManager::getDescriptorsMap() {
|
||||||
|
|
||||||
static const QString DESCRIPTORS{ "descriptors" };
|
static const QString DESCRIPTORS{ "descriptors" };
|
||||||
|
|
||||||
auto& settingsMap = getSettingsMap();
|
auto& settingsMap = getSettingsMap();
|
||||||
|
@ -1355,18 +1357,12 @@ QStringList DomainServerSettingsManager::getAllKnownGroupNames() {
|
||||||
// extract all the group names from the group-permissions and group-forbiddens settings
|
// extract all the group names from the group-permissions and group-forbiddens settings
|
||||||
QSet<QString> result;
|
QSet<QString> result;
|
||||||
|
|
||||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(_groupPermissions.get());
|
for (const auto& entry : _groupPermissions.get()) {
|
||||||
while (i.hasNext()) {
|
result += entry.first.first;
|
||||||
i.next();
|
|
||||||
NodePermissionsKey key = i.key();
|
|
||||||
result += key.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> j(_groupForbiddens.get());
|
for (const auto& entry : _groupForbiddens.get()) {
|
||||||
while (j.hasNext()) {
|
result += entry.first.first;
|
||||||
j.next();
|
|
||||||
NodePermissionsKey key = j.key();
|
|
||||||
result += key.first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.toList();
|
return result.toList();
|
||||||
|
@ -1377,20 +1373,17 @@ bool DomainServerSettingsManager::setGroupID(const QString& groupName, const QUu
|
||||||
_groupIDs[groupName.toLower()] = groupID;
|
_groupIDs[groupName.toLower()] = groupID;
|
||||||
_groupNames[groupID] = groupName;
|
_groupNames[groupID] = groupName;
|
||||||
|
|
||||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(_groupPermissions.get());
|
|
||||||
while (i.hasNext()) {
|
for (const auto& entry : _groupPermissions.get()) {
|
||||||
i.next();
|
auto& perms = entry.second;
|
||||||
NodePermissionsPointer perms = i.value();
|
|
||||||
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
||||||
changed = true;
|
changed = true;
|
||||||
perms->setGroupID(groupID);
|
perms->setGroupID(groupID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> j(_groupForbiddens.get());
|
for (const auto& entry : _groupForbiddens.get()) {
|
||||||
while (j.hasNext()) {
|
auto& perms = entry.second;
|
||||||
j.next();
|
|
||||||
NodePermissionsPointer perms = j.value();
|
|
||||||
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
||||||
changed = true;
|
changed = true;
|
||||||
perms->setGroupID(groupID);
|
perms->setGroupID(groupID);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
QPlainTextEdit {
|
QPlainTextEdit {
|
||||||
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
font-family: Inconsolata, Consolas, Courier New, monospace;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
padding-left: 28px;
|
padding-left: 28px;
|
||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
|
@ -11,7 +11,7 @@ QPlainTextEdit {
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineEdit {
|
QLineEdit {
|
||||||
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
font-family: Inconsolata, Consolas, Courier New, monospace;
|
||||||
padding-left: 7px;
|
padding-left: 7px;
|
||||||
background-color: #CCCCCC;
|
background-color: #CCCCCC;
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
|
|
|
@ -20,55 +20,28 @@ using namespace render;
|
||||||
CauterizedMeshPartPayload::CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
|
CauterizedMeshPartPayload::CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
|
||||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
|
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
|
||||||
|
|
||||||
void CauterizedMeshPartPayload::updateTransformForSkinnedCauterizedMesh(const Transform& transform,
|
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(
|
||||||
const QVector<glm::mat4>& clusterMatrices,
|
const Transform& renderTransform,
|
||||||
const QVector<glm::mat4>& cauterizedClusterMatrices) {
|
const gpu::BufferPointer& buffer) {
|
||||||
_transform = transform;
|
_cauterizedTransform = renderTransform;
|
||||||
_cauterizedTransform = transform;
|
_cauterizedClusterBuffer = buffer;
|
||||||
|
|
||||||
if (clusterMatrices.size() > 0) {
|
|
||||||
_worldBound = AABox();
|
|
||||||
for (auto& clusterMatrix : clusterMatrices) {
|
|
||||||
AABox clusterBound = _localBound;
|
|
||||||
clusterBound.transform(clusterMatrix);
|
|
||||||
_worldBound += clusterBound;
|
|
||||||
}
|
|
||||||
|
|
||||||
_worldBound.transform(transform);
|
|
||||||
if (clusterMatrices.size() == 1) {
|
|
||||||
_transform = _transform.worldTransform(Transform(clusterMatrices[0]));
|
|
||||||
if (cauterizedClusterMatrices.size() != 0) {
|
|
||||||
_cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0]));
|
|
||||||
} else {
|
|
||||||
_cauterizedTransform = _transform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_worldBound = _localBound;
|
|
||||||
_worldBound.transform(_drawTransform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
||||||
// Still relying on the raw data from the model
|
// Still relying on the raw data from the model
|
||||||
const Model::MeshState& state = _model->getMeshState(_meshIndex);
|
|
||||||
SkeletonModel* skeleton = static_cast<SkeletonModel*>(_model);
|
SkeletonModel* skeleton = static_cast<SkeletonModel*>(_model);
|
||||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE) && skeleton->getEnableCauterization();
|
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE) && skeleton->getEnableCauterization();
|
||||||
|
|
||||||
if (state.clusterBuffer) {
|
|
||||||
if (useCauterizedMesh) {
|
if (useCauterizedMesh) {
|
||||||
const Model::MeshState& cState = skeleton->getCauterizeMeshState(_meshIndex);
|
if (_cauterizedClusterBuffer) {
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, cState.clusterBuffer);
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer);
|
||||||
} else {
|
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer);
|
|
||||||
}
|
}
|
||||||
batch.setModelTransform(_transform);
|
|
||||||
} else {
|
|
||||||
if (useCauterizedMesh) {
|
|
||||||
batch.setModelTransform(_cauterizedTransform);
|
batch.setModelTransform(_cauterizedTransform);
|
||||||
} else {
|
} else {
|
||||||
batch.setModelTransform(_transform);
|
if (_clusterBuffer) {
|
||||||
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||||
}
|
}
|
||||||
|
batch.setModelTransform(_transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,13 @@
|
||||||
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
||||||
public:
|
public:
|
||||||
CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||||
void updateTransformForSkinnedCauterizedMesh(const Transform& transform,
|
|
||||||
const QVector<glm::mat4>& clusterMatrices,
|
void updateTransformForCauterizedMesh(const Transform& renderTransform, const gpu::BufferPointer& buffer);
|
||||||
const QVector<glm::mat4>& cauterizedClusterMatrices);
|
|
||||||
|
|
||||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
gpu::BufferPointer _cauterizedClusterBuffer;
|
||||||
Transform _cauterizedTransform;
|
Transform _cauterizedTransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,9 @@ void CauterizedModel::updateRenderItems() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||||
|
self->updateClusterMatrices();
|
||||||
|
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
|
||||||
Transform modelTransform;
|
Transform modelTransform;
|
||||||
|
@ -209,15 +212,22 @@ void CauterizedModel::updateRenderItems() {
|
||||||
if (data._model && data._model->isLoaded()) {
|
if (data._model && data._model->isLoaded()) {
|
||||||
// Ensure the model geometry was not reset between frames
|
// Ensure the model geometry was not reset between frames
|
||||||
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
|
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
|
||||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
// this stuff identical to what happens in regular Model
|
||||||
data._model->updateClusterMatrices();
|
|
||||||
|
|
||||||
// update the model transform and bounding box for this render item.
|
|
||||||
const Model::MeshState& state = data._model->getMeshState(data._meshIndex);
|
const Model::MeshState& state = data._model->getMeshState(data._meshIndex);
|
||||||
|
Transform renderTransform = modelTransform;
|
||||||
|
if (state.clusterMatrices.size() == 1) {
|
||||||
|
renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||||
|
}
|
||||||
|
data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
|
||||||
|
|
||||||
|
// this stuff for cauterized mesh
|
||||||
CauterizedModel* cModel = static_cast<CauterizedModel*>(data._model);
|
CauterizedModel* cModel = static_cast<CauterizedModel*>(data._model);
|
||||||
assert(data._meshIndex < cModel->_cauterizeMeshStates.size());
|
const Model::MeshState& cState = cModel->getCauterizeMeshState(data._meshIndex);
|
||||||
const Model::MeshState& cState = cModel->_cauterizeMeshStates.at(data._meshIndex);
|
renderTransform = modelTransform;
|
||||||
data.updateTransformForSkinnedCauterizedMesh(modelTransform, state.clusterMatrices, cState.clusterMatrices);
|
if (cState.clusterMatrices.size() == 1) {
|
||||||
|
renderTransform = modelTransform.worldTransform(Transform(cState.clusterMatrices[0]));
|
||||||
|
}
|
||||||
|
data.updateTransformForCauterizedMesh(renderTransform, cState.clusterBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -154,9 +154,12 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
||||||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||||
setRecordingBasis();
|
setRecordingBasis();
|
||||||
}
|
}
|
||||||
|
_wasCharacterControllerEnabled = _characterController.isEnabled();
|
||||||
|
_characterController.setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
clearRecordingBasis();
|
clearRecordingBasis();
|
||||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||||
|
_characterController.setEnabled(_wasCharacterControllerEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto audioIO = DependencyManager::get<AudioClient>();
|
auto audioIO = DependencyManager::get<AudioClient>();
|
||||||
|
|
|
@ -411,6 +411,7 @@ private:
|
||||||
SharedSoundPointer _collisionSound;
|
SharedSoundPointer _collisionSound;
|
||||||
|
|
||||||
MyCharacterController _characterController;
|
MyCharacterController _characterController;
|
||||||
|
bool _wasCharacterControllerEnabled { true };
|
||||||
|
|
||||||
AvatarWeakPointer _lookAtTargetAvatar;
|
AvatarWeakPointer _lookAtTargetAvatar;
|
||||||
glm::vec3 _targetAvatarPosition;
|
glm::vec3 _targetAvatarPosition;
|
||||||
|
|
|
@ -28,17 +28,23 @@ const int SEARCH_BUTTON_LEFT = 25;
|
||||||
const int SEARCH_BUTTON_WIDTH = 20;
|
const int SEARCH_BUTTON_WIDTH = 20;
|
||||||
const int SEARCH_TOGGLE_BUTTON_WIDTH = 50;
|
const int SEARCH_TOGGLE_BUTTON_WIDTH = 50;
|
||||||
const int SEARCH_TEXT_WIDTH = 240;
|
const int SEARCH_TEXT_WIDTH = 240;
|
||||||
|
const int TIME_STAMP_LENGTH = 16;
|
||||||
|
const int FONT_WEIGHT = 75;
|
||||||
const QColor HIGHLIGHT_COLOR = QColor("#3366CC");
|
const QColor HIGHLIGHT_COLOR = QColor("#3366CC");
|
||||||
|
const QColor BOLD_COLOR = QColor("#445c8c");
|
||||||
|
const QString BOLD_PATTERN = "\\[\\d*\\/.*:\\d*:\\d*\\]";
|
||||||
|
|
||||||
class KeywordHighlighter : public QSyntaxHighlighter {
|
class Highlighter : public QSyntaxHighlighter {
|
||||||
public:
|
public:
|
||||||
KeywordHighlighter(QTextDocument* parent = nullptr);
|
Highlighter(QTextDocument* parent = nullptr);
|
||||||
|
void setBold(int indexToBold);
|
||||||
QString keyword;
|
QString keyword;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void highlightBlock(const QString& text) override;
|
void highlightBlock(const QString& text) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QTextCharFormat boldFormat;
|
||||||
QTextCharFormat keywordFormat;
|
QTextCharFormat keywordFormat;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -101,9 +107,8 @@ void BaseLogDialog::initControls() {
|
||||||
_logTextBox = new QPlainTextEdit(this);
|
_logTextBox = new QPlainTextEdit(this);
|
||||||
_logTextBox->setReadOnly(true);
|
_logTextBox->setReadOnly(true);
|
||||||
_logTextBox->show();
|
_logTextBox->show();
|
||||||
_highlighter = new KeywordHighlighter(_logTextBox->document());
|
_highlighter = new Highlighter(_logTextBox->document());
|
||||||
connect(_logTextBox, SIGNAL(selectionChanged()), SLOT(updateSelection()));
|
connect(_logTextBox, SIGNAL(selectionChanged()), SLOT(updateSelection()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseLogDialog::showEvent(QShowEvent* event) {
|
void BaseLogDialog::showEvent(QShowEvent* event) {
|
||||||
|
@ -116,7 +121,9 @@ void BaseLogDialog::resizeEvent(QResizeEvent* event) {
|
||||||
|
|
||||||
void BaseLogDialog::appendLogLine(QString logLine) {
|
void BaseLogDialog::appendLogLine(QString logLine) {
|
||||||
if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) {
|
if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) {
|
||||||
|
int indexToBold = _logTextBox->document()->characterCount();
|
||||||
_logTextBox->appendPlainText(logLine.trimmed());
|
_logTextBox->appendPlainText(logLine.trimmed());
|
||||||
|
_highlighter->setBold(indexToBold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +182,7 @@ void BaseLogDialog::showLogData() {
|
||||||
_logTextBox->clear();
|
_logTextBox->clear();
|
||||||
_logTextBox->appendPlainText(getCurrentLog());
|
_logTextBox->appendPlainText(getCurrentLog());
|
||||||
_logTextBox->ensureCursorVisible();
|
_logTextBox->ensureCursorVisible();
|
||||||
|
_highlighter->rehighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseLogDialog::updateSelection() {
|
void BaseLogDialog::updateSelection() {
|
||||||
|
@ -187,16 +195,28 @@ void BaseLogDialog::updateSelection() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeywordHighlighter::KeywordHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) {
|
Highlighter::Highlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) {
|
||||||
|
boldFormat.setFontWeight(FONT_WEIGHT);
|
||||||
|
boldFormat.setForeground(BOLD_COLOR);
|
||||||
keywordFormat.setForeground(HIGHLIGHT_COLOR);
|
keywordFormat.setForeground(HIGHLIGHT_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeywordHighlighter::highlightBlock(const QString& text) {
|
void Highlighter::highlightBlock(const QString& text) {
|
||||||
|
QRegExp expression(BOLD_PATTERN);
|
||||||
|
|
||||||
|
int index = text.indexOf(expression, 0);
|
||||||
|
|
||||||
|
while (index >= 0) {
|
||||||
|
int length = expression.matchedLength();
|
||||||
|
setFormat(index, length, boldFormat);
|
||||||
|
index = text.indexOf(expression, index + length);
|
||||||
|
}
|
||||||
|
|
||||||
if (keyword.isNull() || keyword.isEmpty()) {
|
if (keyword.isNull() || keyword.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = text.indexOf(keyword, 0, Qt::CaseInsensitive);
|
index = text.indexOf(keyword, 0, Qt::CaseInsensitive);
|
||||||
int length = keyword.length();
|
int length = keyword.length();
|
||||||
|
|
||||||
while (index >= 0) {
|
while (index >= 0) {
|
||||||
|
@ -204,3 +224,7 @@ void KeywordHighlighter::highlightBlock(const QString& text) {
|
||||||
index = text.indexOf(keyword, index + length, Qt::CaseInsensitive);
|
index = text.indexOf(keyword, index + length, Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Highlighter::setBold(int indexToBold) {
|
||||||
|
setFormat(indexToBold, TIME_STAMP_LENGTH, boldFormat);
|
||||||
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ const int BUTTON_MARGIN = 8;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QPlainTextEdit;
|
class QPlainTextEdit;
|
||||||
class KeywordHighlighter;
|
class Highlighter;
|
||||||
|
|
||||||
class BaseLogDialog : public QDialog {
|
class BaseLogDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -56,7 +56,7 @@ private:
|
||||||
QPushButton* _searchPrevButton { nullptr };
|
QPushButton* _searchPrevButton { nullptr };
|
||||||
QPushButton* _searchNextButton { nullptr };
|
QPushButton* _searchNextButton { nullptr };
|
||||||
QString _searchTerm;
|
QString _searchTerm;
|
||||||
KeywordHighlighter* _highlighter { nullptr };
|
Highlighter* _highlighter { nullptr };
|
||||||
|
|
||||||
void initControls();
|
void initControls();
|
||||||
void showLogData();
|
void showLogData();
|
||||||
|
|
|
@ -45,13 +45,13 @@
|
||||||
#include <AudioReverb.h>
|
#include <AudioReverb.h>
|
||||||
#include <AudioLimiter.h>
|
#include <AudioLimiter.h>
|
||||||
#include <AudioConstants.h>
|
#include <AudioConstants.h>
|
||||||
|
#include <AudioNoiseGate.h>
|
||||||
|
|
||||||
#include <shared/RateCounter.h>
|
#include <shared/RateCounter.h>
|
||||||
|
|
||||||
#include <plugins/CodecPlugin.h>
|
#include <plugins/CodecPlugin.h>
|
||||||
|
|
||||||
#include "AudioIOStats.h"
|
#include "AudioIOStats.h"
|
||||||
#include "AudioNoiseGate.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma warning( push )
|
#pragma warning( push )
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// AudioNoiseGate.cpp
|
// AudioNoiseGate.cpp
|
||||||
// interface/src/audio
|
// libraries/audio
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 2014-12-16.
|
// Created by Stephen Birarda on 2014-12-16.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
@ -9,29 +9,23 @@
|
||||||
// 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 "AudioNoiseGate.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <AudioConstants.h>
|
#include "AudioConstants.h"
|
||||||
|
|
||||||
#include "AudioNoiseGate.h"
|
|
||||||
|
|
||||||
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
||||||
|
|
||||||
AudioNoiseGate::AudioNoiseGate() :
|
AudioNoiseGate::AudioNoiseGate() :
|
||||||
_inputBlockCounter(0),
|
|
||||||
_lastLoudness(0.0f),
|
_lastLoudness(0.0f),
|
||||||
_quietestBlock(std::numeric_limits<float>::max()),
|
|
||||||
_loudestBlock(0.0f),
|
|
||||||
_didClipInLastBlock(false),
|
_didClipInLastBlock(false),
|
||||||
_dcOffset(0.0f),
|
_dcOffset(0.0f),
|
||||||
_measuredFloor(0.0f),
|
_measuredFloor(0.0f),
|
||||||
_sampleCounter(0),
|
_sampleCounter(0),
|
||||||
_isOpen(false),
|
_isOpen(false),
|
||||||
_blocksToClose(0)
|
_blocksToClose(0) {}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||||
//
|
//
|
||||||
|
@ -104,20 +98,6 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
||||||
|
|
||||||
_lastLoudness = fabs(loudness / numSamples);
|
_lastLoudness = fabs(loudness / numSamples);
|
||||||
|
|
||||||
if (_quietestBlock > _lastLoudness) {
|
|
||||||
_quietestBlock = _lastLoudness;
|
|
||||||
}
|
|
||||||
if (_loudestBlock < _lastLoudness) {
|
|
||||||
_loudestBlock = _lastLoudness;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
|
||||||
if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
|
||||||
_quietestBlock = std::numeric_limits<float>::max();
|
|
||||||
_loudestBlock = 0.0f;
|
|
||||||
_inputBlockCounter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If Noise Gate is enabled, check and turn the gate on and off
|
// If Noise Gate is enabled, check and turn the gate on and off
|
||||||
float averageOfAllSampleBlocks = 0.0f;
|
float averageOfAllSampleBlocks = 0.0f;
|
||||||
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// AudioNoiseGate.h
|
// AudioNoiseGate.h
|
||||||
// interface/src/audio
|
// libraries/audio
|
||||||
//
|
//
|
||||||
// Created by Stephen Birarda on 2014-12-16.
|
// Created by Stephen Birarda on 2014-12-16.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
@ -33,10 +33,7 @@ public:
|
||||||
static const float CLIPPING_THRESHOLD;
|
static const float CLIPPING_THRESHOLD;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _inputBlockCounter;
|
|
||||||
float _lastLoudness;
|
float _lastLoudness;
|
||||||
float _quietestBlock;
|
|
||||||
float _loudestBlock;
|
|
||||||
bool _didClipInLastBlock;
|
bool _didClipInLastBlock;
|
||||||
float _dcOffset;
|
float _dcOffset;
|
||||||
float _measuredFloor;
|
float _measuredFloor;
|
|
@ -947,7 +947,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
||||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||||
|
|
|
@ -13,18 +13,31 @@
|
||||||
#define hifi_NodePermissions_h
|
#define hifi_NodePermissions_h
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
#include <QHash>
|
||||||
|
#include <utility>
|
||||||
#include "GroupRank.h"
|
#include "GroupRank.h"
|
||||||
|
|
||||||
class NodePermissions;
|
class NodePermissions;
|
||||||
using NodePermissionsPointer = std::shared_ptr<NodePermissions>;
|
using NodePermissionsPointer = std::shared_ptr<NodePermissions>;
|
||||||
using NodePermissionsKey = QPair<QString, QUuid>; // name, rankID
|
using NodePermissionsKey = std::pair<QString, QUuid>; // name, rankID
|
||||||
using NodePermissionsKeyList = QList<QPair<QString, QUuid>>;
|
using NodePermissionsKeyList = QList<QPair<QString, QUuid>>;
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<>
|
||||||
|
struct hash<NodePermissionsKey> {
|
||||||
|
size_t operator()(const NodePermissionsKey& key) const {
|
||||||
|
size_t result = qHash(key.first);
|
||||||
|
result <<= 32;
|
||||||
|
result |= qHash(key.second);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class NodePermissions {
|
class NodePermissions {
|
||||||
public:
|
public:
|
||||||
|
@ -100,27 +113,40 @@ public:
|
||||||
NodePermissionsMap() { }
|
NodePermissionsMap() { }
|
||||||
NodePermissionsPointer& operator[](const NodePermissionsKey& key) {
|
NodePermissionsPointer& operator[](const NodePermissionsKey& key) {
|
||||||
NodePermissionsKey dataKey(key.first.toLower(), key.second);
|
NodePermissionsKey dataKey(key.first.toLower(), key.second);
|
||||||
if (!_data.contains(dataKey)) {
|
if (0 == _data.count(dataKey)) {
|
||||||
_data[dataKey] = NodePermissionsPointer(new NodePermissions(key));
|
_data[dataKey] = NodePermissionsPointer(new NodePermissions(key));
|
||||||
}
|
}
|
||||||
return _data[dataKey];
|
return _data[dataKey];
|
||||||
}
|
}
|
||||||
NodePermissionsPointer operator[](const NodePermissionsKey& key) const {
|
NodePermissionsPointer operator[](const NodePermissionsKey& key) const {
|
||||||
return _data.value(NodePermissionsKey(key.first.toLower(), key.second));
|
NodePermissionsPointer result;
|
||||||
|
auto itr = _data.find(NodePermissionsKey(key.first.toLower(), key.second));
|
||||||
|
if (_data.end() != itr) {
|
||||||
|
result = itr->second;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
bool contains(const NodePermissionsKey& key) const {
|
bool contains(const NodePermissionsKey& key) const {
|
||||||
return _data.contains(NodePermissionsKey(key.first.toLower(), key.second));
|
return 0 != _data.count(NodePermissionsKey(key.first.toLower(), key.second));
|
||||||
}
|
}
|
||||||
bool contains(const QString& keyFirst, QUuid keySecond) const {
|
bool contains(const QString& keyFirst, const QUuid& keySecond) const {
|
||||||
return _data.contains(NodePermissionsKey(keyFirst.toLower(), keySecond));
|
return 0 != _data.count(NodePermissionsKey(keyFirst.toLower(), keySecond));
|
||||||
}
|
}
|
||||||
QList<NodePermissionsKey> keys() const { return _data.keys(); }
|
|
||||||
QHash<NodePermissionsKey, NodePermissionsPointer> get() { return _data; }
|
QList<NodePermissionsKey> keys() const {
|
||||||
|
QList<NodePermissionsKey> result;
|
||||||
|
for (const auto& entry : _data) {
|
||||||
|
result.push_back(entry.first);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<NodePermissionsKey, NodePermissionsPointer>& get() { return _data; }
|
||||||
void clear() { _data.clear(); }
|
void clear() { _data.clear(); }
|
||||||
void remove(const NodePermissionsKey& key) { _data.remove(key); }
|
void remove(const NodePermissionsKey& key) { _data.erase(key); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<NodePermissionsKey, NodePermissionsPointer> _data;
|
std::unordered_map<NodePermissionsKey, NodePermissionsPointer> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
|
|
||||||
using namespace udt;
|
using namespace udt;
|
||||||
|
|
||||||
|
PacketQueue::PacketQueue() {
|
||||||
|
_channels.emplace_back(new std::list<PacketPointer>());
|
||||||
|
}
|
||||||
|
|
||||||
MessageNumber PacketQueue::getNextMessageNumber() {
|
MessageNumber PacketQueue::getNextMessageNumber() {
|
||||||
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE;
|
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE;
|
||||||
_currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER;
|
_currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER;
|
||||||
|
@ -24,7 +28,7 @@ MessageNumber PacketQueue::getNextMessageNumber() {
|
||||||
bool PacketQueue::isEmpty() const {
|
bool PacketQueue::isEmpty() const {
|
||||||
LockGuard locker(_packetsLock);
|
LockGuard locker(_packetsLock);
|
||||||
// Only the main channel and it is empty
|
// Only the main channel and it is empty
|
||||||
return (_channels.size() == 1) && _channels.front().empty();
|
return (_channels.size() == 1) && _channels.front()->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketQueue::PacketPointer PacketQueue::takePacket() {
|
PacketQueue::PacketPointer PacketQueue::takePacket() {
|
||||||
|
@ -34,19 +38,19 @@ PacketQueue::PacketPointer PacketQueue::takePacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find next non empty channel
|
// Find next non empty channel
|
||||||
if (_channels[nextIndex()].empty()) {
|
if (_channels[nextIndex()]->empty()) {
|
||||||
nextIndex();
|
nextIndex();
|
||||||
}
|
}
|
||||||
auto& channel = _channels[_currentIndex];
|
auto& channel = _channels[_currentIndex];
|
||||||
Q_ASSERT(!channel.empty());
|
Q_ASSERT(!channel->empty());
|
||||||
|
|
||||||
// Take front packet
|
// Take front packet
|
||||||
auto packet = std::move(channel.front());
|
auto packet = std::move(channel->front());
|
||||||
channel.pop_front();
|
channel->pop_front();
|
||||||
|
|
||||||
// Remove now empty channel (Don't remove the main channel)
|
// Remove now empty channel (Don't remove the main channel)
|
||||||
if (channel.empty() && _currentIndex != 0) {
|
if (channel->empty() && _currentIndex != 0) {
|
||||||
channel.swap(_channels.back());
|
channel->swap(*_channels.back());
|
||||||
_channels.pop_back();
|
_channels.pop_back();
|
||||||
--_currentIndex;
|
--_currentIndex;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +65,7 @@ unsigned int PacketQueue::nextIndex() {
|
||||||
|
|
||||||
void PacketQueue::queuePacket(PacketPointer packet) {
|
void PacketQueue::queuePacket(PacketPointer packet) {
|
||||||
LockGuard locker(_packetsLock);
|
LockGuard locker(_packetsLock);
|
||||||
_channels.front().push_back(std::move(packet));
|
_channels.front()->push_back(std::move(packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
||||||
|
@ -70,5 +74,6 @@ void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LockGuard locker(_packetsLock);
|
LockGuard locker(_packetsLock);
|
||||||
_channels.push_back(std::move(packetList->_packets));
|
_channels.emplace_back(new std::list<PacketPointer>());
|
||||||
|
_channels.back()->swap(packetList->_packets);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,11 @@ class PacketQueue {
|
||||||
using LockGuard = std::lock_guard<Mutex>;
|
using LockGuard = std::lock_guard<Mutex>;
|
||||||
using PacketPointer = std::unique_ptr<Packet>;
|
using PacketPointer = std::unique_ptr<Packet>;
|
||||||
using PacketListPointer = std::unique_ptr<PacketList>;
|
using PacketListPointer = std::unique_ptr<PacketList>;
|
||||||
using Channel = std::list<PacketPointer>;
|
using Channel = std::unique_ptr<std::list<PacketPointer>>;
|
||||||
using Channels = std::vector<Channel>;
|
using Channels = std::vector<Channel>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
PacketQueue();
|
||||||
void queuePacket(PacketPointer packet);
|
void queuePacket(PacketPointer packet);
|
||||||
void queuePacketList(PacketListPointer packetList);
|
void queuePacketList(PacketListPointer packetList);
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ private:
|
||||||
MessageNumber _currentMessageNumber { 0 };
|
MessageNumber _currentMessageNumber { 0 };
|
||||||
|
|
||||||
mutable Mutex _packetsLock; // Protects the packets to be sent.
|
mutable Mutex _packetsLock; // Protects the packets to be sent.
|
||||||
Channels _channels = Channels(1); // One channel per packet list + Main channel
|
Channels _channels; // One channel per packet list + Main channel
|
||||||
unsigned int _currentIndex { 0 };
|
unsigned int _currentIndex { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ void Deck::queueClip(ClipPointer clip, float timeOffset) {
|
||||||
|
|
||||||
// FIXME disabling multiple clips for now
|
// FIXME disabling multiple clips for now
|
||||||
_clips.clear();
|
_clips.clear();
|
||||||
|
_length = 0.0f;
|
||||||
|
|
||||||
// if the time offset is not zero, wrap in an OffsetClip
|
// if the time offset is not zero, wrap in an OffsetClip
|
||||||
if (timeOffset != 0.0f) {
|
if (timeOffset != 0.0f) {
|
||||||
|
@ -153,8 +154,8 @@ void Deck::processFrames() {
|
||||||
// if doing relative movement
|
// if doing relative movement
|
||||||
emit looped();
|
emit looped();
|
||||||
} else {
|
} else {
|
||||||
// otherwise pause playback
|
// otherwise stop playback
|
||||||
pause();
|
stop();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,19 +372,12 @@ void ModelMeshPartPayload::notifyLocationChanged() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const QVector<glm::mat4>& clusterMatrices) {
|
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform,
|
||||||
_transform = transform;
|
const gpu::BufferPointer& buffer) {
|
||||||
|
_transform = renderTransform;
|
||||||
if (clusterMatrices.size() > 0) {
|
|
||||||
_worldBound = _adjustedLocalBound;
|
_worldBound = _adjustedLocalBound;
|
||||||
_worldBound.transform(_transform);
|
_worldBound.transform(boundTransform);
|
||||||
if (clusterMatrices.size() == 1) {
|
_clusterBuffer = buffer;
|
||||||
_transform = _transform.worldTransform(Transform(clusterMatrices[0]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_worldBound = _localBound;
|
|
||||||
_worldBound.transform(_transform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKey ModelMeshPartPayload::getKey() const {
|
ItemKey ModelMeshPartPayload::getKey() const {
|
||||||
|
@ -532,9 +525,8 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
|
|
||||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
||||||
// Still relying on the raw data from the model
|
// Still relying on the raw data from the model
|
||||||
const Model::MeshState& state = _model->getMeshState(_meshIndex);
|
if (_clusterBuffer) {
|
||||||
if (state.clusterBuffer) {
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer);
|
|
||||||
}
|
}
|
||||||
batch.setModelTransform(_transform);
|
batch.setModelTransform(_transform);
|
||||||
}
|
}
|
||||||
|
@ -590,8 +582,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
auto locations = args->_pipeline->locations;
|
auto locations = args->_pipeline->locations;
|
||||||
assert(locations);
|
assert(locations);
|
||||||
|
|
||||||
// Bind the model transform and the skinCLusterMatrices if needed
|
|
||||||
_model->updateClusterMatrices();
|
|
||||||
bindTransform(batch, locations, args->_renderMode);
|
bindTransform(batch, locations, args->_renderMode);
|
||||||
|
|
||||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||||
|
|
|
@ -89,8 +89,9 @@ public:
|
||||||
typedef Payload::DataPointer Pointer;
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
void notifyLocationChanged() override;
|
void notifyLocationChanged() override;
|
||||||
void updateTransformForSkinnedMesh(const Transform& transform,
|
void updateTransformForSkinnedMesh(const Transform& renderTransform,
|
||||||
const QVector<glm::mat4>& clusterMatrices);
|
const Transform& boundTransform,
|
||||||
|
const gpu::BufferPointer& buffer);
|
||||||
|
|
||||||
float computeFadeAlpha() const;
|
float computeFadeAlpha() const;
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ public:
|
||||||
|
|
||||||
void computeAdjustedLocalBound(const QVector<glm::mat4>& clusterMatrices);
|
void computeAdjustedLocalBound(const QVector<glm::mat4>& clusterMatrices);
|
||||||
|
|
||||||
|
gpu::BufferPointer _clusterBuffer;
|
||||||
Model* _model;
|
Model* _model;
|
||||||
|
|
||||||
int _meshIndex;
|
int _meshIndex;
|
||||||
|
|
|
@ -227,6 +227,10 @@ void Model::updateRenderItems() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lazy update of cluster matrices used for rendering.
|
||||||
|
// We need to update them here so we can correctly update the bounding box.
|
||||||
|
self->updateClusterMatrices();
|
||||||
|
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
|
||||||
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
|
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
|
||||||
|
@ -240,12 +244,12 @@ void Model::updateRenderItems() {
|
||||||
Transform modelTransform = data._model->getTransform();
|
Transform modelTransform = data._model->getTransform();
|
||||||
modelTransform.setScale(glm::vec3(1.0f));
|
modelTransform.setScale(glm::vec3(1.0f));
|
||||||
|
|
||||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
const Model::MeshState& state = data._model->getMeshState(data._meshIndex);
|
||||||
data._model->updateClusterMatrices();
|
Transform renderTransform = modelTransform;
|
||||||
|
if (state.clusterMatrices.size() == 1) {
|
||||||
// update the model transform and bounding box for this render item.
|
renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||||
const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex);
|
}
|
||||||
data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices);
|
data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -541,16 +541,6 @@ void ScriptEngine::init() {
|
||||||
|
|
||||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||||
entityScriptingInterface->init();
|
entityScriptingInterface->init();
|
||||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) {
|
|
||||||
if (_entityScripts.contains(entityID)) {
|
|
||||||
if (isEntityScriptRunning(entityID)) {
|
|
||||||
qCWarning(scriptengine) << "deletingEntity while entity script is still running!" << entityID;
|
|
||||||
}
|
|
||||||
_entityScripts.remove(entityID);
|
|
||||||
emit entityScriptDetailsUpdated();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// register various meta-types
|
// register various meta-types
|
||||||
registerMetaTypes(this);
|
registerMetaTypes(this);
|
||||||
|
@ -1844,7 +1834,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
processDeferredEntityLoads(entityScript, entityID);
|
processDeferredEntityLoads(entityScript, entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
#ifdef THREAD_DEBUGGING
|
#ifdef THREAD_DEBUGGING
|
||||||
qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||||
|
@ -1852,7 +1842,8 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "unloadEntityScript",
|
QMetaObject::invokeMethod(this, "unloadEntityScript",
|
||||||
Q_ARG(const EntityItemID&, entityID));
|
Q_ARG(const EntityItemID&, entityID),
|
||||||
|
Q_ARG(bool, shouldRemoveFromMap));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef THREAD_DEBUGGING
|
#ifdef THREAD_DEBUGGING
|
||||||
|
@ -1867,7 +1858,12 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||||
} else {
|
} else {
|
||||||
qCDebug(scriptengine) << "unload called while !running" << entityID << oldDetails.status;
|
qCDebug(scriptengine) << "unload called while !running" << entityID << oldDetails.status;
|
||||||
}
|
}
|
||||||
if (oldDetails.status != EntityScriptStatus::UNLOADED) {
|
|
||||||
|
if (shouldRemoveFromMap) {
|
||||||
|
// this was a deleted entity, we've been asked to remove it from the map
|
||||||
|
_entityScripts.remove(entityID);
|
||||||
|
emit entityScriptDetailsUpdated();
|
||||||
|
} else if (oldDetails.status != EntityScriptStatus::UNLOADED) {
|
||||||
EntityScriptDetails newDetails;
|
EntityScriptDetails newDetails;
|
||||||
newDetails.status = EntityScriptStatus::UNLOADED;
|
newDetails.status = EntityScriptStatus::UNLOADED;
|
||||||
newDetails.lastModified = QDateTime::currentMSecsSinceEpoch();
|
newDetails.lastModified = QDateTime::currentMSecsSinceEpoch();
|
||||||
|
@ -1875,6 +1871,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||||
newDetails.scriptText = oldDetails.scriptText;
|
newDetails.scriptText = oldDetails.scriptText;
|
||||||
setEntityScriptDetails(entityID, newDetails);
|
setEntityScriptDetails(entityID, newDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
stopAllTimersForEntityScript(entityID);
|
stopAllTimersForEntityScript(entityID);
|
||||||
{
|
{
|
||||||
// FIXME: shouldn't have to do this here, but currently something seems to be firing unloads moments after firing initial load requests
|
// FIXME: shouldn't have to do this here, but currently something seems to be firing unloads moments after firing initial load requests
|
||||||
|
|
|
@ -171,7 +171,7 @@ public:
|
||||||
return _entityScripts.contains(entityID) && _entityScripts[entityID].status == EntityScriptStatus::RUNNING;
|
return _entityScripts.contains(entityID) && _entityScripts[entityID].status == EntityScriptStatus::RUNNING;
|
||||||
}
|
}
|
||||||
Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload);
|
Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload);
|
||||||
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID); // will call unload method
|
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method
|
||||||
Q_INVOKABLE void unloadAllEntityScripts();
|
Q_INVOKABLE void unloadAllEntityScripts();
|
||||||
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName,
|
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName,
|
||||||
const QStringList& params = QStringList()) override;
|
const QStringList& params = QStringList()) override;
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
// 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
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/* globals HIFI_PUBLIC_BUCKET:true, Tool, ToolBar */
|
||||||
|
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
Script.include("/~/system/libraries/toolBars.js");
|
Script.include("/~/system/libraries/toolBars.js");
|
||||||
|
|
||||||
var recordingFile = "recording.hfr";
|
var recordingFile = "recording.hfr";
|
||||||
|
|
||||||
function setPlayerOptions() {
|
function setDefaultPlayerOptions() {
|
||||||
Recording.setPlayFromCurrentLocation(true);
|
Recording.setPlayFromCurrentLocation(true);
|
||||||
Recording.setPlayerUseDisplayName(false);
|
Recording.setPlayerUseDisplayName(false);
|
||||||
Recording.setPlayerUseAttachments(false);
|
Recording.setPlayerUseAttachments(false);
|
||||||
|
@ -38,16 +40,16 @@ var saveIcon;
|
||||||
var loadIcon;
|
var loadIcon;
|
||||||
var spacing;
|
var spacing;
|
||||||
var timerOffset;
|
var timerOffset;
|
||||||
setupToolBar();
|
|
||||||
|
|
||||||
var timer = null;
|
var timer = null;
|
||||||
var slider = null;
|
var slider = null;
|
||||||
|
|
||||||
|
setupToolBar();
|
||||||
setupTimer();
|
setupTimer();
|
||||||
|
|
||||||
var watchStop = false;
|
var watchStop = false;
|
||||||
|
|
||||||
function setupToolBar() {
|
function setupToolBar() {
|
||||||
if (toolBar != null) {
|
if (toolBar !== null) {
|
||||||
print("Multiple calls to Recorder.js:setupToolBar()");
|
print("Multiple calls to Recorder.js:setupToolBar()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +58,8 @@ function setupToolBar() {
|
||||||
|
|
||||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||||
|
|
||||||
|
toolBar.onMove = onToolbarMove;
|
||||||
|
|
||||||
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
||||||
|
|
||||||
recordIcon = toolBar.addTool({
|
recordIcon = toolBar.addTool({
|
||||||
|
@ -86,7 +90,7 @@ function setupToolBar() {
|
||||||
visible: true
|
visible: true
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
timerOffset = toolBar.width;
|
timerOffset = toolBar.width + ToolBar.SPACING;
|
||||||
spacing = toolBar.addSpacing(0);
|
spacing = toolBar.addSpacing(0);
|
||||||
|
|
||||||
saveIcon = toolBar.addTool({
|
saveIcon = toolBar.addTool({
|
||||||
|
@ -112,15 +116,15 @@ function setupTimer() {
|
||||||
text: (0.00).toFixed(3),
|
text: (0.00).toFixed(3),
|
||||||
backgroundColor: COLOR_OFF,
|
backgroundColor: COLOR_OFF,
|
||||||
x: 0, y: 0,
|
x: 0, y: 0,
|
||||||
width: 0, height: 0,
|
width: 200, height: 25,
|
||||||
leftMargin: 10, topMargin: 10,
|
leftMargin: 5, topMargin: 3,
|
||||||
alpha: 1.0, backgroundAlpha: 1.0,
|
alpha: 1.0, backgroundAlpha: 1.0,
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
|
|
||||||
slider = { x: 0, y: 0,
|
slider = { x: 0, y: 0,
|
||||||
w: 200, h: 20,
|
w: 200, h: 20,
|
||||||
pos: 0.0, // 0.0 <= pos <= 1.0
|
pos: 0.0 // 0.0 <= pos <= 1.0
|
||||||
};
|
};
|
||||||
slider.background = Overlays.addOverlay("text", {
|
slider.background = Overlays.addOverlay("text", {
|
||||||
text: "",
|
text: "",
|
||||||
|
@ -144,20 +148,40 @@ function setupTimer() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onToolbarMove(newX, newY, deltaX, deltaY) {
|
||||||
|
Overlays.editOverlay(timer, {
|
||||||
|
x: newX + timerOffset - ToolBar.SPACING,
|
||||||
|
y: newY
|
||||||
|
});
|
||||||
|
|
||||||
|
slider.x = newX - ToolBar.SPACING;
|
||||||
|
slider.y = newY - slider.h - ToolBar.SPACING;
|
||||||
|
|
||||||
|
Overlays.editOverlay(slider.background, {
|
||||||
|
x: slider.x,
|
||||||
|
y: slider.y
|
||||||
|
});
|
||||||
|
Overlays.editOverlay(slider.foreground, {
|
||||||
|
x: slider.x,
|
||||||
|
y: slider.y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function updateTimer() {
|
function updateTimer() {
|
||||||
var text = "";
|
var text = "";
|
||||||
if (Recording.isRecording()) {
|
if (Recording.isRecording()) {
|
||||||
text = formatTime(Recording.recorderElapsed());
|
text = formatTime(Recording.recorderElapsed());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
text = formatTime(Recording.playerElapsed()) + " / " +
|
text = formatTime(Recording.playerElapsed()) + " / " + formatTime(Recording.playerLength());
|
||||||
formatTime(Recording.playerLength());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var timerWidth = text.length * 8 + ((Recording.isRecording()) ? 15 : 0);
|
||||||
|
|
||||||
Overlays.editOverlay(timer, {
|
Overlays.editOverlay(timer, {
|
||||||
text: text
|
text: text,
|
||||||
})
|
width: timerWidth
|
||||||
toolBar.changeSpacing(text.length * 8 + ((Recording.isRecording()) ? 15 : 0), spacing);
|
});
|
||||||
|
toolBar.changeSpacing(timerWidth + ToolBar.SPACING, spacing);
|
||||||
|
|
||||||
if (Recording.isRecording()) {
|
if (Recording.isRecording()) {
|
||||||
slider.pos = 1.0;
|
slider.pos = 1.0;
|
||||||
|
@ -173,7 +197,7 @@ function updateTimer() {
|
||||||
function formatTime(time) {
|
function formatTime(time) {
|
||||||
var MIN_PER_HOUR = 60;
|
var MIN_PER_HOUR = 60;
|
||||||
var SEC_PER_MIN = 60;
|
var SEC_PER_MIN = 60;
|
||||||
var MSEC_PER_SEC = 1000;
|
var MSEC_DIGITS = 3;
|
||||||
|
|
||||||
var hours = Math.floor(time / (SEC_PER_MIN * MIN_PER_HOUR));
|
var hours = Math.floor(time / (SEC_PER_MIN * MIN_PER_HOUR));
|
||||||
time -= hours * (SEC_PER_MIN * MIN_PER_HOUR);
|
time -= hours * (SEC_PER_MIN * MIN_PER_HOUR);
|
||||||
|
@ -184,37 +208,19 @@ function formatTime(time) {
|
||||||
var seconds = time;
|
var seconds = time;
|
||||||
|
|
||||||
var text = "";
|
var text = "";
|
||||||
text += (hours > 0) ? hours + ":" :
|
text += (hours > 0) ? hours + ":" : "";
|
||||||
"";
|
text += (minutes > 0) ? ((minutes < 10 && text !== "") ? "0" : "") + minutes + ":" : "";
|
||||||
text += (minutes > 0) ? ((minutes < 10 && text != "") ? "0" : "") + minutes + ":" :
|
text += ((seconds < 10 && text !== "") ? "0" : "") + seconds.toFixed(MSEC_DIGITS);
|
||||||
"";
|
|
||||||
text += ((seconds < 10 && text != "") ? "0" : "") + seconds.toFixed(3);
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveUI() {
|
function moveUI() {
|
||||||
var relative = { x: 70, y: 40 };
|
var relative = { x: 70, y: 40 };
|
||||||
toolBar.move(relative.x, windowDimensions.y - relative.y);
|
toolBar.move(relative.x, windowDimensions.y - relative.y);
|
||||||
Overlays.editOverlay(timer, {
|
|
||||||
x: relative.x + timerOffset - ToolBar.SPACING,
|
|
||||||
y: windowDimensions.y - relative.y - ToolBar.SPACING
|
|
||||||
});
|
|
||||||
|
|
||||||
slider.x = relative.x - ToolBar.SPACING;
|
|
||||||
slider.y = windowDimensions.y - relative.y - slider.h - ToolBar.SPACING;
|
|
||||||
|
|
||||||
Overlays.editOverlay(slider.background, {
|
|
||||||
x: slider.x,
|
|
||||||
y: slider.y,
|
|
||||||
});
|
|
||||||
Overlays.editOverlay(slider.foreground, {
|
|
||||||
x: slider.x,
|
|
||||||
y: slider.y,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function mousePressEvent(event) {
|
function mousePressEvent(event) {
|
||||||
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()) {
|
||||||
|
@ -226,7 +232,11 @@ function mousePressEvent(event) {
|
||||||
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
||||||
} else {
|
} else {
|
||||||
Recording.stopRecording();
|
Recording.stopRecording();
|
||||||
toolBar.selectTool(recordIcon, true );
|
toolBar.selectTool(recordIcon, true);
|
||||||
|
setDefaultPlayerOptions();
|
||||||
|
// Plays the recording at the same spot as you recorded it
|
||||||
|
Recording.setPlayFromCurrentLocation(false);
|
||||||
|
Recording.setPlayerTime(0);
|
||||||
Recording.loadLastRecording();
|
Recording.loadLastRecording();
|
||||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||||
toolBar.setAlpha(ALPHA_ON, playLoopIcon);
|
toolBar.setAlpha(ALPHA_ON, playLoopIcon);
|
||||||
|
@ -240,7 +250,6 @@ function mousePressEvent(event) {
|
||||||
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
||||||
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
||||||
} else if (Recording.playerLength() > 0) {
|
} else if (Recording.playerLength() > 0) {
|
||||||
setPlayerOptions();
|
|
||||||
Recording.setPlayerLoop(false);
|
Recording.setPlayerLoop(false);
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
||||||
|
@ -255,7 +264,6 @@ function mousePressEvent(event) {
|
||||||
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
||||||
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
||||||
} else if (Recording.playerLength() > 0) {
|
} else if (Recording.playerLength() > 0) {
|
||||||
setPlayerOptions();
|
|
||||||
Recording.setPlayerLoop(true);
|
Recording.setPlayerLoop(true);
|
||||||
Recording.startPlaying();
|
Recording.startPlaying();
|
||||||
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
||||||
|
@ -263,7 +271,7 @@ function mousePressEvent(event) {
|
||||||
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
||||||
}
|
}
|
||||||
} else if (saveIcon === toolBar.clicked(clickedOverlay)) {
|
} else if (saveIcon === toolBar.clicked(clickedOverlay)) {
|
||||||
if (!Recording.isRecording() && !Recording.isPlaying() && Recording.playerLength() != 0) {
|
if (!Recording.isRecording() && !Recording.isPlaying() && Recording.playerLength() !== 0) {
|
||||||
recordingFile = Window.save("Save recording to file", ".", "Recordings (*.hfr)");
|
recordingFile = Window.save("Save recording to file", ".", "Recordings (*.hfr)");
|
||||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||||
Recording.saveRecording(recordingFile);
|
Recording.saveRecording(recordingFile);
|
||||||
|
@ -274,6 +282,7 @@ function mousePressEvent(event) {
|
||||||
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);
|
||||||
|
setDefaultPlayerOptions();
|
||||||
}
|
}
|
||||||
if (Recording.playerLength() > 0) {
|
if (Recording.playerLength() > 0) {
|
||||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||||
|
@ -308,7 +317,7 @@ function mouseReleaseEvent(event) {
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
var newDimensions = Controller.getViewportDimensions();
|
var newDimensions = Controller.getViewportDimensions();
|
||||||
if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) {
|
if (windowDimensions.x !== newDimensions.x || windowDimensions.y !== newDimensions.y) {
|
||||||
windowDimensions = newDimensions;
|
windowDimensions = newDimensions;
|
||||||
moveUI();
|
moveUI();
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
this.spacing = [];
|
this.spacing = [];
|
||||||
|
this.onMove = null;
|
||||||
|
|
||||||
this.addTool = function(properties, selectable, selected) {
|
this.addTool = function(properties, selectable, selected) {
|
||||||
if (direction == ToolBar.HORIZONTAL) {
|
if (direction == ToolBar.HORIZONTAL) {
|
||||||
|
@ -254,6 +255,9 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
||||||
y: y - ToolBar.SPACING
|
y: y - ToolBar.SPACING
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.onMove !== null) {
|
||||||
|
this.onMove(x, y, dx, dy);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setAlpha = function(alpha, tool) {
|
this.setAlpha = function(alpha, tool) {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Script.include("/~/system/libraries/utils.js");
|
Script.include("/~/system/libraries/utils.js");
|
||||||
|
|
||||||
var SETTING_KEY = "com.highfidelity.avatar.isSitting";
|
var SETTING_KEY = "com.highfidelity.avatar.isSitting";
|
||||||
var ROLE = "fly";
|
|
||||||
var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx";
|
var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx";
|
||||||
var ANIMATION_FPS = 30;
|
var ANIMATION_FPS = 30;
|
||||||
var ANIMATION_FIRST_FRAME = 1;
|
var ANIMATION_FIRST_FRAME = 1;
|
||||||
|
@ -10,23 +9,25 @@
|
||||||
var RELEASE_KEYS = ['w', 'a', 's', 'd', 'UP', 'LEFT', 'DOWN', 'RIGHT'];
|
var RELEASE_KEYS = ['w', 'a', 's', 'd', 'UP', 'LEFT', 'DOWN', 'RIGHT'];
|
||||||
var RELEASE_TIME = 500; // ms
|
var RELEASE_TIME = 500; // ms
|
||||||
var RELEASE_DISTANCE = 0.2; // meters
|
var RELEASE_DISTANCE = 0.2; // meters
|
||||||
var MAX_IK_ERROR = 20;
|
var MAX_IK_ERROR = 30;
|
||||||
var DESKTOP_UI_CHECK_INTERVAL = 250;
|
var DESKTOP_UI_CHECK_INTERVAL = 100;
|
||||||
var DESKTOP_MAX_DISTANCE = 5;
|
var DESKTOP_MAX_DISTANCE = 5;
|
||||||
var SIT_DELAY = 25
|
var SIT_DELAY = 25
|
||||||
|
var MAX_RESET_DISTANCE = 0.5
|
||||||
|
|
||||||
this.entityID = null;
|
this.entityID = null;
|
||||||
this.timers = {};
|
this.timers = {};
|
||||||
this.animStateHandlerID = null;
|
this.animStateHandlerID = null;
|
||||||
|
this.interval = null;
|
||||||
|
|
||||||
this.preload = function(entityID) {
|
this.preload = function(entityID) {
|
||||||
this.entityID = entityID;
|
this.entityID = entityID;
|
||||||
}
|
}
|
||||||
this.unload = function() {
|
this.unload = function() {
|
||||||
if (MyAvatar.sessionUUID === this.getSeatUser()) {
|
if (Settings.getValue(SETTING_KEY) === this.entityID) {
|
||||||
this.sitUp(this.entityID);
|
this.sitUp();
|
||||||
}
|
}
|
||||||
if (this.interval) {
|
if (this.interval !== null) {
|
||||||
Script.clearInterval(this.interval);
|
Script.clearInterval(this.interval);
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
}
|
}
|
||||||
|
@ -34,10 +35,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setSeatUser = function(user) {
|
this.setSeatUser = function(user) {
|
||||||
|
try {
|
||||||
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
||||||
userData = JSON.parse(userData);
|
userData = JSON.parse(userData);
|
||||||
|
|
||||||
if (user) {
|
if (user !== null) {
|
||||||
userData.seat.user = user;
|
userData.seat.user = user;
|
||||||
} else {
|
} else {
|
||||||
delete userData.seat.user;
|
delete userData.seat.user;
|
||||||
|
@ -46,30 +48,47 @@
|
||||||
Entities.editEntity(this.entityID, {
|
Entities.editEntity(this.entityID, {
|
||||||
userData: JSON.stringify(userData)
|
userData: JSON.stringify(userData)
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
// Do Nothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.getSeatUser = function() {
|
this.getSeatUser = function() {
|
||||||
|
try {
|
||||||
var properties = Entities.getEntityProperties(this.entityID, ["userData", "position"]);
|
var properties = Entities.getEntityProperties(this.entityID, ["userData", "position"]);
|
||||||
var userData = JSON.parse(properties.userData);
|
var userData = JSON.parse(properties.userData);
|
||||||
|
|
||||||
if (userData.seat.user && userData.seat.user !== MyAvatar.sessionUUID) {
|
// If MyAvatar return my uuid
|
||||||
var avatar = AvatarList.getAvatar(userData.seat.user);
|
if (userData.seat.user === MyAvatar.sessionUUID) {
|
||||||
if (avatar && Vec3.distance(avatar.position, properties.position) > RELEASE_DISTANCE) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return userData.seat.user;
|
return userData.seat.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If Avatar appears to be sitting
|
||||||
|
if (userData.seat.user) {
|
||||||
|
var avatar = AvatarList.getAvatar(userData.seat.user);
|
||||||
|
if (avatar && (Vec3.distance(avatar.position, properties.position) < RELEASE_DISTANCE)) {
|
||||||
|
return userData.seat.user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nobody on the seat
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the seat used
|
||||||
this.checkSeatForAvatar = function() {
|
this.checkSeatForAvatar = function() {
|
||||||
var seatUser = this.getSeatUser();
|
var seatUser = this.getSeatUser();
|
||||||
var avatarIdentifiers = AvatarList.getAvatarIdentifiers();
|
|
||||||
for (var i in avatarIdentifiers) {
|
// If MyAvatar appears to be sitting
|
||||||
var avatar = AvatarList.getAvatar(avatarIdentifiers[i]);
|
if (seatUser === MyAvatar.sessionUUID) {
|
||||||
if (avatar && avatar.sessionUUID === seatUser) {
|
var properties = Entities.getEntityProperties(this.entityID, ["position"]);
|
||||||
return true;
|
return Vec3.distance(MyAvatar.position, properties.position) < RELEASE_DISTANCE;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return seatUser !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sitDown = function() {
|
this.sitDown = function() {
|
||||||
|
@ -78,40 +97,50 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setSeatUser(MyAvatar.sessionUUID);
|
|
||||||
|
|
||||||
var previousValue = Settings.getValue(SETTING_KEY);
|
var previousValue = Settings.getValue(SETTING_KEY);
|
||||||
Settings.setValue(SETTING_KEY, this.entityID);
|
Settings.setValue(SETTING_KEY, this.entityID);
|
||||||
|
this.setSeatUser(MyAvatar.sessionUUID);
|
||||||
if (previousValue === "") {
|
if (previousValue === "") {
|
||||||
MyAvatar.characterControllerEnabled = false;
|
MyAvatar.characterControllerEnabled = false;
|
||||||
MyAvatar.hmdLeanRecenterEnabled = false;
|
MyAvatar.hmdLeanRecenterEnabled = false;
|
||||||
MyAvatar.overrideRoleAnimation(ROLE, ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME);
|
var ROLES = MyAvatar.getAnimationRoles();
|
||||||
|
for (i in ROLES) {
|
||||||
|
MyAvatar.overrideRoleAnimation(ROLES[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME);
|
||||||
|
}
|
||||||
MyAvatar.resetSensorsAndBody();
|
MyAvatar.resetSensorsAndBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
var that = this;
|
var properties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
|
||||||
Script.setTimeout(function() {
|
|
||||||
var properties = Entities.getEntityProperties(that.entityID, ["position", "rotation"]);
|
|
||||||
var index = MyAvatar.getJointIndex("Hips");
|
var index = MyAvatar.getJointIndex("Hips");
|
||||||
MyAvatar.pinJoint(index, properties.position, properties.rotation);
|
MyAvatar.pinJoint(index, properties.position, properties.rotation);
|
||||||
|
|
||||||
that.animStateHandlerID = MyAvatar.addAnimationStateHandler(function(properties) {
|
this.animStateHandlerID = MyAvatar.addAnimationStateHandler(function(properties) {
|
||||||
return { headType: 0 };
|
return { headType: 0 };
|
||||||
}, ["headType"]);
|
}, ["headType"]);
|
||||||
Script.update.connect(that, that.update);
|
Script.update.connect(this, this.update);
|
||||||
Controller.keyPressEvent.connect(that, that.keyPressed);
|
Controller.keyPressEvent.connect(this, this.keyPressed);
|
||||||
Controller.keyReleaseEvent.connect(that, that.keyReleased);
|
Controller.keyReleaseEvent.connect(this, this.keyReleased);
|
||||||
for (var i in RELEASE_KEYS) {
|
for (var i in RELEASE_KEYS) {
|
||||||
Controller.captureKeyEvents({ text: RELEASE_KEYS[i] });
|
Controller.captureKeyEvents({ text: RELEASE_KEYS[i] });
|
||||||
}
|
}
|
||||||
}, SIT_DELAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sitUp = function() {
|
this.sitUp = function() {
|
||||||
this.setSeatUser(null);
|
MyAvatar.removeAnimationStateHandler(this.animStateHandlerID);
|
||||||
|
Script.update.disconnect(this, this.update);
|
||||||
|
Controller.keyPressEvent.disconnect(this, this.keyPressed);
|
||||||
|
Controller.keyReleaseEvent.disconnect(this, this.keyReleased);
|
||||||
|
for (var i in RELEASE_KEYS) {
|
||||||
|
Controller.releaseKeyEvents({ text: RELEASE_KEYS[i] });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setSeatUser(null);
|
||||||
if (Settings.getValue(SETTING_KEY) === this.entityID) {
|
if (Settings.getValue(SETTING_KEY) === this.entityID) {
|
||||||
MyAvatar.restoreRoleAnimation(ROLE);
|
Settings.setValue(SETTING_KEY, "");
|
||||||
|
var ROLES = MyAvatar.getAnimationRoles();
|
||||||
|
for (i in ROLES) {
|
||||||
|
MyAvatar.restoreRoleAnimation(ROLES[i]);
|
||||||
|
}
|
||||||
MyAvatar.characterControllerEnabled = true;
|
MyAvatar.characterControllerEnabled = true;
|
||||||
MyAvatar.hmdLeanRecenterEnabled = true;
|
MyAvatar.hmdLeanRecenterEnabled = true;
|
||||||
|
|
||||||
|
@ -124,16 +153,6 @@
|
||||||
MyAvatar.bodyPitch = 0.0;
|
MyAvatar.bodyPitch = 0.0;
|
||||||
MyAvatar.bodyRoll = 0.0;
|
MyAvatar.bodyRoll = 0.0;
|
||||||
}, SIT_DELAY);
|
}, SIT_DELAY);
|
||||||
|
|
||||||
Settings.setValue(SETTING_KEY, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
MyAvatar.removeAnimationStateHandler(this.animStateHandlerID);
|
|
||||||
Script.update.disconnect(this, this.update);
|
|
||||||
Controller.keyPressEvent.disconnect(this, this.keyPressed);
|
|
||||||
Controller.keyReleaseEvent.disconnect(this, this.keyReleased);
|
|
||||||
for (var i in RELEASE_KEYS) {
|
|
||||||
Controller.releaseKeyEvents({ text: RELEASE_KEYS[i] });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,15 +202,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.update = function(dt) {
|
this.update = function(dt) {
|
||||||
if (MyAvatar.sessionUUID === this.getSeatUser()) {
|
if (MyAvatar.sessionUUID === this.getSeatUser()) {
|
||||||
var properties = Entities.getEntityProperties(this.entityID, ["position"]);
|
var properties = Entities.getEntityProperties(this.entityID);
|
||||||
var avatarDistance = Vec3.distance(MyAvatar.position, properties.position);
|
var avatarDistance = Vec3.distance(MyAvatar.position, properties.position);
|
||||||
var ikError = MyAvatar.getIKErrorOnLastSolve();
|
var ikError = MyAvatar.getIKErrorOnLastSolve();
|
||||||
if (avatarDistance > RELEASE_DISTANCE || ikError > MAX_IK_ERROR) {
|
if (avatarDistance > RELEASE_DISTANCE || ikError > MAX_IK_ERROR) {
|
||||||
print("IK error: " + ikError + ", distance from chair: " + avatarDistance);
|
print("IK error: " + ikError + ", distance from chair: " + avatarDistance);
|
||||||
this.sitUp(this.entityID);
|
|
||||||
|
// Move avatar in front of the chair to avoid getting stuck in collision hulls
|
||||||
|
if (avatarDistance < MAX_RESET_DISTANCE) {
|
||||||
|
var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z };
|
||||||
|
var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset));
|
||||||
|
MyAvatar.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sitUp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +229,18 @@
|
||||||
if (RELEASE_KEYS.indexOf(event.text) !== -1) {
|
if (RELEASE_KEYS.indexOf(event.text) !== -1) {
|
||||||
var that = this;
|
var that = this;
|
||||||
this.timers[event.text] = Script.setTimeout(function() {
|
this.timers[event.text] = Script.setTimeout(function() {
|
||||||
|
delete that.timers[event.text];
|
||||||
|
|
||||||
|
var properties = Entities.getEntityProperties(that.entityID);
|
||||||
|
var avatarDistance = Vec3.distance(MyAvatar.position, properties.position);
|
||||||
|
|
||||||
|
// Move avatar in front of the chair to avoid getting stuck in collision hulls
|
||||||
|
if (avatarDistance < MAX_RESET_DISTANCE) {
|
||||||
|
var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z };
|
||||||
|
var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset));
|
||||||
|
MyAvatar.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
that.sitUp();
|
that.sitUp();
|
||||||
}, RELEASE_TIME);
|
}, RELEASE_TIME);
|
||||||
}
|
}
|
||||||
|
@ -223,7 +261,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hoverEnterEntity = function(event) {
|
this.hoverEnterEntity = function(event) {
|
||||||
if (isInEditMode() || (MyAvatar.sessionUUID === this.getSeatUser())) {
|
if (isInEditMode() || this.interval !== null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,18 +277,18 @@
|
||||||
}, DESKTOP_UI_CHECK_INTERVAL);
|
}, DESKTOP_UI_CHECK_INTERVAL);
|
||||||
}
|
}
|
||||||
this.hoverLeaveEntity = function(event) {
|
this.hoverLeaveEntity = function(event) {
|
||||||
if (this.interval) {
|
if (this.interval !== null) {
|
||||||
Script.clearInterval(this.interval);
|
Script.clearInterval(this.interval);
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
}
|
}
|
||||||
this.cleanupOverlay();
|
this.cleanupOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clickDownOnEntity = function () {
|
this.clickDownOnEntity = function (id, event) {
|
||||||
if (isInEditMode() || (MyAvatar.sessionUUID === this.getSeatUser())) {
|
if (isInEditMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.canSitDesktop()) {
|
if (event.isPrimaryButton && this.canSitDesktop()) {
|
||||||
this.sitDown();
|
this.sitDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,5 @@ set_target_properties(ac-client PROPERTIES FOLDER "Tools")
|
||||||
add_subdirectory(skeleton-dump)
|
add_subdirectory(skeleton-dump)
|
||||||
set_target_properties(skeleton-dump PROPERTIES FOLDER "Tools")
|
set_target_properties(skeleton-dump PROPERTIES FOLDER "Tools")
|
||||||
|
|
||||||
|
add_subdirectory(atp-get)
|
||||||
|
set_target_properties(atp-get PROPERTIES FOLDER "Tools")
|
||||||
|
|
3
tools/atp-get/CMakeLists.txt
Normal file
3
tools/atp-get/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
set(TARGET_NAME atp-get)
|
||||||
|
setup_hifi_project(Core Widgets)
|
||||||
|
link_hifi_libraries(shared networking)
|
269
tools/atp-get/src/ATPGetApp.cpp
Normal file
269
tools/atp-get/src/ATPGetApp.cpp
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
//
|
||||||
|
// ATPGetApp.cpp
|
||||||
|
// tools/atp-get/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2017-3-15
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QThread>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <NetworkLogging.h>
|
||||||
|
#include <SharedLogging.h>
|
||||||
|
#include <AddressManager.h>
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <SettingHandle.h>
|
||||||
|
|
||||||
|
#include "ATPGetApp.h"
|
||||||
|
|
||||||
|
ATPGetApp::ATPGetApp(int argc, char* argv[]) :
|
||||||
|
QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
// parse command-line
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.setApplicationDescription("High Fidelity ATP-Get");
|
||||||
|
|
||||||
|
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||||
|
|
||||||
|
const QCommandLineOption verboseOutput("v", "verbose output");
|
||||||
|
parser.addOption(verboseOutput);
|
||||||
|
|
||||||
|
const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1");
|
||||||
|
parser.addOption(domainAddressOption);
|
||||||
|
|
||||||
|
const QCommandLineOption cacheSTUNOption("s", "cache stun-server response");
|
||||||
|
parser.addOption(cacheSTUNOption);
|
||||||
|
|
||||||
|
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
|
||||||
|
parser.addOption(listenPortOption);
|
||||||
|
|
||||||
|
|
||||||
|
if (!parser.parse(QCoreApplication::arguments())) {
|
||||||
|
qCritical() << parser.errorText() << endl;
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.isSet(helpOption)) {
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
_verbose = parser.isSet(verboseOutput);
|
||||||
|
if (!_verbose) {
|
||||||
|
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
|
||||||
|
|
||||||
|
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtDebugMsg, false);
|
||||||
|
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtInfoMsg, false);
|
||||||
|
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtWarningMsg, false);
|
||||||
|
|
||||||
|
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtDebugMsg, false);
|
||||||
|
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
|
||||||
|
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QStringList filenames = parser.positionalArguments();
|
||||||
|
if (filenames.empty() || filenames.size() > 2) {
|
||||||
|
qDebug() << "give remote url and optional local filename as arguments";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
_url = QUrl(filenames[0]);
|
||||||
|
if (_url.scheme() != "atp") {
|
||||||
|
qDebug() << "url should start with atp:";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filenames.size() == 2) {
|
||||||
|
_localOutputFile = filenames[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
QString domainServerAddress = "127.0.0.1:40103";
|
||||||
|
if (parser.isSet(domainAddressOption)) {
|
||||||
|
domainServerAddress = parser.value(domainAddressOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_verbose) {
|
||||||
|
qDebug() << "domain-server address is" << domainServerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
int listenPort = INVALID_PORT;
|
||||||
|
if (parser.isSet(listenPortOption)) {
|
||||||
|
listenPort = parser.value(listenPortOption).toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting::init();
|
||||||
|
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||||
|
|
||||||
|
DependencyManager::set<AccountManager>([&]{ return QString("Mozilla/5.0 (HighFidelityATPGet)"); });
|
||||||
|
DependencyManager::set<AddressManager>();
|
||||||
|
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||||
|
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// start the nodeThread so its event loop is running
|
||||||
|
QThread* nodeThread = new QThread(this);
|
||||||
|
nodeThread->setObjectName("NodeList Thread");
|
||||||
|
nodeThread->start();
|
||||||
|
|
||||||
|
// make sure the node thread is given highest priority
|
||||||
|
nodeThread->setPriority(QThread::TimeCriticalPriority);
|
||||||
|
|
||||||
|
// setup a timer for domain-server check ins
|
||||||
|
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
|
||||||
|
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
|
||||||
|
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||||
|
|
||||||
|
// put the NodeList and datagram processing on the node thread
|
||||||
|
nodeList->moveToThread(nodeThread);
|
||||||
|
|
||||||
|
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||||
|
|
||||||
|
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||||
|
// connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
||||||
|
// connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||||
|
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ATPGetApp::domainConnectionRefused);
|
||||||
|
|
||||||
|
connect(nodeList.data(), &NodeList::nodeAdded, this, &ATPGetApp::nodeAdded);
|
||||||
|
connect(nodeList.data(), &NodeList::nodeKilled, this, &ATPGetApp::nodeKilled);
|
||||||
|
connect(nodeList.data(), &NodeList::nodeActivated, this, &ATPGetApp::nodeActivated);
|
||||||
|
// connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
|
||||||
|
// connect(nodeList.data(), &NodeList::uuidChanged, this, &ATPGetApp::setSessionUUID);
|
||||||
|
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ATPGetApp::notifyPacketVersionMismatch);
|
||||||
|
|
||||||
|
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||||
|
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
|
||||||
|
|
||||||
|
DependencyManager::get<AddressManager>()->handleLookupString(domainServerAddress, false);
|
||||||
|
|
||||||
|
auto assetClient = DependencyManager::set<AssetClient>();
|
||||||
|
assetClient->init();
|
||||||
|
|
||||||
|
QTimer* doTimer = new QTimer(this);
|
||||||
|
doTimer->setSingleShot(true);
|
||||||
|
connect(doTimer, &QTimer::timeout, this, &ATPGetApp::timedOut);
|
||||||
|
doTimer->start(4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
ATPGetApp::~ATPGetApp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ATPGetApp::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
||||||
|
qDebug() << "domainConnectionRefused";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::domainChanged(const QString& domainHostname) {
|
||||||
|
if (_verbose) {
|
||||||
|
qDebug() << "domainChanged";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::nodeAdded(SharedNodePointer node) {
|
||||||
|
if (_verbose) {
|
||||||
|
qDebug() << "node added: " << node->getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::nodeActivated(SharedNodePointer node) {
|
||||||
|
if (node->getType() == NodeType::AssetServer) {
|
||||||
|
lookup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::nodeKilled(SharedNodePointer node) {
|
||||||
|
qDebug() << "nodeKilled";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::timedOut() {
|
||||||
|
finish(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::notifyPacketVersionMismatch() {
|
||||||
|
if (_verbose) {
|
||||||
|
qDebug() << "packet version mismatch";
|
||||||
|
}
|
||||||
|
finish(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::lookup() {
|
||||||
|
|
||||||
|
auto path = _url.path();
|
||||||
|
qDebug() << "path is " << path;
|
||||||
|
|
||||||
|
auto request = DependencyManager::get<AssetClient>()->createGetMappingRequest(path);
|
||||||
|
QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable {
|
||||||
|
auto result = request->getError();
|
||||||
|
if (result == GetMappingRequest::NotFound) {
|
||||||
|
qDebug() << "not found";
|
||||||
|
} else if (result == GetMappingRequest::NoError) {
|
||||||
|
qDebug() << "found, hash is " << request->getHash();
|
||||||
|
download(request->getHash());
|
||||||
|
} else {
|
||||||
|
qDebug() << "error -- " << request->getError() << " -- " << request->getErrorString();
|
||||||
|
}
|
||||||
|
request->deleteLater();
|
||||||
|
});
|
||||||
|
request->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::download(AssetHash hash) {
|
||||||
|
auto assetClient = DependencyManager::get<AssetClient>();
|
||||||
|
auto assetRequest = new AssetRequest(hash);
|
||||||
|
|
||||||
|
connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) mutable {
|
||||||
|
Q_ASSERT(request->getState() == AssetRequest::Finished);
|
||||||
|
|
||||||
|
if (request->getError() == AssetRequest::Error::NoError) {
|
||||||
|
QString data = QString::fromUtf8(request->getData());
|
||||||
|
if (_localOutputFile == "") {
|
||||||
|
QTextStream cout(stdout);
|
||||||
|
cout << data;
|
||||||
|
} else {
|
||||||
|
QFile outputHandle(_localOutputFile);
|
||||||
|
if (outputHandle.open(QIODevice::ReadWrite)) {
|
||||||
|
QTextStream stream( &outputHandle );
|
||||||
|
stream << data;
|
||||||
|
} else {
|
||||||
|
qDebug() << "couldn't open output file:" << _localOutputFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request->deleteLater();
|
||||||
|
finish(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
assetRequest->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATPGetApp::finish(int exitCode) {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// send the domain a disconnect packet, force stoppage of domain-server check-ins
|
||||||
|
nodeList->getDomainHandler().disconnect();
|
||||||
|
nodeList->setIsShuttingDown(true);
|
||||||
|
|
||||||
|
// tell the packet receiver we're shutting down, so it can drop packets
|
||||||
|
nodeList->getPacketReceiver().setShouldDropPackets(true);
|
||||||
|
|
||||||
|
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
||||||
|
// remove the NodeList from the DependencyManager
|
||||||
|
DependencyManager::destroy<NodeList>();
|
||||||
|
// ask the node thread to quit and wait until it is done
|
||||||
|
nodeThread->quit();
|
||||||
|
nodeThread->wait();
|
||||||
|
|
||||||
|
QCoreApplication::exit(exitCode);
|
||||||
|
}
|
52
tools/atp-get/src/ATPGetApp.h
Normal file
52
tools/atp-get/src/ATPGetApp.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// ATPGetApp.h
|
||||||
|
// tools/atp-get/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2017-3-15
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef hifi_ATPGetApp_h
|
||||||
|
#define hifi_ATPGetApp_h
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <udt/Constants.h>
|
||||||
|
#include <udt/Socket.h>
|
||||||
|
#include <ReceivedMessage.h>
|
||||||
|
#include <NetworkPeer.h>
|
||||||
|
#include <NodeList.h>
|
||||||
|
#include <AssetRequest.h>
|
||||||
|
#include <MappingRequest.h>
|
||||||
|
|
||||||
|
|
||||||
|
class ATPGetApp : public QCoreApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ATPGetApp(int argc, char* argv[]);
|
||||||
|
~ATPGetApp();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo);
|
||||||
|
void domainChanged(const QString& domainHostname);
|
||||||
|
void nodeAdded(SharedNodePointer node);
|
||||||
|
void nodeActivated(SharedNodePointer node);
|
||||||
|
void nodeKilled(SharedNodePointer node);
|
||||||
|
void notifyPacketVersionMismatch();
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeList* _nodeList;
|
||||||
|
void timedOut();
|
||||||
|
void lookup();
|
||||||
|
void download(AssetHash hash);
|
||||||
|
void finish(int exitCode);
|
||||||
|
bool _verbose;
|
||||||
|
|
||||||
|
QUrl _url;
|
||||||
|
QString _localOutputFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ATPGetApp_h
|
31
tools/atp-get/src/main.cpp
Normal file
31
tools/atp-get/src/main.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// main.cpp
|
||||||
|
// tools/atp-get/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2017-3-15
|
||||||
|
// Copyright 2017 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
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <BuildInfo.h>
|
||||||
|
|
||||||
|
#include "ATPGetApp.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
QCoreApplication::setApplicationName(BuildInfo::AC_CLIENT_SERVER_NAME);
|
||||||
|
QCoreApplication::setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||||
|
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||||
|
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||||
|
|
||||||
|
ATPGetApp app(argc, argv);
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
Loading…
Reference in a new issue