Merge branch 'master' into 21114-part3

This commit is contained in:
humbletim 2017-03-16 16:39:37 -04:00 committed by GitHub
commit 87d62ad1eb
15 changed files with 152 additions and 122 deletions

View file

@ -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()) {

View file

@ -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 };

View file

@ -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);
} }
} }

View file

@ -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;

View file

@ -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);
}
} }
} }

View file

@ -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;
}; };

View file

@ -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);
} }
} }
}); });

View file

@ -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);
}

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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;