added easier support for calculating multitouch rotating behavior including deltaAngle, isRotating, rotating(direction) properties

This commit is contained in:
ZappoMan 2014-02-09 12:08:17 -08:00
parent 3bf8dd87e8
commit dca0b05927
5 changed files with 160 additions and 31 deletions

View file

@ -146,8 +146,8 @@ function printTouchEvent(eventName, event) {
for (var i = 0; i < event.points.length; i++) {
print(" event.angles[" + i + "]:" + event.angles[i]);
}
print(" event.rotatingClockwise=" + event.rotatingClockwise);
print(" event.rotatingCounterClockwise=" + event.rotatingCounterClockwise);
print(" event.isRotating=" + event.isRotating);
print(" event.rotating=" + event.rotating);
}
function touchBeginEvent(event) {

View 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);

View file

@ -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) {
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
@ -1320,7 +1325,7 @@ void Application::touchUpdateEvent(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
touchUpdateEvent(event);
_lastTouchEvent = thisEvent;
@ -2007,12 +2012,9 @@ void Application::updateHoverVoxels(float deltaTime, float& distance, BoxFace& f
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
// Check for a new hover voxel
if (!_mousePressed) {
{
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
}
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
_isHoverVoxel = _voxels.findRayIntersection(_mouseRayOrigin, _mouseRayDirection, _hoverVoxel, distance, face);
}
}

View file

@ -323,14 +323,16 @@ TouchEvent::TouchEvent() :
isControl(false),
isMeta(false),
isAlt(false),
touchPoints(0),
points(),
radius(0.0f),
isPinching(false),
isPinchOpening(false),
angles(),
angle(0.0f),
rotatingClockwise(false),
rotatingCounterClockwise(false)
deltaAngle(0.0f),
isRotating(false),
rotating("none")
{
};
@ -359,9 +361,9 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
const QList<QTouchEvent::TouchPoint>& tPoints = event.touchPoints();
float touchAvgX = 0.0f;
float touchAvgY = 0.0f;
int numTouches = tPoints.count();
if (numTouches > 1) {
for (int i = 0; i < numTouches; ++i) {
touchPoints = tPoints.count();
if (touchPoints > 1) {
for (int i = 0; i < touchPoints; ++i) {
touchAvgX += tPoints[i].pos().x();
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());
points << thisPoint;
}
touchAvgX /= (float)(numTouches);
touchAvgY /= (float)(numTouches);
touchAvgX /= (float)(touchPoints);
touchAvgY /= (float)(touchPoints);
} else {
// 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?
@ -384,7 +386,7 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
// also calculate the rotation angle for each point
float maxRadius = 0.0f;
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());
float thisRadius = glm::distance(center,touchPoint);
if (thisRadius > maxRadius) {
@ -397,13 +399,12 @@ void TouchEvent::initWithQTouchEvent(const QTouchEvent& event) {
}
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;
for (int i = 0; i < numTouches; ++i) {
for (int i = 0; i < touchPoints; ++i) {
totalAngle += angles[i];
}
angle = totalAngle/numTouches;
angle = totalAngle/(float)touchPoints;
isPressed = event.touchPointStates().testFlag(Qt::TouchPointPressed);
isMoved = event.touchPointStates().testFlag(Qt::TouchPointMoved);
@ -431,15 +432,16 @@ void TouchEvent::calculateMetaAttributes(const TouchEvent& other) {
}
// determine if the points are rotating...
deltaAngle = angle - other.angle;
if (other.angle < angle) {
rotatingClockwise = true;
rotatingCounterClockwise = false;
isRotating = true;
rotating = "clockwise";
} else if (other.angle > angle) {
rotatingClockwise = false;
rotatingCounterClockwise = true;
isRotating = true;
rotating = "counterClockwise";
} else {
rotatingClockwise = false;
rotatingCounterClockwise = false;
isRotating = false;
rotating = "none";
}
}
@ -456,6 +458,7 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
obj.setProperty("isMeta", event.isMeta);
obj.setProperty("isControl", event.isControl);
obj.setProperty("isAlt", event.isAlt);
obj.setProperty("touchPoints", event.touchPoints);
QScriptValue pointsObj = engine->newArray();
int index = 0;
@ -470,6 +473,7 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
obj.setProperty("isPinchOpening", event.isPinchOpening);
obj.setProperty("angle", event.angle);
obj.setProperty("deltaAngle", event.deltaAngle);
QScriptValue anglesObj = engine->newArray();
index = 0;
foreach (float angle, event.angles) {
@ -478,8 +482,8 @@ QScriptValue touchEventToScriptValue(QScriptEngine* engine, const TouchEvent& ev
}
obj.setProperty("angles", anglesObj);
obj.setProperty("rotatingClockwise", event.rotatingClockwise);
obj.setProperty("rotatingCounterClockwise", event.rotatingCounterClockwise);
obj.setProperty("isRotating", event.isRotating);
obj.setProperty("rotating", event.rotating);
return obj;
}

View file

@ -67,14 +67,16 @@ public:
bool isControl;
bool isMeta;
bool isAlt;
int touchPoints;
QVector<glm::vec2> points;
float radius;
bool isPinching;
bool isPinchOpening;
QVector<float> angles; // angle from center to each point
float angle;
bool rotatingClockwise;
bool rotatingCounterClockwise;
float angle; // the average of the angles
float deltaAngle; // the change in average angle from last event
bool isRotating;
QString rotating;
private:
void initWithQTouchEvent(const QTouchEvent& event);