From 55b4784a02969adbe4d7f4ae0ae44af41c720d9f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 13:52:49 -0700 Subject: [PATCH 01/15] avoid entity-server node/octree deadlock on shutdown --- assignment-client/src/octree/OctreeSendThread.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 78f480b5eb..f22d63611c 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -42,7 +42,7 @@ protected: virtual bool process(); private: - OctreeServer* _myServer; + QPointer _myServer; SharedNodePointer _node; QUuid _nodeUUID; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f5d599b5d3..c018d65f98 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1175,13 +1175,22 @@ void OctreeServer::aboutToFinish() { if (_jurisdictionSender) { _jurisdictionSender->terminating(); } + + QSet nodesToKill; - // force a shutdown of all of our OctreeSendThreads - at this point it has to be impossible for a - // linkedDataCreateCallback to be called for a new node - nodeList->eachNode([this](const SharedNodePointer& node) { + // Force a shutdown of all of our OctreeSendThreads. + // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node + nodeList->eachNode([&nodesToKill](const SharedNodePointer& node) { + nodesToKill << node; + }); + + // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. + // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically + // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. + for (auto& node : nodesToKill) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); - }); + } if (_persistThread) { _persistThread->aboutToFinish(); From d22219a1f2c00a98437de5ba2e87628a9b37d9ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 13:54:39 -0700 Subject: [PATCH 02/15] make myServer pointer an OctreeServer* again, it's not checked --- assignment-client/src/octree/OctreeSendThread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index f22d63611c..78f480b5eb 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -42,7 +42,7 @@ protected: virtual bool process(); private: - QPointer _myServer; + OctreeServer* _myServer; SharedNodePointer _node; QUuid _nodeUUID; From 67294d3a23ac3a7c1a8fb88c235cf16d4e829a20 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 13:55:22 -0700 Subject: [PATCH 03/15] rename nodesToKill to nodesToShutdown --- assignment-client/src/octree/OctreeServer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c018d65f98..76d701f0e3 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1176,18 +1176,18 @@ void OctreeServer::aboutToFinish() { _jurisdictionSender->terminating(); } - QSet nodesToKill; + QSet nodesToShutdown; // Force a shutdown of all of our OctreeSendThreads. // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node - nodeList->eachNode([&nodesToKill](const SharedNodePointer& node) { - nodesToKill << node; + nodeList->eachNode([&nodesToShutdown](const SharedNodePointer& node) { + nodesToShutdown << node; }); // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. - for (auto& node : nodesToKill) { + for (auto& node : nodesToShutdown) { qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; forceNodeShutdown(node); } From 9e2eb7fdbdc861241ff4a93279b410884cb48841 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 22 Jul 2015 14:49:20 -0700 Subject: [PATCH 04/15] Fix face-camera functionality for BillboardOverlay --- interface/src/ui/overlays/BillboardOverlay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/overlays/BillboardOverlay.cpp b/interface/src/ui/overlays/BillboardOverlay.cpp index b2843230f3..d26ecc5c67 100644 --- a/interface/src/ui/overlays/BillboardOverlay.cpp +++ b/interface/src/ui/overlays/BillboardOverlay.cpp @@ -91,6 +91,7 @@ void BillboardOverlay::render(RenderArgs* args) { if (batch) { Transform transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); + transform.setRotation(rotation); batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); From bf3ff8daea9e53359ea15e11c72d2ff0f1fe2b58 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 22 Jul 2015 15:06:10 -0700 Subject: [PATCH 05/15] fix crash for convex hull of co-planar points --- libraries/physics/src/ShapeFactory.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 74b0304ace..cfe7abd4db 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -43,9 +43,18 @@ btConvexHullShape* ShapeFactory::createConvexHull(const QVector& poin const float MIN_MARGIN = 0.01f; glm::vec3 diagonal = maxCorner - minCorner; - float minDimension = glm::min(diagonal[0], diagonal[1]); - minDimension = glm::min(minDimension, diagonal[2]); - margin = glm::min(glm::max(0.5f * minDimension, MIN_MARGIN), margin); + float smallestDimension = glm::min(diagonal[0], diagonal[1]); + smallestDimension = glm::min(smallestDimension, diagonal[2]); + const float MIN_DIMENSION = 2.0f * MIN_MARGIN + 0.001f; + if (smallestDimension < MIN_DIMENSION) { + for (int i = 0; i < 3; ++i) { + if (diagonal[i] < MIN_DIMENSION) { + diagonal[i] = MIN_DIMENSION; + } + } + smallestDimension = MIN_DIMENSION; + } + margin = glm::min(glm::max(0.5f * smallestDimension, MIN_MARGIN), margin); hull->setMargin(margin); // add the points, correcting for margin From 71eeecc7f6a4e3a25b1d5dc1e952d7a00c2bdae8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 22 Jul 2015 16:53:56 -0700 Subject: [PATCH 06/15] Revert "Instrument the inter-idle time and tweaking the timeout setting" This reverts commit 0c88972f090abde0b2b91460aa4da37311445c9f. --- interface/src/Application.cpp | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7de69ef602..9cbe7ed37c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1761,25 +1761,8 @@ void Application::checkFPS() { } void Application::idle() { - PROFILE_RANGE(__FUNCTION__); - static SimpleAverage interIdleDurations; - static uint64_t lastIdleEnd{ 0 }; - - if (lastIdleEnd != 0) { - uint64_t now = usecTimestampNow(); - interIdleDurations.update(now - lastIdleEnd); - static uint64_t lastReportTime = now; - if ((now - lastReportTime) >= (USECS_PER_SECOND)) { - static QString LOGLINE("Average inter-idle time: %1 us for %2 samples"); - if (Menu::getInstance()->isOptionChecked(MenuOption::LogExtraTimings)) { - qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount()); - } - interIdleDurations.reset(); - lastReportTime = now; - } - } - PerformanceTimer perfTimer("idle"); + if (_aboutToQuit) { return; // bail early, nothing to do here. } @@ -1823,15 +1806,13 @@ void Application::idle() { _idleLoopStdev.reset(); } + // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. + idleTimer->start(2); } - // After finishing all of the above work, ensure the idle timer is set to the proper interval, - // depending on whether we're throttling or not - idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : 1); } // check for any requested background downloads. emit checkBackgroundDownloads(); - lastIdleEnd = usecTimestampNow(); } void Application::setFullscreen(bool fullscreen) { From 785ae190cac19425ee3768d14fa791bda5aabd7c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 17:49:27 -0700 Subject: [PATCH 07/15] add back send posted touch events --- interface/src/Application.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9cbe7ed37c..3d44f45e38 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -882,7 +882,7 @@ void Application::paintGL() { // NOTE: There is no batch associated with this renderArgs // the ApplicationOverlay class assumes it's viewport is setup to be the device size QSize size = qApp->getDeviceSize(); - renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); + renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); } @@ -959,7 +959,7 @@ void Application::paintGL() { batch.setFramebuffer(primaryFbo); // clear the normal and specular buffers batch.clearFramebuffer( - gpu::Framebuffer::BUFFER_COLOR0 | + gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_COLOR1 | gpu::Framebuffer::BUFFER_COLOR2 | gpu::Framebuffer::BUFFER_DEPTH, @@ -1781,6 +1781,14 @@ void Application::idle() { } double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0; if (timeSinceLastUpdate > targetFramePeriod) { + + { + PerformanceTimer perfTimer("sendPostedEvents(touch)"); + sendPostedEvents(NULL, QEvent::TouchBegin); + sendPostedEvents(NULL, QEvent::TouchUpdate); + sendPostedEvents(NULL, QEvent::TouchEnd); + } + _lastTimeUpdated.start(); { PerformanceTimer perfTimer("update"); @@ -1805,9 +1813,6 @@ void Application::idle() { _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); _idleLoopStdev.reset(); } - - // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. - idleTimer->start(2); } } From b515b163fbd07a446e5bb73646d520739e66a8bf Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Jul 2015 11:51:26 -0700 Subject: [PATCH 08/15] Remove dead code from Head --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/Head.h | 2 +- interface/src/avatar/MyAvatar.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3a55e73fa6..a0414838ed 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -586,7 +586,7 @@ void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool getHand()->render(renderArgs, false); } } - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 43e68557ce..040d145284 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -293,7 +293,7 @@ void Head::relaxLean(float deltaTime) { _deltaLeanForward *= relaxationFactor; } -void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting) { +void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum) { if (_renderLookatVectors) { renderLookatVectors(renderArgs, _leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition()); } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index d7a8462693..f6283c93ea 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -33,7 +33,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine, bool billboard = false); - void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting); + void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum); void setScale(float scale); void setPosition(glm::vec3 position) { _position = position; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4147d24b15..55202a9709 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1236,7 +1236,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo // Render head so long as the camera isn't inside it if (shouldRenderHead(renderArgs)) { - getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting); + getHead()->render(renderArgs, 1.0f, renderFrustum); } getHand()->render(renderArgs, true); } From 3362358dcd8323e7113e855423022f5126dbb5b8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Jul 2015 16:14:27 -0700 Subject: [PATCH 09/15] Remove unused postLighting variable from Avatar and MyAvatar Fixes Leap and Hydra laser pointers not displaying. Enables: - Avatar billboard display - Avatar collision bounding shape display - Hand information display --- interface/src/avatar/Avatar.cpp | 47 +++++++++++++------------------ interface/src/avatar/Avatar.h | 5 ++-- interface/src/avatar/MyAvatar.cpp | 6 ++-- interface/src/avatar/MyAvatar.h | 4 +-- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a0414838ed..9120632f80 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -316,15 +316,14 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); } auto& batch = *renderArgs->_batch; - if (postLighting && - glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { + if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); @@ -414,9 +413,9 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo : GLOW_FROM_AVERAGE_LOUDNESS; // render body - renderBody(renderArgs, frustum, postLighting, glowLevel); + renderBody(renderArgs, frustum, glowLevel); - if (!postLighting && renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { + if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) { // add local lights const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; @@ -431,21 +430,17 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo } } - if (postLighting) { - bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); - bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); - bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); - - if (renderSkeleton) { - _skeletonModel.renderJointCollisionShapes(0.7f); - } - - if (renderHead && shouldRenderHead(renderArgs)) { - getHead()->getFaceModel().renderJointCollisionShapes(0.7f); - } - if (renderBounding && shouldRenderHead(renderArgs)) { - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); - } + bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); + bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); + bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); + if (renderSkeleton) { + _skeletonModel.renderJointCollisionShapes(0.7f); + } + if (renderHead && shouldRenderHead(renderArgs)) { + getHead()->getFaceModel().renderJointCollisionShapes(0.7f); + } + if (renderBounding && shouldRenderHead(renderArgs)) { + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); } // Stack indicator spheres @@ -569,22 +564,18 @@ void Avatar::fixupModelsInScene() { scene->enqueuePendingChanges(pendingChanges); } -void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { fixupModelsInScene(); { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { - if (postLighting || renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) { - // render the billboard until both models are loaded - renderBillboard(renderArgs); - } + // render the billboard until both models are loaded + renderBillboard(renderArgs); return; } - if (postLighting) { - getHand()->render(renderArgs, false); - } + getHand()->render(renderArgs, false); } getHead()->render(renderArgs, 1.0f, renderFrustum); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ae99317541..253c94b0b3 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -81,8 +81,7 @@ public: void init(); void simulate(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, - bool postLighting = false); + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition); bool addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); @@ -235,7 +234,7 @@ protected: Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const; void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f); + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f); virtual bool shouldRenderHead(const RenderArgs* renderArgs) const; virtual void fixupModelsInScene(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 55202a9709..ac0cb3feda 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -332,13 +332,13 @@ void MyAvatar::updateFromTrackers(float deltaTime) { // virtual -void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) { +void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { // don't render if we've been asked to disable local rendering if (!_shouldRender) { return; // exit early } - Avatar::render(renderArgs, cameraPosition, postLighting); + Avatar::render(renderArgs, cameraPosition); // don't display IK constraints in shadow mode if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && @@ -1226,7 +1226,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved); } -void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) { +void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) { if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { return; // wait until all models are loaded diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3253319204..b18b8df121 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -45,8 +45,8 @@ public: void preRender(RenderArgs* renderArgs); void updateFromTrackers(float deltaTime); - virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override; - virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f) override; + virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; + virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; // setters From 11078d0d02d50cd081a7374aaf485432de225f50 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 22 Jul 2015 16:15:17 -0700 Subject: [PATCH 10/15] Get Developer > Avatar > Show Collision Bounding Shapes working again Note: Currently doesn't display well because alpha isn't working. --- interface/src/avatar/SkeletonModel.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d92481494a..4963571f56 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include "Application.h" @@ -785,31 +786,34 @@ void SkeletonModel::resetShapePositionsToDefaultPose() { void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { const int BALL_SUBDIVISIONS = 10; if (_shapes.isEmpty()) { - // the bounding shape has not been propery computed + // the bounding shape has not been properly computed // so no need to render it return; } - // draw a blue sphere at the capsule endpoint + auto geometryCache = DependencyManager::get(); + auto deferredLighting = DependencyManager::get(); + Transform transform; // = Transform(); + + // draw a blue sphere at the capsule end point glm::vec3 endPoint; _boundingShape.getEndPoint(endPoint); endPoint = endPoint + _translation; - Transform transform = Transform(); transform.setTranslation(endPoint); batch.setModelTransform(transform); - auto geometryCache = DependencyManager::get(); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); - // draw a yellow sphere at the capsule startpoint + // draw a yellow sphere at the capsule start point glm::vec3 startPoint; _boundingShape.getStartPoint(startPoint); startPoint = startPoint + _translation; glm::vec3 axis = endPoint - startPoint; - Transform axisTransform = Transform(); - axisTransform.setTranslation(-axis); - batch.setModelTransform(axisTransform); - geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, + transform.setTranslation(startPoint); + batch.setModelTransform(transform); + deferredLighting->bindSimpleProgram(batch); + geometryCache->renderSphere(batch, _boundingShape.getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points From db5e8c72ee58388edde2aea7ce47adc903abce70 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 17:59:07 -0700 Subject: [PATCH 11/15] force event processing up to a certain max time --- interface/src/Application.cpp | 36 ++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3d44f45e38..7acc05236e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1761,8 +1761,25 @@ void Application::checkFPS() { } void Application::idle() { - PerformanceTimer perfTimer("idle"); + PROFILE_RANGE(__FUNCTION__); + static SimpleAverage interIdleDurations; + static uint64_t lastIdleEnd{ 0 }; + if (lastIdleEnd != 0) { + uint64_t now = usecTimestampNow(); + interIdleDurations.update(now - lastIdleEnd); + static uint64_t lastReportTime = now; + if ((now - lastReportTime) >= (USECS_PER_SECOND)) { + static QString LOGLINE("Average inter-idle time: %1 us for %2 samples"); + if (Menu::getInstance()->isOptionChecked(MenuOption::LogExtraTimings)) { + qCDebug(interfaceapp_timing) << LOGLINE.arg((int)interIdleDurations.getAverage()).arg(interIdleDurations.getCount()); + } + interIdleDurations.reset(); + lastReportTime = now; + } + } + + PerformanceTimer perfTimer("idle"); if (_aboutToQuit) { return; // bail early, nothing to do here. } @@ -1783,10 +1800,9 @@ void Application::idle() { if (timeSinceLastUpdate > targetFramePeriod) { { - PerformanceTimer perfTimer("sendPostedEvents(touch)"); - sendPostedEvents(NULL, QEvent::TouchBegin); - sendPostedEvents(NULL, QEvent::TouchUpdate); - sendPostedEvents(NULL, QEvent::TouchEnd); + static const int IDLE_EVENT_PROCESS_MAX_TIME_MS = 2; + PerformanceTimer perfTimer("processEvents"); + processEvents(QEventLoop::AllEvents, IDLE_EVENT_PROCESS_MAX_TIME_MS); } _lastTimeUpdated.start(); @@ -1814,10 +1830,20 @@ void Application::idle() { _idleLoopStdev.reset(); } } + + // After finishing all of the above work, ensure the idle timer is set to the proper interval, + // depending on whether we're throttling or not. + // Once rendering is off on another thread we should be able to have Application::idle run at start(0) in + // perpetuity and not expect events to get backed up. + + static const int IDLE_TIMER_DELAY_MS = 0; + + idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS); } // check for any requested background downloads. emit checkBackgroundDownloads(); + lastIdleEnd = usecTimestampNow(); } void Application::setFullscreen(bool fullscreen) { From 7cee5f3ce5c49bfb311b1d538a38409e935bbcee Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 22 Jul 2015 18:05:04 -0700 Subject: [PATCH 12/15] don't reset the idleTimer if the interval hasn't changed --- interface/src/Application.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7acc05236e..0a5d9bd68e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1837,8 +1837,11 @@ void Application::idle() { // perpetuity and not expect events to get backed up. static const int IDLE_TIMER_DELAY_MS = 0; + int desiredInterval = _glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS; - idleTimer->start(_glWidget->isThrottleRendering() ? THROTTLED_IDLE_TIMER_DELAY : IDLE_TIMER_DELAY_MS); + if (idleTimer->interval() != desiredInterval) { + idleTimer->start(desiredInterval); + } } // check for any requested background downloads. From 198b6cfa887b8c5127ab049d6ac91f320c54c7f5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 06:17:08 -0700 Subject: [PATCH 13/15] Fix ray picking working intermittently Ray picking relies on the Application's viewFrustum which was being set to both the main camera and mirror camera for their respective pass while rendering. This makes sure the viewFrustum only ever holds the main camera. Application::_displayViewFrustum still gets updated to the current camera while rendering. --- interface/src/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9cbe7ed37c..a3e8e61fc4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3395,9 +3395,6 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi renderArgs->_context->render(batch); } - bool updateViewFrustum = false; - loadViewFrustum(_mirrorCamera, _viewFrustum); - // render rear mirror view displaySide(renderArgs, _mirrorCamera, true, billboard); From c17a603714bbe222e84e195d61f4987bebdb921f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 23 Jul 2015 08:42:29 -0700 Subject: [PATCH 14/15] Fix model entity not showing up in list on creation --- examples/edit.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index b33f47c2b7..1af016958f 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -318,11 +318,15 @@ var toolBar = (function () { print("Resize failed: timed out waiting for model (" + url + ") to load"); } } else { - entityProperties.dimensions = naturalDimensions; - Entities.editEntity(entityId, entityProperties); + Entities.editEntity(entityId, { dimensions: naturalDimensions }); + + // Reset selection so that the selection overlays will be updated + selectionManager.setSelections([entityId]); } } + selectionManager.setSelections([entityId]); + Script.setTimeout(resize, RESIZE_INTERVAL); } else { print("Can't add model: Model would be out of bounds."); From 4566d16402236ac77a7b7784e5387159d6837ac8 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Jul 2015 13:03:38 -0700 Subject: [PATCH 15/15] move Model's AnimationHandles to Rig. Move a bunch of Model methods from public to protected --- interface/src/avatar/Avatar.cpp | 4 +- interface/src/avatar/MyAvatar.cpp | 4 +- libraries/animation/src/Rig.cpp | 15 +- libraries/animation/src/Rig.h | 3 +- libraries/render-utils/src/Model.cpp | 25 +-- libraries/render-utils/src/Model.h | 279 +++++++++++++-------------- 6 files changed, 161 insertions(+), 169 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 10866fa9ca..2bc7e788ad 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -823,7 +823,7 @@ QVector Avatar::getJointRotations() const { } QVector jointRotations(_skeletonModel.getJointStateCount()); for (int i = 0; i < _skeletonModel.getJointStateCount(); ++i) { - _skeletonModel.getJointState(i, jointRotations[i]); + _skeletonModel.getJointRotation(i, jointRotations[i]); } return jointRotations; } @@ -833,7 +833,7 @@ glm::quat Avatar::getJointRotation(int index) const { return AvatarData::getJointRotation(index); } glm::quat rotation; - _skeletonModel.getJointState(index, rotation); + _skeletonModel.getJointRotation(index, rotation); return rotation; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 56f5241316..178ebc0487 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -216,10 +216,10 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("joints"); // copy out the skeleton joints from the model - _jointData.resize(_skeletonModel.getJointStateCount()); + _jointData.resize(_rig->getJointStateCount()); for (int i = 0; i < _jointData.size(); i++) { JointData& data = _jointData[i]; - data.valid = _skeletonModel.getJointState(i, data.rotation); + data.valid = _rig->getJointStateRotation(i, data.rotation); } } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 12bfd606da..0a889fce88 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -41,6 +41,14 @@ bool Rig::isRunningAnimation(AnimationHandlePointer animationHandle) { return _runningAnimations.contains(animationHandle); } +void Rig::deleteAnimations() { + for (QSet::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) { + (*it)->clearJoints(); + it = _animationHandles.erase(it); + } +} + + float Rig::initJointStates(QVector states, glm::mat4 parentTransform) { _jointStates = states; initJointTransforms(parentTransform); @@ -235,7 +243,12 @@ glm::mat4 Rig::getJointVisibleTransform(int jointIndex) const { return _jointStates[jointIndex].getVisibleTransform(); } -void Rig::simulateInternal(glm::mat4 parentTransform) { +void Rig::simulateInternal(float deltaTime, glm::mat4 parentTransform) { + // update animations + foreach (const AnimationHandlePointer& handle, _runningAnimations) { + handle->simulate(deltaTime); + } + for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i, parentTransform); } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 6d282bf8f4..e60116a35e 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -49,6 +49,7 @@ public: void addRunningAnimation(AnimationHandlePointer animationHandle); bool isRunningAnimation(AnimationHandlePointer animationHandle); const QList& getRunningAnimations() const { return _runningAnimations; } + void deleteAnimations(); float initJointStates(QVector states, glm::mat4 parentTransform); bool jointStatesEmpty() { return _jointStates.isEmpty(); }; @@ -81,7 +82,7 @@ public: void setJointTransform(int jointIndex, glm::mat4 newTransform); glm::mat4 getJointVisibleTransform(int jointIndex) const; void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform); - void simulateInternal(glm::mat4 parentTransform); + void simulateInternal(float deltaTime, glm::mat4 parentTransform); bool setJointPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, bool useRotation, int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment, float priority, const QVector& freeLineage, glm::mat4 parentTransform); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index af60c91664..bd33e75207 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1365,18 +1365,13 @@ void Model::updateClusterMatrices() { void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints - - // update animations - foreach (const AnimationHandlePointer& handle, _runningAnimations) { - handle->simulate(deltaTime); - } const FBXGeometry& geometry = _geometry->getFBXGeometry(); glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; - _rig->simulateInternal(parentTransform); + _rig->simulateInternal(deltaTime, parentTransform); _shapesAreDirty = !_shapes.isEmpty(); - + glm::mat4 modelToWorld = glm::mat4_cast(_rotation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; @@ -1512,21 +1507,13 @@ void Model::deleteGeometry() { _rig->clearJointStates(); _meshStates.clear(); clearShapes(); - - for (QSet::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) { - AnimationHandlePointer handle = it->lock(); - if (handle) { - handle->clearJoints(); - it++; - } else { - it = _animationHandles.erase(it); - } - } - + + _rig->deleteAnimations(); + if (_geometry) { _geometry->clearLoadPriority(this); } - + _blendedBlendshapeCoefficients.clear(); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index f8d8cbbd74..30c5211990 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -57,7 +57,7 @@ inline uint qHash(const std::shared_ptr& a, uint seed) { /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public PhysicsEntity { Q_OBJECT - + public: typedef RenderArgs::RenderMode RenderMode; @@ -66,58 +66,7 @@ public: Model(RigPointer rig, QObject* parent = nullptr); virtual ~Model(); - - /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension - void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); - bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled - bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit - const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to - void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); - void setSnapModelToCenter(bool snapModelToCenter) { - setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f)); - }; - bool getSnapModelToCenter() { - return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f); - } - - void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); - bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } - - void setScale(const glm::vec3& scale); - const glm::vec3& getScale() const { return _scale; } - - void setOffset(const glm::vec3& offset); - const glm::vec3& getOffset() const { return _offset; } - - void setPupilDilation(float dilation) { _pupilDilation = dilation; } - float getPupilDilation() const { return _pupilDilation; } - - void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } - const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } - - bool isActive() const { return _geometry && _geometry->isLoaded(); } - - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().isEmpty()); } - - void setVisibleInScene(bool newValue, std::shared_ptr scene); - bool isVisible() const { return _isVisible; } - - bool isLoaded() const { return _geometry && _geometry->isLoaded(); } - bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); } - - void init(); - void reset(); - virtual void simulate(float deltaTime, bool fullUpdate = true); - - void renderSetup(RenderArgs* args); - - // new Scene/Engine rendering support - bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return !_needsReload && isRenderable() && isActive() && isLoaded(); } - bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); - bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters); - void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); /// Sets the URL of the model to render. /// \param fallback the URL of a fallback model to render if the requested model fails to load @@ -127,22 +76,127 @@ public: bool retainCurrent = false, bool delayLoad = false); const QUrl& getURL() const { return _url; } + // new Scene/Engine rendering support + void setVisibleInScene(bool newValue, std::shared_ptr scene); + bool needsFixupInScene() { return !_readyWhenAdded && readyToAddToScene(); } + bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { + return !_needsReload && isRenderable() && isActive() && isLoaded(); + } + bool initWhenReady(render::ScenePointer scene); + bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); + bool addToScene(std::shared_ptr scene, + render::PendingChanges& pendingChanges, + render::Item::Status::Getters& statusGetters); + void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); + void renderSetup(RenderArgs* args); + bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().isEmpty()); } + virtual void renderJointCollisionShapes(float alpha); + + bool isVisible() const { return _isVisible; } + + AABox getPartBounds(int meshIndex, int partIndex); + void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent); + + bool maybeStartBlender(); + + /// Sets blended vertices computed in a separate thread. + void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, + const QVector& vertices, const QVector& normals); + + bool isLoaded() const { return _geometry && _geometry->isLoaded(); } + bool isLoadedWithTextures() const { return _geometry && _geometry->isLoadedWithTextures(); } + + void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } + bool isWireframe() const { return _isWireframe; } + + void init(); + void reset(); + + void setScaleToFit(bool scaleToFit, const glm::vec3& dimensions); + + void setSnapModelToRegistrationPoint(bool snapModelToRegistrationPoint, const glm::vec3& registrationPoint); + bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } + + virtual void simulate(float deltaTime, bool fullUpdate = true); + + /// Returns a reference to the shared geometry. + const QSharedPointer& getGeometry() const { return _geometry; } + + bool isActive() const { return _geometry && _geometry->isLoaded(); } + + Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) + { _geometry->setTextureWithNameToURL(name, url); } + + bool convexHullContains(glm::vec3 point); + + QStringList getJointNames() const; + + /// Sets the joint state at the specified index. + void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); + + bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); + // Set the model to use for collisions Q_INVOKABLE void setCollisionModelURL(const QUrl& url); const QUrl& getCollisionURL() const { return _collisionUrl; } - - void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } - bool isWireframe() const { return _isWireframe; } - + + /// Returns a reference to the shared collision geometry. + const QSharedPointer getCollisionGeometry(bool delayLoad = true); + + void setOffset(const glm::vec3& offset); + const glm::vec3& getOffset() const { return _offset; } + /// Sets the distance parameter used for LOD computations. void setLODDistance(float distance) { _lodDistance = distance; } - + + const QList& getRunningAnimations() const { return _rig->getRunningAnimations(); } + /// Clear the joint animation priority + void clearJointAnimationPriority(int index); + + void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false); + bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled + + void setSnapModelToCenter(bool snapModelToCenter) { + setSnapModelToRegistrationPoint(snapModelToCenter, glm::vec3(0.5f,0.5f,0.5f)); + }; + bool getSnapModelToCenter() { + return _snapModelToRegistrationPoint && _registrationPoint == glm::vec3(0.5f,0.5f,0.5f); + } + + /// Returns the number of joint states in the model. + int getJointStateCount() const { return _rig->getJointStateCount(); } + bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; + bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; + bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; + /// \param jointIndex index of joint in model structure + /// \param rotation[out] rotation of joint in model-frame + /// \return true if joint exists + bool getJointRotation(int jointIndex, glm::quat& rotation) const; + + void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); + /// Returns the extents of the model in its bind pose. Extents getBindExtents() const; /// Returns the extents of the model's mesh Extents getMeshExtents() const; + void setScale(const glm::vec3& scale); + const glm::vec3& getScale() const { return _scale; } + + /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension + bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit + const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to + +protected: + + void setPupilDilation(float dilation) { _pupilDilation = dilation; } + float getPupilDilation() const { return _pupilDilation; } + + void setBlendshapeCoefficients(const QVector& coefficients) { _blendshapeCoefficients = coefficients; } + const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } + /// Returns the unscaled extents of the model's mesh Extents getUnscaledMeshExtents() const; @@ -155,15 +209,6 @@ public: /// Returns the scaled equivalent of a point in model space. glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; - /// Returns a reference to the shared geometry. - const QSharedPointer& getGeometry() const { return _geometry; } - - /// Returns a reference to the shared collision geometry. - const QSharedPointer getCollisionGeometry(bool delayLoad = true); - - /// Returns the number of joint states in the model. - int getJointStateCount() const { return _rig->getJointStateCount(); } - /// Fetches the joint state at the specified index. /// \return whether or not the joint state is "valid" (that is, non-default) bool getJointState(int index, glm::quat& rotation) const; @@ -171,25 +216,15 @@ public: /// Fetches the visible joint state at the specified index. /// \return whether or not the joint state is "valid" (that is, non-default) bool getVisibleJointState(int index, glm::quat& rotation) const; - + /// Clear the joint states void clearJointState(int index); - - /// Clear the joint animation priority - void clearJointAnimationPriority(int index); - - /// Sets the joint state at the specified index. - void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); - + /// Returns the index of the parent of the indexed joint, or -1 if not found. int getParentJointIndex(int jointIndex) const; - + /// Returns the index of the last free ancestor of the indexed joint, or -1 if not found. int getLastFreeJointIndex(int jointIndex) const; - - bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; - bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; - bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; @@ -199,52 +234,15 @@ public: /// \return true if joint exists bool getJointPosition(int jointIndex, glm::vec3& position) const; - /// \param jointIndex index of joint in model structure - /// \param rotation[out] rotation of joint in model-frame - /// \return true if joint exists - bool getJointRotation(int jointIndex, glm::quat& rotation) const; - - QStringList getJointNames() const; - - AnimationHandlePointer createAnimationHandle(); - - const QList& getRunningAnimations() const { return _runningAnimations; } - // virtual overrides from PhysicsEntity virtual void buildShapes(); virtual void updateShapePositions(); - virtual void renderJointCollisionShapes(float alpha); - - bool maybeStartBlender(); - - /// Sets blended vertices computed in a separate thread. - void setBlendedVertices(int blendNumber, const QWeakPointer& geometry, - const QVector& vertices, const QVector& normals); - void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } - // QVector& getJointStates() { return _rig->getJointStates(); } - // const QVector& getJointStates() const { return _jointStates; } - - void inverseKinematics(int jointIndex, glm::vec3 position, const glm::quat& rotation, float priority); - - Q_INVOKABLE void setTextureWithNameToURL(const QString& name, const QUrl& url) - { _geometry->setTextureWithNameToURL(name, url); } - - bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, - BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); - bool convexHullContains(glm::vec3 point); - - AABox getPartBounds(int meshIndex, int partIndex); - void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent); - - bool initWhenReady(render::ScenePointer scene); - -protected: QSharedPointer _geometry; void setGeometry(const QSharedPointer& newGeometry); - + glm::vec3 _scale; glm::vec3 _offset; @@ -257,21 +255,21 @@ protected: bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to - + bool _showTrueJointTransforms; class MeshState { public: QVector clusterMatrices; }; - + QVector _meshStates; - + // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); virtual void initJointStates(QVector states); - + void setScaleInternal(const glm::vec3& scale); void scaleToFit(); void snapToRegistrationPoint(); @@ -298,11 +296,11 @@ protected: /// the original position /// \return true if the joint was found bool restoreJointPosition(int jointIndex, float fraction = 1.0f, float priority = 0.0f); - + /// Computes and returns the extended length of the limb terminating at the specified joint and starting at the joint's /// first free ancestor. float getLimbLength(int jointIndex) const; - + /// Allow sub classes to force invalidating the bboxes void invalidCalculatedMeshBoxes() { _calculatedMeshBoxesValid = false; @@ -316,28 +314,25 @@ protected: // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; -protected slots: void geometryRefreshed(); - + private: - - friend class AnimationHandle; - + void applyNextGeometry(); void deleteGeometry(); QVector createJointStates(const FBXGeometry& geometry); void initJointTransforms(); - + QSharedPointer _nextGeometry; float _lodDistance; float _lodHysteresis; float _nextLODHysteresis; QSharedPointer _collisionGeometry; - + float _pupilDilation; QVector _blendshapeCoefficients; - + QUrl _url; QUrl _collisionUrl; bool _isVisible; @@ -347,10 +342,6 @@ private: gpu::Batch _renderBatch; QVector > > _dilatedTextures; - - QSet _animationHandles; - - QList _runningAnimations; QVector _blendedBlendshapeCoefficients; int _blendNumber; @@ -375,12 +366,12 @@ private: QHash, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes QHash, qint64> _calculatedMeshPartOffset; bool _calculatedMeshPartOffsetValid; - - + + bool _calculatedMeshPartBoxesValid; QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; - + QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes bool _calculatedMeshTrianglesValid; QMutex _mutex; @@ -420,10 +411,10 @@ private: IS_SHADOW_FLAG, IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" IS_WIREFRAME_FLAG, - + NUM_FLAGS, }; - + enum Flag { IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG), HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG), @@ -489,7 +480,7 @@ private: RenderKey(int bitmask) : _flags(bitmask) {} }; - + class RenderPipeline { public: gpu::PipelinePointer _pipeline; @@ -503,7 +494,7 @@ private: public: typedef RenderKey Key; - + void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader); void initLocations(gpu::ShaderPointer& program, Locations& locations); @@ -511,8 +502,8 @@ private: static RenderPipelineLib _renderPipelineLib; bool _renderCollisionHull; - - + + QSet> _transparentRenderItems; QSet> _opaqueRenderItems; QMap _renderItems;