From 970ca5e08f4a635e7a7cbaf4df0b916e662f7d38 Mon Sep 17 00:00:00 2001 From: Gabriel Calero Date: Wed, 17 Jan 2018 14:45:56 -0300 Subject: [PATCH] Add virtual pad for android --- .../controllers/touchscreenvirtualpad.json | 15 ++ interface/resources/images/analog_stick.png | Bin 0 -> 2713 bytes .../resources/images/analog_stick_base.png | Bin 0 -> 2020 bytes interface/src/Application.cpp | 23 +- interface/src/Application.h | 2 + .../ControllerScriptingInterface.cpp | 6 + .../scripting/ControllerScriptingInterface.h | 2 + .../Basic2DWindowOpenGLDisplayPlugin.cpp | 82 ++++++ .../Basic2DWindowOpenGLDisplayPlugin.h | 8 + .../src/display-plugins/CompositorHelper.cpp | 16 ++ .../src/display-plugins/CompositorHelper.h | 1 + libraries/input-plugins/CMakeLists.txt | 2 +- .../src/input-plugins/InputPlugin.cpp | 4 + .../TouchscreenVirtualPadDevice.cpp | 247 ++++++++++++++++++ .../TouchscreenVirtualPadDevice.h | 89 +++++++ libraries/ui/src/VirtualPadManager.cpp | 58 ++++ libraries/ui/src/VirtualPadManager.h | 46 ++++ scripts/+android/defaultScripts.js | 3 +- scripts/system/touchscreenvirtualpad.js | 21 ++ 19 files changed, 621 insertions(+), 4 deletions(-) create mode 100644 interface/resources/controllers/touchscreenvirtualpad.json create mode 100644 interface/resources/images/analog_stick.png create mode 100644 interface/resources/images/analog_stick_base.png create mode 100644 libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp create mode 100644 libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h create mode 100644 libraries/ui/src/VirtualPadManager.cpp create mode 100644 libraries/ui/src/VirtualPadManager.h create mode 100644 scripts/system/touchscreenvirtualpad.js diff --git a/interface/resources/controllers/touchscreenvirtualpad.json b/interface/resources/controllers/touchscreenvirtualpad.json new file mode 100644 index 0000000000..9f65994e98 --- /dev/null +++ b/interface/resources/controllers/touchscreenvirtualpad.json @@ -0,0 +1,15 @@ +{ + "name": "TouchscreenVirtualPad to Actions", + "channels": [ + { "from": "TouchscreenVirtualPad.LY", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" }, + { "from": "TouchscreenVirtualPad.LX", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" }, + + + { "from": "TouchscreenVirtualPad.RX", "when": "Application.CameraFirstPerson", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.Yaw" }, + + { "from": "TouchscreenVirtualPad.RY", + "when": "Application.CameraFirstPerson", + "to": "Actions.Pitch" + } + ] +} diff --git a/interface/resources/images/analog_stick.png b/interface/resources/images/analog_stick.png new file mode 100644 index 0000000000000000000000000000000000000000..e9457c730798ae0a77d6b50c2de30494515b3c61 GIT binary patch literal 2713 zcmb7GZBSI#8Gg>$ySsOn1@6knZt6Ph;z!gX(WXPT2@@6u1T-p2A~6uS8UbyVdW|;0 z#=zktIF3m$(KNBpiutn5hio(L4pRso(lXXIp_w$JYwgqv7^k+j1A%EYFxa_w*|3DB zNq+2{+2?)F^PcTx1aM5|)z>wEqHKJs`$-}~ zxiIlmZg@@0)7HT~7a8El z%F%i3RF6pP;k3JH*_2xCx(#w--@`hMUSY`W@mcE3cp=L>zm{OwRBq5%%pPB1FXbP{ z4@l+UI~vZT2keh2?JIh~cGFH$OSBz(MA+==wP)WgfivazSqFOO@ff7nD@(E=@8B1j z4ZW0i`QF*{k8hJ6sGpdtlLfR0?GJX{uws}j82DwUFhVujof4c@C1{6JOd;N35jKPR z=0dC#+3g#WrjnQ)KRRB2Ge>9V$!;hrX=C8oX1{^L>f$B~T$w0c1Vx4a zIq+;lU>$|o##dY5N<-;lZJ60hCVw)8*%EkAgv-raJQ~{3PW-n}-arC7MVO5|7)B2h zzl-ud1b!&OO!*ayrh|@V;y(^f5NOaVFRei7Qj8el?LF1m_DLQx8PzJYBUB;P-Jx>c(1O#eydy@W_caK`*fBQRDMW@jxIxRvkpB= z2ciZyx=fAio@@UX0)a z`T-zeYvwW%@<+0c4llFtM`NNK;Ku#~g8bV^{i0`1E<|a1lu=wB`>CC+b3~cQCpS)s zJQ&RZ2J!L>x$yVQHX7!u`<}qheIXSPeDrjZRUV5}o#RO_Hr2;l<%utif0dohv5x=a zDzid!&61^UNFnTB(G8g8qVn>o3Lv8*((f7feD3;NMJT;(cDnn;iZ~J&{es^$-dJqM z#pt$wG}xVrw%N#CQLl!*ow-`3!R=5 zfJg%g39RPxY1$sy-8^<#kPn5Y=~iUiuMcVil^>715~;5^k-eX!kLN20J)m!_w6dqe z(9aRttV6F_Sa!~9#dXJa|0Kn>Ll;57?ePLwXu z(ML>vCxuzmEn^X{(#=6Lk|YXqOkks^nM{TUuJ59)S$7{h<$Z=gwy4SJZfcB^9~Tgp z%HFrbdlqz9k>B6V)!l8qi)NpoJ>0 zS=0(LvUBBR3{gghjWAGew+Nd>eQ(~`5==f?w0|+u>v|x|s7@g41Zgi!y>4Z@%x6ld zPHqyF|44AA@?#IJ>7{C?`D`R$Re~dwo!7o*4%i&3ZP18L!VaYnCc%-_-d_TzSIHQm zC^zu_R=|VwIsqb4MvI#+5x%nV`0gIC^H4??!Y67Qk%O{H5fW90^1&qDA5U>=e%UIv zHbp?WQU9;8Nch$K@6SRzsrq3)SP3bcbc4Tv^d}^^P0H0Ku=S27-O6AS*cHb?r-s1s zln%ggczQj$RJowx$EMf6o%r?D`a9h4IVa`Vn`4F}U9GG3Tk*krLknk#`tu9TEOYp> v3)MGFpE0Me#XgfhV^04In{&JKo>|KXOnYOW8Mq_81^^24*5{teksJRDyY64- literal 0 HcmV?d00001 diff --git a/interface/resources/images/analog_stick_base.png b/interface/resources/images/analog_stick_base.png new file mode 100644 index 0000000000000000000000000000000000000000..3b7b8aa8a9a6d8a83847680423a18d86ff182b84 GIT binary patch literal 2020 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelajGNS3%plmzFem6RtIr7}3C zG&JWf&Pa7#JMDHZce=Ff=eQFt9K%C@?TEFftI3B2hWQ5~55; zC`Y&nn;3>W9pux$F|XL#_hZKC6^whXRnpAK=VIS!B6HJr*%Iv2A8;N>U|h3fwJqllwgXT36Y`ZAcmx~% z_A(gQFnrqq3Z#ZCmIHR;3~j6o)v*i`LJV)p!2wpv(O|0&3cUqfj2qswLW9zvX?-)p zn_8qGeei$Jf94zinMe+GXc!P1Nf<#k+@c$iI#5%>XaIo<5IlKwG=N4(0I6M+VQlyd zE|j1}y3XPE3`oV1&S_(YhFW;3^&DJkT~TECwwu8~h2h3)rUM%o66SM*>WLL@3~ve< z6Dk-s>}PFIWIAx~-GdUA_3bZTny?lVZ}F}z7 #include #include +#include #include #include #include @@ -669,6 +670,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT); @@ -1422,12 +1424,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return DependencyManager::get()->navigationFocused() ? 1 : 0; }); - // Setup the _keyboardMouseDevice, _touchscreenDevice and the user input mapper with the default bindings + // Setup the _keyboardMouseDevice, _touchscreenDevice, _touchscreenVirtualPadDevice and the user input mapper with the default bindings userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice()); // if the _touchscreenDevice is not supported it will not be registered if (_touchscreenDevice) { userInputMapper->registerDevice(_touchscreenDevice->getInputDevice()); } + if (_touchscreenVirtualPadDevice) { + userInputMapper->registerDevice(_touchscreenVirtualPadDevice->getInputDevice()); + } // force the model the look at the correct directory (weird order of operations issue) scriptEngines->setScriptsLocation(scriptEngines->getScriptsLocation()); @@ -2489,6 +2494,9 @@ void Application::initializeUi() { if (TouchscreenDevice::NAME == inputPlugin->getName()) { _touchscreenDevice = std::dynamic_pointer_cast(inputPlugin); } + if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) { + _touchscreenVirtualPadDevice = std::dynamic_pointer_cast(inputPlugin); + } } _window->setMenuBar(new Menu()); @@ -3577,6 +3585,9 @@ void Application::touchUpdateEvent(QTouchEvent* event) { if (_touchscreenDevice && _touchscreenDevice->isActive()) { _touchscreenDevice->touchUpdateEvent(event); } + if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { + _touchscreenVirtualPadDevice->touchUpdateEvent(event); + } } void Application::touchBeginEvent(QTouchEvent* event) { @@ -3598,6 +3609,9 @@ void Application::touchBeginEvent(QTouchEvent* event) { if (_touchscreenDevice && _touchscreenDevice->isActive()) { _touchscreenDevice->touchBeginEvent(event); } + if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { + _touchscreenVirtualPadDevice->touchBeginEvent(event); + } } @@ -3618,7 +3632,9 @@ void Application::touchEndEvent(QTouchEvent* event) { if (_touchscreenDevice && _touchscreenDevice->isActive()) { _touchscreenDevice->touchEndEvent(event); } - + if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { + _touchscreenVirtualPadDevice->touchEndEvent(event); + } // put any application specific touch behavior below here.. } @@ -3626,6 +3642,9 @@ void Application::touchGestureEvent(QGestureEvent* event) { if (_touchscreenDevice && _touchscreenDevice->isActive()) { _touchscreenDevice->touchGestureEvent(event); } + if (_touchscreenVirtualPadDevice && _touchscreenVirtualPadDevice->isActive()) { + _touchscreenVirtualPadDevice->touchGestureEvent(event); + } } void Application::wheelEvent(QWheelEvent* event) const { diff --git a/interface/src/Application.h b/interface/src/Application.h index ddb8ce11e5..8f0690bda1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -545,6 +546,7 @@ private: std::shared_ptr _applicationStateDevice; // Default ApplicationDevice reflecting the state of different properties of the session std::shared_ptr _keyboardMouseDevice; // Default input device, the good old keyboard mouse and maybe touchpad std::shared_ptr _touchscreenDevice; // the good old touchscreen + std::shared_ptr _touchscreenVirtualPadDevice; SimpleMovingAverage _avatarSimsPerSecond {10}; int _avatarSimsPerSecondReport {0}; quint64 _lastAvatarSimsPerSecondUpdate {0}; diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 4848531de7..95be7b29e9 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -16,6 +16,7 @@ #include #include "Application.h" +#include "VirtualPadManager.h" bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const { return isKeyCaptured(KeyEvent(*event)); @@ -83,6 +84,11 @@ QVariant ControllerScriptingInterface::getRecommendedHUDRect() const { return qRectToVariant(rect); } +void ControllerScriptingInterface::setVPadEnabled(const bool enable) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + virtualPadManager.enable(enable); +} + void ControllerScriptingInterface::emitKeyPressEvent(QKeyEvent* event) { emit keyPressEvent(KeyEvent(*event)); } void ControllerScriptingInterface::emitKeyReleaseEvent(QKeyEvent* event) { emit keyReleaseEvent(KeyEvent(*event)); } diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index 7a2c964622..1f223814a3 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -65,6 +65,8 @@ public slots: virtual glm::vec2 getViewportDimensions() const; virtual QVariant getRecommendedHUDRect() const; + virtual void setVPadEnabled(bool enable); + signals: void keyPressEvent(const KeyEvent& event); void keyReleaseEvent(const KeyEvent& event); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 588c43d534..f1fefc9425 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -6,6 +6,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Basic2DWindowOpenGLDisplayPlugin.h" +#include "CompositorHelper.h" +#include "VirtualPadManager.h" #include @@ -14,11 +16,60 @@ #include #include +#include const QString Basic2DWindowOpenGLDisplayPlugin::NAME("Desktop"); static const QString FULLSCREEN = "Fullscreen"; +void Basic2DWindowOpenGLDisplayPlugin::customizeContext() { + auto iconPath = PathUtils::resourcesPath() + "images/analog_stick.png"; + auto image = QImage(iconPath); + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + if ((image.width() > 0) && (image.height() > 0)) { + + _virtualPadStickTexture = gpu::Texture::createStrict( + gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), + image.width(), image.height(), + gpu::Texture::MAX_NUM_MIPS, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); + _virtualPadStickTexture->setSource("virtualPad stick"); + auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); + _virtualPadStickTexture->setUsage(usage.build()); + _virtualPadStickTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); + _virtualPadStickTexture->assignStoredMip(0, image.byteCount(), image.constBits()); + _virtualPadStickTexture->setAutoGenerateMips(true); + } + + iconPath = PathUtils::resourcesPath() + "images/analog_stick_base.png"; + image = QImage(iconPath); + if (image.format() != QImage::Format_ARGB32) { + image = image.convertToFormat(QImage::Format_ARGB32); + } + if ((image.width() > 0) && (image.height() > 0)) { + _virtualPadStickBaseTexture = gpu::Texture::createStrict( + gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), + image.width(), image.height(), + gpu::Texture::MAX_NUM_MIPS, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); + _virtualPadStickBaseTexture->setSource("virtualPad base"); + auto usage = gpu::Texture::Usage::Builder().withColor().withAlpha(); + _virtualPadStickBaseTexture->setUsage(usage.build()); + _virtualPadStickBaseTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); + _virtualPadStickBaseTexture->assignStoredMip(0, image.byteCount(), image.constBits()); + _virtualPadStickBaseTexture->setAutoGenerateMips(true); + } + + + Parent::customizeContext(); +} + +void Basic2DWindowOpenGLDisplayPlugin::uncustomizeContext() { + Parent::uncustomizeContext(); +} + bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() { _framerateActions.clear(); _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN, @@ -33,6 +84,37 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() { return Parent::internalActivate(); } +void Basic2DWindowOpenGLDisplayPlugin::compositeExtra() { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if(virtualPadManager.getLeftVirtualPad()->isBeingTouched()) { + // render stick base + auto stickBaseTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getFirstTouch()); + render([&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setProjectionTransform(mat4()); + batch.setPipeline(_cursorPipeline); + batch.setResourceTexture(0, _virtualPadStickBaseTexture); + batch.resetViewTransform(); + batch.setModelTransform(stickBaseTransform); + batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize())); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + // render stick head + auto stickTransform = DependencyManager::get()->getPoint2DTransform(virtualPadManager.getLeftVirtualPad()->getCurrentTouch()); + render([&](gpu::Batch& batch) { + batch.enableStereo(false); + batch.setProjectionTransform(mat4()); + batch.setPipeline(_cursorPipeline); + batch.setResourceTexture(0, _virtualPadStickTexture); + batch.resetViewTransform(); + batch.setModelTransform(stickTransform); + batch.setViewportTransform(ivec4(uvec2(0), getRecommendedRenderSize())); + batch.draw(gpu::TRIANGLE_STRIP, 4); + }); + } + Parent::compositeExtra(); +} + static const uint32_t MIN_THROTTLE_CHECK_FRAMES = 60; bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const { diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index f3dd50602c..d9b942bd97 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -22,10 +22,15 @@ public: virtual float getTargetFrameRate() const override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; } + virtual void customizeContext() override; + virtual void uncustomizeContext() override; + virtual bool internalActivate() override; virtual bool isThrottled() const override; + virtual void compositeExtra() override; + protected: mutable bool _isThrottled = false; @@ -36,4 +41,7 @@ private: QAction* _vsyncAction { nullptr }; uint32_t _framerateTarget { 0 }; int _fullscreenTarget{ -1 }; + + gpu::TexturePointer _virtualPadStickTexture; + gpu::TexturePointer _virtualPadStickBaseTexture; }; diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp index f3f81c0b2e..74225b5b39 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.cpp @@ -458,6 +458,22 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const return result; } +glm::mat4 CompositorHelper::getPoint2DTransform(const glm::vec2& point) const { + glm::mat4 result; + static const float PIXEL_SIZE = 512.0f; + const auto canvasSize = vec2(toGlm(_renderingWidget->size()));; + QPoint qPoint(point.x,point.y); + vec2 position = toGlm(_renderingWidget->mapFromGlobal(qPoint)); + position /= canvasSize; + position *= 2.0; + position -= 1.0; + position.y *= -1.0f; + + vec2 size = PIXEL_SIZE / canvasSize; + result = glm::scale(glm::translate(glm::mat4(), vec3(position, 0.0f)), vec3(size, 1.0f)); + return result; +} + QVariant ReticleInterface::getPosition() const { return vec2toVariant(_compositor->getReticlePosition()); diff --git a/libraries/display-plugins/src/display-plugins/CompositorHelper.h b/libraries/display-plugins/src/display-plugins/CompositorHelper.h index f448375f0d..c06ea77787 100644 --- a/libraries/display-plugins/src/display-plugins/CompositorHelper.h +++ b/libraries/display-plugins/src/display-plugins/CompositorHelper.h @@ -92,6 +92,7 @@ public: glm::vec2 getReticleMaximumPosition() const; glm::mat4 getReticleTransform(const glm::mat4& eyePose = glm::mat4(), const glm::vec3& headPosition = glm::vec3()) const; + glm::mat4 getPoint2DTransform(const glm::vec2& point = glm::vec2()) const; ReticleInterface* getReticleInterface() { return _reticleInterface; } diff --git a/libraries/input-plugins/CMakeLists.txt b/libraries/input-plugins/CMakeLists.txt index b0ea13843b..b1fcc4076a 100644 --- a/libraries/input-plugins/CMakeLists.txt +++ b/libraries/input-plugins/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME input-plugins) setup_hifi_library() -link_hifi_libraries(shared plugins ui-plugins controllers) +link_hifi_libraries(shared plugins ui-plugins controllers ui) GroupSources("src/input-plugins") diff --git a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp index acd7a20327..96f1daba8c 100644 --- a/libraries/input-plugins/src/input-plugins/InputPlugin.cpp +++ b/libraries/input-plugins/src/input-plugins/InputPlugin.cpp @@ -14,12 +14,16 @@ #include "KeyboardMouseDevice.h" #include "TouchscreenDevice.h" +#include "TouchscreenVirtualPadDevice.h" // TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class InputPluginList getInputPlugins() { InputPlugin* PLUGIN_POOL[] = { new KeyboardMouseDevice(), new TouchscreenDevice(), +#if defined(Q_OS_ANDROID) + new TouchscreenVirtualPadDevice(), +#endif nullptr }; diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp new file mode 100644 index 0000000000..8e1e6c2fba --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.cpp @@ -0,0 +1,247 @@ +// +// TouchscreenVirtualPadDevice.cpp +// input-plugins/src/input-plugins +// +// Created by Triplelexx on 01/31/16. +// Copyright 2016 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 +// +#include "TouchscreenVirtualPadDevice.h" +#include "KeyboardMouseDevice.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "VirtualPadManager.h" + +const char* TouchscreenVirtualPadDevice::NAME = "TouchscreenVirtualPad"; + +bool TouchscreenVirtualPadDevice::isSupported() const { + for (auto touchDevice : QTouchDevice::devices()) { + if (touchDevice->type() == QTouchDevice::TouchScreen) { + return true; + } + } +#if defined(Q_OS_ANDROID) + // last chance, assume that if this is android, a touchscreen is indeed supported + return true; +#endif + return false; +} + +float clip(float n, float lower, float upper) { + return std::max(lower, std::min(n, upper)); +} + +void TouchscreenVirtualPadDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->withLock([&, this]() { + _inputDevice->update(deltaTime, inputCalibrationData); + }); + + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (_validTouchLeft) { + float leftDistanceScaleX, leftDistanceScaleY; + leftDistanceScaleX = (_currentTouchLeftPoint.x - _firstTouchLeftPoint.x) / _screenDPIScale.x; + leftDistanceScaleY = (_currentTouchLeftPoint.y - _firstTouchLeftPoint.y) / _screenDPIScale.y; + + leftDistanceScaleX = clip(leftDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + leftDistanceScaleY = clip(leftDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + + // NOW BETWEEN -1 1 + leftDistanceScaleX /= STICK_RADIUS_INCHES; + leftDistanceScaleY /= STICK_RADIUS_INCHES; + + _inputDevice->_axisStateMap[controller::LX] = leftDistanceScaleX; + _inputDevice->_axisStateMap[controller::LY] = leftDistanceScaleY; + + /* Shared variables for stick rendering (clipped to the stick radius)*/ + // Prevent this for being done when not in first person view + virtualPadManager.getLeftVirtualPad()->setBeingTouched(true); + virtualPadManager.getLeftVirtualPad()->setFirstTouch(_firstTouchLeftPoint); + virtualPadManager.getLeftVirtualPad()->setCurrentTouch( + glm::vec2(clip(_currentTouchLeftPoint.x, -STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x, STICK_RADIUS_INCHES * _screenDPIScale.x + _firstTouchLeftPoint.x), + clip(_currentTouchLeftPoint.y, -STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y, STICK_RADIUS_INCHES * _screenDPIScale.y + _firstTouchLeftPoint.y)) + ); + } else { + virtualPadManager.getLeftVirtualPad()->setBeingTouched(false); + } + + if (_validTouchRight) { + float rightDistanceScaleX, rightDistanceScaleY; + rightDistanceScaleX = (_currentTouchRightPoint.x - _firstTouchRightPoint.x) / _screenDPIScale.x; + rightDistanceScaleY = (_currentTouchRightPoint.y - _firstTouchRightPoint.y) / _screenDPIScale.y; + + rightDistanceScaleX = clip(rightDistanceScaleX, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + rightDistanceScaleY = clip(rightDistanceScaleY, -STICK_RADIUS_INCHES, STICK_RADIUS_INCHES); + + // NOW BETWEEN -1 1 + rightDistanceScaleX /= STICK_RADIUS_INCHES; + rightDistanceScaleY /= STICK_RADIUS_INCHES; + + _inputDevice->_axisStateMap[controller::RX] = rightDistanceScaleX; + _inputDevice->_axisStateMap[controller::RY] = rightDistanceScaleY; + } + +} + +void TouchscreenVirtualPadDevice::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { + _axisStateMap.clear(); +} + +void TouchscreenVirtualPadDevice::InputDevice::focusOutEvent() { +} + +void TouchscreenVirtualPadDevice::debugPoints(const QTouchEvent* event, QString who) { + // convert the touch points into an average + const QList& tPoints = event->touchPoints(); + QVector points; + int touchPoints = tPoints.count(); + for (int i = 0; i < touchPoints; ++i) { + glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + points << thisPoint; + } + QScreen* eventScreen = event->window()->screen(); + int midScreenX = eventScreen->size().width()/2; + int lefties = 0; + int righties = 0; + vec2 currentPoint; + for (int i = 0; i < points.length(); i++) { + currentPoint = points.at(i); + if (currentPoint.x < midScreenX) { + lefties++; + } else { + righties++; + } + } +} + +void TouchscreenVirtualPadDevice::touchBeginEvent(const QTouchEvent* event) { + // touch begin here is a big begin -> begins both pads? maybe it does nothing + debugPoints(event, " BEGIN ++++++++++++++++"); + KeyboardMouseDevice::enableTouch(false); + QScreen* eventScreen = event->window()->screen(); + _screenWidthCenter = eventScreen->size().width() / 2; + if (_screenDPI != eventScreen->physicalDotsPerInch()) { + _screenDPIScale.x = (float)eventScreen->physicalDotsPerInchX(); + _screenDPIScale.y = (float)eventScreen->physicalDotsPerInchY(); + _screenDPI = eventScreen->physicalDotsPerInch(); + } +} + +void TouchscreenVirtualPadDevice::touchEndEvent(const QTouchEvent* event) { + // touch end here is a big reset -> resets both pads + _touchPointCount = 0; + KeyboardMouseDevice::enableTouch(true); + debugPoints(event, " END ----------------"); + touchLeftEnd(); + touchRightEnd(); + _inputDevice->_axisStateMap.clear(); +} + +void TouchscreenVirtualPadDevice::touchUpdateEvent(const QTouchEvent* event) { + _touchPointCount = event->touchPoints().count(); + + const QList& tPoints = event->touchPoints(); + bool leftTouchFound = false; + bool rightTouchFound = false; + for (int i = 0; i < _touchPointCount; ++i) { + glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y()); + if (thisPoint.x < _screenWidthCenter) { + if (!leftTouchFound) { + leftTouchFound = true; + if (!_validTouchLeft) { + touchLeftBegin(thisPoint); + } else { + touchLeftUpdate(thisPoint); + } + } + } else { + if (!rightTouchFound) { + rightTouchFound = true; + if (!_validTouchRight) { + touchRightBegin(thisPoint); + } else { + touchRightUpdate(thisPoint); + } + } + } + } + if (!leftTouchFound) { + touchLeftEnd(); + } + if (!rightTouchFound) { + touchRightEnd(); + } +} + +void TouchscreenVirtualPadDevice::touchLeftBegin(glm::vec2 touchPoint) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (virtualPadManager.isEnabled()) { + _firstTouchLeftPoint = touchPoint; + _validTouchLeft = true; + } +} + +void TouchscreenVirtualPadDevice::touchLeftUpdate(glm::vec2 touchPoint) { + _currentTouchLeftPoint = touchPoint; +} + +void TouchscreenVirtualPadDevice::touchLeftEnd() { + if (_validTouchLeft) { // do stuff once + _validTouchLeft = false; + _inputDevice->_axisStateMap[controller::LX] = 0; + _inputDevice->_axisStateMap[controller::LY] = 0; + } +} + +void TouchscreenVirtualPadDevice::touchRightBegin(glm::vec2 touchPoint) { + auto& virtualPadManager = VirtualPad::Manager::instance(); + if (virtualPadManager.isEnabled()) { + _firstTouchRightPoint = touchPoint; + _validTouchRight = true; + } +} + +void TouchscreenVirtualPadDevice::touchRightUpdate(glm::vec2 touchPoint) { + _currentTouchRightPoint = touchPoint; +} + +void TouchscreenVirtualPadDevice::touchRightEnd() { + if (_validTouchRight) { // do stuff once + _validTouchRight = false; + _inputDevice->_axisStateMap[controller::RX] = 0; + _inputDevice->_axisStateMap[controller::RY] = 0; + } +} + +void TouchscreenVirtualPadDevice::touchGestureEvent(const QGestureEvent* event) { + if (QGesture* gesture = event->gesture(Qt::PinchGesture)) { + QPinchGesture* pinch = static_cast(gesture); + _pinchScale = pinch->totalScaleFactor(); + } +} + +controller::Input::NamedVector TouchscreenVirtualPadDevice::InputDevice::getAvailableInputs() const { + using namespace controller; + QVector availableInputs{ + makePair(LX, "LX"), + makePair(LY, "LY"), + makePair(RX, "RX"), + makePair(RY, "RY") + }; + return availableInputs; +} + +QString TouchscreenVirtualPadDevice::InputDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/touchscreenvirtualpad.json"; + return MAPPING_JSON; +} diff --git a/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h new file mode 100644 index 0000000000..fd74009ee8 --- /dev/null +++ b/libraries/input-plugins/src/input-plugins/TouchscreenVirtualPadDevice.h @@ -0,0 +1,89 @@ +// +// TouchscreenVirtualPadDevice.h +// input-plugins/src/input-plugins +// +// Created by Triplelexx on 1/31/16. +// Copyright 2016 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 +// + +#ifndef hifi_TouchscreenVirtualPadDevice_h +#define hifi_TouchscreenVirtualPadDevice_h + +#include +#include "InputPlugin.h" +#include + +class QTouchEvent; +class QGestureEvent; + +const float STICK_RADIUS_INCHES = .3f; + +class TouchscreenVirtualPadDevice : public InputPlugin { +Q_OBJECT +public: + + // Plugin functions + virtual bool isSupported() const override; + virtual const QString getName() const override { return NAME; } + + bool isHandController() const override { return false; } + + virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; + + void touchBeginEvent(const QTouchEvent* event); + void touchEndEvent(const QTouchEvent* event); + void touchUpdateEvent(const QTouchEvent* event); + void touchGestureEvent(const QGestureEvent* event); + + static const char* NAME; + +protected: + + class InputDevice : public controller::InputDevice { + public: + InputDevice() : controller::InputDevice("TouchscreenVirtualPad") {} + private: + // Device functions + virtual controller::Input::NamedVector getAvailableInputs() const override; + virtual QString getDefaultMappingConfig() const override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; + virtual void focusOutEvent() override; + + friend class TouchscreenVirtualPadDevice; + }; + +public: + const std::shared_ptr& getInputDevice() const { return _inputDevice; } + +protected: + qreal _lastPinchScale; + qreal _pinchScale; + qreal _screenDPI; + glm::vec2 _screenDPIScale; + bool _validTouchLeft; + glm::vec2 _firstTouchLeftPoint; + glm::vec2 _currentTouchLeftPoint; + bool _validTouchRight; + glm::vec2 _firstTouchRightPoint; + glm::vec2 _currentTouchRightPoint; + int _touchPointCount; + int _screenWidthCenter; + std::shared_ptr _inputDevice { std::make_shared() }; + + void touchLeftBegin(glm::vec2 touchPoint); + void touchLeftUpdate(glm::vec2 touchPoint); + void touchLeftEnd(); + void touchRightBegin(glm::vec2 touchPoint); + void touchRightUpdate(glm::vec2 touchPoint); + void touchRightEnd(); +// just for debug +private: + void debugPoints(const QTouchEvent* event, QString who); + +}; + +#endif // hifi_TouchscreenVirtualPadDevice_h diff --git a/libraries/ui/src/VirtualPadManager.cpp b/libraries/ui/src/VirtualPadManager.cpp new file mode 100644 index 0000000000..4c3e6ff728 --- /dev/null +++ b/libraries/ui/src/VirtualPadManager.cpp @@ -0,0 +1,58 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 01/16/2018 +// Copyright 2018 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 +// + +#include "VirtualPadManager.h" + +namespace VirtualPad { + + bool Instance::isBeingTouched() { + return _isBeingTouched; + } + + void Instance::setBeingTouched(bool touched) { + _isBeingTouched = touched; + } + + void Instance::setFirstTouch(glm::vec2 point) { + _firstTouch = point; + } + + glm::vec2 Instance::getFirstTouch() { + return _firstTouch; + } + + void Instance::setCurrentTouch(glm::vec2 point) { + _currentTouch = point; + } + + glm::vec2 Instance::getCurrentTouch() { + return _currentTouch; + } + + Manager::Manager() { + + } + + Manager& Manager::instance() { + static QSharedPointer instance = DependencyManager::get(); + return *instance; + } + + void Manager::enable(bool enable) { + _enabled = enable; + } + + bool Manager::isEnabled() { + return _enabled; + } + + Instance* Manager::getLeftVirtualPad() { + return &_leftVPadInstance; + } + +} diff --git a/libraries/ui/src/VirtualPadManager.h b/libraries/ui/src/VirtualPadManager.h new file mode 100644 index 0000000000..599954989f --- /dev/null +++ b/libraries/ui/src/VirtualPadManager.h @@ -0,0 +1,46 @@ +// +// Created by Gabriel Calero & Cristian Duarte on 01/16/2018 +// Copyright 2018 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 +// + +#pragma once +#include +#include + +#include + +namespace VirtualPad { + class Instance { + public: + virtual bool isBeingTouched(); + virtual void setBeingTouched(bool touched); + virtual void setFirstTouch(glm::vec2 point); + virtual glm::vec2 getFirstTouch(); + virtual void setCurrentTouch(glm::vec2 point); + virtual glm::vec2 getCurrentTouch(); + private: + bool _isBeingTouched; + glm::vec2 _firstTouch; + glm::vec2 _currentTouch; + }; + + class Manager : public QObject, public Dependency { + SINGLETON_DEPENDENCY + + Manager(); + Manager(const Manager& other) = delete; + public: + static Manager& instance(); + Instance* getLeftVirtualPad(); + bool isEnabled(); + void enable(bool enable); + private: + Instance _leftVPadInstance; + bool _enabled; + }; +} + + diff --git a/scripts/+android/defaultScripts.js b/scripts/+android/defaultScripts.js index a115e498da..54c899d1da 100644 --- a/scripts/+android/defaultScripts.js +++ b/scripts/+android/defaultScripts.js @@ -12,7 +12,8 @@ // var DEFAULT_SCRIPTS_COMBINED = [ - "system/progress.js"/*, + "system/progress.js", + "system/touchscreenvirtualpad.js"/*, "system/away.js", "system/controllers/controllerDisplayManager.js", "system/controllers/handControllerGrabAndroid.js", diff --git a/scripts/system/touchscreenvirtualpad.js b/scripts/system/touchscreenvirtualpad.js new file mode 100644 index 0000000000..e6f9204d4d --- /dev/null +++ b/scripts/system/touchscreenvirtualpad.js @@ -0,0 +1,21 @@ +"use strict"; +// +// android.js +// scripts/system/ +// +// Created by Gabriel Calero & Cristian Duarte on Jan 16, 2018 +// Copyright 2018 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 + +function init() { + Controller.setVPadEnabled(true); +} + +init(); + +}()); // END LOCAL_SCOPE