mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-06 11:39:49 -06:00
Touch module code cleanup (#2465)
* Remove unused feature that allowed us to "pick" nodes using touch (it didn't really work and had some nasty hardcoded and costly implementation). Fixes Touch interaction picking refactor #1041 * General refactoring of code and removing redundant code * Make touch markers prettier (change default color and smoothen edges) * Add module property to control which renderable types are "directly touchable" * Add SGN property to control which individual nodes are "directly touchable" ("SupportsDirectInteraction") * Fix stuttering when zooming in closer than the orbitalnavigator allows
This commit is contained in:
@@ -19,6 +19,7 @@ asset.require("util/launcher_images")
|
||||
-- Modules and component settings
|
||||
asset.require("modules/exoplanets/exoplanets")
|
||||
asset.require("modules/skybrowser/skybrowser")
|
||||
asset.require("modules/touch/default_settings")
|
||||
|
||||
|
||||
asset.onInitialize(function ()
|
||||
|
||||
19
data/assets/modules/touch/default_settings.asset
Normal file
19
data/assets/modules/touch/default_settings.asset
Normal file
@@ -0,0 +1,19 @@
|
||||
asset.onInitialize(function ()
|
||||
openspace.setPropertyValueSingle("Modules.Touch.EnableTouchInteraction", true)
|
||||
|
||||
-- A list of renderable types that apply the "direct manipulation". Works best for
|
||||
-- things with a sperical-ish shape and an intearction sphere of about the same size
|
||||
-- as the bounding sphere.
|
||||
-- Can also be set for each scene graph node using the "IsDirectlyTouchable" property
|
||||
local directTouchList = { "RenderableGlobe" }
|
||||
openspace.setPropertyValueSingle("Modules.Touch.DefaultDirectTouchRenderableTypes", directTouchList)
|
||||
end)
|
||||
|
||||
asset.meta = {
|
||||
Name = "Touch Module Default Settings",
|
||||
Version = "1.0",
|
||||
Description = "Some default settings related to the touch module",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
}
|
||||
@@ -129,9 +129,18 @@ public:
|
||||
bool hasZoomFriction() const;
|
||||
bool hasRollFriction() const;
|
||||
|
||||
double minAllowedDistance() const;
|
||||
|
||||
glm::dvec3 anchorNodeToCameraVector() const;
|
||||
glm::quat anchorNodeToCameraRotation() const;
|
||||
|
||||
/**
|
||||
* Compute a camera position that pushed the camera position to
|
||||
* a valid position over the anchor node, accounting for the
|
||||
* minimal allowed distance
|
||||
*/
|
||||
glm::dvec3 pushToSurfaceOfAnchor(const glm::dvec3& cameraPosition) const;
|
||||
|
||||
private:
|
||||
struct CameraRotationDecomposition {
|
||||
glm::dquat localRotation = glm::dquat(1.0, 0.0, 0.0, 0.0);
|
||||
@@ -328,11 +337,11 @@ private:
|
||||
/**
|
||||
* Push the camera out to the surface of the object.
|
||||
*
|
||||
* \return a position vector adjusted to be at least minHeightAboveGround meters
|
||||
* \return a position vector adjusted to be at least _minimumAllowedDistance meters
|
||||
* above the actual surface of the object
|
||||
*/
|
||||
glm::dvec3 pushToSurface(double minHeightAboveGround,
|
||||
const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition,
|
||||
glm::dvec3 pushToSurface(const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/**
|
||||
@@ -351,7 +360,7 @@ private:
|
||||
* Calculates a SurfacePositionHandle given a camera position in world space.
|
||||
*/
|
||||
SurfacePositionHandle calculateSurfacePositionHandle(const SceneGraphNode& node,
|
||||
const glm::dvec3 cameraPositionWorldSpace);
|
||||
const glm::dvec3& cameraPositionWorldSpace) const;
|
||||
|
||||
void resetIdleBehavior();
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <ghoul/misc/managedmemoryuniqueptr.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
namespace ghoul::opengl {
|
||||
@@ -79,6 +80,8 @@ public:
|
||||
double boundingSphere() const;
|
||||
double interactionSphere() const;
|
||||
|
||||
std::string_view typeAsString() const;
|
||||
|
||||
virtual void render(const RenderData& data, RendererTasks& rendererTask);
|
||||
virtual void update(const UpdateData& data);
|
||||
|
||||
|
||||
@@ -139,6 +139,8 @@ public:
|
||||
double reachFactor() const;
|
||||
double approachFactor() const;
|
||||
|
||||
bool supportsDirectInteraction() const;
|
||||
|
||||
SceneGraphNode* childNode(const std::string& identifier);
|
||||
|
||||
const Renderable* renderable() const;
|
||||
@@ -204,6 +206,7 @@ private:
|
||||
properties::DoubleProperty _distFromCamToNode;
|
||||
properties::DoubleProperty _screenSizeRadius;
|
||||
properties::FloatProperty _visibilityDistance;
|
||||
properties::BoolProperty _supportsDirectInteraction;
|
||||
|
||||
// This variable is used for the rate-limiting of the screenspace positions (if they
|
||||
// are calculated when _computeScreenSpaceValues is true)
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <memory>
|
||||
|
||||
//#define TOUCH_DEBUG_PROPERTIES
|
||||
//#define TOUCH_DEBUG_NODE_PICK_MESSAGES
|
||||
|
||||
namespace openspace {
|
||||
|
||||
@@ -51,9 +50,9 @@ class SceneGraphNode;
|
||||
// Class used for keeping track of the recent average frame time
|
||||
class FrameTimeAverage {
|
||||
public:
|
||||
//Update the circular buffer with the most recent frame time
|
||||
// Update the circular buffer with the most recent frame time
|
||||
void updateWithNewFrame(double sample);
|
||||
//Get the value of the most recent average frame time (seconds)
|
||||
// Get the value of the most recent average frame time (seconds)
|
||||
double averageFrameTime() const;
|
||||
|
||||
private:
|
||||
@@ -67,13 +66,11 @@ class TouchInteraction : public properties::PropertyOwner {
|
||||
public:
|
||||
TouchInteraction();
|
||||
|
||||
// for interpretInteraction()
|
||||
enum Type {
|
||||
enum class InteractionType {
|
||||
ROTATION = 0,
|
||||
PINCH,
|
||||
PAN,
|
||||
ROLL,
|
||||
PICK,
|
||||
ZOOM_OUT
|
||||
};
|
||||
|
||||
@@ -85,18 +82,19 @@ public:
|
||||
glm::dvec2 pan = glm::dvec2(0.0);
|
||||
};
|
||||
|
||||
/* Main function call
|
||||
/**
|
||||
* Main function call
|
||||
* 1 Checks if doubleTap occured
|
||||
* 2 If the node in focus is large enough and all contact points have selected it,
|
||||
* calls directControl() function for direct-manipulation
|
||||
* 3 Updates std::vector<SelectedBody> _selected (only if LMA successfully
|
||||
* 3 Updates std::vector<SelectedBody> _selectedContactPoints (only if LMA successfully
|
||||
* converged, avoids interaction to snap on LMA fails)
|
||||
* 4 If directControl() wasn't called this frame, interpret the incoming
|
||||
* list and decide what type of interaction this frame should do
|
||||
* 5 Compute the new total velocities after interaction
|
||||
* 6 Evaluate if directControl should be called next frame- true if all contact points
|
||||
* select the same node and said node is larger than _nodeRadiusThreshold
|
||||
*/
|
||||
*/
|
||||
|
||||
void updateStateFromInput(const std::vector<TouchInputHolder>& list,
|
||||
std::vector<TouchInput>& lastProcessed);
|
||||
@@ -109,46 +107,43 @@ public:
|
||||
|
||||
// Sets _tap to true, called if tap occured current frame (called from touchmodule)
|
||||
void tap();
|
||||
// Set touchactive as true from the touchmodule if incoming list isn't empty, used to
|
||||
// void mouse input
|
||||
void touchActive(bool active);
|
||||
|
||||
// Get & Setters
|
||||
Camera* getCamera();
|
||||
const SceneGraphNode* getFocusNode();
|
||||
void setFocusNode(const SceneGraphNode* focusNode);
|
||||
void setCamera(Camera* camera);
|
||||
|
||||
private:
|
||||
/* Function that calculates the new camera state such that it minimizes the L2 error
|
||||
/**
|
||||
* Function that calculates the new camera state such that it minimizes the L2 error
|
||||
* in screenspace
|
||||
* between contact points and surface coordinates projected to clip space using LMA
|
||||
*/
|
||||
void directControl(const std::vector<TouchInputHolder>& list);
|
||||
|
||||
/* Traces each contact point into the scene as a ray
|
||||
* if the ray hits a node, save the id, node and surface coordinates the cursor hit
|
||||
* in the list _selected
|
||||
/**
|
||||
* Traces each contact point into the scene as a ray and find the intersection
|
||||
* points on the surface of the current anchor node, if any. Saves the input id
|
||||
* the node and surface coordinates the cursor hit
|
||||
*/
|
||||
void findSelectedNode(const std::vector<TouchInputHolder>& list);
|
||||
void updateNodeSurfacePoints(const std::vector<TouchInputHolder>& list);
|
||||
|
||||
/* Returns an int (ROT = 0, PINCH, PAN, ROLL, PICK) for what interaction to be used,
|
||||
* depending on what input was gotten
|
||||
/**
|
||||
* Returns an enum for what interaction to be used, depending on what input was
|
||||
* received
|
||||
*/
|
||||
int interpretInteraction(const std::vector<TouchInputHolder>& list,
|
||||
InteractionType interpretInteraction(const std::vector<TouchInputHolder>& list,
|
||||
const std::vector<TouchInput>& lastProcessed);
|
||||
|
||||
// Compute new velocity according to the interpreted action
|
||||
void computeVelocities(const std::vector<TouchInputHolder>& list,
|
||||
const std::vector<TouchInput>& lastProcessed);
|
||||
|
||||
//Compute velocity based on double-tap for zooming
|
||||
// Compute velocity based on double-tap for zooming
|
||||
double computeTapZoomDistance(double zoomGain);
|
||||
|
||||
//Compute coefficient for velocity decay to be applied in decceleration
|
||||
// Compute coefficient for velocity decay to be applied in decceleration
|
||||
double computeConstTimeDecayCoefficient(double velocity);
|
||||
|
||||
/* Decelerate the velocities. Function is called in step() but is dereferenced from
|
||||
/**
|
||||
* Decelerate the velocities. Function is called in step() but is dereferenced from
|
||||
* frame time to assure same behaviour on all systems
|
||||
*/
|
||||
void decelerate(double dt);
|
||||
@@ -156,12 +151,13 @@ private:
|
||||
// Resets all properties that can be changed in the GUI to default
|
||||
void resetPropertiesToDefault();
|
||||
|
||||
// Set all velocities to zero
|
||||
void resetVelocities();
|
||||
|
||||
Camera* _camera = nullptr;
|
||||
|
||||
// Property variables
|
||||
properties::StringProperty _origin;
|
||||
properties::BoolProperty _unitTest;
|
||||
properties::BoolProperty _touchActive;
|
||||
properties::BoolProperty _disableZoom;
|
||||
properties::BoolProperty _disableRoll;
|
||||
properties::TriggerProperty _reset;
|
||||
@@ -170,10 +166,7 @@ private:
|
||||
properties::FloatProperty _touchScreenSize;
|
||||
properties::FloatProperty _tapZoomFactor;
|
||||
properties::FloatProperty _pinchZoomFactor;
|
||||
properties::FloatProperty _nodeRadiusThreshold;
|
||||
properties::FloatProperty _rollAngleThreshold;
|
||||
properties::FloatProperty _orbitSpeedThreshold;
|
||||
properties::FloatProperty _spinSensitivity;
|
||||
properties::FloatProperty _zoomSensitivityExponential;
|
||||
properties::FloatProperty _zoomSensitivityProportionalDist;
|
||||
properties::FloatProperty _zoomSensitivityDistanceThreshold;
|
||||
@@ -184,11 +177,12 @@ private:
|
||||
properties::FloatProperty _centroidStillThreshold;
|
||||
properties::BoolProperty _panEnabled;
|
||||
properties::FloatProperty _interpretPan;
|
||||
properties::FloatProperty _slerpTime;
|
||||
properties::Vec4Property _friction;
|
||||
properties::FloatProperty _pickingRadiusMinimum;
|
||||
properties::FloatProperty _constTimeDecay_secs;
|
||||
|
||||
properties::BoolProperty _enableDirectManipulation;
|
||||
properties::FloatProperty _directTouchDistanceThreshold;
|
||||
|
||||
#ifdef TOUCH_DEBUG_PROPERTIES
|
||||
struct DebugProperties : PropertyOwner {
|
||||
DebugProperties();
|
||||
@@ -205,14 +199,13 @@ private:
|
||||
int stepVelUpdate = 0;
|
||||
#endif
|
||||
std::array<TouchInputHolder, 2> _pinchInputs;
|
||||
|
||||
// Class variables
|
||||
VelocityStates _vel;
|
||||
VelocityStates _lastVel;
|
||||
VelocityStates _sensitivity;
|
||||
|
||||
double _projectionScaleFactor = 1.000004;
|
||||
double _currentRadius = 1.0;
|
||||
double _slerpdT = 10001.0;
|
||||
bool _isWithinDirectTouchDistance = false;
|
||||
double _timeSlack = 0.0;
|
||||
std::chrono::milliseconds _time;
|
||||
bool _directTouchMode = false;
|
||||
@@ -220,12 +213,9 @@ private:
|
||||
bool _tap = false;
|
||||
bool _doubleTap = false;
|
||||
bool _zoomOutTap = false;
|
||||
bool _lmSuccess = true;
|
||||
std::vector<DirectInputSolver::SelectedBody> _selected;
|
||||
SceneGraphNode* _pickingSelected = nullptr;
|
||||
DirectInputSolver _solver;
|
||||
std::vector<DirectInputSolver::SelectedBody> _selectedNodeSurfacePoints;
|
||||
DirectInputSolver _directInputSolver;
|
||||
|
||||
glm::dquat _toSlerp = glm::dquat(1.0, 0.0, 0.0, 0.0);
|
||||
glm::vec2 _centroid = glm::vec2(0.f);
|
||||
|
||||
FrameTimeAverage _frameTimeAvg;
|
||||
|
||||
@@ -33,20 +33,28 @@ uniform vec3 color;
|
||||
|
||||
|
||||
Fragment getFragment() {
|
||||
// calculate normal from texture coordinates
|
||||
// Calculate normal from texture coordinates
|
||||
vec3 n;
|
||||
n.xy = gl_PointCoord.st * vec2(2.0, -2.0) + vec2(-1.0, 1.0);
|
||||
float mag = dot(n.xy, n.xy);
|
||||
if (mag > 1.0) {
|
||||
// kill pixels outside circle
|
||||
discard;
|
||||
|
||||
float edgeSmoothing = 1.0;
|
||||
float w = 0.1; // wdith for smoothing
|
||||
if (mag > 1.0 - w) {
|
||||
// Kill pixels outside circle. Do a smoothstep for soft border
|
||||
float t = (mag - (1.0-w)) / w;
|
||||
edgeSmoothing = smoothstep(1.0, 0.0, t);
|
||||
if (edgeSmoothing <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
n.z = sqrt(1.0 - mag);
|
||||
|
||||
// calculate lighting
|
||||
|
||||
// Calculate lighting
|
||||
vec3 light_dir = vec3(0.0, 0.0, 1.0);
|
||||
float diffuse = max(0.0, dot(light_dir, n));
|
||||
float alpha = min(pow(sqrt(mag), thickness), opacity);
|
||||
alpha *= edgeSmoothing;
|
||||
|
||||
Fragment frag;
|
||||
frag.color = vec4(color * diffuse, alpha);
|
||||
|
||||
@@ -212,6 +212,13 @@ bool DirectInputSolver::solve(const std::vector<TouchInputHolder>& list,
|
||||
const std::vector<SelectedBody>& selectedBodies,
|
||||
std::vector<double>* parameters, const Camera& camera)
|
||||
{
|
||||
ZoneScopedN("Direct touch input solver")
|
||||
|
||||
ghoul_assert(
|
||||
selectedBodies.size() >= list.size(),
|
||||
"Number of touch inputs must match the number of 'selected bodies'"
|
||||
);
|
||||
|
||||
int nFingers = std::min(static_cast<int>(list.size()), 3);
|
||||
_nDof = std::min(nFingers * 2, 6);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -72,7 +72,7 @@ TouchMarker::TouchMarker()
|
||||
, _radiusSize(RadiusInfo, 30.f, 0.f, 100.f)
|
||||
, _opacity(OpacityInfo, 0.8f, 0.f, 1.f)
|
||||
, _thickness(ThicknessInfo, 2.f, 0.f, 4.f)
|
||||
, _color(ColorInfo, glm::vec3(0.96f, 0.2f, 0.2f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
, _color(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
{
|
||||
addProperty(_visible);
|
||||
addProperty(_radiusSize);
|
||||
|
||||
@@ -28,44 +28,98 @@
|
||||
#include <modules/touch/include/win32_touch.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/globalscallbacks.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/interactionmonitor.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace TUIO;
|
||||
|
||||
namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo TouchActiveInfo = {
|
||||
"TouchActive",
|
||||
"True if we want to use touch input as 3D navigation",
|
||||
"Use this if we want to turn on or off Touch input navigation. "
|
||||
"Disabling this will reset all current touch inputs to the navigation."
|
||||
constexpr std::string_view _loggerCat = "TouchModule";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EnableTouchInfo = {
|
||||
"EnableTouchInteraction",
|
||||
"Enable Touch Interaction",
|
||||
"Use this property to turn on/off touch input navigation in the 3D scene. "
|
||||
"Disabling will reset all current touch inputs to the navigation."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo EventsInfo = {
|
||||
"DetectedTouchEvent",
|
||||
"Detected Touch Event",
|
||||
"True when there is an active touch event",
|
||||
openspace::properties::Property::Visibility::Hidden
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo
|
||||
DefaultDirectTouchRenderableTypesInfo =
|
||||
{
|
||||
"DefaultDirectTouchRenderableTypes",
|
||||
"Default Direct Touch Renderable Types",
|
||||
"A list of renderable types that will automatically use the \'direct "
|
||||
"manipulation\' scheme when interacted with, keeping the finger on a static "
|
||||
"position on the interaction sphere of the object when touching. Good for "
|
||||
"relatively spherical objects.",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
}
|
||||
namespace openspace {
|
||||
|
||||
TouchModule::TouchModule()
|
||||
: OpenSpaceModule("Touch")
|
||||
, _touchActive(TouchActiveInfo, true)
|
||||
, _touchIsEnabled(EnableTouchInfo, true)
|
||||
, _hasActiveTouchEvent(EventsInfo, false)
|
||||
, _defaultDirectTouchRenderableTypes(DefaultDirectTouchRenderableTypesInfo)
|
||||
{
|
||||
addPropertySubOwner(_touch);
|
||||
addPropertySubOwner(_markers);
|
||||
addProperty(_touchActive);
|
||||
_touchActive.onChange([&] {
|
||||
addProperty(_touchIsEnabled);
|
||||
_touchIsEnabled.onChange([&]() {
|
||||
_touch.resetAfterInput();
|
||||
_lastTouchInputs.clear();
|
||||
});
|
||||
|
||||
_hasActiveTouchEvent.setReadOnly(true);
|
||||
addProperty(_hasActiveTouchEvent);
|
||||
|
||||
_defaultDirectTouchRenderableTypes.onChange([&]() {
|
||||
_sortedDefaultRenderableTypes.clear();
|
||||
for (const std::string& s : _defaultDirectTouchRenderableTypes.value()) {
|
||||
ghoul::TemplateFactory<Renderable>* fRenderable =
|
||||
FactoryManager::ref().factory<Renderable>();
|
||||
|
||||
if (!fRenderable->hasClass(s)) {
|
||||
LWARNING(fmt::format(
|
||||
"In property 'DefaultDirectTouchRenderableTypes': '{}' is not a "
|
||||
"registered renderable type. Ignoring", s
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
_sortedDefaultRenderableTypes.insert(s);
|
||||
}
|
||||
});
|
||||
addProperty(_defaultDirectTouchRenderableTypes);
|
||||
}
|
||||
|
||||
TouchModule::~TouchModule() {
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){
|
||||
bool TouchModule::isDefaultDirectTouchType(std::string_view renderableType) const {
|
||||
return _sortedDefaultRenderableTypes.find(std::string(renderableType)) !=
|
||||
_sortedDefaultRenderableTypes.end();
|
||||
}
|
||||
|
||||
void TouchModule::internalInitialize(const ghoul::Dictionary&){
|
||||
_ear.reset(new TuioEar());
|
||||
|
||||
global::callback::initializeGL->push_back([&]() {
|
||||
LDEBUGC("TouchModule", "Initializing TouchMarker OpenGL");
|
||||
LDEBUG("Initializing TouchMarker OpenGL");
|
||||
_markers.initialize();
|
||||
#ifdef WIN32
|
||||
// We currently only support one window of touch input internally
|
||||
@@ -78,7 +132,7 @@ void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){
|
||||
});
|
||||
|
||||
global::callback::deinitializeGL->push_back([&]() {
|
||||
LDEBUGC("TouchMarker", "Deinitialize TouchMarker OpenGL");
|
||||
LDEBUG("Deinitialize TouchMarker OpenGL");
|
||||
_markers.deinitialize();
|
||||
});
|
||||
|
||||
@@ -104,26 +158,37 @@ void TouchModule::internalInitialize(const ghoul::Dictionary& /*dictionary*/){
|
||||
|
||||
|
||||
global::callback::preSync->push_back([&]() {
|
||||
if (!_touchActive) {
|
||||
if (!_touchIsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenSpaceEngine::Mode mode = global::openSpaceEngine->currentMode();
|
||||
if (mode == OpenSpaceEngine::Mode::CameraPath ||
|
||||
mode == OpenSpaceEngine::Mode::SessionRecordingPlayback)
|
||||
{
|
||||
// Reset everything, to avoid problems once we process inputs again
|
||||
_lastTouchInputs.clear();
|
||||
_touch.resetAfterInput();
|
||||
clearInputs();
|
||||
return;
|
||||
}
|
||||
|
||||
_touch.setCamera(global::navigationHandler->camera());
|
||||
_touch.setFocusNode(global::navigationHandler->orbitalNavigator().anchorNode());
|
||||
|
||||
if (processNewInput() && global::windowDelegate->isMaster()) {
|
||||
bool gotNewInput = processNewInput();
|
||||
if (gotNewInput && global::windowDelegate->isMaster()) {
|
||||
_touch.updateStateFromInput(_touchPoints, _lastTouchInputs);
|
||||
}
|
||||
else if (_touchPoints.empty()) {
|
||||
_touch.resetAfterInput();
|
||||
}
|
||||
|
||||
// update lastProcessed
|
||||
// Update last processed touch inputs
|
||||
_lastTouchInputs.clear();
|
||||
for (const TouchInputHolder& points : _touchPoints) {
|
||||
_lastTouchInputs.emplace_back(points.latestInput());
|
||||
}
|
||||
// calculate the new camera state for this frame
|
||||
// Calculate the new camera state for this frame
|
||||
_touch.step(global::windowDelegate->deltaTime());
|
||||
clearInputs();
|
||||
});
|
||||
@@ -145,14 +210,15 @@ bool TouchModule::processNewInput() {
|
||||
removeTouchInput(removal);
|
||||
}
|
||||
|
||||
// Set touch property to active (to void mouse input, mainly for mtdev bridges)
|
||||
_touch.touchActive(!_touchPoints.empty());
|
||||
bool touchHappened = !_touchPoints.empty();
|
||||
_hasActiveTouchEvent = touchHappened;
|
||||
|
||||
if (!_touchPoints.empty()) {
|
||||
// Set touch property to active (to void mouse input, mainly for mtdev bridges)
|
||||
if (touchHappened) {
|
||||
global::interactionMonitor->markInteraction();
|
||||
}
|
||||
|
||||
// Erase old input id's that no longer exists
|
||||
// Erase old input ids that no longer exist
|
||||
_lastTouchInputs.erase(
|
||||
std::remove_if(
|
||||
_lastTouchInputs.begin(),
|
||||
@@ -168,7 +234,7 @@ bool TouchModule::processNewInput() {
|
||||
}
|
||||
),
|
||||
_lastTouchInputs.end()
|
||||
);
|
||||
);
|
||||
|
||||
if (_tap) {
|
||||
_touch.tap();
|
||||
@@ -180,9 +246,11 @@ bool TouchModule::processNewInput() {
|
||||
if (_touchPoints.size() == _lastTouchInputs.size() &&
|
||||
!_touchPoints.empty())
|
||||
{
|
||||
// @TODO (emmbr26, 2023-02-03) Looks to me like this code will always return
|
||||
// true? That's a bit weird and should probably be investigated
|
||||
bool newInput = true;
|
||||
// go through list and check if the last registrered time is newer than the one in
|
||||
// lastProcessed (last frame)
|
||||
// Go through list and check if the last registrered time is newer than the
|
||||
// last processed touch inputs (last frame)
|
||||
std::for_each(
|
||||
_lastTouchInputs.begin(),
|
||||
_lastTouchInputs.end(),
|
||||
@@ -197,7 +265,8 @@ bool TouchModule::processNewInput() {
|
||||
if (!holder->isMoving()) {
|
||||
newInput = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
return newInput;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <modules/touch/include/touchmarker.h>
|
||||
#include <modules/touch/include/touchinteraction.h>
|
||||
#include <openspace/properties/list/stringlistproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
#include <openspace/util/touch.h>
|
||||
#include <memory>
|
||||
@@ -41,9 +43,15 @@ class Win32TouchHook;
|
||||
|
||||
class TouchModule : public OpenSpaceModule {
|
||||
public:
|
||||
constexpr static const char* Name = "Touch";
|
||||
|
||||
TouchModule();
|
||||
~TouchModule();
|
||||
|
||||
// Function to check if the given renderable type is one that should
|
||||
// use direct maniuplation
|
||||
bool isDefaultDirectTouchType(std::string_view renderableType) const;
|
||||
|
||||
protected:
|
||||
void internalInitialize(const ghoul::Dictionary& dictionary) override;
|
||||
|
||||
@@ -64,7 +72,13 @@ private:
|
||||
std::vector<TouchInput> _deferredRemovals;
|
||||
std::vector<TouchInput> _lastTouchInputs;
|
||||
|
||||
properties::BoolProperty _touchActive;
|
||||
properties::BoolProperty _touchIsEnabled;
|
||||
properties::BoolProperty _hasActiveTouchEvent;
|
||||
properties::StringListProperty _defaultDirectTouchRenderableTypes;
|
||||
|
||||
// A sorted version of the list in the property
|
||||
std::set<std::string> _sortedDefaultRenderableTypes;
|
||||
|
||||
// contains an id and the Point that was processed last frame
|
||||
glm::ivec2 _webPositionCallback = glm::ivec2(0);
|
||||
#ifdef WIN32
|
||||
|
||||
@@ -539,6 +539,20 @@ glm::quat OrbitalNavigator::anchorNodeToCameraRotation() const {
|
||||
return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion());
|
||||
}
|
||||
|
||||
|
||||
glm::dvec3 OrbitalNavigator::pushToSurfaceOfAnchor(
|
||||
const glm::dvec3& cameraPosition) const
|
||||
{
|
||||
const SurfacePositionHandle posHandle =
|
||||
calculateSurfacePositionHandle(*_anchorNode, cameraPosition);
|
||||
|
||||
return pushToSurface(
|
||||
cameraPosition,
|
||||
_anchorNode->worldPosition(),
|
||||
posHandle
|
||||
);
|
||||
}
|
||||
|
||||
void OrbitalNavigator::resetVelocities() {
|
||||
_mouseStates.resetVelocities();
|
||||
_joystickStates.resetVelocities();
|
||||
@@ -703,7 +717,6 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
// Perform the vertical movements based on user input
|
||||
pose.position = translateVertically(deltaTime, pose.position, anchorPos, posHandle);
|
||||
pose.position = pushToSurface(
|
||||
_minimumAllowedDistance,
|
||||
pose.position,
|
||||
anchorPos,
|
||||
posHandle
|
||||
@@ -992,6 +1005,10 @@ bool OrbitalNavigator::hasRollFriction() const {
|
||||
return _friction.roll;
|
||||
}
|
||||
|
||||
double OrbitalNavigator::minAllowedDistance() const {
|
||||
return _minimumAllowedDistance;
|
||||
}
|
||||
|
||||
OrbitalNavigator::CameraRotationDecomposition
|
||||
OrbitalNavigator::decomposeCameraRotationSurface(CameraPose cameraPose,
|
||||
const SceneGraphNode& reference)
|
||||
@@ -1473,8 +1490,7 @@ glm::dquat OrbitalNavigator::rotateHorizontally(double deltaTime,
|
||||
return mouseCameraRollRotation * globalCameraRotation;
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::pushToSurface(double minHeightAboveGround,
|
||||
const glm::dvec3& cameraPosition,
|
||||
glm::dvec3 OrbitalNavigator::pushToSurface(const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
@@ -1495,7 +1511,7 @@ glm::dvec3 OrbitalNavigator::pushToSurface(double minHeightAboveGround,
|
||||
glm::sign(dot(actualSurfaceToCamera, referenceSurfaceOutDirection));
|
||||
|
||||
return cameraPosition + referenceSurfaceOutDirection *
|
||||
glm::max(minHeightAboveGround - surfaceToCameraSigned, 0.0);
|
||||
glm::max(_minimumAllowedDistance - surfaceToCameraSigned, 0.0);
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::interpolateRotationDifferential(double deltaTime,
|
||||
@@ -1520,7 +1536,7 @@ glm::dquat OrbitalNavigator::interpolateRotationDifferential(double deltaTime,
|
||||
|
||||
SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle(
|
||||
const SceneGraphNode& node,
|
||||
const glm::dvec3 cameraPositionWorldSpace)
|
||||
const glm::dvec3& cameraPositionWorldSpace) const
|
||||
{
|
||||
ghoul_assert(
|
||||
glm::length(cameraPositionWorldSpace) > 0.0,
|
||||
|
||||
@@ -240,6 +240,10 @@ double Renderable::interactionSphere() const {
|
||||
return _interactionSphere;
|
||||
}
|
||||
|
||||
std::string_view Renderable::typeAsString() const {
|
||||
return _renderableType;
|
||||
}
|
||||
|
||||
SurfacePositionHandle Renderable::calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace) const
|
||||
{
|
||||
|
||||
@@ -160,25 +160,40 @@ namespace {
|
||||
openspace::properties::Property::Visibility::Developer
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo
|
||||
SupportsDirectInteractionInfo =
|
||||
{
|
||||
"SupportsDirectInteraction",
|
||||
"Supports Direct Interaction",
|
||||
"Only relevant when using touch interaction. If true, the \'direct "
|
||||
"manipulation\' scheme will be used when interacting with this scene graph "
|
||||
"node, meaning that the positions on the interaction sphere that intersects "
|
||||
"with the touch points will directly follow the motion of the touch points. "
|
||||
"Works best for objects that have an interaction sphere of about the same size "
|
||||
"as the bounding sphere, and that are somewhat spherical. Note that using this "
|
||||
"feature might significalty reduce the performance.",
|
||||
openspace::properties::Property::Visibility::AdvancedUser
|
||||
};
|
||||
|
||||
struct [[codegen::Dictionary(SceneGraphNode)]] Parameters {
|
||||
// The identifier of this scenegraph node. This name must be unique among all
|
||||
// The identifier of this scene graph node. This name must be unique among all
|
||||
// scene graph nodes that are loaded in a specific scene. If a duplicate is
|
||||
// detected the loading of the node will fail, as will all childing that depend on
|
||||
// the node. The identifier must not contain any whitespaces or '.'
|
||||
std::string identifier;
|
||||
|
||||
// This names the parent of the currently specified scenegraph node. The parent
|
||||
// This names the parent of the currently specified scene graph node. The parent
|
||||
// must already exist in the scene graph. If not specified, the node will be
|
||||
// attached to the root of the scenegraph
|
||||
// attached to the root of the scene graph
|
||||
std::optional<std::string> parent
|
||||
[[codegen::annotation(
|
||||
"If specified, this must be a name for another scenegraph node"
|
||||
"If specified, this must be a name for another scene graph node"
|
||||
)]];
|
||||
|
||||
// The renderable that is to be created for this scenegraph node. A renderable is
|
||||
// a component of a scenegraph node that will lead to some visual result on the
|
||||
// The renderable that is to be created for this scene graph node. A renderable is
|
||||
// a component of a scene graph node that will lead to some visual result on the
|
||||
// screen. The specifics heavily depend on the 'Type' of the renderable. If no
|
||||
// Renderable is specified, this scenegraph node is an internal node and can be
|
||||
// Renderable is specified, this scene graph node is an internal node and can be
|
||||
// used for either group children, or apply common transformations to a group of
|
||||
// children
|
||||
std::optional<ghoul::Dictionary> renderable [[codegen::reference("renderable")]];
|
||||
@@ -189,27 +204,30 @@ namespace {
|
||||
// [[codegen::verbatim(InteractionSphereInfo.description)]]
|
||||
std::optional<double> interactionSphere;
|
||||
|
||||
// [[codegen::verbatim(SupportsDirectInteractionInfo.description)]]
|
||||
std::optional<bool> supportsDirectInteraction;
|
||||
|
||||
struct Transform {
|
||||
// This node describes a translation that is applied to the scenegraph node
|
||||
// This node describes a translation that is applied to the scene graph node
|
||||
// and all its children. Depending on the 'Type' of the translation, this can
|
||||
// either be a static translation or a time-varying one
|
||||
std::optional<ghoul::Dictionary> translation
|
||||
[[codegen::reference("core_transform_translation")]];
|
||||
|
||||
// This nodes describes a rotation that is applied to the scenegraph node and
|
||||
// This nodes describes a rotation that is applied to the scene graph node and
|
||||
// all its children. Depending on the 'Type' of the rotation, this can either
|
||||
// be a static rotation or a time-varying one
|
||||
std::optional<ghoul::Dictionary> rotation
|
||||
[[codegen::reference("core_transform_rotation")]];
|
||||
|
||||
// This node describes a scaling that is applied to the scenegraph node and
|
||||
// This node describes a scaling that is applied to the scene graph node and
|
||||
// all its children. Depending on the 'Type' of the scaling, this can either
|
||||
// be a static scaling or a time-varying one
|
||||
std::optional<ghoul::Dictionary> scale
|
||||
[[codegen::reference("core_transform_scaling")]];
|
||||
};
|
||||
|
||||
// This describes a set of transformations that are applied to this scenegraph
|
||||
// This describes a set of transformations that are applied to this scene graph
|
||||
// node and all of its children. There are only three possible values
|
||||
// corresponding to a 'Translation', a 'Rotation', and a 'Scale'
|
||||
std::optional<Transform> transform;
|
||||
@@ -248,7 +266,7 @@ namespace {
|
||||
std::optional<ghoul::Dictionary> timeFrame
|
||||
[[codegen::reference("core_time_frame")]];
|
||||
|
||||
// A tag or list of tags that can be used to reference to a group of scenegraph
|
||||
// A tag or list of tags that can be used to reference to a group of scene graph
|
||||
// nodes.
|
||||
std::optional<std::variant<std::string, std::vector<std::string>>> tag;
|
||||
|
||||
@@ -258,7 +276,7 @@ namespace {
|
||||
std::optional<std::string> name;
|
||||
|
||||
// If this value is specified, this '/' separated URI specifies the location
|
||||
// of this scenegraph node in a GUI representation, for instance
|
||||
// of this scene graph node in a GUI representation, for instance
|
||||
// '/SolarSystem/Earth/Moon'
|
||||
std::optional<std::string> path;
|
||||
|
||||
@@ -266,12 +284,12 @@ namespace {
|
||||
std::optional<std::string> description;
|
||||
|
||||
// If this value is specified, GUI applications are incouraged to ignore this
|
||||
// scenegraph node. This is most useful to trim collective lists of nodes and
|
||||
// scene graph node. This is most useful to trim collective lists of nodes and
|
||||
// not display, for example, barycenters
|
||||
std::optional<bool> hidden;
|
||||
};
|
||||
// Additional information that is passed to GUI applications. These are all hints
|
||||
// and do not have any impact on the actual function of the scenegraph node
|
||||
// and do not have any impact on the actual function of the scene graph node
|
||||
std::optional<Gui> gui [[codegen::key("GUI")]];
|
||||
};
|
||||
#include "scenegraphnode_codegen.cpp"
|
||||
@@ -513,6 +531,7 @@ SceneGraphNode::SceneGraphNode()
|
||||
, _screenSizeRadius(ScreenSizeRadiusInfo, 0)
|
||||
, _visibilityDistance(VisibilityDistanceInfo, 6e10f)
|
||||
, _showDebugSphere(ShowDebugSphereInfo, false)
|
||||
, _supportsDirectInteraction(SupportsDirectInteractionInfo, false)
|
||||
{
|
||||
addProperty(_computeScreenSpaceValues);
|
||||
addProperty(_screenSpacePosition);
|
||||
@@ -552,6 +571,8 @@ SceneGraphNode::SceneGraphNode()
|
||||
addProperty(_approachFactor);
|
||||
|
||||
addProperty(_showDebugSphere);
|
||||
|
||||
addProperty(_supportsDirectInteraction);
|
||||
}
|
||||
|
||||
SceneGraphNode::~SceneGraphNode() {}
|
||||
@@ -1207,6 +1228,10 @@ double SceneGraphNode::approachFactor() const {
|
||||
return _approachFactor;
|
||||
}
|
||||
|
||||
bool SceneGraphNode::supportsDirectInteraction() const {
|
||||
return _supportsDirectInteraction;
|
||||
}
|
||||
|
||||
const Renderable* SceneGraphNode::renderable() const {
|
||||
return _renderable.get();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user