Merge branch 'master' of https://github.com/highfidelity/hifi into desktopEquip

This commit is contained in:
David Back 2018-04-24 14:09:29 -07:00
commit 3b251c0c49
26 changed files with 305 additions and 250 deletions

View file

@ -17,6 +17,7 @@ StackView {
id: stack id: stack
initialItem: inputConfiguration initialItem: inputConfiguration
property alias messageVisible: imageMessageBox.visible property alias messageVisible: imageMessageBox.visible
property alias selectedPlugin: box.currentText
Rectangle { Rectangle {
id: inputConfiguration id: inputConfiguration
anchors.fill: parent anchors.fill: parent

View file

@ -34,7 +34,7 @@ Rectangle {
readonly property bool hmdHead: headBox.checked readonly property bool hmdHead: headBox.checked
readonly property bool headPuck: headPuckBox.checked readonly property bool headPuck: headPuckBox.checked
readonly property bool handController: handBox.checked readonly property bool handController: handBox.checked
readonly property bool handPuck: handPuckBox.checked readonly property bool handPuck: handPuckBox.checked
readonly property bool hmdDesktop: hmdInDesktop.checked readonly property bool hmdDesktop: hmdInDesktop.checked
@ -105,7 +105,7 @@ Rectangle {
RalewayBold { RalewayBold {
size: 12 size: 12
text: "Vive HMD" text: stack.selectedPlugin + " HMD"
color: hifi.colors.lightGrayText color: hifi.colors.lightGrayText
} }
@ -143,7 +143,7 @@ Rectangle {
anchors.topMargin: 5 anchors.topMargin: 5
anchors.left: openVrConfiguration.left anchors.left: openVrConfiguration.left
anchors.leftMargin: leftMargin + 10 anchors.leftMargin: leftMargin + 10
onClicked: { onClicked: {
if (checked) { if (checked) {
headBox.checked = false; headBox.checked = false;
@ -772,12 +772,12 @@ Rectangle {
RalewayBold { RalewayBold {
id: advanceSettings id: advanceSettings
text: "Advanced Settings" text: "Advanced Settings"
size: 12 size: 12
color: hifi.colors.white color: hifi.colors.white
anchors.top: advanceSeperator.bottom anchors.top: advanceSeperator.bottom
anchors.topMargin: 10 anchors.topMargin: 10
anchors.left: parent.left anchors.left: parent.left
@ -795,7 +795,7 @@ Rectangle {
anchors.topMargin: 5 anchors.topMargin: 5
anchors.left: openVrConfiguration.left anchors.left: openVrConfiguration.left
anchors.leftMargin: leftMargin + 10 anchors.leftMargin: leftMargin + 10
onClicked: { onClicked: {
if (!checked & hmdInDesktop.checked) { if (!checked & hmdInDesktop.checked) {
headBox.checked = true; headBox.checked = true;
@ -809,9 +809,9 @@ Rectangle {
RalewayBold { RalewayBold {
id: viveDesktopText id: viveDesktopText
size: 10 size: 10
text: "Use Vive devices in desktop mode" text: "Use " + stack.selectedPlugin + " devices in desktop mode"
color: hifi.colors.white color: hifi.colors.white
anchors { anchors {
left: viveInDesktop.right left: viveInDesktop.right
leftMargin: 5 leftMargin: 5
@ -819,7 +819,7 @@ Rectangle {
} }
} }
NumberAnimation { NumberAnimation {
id: numberAnimation id: numberAnimation
target: openVrConfiguration target: openVrConfiguration

View file

@ -4741,7 +4741,7 @@ void Application::updateLOD(float deltaTime) const {
} }
} }
void Application::pushPostUpdateLambda(void* key, std::function<void()> func) { void Application::pushPostUpdateLambda(void* key, const std::function<void()>& func) {
std::unique_lock<std::mutex> guard(_postUpdateLambdasLock); std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);
_postUpdateLambdas[key] = func; _postUpdateLambdas[key] = func;
} }
@ -7351,7 +7351,7 @@ void Application::windowMinimizedChanged(bool minimized) {
} }
} }
void Application::postLambdaEvent(std::function<void()> f) { void Application::postLambdaEvent(const std::function<void()>& f) {
if (this->thread() == QThread::currentThread()) { if (this->thread() == QThread::currentThread()) {
f(); f();
} else { } else {
@ -7359,6 +7359,15 @@ void Application::postLambdaEvent(std::function<void()> f) {
} }
} }
void Application::sendLambdaEvent(const std::function<void()>& f) {
if (this->thread() == QThread::currentThread()) {
f();
} else {
LambdaEvent event(f);
QCoreApplication::sendEvent(this, &event);
}
}
void Application::initPlugins(const QStringList& arguments) { void Application::initPlugins(const QStringList& arguments) {
QCommandLineOption display("display", "Preferred displays", "displays"); QCommandLineOption display("display", "Preferred displays", "displays");
QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays"); QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays");

View file

@ -136,7 +136,8 @@ public:
Application(int& argc, char** argv, QElapsedTimer& startup_time, bool runningMarkerExisted); Application(int& argc, char** argv, QElapsedTimer& startup_time, bool runningMarkerExisted);
~Application(); ~Application();
void postLambdaEvent(std::function<void()> f) override; void postLambdaEvent(const std::function<void()>& f) override;
void sendLambdaEvent(const std::function<void()>& f) override;
QString getPreviousScriptLocation(); QString getPreviousScriptLocation();
void setPreviousScriptLocation(const QString& previousScriptLocation); void setPreviousScriptLocation(const QString& previousScriptLocation);
@ -240,7 +241,7 @@ public:
qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); }
bool isAboutToQuit() const override { return _aboutToQuit; } bool isAboutToQuit() const { return _aboutToQuit; }
bool isPhysicsEnabled() const { return _physicsEnabled; } bool isPhysicsEnabled() const { return _physicsEnabled; }
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display // the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
@ -264,7 +265,7 @@ public:
render::EnginePointer getRenderEngine() override { return _renderEngine; } render::EnginePointer getRenderEngine() override { return _renderEngine; }
gpu::ContextPointer getGPUContext() const { return _gpuContext; } gpu::ContextPointer getGPUContext() const { return _gpuContext; }
virtual void pushPostUpdateLambda(void* key, std::function<void()> func) override; virtual void pushPostUpdateLambda(void* key, const std::function<void()>& func) override;
void updateMyAvatarLookAtPosition(); void updateMyAvatarLookAtPosition();

View file

@ -65,14 +65,10 @@ const QString Web3DOverlay::TYPE = "web3d";
const QString Web3DOverlay::QML = "Web3DOverlay.qml"; const QString Web3DOverlay::QML = "Web3DOverlay.qml";
static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) { static auto qmlSurfaceDeleter = [](OffscreenQmlSurface* surface) {
AbstractViewStateInterface::instance()->postLambdaEvent([surface] { AbstractViewStateInterface::instance()->sendLambdaEvent([surface] {
if (AbstractViewStateInterface::instance()->isAboutToQuit()) { // WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown // if the application has already stopped its event loop, delete must be explicit
// if the application has already stopped its event loop, delete must be explicit delete surface;
delete surface;
} else {
surface->deleteLater();
}
}); });
}; };

View file

@ -25,7 +25,7 @@
#include <EntityScriptingInterface.h> #include <EntityScriptingInterface.h>
#include "EntitiesRendererLogging.h" #include "EntitiesRendererLogging.h"
#include <NetworkingConstants.h>
using namespace render; using namespace render;
using namespace render::entities; using namespace render::entities;
@ -45,6 +45,7 @@ static int DEFAULT_MAX_FPS = 10;
static int YOUTUBE_MAX_FPS = 30; static int YOUTUBE_MAX_FPS = 30;
static QTouchDevice _touchDevice; static QTouchDevice _touchDevice;
static const char* URL_PROPERTY = "url";
WebEntityRenderer::ContentType WebEntityRenderer::getContentType(const QString& urlString) { WebEntityRenderer::ContentType WebEntityRenderer::getContentType(const QString& urlString) {
if (urlString.isEmpty()) { if (urlString.isEmpty()) {
@ -52,7 +53,7 @@ WebEntityRenderer::ContentType WebEntityRenderer::getContentType(const QString&
} }
const QUrl url(urlString); const QUrl url(urlString);
if (url.scheme() == "http" || url.scheme() == "https" || if (url.scheme() == URL_SCHEME_HTTP || url.scheme() == URL_SCHEME_HTTPS ||
urlString.toLower().endsWith(".htm") || urlString.toLower().endsWith(".html")) { urlString.toLower().endsWith(".htm") || urlString.toLower().endsWith(".html")) {
return ContentType::HtmlContent; return ContentType::HtmlContent;
} }
@ -164,6 +165,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
if (urlChanged) { if (urlChanged) {
if (newContentType != ContentType::HtmlContent || currentContentType != ContentType::HtmlContent) { if (newContentType != ContentType::HtmlContent || currentContentType != ContentType::HtmlContent) {
destroyWebSurface(); destroyWebSurface();
// If we destroyed the surface, the URL change will be implicitly handled by the re-creation
urlChanged = false;
} }
withWriteLock([&] { withWriteLock([&] {
@ -185,8 +188,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
return; return;
} }
if (urlChanged) { if (urlChanged && _contentType == ContentType::HtmlContent) {
_webSurface->getRootItem()->setProperty("url", _lastSourceUrl); _webSurface->getRootItem()->setProperty(URL_PROPERTY, _lastSourceUrl);
} }
if (_contextPosition != entity->getWorldPosition()) { if (_contextPosition != entity->getWorldPosition()) {
@ -254,6 +257,14 @@ bool WebEntityRenderer::hasWebSurface() {
return (bool)_webSurface && _webSurface->getRootItem(); return (bool)_webSurface && _webSurface->getRootItem();
} }
static const auto WebSurfaceDeleter = [](OffscreenQmlSurface* webSurface) {
AbstractViewStateInterface::instance()->sendLambdaEvent([webSurface] {
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
// if the application has already stopped its event loop, delete must be explicit
delete webSurface;
});
};
bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) { if (_currentWebCount >= MAX_CONCURRENT_WEB_VIEWS) {
qWarning() << "Too many concurrent web views to create new view"; qWarning() << "Too many concurrent web views to create new view";
@ -261,20 +272,9 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
} }
++_currentWebCount; ++_currentWebCount;
auto deleter = [](OffscreenQmlSurface* webSurface) {
AbstractViewStateInterface::instance()->postLambdaEvent([webSurface] {
if (AbstractViewStateInterface::instance()->isAboutToQuit()) {
// WebEngineView may run other threads (wasapi), so they must be deleted for a clean shutdown
// if the application has already stopped its event loop, delete must be explicit
delete webSurface;
} else {
webSurface->deleteLater();
}
});
};
// FIXME use the surface cache instead of explicit creation // FIXME use the surface cache instead of explicit creation
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter); _webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), WebSurfaceDeleter);
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
// and the current rendering load) // and the current rendering load)
_webSurface->setMaxFps(DEFAULT_MAX_FPS); _webSurface->setMaxFps(DEFAULT_MAX_FPS);
@ -302,7 +302,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
_webSurface->setMaxFps(DEFAULT_MAX_FPS); _webSurface->setMaxFps(DEFAULT_MAX_FPS);
} }
_webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) { _webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
item->setProperty("url", _lastSourceUrl); item->setProperty(URL_PROPERTY, _lastSourceUrl);
}); });
} else if (_contentType == ContentType::QmlContent) { } else if (_contentType == ContentType::QmlContent) {
_webSurface->load(_lastSourceUrl, [this](QQmlContext* context, QObject* item) { _webSurface->load(_lastSourceUrl, [this](QQmlContext* context, QObject* item) {
@ -327,6 +327,11 @@ void WebEntityRenderer::destroyWebSurface() {
if (webSurface) { if (webSurface) {
--_currentWebCount; --_currentWebCount;
QQuickItem* rootItem = webSurface->getRootItem(); QQuickItem* rootItem = webSurface->getRootItem();
// Explicitly set the web URL to an empty string, in an effort to get a
// faster shutdown of any chromium processes interacting with audio
if (rootItem && _contentType == ContentType::HtmlContent) {
rootItem->setProperty(URL_PROPERTY, "");
}
if (rootItem && rootItem->objectName() == "tabletRoot") { if (rootItem && rootItem->objectName() == "tabletRoot") {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();

View file

@ -69,7 +69,6 @@ private:
graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; }
bool _needsInitialSimulation{ true };
glm::vec3 _lastPosition; glm::vec3 _lastPosition;
glm::vec3 _lastDimensions; glm::vec3 _lastDimensions;
glm::quat _lastRotation; glm::quat _lastRotation;

View file

@ -216,7 +216,6 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0; int bytesRead = 0;
bool overwriteLocalData = true; bool overwriteLocalData = true;
bool somethingChanged = false; bool somethingChanged = false;
@ -360,3 +359,21 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold);
return bytesRead; return bytesRead;
} }
float AnimationPropertyGroup::getNumFrames() const {
return _lastFrame - _firstFrame + 1.0f;
}
float AnimationPropertyGroup::computeLoopedFrame(float frame) const {
float numFrames = getNumFrames();
if (numFrames > 1.0f) {
frame = getFirstFrame() + fmodf(frame - getFirstFrame(), numFrames);
} else {
frame = getFirstFrame();
}
return frame;
}
bool AnimationPropertyGroup::isValidAndRunning() const {
return getRunning() && (getFPS() > 0.0f) && (getNumFrames() > 1.0f) && !(getURL().isEmpty());
}

View file

@ -77,6 +77,10 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override; bool& somethingChanged) override;
float getNumFrames() const;
float computeLoopedFrame(float frame) const;
bool isValidAndRunning() const;
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, URL, url, QString, ""); DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, URL, url, QString, "");
DEFINE_PROPERTY(PROP_ANIMATION_FPS, FPS, fps, float, 30.0f); DEFINE_PROPERTY(PROP_ANIMATION_FPS, FPS, fps, float, 30.0f);
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, CurrentFrame, currentFrame, float, 0.0f); DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, CurrentFrame, currentFrame, float, 0.0f);

View file

@ -597,7 +597,7 @@ protected:
// //
// DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about.
uint32_t _flags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation std::atomic_uint _flags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation
// these backpointers are only ever set/cleared by friends: // these backpointers are only ever set/cleared by friends:
EntityTreeElementPointer _element; // set by EntityTreeElement EntityTreeElementPointer _element; // set by EntityTreeElement

View file

@ -82,12 +82,12 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslations, setJointTranslations); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslations, setJointTranslations);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints); SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints);
bool somethingChangedInAnimations = _animationProperties.setProperties(properties); withWriteLock([&] {
AnimationPropertyGroup animationProperties = _animationProperties;
if (somethingChangedInAnimations) { animationProperties.setProperties(properties);
_flags |= Simulation::DIRTY_UPDATEABLE; bool somethingChangedInAnimations = applyNewAnimationProperties(animationProperties);
} somethingChanged = somethingChanged || somethingChangedInAnimations;
somethingChanged = somethingChanged || somethingChangedInAnimations; });
if (somethingChanged) { if (somethingChanged) {
bool wantDebug = false; bool wantDebug = false;
@ -118,12 +118,16 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
// grab a local copy of _animationProperties to avoid multiple locks
int bytesFromAnimation; int bytesFromAnimation;
withWriteLock([&] { withReadLock([&] {
// Note: since we've associated our _animationProperties with our _animationLoop, the readEntitySubclassDataFromBuffer() AnimationPropertyGroup animationProperties = _animationProperties;
// will automatically read into the animation loop bytesFromAnimation = animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
bytesFromAnimation = _animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, animationPropertiesChanged); propertyFlags, overwriteLocalData, animationPropertiesChanged);
if (animationPropertiesChanged) {
applyNewAnimationProperties(animationProperties);
somethingChanged = true;
}
}); });
bytesRead += bytesFromAnimation; bytesRead += bytesFromAnimation;
@ -131,11 +135,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
if (animationPropertiesChanged) {
_flags |= Simulation::DIRTY_UPDATEABLE;
somethingChanged = true;
}
READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector<bool>, setJointRotationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector<bool>, setJointRotationsSet);
READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector<glm::quat>, setJointRotations); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector<glm::quat>, setJointRotations);
READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector<bool>, setJointTranslationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector<bool>, setJointTranslationsSet);
@ -194,98 +193,38 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
// added update function back for property fix // added update function back for property fix
void ModelEntityItem::update(const quint64& now) { void ModelEntityItem::update(const quint64& now) {
assert(_lastAnimated > 0);
{ // increment timestamp before checking "hold"
auto currentAnimationProperties = this->getAnimationProperties();
if (_previousAnimationProperties != currentAnimationProperties) {
withWriteLock([&] {
// if we hit start animation or change the first or last frame then restart the animation
if ((currentAnimationProperties.getFirstFrame() != _previousAnimationProperties.getFirstFrame()) ||
(currentAnimationProperties.getLastFrame() != _previousAnimationProperties.getLastFrame()) ||
(currentAnimationProperties.getRunning() && !_previousAnimationProperties.getRunning())) {
// when we start interface and the property is are set then the current frame is initialized to -1
if (_currentFrame < 0) {
// don't reset _lastAnimated here because we need the timestamp from the ModelEntityItem constructor for when the properties were set
_currentFrame = currentAnimationProperties.getCurrentFrame();
setAnimationCurrentFrame(_currentFrame);
} else {
_lastAnimated = usecTimestampNow();
_currentFrame = currentAnimationProperties.getFirstFrame();
setAnimationCurrentFrame(currentAnimationProperties.getFirstFrame());
}
} else if (!currentAnimationProperties.getRunning() && _previousAnimationProperties.getRunning()) {
_currentFrame = currentAnimationProperties.getFirstFrame();
setAnimationCurrentFrame(_currentFrame);
} else if (currentAnimationProperties.getCurrentFrame() != _previousAnimationProperties.getCurrentFrame()) {
// don't reset _lastAnimated here because the currentFrame was set with the previous setting of _lastAnimated
_currentFrame = currentAnimationProperties.getCurrentFrame();
}
});
_previousAnimationProperties = this->getAnimationProperties();
}
if (isAnimatingSomething()) {
if (!(getAnimationFirstFrame() < 0) && !(getAnimationFirstFrame() > getAnimationLastFrame())) {
updateFrameCount();
}
}
}
EntityItem::update(now);
}
bool ModelEntityItem::needsToCallUpdate() const {
return true;
}
void ModelEntityItem::updateFrameCount() {
if (_currentFrame < 0.0f) {
return;
}
if (!_lastAnimated) {
_lastAnimated = usecTimestampNow();
return;
}
auto now = usecTimestampNow();
// update the interval since the last animation.
auto interval = now - _lastAnimated; auto interval = now - _lastAnimated;
_lastAnimated = now; _lastAnimated = now;
// if fps is negative then increment timestamp and return. // grab a local copy of _animationProperties to avoid multiple locks
if (getAnimationFPS() < 0.0f) { auto animationProperties = getAnimationProperties();
// bail on "hold"
if (animationProperties.getHold()) {
return; return;
} }
int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1; // increment animation frame
_currentFrame += (animationProperties.getFPS() * ((float)interval) / (float)USECS_PER_SECOND);
if (!getAnimationHold() && getAnimationIsPlaying()) { if (_currentFrame > animationProperties.getLastFrame() + 1.0f) {
float deltaTime = (float)interval / (float)USECS_PER_SECOND; if (animationProperties.getLoop()) {
_currentFrame += (deltaTime * getAnimationFPS()); _currentFrame = animationProperties.computeLoopedFrame(_currentFrame);
if (_currentFrame > getAnimationLastFrame() + 1) { } else {
if (getAnimationLoop() && getAnimationFirstFrame() != getAnimationLastFrame()) { _currentFrame = animationProperties.getLastFrame();
_currentFrame = getAnimationFirstFrame() + (int)(_currentFrame - getAnimationFirstFrame()) % updatedFrameCount; }
} else { } else if (_currentFrame < animationProperties.getFirstFrame()) {
_currentFrame = getAnimationLastFrame(); if (animationProperties.getFirstFrame() < 0.0f) {
} _currentFrame = 0.0f;
} else if (_currentFrame < getAnimationFirstFrame()) { } else {
if (getAnimationFirstFrame() < 0) { _currentFrame = animationProperties.getFirstFrame();
_currentFrame = 0;
} else {
_currentFrame = getAnimationFirstFrame();
}
} }
// qCDebug(entities) << "in update frame " << _currentFrame;
setAnimationCurrentFrame(_currentFrame);
} }
setAnimationCurrentFrame(_currentFrame);
EntityItem::update(now);
} }
void ModelEntityItem::debugDump() const { void ModelEntityItem::debugDump() const {
@ -361,67 +300,61 @@ void ModelEntityItem::setAnimationURL(const QString& url) {
} }
void ModelEntityItem::setAnimationSettings(const QString& value) { void ModelEntityItem::setAnimationSettings(const QString& value) {
// the animations setting is a JSON string that may contain various animation settings. // NOTE: this method only called for old bitstream format
// if it includes fps, currentFrame, or running, those values will be parsed out and
// will over ride the regular animation settings
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); withWriteLock([&] {
QJsonObject settingsAsJsonObject = settingsAsJson.object(); auto animationProperties = _animationProperties;
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
if (settingsMap.contains("fps")) {
float fps = settingsMap["fps"].toFloat();
setAnimationFPS(fps);
}
// old settings used frameIndex // the animations setting is a JSON string that may contain various animation settings.
if (settingsMap.contains("frameIndex")) { // if it includes fps, currentFrame, or running, those values will be parsed out and
float currentFrame = settingsMap["frameIndex"].toFloat(); // will over ride the regular animation settings
#ifdef WANT_DEBUG QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
if (!getAnimationURL().isEmpty()) { QJsonObject settingsAsJsonObject = settingsAsJson.object();
qCDebug(entities) << "ModelEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
qCDebug(entities) << " model URL:" << getModelURL(); if (settingsMap.contains("fps")) {
qCDebug(entities) << " animation URL:" << getAnimationURL(); float fps = settingsMap["fps"].toFloat();
qCDebug(entities) << " settings:" << value; animationProperties.setFPS(fps);
qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"];
qCDebug(entities" currentFrame: %20.5f", currentFrame);
} }
#endif
setAnimationCurrentFrame(currentFrame); // old settings used frameIndex
} if (settingsMap.contains("frameIndex")) {
float currentFrame = settingsMap["frameIndex"].toFloat();
if (settingsMap.contains("running")) { animationProperties.setCurrentFrame(currentFrame);
bool running = settingsMap["running"].toBool();
if (running != getAnimationIsPlaying()) {
setAnimationIsPlaying(running);
} }
}
if (settingsMap.contains("firstFrame")) { if (settingsMap.contains("running")) {
float firstFrame = settingsMap["firstFrame"].toFloat(); bool running = settingsMap["running"].toBool();
setAnimationFirstFrame(firstFrame); if (running != animationProperties.getRunning()) {
} animationProperties.setRunning(running);
}
}
if (settingsMap.contains("lastFrame")) { if (settingsMap.contains("firstFrame")) {
float lastFrame = settingsMap["lastFrame"].toFloat(); float firstFrame = settingsMap["firstFrame"].toFloat();
setAnimationLastFrame(lastFrame); animationProperties.setFirstFrame(firstFrame);
} }
if (settingsMap.contains("loop")) { if (settingsMap.contains("lastFrame")) {
bool loop = settingsMap["loop"].toBool(); float lastFrame = settingsMap["lastFrame"].toFloat();
setAnimationLoop(loop); animationProperties.setLastFrame(lastFrame);
} }
if (settingsMap.contains("hold")) { if (settingsMap.contains("loop")) {
bool hold = settingsMap["hold"].toBool(); bool loop = settingsMap["loop"].toBool();
setAnimationHold(hold); animationProperties.setLoop(loop);
} }
if (settingsMap.contains("allowTranslation")) { if (settingsMap.contains("hold")) {
bool allowTranslation = settingsMap["allowTranslation"].toBool(); bool hold = settingsMap["hold"].toBool();
setAnimationAllowTranslation(allowTranslation); animationProperties.setHold(hold);
} }
_flags |= Simulation::DIRTY_UPDATEABLE;
if (settingsMap.contains("allowTranslation")) {
bool allowTranslation = settingsMap["allowTranslation"].toBool();
animationProperties.setAllowTranslation(allowTranslation);
}
applyNewAnimationProperties(animationProperties);
});
} }
void ModelEntityItem::setAnimationIsPlaying(bool value) { void ModelEntityItem::setAnimationIsPlaying(bool value) {
@ -713,11 +646,45 @@ float ModelEntityItem::getAnimationFPS() const {
}); });
} }
bool ModelEntityItem::isAnimatingSomething() const { bool ModelEntityItem::isAnimatingSomething() const {
return resultWithReadLock<bool>([&] { return resultWithReadLock<bool>([&] {
return !_animationProperties.getURL().isEmpty() && return _animationProperties.isValidAndRunning();
_animationProperties.getRunning() && });
(_animationProperties.getFPS() != 0.0f); }
});
bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProperties) {
// call applyNewAnimationProperties() whenever trying to update _animationProperties
// because there is some reset logic we need to do whenever the animation "config" properties change
// NOTE: this private method is always called inside withWriteLock()
// if we hit start animation or change the first or last frame then restart the animation
if ((newProperties.getFirstFrame() != _animationProperties.getFirstFrame()) ||
(newProperties.getLastFrame() != _animationProperties.getLastFrame()) ||
(newProperties.getRunning() && !_animationProperties.getRunning())) {
// when we start interface and the property is are set then the current frame is initialized to -1
if (_currentFrame < 0.0f) {
// don't reset _lastAnimated here because we need the timestamp from the ModelEntityItem constructor for when the properties were set
_currentFrame = newProperties.getCurrentFrame();
newProperties.setCurrentFrame(_currentFrame);
} else {
_lastAnimated = usecTimestampNow();
_currentFrame = newProperties.getFirstFrame();
newProperties.setCurrentFrame(newProperties.getFirstFrame());
}
} else if (!newProperties.getRunning() && _animationProperties.getRunning()) {
_currentFrame = newProperties.getFirstFrame();
newProperties.setCurrentFrame(_currentFrame);
} else if (newProperties.getCurrentFrame() != _animationProperties.getCurrentFrame()) {
// don't reset _lastAnimated here because the currentFrame was set with the previous setting of _lastAnimated
_currentFrame = newProperties.getCurrentFrame();
}
// finally apply the changes
bool somethingChanged = newProperties != _animationProperties;
if (somethingChanged) {
_animationProperties = newProperties;
_flags |= Simulation::DIRTY_UPDATEABLE;
}
return somethingChanged;
} }

View file

@ -46,10 +46,9 @@ public:
EntityPropertyFlags& propertyFlags, bool overwriteLocalData, EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override; bool& somethingChanged) override;
// update() and needstocallupdate() added back for the entity property fix
virtual void update(const quint64& now) override; virtual void update(const quint64& now) override;
virtual bool needsToCallUpdate() const override; bool needsToCallUpdate() const override { return isAnimatingSomething(); }
void updateFrameCount();
virtual void debugDump() const override; virtual void debugDump() const override;
@ -132,6 +131,7 @@ public:
private: private:
void setAnimationSettings(const QString& value); // only called for old bitstream format void setAnimationSettings(const QString& value); // only called for old bitstream format
bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
ShapeType computeTrueShapeType() const; ShapeType computeTrueShapeType() const;
protected: protected:
@ -172,7 +172,6 @@ protected:
private: private:
uint64_t _lastAnimated{ 0 }; uint64_t _lastAnimated{ 0 };
AnimationPropertyGroup _previousAnimationProperties;
float _currentFrame{ -1.0f }; float _currentFrame{ -1.0f };
}; };

View file

@ -77,8 +77,6 @@ class PolyLineEntityItem : public EntityItem {
QString getTextures() const; QString getTextures() const;
void setTextures(const QString& textures); void setTextures(const QString& textures);
virtual bool needsToCallUpdate() const override { return true; }
virtual ShapeType getShapeType() const override { return SHAPE_TYPE_NONE; } virtual ShapeType getShapeType() const override { return SHAPE_TYPE_NONE; }
bool pointsChanged() const { return _pointsChanged; } bool pointsChanged() const { return _pointsChanged; }

View file

@ -32,7 +32,8 @@ QStringList InputConfiguration::inputPlugins() {
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
QString pluginName = plugin->getName(); QString pluginName = plugin->getName();
if (pluginName == QString("OpenVR")) { if (pluginName == QString("OpenVR")) {
inputPlugins << QString("Vive"); QString headsetName = plugin->getDeviceName();
inputPlugins << headsetName;
} else { } else {
inputPlugins << pluginName; inputPlugins << pluginName;
} }
@ -54,7 +55,8 @@ QStringList InputConfiguration::activeInputPlugins() {
if (plugin->configurable()) { if (plugin->configurable()) {
QString pluginName = plugin->getName(); QString pluginName = plugin->getName();
if (pluginName == QString("OpenVR")) { if (pluginName == QString("OpenVR")) {
activePlugins << QString("Vive"); QString headsetName = plugin->getDeviceName();
activePlugins << headsetName;
} else { } else {
activePlugins << pluginName; activePlugins << pluginName;
} }
@ -74,7 +76,7 @@ QString InputConfiguration::configurationLayout(QString pluginName) {
QString sourcePath; QString sourcePath;
for (auto plugin : PluginManager::getInstance()->getInputPlugins()) { for (auto plugin : PluginManager::getInstance()->getInputPlugins()) {
if (plugin->getName() == pluginName) { if (plugin->getName() == pluginName || plugin->getDeviceName() == pluginName) {
return plugin->configurationLayout(); return plugin->configurationLayout();
} }
} }

View file

@ -26,10 +26,11 @@ public:
// If an input plugin is only a single device, it will only return it's primary name. // If an input plugin is only a single device, it will only return it's primary name.
virtual QStringList getSubdeviceNames() { return { getName() }; }; virtual QStringList getSubdeviceNames() { return { getName() }; };
virtual void setConfigurationSettings(const QJsonObject configurationSettings) { } virtual void setConfigurationSettings(const QJsonObject configurationSettings) { }
virtual QJsonObject configurationSettings() { return QJsonObject(); } virtual QJsonObject configurationSettings() { return QJsonObject(); }
virtual QString configurationLayout() { return QString(); } virtual QString configurationLayout() { return QString(); }
virtual QString getDeviceName() { return QString(); }
virtual void calibrate() {} virtual void calibrate() {}
virtual bool uncalibrate() { return false; } virtual bool uncalibrate() { return false; }
virtual bool configurable() { return false; } virtual bool configurable() { return false; }
virtual bool isHandController() const { return false; } virtual bool isHandController() const { return false; }
virtual bool isHeadController() const { return false; } virtual bool isHeadController() const { return false; }

View file

@ -66,14 +66,10 @@ OffscreenSurface::OffscreenSurface()
} }
OffscreenSurface::~OffscreenSurface() { OffscreenSurface::~OffscreenSurface() {
disconnect(qApp); delete _sharedObject;
_sharedObject->destroy();
} }
bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) { bool OffscreenSurface::fetchTexture(TextureAndFence& textureAndFence) {
if (!_sharedObject) {
return false;
}
hifi::qml::impl::TextureAndFence typedTextureAndFence; hifi::qml::impl::TextureAndFence typedTextureAndFence;
bool result = _sharedObject->fetchTexture(typedTextureAndFence); bool result = _sharedObject->fetchTexture(typedTextureAndFence);
textureAndFence = typedTextureAndFence; textureAndFence = typedTextureAndFence;

View file

@ -49,8 +49,8 @@ RenderEventHandler::RenderEventHandler(SharedObject* shared, QThread* targetThre
qFatal("Unable to create new offscreen GL context"); qFatal("Unable to create new offscreen GL context");
} }
moveToThread(targetThread);
_canvas.moveToThreadWithContext(targetThread); _canvas.moveToThreadWithContext(targetThread);
moveToThread(targetThread);
} }
void RenderEventHandler::onInitalize() { void RenderEventHandler::onInitalize() {
@ -160,11 +160,8 @@ void RenderEventHandler::onQuit() {
} }
_shared->shutdownRendering(_canvas, _currentSize); _shared->shutdownRendering(_canvas, _currentSize);
// Release the reference to the shared object. This will allow it to _canvas.doneCurrent();
// be destroyed (should happen on it's own thread). _canvas.moveToThreadWithContext(qApp->thread());
_shared->deleteLater(); moveToThread(qApp->thread());
deleteLater();
QThread::currentThread()->quit(); QThread::currentThread()->quit();
} }

View file

@ -72,26 +72,35 @@ SharedObject::SharedObject() {
QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SharedObject::onAboutToQuit); QObject::connect(qApp, &QCoreApplication::aboutToQuit, this, &SharedObject::onAboutToQuit);
} }
SharedObject::~SharedObject() { SharedObject::~SharedObject() {
if (_quickWindow) { // After destroy returns, the rendering thread should be gone
_quickWindow->destroy(); destroy();
_quickWindow = nullptr;
// _renderTimer is created with `this` as the parent, so need no explicit destruction
// Destroy the event hand
if (_renderObject) {
delete _renderObject;
_renderObject = nullptr;
} }
if (_renderControl) { if (_renderControl) {
_renderControl->deleteLater(); delete _renderControl;
_renderControl = nullptr; _renderControl = nullptr;
} }
if (_renderThread) { if (_quickWindow) {
_renderThread->quit(); _quickWindow->destroy();
_renderThread->deleteLater(); delete _quickWindow;
_quickWindow = nullptr;
} }
if (_rootItem) { // _rootItem is parented to the quickWindow, so needs no explicit destruction
_rootItem->deleteLater(); //if (_rootItem) {
_rootItem = nullptr; // delete _rootItem;
} // _rootItem = nullptr;
//}
releaseEngine(_qmlContext->engine()); releaseEngine(_qmlContext->engine());
} }
@ -119,6 +128,10 @@ void SharedObject::create(OffscreenSurface* surface) {
} }
void SharedObject::setRootItem(QQuickItem* rootItem) { void SharedObject::setRootItem(QQuickItem* rootItem) {
if (_quit) {
return;
}
_rootItem = rootItem; _rootItem = rootItem;
_rootItem->setSize(_quickWindow->size()); _rootItem->setSize(_quickWindow->size());
@ -127,7 +140,6 @@ void SharedObject::setRootItem(QQuickItem* rootItem) {
_renderThread->setObjectName(objectName()); _renderThread->setObjectName(objectName());
_renderThread->start(); _renderThread->start();
// Create event handler for the render thread // Create event handler for the render thread
_renderObject = new RenderEventHandler(this, _renderThread); _renderObject = new RenderEventHandler(this, _renderThread);
QCoreApplication::postEvent(this, new OffscreenEvent(OffscreenEvent::Initialize)); QCoreApplication::postEvent(this, new OffscreenEvent(OffscreenEvent::Initialize));
@ -137,35 +149,43 @@ void SharedObject::setRootItem(QQuickItem* rootItem) {
} }
void SharedObject::destroy() { void SharedObject::destroy() {
// `destroy` is idempotent, it can be called multiple times without issues
if (_quit) { if (_quit) {
return; return;
} }
if (!_rootItem) { if (!_rootItem) {
deleteLater();
return; return;
} }
_paused = true; _paused = true;
if (_renderTimer) { if (_renderTimer) {
_renderTimer->stop();
QObject::disconnect(_renderTimer); QObject::disconnect(_renderTimer);
_renderTimer->deleteLater();
} }
QObject::disconnect(_renderControl); if (_renderControl) {
QObject::disconnect(_renderControl);
}
QObject::disconnect(qApp); QObject::disconnect(qApp);
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
_quit = true; _quit = true;
QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority); if (_renderObject) {
QCoreApplication::postEvent(_renderObject, new OffscreenEvent(OffscreenEvent::Quit), Qt::HighEventPriority);
}
} }
// Block until the rendering thread has stopped // Block until the rendering thread has stopped
// FIXME this is undesirable because this is blocking the main thread, // FIXME this is undesirable because this is blocking the main thread,
// but I haven't found a reliable way to do this only at application // but I haven't found a reliable way to do this only at application
// shutdown // shutdown
_renderThread->wait(); if (_renderThread) {
_renderThread->wait();
delete _renderThread;
_renderThread = nullptr;
}
} }

