diff --git a/interface/src/avatar/CauterizedModel.cpp b/interface/src/avatar/CauterizedModel.cpp index d8db83fbb7..f479ed9a35 100644 --- a/interface/src/avatar/CauterizedModel.cpp +++ b/interface/src/avatar/CauterizedModel.cpp @@ -56,9 +56,9 @@ void CauterizedModel::createVisibleRenderItemSet() { } // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_modelMeshRenderItemsSet.isEmpty()); + Q_ASSERT(_modelMeshRenderItems.isEmpty()); - _modelMeshRenderItemsSet.clear(); + _modelMeshRenderItems.clear(); Transform transform; transform.setTranslation(_translation); @@ -81,7 +81,7 @@ void CauterizedModel::createVisibleRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { auto ptr = std::make_shared(this, i, partIndex, shapeID, transform, offset); - _modelMeshRenderItemsSet << std::static_pointer_cast(ptr); + _modelMeshRenderItems << std::static_pointer_cast(ptr); shapeID++; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 935dd4e796..e94e5df9cb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -371,109 +371,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { _model->updateRenderItems(); } - if (hasModel()) { - // Prepare the current frame - { - if (!_model || _needsModelReload) { - // TODO: this getModel() appears to be about 3% of model render time. We should optimize - PerformanceTimer perfTimer("getModel"); - auto renderer = qSharedPointerCast(args->_renderer); - getModel(renderer); - - // Remap textures immediately after loading to avoid flicker - remapTextures(); - } - - if (_model) { - if (hasRenderAnimation()) { - if (!jointsMapped()) { - QStringList modelJointNames = _model->getJointNames(); - mapJoints(modelJointNames); - } - } - - _jointDataLock.withWriteLock([&] { - getAnimationFrame(); - - // relay any inbound joint changes from scripts/animation/network to the model/rig - for (int index = 0; index < _localJointRotations.size(); index++) { - if (_localJointRotationsDirty[index]) { - glm::quat rotation = _localJointRotations[index]; - _model->setJointRotation(index, true, rotation, 1.0f); - _localJointRotationsDirty[index] = false; - } - } - for (int index = 0; index < _localJointTranslations.size(); index++) { - if (_localJointTranslationsDirty[index]) { - glm::vec3 translation = _localJointTranslations[index]; - _model->setJointTranslation(index, true, translation, 1.0f); - _localJointTranslationsDirty[index] = false; - } - } - }); - updateModelBounds(); - } - } - - // Enqueue updates for the next frame - if (_model) { - -#ifdef WANT_EXTRA_RENDER_DEBUGGING - // debugging... - gpu::Batch& batch = *args->_batch; - _model->renderDebugMeshBoxes(batch); -#endif - - render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); - - // FIXME: this seems like it could be optimized if we tracked our last known visible state in - // the renderable item. As it stands now the model checks it's visible/invisible state - // so most of the time we don't do anything in this function. - _model->setVisibleInScene(getVisible(), scene); - - // Remap textures for the next frame to avoid flicker - remapTextures(); - - // update whether the model should be showing collision mesh (this may flag for fixupInScene) - bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); - if (showingCollisionGeometry != _showCollisionGeometry) { - ShapeType type = getShapeType(); - _showCollisionGeometry = showingCollisionGeometry; - if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { - // NOTE: it is OK if _collisionMeshKey is nullptr - model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); - // NOTE: the model will render the collisionGeometry if it has one - _model->setCollisionMesh(mesh); - } else { - // release mesh - if (_collisionMeshKey) { - collisionMeshCache.releaseMesh(_collisionMeshKey); - } - // clear model's collision geometry - model::MeshPointer mesh = nullptr; - _model->setCollisionMesh(mesh); - } - } - - if (_model->needsFixupInScene()) { - render::PendingChanges pendingChanges; - - _model->removeFromScene(scene, pendingChanges); - - render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, statusGetters); - - scene->enqueuePendingChanges(pendingChanges); - } - - auto& currentURL = getParsedModelURL(); - if (currentURL != _model->getURL()) { - // Defer setting the url to the render thread - getModel(_myRenderer); - } - } - } else { + if (!hasModel() || (_model && _model->didVisualGeometryRequestFail())) { static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); gpu::Batch& batch = *args->_batch; bool success; @@ -482,6 +380,109 @@ void RenderableModelEntityItem::render(RenderArgs* args) { batch.setModelTransform(shapeTransform); // we want to include the scale as well DependencyManager::get()->renderWireCubeInstance(batch, greenColor); } + return; + } + + // Prepare the current frame + { + if (!_model || _needsModelReload) { + // TODO: this getModel() appears to be about 3% of model render time. We should optimize + PerformanceTimer perfTimer("getModel"); + auto renderer = qSharedPointerCast(args->_renderer); + getModel(renderer); + + // Remap textures immediately after loading to avoid flicker + remapTextures(); + } + + if (_model) { + if (hasRenderAnimation()) { + if (!jointsMapped()) { + QStringList modelJointNames = _model->getJointNames(); + mapJoints(modelJointNames); + } + } + + _jointDataLock.withWriteLock([&] { + getAnimationFrame(); + + // relay any inbound joint changes from scripts/animation/network to the model/rig + for (int index = 0; index < _localJointRotations.size(); index++) { + if (_localJointRotationsDirty[index]) { + glm::quat rotation = _localJointRotations[index]; + _model->setJointRotation(index, true, rotation, 1.0f); + _localJointRotationsDirty[index] = false; + } + } + for (int index = 0; index < _localJointTranslations.size(); index++) { + if (_localJointTranslationsDirty[index]) { + glm::vec3 translation = _localJointTranslations[index]; + _model->setJointTranslation(index, true, translation, 1.0f); + _localJointTranslationsDirty[index] = false; + } + } + }); + updateModelBounds(); + } + } + + // Enqueue updates for the next frame + if (_model) { + +#ifdef WANT_EXTRA_RENDER_DEBUGGING + // debugging... + gpu::Batch& batch = *args->_batch; + _model->renderDebugMeshBoxes(batch); +#endif + + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + // FIXME: this seems like it could be optimized if we tracked our last known visible state in + // the renderable item. As it stands now the model checks it's visible/invisible state + // so most of the time we don't do anything in this function. + _model->setVisibleInScene(getVisible(), scene); + + // Remap textures for the next frame to avoid flicker + remapTextures(); + + // update whether the model should be showing collision mesh (this may flag for fixupInScene) + bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); + if (showingCollisionGeometry != _showCollisionGeometry) { + ShapeType type = getShapeType(); + _showCollisionGeometry = showingCollisionGeometry; + if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { + // NOTE: it is OK if _collisionMeshKey is nullptr + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + // NOTE: the model will render the collisionGeometry if it has one + _model->setCollisionMesh(mesh); + } else { + // release mesh + if (_collisionMeshKey) { + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + // clear model's collision geometry + model::MeshPointer mesh = nullptr; + _model->setCollisionMesh(mesh); + } + } + + if (_model->needsFixupInScene()) { + render::PendingChanges pendingChanges; + + _model->removeFromScene(scene, pendingChanges); + + render::Item::Status::Getters statusGetters; + makeEntityItemStatusGetters(getThisPointer(), statusGetters); + _model->addToScene(scene, pendingChanges, statusGetters); + + scene->enqueuePendingChanges(pendingChanges); + } + + auto& currentURL = getParsedModelURL(); + if (currentURL != _model->getURL()) { + // Defer setting the url to the render thread + getModel(_myRenderer); + } } } @@ -587,6 +588,10 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag return properties; } +bool RenderableModelEntityItem::supportsDetailedRayIntersection() const { + return _model && _model->isLoaded(); +} + bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { @@ -807,6 +812,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { auto& meshes = _model->getGeometry()->getMeshes(); int32_t numMeshes = (int32_t)(meshes.size()); + const int MAX_ALLOWED_MESH_COUNT = 500; + if (numMeshes > MAX_ALLOWED_MESH_COUNT) { + // too many will cause the deadlock timer to throw... + shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions); + return; + } + ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); pointCollection.clear(); if (type == SHAPE_TYPE_SIMPLE_COMPOUND) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index bac2118326..057ca36e13 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -46,7 +46,7 @@ public: void updateModelBounds(); virtual void render(RenderArgs* args) override; - virtual bool supportsDetailedRayIntersection() const override { return true; } + virtual bool supportsDetailedRayIntersection() const override; virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index bd76b2d70f..6f5b474810 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -208,6 +208,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re assert(!entity->getPhysicsInfo()); if (entity->isDead()) { prepareEntityForDelete(entity); + entityItr = _entitiesToAddToPhysics.erase(entityItr); } else if (!entity->shouldBePhysical()) { // this entity should no longer be on the internal _entitiesToAddToPhysics entityItr = _entitiesToAddToPhysics.erase(entityItr); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index c584b0bc21..3448c9e8da 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -176,11 +176,11 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::calculateTextureInfo() { - if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItems.isEmpty()) { + if (!_hasCalculatedTextureInfo && isLoaded() && getGeometry()->areTexturesLoaded() && !_modelMeshRenderItemsMap.isEmpty()) { size_t textureSize = 0; int textureCount = 0; bool allTexturesLoaded = true; - foreach(auto renderItem, _modelMeshRenderItemsSet) { + foreach(auto renderItem, _modelMeshRenderItems) { auto meshPart = renderItem.get(); textureSize += meshPart->getMaterialTextureSize(); textureCount += meshPart->getMaterialTextureCount(); @@ -236,7 +236,7 @@ void Model::updateRenderItems() { uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; render::PendingChanges pendingChanges; - foreach (auto itemID, self->_modelMeshRenderItems.keys()) { + foreach (auto itemID, self->_modelMeshRenderItemsMap.keys()) { pendingChanges.updateItem(itemID, [deleteGeometryCounter](ModelMeshPartPayload& data) { if (data._model && data._model->isLoaded()) { // Ensure the model geometry was not reset between frames @@ -259,7 +259,7 @@ void Model::updateRenderItems() { Transform collisionMeshOffset; collisionMeshOffset.setIdentity(); Transform modelTransform = self->getTransform(); - foreach (auto itemID, self->_collisionRenderItems.keys()) { + foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. data.updateTransform(modelTransform, collisionMeshOffset); @@ -539,11 +539,11 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen _isVisible = newValue; render::PendingChanges pendingChanges; - foreach (auto item, _modelMeshRenderItems.keys()) { - pendingChanges.resetItem(item, _modelMeshRenderItems[item]); + foreach (auto item, _modelMeshRenderItemsMap.keys()) { + pendingChanges.resetItem(item, _modelMeshRenderItemsMap[item]); } - foreach (auto item, _collisionRenderItems.keys()) { - pendingChanges.resetItem(item, _collisionRenderItems[item]); + foreach(auto item, _collisionRenderItemsMap.keys()) { + pendingChanges.resetItem(item, _collisionRenderItemsMap[item]); } scene->enqueuePendingChanges(pendingChanges); } @@ -555,11 +555,11 @@ void Model::setLayeredInFront(bool layered, std::shared_ptr scene _isLayeredInFront = layered; render::PendingChanges pendingChanges; - foreach(auto item, _modelMeshRenderItems.keys()) { - pendingChanges.resetItem(item, _modelMeshRenderItems[item]); + foreach(auto item, _modelMeshRenderItemsMap.keys()) { + pendingChanges.resetItem(item, _modelMeshRenderItemsMap[item]); } - foreach(auto item, _collisionRenderItems.keys()) { - pendingChanges.resetItem(item, _collisionRenderItems[item]); + foreach(auto item, _collisionRenderItemsMap.keys()) { + pendingChanges.resetItem(item, _collisionRenderItemsMap[item]); } scene->enqueuePendingChanges(pendingChanges); } @@ -576,39 +576,39 @@ bool Model::addToScene(std::shared_ptr scene, bool somethingAdded = false; if (_collisionGeometry) { if (_collisionRenderItems.empty()) { - foreach (auto renderItem, _collisionRenderItemsSet) { + foreach (auto renderItem, _collisionRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { + if (_collisionRenderItems.empty() && statusGetters.size()) { renderPayload->addStatusGetters(statusGetters); } pendingChanges.resetItem(item, renderPayload); - _collisionRenderItems.insert(item, renderPayload); + _collisionRenderItemsMap.insert(item, renderPayload); } somethingAdded = !_collisionRenderItems.empty(); } } else { - if (_modelMeshRenderItems.empty()) { + if (_modelMeshRenderItemsMap.empty()) { bool hasTransparent = false; size_t verticesCount = 0; - foreach(auto renderItem, _modelMeshRenderItemsSet) { + foreach(auto renderItem, _modelMeshRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { + if (_modelMeshRenderItemsMap.empty() && statusGetters.size()) { renderPayload->addStatusGetters(statusGetters); } pendingChanges.resetItem(item, renderPayload); hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); - _modelMeshRenderItems.insert(item, renderPayload); + _modelMeshRenderItemsMap.insert(item, renderPayload); _modelMeshRenderItemIDs.emplace_back(item); } - somethingAdded = !_modelMeshRenderItems.empty(); + somethingAdded = !_modelMeshRenderItemsMap.empty(); _renderInfoVertexCount = verticesCount; - _renderInfoDrawCalls = _modelMeshRenderItems.count(); + _renderInfoDrawCalls = _modelMeshRenderItemsMap.count(); _renderInfoHasTransparent = hasTransparent; } } @@ -623,18 +623,18 @@ bool Model::addToScene(std::shared_ptr scene, } void Model::removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges) { - foreach (auto item, _modelMeshRenderItems.keys()) { + foreach (auto item, _modelMeshRenderItemsMap.keys()) { pendingChanges.removeItem(item); } _modelMeshRenderItemIDs.clear(); + _modelMeshRenderItemsMap.clear(); _modelMeshRenderItems.clear(); - _modelMeshRenderItemsSet.clear(); - foreach (auto item, _collisionRenderItems.keys()) { + foreach(auto item, _collisionRenderItemsMap.keys()) { pendingChanges.removeItem(item); } _collisionRenderItems.clear(); - _collisionRenderItemsSet.clear(); + _collisionRenderItems.clear(); _addedToScene = false; _renderInfoVertexCount = 0; @@ -1052,8 +1052,8 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { } void Model::computeMeshPartLocalBounds() { - for (auto& part : _modelMeshRenderItemsSet) { - assert(part->_meshIndex < _modelMeshRenderItemsSet.size()); + for (auto& part : _modelMeshRenderItems) { + assert(part->_meshIndex < _modelMeshRenderItems.size()); const Model::MeshState& state = _meshStates.at(part->_meshIndex); part->computeAdjustedLocalBound(state.clusterMatrices); } @@ -1167,7 +1167,7 @@ AABox Model::getRenderableMeshBound() const { } else { // Build a bound using the last known bound from all the renderItems. AABox totalBound; - for (auto& renderItem : _modelMeshRenderItemsSet) { + for (auto& renderItem : _modelMeshRenderItems) { totalBound += renderItem->getBound(); } return totalBound; @@ -1180,11 +1180,11 @@ const render::ItemIDs& Model::fetchRenderItemIDs() const { void Model::createRenderItemSet() { if (_collisionGeometry) { - if (_collisionRenderItemsSet.empty()) { + if (_collisionRenderItems.empty()) { createCollisionRenderItemSet(); } } else { - if (_modelMeshRenderItemsSet.empty()) { + if (_modelMeshRenderItems.empty()) { createVisibleRenderItemSet(); } } @@ -1201,9 +1201,9 @@ void Model::createVisibleRenderItemSet() { } // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_modelMeshRenderItemsSet.isEmpty()); + Q_ASSERT(_modelMeshRenderItems.isEmpty()); - _modelMeshRenderItemsSet.clear(); + _modelMeshRenderItems.clear(); Transform transform; transform.setTranslation(_translation); @@ -1225,7 +1225,7 @@ void Model::createVisibleRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); + _modelMeshRenderItems << std::make_shared(this, i, partIndex, shapeID, transform, offset); shapeID++; } } @@ -1241,7 +1241,7 @@ void Model::createCollisionRenderItemSet() { const auto& meshes = _collisionGeometry->getMeshes(); // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_collisionRenderItemsSet.isEmpty()); + Q_ASSERT(_collisionRenderItems.isEmpty()); Transform identity; identity.setIdentity(); @@ -1262,7 +1262,7 @@ void Model::createCollisionRenderItemSet() { model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; auto payload = std::make_shared(mesh, partIndex, material); payload->updateTransform(identity, offset); - _collisionRenderItemsSet << payload; + _collisionRenderItems << payload; } } } @@ -1283,28 +1283,28 @@ bool Model::initWhenReady(render::ScenePointer scene) { bool addedPendingChanges = false; if (_collisionGeometry) { - foreach (auto renderItem, _collisionRenderItemsSet) { + foreach (auto renderItem, _collisionRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); - _collisionRenderItems.insert(item, renderPayload); + _collisionRenderItemsMap.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); } addedPendingChanges = !_collisionRenderItems.empty(); } else { bool hasTransparent = false; size_t verticesCount = 0; - foreach (auto renderItem, _modelMeshRenderItemsSet) { + foreach (auto renderItem, _modelMeshRenderItems) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); hasTransparent = hasTransparent || renderItem.get()->getShapeKey().isTranslucent(); verticesCount += renderItem.get()->getVerticesCount(); - _modelMeshRenderItems.insert(item, renderPayload); + _modelMeshRenderItemsMap.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); } - addedPendingChanges = !_modelMeshRenderItems.empty(); + addedPendingChanges = !_modelMeshRenderItemsMap.empty(); _renderInfoVertexCount = verticesCount; - _renderInfoDrawCalls = _modelMeshRenderItems.count(); + _renderInfoDrawCalls = _modelMeshRenderItemsMap.count(); _renderInfoHasTransparent = hasTransparent; } _addedToScene = addedPendingChanges; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 41821736f7..bb283cce1f 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -248,7 +248,7 @@ public: const MeshState& getMeshState(int index) { return _meshStates.at(index); } uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } - const QMap& getRenderItems() const { return _modelMeshRenderItems; } + const QMap& getRenderItems() const { return _modelMeshRenderItemsMap; } void renderDebugMeshBoxes(gpu::Batch& batch); @@ -373,11 +373,11 @@ protected: static AbstractViewStateInterface* _viewState; - QSet> _collisionRenderItemsSet; - QMap _collisionRenderItems; + QVector> _collisionRenderItems; + QMap _collisionRenderItemsMap; - QSet> _modelMeshRenderItemsSet; - QMap _modelMeshRenderItems; + QVector> _modelMeshRenderItems; + QMap _modelMeshRenderItemsMap; render::ItemIDs _modelMeshRenderItemIDs; diff --git a/plugins/oculus/src/OculusControllerManager.cpp b/plugins/oculus/src/OculusControllerManager.cpp index ce59eafd50..87c52de3e7 100644 --- a/plugins/oculus/src/OculusControllerManager.cpp +++ b/plugins/oculus/src/OculusControllerManager.cpp @@ -20,6 +20,8 @@ #include #include +#include + #include "OculusHelpers.h" Q_DECLARE_LOGGING_CATEGORY(oculus) @@ -42,26 +44,33 @@ bool OculusControllerManager::activate() { } Q_ASSERT(_session); - // register with UserInputMapper - auto userInputMapper = DependencyManager::get(); + checkForConnectedDevices(); + + return true; +} + +void OculusControllerManager::checkForConnectedDevices() { + if (_touch && _remote) { + return; + } unsigned int controllerConnected = ovr_GetConnectedControllerTypes(_session); - if ((controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) { + if (!_remote && (controllerConnected & ovrControllerType_Remote) == ovrControllerType_Remote) { if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Remote, &_inputState))) { + auto userInputMapper = DependencyManager::get(); _remote = std::make_shared(*this); userInputMapper->registerDevice(_remote); } } - if ((controllerConnected & ovrControllerType_Touch) != 0) { + if (!_touch && (controllerConnected & ovrControllerType_Touch) != 0) { if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { + auto userInputMapper = DependencyManager::get(); _touch = std::make_shared(*this); userInputMapper->registerDevice(_touch); } } - - return true; } void OculusControllerManager::deactivate() { @@ -85,6 +94,8 @@ void OculusControllerManager::deactivate() { void OculusControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { PerformanceTimer perfTimer("OculusControllerManager::TouchDevice::update"); + checkForConnectedDevices(); + if (_touch) { if (OVR_SUCCESS(ovr_GetInputState(_session, ovrControllerType_Touch, &_inputState))) { _touch->update(deltaTime, inputCalibrationData); diff --git a/plugins/oculus/src/OculusControllerManager.h b/plugins/oculus/src/OculusControllerManager.h index 98e0e3d650..23ef52ab64 100644 --- a/plugins/oculus/src/OculusControllerManager.h +++ b/plugins/oculus/src/OculusControllerManager.h @@ -91,6 +91,8 @@ private: friend class OculusControllerManager; }; + void checkForConnectedDevices(); + ovrSession _session { nullptr }; ovrInputState _inputState {}; RemoteDevice::Pointer _remote; diff --git a/scripts/developer/libraries/utils.js b/scripts/developer/libraries/utils.js index f39f4d7913..0da9703c87 100644 --- a/scripts/developer/libraries/utils.js +++ b/scripts/developer/libraries/utils.js @@ -311,3 +311,6 @@ clamp = function(val, min, max){ return Math.max(min, Math.min(max, val)) } +easeIn = function(t) { + return Math.pow(t / 1, 5); +} diff --git a/scripts/system/audioMuteOverlay.js b/scripts/system/audioMuteOverlay.js new file mode 100644 index 0000000000..cf07402d64 --- /dev/null +++ b/scripts/system/audioMuteOverlay.js @@ -0,0 +1,104 @@ +"use strict"; +/* jslint vars: true, plusplus: true, forin: true*/ +/* globals Tablet, Script, AvatarList, Users, Entities, MyAvatar, Camera, Overlays, Vec3, Quat, Controller, print, getControllerWorldLocation */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ +// +// audioMuteOverlay.js +// +// client script that creates an overlay to provide mute feedback +// +// Created by Triplelexx on 17/03/09 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function() { // BEGIN LOCAL_SCOPE + var utilsPath = Script.resolvePath('../developer/libraries/utils.js'); + Script.include(utilsPath); + + var TWEEN_SPEED = 0.025; + var MIX_AMOUNT = 0.25; + + var overlayPosition = Vec3.ZERO; + var tweenPosition = 0; + var startColor = { + red: 170, + green: 170, + blue: 170 + }; + var endColor = { + red: 255, + green: 0, + blue: 0 + }; + var overlayID; + + Script.update.connect(update); + Script.scriptEnding.connect(cleanup); + + function update(dt) { + if (!AudioDevice.getMuted()) { + if (hasOverlay()) { + deleteOverlay(); + } + } else if (!hasOverlay()) { + createOverlay(); + } else { + updateOverlay(); + } + } + + function getOffsetPosition() { + return Vec3.sum(Camera.position, Quat.getFront(Camera.orientation)); + } + + function createOverlay() { + overlayPosition = getOffsetPosition(); + overlayID = Overlays.addOverlay("sphere", { + position: overlayPosition, + rotation: Camera.orientation, + alpha: 0.9, + dimensions: 0.1, + solid: true, + ignoreRayIntersection: true + }); + } + + function hasOverlay() { + return Overlays.getProperty(overlayID, "position") !== undefined; + } + + function updateOverlay() { + // increase by TWEEN_SPEED until completion + if (tweenPosition < 1) { + tweenPosition += TWEEN_SPEED; + } else { + // after tween completion reset to zero and flip values to ping pong + tweenPosition = 0; + for (var component in startColor) { + var storedColor = startColor[component]; + startColor[component] = endColor[component]; + endColor[component] = storedColor; + } + } + // mix previous position with new and mix colors + overlayPosition = Vec3.mix(overlayPosition, getOffsetPosition(), MIX_AMOUNT); + Overlays.editOverlay(overlayID, { + color: colorMix(startColor, endColor, easeIn(tweenPosition)), + position: overlayPosition, + rotation: Camera.orientation + }); + } + + function deleteOverlay() { + Overlays.deleteOverlay(overlayID); + } + + function cleanup() { + deleteOverlay(); + AudioDevice.muteToggled.disconnect(onMuteToggled); + Script.update.disconnect(update); + } +}()); // END LOCAL_SCOPE