From 31a23acb1a43a274f4889bf47ee8606c815834e2 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 6 Sep 2017 23:04:58 +0200 Subject: [PATCH 01/12] Add flickable on mouse wheel to web pages --- interface/resources/qml/controls/FlickableWebViewCore.qml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index 0460b5b16a..13a435c4e5 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -19,6 +19,7 @@ Flickable { signal newViewRequestedCallback(var request) signal loadingChangedCallback(var loadRequest) + pressDelay: 300 boundsBehavior: Flickable.StopAtBounds @@ -167,4 +168,11 @@ Flickable { playing: visible z: 10000 } + + MouseArea { + anchors.fill: parent + onWheel: { + flick.flick(0, wheel.angleDelta.y*10) + } + } } From 37b184d9829962d5458386ff5b81669f0798bf8a Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 7 Sep 2017 14:32:50 -0700 Subject: [PATCH 02/12] Fix crashes in entity rendering on OSX --- .../RenderableParticleEffectEntityItem.cpp | 93 ++++++++++--------- .../src/RenderableParticleEffectEntityItem.h | 3 +- .../src/RenderableTextEntityItem.cpp | 5 +- .../src/RenderableTextEntityItem.h | 5 +- .../entities/src/ParticleEffectEntityItem.cpp | 15 ++- .../entities/src/ParticleEffectEntityItem.h | 4 +- 6 files changed, 70 insertions(+), 55 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 7349e9147e..3328076911 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -91,20 +91,27 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi qCWarning(entitiesrenderer) << "Bad particle properties"; } } - if (_particleProperties != newParticleProperties) { + + if (resultWithReadLock([&]{ return _particleProperties != newParticleProperties; })) { _timeUntilNextEmit = 0; - _particleProperties = newParticleProperties; + withWriteLock([&]{ + _particleProperties = newParticleProperties; + }); } _emitting = entity->getIsEmitting(); - if (_particleProperties.textures.isEmpty()) { + bool hasTexture = resultWithReadLock([&]{ return _particleProperties.textures.isEmpty(); }); + if (hasTexture) { if (_networkTexture) { withWriteLock([&] { _networkTexture.reset(); }); } } else { - if (!_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures)) { + bool textureNeedsUpdate = resultWithReadLock([&]{ + return !_networkTexture || _networkTexture->getURL() != QUrl(_particleProperties.textures); + }); + if (textureNeedsUpdate) { withWriteLock([&] { _networkTexture = DependencyManager::get()->getTexture(_particleProperties.textures); }); @@ -115,15 +122,17 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { // Fill in Uniforms structure ParticleUniforms particleUniforms; - particleUniforms.radius.start = _particleProperties.radius.range.start; - particleUniforms.radius.middle = _particleProperties.radius.gradient.target; - particleUniforms.radius.finish = _particleProperties.radius.range.finish; - particleUniforms.radius.spread = _particleProperties.radius.gradient.spread; - particleUniforms.color.start = _particleProperties.getColorStart(); - particleUniforms.color.middle = _particleProperties.getColorMiddle(); - particleUniforms.color.finish = _particleProperties.getColorFinish(); - particleUniforms.color.spread = _particleProperties.getColorSpread(); - particleUniforms.lifespan = _particleProperties.lifespan; + withReadLock([&]{ + particleUniforms.radius.start = _particleProperties.radius.range.start; + particleUniforms.radius.middle = _particleProperties.radius.gradient.target; + particleUniforms.radius.finish = _particleProperties.radius.range.finish; + particleUniforms.radius.spread = _particleProperties.radius.gradient.spread; + particleUniforms.color.start = _particleProperties.getColorStart(); + particleUniforms.color.middle = _particleProperties.getColorMiddle(); + particleUniforms.color.finish = _particleProperties.getColorFinish(); + particleUniforms.color.spread = _particleProperties.getColorSpread(); + particleUniforms.lifespan = _particleProperties.lifespan; + }); // Update particle uniforms memcpy(&_uniformBuffer.edit(), &particleUniforms, sizeof(ParticleUniforms)); } @@ -146,35 +155,26 @@ Item::Bound ParticleEffectEntityRenderer::getBound() { static const size_t VERTEX_PER_PARTICLE = 4; -bool ParticleEffectEntityRenderer::emitting() const { - return ( - _emitting && - _particleProperties.emission.rate > 0.0f && - _particleProperties.lifespan > 0.0f && - _particleProperties.polar.start <= _particleProperties.polar.finish - ); -} - -void ParticleEffectEntityRenderer::createParticle(uint64_t now) { +ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties) { CpuParticle particle; - const auto& accelerationSpread = _particleProperties.emission.acceleration.spread; - const auto& azimuthStart = _particleProperties.azimuth.start; - const auto& azimuthFinish = _particleProperties.azimuth.finish; - const auto& emitDimensions = _particleProperties.emission.dimensions; - const auto& emitAcceleration = _particleProperties.emission.acceleration.target; - auto emitOrientation = _particleProperties.emission.orientation; - const auto& emitRadiusStart = glm::max(_particleProperties.radiusStart, EPSILON); // Avoid math complications at center - const auto& emitSpeed = _particleProperties.emission.speed.target; - const auto& speedSpread = _particleProperties.emission.speed.spread; - const auto& polarStart = _particleProperties.polar.start; - const auto& polarFinish = _particleProperties.polar.finish; + const auto& accelerationSpread = particleProperties.emission.acceleration.spread; + const auto& azimuthStart = particleProperties.azimuth.start; + const auto& azimuthFinish = particleProperties.azimuth.finish; + const auto& emitDimensions = particleProperties.emission.dimensions; + const auto& emitAcceleration = particleProperties.emission.acceleration.target; + auto emitOrientation = particleProperties.emission.orientation; + const auto& emitRadiusStart = glm::max(particleProperties.radiusStart, EPSILON); // Avoid math complications at center + const auto& emitSpeed = particleProperties.emission.speed.target; + const auto& speedSpread = particleProperties.emission.speed.spread; + const auto& polarStart = particleProperties.polar.start; + const auto& polarFinish = particleProperties.polar.finish; particle.seed = randFloatInRange(-1.0f, 1.0f); - particle.expiration = now + (uint64_t)(_particleProperties.lifespan * USECS_PER_SECOND); - if (_particleProperties.emission.shouldTrail) { - particle.position = _modelTransform.getTranslation(); - emitOrientation = _modelTransform.getRotation() * emitOrientation; + particle.expiration = now + (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); + if (particleProperties.emission.shouldTrail) { + particle.position = baseTransform.getTranslation(); + emitOrientation = baseTransform.getRotation() * emitOrientation; } // Position, velocity, and acceleration @@ -232,7 +232,7 @@ void ParticleEffectEntityRenderer::createParticle(uint64_t now) { particle.acceleration = emitAcceleration + randFloatInRange(-1.0f, 1.0f) * accelerationSpread; } - _cpuParticles.push_back(particle); + return particle; } void ParticleEffectEntityRenderer::stepSimulation() { @@ -244,14 +244,19 @@ void ParticleEffectEntityRenderer::stepSimulation() { const auto now = usecTimestampNow(); const auto interval = std::min(USECS_PER_SECOND / 60, now - _lastSimulated); _lastSimulated = now; + + particle::Properties particleProperties; + withReadLock([&]{ + particleProperties = _particleProperties; + }); - if (emitting()) { - uint64_t emitInterval = (uint64_t)(USECS_PER_SECOND / _particleProperties.emission.rate); - if (interval >= _timeUntilNextEmit) { + if (_emitting && particleProperties.emitting()) { + uint64_t emitInterval = particleProperties.emitIntervalUsecs(); + if (emitInterval > 0 && interval >= _timeUntilNextEmit) { auto timeRemaining = interval; while (timeRemaining > _timeUntilNextEmit) { // emit particle - createParticle(now); + _cpuParticles.push_back(createParticle(now, _modelTransform, particleProperties)); _timeUntilNextEmit = emitInterval; if (emitInterval < timeRemaining) { timeRemaining -= emitInterval; @@ -263,7 +268,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { } // Kill any particles that have expired or are over the max size - while (_cpuParticles.size() > _particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) { + while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) { _cpuParticles.pop_front(); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index e4c1d4be13..be2641c0c9 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -93,9 +93,8 @@ private: }; - void createParticle(uint64_t now); + static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties); void stepSimulation(); - bool emitting() const; particle::Properties _particleProperties; CpuParticles _cpuParticles; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index d39139257b..8757bcbb0f 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -30,14 +30,11 @@ TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) : } - -void TextEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) { +TextEntityRenderer::~TextEntityRenderer() { auto geometryCache = DependencyManager::get(); if (_geometryID && geometryCache) { geometryCache->releaseID(_geometryID); } - delete _textRenderer; - _textRenderer = nullptr; } bool TextEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 1d8227069e..b0a72cf253 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -24,14 +24,13 @@ class TextEntityRenderer : public TypedEntityRenderer { using Pointer = std::shared_ptr; public: TextEntityRenderer(const EntityItemPointer& entity); - + ~TextEntityRenderer(); private: - virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; virtual void doRender(RenderArgs* args) override; int _geometryID{ 0 }; - TextRenderer3D* _textRenderer; + std::shared_ptr _textRenderer; bool _faceCamera; glm::vec3 _dimensions; glm::vec3 _textColor; diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index bc6830e1a7..9bbf4323da 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -104,7 +104,7 @@ bool operator!=(const Properties& a, const Properties& b) { return !(a == b); } -bool particle::Properties::valid() const { +bool Properties::valid() const { if (glm::any(glm::isnan(emission.orientation))) { qCWarning(entities) << "Bad particle data"; return false; @@ -133,6 +133,19 @@ bool particle::Properties::valid() const { (radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)); } +bool Properties::emitting() const { + return emission.rate > 0.0f && lifespan > 0.0f && polar.start <= polar.finish; + +} + +uint64_t Properties::emitIntervalUsecs() const { + if (emission.rate > 0.0f) { + return (uint64_t)(USECS_PER_SECOND / emission.rate); + } + return 0; +} + + EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity { new ParticleEffectEntityItem(entityID) }; entity->setProperties(properties); diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 6a3791f77e..9c0fd0ef95 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -160,7 +160,9 @@ namespace particle { Properties() {}; Properties(const Properties& other) { *this = other; } bool valid() const; - + bool emitting() const; + uint64_t emitIntervalUsecs() const; + Properties& operator =(const Properties& other) { color = other.color; alpha = other.alpha; From eb8b892571df62edcdfe44ff4e8c8a31ca9a5ef5 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Thu, 7 Sep 2017 14:45:35 -0700 Subject: [PATCH 03/12] Various Mac fixes --- interface/src/main.cpp | 23 ++++++++++++++----- .../src/EntityTreeRenderer.cpp | 7 +++++- libraries/gl/src/gl/GLHelpers.cpp | 7 ++++-- libraries/gpu-gl/src/gpu/gl/GLTexture.cpp | 12 ++++++---- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 11 +++++---- 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 503daa177d..cb90160cfe 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -144,25 +144,33 @@ int main(int argc, const char* argv[]) { #endif } + + // FIXME this method of checking the OpenGL version screws up the `QOpenGLContext::globalShareContext()` value, which in turn + // leads to crashes when creating the real OpenGL instance. Disabling for now until we come up with a better way of checking + // the GL version on the system without resorting to creating a full Qt application +#if 0 // Check OpenGL version. // This is done separately from the main Application so that start-up and shut-down logic within the main Application is // not made more complicated than it already is. - bool override = false; + bool overrideGLCheck = false; + QJsonObject glData; { OpenGLVersionChecker openGLVersionChecker(argc, const_cast(argv)); bool valid = true; - glData = openGLVersionChecker.checkVersion(valid, override); + glData = openGLVersionChecker.checkVersion(valid, overrideGLCheck); if (!valid) { - if (override) { + if (overrideGLCheck) { auto glVersion = glData["version"].toString(); - qCDebug(interfaceapp, "Running on insufficient OpenGL version: %s.", glVersion.toStdString().c_str()); + qCWarning(interfaceapp, "Running on insufficient OpenGL version: %s.", glVersion.toStdString().c_str()); } else { - qCDebug(interfaceapp, "Early exit due to OpenGL version."); + qCWarning(interfaceapp, "Early exit due to OpenGL version."); return 0; } } } +#endif + // Debug option to demonstrate that the client's local time does not // need to be in sync with any other network node. This forces clock @@ -223,8 +231,9 @@ int main(int argc, const char* argv[]) { Application app(argcExtended, const_cast(argvExtended.data()), startupTime, runningMarkerExisted); +#if 0 // If we failed the OpenGLVersion check, log it. - if (override) { + if (overrideGLcheck) { auto accountManager = DependencyManager::get(); if (accountManager->isLoggedIn()) { UserActivityLogger::getInstance().insufficientGLVersion(glData); @@ -238,6 +247,8 @@ int main(int argc, const char* argv[]) { }); } } +#endif + // Setup local server QLocalServer server { &app }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 9f4a9a3c4a..d754d59721 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -91,7 +91,12 @@ void entitiesScriptEngineDeleter(ScriptEngine* engine) { }; // Wait for the scripting thread from the thread pool to avoid hanging the main thread - QThreadPool::globalInstance()->start(new WaitRunnable(engine)); + auto threadPool = QThreadPool::globalInstance(); + if (threadPool) { + threadPool->start(new WaitRunnable(engine)); + } else { + delete engine; + } } void EntityTreeRenderer::resetEntitiesScriptEngine() { diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index ab91ca0902..28982703dd 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -40,8 +40,11 @@ const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { int glVersionToInteger(QString glVersion) { QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); - int majorNumber = versionParts[0].toInt(); - int minorNumber = versionParts[1].toInt(); + int majorNumber = 0, minorNumber = 0; + if (versionParts.size() >= 2) { + majorNumber = versionParts[0].toInt(); + minorNumber = versionParts[1].toInt(); + } return (majorNumber << 16) | minorNumber; } diff --git a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp index 7758ddaf49..943b8148ef 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLTexture.cpp @@ -467,12 +467,14 @@ void GLVariableAllocationSupport::updateMemoryPressure() { _demoteQueue = WorkQueue(); // Populate the existing textures into the queue - for (const auto& texture : strongTextures) { - // Race conditions can still leave nulls in the list, so we need to check - if (!texture) { - continue; + if (_memoryPressureState != MemoryPressureState::Idle) { + for (const auto& texture : strongTextures) { + // Race conditions can still leave nulls in the list, so we need to check + if (!texture) { + continue; + } + addToWorkQueue(texture); } - addToWorkQueue(texture); } } } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 84466f41b0..11790041db 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -528,6 +528,12 @@ void OffscreenQmlSurface::create() { connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, &OffscreenQmlSurface::onFocusObjectChanged); + // acquireEngine interrogates the GL context, so we need to have the context current here + if (!_canvas->makeCurrent()) { + qFatal("Failed to make context current for QML Renderer"); + return; + } + // Create a QML engine. auto qmlEngine = acquireEngine(_quickWindow); @@ -540,11 +546,6 @@ void OffscreenQmlSurface::create() { // FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper // Find a way to flag older scripts using this mechanism and wanr that this is deprecated _qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, _qmlContext)); - - if (!_canvas->makeCurrent()) { - qWarning("Failed to make context current for QML Renderer"); - return; - } _renderControl->initialize(_canvas->getContext()); // When Quick says there is a need to render, we will not render immediately. Instead, From 48b6586d01f5f4eb27af3ad04b6ff80d2ab43e8d Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 8 Sep 2017 11:36:32 -0700 Subject: [PATCH 04/12] Modifying SDL initialization due to crash on OSX --- plugins/hifiSdl2/src/SDL2Manager.cpp | 98 +++++++++++++++------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/plugins/hifiSdl2/src/SDL2Manager.cpp b/plugins/hifiSdl2/src/SDL2Manager.cpp index 021cb4dfec..a5376af24e 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.cpp +++ b/plugins/hifiSdl2/src/SDL2Manager.cpp @@ -54,49 +54,6 @@ SDL_JoystickID SDL2Manager::getInstanceId(SDL_GameController* controller) { } void SDL2Manager::init() { - loadSettings(); - - auto preferences = DependencyManager::get(); - static const QString SDL2_PLUGIN { "Game Controller" }; - { - auto getter = [this]()->bool { return _isEnabled; }; - auto setter = [this](bool value) { - _isEnabled = value; - saveSettings(); - }; - auto preference = new CheckPreference(SDL2_PLUGIN, "Enabled", getter, setter); - preferences->addPreference(preference); - } - - bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == 0); - - if (initSuccess) { - int joystickCount = SDL_NumJoysticks(); - - for (int i = 0; i < joystickCount; i++) { - SDL_GameController* controller = SDL_GameControllerOpen(i); - - if (controller) { - SDL_JoystickID id = getInstanceId(controller); - if (!_openJoysticks.contains(id)) { - //Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); - Joystick::Pointer joystick = std::make_shared(id, controller); - _openJoysticks[id] = joystick; - auto userInputMapper = DependencyManager::get(); - userInputMapper->registerDevice(joystick); - auto name = SDL_GameControllerName(controller); - _subdeviceNames << name; - emit joystickAdded(joystick.get()); - emit subdeviceConnected(getName(), name); - } - } - } - - _isInitialized = true; - } - else { - qDebug() << "Error initializing SDL2 Manager"; - } } QStringList SDL2Manager::getSubdeviceNames() { @@ -110,8 +67,61 @@ void SDL2Manager::deinit() { } bool SDL2Manager::activate() { + + // FIXME for some reason calling this code in the `init` function triggers a crash + // on OSX in PR builds, but not on my local debug build. Attempting a workaround by + // + static std::once_flag once; + std::call_once(once, [&]{ + loadSettings(); + + auto preferences = DependencyManager::get(); + static const QString SDL2_PLUGIN { "Game Controller" }; + { + auto getter = [this]()->bool { return _isEnabled; }; + auto setter = [this](bool value) { + _isEnabled = value; + saveSettings(); + }; + auto preference = new CheckPreference(SDL2_PLUGIN, "Enabled", getter, setter); + preferences->addPreference(preference); + } + + bool initSuccess = (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == 0); + + if (initSuccess) { + int joystickCount = SDL_NumJoysticks(); + + for (int i = 0; i < joystickCount; i++) { + SDL_GameController* controller = SDL_GameControllerOpen(i); + + if (controller) { + SDL_JoystickID id = getInstanceId(controller); + if (!_openJoysticks.contains(id)) { + //Joystick* joystick = new Joystick(id, SDL_GameControllerName(controller), controller); + Joystick::Pointer joystick = std::make_shared(id, controller); + _openJoysticks[id] = joystick; + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(joystick); + auto name = SDL_GameControllerName(controller); + _subdeviceNames << name; + emit joystickAdded(joystick.get()); + emit subdeviceConnected(getName(), name); + } + } + } + + _isInitialized = true; + } else { + qDebug() << "Error initializing SDL2 Manager"; + } + }); + + if (!_isInitialized) { + return false; + } + InputPlugin::activate(); - auto userInputMapper = DependencyManager::get(); for (auto joystick : _openJoysticks) { userInputMapper->registerDevice(joystick); From 3e0b222ec45d10c21912ac9cf9d661924c8d97fd Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 8 Sep 2017 11:44:19 -0700 Subject: [PATCH 05/12] fix wallet for new openssl --- interface/src/commerce/Wallet.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 2faa08064d..0ee53f7769 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -31,6 +31,11 @@ #include #include +// I know, right? But per https://www.openssl.org/docs/faq.html +// this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink +// at runtime. +#include + static const char* KEY_FILE = "hifikey"; static const char* IMAGE_FILE = "hifi_image"; // eventually this will live in keyfile From c1422159350e7359cdddc79f791a5e462d549e0f Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 8 Sep 2017 12:52:12 -0700 Subject: [PATCH 06/12] oops -- this is a windows-only thing (like so many other problems) --- interface/src/commerce/Wallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 0ee53f7769..a0664f4f9b 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -34,7 +34,9 @@ // I know, right? But per https://www.openssl.org/docs/faq.html // this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink // at runtime. +#ifdef Q_OS_WIN #include +#endif static const char* KEY_FILE = "hifikey"; static const char* IMAGE_FILE = "hifi_image"; // eventually this will live in keyfile From 99cdbbe306aab40c67a992fd330e67d54fc63d4f Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 8 Sep 2017 14:00:09 -0700 Subject: [PATCH 07/12] and lets fix the purchases flow too --- .../qml/hifi/commerce/purchases/Purchases.qml | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 383223a49c..d95738fc08 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -35,12 +35,20 @@ Rectangle { Hifi.QmlCommerce { id: commerce; + onAccountResult: { + if(result.status === "success") { + commerce.getKeyFilePathIfExists(); + } else { + // unsure how to handle a failure here. We definitely cannot proceed. + } + } + onLoginStatusResult: { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else if (isLoggedIn) { root.activeView = "initialize"; - commerce.getKeyFilePathIfExists(); + commerce.account(); } } @@ -174,7 +182,7 @@ Rectangle { commerce.getLoginStatus(); } } - + HifiWallet.NeedsLogIn { id: needsLogIn; visible: root.activeView === "needsLogIn"; @@ -210,7 +218,7 @@ Rectangle { } } } - + // // "WALLET NOT SET UP" START // @@ -221,7 +229,7 @@ Rectangle { anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right; - + RalewayRegular { id: notSetUpText; text: "Your wallet isn't set up.

Set up your Wallet (no credit card necessary) to claim your free HFC " + @@ -252,7 +260,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; anchors.bottomMargin: 24; - + // "Cancel" button HifiControlsUit.Button { id: cancelButton; @@ -309,7 +317,7 @@ Rectangle { anchors.topMargin: 8; anchors.bottom: actionButtonsContainer.top; anchors.bottomMargin: 8; - + // // FILTER BAR START // @@ -383,7 +391,7 @@ Rectangle { itemHref: root_file_url; anchors.topMargin: 12; anchors.bottomMargin: 12; - + Connections { onSendToPurchases: { if (msg.method === 'purchases_itemInfoClicked') { @@ -402,7 +410,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; width: parent.width; - + // Explanitory text RalewayRegular { id: haventPurchasedYet; From 0a3958f7433129b83aaae434af34b52597918f1d Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 8 Sep 2017 16:06:30 -0700 Subject: [PATCH 08/12] cr feedback --- interface/resources/qml/hifi/commerce/purchases/Purchases.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index d95738fc08..697249f740 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -36,7 +36,7 @@ Rectangle { id: commerce; onAccountResult: { - if(result.status === "success") { + if (result.status === "success") { commerce.getKeyFilePathIfExists(); } else { // unsure how to handle a failure here. We definitely cannot proceed. From 1903f65e45dcf7152ec9eeaa8b507a2dcc4910eb Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 8 Sep 2017 16:58:12 -0700 Subject: [PATCH 09/12] oops --- .../qml/hifi/commerce/checkout/Checkout.qml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 04f106d0f9..14a84311aa 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -40,12 +40,20 @@ Rectangle { Hifi.QmlCommerce { id: commerce; + onAccountResult: { + if (result.status === "success") { + commerce.getKeyFilePathIfExists(); + } else { + // unsure how to handle a failure here. We definitely cannot proceed. + } + } + onLoginStatusResult: { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else if (isLoggedIn) { root.activeView = "initialize"; - commerce.getKeyFilePathIfExists(); + commerce.account(); } } @@ -203,7 +211,7 @@ Rectangle { commerce.getLoginStatus(); } } - + HifiWallet.NeedsLogIn { id: needsLogIn; visible: root.activeView === "needsLogIn"; @@ -239,7 +247,7 @@ Rectangle { } } } - + // // "WALLET NOT SET UP" START // @@ -250,7 +258,7 @@ Rectangle { anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right; - + RalewayRegular { id: notSetUpText; text: "Your wallet isn't set up.

Set up your Wallet (no credit card necessary) to claim your free HFC " + @@ -281,7 +289,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; anchors.bottomMargin: 24; - + // "Cancel" button HifiControlsUit.Button { id: cancelButton; From 6ba6c6ee35b4001bbbd7401b8d0d4ef81b61f14d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 9 Sep 2017 18:00:21 +1200 Subject: [PATCH 10/12] Reduce entity fade-in time --- libraries/shared/src/Interpolate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/Interpolate.cpp b/libraries/shared/src/Interpolate.cpp index 35c164f0f2..cd595ee1ed 100644 --- a/libraries/shared/src/Interpolate.cpp +++ b/libraries/shared/src/Interpolate.cpp @@ -69,7 +69,7 @@ float Interpolate::simpleNonLinearBlend(float fraction) { } float Interpolate::calculateFadeRatio(quint64 start) { - const float FADE_TIME = 1.0f; + const float FADE_TIME = 0.5f; float t = 2.0f * std::min(((float)(usecTimestampNow() - start)) / ((float)(FADE_TIME * USECS_PER_SECOND)), 1.0f); float fadeRatio = (t < 1.0f) ? 0.5f * powf(2.0f, 10.0f * (t - 1.0f)) : 0.5f * (-powf(2.0f, -10.0f * (t - 1.0f)) + 2.0f); From dfaa8761e5d723403220b8b23c0608df126a4029 Mon Sep 17 00:00:00 2001 From: vladest Date: Sun, 10 Sep 2017 20:08:40 +0200 Subject: [PATCH 11/12] Make sure root item is created before lambda gets called for desktop loader --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 27 ++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index d29dc7a0f9..9015cc91d7 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -690,7 +690,6 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext return; } - QObject* newObject = qmlComponent->beginCreate(qmlContext); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -704,7 +703,20 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext } qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); - f(qmlContext, newObject); + + // All quick items should be focusable + QQuickItem* newItem = qobject_cast(newObject); + if (newItem) { + // Make sure we make items focusable (critical for + // supporting keyboard shortcuts) + newItem->setFlag(QQuickItem::ItemIsFocusScope, true); + } + + // Make sure we will call callback for this codepath + // Caal this before qmlComponent->completeCreate() otherwise ghost window appears + if (newItem && _rootItem) { + f(qmlContext, newObject); + } QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { @@ -716,15 +728,6 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext qmlComponent->completeCreate(); qmlComponent->deleteLater(); - - // All quick items should be focusable - QQuickItem* newItem = qobject_cast(newObject); - if (newItem) { - // Make sure we make items focusable (critical for - // supporting keyboard shortcuts) - newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - } - // If we already have a root, just set a couple of flags and the ancestry if (newItem && _rootItem) { // Allow child windows to be destroyed from JS @@ -747,6 +750,8 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem = newItem; _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); + // Call this callback after rootitem is set, otherwise VrMenu wont work + f(qmlContext, newObject); } void OffscreenQmlSurface::updateQuick() { From 34c1cb6579b88d3099411d8123745f6ad113263c Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 11 Sep 2017 19:42:05 +0200 Subject: [PATCH 12/12] Typos and naming fixes --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 24 ++++++++++----------- libraries/ui/src/ui/OffscreenQmlSurface.h | 12 +++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 9015cc91d7..ca088fa3fe 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -639,7 +639,7 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { _qmlContext->setBaseUrl(baseUrl); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function f) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback) { if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } @@ -659,28 +659,28 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, - [this, qmlComponent, targetContext, f](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, f); + [this, qmlComponent, targetContext, onQmlLoadedCallback](QQmlComponent::Status) { + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); }); return; } - finishQmlLoad(qmlComponent, targetContext, f); + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); } -void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function f) { - load(qmlSource, true, f); +void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback) { + load(qmlSource, true, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function f) { - load(qmlSource, false, f); +void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function onQmlLoadedCallback) { + load(qmlSource, false, onQmlLoadedCallback); } void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function f) { +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -713,9 +713,9 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext } // Make sure we will call callback for this codepath - // Caal this before qmlComponent->completeCreate() otherwise ghost window appears + // Call this before qmlComponent->completeCreate() otherwise ghost window appears if (newItem && _rootItem) { - f(qmlContext, newObject); + onQmlLoadedCallback(qmlContext, newObject); } QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); @@ -751,7 +751,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); // Call this callback after rootitem is set, otherwise VrMenu wont work - f(qmlContext, newObject); + onQmlLoadedCallback(qmlContext, newObject); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 7da929723c..95dabdef0f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -50,11 +50,11 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; - Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { - return load(QUrl(qmlSourceFile), f); + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void load(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void load(const QString& qmlSourceFile, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}) { + return load(QUrl(qmlSourceFile), onQmlLoadedCallback); } void clearCache(); void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } @@ -120,7 +120,7 @@ protected: private: static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function f); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); void setupFbo(); bool allowNewFrame(uint8_t fps);