View file

@ -37,15 +37,25 @@ public:
virtual glm::vec3 getAvatarPosition() const = 0; virtual glm::vec3 getAvatarPosition() const = 0;
virtual bool isAboutToQuit() const = 0; // Unfortunately, having this here is a bad idea. Lots of objects connect to
virtual void postLambdaEvent(std::function<void()> f) = 0; // the aboutToQuit signal, and it's impossible to know the order in which
// the receivers will be called, so this might return false negatives
//virtual bool isAboutToQuit() const = 0;
// Queue code to execute on the main thread.
// If called from the main thread, the lambda will execute synchronously
virtual void postLambdaEvent(const std::function<void()>& f) = 0;
// Synchronously execute code on the main thread. This function will
// not return until the code is executed, regardles of which thread it
// is called from
virtual void sendLambdaEvent(const std::function<void()>& f) = 0;
virtual qreal getDevicePixelRatio() = 0; virtual qreal getDevicePixelRatio() = 0;
virtual render::ScenePointer getMain3DScene() = 0; virtual render::ScenePointer getMain3DScene() = 0;
virtual render::EnginePointer getRenderEngine() = 0; virtual render::EnginePointer getRenderEngine() = 0;
virtual void pushPostUpdateLambda(void* key, std::function<void()> func) = 0; virtual void pushPostUpdateLambda(void* key, const std::function<void()>& func) = 0;
virtual bool isHMDMode() const = 0; virtual bool isHMDMode() const = 0;
@ -54,5 +64,4 @@ public:
static void setInstance(AbstractViewStateInterface* instance); static void setInstance(AbstractViewStateInterface* instance);
}; };
#endif // hifi_AbstractViewStateInterface_h
#endif // hifi_AbstractViewStateInterface_h

