mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 16:41:02 +02:00
Merge branch 'master' into 21114-part3
This commit is contained in:
commit
87d62ad1eb
15 changed files with 152 additions and 122 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
if (_cauterizedClusterBuffer) {
|
||||||
const Model::MeshState& cState = skeleton->getCauterizeMeshState(_meshIndex);
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer);
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, cState.clusterBuffer);
|
}
|
||||||
} else {
|
batch.setModelTransform(_cauterizedTransform);
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer);
|
} else {
|
||||||
|
if (_clusterBuffer) {
|
||||||
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||||
}
|
}
|
||||||
batch.setModelTransform(_transform);
|
batch.setModelTransform(_transform);
|
||||||
} else {
|
|
||||||
if (useCauterizedMesh) {
|
|
||||||
batch.setModelTransform(_cauterizedTransform);
|
|
||||||
} else {
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,8 @@ CauterizedModel::~CauterizedModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedModel::deleteGeometry() {
|
void CauterizedModel::deleteGeometry() {
|
||||||
Model::deleteGeometry();
|
Model::deleteGeometry();
|
||||||
_cauterizeMeshStates.clear();
|
_cauterizeMeshStates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CauterizedModel::updateGeometry() {
|
bool CauterizedModel::updateGeometry() {
|
||||||
|
@ -41,7 +41,7 @@ bool CauterizedModel::updateGeometry() {
|
||||||
_cauterizeMeshStates.append(state);
|
_cauterizeMeshStates.append(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return needsFullUpdate;
|
return needsFullUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedModel::createVisibleRenderItemSet() {
|
void CauterizedModel::createVisibleRenderItemSet() {
|
||||||
|
@ -86,13 +86,13 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Model::createVisibleRenderItemSet();
|
Model::createVisibleRenderItemSet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedModel::createCollisionRenderItemSet() {
|
void CauterizedModel::createCollisionRenderItemSet() {
|
||||||
// Temporary HACK: use base class method for now
|
// Temporary HACK: use base class method for now
|
||||||
Model::createCollisionRenderItemSet();
|
Model::createCollisionRenderItemSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedModel::updateClusterMatrices() {
|
void CauterizedModel::updateClusterMatrices() {
|
||||||
|
@ -122,8 +122,8 @@ void CauterizedModel::updateClusterMatrices() {
|
||||||
state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
|
state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
|
||||||
(const gpu::Byte*) state.clusterMatrices.constData());
|
(const gpu::Byte*) state.clusterMatrices.constData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
|
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
|
||||||
if (!_cauterizeBoneSet.empty()) {
|
if (!_cauterizeBoneSet.empty()) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -89,7 +95,7 @@ void BaseLogDialog::initControls() {
|
||||||
_leftPad += SEARCH_TOGGLE_BUTTON_WIDTH + BUTTON_MARGIN;
|
_leftPad += SEARCH_TOGGLE_BUTTON_WIDTH + BUTTON_MARGIN;
|
||||||
_searchPrevButton->show();
|
_searchPrevButton->show();
|
||||||
connect(_searchPrevButton, SIGNAL(clicked()), SLOT(toggleSearchPrev()));
|
connect(_searchPrevButton, SIGNAL(clicked()), SLOT(toggleSearchPrev()));
|
||||||
|
|
||||||
_searchNextButton = new QPushButton(this);
|
_searchNextButton = new QPushButton(this);
|
||||||
_searchNextButton->setObjectName("searchNextButton");
|
_searchNextButton->setObjectName("searchNextButton");
|
||||||
_searchNextButton->setGeometry(_leftPad, ELEMENT_MARGIN, SEARCH_TOGGLE_BUTTON_WIDTH, ELEMENT_HEIGHT);
|
_searchNextButton->setGeometry(_leftPad, ELEMENT_MARGIN, SEARCH_TOGGLE_BUTTON_WIDTH, ELEMENT_HEIGHT);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +135,7 @@ void BaseLogDialog::handleSearchTextChanged(QString searchText) {
|
||||||
if (searchText.isEmpty()) {
|
if (searchText.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextCursor cursor = _logTextBox->textCursor();
|
QTextCursor cursor = _logTextBox->textCursor();
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
QString selectedTerm = cursor.selectedText();
|
QString selectedTerm = cursor.selectedText();
|
||||||
|
@ -136,16 +143,16 @@ void BaseLogDialog::handleSearchTextChanged(QString searchText) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor.setPosition(0, QTextCursor::MoveAnchor);
|
cursor.setPosition(0, QTextCursor::MoveAnchor);
|
||||||
_logTextBox->setTextCursor(cursor);
|
_logTextBox->setTextCursor(cursor);
|
||||||
bool foundTerm = _logTextBox->find(searchText);
|
bool foundTerm = _logTextBox->find(searchText);
|
||||||
|
|
||||||
if (!foundTerm) {
|
if (!foundTerm) {
|
||||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||||
_logTextBox->setTextCursor(cursor);
|
_logTextBox->setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
_searchTerm = searchText;
|
_searchTerm = searchText;
|
||||||
_highlighter->keyword = searchText;
|
_highlighter->keyword = searchText;
|
||||||
_highlighter->rehighlight();
|
_highlighter->rehighlight();
|
||||||
|
@ -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();
|
||||||
|
|
|
@ -941,7 +941,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
|
||||||
|
|
|
@ -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(boundTransform);
|
||||||
_worldBound.transform(_transform);
|
_clusterBuffer = buffer;
|
||||||
if (clusterMatrices.size() == 1) {
|
|
||||||
_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1048,7 +1052,7 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::computeMeshPartLocalBounds() {
|
void Model::computeMeshPartLocalBounds() {
|
||||||
for (auto& part : _modelMeshRenderItemsSet) {
|
for (auto& part : _modelMeshRenderItemsSet) {
|
||||||
assert(part->_meshIndex < _modelMeshRenderItemsSet.size());
|
assert(part->_meshIndex < _modelMeshRenderItemsSet.size());
|
||||||
const Model::MeshState& state = _meshStates.at(part->_meshIndex);
|
const Model::MeshState& state = _meshStates.at(part->_meshIndex);
|
||||||
part->computeAdjustedLocalBound(state.clusterMatrices);
|
part->computeAdjustedLocalBound(state.clusterMatrices);
|
||||||
|
|
|
@ -583,16 +583,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) && !isStopping()) {
|
|
||||||
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);
|
||||||
|
@ -2291,7 +2281,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() << "] "
|
||||||
|
@ -2299,7 +2289,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
|
||||||
|
@ -2317,7 +2308,11 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||||
qCDebug(scriptengine) << "unload called while !running" << entityID << oldDetails.status;
|
qCDebug(scriptengine) << "unload called while !running" << entityID << oldDetails.status;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
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();
|
||||||
|
@ -2325,6 +2320,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
|
||||||
|
|
|
@ -186,7 +186,7 @@ public:
|
||||||
QVariant cloneEntityScriptDetails(const EntityItemID& entityID);
|
QVariant cloneEntityScriptDetails(const EntityItemID& entityID);
|
||||||
QFuture<QVariant> getLocalEntityScriptDetails(const EntityItemID& entityID) override;
|
QFuture<QVariant> getLocalEntityScriptDetails(const EntityItemID& entityID) override;
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue