mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 01:17:14 +02:00
added easier support for calculating multitouch rotating behavior including deltaAngle, isRotating, rotating(direction) properties
This commit is contained in:
parent
3bf8dd87e8
commit
dca0b05927
5 changed files with 160 additions and 31 deletions
|
@ -146,8 +146,8 @@ function printTouchEvent(eventName, event) {
|
||||||
for (var i = 0; i < event.points.length; i++) {
|
for (var i = 0; i < event.points.length; i++) {
|
||||||
print(" event.angles[" + i + "]:" + event.angles[i]);
|
print(" event.angles[" + i + "]:" + event.angles[i]);
|
||||||
}
|
}
|
||||||
print(" event.rotatingClockwise=" + event.rotatingClockwise);
|
print(" event.isRotating=" + event.isRotating);
|
||||||
print(" event.rotatingCounterClockwise=" + event.rotatingCounterClockwise);
|
print(" event.rotating=" + event.rotating);
|
||||||
}
|
}
|
||||||
|
|
||||||
function touchBeginEvent(event) {
|
function touchBeginEvent(event) {
|
||||||
|
|
121
examples/multitouchExample.js
Normal file
121
examples/multitouchExample.js
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
//
|
||||||
|
// multitouchExample.js
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 2/9/14.
|
||||||
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// This is an example script that demonstrates use of the Controller class's multi-touch features
|
||||||
|
//
|
||||||
|
// When this script is running:
|
||||||
|
// * Four finger rotate gesture will rotate your avatar.
|
||||||
|
// * Three finger swipe up/down will adjust the pitch of your avatars head.
|
||||||
|
//
|
||||||
|
|
||||||
|
var lastX = 0;
|
||||||
|
var lastY = 0;
|
||||||
|
var lastAngle = 0;
|
||||||
|
var yawFromMultiTouch = 0;
|
||||||
|
var pitchFromMultiTouch = 0;
|
||||||
|
var wantDebugging = false;
|
||||||
|
var ROTATE_YAW_SCALE = 0.15;
|
||||||
|
var MOUSE_PITCH_SCALE = -12.5;
|
||||||
|
var FIXED_MOUSE_TIMESTEP = 0.016;
|
||||||
|
|
||||||
|
var ROTATE_TOUCH_POINTS = 4;
|
||||||
|
var PITCH_TOUCH_POINTS = 3;
|
||||||
|
|
||||||
|
|
||||||
|
function printTouchEvent(eventName, event) {
|
||||||
|
print(eventName);
|
||||||
|
|
||||||
|
print(" event.x,y=" + event.x + ", " + event.y);
|
||||||
|
print(" event.isPressed=" + event.isPressed);
|
||||||
|
print(" event.isMoved=" + event.isMoved);
|
||||||
|
print(" event.isStationary=" + event.isStationary);
|
||||||
|
print(" event.isReleased=" + event.isReleased);
|
||||||
|
print(" event.isShifted=" + event.isShifted);
|
||||||
|
print(" event.isControl=" + event.isControl);
|
||||||
|
print(" event.isMeta=" + event.isMeta);
|
||||||
|
print(" event.isAlt=" + event.isAlt);
|
||||||
|
print(" event.touchPoints=" + event.touchPoints);
|
||||||
|
for (var i = 0; i < event.points.length; i++) {
|
||||||
|
print(" event.points[" + i + "].x.y:" + event.points[i].x + ", " + event.points[i].y);
|
||||||
|
}
|
||||||
|
print(" event.radius=" + event.radius);
|
||||||
|
print(" event.isPinching=" + event.isPinching);
|
||||||
|
print(" event.isPinchOpening=" + event.isPinchOpening);
|
||||||
|
|
||||||
|
print(" event.angle=" + event.angle);
|
||||||
|
print(" event.deltaAngle=" + event.deltaAngle);
|
||||||
|
for (var i = 0; i < event.points.length; i++) {
|
||||||
|
print(" event.angles[" + i + "]:" + event.angles[i]);
|
||||||
|
}
|
||||||
|
print(" event.isRotating=" + event.isRotating);
|
||||||
|
print(" event.rotating=" + event.rotating);
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchBeginEvent(event) {
|
||||||
|
printTouchEvent("touchBeginEvent", event);
|
||||||
|
lastX = event.x;
|
||||||
|
lastY = event.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchUpdateEvent(event) {
|
||||||
|
printTouchEvent("touchUpdateEvent", event);
|
||||||
|
|
||||||
|
if (event.isRotating && event.touchPoints == ROTATE_TOUCH_POINTS) {
|
||||||
|
// it's possible for the multitouch rotate gesture to generate angle changes which are faster than comfortable to
|
||||||
|
// view, so we will scale this change in angle to make it more comfortable
|
||||||
|
var scaledRotate = event.deltaAngle * ROTATE_YAW_SCALE;
|
||||||
|
print(">>> event.deltaAngle=" + event.deltaAngle);
|
||||||
|
print(">>> scaledRotate=" + scaledRotate);
|
||||||
|
yawFromMultiTouch += scaledRotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.touchPoints == PITCH_TOUCH_POINTS) {
|
||||||
|
pitchFromMultiTouch += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP);
|
||||||
|
}
|
||||||
|
lastX = event.x;
|
||||||
|
lastY = event.y;
|
||||||
|
lastAngle = event.angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchEndEvent(event) {
|
||||||
|
printTouchEvent("touchEndEvent", event);
|
||||||
|
}
|
||||||
|
// Map touch events to our callbacks
|
||||||
|
Controller.touchBeginEvent.connect(touchBeginEvent);
|
||||||
|
Controller.touchUpdateEvent.connect(touchUpdateEvent);
|
||||||
|
Controller.touchEndEvent.connect(touchEndEvent);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// rotate body yaw for yaw received from multitouch rotate
|
||||||
|
var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3( { x: 0, y: yawFromMultiTouch, z: 0 } ));
|
||||||
|
if (wantDebugging) {
|
||||||
|
print("changing orientation"
|
||||||
|
+ " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + ","
|
||||||
|
+ MyAvatar.orientation.z + "," + MyAvatar.orientation.w
|
||||||
|
+ " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w);
|
||||||
|
}
|
||||||
|
MyAvatar.orientation = newOrientation;
|
||||||
|
yawFromMultiTouch = 0;
|
||||||
|
|
||||||
|
// apply pitch from mouse
|
||||||
|
var newPitch = MyAvatar.headPitch + pitchFromMultiTouch;
|
||||||
|
if (wantDebugging) {
|
||||||
|
print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch);
|
||||||
|
}
|
||||||
|
MyAvatar.headPitch = newPitch;
|
||||||
|
pitchFromMultiTouch = 0;
|
||||||
|
}
|
||||||
|
Script.willSendVisualDataCallback.connect(update);
|
||||||
|
|
||||||
|
|
||||||
|
function scriptEnding() {
|
||||||
|
// handle any shutdown logic here
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
|
@ -1218,6 +1218,11 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool MAKE_SOUND_ON_VOXEL_HOVER = false;
|
||||||
|
const bool MAKE_SOUND_ON_VOXEL_CLICK = true;
|
||||||
|
const float HOVER_VOXEL_FREQUENCY = 7040.f;
|
||||||
|
const float HOVER_VOXEL_DECAY = 0.999f;
|
||||||
|
|
||||||
void Application::mousePressEvent(QMouseEvent* event) {
|
void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
||||||
|
|
||||||
|
@ -1320,7 +1325,7 @@ void Application::touchUpdateEvent(QTouchEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::touchBeginEvent(QTouchEvent* event) {
|
void Application::touchBeginEvent(QTouchEvent* event) {
|
||||||
TouchEvent thisEvent(*event, _lastTouchEvent);
|
TouchEvent thisEvent(*event); // on touch begin, we don't compare to last event
|
||||||
_controllerScriptingInterface.emitTouchBeginEvent(thisEvent); // send events to any registered scripts
|
_controllerScriptingInterface.emitTouchBeginEvent(thisEvent); // send events to any registered scripts
|
||||||
touchUpdateEvent(event);
|
touchUpdateEvent(event);
|
||||||
_lastTouchEvent = thisEvent;
|
_lastTouchEvent = thisEvent;
|
||||||
|
@ -2007,12 +2012,9 @@ void Application::updateHoverVoxels(float deltaTime, float& distance, BoxFace& f
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
|
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
|
||||||
|
|
||||||
// Check for a new hover voxel
|
|
||||||
if (!_mousePressed) {
|
if (!_mousePressed) {
|
||||||
{
|
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
|
||||||
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,14 +323,16 @@ TouchEvent::TouchEvent() :
|
||||||
isControl(false),
|
isControl(false),
|
||||||
isMeta(false),
|
isMeta(false),
|
||||||
isAlt(false),
|
isAlt(false),
|
||||||
|
touchPoints(0),
|
||||||
points(),
|
points(),
|
||||||
radius(0.0f),
|
radius(0.0f),
|
||||||
isPinching(false),
|
isPinching(false),
|
||||||
isPinchOpening(false),
|
isPinchOpening(false),
|
||||||
angles(),
|
angles(),
|
||||||
angle(0.0f),
|
angle(0.0f),
|
||||||
rotatingClockwise(false),
|
deltaAngle(0.0f),
|
||||||
rotatingCounterClockwise(false)
|
isRotating(false),
|
||||||
|
rotating("none")
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -359,9 +361,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
|
||||||
const QList<QTouchEvent::TouchPoint>& tPoints = event.touchPoints();
|
const QList<QTouchEvent::TouchPoint>& tPoints = event.touchPoints();
|
||||||
float touchAvgX = 0.0f;
|
float touchAvgX = 0.0f;
|
||||||
float touchAvgY = 0.0f;
|
float touchAvgY = 0.0f;
|
||||||
int numTouches = tPoints.count();
|
touchPoints = tPoints.count();
|
||||||
if (numTouches > 1) {
|
if (touchPoints > 1) {
|
||||||
for (int i = 0; i < numTouches; ++i) {
|
for (int i = 0; i < touchPoints; ++i) {
|
||||||
touchAvgX += tPoints[i].pos().x();
|
touchAvgX += tPoints[i].pos().x();
|
||||||
touchAvgY += tPoints[i].pos().y();
|
touchAvgY += tPoints[i].pos().y();
|
||||||
|
|
||||||
|
@ -369,8 +371,8 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
|
||||||
glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
glm::vec2 thisPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
||||||
points << thisPoint;
|
points << thisPoint;
|
||||||
}
|
}
|
||||||
touchAvgX /= (float)(numTouches);
|
touchAvgX /= (float)(touchPoints);
|
||||||
touchAvgY /= (float)(numTouches);
|
touchAvgY /= (float)(touchPoints);
|
||||||
} else {
|
} else {
|
||||||
// I'm not sure this should ever happen, why would Qt send us a touch event for only one point?
|
// I'm not sure this should ever happen, why would Qt send us a touch event for only one point?
|
||||||
// maybe this happens in the case of a multi-touch where all but the last finger is released?
|
// maybe this happens in the case of a multi-touch where all but the last finger is released?
|
||||||
|
@ -384,7 +386,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
|
||||||
// also calculate the rotation angle for each point
|
// also calculate the rotation angle for each point
|
||||||
float maxRadius = 0.0f;
|
float maxRadius = 0.0f;
|
||||||
glm::vec2 center(x,y);
|
glm::vec2 center(x,y);
|
||||||
for (int i = 0; i < numTouches; ++i) {
|
for (int i = 0; i < touchPoints; ++i) {
|
||||||
glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
glm::vec2 touchPoint(tPoints[i].pos().x(), tPoints[i].pos().y());
|
||||||
float thisRadius = glm::distance(center,touchPoint);
|
float thisRadius = glm::distance(center,touchPoint);
|
||||||
if (thisRadius > maxRadius) {
|
if (thisRadius > maxRadius) {
|
||||||
|
@ -397,13 +399,12 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
|
||||||
}
|
}
|
||||||
radius = maxRadius;
|
radius = maxRadius;
|
||||||
|
|
||||||
// after calculating the center point (average touch point), determine the maximum radius
|
// after calculating the angles for each touch point, determine the average angle
|
||||||
float totalAngle = 0.0f;
|
float totalAngle = 0.0f;
|
||||||
for (int i = 0; i < numTouches; ++i) {
|
for (int i = 0; i < touchPoints; ++i) {
|
||||||
totalAngle += angles[i];
|
totalAngle += angles[i];
|
||||||
}
|
}
|
||||||
angle = totalAngle/numTouches;
|
angle = totalAngle/(float)touchPoints;
|
||||||
|
|
||||||
|
|
||||||
isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
|
isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
|
||||||
isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
|
isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
|
||||||
|
@ -431,15 +432,16 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine if the points are rotating...
|
// determine if the points are rotating...
|
||||||
|
deltaAngle = angle - other.angle;
|
||||||
if (other.angle < angle) {
|
if (other.angle < angle) {
|
||||||
rotatingClockwise = true;
|
isRotating = true;
|
||||||
rotatingCounterClockwise = false;
|
rotating = "clockwise";
|
||||||
} else if (other.angle > angle) {
|
} else if (other.angle > angle) {
|
||||||
rotatingClockwise = false;
|
isRotating = true;
|
||||||
rotatingCounterClockwise = true;
|
rotating = "counterClockwise";
|
||||||
} else {
|
} else {
|
||||||
rotatingClockwise = false;
|
isRotating = false;
|
||||||
rotatingCounterClockwise = false;
|
rotating = "none";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,6 +458,7 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
|
||||||
obj.setProperty("isMeta", event.isMeta);
|
obj.setProperty("isMeta", event.isMeta);
|
||||||
obj.setProperty("isControl", event.isControl);
|
obj.setProperty("isControl", event.isControl);
|
||||||
obj.setProperty("isAlt", event.isAlt);
|
obj.setProperty("isAlt", event.isAlt);
|
||||||
|
obj.setProperty("touchPoints", event.touchPoints);
|
||||||
|
|
||||||
QScriptValue pointsObj = engine->newArray();
|
QScriptValue pointsObj = engine->newArray();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -470,6 +473,7 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
|
||||||
obj.setProperty("isPinchOpening", event.isPinchOpening);
|
obj.setProperty("isPinchOpening", event.isPinchOpening);
|
||||||
|
|
||||||
obj.setProperty("angle", event.angle);
|
obj.setProperty("angle", event.angle);
|
||||||
|
obj.setProperty("deltaAngle", event.deltaAngle);
|
||||||
QScriptValue anglesObj = engine->newArray();
|
QScriptValue anglesObj = engine->newArray();
|
||||||
index = 0;
|
index = 0;
|
||||||
foreach (float angle, event.angles) {
|
foreach (float angle, event.angles) {
|
||||||
|
@ -478,8 +482,8 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
|
||||||
}
|
}
|
||||||
obj.setProperty("angles", anglesObj);
|
obj.setProperty("angles", anglesObj);
|
||||||
|
|
||||||
obj.setProperty("rotatingClockwise", event.rotatingClockwise);
|
obj.setProperty("isRotating", event.isRotating);
|
||||||
obj.setProperty("rotatingCounterClockwise", event.rotatingCounterClockwise);
|
obj.setProperty("rotating", event.rotating);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,14 +67,16 @@ public:
|
||||||
bool isControl;
|
bool isControl;
|
||||||
bool isMeta;
|
bool isMeta;
|
||||||
bool isAlt;
|
bool isAlt;
|
||||||
|
int touchPoints;
|
||||||
QVector<glm::vec2> points;
|
QVector<glm::vec2> points;
|
||||||
float radius;
|
float radius;
|
||||||
bool isPinching;
|
bool isPinching;
|
||||||
bool isPinchOpening;
|
bool isPinchOpening;
|
||||||
QVector<float> angles; // angle from center to each point
|
QVector<float> angles; // angle from center to each point
|
||||||
float angle;
|
float angle; // the average of the angles
|
||||||
bool rotatingClockwise;
|
float deltaAngle; // the change in average angle from last event
|
||||||
bool rotatingCounterClockwise;
|
bool isRotating;
|
||||||
|
QString rotating;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initWithQTouchEvent(const QTouchEvent& event);
|
void initWithQTouchEvent(const QTouchEvent& event);
|
||||||
|
|
Loading…
Reference in a new issue