View file

@ -36,7 +36,6 @@
Q_DECLARE_LOGGING_CATEGORY(displayplugins) Q_DECLARE_LOGGING_CATEGORY(displayplugins)
const char* OpenVrDisplayPlugin::NAME { "OpenVR (Vive)" };
const char* StandingHMDSensorMode { "Standing HMD Sensor Mode" }; // this probably shouldn't be hardcoded here const char* StandingHMDSensorMode { "Standing HMD Sensor Mode" }; // this probably shouldn't be hardcoded here
const char* OpenVrThreadedSubmit { "OpenVR Threaded Submit" }; // this probably shouldn't be hardcoded here const char* OpenVrThreadedSubmit { "OpenVR Threaded Submit" }; // this probably shouldn't be hardcoded here
@ -410,6 +409,15 @@ void OpenVrDisplayPlugin::init() {
emit deviceConnected(getName()); emit deviceConnected(getName());
} }
const QString OpenVrDisplayPlugin::getName() const {
std::string headsetName = getOpenVrDeviceName();
if (headsetName == "HTC") {
headsetName += " Vive";
}
return QString::fromStdString(headsetName);
}
bool OpenVrDisplayPlugin::internalActivate() { bool OpenVrDisplayPlugin::internalActivate() {
if (!_system) { if (!_system) {
_system = acquireOpenVrSystem(); _system = acquireOpenVrSystem();
@ -444,7 +452,6 @@ bool OpenVrDisplayPlugin::internalActivate() {
_openVrDisplayActive = true; _openVrDisplayActive = true;
_container->setIsOptionChecked(StandingHMDSensorMode, true); _container->setIsOptionChecked(StandingHMDSensorMode, true);
_system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y); _system->GetRecommendedRenderTargetSize(&_renderTargetSize.x, &_renderTargetSize.y);
// Recommended render target size is per-eye, so double the X size for // Recommended render target size is per-eye, so double the X size for
// left + right eyes // left + right eyes

View file

@ -36,7 +36,7 @@ class OpenVrDisplayPlugin : public HmdDisplayPlugin {
using Parent = HmdDisplayPlugin; using Parent = HmdDisplayPlugin;
public: public:
bool isSupported() const override; bool isSupported() const override;
const QString getName() const override { return NAME; } const QString getName() const override;
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override; glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override; glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
@ -78,7 +78,6 @@ private:
vr::IVRSystem* _system { nullptr }; vr::IVRSystem* _system { nullptr };
std::atomic<vr::EDeviceActivityLevel> _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown }; std::atomic<vr::EDeviceActivityLevel> _hmdActivityLevel { vr::k_EDeviceActivityLevel_Unknown };
std::atomic<uint32_t> _keyboardSupressionCount{ 0 }; std::atomic<uint32_t> _keyboardSupressionCount{ 0 };
static const char* NAME;
vr::HmdMatrix34_t _lastGoodHMDPose; vr::HmdMatrix34_t _lastGoodHMDPose;
mat4 _sensorResetMat; mat4 _sensorResetMat;

View file

@ -66,6 +66,22 @@ bool oculusViaOpenVR() {
return enableDebugOpenVR && isOculusPresent() && vr::VR_IsHmdPresent(); return enableDebugOpenVR && isOculusPresent() && vr::VR_IsHmdPresent();
} }
std::string getOpenVrDeviceName() {
auto system = acquireOpenVrSystem();
std::string trackingSystemName = "";
if (system) {
uint32_t HmdTrackingIndex = 0;
uint32_t bufferLength = system->GetStringTrackedDeviceProperty(HmdTrackingIndex, vr::Prop_TrackingSystemName_String, NULL, 0, NULL);
if (bufferLength > 0) {
char* stringBuffer = new char[bufferLength];
system->GetStringTrackedDeviceProperty(HmdTrackingIndex, vr::Prop_ManufacturerName_String, stringBuffer, bufferLength, NULL);
trackingSystemName = stringBuffer;
delete[] stringBuffer;
}
}
return trackingSystemName;
}
bool openVrSupported() { bool openVrSupported() {
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR"); static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR");
static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);

View file

@ -14,6 +14,7 @@
#include <controllers/Forward.h> #include <controllers/Forward.h>
#include <plugins/Forward.h> #include <plugins/Forward.h>
#include <string>
bool oculusViaOpenVR(); // is the user using Oculus via OpenVR bool oculusViaOpenVR(); // is the user using Oculus via OpenVR
bool openVrSupported(); bool openVrSupported();
@ -26,6 +27,7 @@ void enableOpenVrKeyboard(PluginContainer* container);
void disableOpenVrKeyboard(); void disableOpenVrKeyboard();
bool isOpenVrKeyboardShown(); bool isOpenVrKeyboardShown();
QString getVrSettingString(const char* section, const char* setting); QString getVrSettingString(const char* section, const char* setting);
std::string getOpenVrDeviceName();
template<typename F> template<typename F>

View file

@ -11,6 +11,7 @@
#include "ViveControllerManager.h" #include "ViveControllerManager.h"
#include <algorithm> #include <algorithm>
#include <string>
#include <PerfStat.h> #include <PerfStat.h>
#include <PathUtils.h> #include <PathUtils.h>
@ -339,6 +340,12 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle
_validTrackedObjects.clear(); _validTrackedObjects.clear();
_trackedControllers = 0; _trackedControllers = 0;
if (_headsetName == "") {
_headsetName = getOpenVrDeviceName();
if (_headsetName == "HTC") {
_headsetName += " Vive";
}
}
// While the keyboard is open, we defer strictly to the keyboard values // While the keyboard is open, we defer strictly to the keyboard values
if (isOpenVrKeyboardShown()) { if (isOpenVrKeyboardShown()) {
_axisStateMap.clear(); _axisStateMap.clear();

View file

@ -52,6 +52,8 @@ public:
bool activate() override; bool activate() override;
void deactivate() override; void deactivate() override;
QString getDeviceName() { return QString::fromStdString(_inputDevice->_headsetName); }
void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
@ -161,6 +163,7 @@ private:
HandConfig _handConfig { HandConfig::HandController }; HandConfig _handConfig { HandConfig::HandController };
FilteredStick _filteredLeftStick; FilteredStick _filteredLeftStick;
FilteredStick _filteredRightStick; FilteredStick _filteredRightStick;
std::string _headsetName {""};
std::vector<PuckPosePair> _validTrackedObjects; std::vector<PuckPosePair> _validTrackedObjects;
std::map<uint32_t, glm::mat4> _pucksPostOffset; std::map<uint32_t, glm::mat4> _pucksPostOffset;

View file

@ -453,8 +453,8 @@ protected:
return vec3(); return vec3();
} }
bool isAboutToQuit() const override { return false; } void postLambdaEvent(const std::function<void()>& f) override {}
void postLambdaEvent(std::function<void()> f) override {} void sendLambdaEvent(const std::function<void()>& f) override {}
qreal getDevicePixelRatio() override { qreal getDevicePixelRatio() override {
return 1.0f; return 1.0f;
@ -469,7 +469,7 @@ protected:
} }
std::map<void*, std::function<void()>> _postUpdateLambdas; std::map<void*, std::function<void()>> _postUpdateLambdas;
void pushPostUpdateLambda(void* key, std::function<void()> func) override { void pushPostUpdateLambda(void* key, const std::function<void()>& func) override {
_postUpdateLambdas[key] = func; _postUpdateLambdas[key] = func;
} }