Merge branch 'master' of https://github.com/highfidelity/hifi into agent/noise-gate

This commit is contained in:
Zach Pomerantz 2017-03-16 18:48:09 +00:00
commit abac14ee19
18 changed files with 175 additions and 173 deletions

View file

@ -17,6 +17,7 @@ module.exports = {
"Clipboard": false, "Clipboard": false,
"Controller": false, "Controller": false,
"DialogsManager": false, "DialogsManager": false,
"DebugDraw": false,
"Entities": false, "Entities": false,
"FaceTracker": false, "FaceTracker": false,
"GlobalServices": false, "GlobalServices": false,

View file

@ -608,6 +608,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
} }
} }
// make sure the debug draw singleton is initialized on the main thread.
DebugDraw::getInstance().removeMarker("");
_runningMarker.startRunningMarker(); _runningMarker.startRunningMarker();

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

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

View file

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

View file

@ -19,19 +19,13 @@
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) {
// //
@ -80,7 +74,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
float loudness = 0; float loudness = 0;
int thisSample = 0; int thisSample = 0;
int samplesOverNoiseGate = 0; int samplesOverNoiseGate = 0;
const float NOISE_GATE_HEIGHT = 7.0f; const float NOISE_GATE_HEIGHT = 7.0f;
const int NOISE_GATE_WIDTH = 5; const int NOISE_GATE_WIDTH = 5;
const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5; const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
@ -88,36 +82,22 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
// Check clipping, and check if should open noise gate // Check clipping, and check if should open noise gate
_didClipInLastBlock = false; _didClipInLastBlock = false;
for (int i = 0; i < numSamples; i++) { for (int i = 0; i < numSamples; i++) {
thisSample = std::abs(samples[i]); thisSample = std::abs(samples[i]);
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) { if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
_didClipInLastBlock = true; _didClipInLastBlock = true;
} }
loudness += thisSample; loudness += thisSample;
// Noise Reduction: Count peaks above the average loudness // Noise Reduction: Count peaks above the average loudness
if (thisSample > (_measuredFloor * NOISE_GATE_HEIGHT)) { if (thisSample > (_measuredFloor * NOISE_GATE_HEIGHT)) {
samplesOverNoiseGate++; samplesOverNoiseGate++;
} }
} }
_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;
@ -130,7 +110,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
averageOfAllSampleBlocks += _sampleBlocks[j]; averageOfAllSampleBlocks += _sampleBlocks[j];
} }
thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE; thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
if (thisAverage < smallestSample) { if (thisAverage < smallestSample) {
smallestSample = thisAverage; smallestSample = thisAverage;
} }
@ -138,7 +118,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS; averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
_measuredFloor = smallestSample; _measuredFloor = smallestSample;
_sampleCounter = 0; _sampleCounter = 0;
} }
_closedInLastBlock = false; _closedInLastBlock = false;
@ -156,7 +136,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
} }
if (!_isOpen) { if (!_isOpen) {
// First block after being closed gets faded to silence, we fade across // First block after being closed gets faded to silence, we fade across
// the entire block on fading out. All subsequent blocks are muted by being slammed // the entire block on fading out. All subsequent blocks are muted by being slammed
// to zeros // to zeros
if (_closedInLastBlock) { if (_closedInLastBlock) {
float fadeSlope = (1.0f / numSamples); float fadeSlope = (1.0f / numSamples);

View file

@ -19,24 +19,21 @@ const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
class AudioNoiseGate { class AudioNoiseGate {
public: public:
AudioNoiseGate(); AudioNoiseGate();
void gateSamples(int16_t* samples, int numSamples); void gateSamples(int16_t* samples, int numSamples);
void removeDCOffset(int16_t* samples, int numSamples); void removeDCOffset(int16_t* samples, int numSamples);
bool clippedInLastBlock() const { return _didClipInLastBlock; } bool clippedInLastBlock() const { return _didClipInLastBlock; }
bool closedInLastBlock() const { return _closedInLastBlock; } bool closedInLastBlock() const { return _closedInLastBlock; }
bool openedInLastBlock() const { return _openedInLastBlock; } bool openedInLastBlock() const { return _openedInLastBlock; }
bool isOpen() const { return _isOpen; } bool isOpen() const { return _isOpen; }
float getMeasuredFloor() const { return _measuredFloor; } float getMeasuredFloor() const { return _measuredFloor; }
float getLastLoudness() const { return _lastLoudness; } float getLastLoudness() const { return _lastLoudness; }
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;

View file

@ -143,12 +143,35 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
} }
void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) { void PhysicsEngine::removeObjects(const VectorOfMotionStates& objects) {
// first bump and prune contacts for all objects in the list // bump and prune contacts for all objects in the list
for (auto object : objects) { for (auto object : objects) {
bumpAndPruneContacts(object); bumpAndPruneContacts(object);
} }
// then remove them if (_activeStaticBodies.size() > 0) {
// _activeStaticBodies was not cleared last frame.
// The only way to get here is if a static object were moved but we did not actually step the simulation last
// frame (because the framerate is faster than our physics simulation rate). When this happens we must scan
// _activeStaticBodies for objects that were recently deleted so we don't try to access a dangling pointer.
for (auto object : objects) {
btRigidBody* body = object->getRigidBody();
std::vector<btRigidBody*>::reverse_iterator itr = _activeStaticBodies.rbegin();
while (itr != _activeStaticBodies.rend()) {
if (body == *itr) {
if (*itr != *(_activeStaticBodies.rbegin())) {
// swap with rbegin
*itr = *(_activeStaticBodies.rbegin());
}
_activeStaticBodies.pop_back();
break;
}
++itr;
}
}
}
// remove bodies
for (auto object : objects) { for (auto object : objects) {
btRigidBody* body = object->getRigidBody(); btRigidBody* body = object->getRigidBody();
if (body) { if (body) {

View file

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

View file

@ -346,7 +346,9 @@ void AnimDebugDraw::update() {
numVerts += (int)markerMap.size() * VERTICES_PER_BONE; numVerts += (int)markerMap.size() * VERTICES_PER_BONE;
auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap(); auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap();
numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE; numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE;
numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY; auto rays = DebugDraw::getInstance().getRays();
DebugDraw::getInstance().clearRays();
numVerts += (int)rays.size() * VERTICES_PER_RAY;
// allocate verts! // allocate verts!
std::vector<AnimDebugDrawData::Vertex> vertices; std::vector<AnimDebugDrawData::Vertex> vertices;
@ -398,10 +400,9 @@ void AnimDebugDraw::update() {
} }
// draw rays from shared DebugDraw singleton // draw rays from shared DebugDraw singleton
for (auto& iter : DebugDraw::getInstance().getRays()) { for (auto& iter : rays) {
addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v); addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v);
} }
DebugDraw::getInstance().clearRays();
data._vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * numVerts); data._vertexBuffer->resize(sizeof(AnimDebugDrawData::Vertex) * numVerts);
data._vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices); data._vertexBuffer->setSubData<AnimDebugDrawData::Vertex>(0, vertices);

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

@ -142,7 +142,7 @@ QString encodeEntityIdIntoEntityUrl(const QString& url, const QString& entityID)
QString ScriptEngine::logException(const QScriptValue& exception) { QString ScriptEngine::logException(const QScriptValue& exception) {
auto message = formatException(exception); auto message = formatException(exception);
scriptErrorMessage(qPrintable(message)); scriptErrorMessage(message);
return message; return message;
} }
@ -453,7 +453,7 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
} }
void ScriptEngine::scriptErrorMessage(const QString& message) { void ScriptEngine::scriptErrorMessage(const QString& message) {
qCCritical(scriptengine) << message; qCCritical(scriptengine) << qPrintable(message);
emit errorMessage(message); emit errorMessage(message);
} }

View file

@ -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);
@ -282,8 +291,8 @@ function mousePressEvent(event) {
} }
} }
} else if (Recording.playerLength() > 0 && } else if (Recording.playerLength() > 0 &&
slider.x < event.x && event.x < slider.x + slider.w && slider.x < event.x && event.x < slider.x + slider.w &&
slider.y < event.y && event.y < slider.y + slider.h) { slider.y < event.y && event.y < slider.y + slider.h) {
isSliding = true; isSliding = true;
slider.pos = (event.x - slider.x) / slider.w; slider.pos = (event.x - slider.x) / slider.w;
Recording.setPlayerTime(slider.pos * Recording.playerLength()); Recording.setPlayerTime(slider.pos * Recording.playerLength());
@ -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();
} }

View file

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