Support for LeapMotion and worklist 19734

-  Introduce the DeviceTracker class  to abstract all the possible
devices
- Introduce the MotionTracker ( a DeviceTracker ) that contains a
transform tree of joints
- Add Leapmotion class as a MotionTracker and the support for the
Leapmotion sdk in external
- Add InputController as the abstraction of a MotionTracker/Joint for
Javascript
This commit is contained in:
samcake 2014-07-01 03:14:01 -07:00
parent fe03743163
commit 3ce455aba4
33 changed files with 7828 additions and 215 deletions

181
examples/leapOfFaith.js Normal file
View file

@ -0,0 +1,181 @@
//
// leapOfFaith.js
// examples
//
// Created by Sam Cake on 6/22/14.
// Copyright 2014 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
//
var jointList = MyAvatar.getJointNames();
var jointMappings = "\n# Joint list start";
for (var i = 0; i < jointList.length; i++) {
jointMappings = jointMappings + "\njointIndex = " + jointList[i] + " = " + i;
}
print(jointMappings + "\n# Joint list end");
function vec3ToString( v ) {
return ("(" + v.x +", " + v.y + ", " + v.z + ")" );
}
function quatToString( q ) {
return ("(" + q.x +", " + q.y + ", " + q.z + ", " + q.w + ")" );
}
function printSpatialEvent( label, spatialEvent ) {
/* var dataString = label + " " +
vec3ToString( spatialEvent.locTranslation ) + " " +
quatToString( spatialEvent.locRotation ) + " " +
vec3ToString( spatialEvent.absTranslation ) + " " +
quatToString( spatialEvent.absRotation );
// print( dataString )
*/;
}
function avatarToWorld( apos ) {
// apply offset ?
var offset = { x: 0, y: 0.5, z: -0.5 };
var lpos = Vec3.sum(apos, offset);
var wpos = Vec3.sum( MyAvatar.position , Vec3.multiplyQbyV(MyAvatar.orientation, lpos) );
return wpos;
}
var jointParticles = [];
function updateJointParticle( joint, pos, look ) {
/* print( "debug 1" );
var jointID = jointParticles[ joint ];
if ( jointID == null ) {
print( "debug create " + joint );
*/
var ballProperties = {
position: pos,
velocity: { x: 0, y: 0, z: 0},
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
radius : 0.005* look.r,
color: look.c,
lifetime: 0.05
};
jointParticles[ joint ] = Particles.addParticle(ballProperties);
/* } else {
print( "debug update " + joint );
var prop = Particles.getParticleProperties( jointID );
prop.position = pos;
prop.lifetime = 1.0;
Particles.editParticle( jointID, prop );
}*/
}
function evalFingerBoneLook( isRightSide, finger, bone ) {
return { c: { red: (255 * ( 1 - isRightSide )),
green: 255 * ( ((bone - 1)) / 3 ),
blue: (255 * isRightSide) },
r: (5 + (5 - (finger-1))) / 10.0 };
}
var leapJoints = [
{ n: "LeftHand", l: { c: { red: 255, green: 0, blue: 0 }, r: 3 } },
{ n: "LeftHandThumb2", l: evalFingerBoneLook( 0, 1, 2) },
{ n: "LeftHandThumb3", l: evalFingerBoneLook( 0, 1, 3) },
{ n: "LeftHandThumb4", l: evalFingerBoneLook( 0, 1, 4) },
{ n: "LeftHandIndex1", l: evalFingerBoneLook( 0, 2, 1) },
{ n: "LeftHandIndex2", l: evalFingerBoneLook( 0, 2, 2) },
{ n: "LeftHandIndex3", l: evalFingerBoneLook( 0, 2, 3) },
{ n: "LeftHandIndex4", l: evalFingerBoneLook( 0, 2, 4) },
{ n: "LeftHandMiddle1", l: evalFingerBoneLook( 0, 3, 1) },
{ n: "LeftHandMiddle2", l: evalFingerBoneLook( 0, 3, 2) },
{ n: "LeftHandMiddle3", l: evalFingerBoneLook( 0, 3, 3) },
{ n: "LeftHandMiddle4", l: evalFingerBoneLook( 0, 3, 4) },
{ n: "LeftHandRing1", l: evalFingerBoneLook( 0, 4, 1) },
{ n: "LeftHandRing2", l: evalFingerBoneLook( 0, 4, 2) },
{ n: "LeftHandRing3", l: evalFingerBoneLook( 0, 4, 3) },
{ n: "LeftHandRing4", l: evalFingerBoneLook( 0, 4, 4) },
{ n: "LeftHandPinky1", l: evalFingerBoneLook( 0, 5, 1) },
{ n: "LeftHandPinky2", l: evalFingerBoneLook( 0, 5, 2) },
{ n: "LeftHandPinky3", l: evalFingerBoneLook( 0, 5, 3) },
{ n: "LeftHandPinky4", l: evalFingerBoneLook( 0, 5, 4) },
{ n: "RightHand", l: { c: { red: 0, green: 0, blue: 255 }, r: 3 } },
{ n: "RightHandThumb2", l: evalFingerBoneLook( 1, 1, 2) },
{ n: "RightHandThumb3", l: evalFingerBoneLook( 1, 1, 3) },
{ n: "RightHandThumb4", l: evalFingerBoneLook( 1, 1, 4) },
{ n: "RightHandIndex1", l: evalFingerBoneLook( 1, 2, 1) },
{ n: "RightHandIndex2", l: evalFingerBoneLook( 1, 2, 2) },
{ n: "RightHandIndex3", l: evalFingerBoneLook( 1, 2, 3) },
{ n: "RightHandIndex4", l: evalFingerBoneLook( 1, 2, 4) },
{ n: "RightHandMiddle1", l: evalFingerBoneLook( 1, 3, 1) },
{ n: "RightHandMiddle2", l: evalFingerBoneLook( 1, 3, 2) },
{ n: "RightHandMiddle3", l: evalFingerBoneLook( 1, 3, 3) },
{ n: "RightHandMiddle4", l: evalFingerBoneLook( 1, 3, 4) },
{ n: "RightHandRing1", l: evalFingerBoneLook( 1, 4, 1) },
{ n: "RightHandRing2", l: evalFingerBoneLook( 1, 4, 2) },
{ n: "RightHandRing3", l: evalFingerBoneLook( 1, 4, 3) },
{ n: "RightHandRing4", l: evalFingerBoneLook( 1, 4, 4) },
{ n: "RightHandPinky1", l: evalFingerBoneLook( 1, 5, 1) },
{ n: "RightHandPinky2", l: evalFingerBoneLook( 1, 5, 2) },
{ n: "RightHandPinky3", l: evalFingerBoneLook( 1, 5, 3) },
{ n: "RightHandPinky4", l: evalFingerBoneLook( 1, 5, 4) },
];
function onSpatialEventHandler( jointName, look ) {
var _jointName = jointName;
var _look = look;
return (function( spatialEvent ) {
MyAvatar.setJointData(_jointName, spatialEvent.absRotation);
updateJointParticle(_jointName, avatarToWorld( spatialEvent.absTranslation ), _look );
printSpatialEvent(_jointName, spatialEvent );
});
}
var isPullingSpatialData = true;
var jointControllers = [];
for ( i in leapJoints ) {
print( leapJoints[i].n );
var controller = Controller.createInputController( "Spatial", leapJoints[i].n );
var handler = onSpatialEventHandler( leapJoints[i].n, leapJoints[i].l );
jointControllers.push( { c: controller, h: handler } );
if ( ! isPullingSpatialData ) {
controller.spatialEvent.connect( handler );
}
}
Script.update.connect(function(deltaTime) {
if ( isPullingSpatialData )
{
for ( i in jointControllers ) {
if ( jointControllers[i].c.isActive() ) {
var spatialEvent = { absTranslation: jointControllers[i].c.getAbsTranslation(),
absRotation: jointControllers[i].c.getAbsRotation() };
jointControllers[i].h( spatialEvent );
}
}
}
});
Script.scriptEnding.connect(function() {
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,787 @@
################################################################################
# Copyright (C) 2012-2013 Leap Motion, Inc. All rights reserved. #
# Leap Motion proprietary and confidential. Not for distribution. #
# Use subject to the terms of the Leap Motion SDK Agreement available at #
# https://developer.leapmotion.com/sdk_agreement, or another agreement #
# between Leap Motion and you, your company or other organization. #
################################################################################
# usage:
# swig -c++ -python -o LeapPython.cpp -interface LeapPython Leap.i
# swig -c++ -java -o LeapJava.cpp -package com.leapmotion.leap -outdir com/leapmotion/leap Leap.i
# swig -c++ -csharp -o LeapCSharp.cpp -dllimport LeapCSharp -namespace Leap Leap.i
%module(directors="1", threads="1") Leap
#pragma SWIG nowarn=325
%include "std_string.i"
%include "std_vector.i"
%include "stdint.i"
%include "attribute.i"
################################################################################
# Ignore constructors for internal use only #
################################################################################
%ignore Leap::Pointable::Pointable(PointableImplementation*);
%ignore Leap::Pointable::Pointable(FingerImplementation*);
%ignore Leap::Pointable::Pointable(ToolImplementation*);
%ignore Leap::Finger::Finger(FingerImplementation*);
%ignore Leap::Tool::Tool(ToolImplementation*);
%ignore Leap::Bone::Bone(BoneImplementation*);
%ignore Leap::Hand::Hand(HandImplementation*);
%ignore Leap::Gesture::Gesture(GestureImplementation*);
%ignore Leap::Screen::Screen(ScreenImplementation*);
%ignore Leap::Frame::Frame(FrameImplementation*);
%ignore Leap::Controller::Controller(ControllerImplementation*);
%ignore Leap::Device::Device(DeviceImplementation*);
%ignore Leap::InteractionBox::InteractionBox(InteractionBoxImplementation*);
#####################################################################################
# Set Attributes (done after functions are uppercased, but before vars are lowered) #
#####################################################################################
#TODO: If possible, figure out how to auomatically make any C++ function
# that is const and takes no arguments be defined as a property in C#
%define %constattrib( Class, Type, Name )
%attribute( Class, Type, Name, Name )
%enddef
%define %staticattrib(Class, AttributeType, AttributeName)
%ignore Class::AttributeName();
%ignore Class::AttributeName() const;
%immutable Class::AttributeName;
%extend Class {
AttributeType AttributeName;
}
%{
#define %mangle(Class) ##_## AttributeName ## _get() Class::AttributeName()
%}
%enddef
%define %leapattrib( Class, Type, Name )
%attributeval(Class, Leap::Type, Name, Name)
%enddef
#if SWIGCSHARP || SWIGPYTHON
%rename(GestureType) Leap::Gesture::Type;
%rename(GestureState) Leap::Gesture::State;
%rename(FingerJoint) Leap::Finger::Joint;
%rename(FingerType) Leap::Finger::Type;
%rename(BoneType) Leap::Bone::Type;
%rename(DeviceType) Leap::Device::Type;
#endif
# Apply language specific caseing
#if SWIGCSHARP
%rename("%(camelcase)s", %$not %$isenumitem) "";
#elif SWIGPYTHON
%typemap(varout, noblock=1) SWIGTYPE & {
%set_varoutput(SWIG_NewPointerObj(%as_voidptr(&$1()), $descriptor, %newpointer_flags));
}
%rename("%(undercase)s", notregexmatch$name="^[A-Z0-9_]+$") "";
#endif
#if SWIGCSHARP || SWIGPYTHON
%constattrib( Leap::Pointable, int, id );
%leapattrib( Leap::Pointable, Hand, hand );
%leapattrib( Leap::Pointable, Vector, tipPosition );
%leapattrib( Leap::Pointable, Vector, tipVelocity );
%leapattrib( Leap::Pointable, Vector, direction );
%constattrib( Leap::Pointable, float, width );
%constattrib( Leap::Pointable, float, length );
%constattrib( Leap::Pointable, bool, isTool );
%constattrib( Leap::Pointable, bool, isFinger );
%constattrib( Leap::Pointable, bool, isExtended );
%constattrib( Leap::Pointable, bool, isValid );
%constattrib( Leap::Pointable, Leap::Pointable::Zone, touchZone )
%constattrib( Leap::Pointable, float, touchDistance )
%leapattrib( Leap::Pointable, Vector, stabilizedTipPosition )
%constattrib( Leap::Pointable, float, timeVisible );
%leapattrib( Leap::Pointable, Frame, frame );
%leapattrib( Leap::Bone, Vector, prevJoint );
%leapattrib( Leap::Bone, Vector, nextJoint );
%leapattrib( Leap::Bone, Vector, center );
%leapattrib( Leap::Bone, Vector, direction );
%constattrib( Leap::Bone, float, length );
%constattrib( Leap::Bone, float, width );
%constattrib( Leap::Bone, Leap::Bone::Type, type )
%leapattrib( Leap::Bone, Matrix, basis )
%constattrib( Leap::Bone, bool, isValid );
%constattrib( Leap::Hand, int, id );
%leapattrib( Leap::Hand, PointableList, pointables );
%leapattrib( Leap::Hand, FingerList, fingers );
%leapattrib( Leap::Hand, ToolList, tools );
%leapattrib( Leap::Hand, Vector, palmPosition );
%leapattrib( Leap::Hand, Vector, palmVelocity );
%leapattrib( Leap::Hand, Vector, palmNormal );
%leapattrib( Leap::Hand, Vector, direction );
%leapattrib( Leap::Hand, Matrix, basis )
%constattrib( Leap::Hand, bool, isValid );
%leapattrib( Leap::Hand, Vector, sphereCenter );
%constattrib( Leap::Hand, float, sphereRadius );
%constattrib( Leap::Hand, float, grabStrength );
%constattrib( Leap::Hand, float, pinchStrength );
%constattrib( Leap::Hand, float, palmWidth );
%leapattrib( Leap::Hand, Vector, stabilizedPalmPosition )
%constattrib( Leap::Hand, float, timeVisible );
%constattrib( Leap::Hand, float, confidence );
%constattrib( Leap::Hand, bool, isLeft );
%constattrib( Leap::Hand, bool, isRight );
%leapattrib( Leap::Hand, Frame, frame );
%constattrib( Leap::Gesture, Leap::Gesture::Type, type )
%constattrib( Leap::Gesture, Leap::Gesture::State, state )
%constattrib( Leap::Gesture, int32_t, id );
%constattrib( Leap::Gesture, int64_t, duration );
%constattrib( Leap::Gesture, float, durationSeconds );
%leapattrib( Leap::Gesture, Frame, frame );
%leapattrib( Leap::Gesture, HandList, hands );
%leapattrib( Leap::Gesture, PointableList, pointables );
%constattrib( Leap::Gesture, bool, isValid );
%leapattrib( Leap::CircleGesture, Vector, center );
%leapattrib( Leap::CircleGesture, Vector, normal );
%constattrib( Leap::CircleGesture, float, progress );
%constattrib( Leap::CircleGesture, float, radius );
%leapattrib( Leap::CircleGesture, Pointable, pointable );
%leapattrib( Leap::SwipeGesture, Vector, startPosition );
%leapattrib( Leap::SwipeGesture, Vector, position );
%leapattrib( Leap::SwipeGesture, Vector, direction );
%constattrib( Leap::SwipeGesture, float, speed );
%leapattrib( Leap::SwipeGesture, Pointable, pointable );
%leapattrib( Leap::ScreenTapGesture, Vector, position );
%leapattrib( Leap::ScreenTapGesture, Vector, direction );
%constattrib( Leap::ScreenTapGesture, float, progress );
%leapattrib( Leap::ScreenTapGesture, Pointable, pointable );
%leapattrib( Leap::KeyTapGesture, Vector, position );
%leapattrib( Leap::KeyTapGesture, Vector, direction );
%constattrib( Leap::KeyTapGesture, float, progress );
%leapattrib( Leap::KeyTapGesture, Pointable, pointable );
# Count is made a const attribute in C# but renamed to __len__ in Python
#if SWIGCSHARP
%constattrib( Leap::PointableList, int, count );
%constattrib( Leap::FingerList, int, count );
%constattrib( Leap::ToolList, int, count );
%constattrib( Leap::HandList, int, count );
%constattrib( Leap::GestureList, int, count );
%constattrib( Leap::ScreenList, int, count );
%constattrib( Leap::DeviceList, int, count );
#endif
%constattrib( Leap::PointableList, bool, isEmpty );
%constattrib( Leap::FingerList, bool, isEmpty );
%constattrib( Leap::ToolList, bool, isEmpty );
%constattrib( Leap::HandList, bool, isEmpty );
%constattrib( Leap::GestureList, bool, isEmpty );
%constattrib( Leap::ScreenList, bool, isEmpty );
%constattrib( Leap::DeviceList, bool, isEmpty );
%leapattrib( Leap::PointableList, Pointable, leftmost );
%leapattrib( Leap::PointableList, Pointable, rightmost );
%leapattrib( Leap::PointableList, Pointable, frontmost );
%leapattrib( Leap::FingerList, Finger, leftmost );
%leapattrib( Leap::FingerList, Finger, rightmost );
%leapattrib( Leap::FingerList, Finger, frontmost );
%leapattrib( Leap::ToolList, Tool, leftmost );
%leapattrib( Leap::ToolList, Tool, rightmost );
%leapattrib( Leap::ToolList, Tool, frontmost );
%leapattrib( Leap::HandList, Hand, leftmost );
%leapattrib( Leap::HandList, Hand, rightmost );
%leapattrib( Leap::HandList, Hand, frontmost );
%constattrib( Leap::Frame, int64_t, id );
%constattrib( Leap::Frame, int64_t, timestamp );
%constattrib( Leap::Frame, float, currentFramesPerSecond );
%leapattrib( Leap::Frame, PointableList, pointables );
%leapattrib( Leap::Frame, FingerList, fingers );
%leapattrib( Leap::Frame, ToolList, tools );
%leapattrib( Leap::Frame, HandList, hands );
%constattrib( Leap::Frame, bool, isValid );
%leapattrib( Leap::Frame, InteractionBox, interactionBox );
%constattrib( Leap::Screen, int32_t, id );
%leapattrib( Leap::Screen, Vector, horizontalAxis );
%leapattrib( Leap::Screen, Vector, verticalAxis );
%leapattrib( Leap::Screen, Vector, bottomLeftCorner );
%constattrib( Leap::Screen, int, widthPixels );
%constattrib( Leap::Screen, int, heightPixels );
%constattrib( Leap::Screen, bool, isValid );
%constattrib( Leap::Device, float, horizontalViewAngle );
%constattrib( Leap::Device, float, verticalViewAngle );
%constattrib( Leap::Device, float, range );
%constattrib( Leap::Device, bool, isValid );
%constattrib( Leap::Device, bool, isEmbedded );
%constattrib( Leap::Device, bool, isStreaming );
%constattrib( Leap::Device, Leap::Device::Type, type );
%leapattrib( Leap::InteractionBox, Vector, center );
%constattrib( Leap::InteractionBox, float, width );
%constattrib( Leap::InteractionBox, float, height );
%constattrib( Leap::InteractionBox, float, depth );
%constattrib( Leap::InteractionBox, bool, isValid );
#if SWIGCSHARP
%csmethodmodifiers Leap::Finger::invalid "public new";
%csmethodmodifiers Leap::Tool::invalid "public new";
#endif
%staticattrib( Leap::Pointable, static const Pointable&, invalid);
%staticattrib( Leap::Finger, static const Finger&, invalid);
%staticattrib( Leap::Tool, static const Tool&, invalid);
%staticattrib( Leap::Bone, static const Bone&, invalid);
%staticattrib( Leap::Hand, static const Hand&, invalid);
%staticattrib( Leap::Gesture, static const Gesture&, invalid);
%staticattrib( Leap::Screen, static const Screen&, invalid );
%staticattrib( Leap::Device, static const Device&, invalid );
%staticattrib( Leap::InteractionBox, static const InteractionBox&, invalid );
%staticattrib( Leap::Frame, static const Frame&, invalid);
%constattrib( Leap::Vector, float, magnitude );
%constattrib( Leap::Vector, float, magnitudeSquared );
%constattrib( Leap::Vector, float, pitch );
%constattrib( Leap::Vector, float, roll );
%constattrib( Leap::Vector, float, yaw );
%leapattrib( Leap::Vector, Vector, normalized );
%constattrib( Leap::Controller, bool, isConnected );
%constattrib( Leap::Controller, bool, hasFocus );
%constattrib( Leap::Controller, Controller::PolicyFlag, policyFlags );
%leapattrib( Leap::Controller, Config, config );
%leapattrib( Leap::Controller, ScreenList, locatedScreens );
%leapattrib( Leap::Controller, DeviceList, devices );
%staticattrib( Leap::Vector, static const Vector&, zero );
%staticattrib( Leap::Vector, static const Vector&, xAxis );
%staticattrib( Leap::Vector, static const Vector&, yAxis );
%staticattrib( Leap::Vector, static const Vector&, zAxis );
%staticattrib( Leap::Vector, static const Vector&, forward );
%staticattrib( Leap::Vector, static const Vector&, backward );
%staticattrib( Leap::Vector, static const Vector&, left );
%staticattrib( Leap::Vector, static const Vector&, right );
%staticattrib( Leap::Vector, static const Vector&, up );
%staticattrib( Leap::Vector, static const Vector&, down );
%staticattrib( Leap::Matrix, static const Matrix&, identity );
#endif
#if SWIGCSHARP
%rename("%(lowercamelcase)s", %$isvariable) "";
%ignore Leap::DEG_TO_RAD;
%ignore Leap::RAD_TO_DEG;
%ignore Leap::PI;
SWIG_CSBODY_PROXY(public, public, SWIGTYPE)
#elif SWIGPYTHON
%rename("%(camelcase)s", %$isclass) "";
%rename("%(camelcase)s", %$isconstructor) "";
#elif SWIGJAVA
%ignore Leap::DEG_TO_RAD;
%ignore Leap::RAD_TO_DEG;
%ignore Leap::PI;
# Use proper Java enums
%include "enums.swg"
%javaconst(1);
SWIG_JAVABODY_PROXY(public, public, SWIGTYPE)
#endif
# Ignore C++ streaming operator
%ignore operator<<;
# Ignore C++ equal operator
%ignore operator=;
#if SWIGPYTHON
%begin %{
#if defined(_WIN32) && defined(_DEBUG)
// Workaround for obscure STL template error
#include <vector>
// Workaround for non-existent Python debug library
#define _TMP_DEBUG _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG _TMP_DEBUG
#undef _TMP_DEBUG
#endif
#if defined(__APPLE__)
#pragma GCC diagnostic ignored "-Wself-assign"
#endif
%}
#endif
#if SWIGCSHARP || SWIGJAVA
%begin %{
#if defined(_WIN32)
#include <windows.h>
// When dynamically loading the Leap C# DLL, set the DLL search path to look in
// the same the directory. This will allow loading the Leap.dll. Create the
// Leap C# DLL with the /DELAYLOAD:Leap.dll link option.
extern "C" BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved)
{
if (lpvReserved == 0) {
static TCHAR lpPrevPathName[1024];
static BOOL restore = FALSE;
if (fdwReason == DLL_PROCESS_ATTACH) {
TCHAR lpPathName[1024];
int len;
len = GetDllDirectory(static_cast<DWORD>(sizeof(lpPrevPathName) - 1),
lpPrevPathName);
if (len < 0 && len >= sizeof(lpPrevPathName)) {
len = 0;
}
lpPrevPathName[len] = '\0';
len = static_cast<int>(GetModuleFileName(static_cast<HMODULE>(hinstDLL),
lpPathName, static_cast<DWORD>(sizeof(lpPathName))));
if (len > 0 && len < sizeof(lpPathName)) {
for (int i = len; i >= 0; i--) {
if (lpPathName[i] == '\\' || lpPathName[i] == '/') {
lpPathName[i] = '\0';
restore = SetDllDirectory(lpPathName);
break;
}
}
}
} else if (fdwReason == DLL_PROCESS_DETACH) {
if (restore && lpPrevPathName[0] != '\0') {
SetDllDirectory(lpPrevPathName);
restore = FALSE;
}
}
}
return TRUE;
}
#endif
%}
#endif
%typemap(csin, pre=" lock(arg0) {", post=" $csinput.Dispose();\n }") const Leap::Controller& "Controller.getCPtr($csinput)"
%header %{
#define SWIG
#include "Leap.h"
%}
%feature("director") Leap::Listener;
#if SWIGPYTHON
%feature("director:except") {
if ($error != NULL) {
PyErr_Print();
}
}
#endif
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("LeapJava");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
################################################################################
# Operator overloading #
################################################################################
#if SWIGCSHARP
%ignore *::operator+=;
%ignore *::operator-=;
%ignore *::operator*=;
%ignore *::operator/=;
%ignore *::operator!=;
%ignore Leap::Vector::toFloatPointer;
%ignore Leap::Matrix::toArray3x3;
%ignore Leap::Matrix::toArray4x4;
%ignore Leap::FloatArray;
%rename(Equals) *::operator ==;
%rename(_operator_add) *::operator +;
%rename(_operator_sub) *::operator -;
%rename(_operator_mul) *::operator *;
%rename(_operator_div) *::operator /;
%rename(_operator_get) *::operator [];
%rename(_operator_to_float) *::operator const float*;
%csmethodmodifiers *::operator + "private";
%csmethodmodifiers *::operator - "private";
%csmethodmodifiers *::operator * "private";
%csmethodmodifiers *::operator / "private";
%csmethodmodifiers *::operator [] "private";
%csmethodmodifiers *::operator const float* "private";
%typemap(cscode) Leap::Vector
%{
/** Add vectors component-wise. */
public static Vector operator + (Vector v1, Vector v2) {
return v1._operator_add(v2);
}
/** Subtract vectors component-wise. */
public static Vector operator - (Vector v1, Vector v2) {
return v1._operator_sub(v2);
}
/** Multiply vector by a scalar. */
public static Vector operator * (Vector v1, float scalar) {
return v1._operator_mul(scalar);
}
/** Multiply vector by a scalar on the left-hand side. */
public static Vector operator * (float scalar, Vector v1) {
return v1._operator_mul(scalar);
}
/** Divide vector by a scalar. */
public static Vector operator / (Vector v1, float scalar) {
return v1._operator_div(scalar);
}
/** Negate a vector. */
public static Vector operator - (Vector v1) {
return v1._operator_sub();
}
/** Convert this vector to an array of three float values: [x,y,z]. */
public float[] ToFloatArray() {
return new float[] {x, y, z};
}
%}
%typemap(cscode) Leap::Matrix
%{
/** Multiply two matrices. */
public static Matrix operator * (Matrix m1, Matrix m2) {
return m1._operator_mul(m2);
}
/** Copy this matrix to the specified array of 9 float values in row-major order. */
public float[] ToArray3x3(float[] output) {
output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z;
output[3] = yBasis.x; output[4] = yBasis.y; output[5] = yBasis.z;
output[6] = zBasis.x; output[7] = zBasis.y; output[8] = zBasis.z;
return output;
}
/** Copy this matrix to the specified array containing 9 double values in row-major order. */
public double[] ToArray3x3(double[] output) {
output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z;
output[3] = yBasis.x; output[4] = yBasis.y; output[5] = yBasis.z;
output[6] = zBasis.x; output[7] = zBasis.y; output[8] = zBasis.z;
return output;
}
/** Convert this matrix to an array containing 9 float values in row-major order. */
public float[] ToArray3x3() {
return ToArray3x3(new float[9]);
}
/** Copy this matrix to the specified array of 16 float values in row-major order. */
public float[] ToArray4x4(float[] output) {
output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; output[3] = 0.0f;
output[4] = yBasis.x; output[5] = yBasis.y; output[6] = yBasis.z; output[7] = 0.0f;
output[8] = zBasis.x; output[9] = zBasis.y; output[10] = zBasis.z; output[11] = 0.0f;
output[12] = origin.x; output[13] = origin.y; output[14] = origin.z; output[15] = 1.0f;
return output;
}
/** Copy this matrix to the specified array of 16 double values in row-major order. */
public double[] ToArray4x4(double[] output) {
output[0] = xBasis.x; output[1] = xBasis.y; output[2] = xBasis.z; output[3] = 0.0f;
output[4] = yBasis.x; output[5] = yBasis.y; output[6] = yBasis.z; output[7] = 0.0f;
output[8] = zBasis.x; output[9] = zBasis.y; output[10] = zBasis.z; output[11] = 0.0f;
output[12] = origin.x; output[13] = origin.y; output[14] = origin.z; output[15] = 1.0f;
return output;
}
/** Convert this matrix to an array containing 16 float values in row-major order. */
public float[] ToArray4x4() {
return ToArray4x4(new float[16]);
}
%}
#elif SWIGJAVA
%ignore *::operator+=;
%ignore *::operator-=;
%ignore *::operator*=;
%ignore *::operator/=;
%ignore *::operator!=;
%ignore Leap::Vector::toFloatPointer;
%ignore Leap::Matrix::toArray3x3;
%ignore Leap::Matrix::toArray4x4;
%ignore Leap::FloatArray;
%rename(plus) *::operator+;
%rename(minus) *::operator-;
%rename(opposite) *::operator-() const;
%rename(times) *::operator*;
%rename(divide) *::operator/;
%rename(get) *::operator [];
%rename(equals) *::operator==;
%typemap(javacode) Leap::Vector
%{
public float[] toFloatArray() {
return new float[] {getX(), getY(), getZ()};
}
%}
%typemap(javacode) Leap::Matrix
%{
public float[] toArray3x3(float[] output) {
output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ();
output[3] = getYBasis().getX(); output[4] = getYBasis().getY(); output[5] = getYBasis().getZ();
output[6] = getZBasis().getX(); output[7] = getZBasis().getY(); output[8] = getZBasis().getZ();
return output;
}
public double[] toArray3x3(double[] output) {
output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ();
output[3] = getYBasis().getX(); output[4] = getYBasis().getY(); output[5] = getYBasis().getZ();
output[6] = getZBasis().getX(); output[7] = getZBasis().getY(); output[8] = getZBasis().getZ();
return output;
}
public float[] toArray3x3() {
return toArray3x3(new float[9]);
}
public float[] toArray4x4(float[] output) {
output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); output[3] = 0.0f;
output[4] = getYBasis().getX(); output[5] = getYBasis().getY(); output[6] = getYBasis().getZ(); output[7] = 0.0f;
output[8] = getZBasis().getX(); output[9] = getZBasis().getY(); output[10] = getZBasis().getZ(); output[11] = 0.0f;
output[12] = getOrigin().getX(); output[13] = getOrigin().getY(); output[14] = getOrigin().getZ(); output[15] = 1.0f;
return output;
}
public double[] toArray4x4(double[] output) {
output[0] = getXBasis().getX(); output[1] = getXBasis().getY(); output[2] = getXBasis().getZ(); output[3] = 0.0f;
output[4] = getYBasis().getX(); output[5] = getYBasis().getY(); output[6] = getYBasis().getZ(); output[7] = 0.0f;
output[8] = getZBasis().getX(); output[9] = getZBasis().getY(); output[10] = getZBasis().getZ(); output[11] = 0.0f;
output[12] = getOrigin().getX(); output[13] = getOrigin().getY(); output[14] = getOrigin().getZ(); output[15] = 1.0f;
return output;
}
public float[] toArray4x4() {
return toArray4x4(new float[16]);
}
%}
#elif SWIGPYTHON
%ignore Leap::Interface::operator=;
%ignore Leap::ConstListIterator::operator++;
%ignore Leap::Vector::toFloatPointer;
%ignore Leap::Matrix::toArray3x3;
%ignore Leap::Matrix::toArray4x4;
%ignore Leap::FloatArray;
%rename(__getitem__) *::operator [];
%extend Leap::Vector {
%pythoncode {
def to_float_array(self): return [self.x, self.y, self.z]
def to_tuple(self): return (self.x, self.y, self.z)
%}}
%extend Leap::Matrix {
%pythoncode {
def to_array_3x3(self, output = None):
if output is None:
output = [0]*9
output[0], output[1], output[2] = self.x_basis.x, self.x_basis.y, self.x_basis.z
output[3], output[4], output[5] = self.y_basis.x, self.y_basis.y, self.y_basis.z
output[6], output[7], output[8] = self.z_basis.x, self.z_basis.y, self.z_basis.z
return output
def to_array_4x4(self, output = None):
if output is None:
output = [0]*16
output[0], output[1], output[2], output[3] = self.x_basis.x, self.x_basis.y, self.x_basis.z, 0.0
output[4], output[5], output[6], output[7] = self.y_basis.x, self.y_basis.y, self.y_basis.z, 0.0
output[8], output[9], output[10], output[11] = self.z_basis.x, self.z_basis.y, self.z_basis.z, 0.0
output[12], output[13], output[14], output[15] = self.origin.x, self.origin.y, self.origin.z, 1.0
return output
%}}
#endif
################################################################################
# List Helpers #
################################################################################
#if SWIGCSHARP
%define %leap_iterator_helper(BaseType)
%typemap(csinterfaces_derived) Leap::BaseType##List "System.Collections.Generic.IEnumerable<BaseType>"
%typemap(cscode) Leap::BaseType##List
%{
private class BaseType##List##Enumerator : System.Collections.Generic.IEnumerator<BaseType> {
private BaseType##List _list;
private int _index;
public BaseType##List##Enumerator(BaseType##List list) {
_list = list;
_index = -1;
}
public void Reset() {
_index = -1;
}
public BaseType Current {
get {
return _list._operator_get(_index);
}
}
object System.Collections.IEnumerator.Current {
get {
return this.Current;
}
}
public bool MoveNext() {
_index++;
return (_index < _list.Count);
}
public void Dispose() {
//No cleanup needed
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public System.Collections.Generic.IEnumerator<BaseType> GetEnumerator() {
return new BaseType##List##Enumerator(this);
}
public BaseType this[int index] {
get { return _operator_get(index); }
}
%}
%enddef
#elif SWIGJAVA
%define %leap_iterator_helper(BaseType)
%typemap(javainterfaces) Leap::BaseType##List "Iterable<BaseType>"
%typemap(javacode) Leap::BaseType##List
%{
public class BaseType##ListIterator implements java.util.Iterator<BaseType> {
int index = 0;
@Override public boolean hasNext() {
return index < count();
}
@Override public BaseType next() {
return get(index++);
}
@Override public void remove() {
}
}
@Override public java.util.Iterator<BaseType> iterator() {
return new BaseType##ListIterator();
}
%}
%enddef
#elif SWIGPYTHON
%define %leap_iterator_helper(BaseType)
%rename(__len__) Leap::BaseType##List::count;
%extend Leap::BaseType##List {
%pythoncode {
def __iter__(self):
_pos = 0
while _pos < len(self):
yield self[_pos]
_pos += 1
%}}
%enddef
#else
%define %leap_iterator_helper(BaseType)
%enddef
#endif
%define %leap_list_helper(BaseType)
%ignore Leap::BaseType##List::BaseType##List(const ListBaseImplementation<BaseType>&);
%ignore Leap::BaseType##List::const_iterator;
%ignore Leap::BaseType##List::begin() const;
%ignore Leap::BaseType##List::end() const;
%leap_iterator_helper(BaseType)
%enddef
%leap_list_helper(Pointable);
%leap_list_helper(Finger);
%leap_list_helper(Tool);
%leap_list_helper(Gesture);
%leap_list_helper(Hand);
%leap_list_helper(Screen);
%leap_list_helper(Device);
################################################################################
# Config Helpers #
################################################################################
#if SWIGPYTHON
// Use dynamic typing to get or set any type of config value with one function
%extend Leap::Config {
%pythoncode {
def get(self, *args):
type = LeapPython.Config_type(self, *args)
if type == LeapPython.Config_TYPE_BOOLEAN:
return LeapPython.Config_get_bool(self, *args)
elif type == LeapPython.Config_TYPE_INT32:
return LeapPython.Config_get_int_32(self, *args)
elif type == LeapPython.Config_TYPE_FLOAT:
return LeapPython.Config_get_float(self, *args)
elif type == LeapPython.Config_TYPE_STRING:
return LeapPython.Config_get_string(self, *args)
return None
def set(self, *args):
type = LeapPython.Config_type(self, *args[:-1]) # Do not pass value through
if type == LeapPython.Config_TYPE_BOOLEAN:
return LeapPython.Config_set_bool(self, *args)
elif type == LeapPython.Config_TYPE_INT32:
return LeapPython.Config_set_int_32(self, *args)
elif type == LeapPython.Config_TYPE_FLOAT:
return LeapPython.Config_set_float(self, *args)
elif type == LeapPython.Config_TYPE_STRING:
return LeapPython.Config_set_string(self, *args)
return False
%}}
// Ignore methods that are unnecessary due to get and set functions defined above
%feature("shadow") Leap::Config::type(const std::string& key) const %{%}
%feature("shadow") Leap::Config::getBool(const std::string& key) const %{%}
%feature("shadow") Leap::Config::setBool(const std::string& key, bool value) %{%}
%feature("shadow") Leap::Config::getInt32(const std::string& key) const %{%}
%feature("shadow") Leap::Config::setInt32(const std::string& key, int32_t value) %{%}
%feature("shadow") Leap::Config::getFloat(const std::string& key) const %{%}
%feature("shadow") Leap::Config::setFloat(const std::string& key, float value) %{%}
%feature("shadow") Leap::Config::getString(const std::string& key) const %{%}
%feature("shadow") Leap::Config::setString(const std::string& key, const std::string& value) %{%}
#endif
################################################################################
# ToString methods #
################################################################################
#if SWIGCSHARP
%csmethodmodifiers *::toString "public override";
#elif SWIGJAVA
%javamethodmodifiers *::toString "@Override public";
#elif SWIGPYTHON
%rename(__str__) *::toString;
#endif
%include "LeapMath.h"
%include "Leap.h"

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -86,6 +86,8 @@
#include "ui/Stats.h"
#include "ui/TextRenderer.h"
#include "devices/Leapmotion.h"
using namespace std;
// Starfield information
@ -1653,6 +1655,10 @@ void Application::init() {
_faceplus.init();
_visage.init();
Leapmotion* leap = new Leapmotion();
int index = DeviceTracker::registerDevice( "Leapmotion", leap );
// _leapmotion.init();
// fire off an immediate domain-server check in now that settings are loaded
NodeList::getInstance()->sendDomainServerCheckIn();
@ -1990,6 +1996,9 @@ void Application::update(float deltaTime) {
updateLOD();
updateMouseRay(); // check what's under the mouse and update the mouse voxel
DeviceTracker::updateAll();
updateFaceshift();
updateVisage();
@ -2003,6 +2012,7 @@ void Application::update(float deltaTime) {
_sixenseManager.update(deltaTime);
_joystickManager.update();
_prioVR.update(deltaTime);
}
{
@ -2010,6 +2020,10 @@ void Application::update(float deltaTime) {
updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
}
// Dispatch input events
_controllerScriptingInterface.updateInputControllers();
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
{
@ -3104,6 +3118,7 @@ void Application::resetSensors() {
}
_prioVR.reset();
//_leapmotion.reset();
QCursor::setPos(_mouseX, _mouseY);
_myAvatar->reset();

View file

@ -286,6 +286,35 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
-MAX_LEAN, MAX_LEAN));
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
-MAX_LEAN, MAX_LEAN));
// Hand Tracker ?
{
/* HandTracker* tracker = Application::getInstance()->getActiveHandTracker();
if (tracker) {
Hand* hand = getHand();
if ( hand ) {
int numPalms = hand->getNumPalms();
numPalms = (numPalms < 2 ? numPalms: 2 ); // stick to 2 palms for now
for ( int palmNum = 0; palmNum < numPalms; palmNum++ ) {
PalmData* palmData = &(hand->getPalms()[ palmNum ]);
int handSide = HandTracker::SIDE_LEFT + palmNum;
if ( tracker->isPalmActive( HandTracker::Side( handSide ) ) ) {
palmData->setRawPosition( tracker->getPalmTranslation( HandTracker::Side( handSide ) ) );
palmData->setRawRotation( tracker->getPalmRotation( HandTracker::Side( handSide ) ) );
palmData->setActive( true );
palmData->setSixenseID( ( (handSide == HandTracker::SIDE_LEFT) ? LEFT_HAND_INDEX : RIGHT_HAND_INDEX ) );
} else {
palmData->setActive( false );
palmData->setSixenseID( -1 );
}
}
}
}
*/
}
}
void MyAvatar::moveWithLean() {

View file

@ -66,7 +66,7 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
const float HAND_RESTORATION_RATE = 0.25f;
if (leftPalmIndex == -1) {
if ( (leftPalmIndex == -1) && ( rightPalmIndex == -1) ) { // NO palm active
// palms are not yet set, use mouse
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
@ -77,10 +77,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
}
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else if (leftPalmIndex == rightPalmIndex) {
} else if ( (leftPalmIndex == -1) && ( rightPalmIndex != -1)) { // Just right hand active
// right hand only
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else if ( (leftPalmIndex != -1) && ( rightPalmIndex == -1) ) { // Just left hand active
// right hand only
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]);
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else {
applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);

View file

@ -0,0 +1,91 @@
//
// DeviceTracker.cpp
// interface/src/devices
//
// Created by Sam Cake on 6/20/14.
// Copyright 2014 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 "DeviceTracker.h"
// The singleton managing the connected devices
DeviceTracker::Singleton DeviceTracker::Singleton::_singleton;
int DeviceTracker::init()
{
return Singleton::get()->_devicesMap.size();
}
int DeviceTracker::getNumDevices()
{
return Singleton::get()->_devicesMap.size();
}
int DeviceTracker::getDeviceIndex( const Name& name )
{
auto deviceIt = Singleton::get()->_devicesMap.find( name );
if ( deviceIt != Singleton::get()->_devicesMap.end() )
return (*deviceIt).second;
else
return -1;
}
DeviceTracker* DeviceTracker::getDevice( const Name& name )
{
return getDevice( getDeviceIndex( name ) );
}
DeviceTracker* DeviceTracker::getDevice( int deviceNum )
{
if ( (deviceNum >= 0) && ( deviceNum < Singleton::get()->_devicesVector.size() ) ) {
return Singleton::get()->_devicesVector[ deviceNum ];
} else {
return NULL;
}
}
int DeviceTracker::registerDevice( const Name& name, DeviceTracker* device )
{
if ( !device )
return -1;
int index = getDeviceIndex( name );
if ( index >= 0 ) {
// early exit because device name already taken
return -2;
} else {
index = Singleton::get()->_devicesVector.size();
Singleton::get()->_devicesMap.insert( SingletonData::Map::value_type( name, index ) );
Singleton::get()->_devicesVector.push_back( device );
return index;
}
}
void DeviceTracker::updateAll()
{
for ( auto deviceIt = Singleton::get()->_devicesVector.begin(); deviceIt != Singleton::get()->_devicesVector.end(); deviceIt++ ) {
if ( (*deviceIt) )
(*deviceIt)->update();
}
}
// Core features of the Device Tracker
DeviceTracker::DeviceTracker()
{
}
DeviceTracker::~DeviceTracker()
{
}
bool DeviceTracker::isConnected() const
{
return false;
}
void DeviceTracker::update()
{
}

View file

@ -0,0 +1,91 @@
//
// DeviceTracker.h
// interface/src/devices
//
// Created by Sam Cake on 6/20/14.
// Copyright 2014 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_DeviceTracker_h
#define hifi_DeviceTracker_h
#include <QObject>
#include <QVector>
//--------------------------------------------------------------------------------------
// Singleton template class
//--------------------------------------------------------------------------------------
template < class T >
class TemplateSingleton
{
static TemplateSingleton< T > _singleton;
T* _one;
public:
static T* get()
{
if ( !_singleton._one ) {
_singleton._one = new T();
}
return _singleton._one;
}
TemplateSingleton() :
_one(0)
{
}
~TemplateSingleton()
{
if ( _one ) {
delete _one;
_one = 0;
}
}
};
/// Base class for device trackers.
class DeviceTracker : public QObject {
Q_OBJECT
public:
typedef std::string Name;
typedef qint64 Stamp;
// Singleton interface to register and query the Devices currently connected
static int init();
static int getNumDevices();
static int getDeviceIndex( const Name& name );
static DeviceTracker* getDevice( int deviceNum );
static DeviceTracker* getDevice( const Name& name );
/// Update all the devices calling for their update() function
static void updateAll();
static int registerDevice( const Name& name, DeviceTracker* tracker );
// DeviceTracker interface
virtual bool isConnected() const;
virtual void update();
protected:
DeviceTracker();
virtual ~DeviceTracker();
private:
struct SingletonData
{
typedef std::map< Name, int > Map;
typedef std::vector< DeviceTracker* > Vector;
Map _devicesMap;
Vector _devicesVector;
};
typedef TemplateSingleton< SingletonData > Singleton;
};
#endif // hifi_DeviceTracker_h

View file

@ -0,0 +1,16 @@
//
// HandTracker.cpp
// interface/src/devices
//
// Created by Sam Cake on 6/10/14.
// Copyright 2014 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 "HandTracker.h"
HandTracker::HandTracker() {
}

View file

@ -0,0 +1,58 @@
//
// HandTracker.h
// interface/src/devices
//
// Created by Sam Cake on 6/10/14.
// Copyright 2014 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_HandTracker_h
#define hifi_HandTracker_h
#include <QObject>
#include <QVector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
/// Base class for face trackers (Faceshift, Visage, Faceplus).
class HandTracker {
public:
struct PalmData
{
glm::vec3 _translation;
glm::quat _rotation;
int _lastUpdate;
PalmData() :
_translation(),
_rotation(),
_lastUpdate(0)
{}
};
enum Side
{
SIDE_LEFT =0,
SIDE_RIGHT,
SIDE_NUMSIDES, // Not a valid Side, the number of sides
};
HandTracker();
const glm::vec3& getPalmTranslation(Side side) const { return _palms[side]._translation; }
const glm::quat& getPalmRotation(Side side) const { return _palms[side]._rotation; }
bool isPalmActive(Side side) const { return _palms[side]._lastUpdate == 0; }
protected:
PalmData _palms[SIDE_NUMSIDES];
};
#endif // hifi_HandTracker_h

View file

@ -1,5 +1,5 @@
//
// LeapMotionManager.cpp
// Leapmotion.cpp
// interface/src/devices
//
// Created by Sam Cake on 6/2/2014
@ -15,56 +15,56 @@
#include <FBXReader.h>
#include "Application.h"
#include "LeapMotionManager.h"
#include "Leapmotion.h"
#include "ui/TextRenderer.h"
#ifdef HAVE_LEAPMOTION
LeapMotionManager::SampleListener::SampleListener() : ::Leap::Listener()
Leapmotion::SampleListener::SampleListener() : ::Leap::Listener()
{
// std::cout << __FUNCTION__ << std::endl;
}
LeapMotionManager::SampleListener::~SampleListener()
Leapmotion::SampleListener::~SampleListener()
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onConnect(const ::Leap::Controller &)
void Leapmotion::SampleListener::onConnect(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onDisconnect(const ::Leap::Controller &)
void Leapmotion::SampleListener::onDisconnect(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onExit(const ::Leap::Controller &)
void Leapmotion::SampleListener::onExit(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onFocusGained(const ::Leap::Controller &)
void Leapmotion::SampleListener::onFocusGained(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onFocusLost(const ::Leap::Controller &)
void Leapmotion::SampleListener::onFocusLost(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onFrame(const ::Leap::Controller &)
void Leapmotion::SampleListener::onFrame(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onInit(const ::Leap::Controller &)
void Leapmotion::SampleListener::onInit(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onServiceConnect(const ::Leap::Controller &)
void Leapmotion::SampleListener::onServiceConnect(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
void LeapMotionManager::SampleListener::onServiceDisconnect(const ::Leap::Controller &)
void Leapmotion::SampleListener::onServiceDisconnect(const ::Leap::Controller &)
{
// std::cout << __FUNCTION__ << std::endl;
}
@ -177,55 +177,109 @@ const float LEAP_Y = 0.3f; // meters
const float LEAP_Z = 0.3f; // meters
#endif
LeapMotionManager::LeapMotionManager() {
const int FINGER_NUM_JOINTS = 4;
const int HAND_NUM_JOINTS = FINGER_NUM_JOINTS*5+1;
Leapmotion::Leapmotion() :
MotionTracker(),
_enabled(false),
_active(false)
{
#ifdef HAVE_LEAPMOTION
// Have the sample listener receive events from the controller
_controller.addListener(_listener);
// By default we assume the _neckBase (in orb frame) is as high above the orb
// as the "torso" is below it.
_leapBasePos = glm::vec3(0, -LEAP_Y, LEAP_Z);
glm::vec3 xAxis(1.f, 0.f, 0.f);
glm::vec3 yAxis(0.f, 1.f, 0.f);
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
_leapBaseOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
reset();
#endif
// Create the Leapmotion joint hierarchy
{
std::vector< Semantic > hands;
hands.push_back( "Left" );
hands.push_back( "Right" );
std::vector< Semantic > fingers;
fingers.push_back( "Thumb" );
fingers.push_back( "Index" );
fingers.push_back( "Middle" );
fingers.push_back( "Ring" );
fingers.push_back( "Pinky" );
std::vector< Semantic > fingerBones;
/* fingerBones.push_back( "Metacarpal" );
fingerBones.push_back( "Proximal" );
fingerBones.push_back( "Intermediate" );
fingerBones.push_back( "Distal" );
*/
fingerBones.push_back( "1" );
fingerBones.push_back( "2" );
fingerBones.push_back( "3" );
fingerBones.push_back( "4" );
std::vector< Index > palms;
for ( int h = 0; h < hands.size(); h++ ) {
Index rootJoint = addJoint( hands[h] + "Hand", 0 );
palms.push_back( rootJoint );
for ( int f = 0; f < fingers.size(); f++ ) {
for ( int b = 0; b < fingerBones.size(); b++ ) {
rootJoint = addJoint( hands[h] + "Hand" + fingers[f] + fingerBones[b], rootJoint );
}
}
}
}
}
LeapMotionManager::~LeapMotionManager() {
Leapmotion::~Leapmotion() {
#ifdef HAVE_LEAPMOTION
// Remove the sample listener when done
_controller.removeListener(_listener);
#endif
}
const int HEAD_ROTATION_INDEX = 0;
glm::vec3 LeapMotionManager::getHandPos( unsigned int handNb ) const
{
if ( handNb < _hands.size() )
{
return _hands[ handNb ];
}
else
return glm::vec3(0.f);
void Leapmotion::init() {
// connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled()));
updateEnabled();
}
void LeapMotionManager::update(float deltaTime) {
#ifdef HAVE_LEAPMOTION
glm::quat quatFromLeapBase( float sideSign, const Leap::Matrix& basis ) {
if ( !_controller.isConnected() )
glm::vec3 xAxis = glm::normalize( sideSign * glm::vec3( basis.xBasis.x, basis.xBasis.y, basis.xBasis.z) );
glm::vec3 yAxis = glm::normalize( glm::vec3( basis.yBasis.x, basis.yBasis.y, basis.yBasis.z) );
glm::vec3 zAxis = glm::normalize( glm::vec3( basis.zBasis.x, basis.zBasis.y, basis.zBasis.z) );
glm::quat orientation = /* glm::inverse*/ (glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
return orientation;
}
glm::vec3 vec3FromLeapVector( const Leap::Vector& vec ) {
return glm::vec3( vec.x * METERS_PER_MILLIMETER, vec.y * METERS_PER_MILLIMETER, vec.z * METERS_PER_MILLIMETER );
}
#endif
void Leapmotion::update() {
#ifdef HAVE_LEAPMOTION
_active = _controller.isConnected();
if (!_active) {
return;
}
// go through all the joints and increment their counter since last update
for ( auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++ ) {
(*jointIt).tickNewFrame();
}
float deltaTime = 0.001f;
// Get the most recent frame and report some basic information
const Leap::Frame frame = _controller.frame();
static _int64 lastFrame = -1;
_hands.clear();
_int64 newFrameNb = frame.id();
if ( (lastFrame >= newFrameNb) )
@ -233,135 +287,64 @@ void LeapMotionManager::update(float deltaTime) {
glm::vec3 delta(0.f);
glm::quat handOri;
if (!frame.hands().isEmpty())
{
// Get the first hand
const Leap::Hand hand = frame.hands()[0];
Leap::Vector lp = hand.palmPosition();
glm::vec3 p(lp.x * METERS_PER_MILLIMETER, lp.y * METERS_PER_MILLIMETER, lp.z * METERS_PER_MILLIMETER );
if ( !frame.hands().isEmpty() ) {
for ( int handNum = 0; handNum < frame.hands().count(); handNum++ ) {
// Get the first hand
const Leap::Hand hand = frame.hands()[handNum];
int side = ( hand.isRight() ? -1 : 1 );
Index handIndex = 1 + ((1 - side)/2) * HAND_NUM_JOINTS;
Leap::Vector n = hand.palmNormal();
glm::vec3 xAxis(n.x, n.y, n.z);
glm::vec3 yAxis(0.f, 1.f, 0.f);
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
handOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
glm::vec3 pos = vec3FromLeapVector(hand.palmPosition());
glm::quat ori = quatFromLeapBase(float(side), hand.basis() );
_hands.push_back( p );
JointTracker* palmJoint = editJointTracker( handIndex );
palmJoint->editLocFrame().setTranslation( pos );
palmJoint->editLocFrame().setRotation( ori );
palmJoint->editAbsFrame().setTranslation( pos );
palmJoint->editAbsFrame().setRotation( ori );
palmJoint->activeFrame();
// Transform the measured position into body frame.
glm::vec3 neck = _leapBasePos;
// Zeroing y component of the "neck" effectively raises the measured position a little bit.
//neck.y = 0.f;
pos = _leapBaseOri * (pos - neck);
//Leap::Vector dp = hand.translation( _controller.frame( lastFrame ) );
Leap::Vector dp = hand.palmVelocity();
delta = glm::vec3( dp.x * METERS_PER_MILLIMETER, dp.y * METERS_PER_MILLIMETER, dp.z * METERS_PER_MILLIMETER);
// Check if the hand has any fingers
const Leap::FingerList fingers = hand.fingers();
if (!fingers.isEmpty()) {
// For every fingers in the list
for (int i = 0; i < fingers.count(); ++i) {
// Reset the parent joint to the palmJoint for every finger traversal
JointTracker* parentJointTracker = palmJoint;
// surprisingly, Leap::Finger::Type start at 0 for thumb a until 4 for the pinky
Index fingerIndex = handIndex + 1 + Index(fingers[i].type()) * FINGER_NUM_JOINTS;
// let's update the finger's joints
for ( int b = 0; b < FINGER_NUM_JOINTS; b++ ) {
Leap::Bone::Type type = Leap::Bone::Type(b + Leap::Bone::TYPE_METACARPAL);
Leap::Bone bone = fingers[i].bone( type );
JointTracker* ljointTracker = editJointTracker( fingerIndex + b );
if ( bone.isValid() ) {
Leap::Vector bp = bone.nextJoint();
ljointTracker->editAbsFrame().setTranslation( vec3FromLeapVector( bp ) );
ljointTracker->editAbsFrame().setRotation(quatFromLeapBase( float(side), bone.basis() ) );
ljointTracker->updateLocFromAbsTransform( parentJointTracker );
ljointTracker->activeFrame();
}
parentJointTracker = ljointTracker;
}
}
}
}
}
lastFrame = newFrameNb;
MyAvatar* avatar = Application::getInstance()->getAvatar();
Hand* hand = avatar->getHand();
// for ( int h = 0; h < frame.hands().count(); h++ )
if ( _hands.size() )
{
// Set palm position and normal based on Hydra position/orientation
// Either find a palm matching the sixense controller, or make a new one
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == 28) {
palm = &(hand->getPalms()[j]);
foundHand = true;
}
}
if (!foundHand) {
PalmData newPalm(hand);
hand->getPalms().push_back(newPalm);
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
palm->setSixenseID(28);
qDebug("Found new LeapMotion hand, ID %i", 28);
}
palm->setActive(true);
// Read controller buttons and joystick into the hand
//palm->setControllerButtons(data->buttons);
//palm->setTrigger(data->trigger);
//palm->setJoystick(data->joystick_x, data->joystick_y);
glm::vec3 position(_hands[0]);
// Transform the measured position into body frame.
glm::vec3 neck = _leapBasePos;
// Zeroing y component of the "neck" effectively raises the measured position a little bit.
//neck.y = 0.f;
position = _leapBaseOri * (position - neck);
// Rotation of Palm
glm::quat rotation(handOri[3], -handOri[0], handOri[1], -handOri[2]);
rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _leapBaseOri * rotation;
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.f) {
// rawVelocity = (position - palm->getRawPosition()) / deltaTime;
rawVelocity = delta / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
palm->setRawVelocity(rawVelocity); // meters/sec
// Use a velocity sensitive filter to damp small motions and preserve large ones with
// no latency.
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
palm->setRawPosition(palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter));
palm->setRawRotation(safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter));
// use the velocity to determine whether there's any movement (if the hand isn't new)
/* const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f;
_amountMoved += rawVelocity * deltaTime;
if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) {
_lastMovement = usecTimestampNow();
_amountMoved = glm::vec3(0.0f);
}*/
// Store the one fingertip in the palm structure so we can track velocity
/* const float FINGER_LENGTH = 0.3f; // meters
const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH);
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
glm::vec3 oldTipPosition = palm->getTipRawPosition();
if (deltaTime > 0.f) {
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
} else {
palm->setTipVelocity(glm::vec3(0.f));
}
palm->setTipPosition(newTipPosition);*/
}
else
{
// Either find a palm matching the sixense controller, or make a new one
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == 28) {
palm = &(hand->getPalms()[j]);
foundHand = true;
}
}
if (foundHand) {
palm->setRawPosition(palm->getRawPosition());
palm->setRawRotation(palm->getRawRotation());
palm->setActive(false);
}
}
/* if (numActiveControllers == 2) {
updateCalibration(controllers);
}
*/
// }
if ( false )
{
@ -411,31 +394,29 @@ void LeapMotionManager::update(float deltaTime) {
#endif
}
void LeapMotionManager::reset() {
#ifdef HAVE_LEAPMOTION
if (!_controller.isConnected()) {
return;
}
/* connect(Application::getInstance(), SIGNAL(renderingOverlay()), SLOT(renderCalibrationCountdown()));
_calibrationCountdownStarted = QDateTime::currentDateTime();
*/
#endif
void Leapmotion::reset() {
// By default we assume the _neckBase (in orb frame) is as high above the orb
// as the "torso" is below it.
_leapBasePos = glm::vec3(0, -LEAP_Y, LEAP_Z);
glm::vec3 xAxis(1.f, 0.f, 0.f);
glm::vec3 yAxis(0.f, 1.f, 0.f);
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
_leapBaseOri = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
}
void LeapMotionManager::renderCalibrationCountdown() {
void Leapmotion::updateEnabled() {
/* setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Visage) &&
!Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) &&
!(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) &&
Application::getInstance()->getFaceshift()->isConnectedOrConnecting()));*/
}
void Leapmotion::setEnabled(bool enabled) {
#ifdef HAVE_LEAPMOTION
/* const int COUNTDOWN_SECONDS = 3;
int secondsRemaining = COUNTDOWN_SECONDS - _calibrationCountdownStarted.secsTo(QDateTime::currentDateTime());
if (secondsRemaining == 0) {
yei_tareSensors(_skeletalDevice);
Application::getInstance()->disconnect(this);
if (_enabled == enabled) {
return;
}
static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2);
QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "...";
textRenderer.draw((Application::getInstance()->getGLWidget()->width() - textRenderer.computeWidth(text.constData())) / 2,
Application::getInstance()->getGLWidget()->height() / 2,
text);
*/
#endif
#endif
}

View file

@ -1,5 +1,5 @@
//
// LeapMotionManager.h
// Leapmotion.h
// interface/src/devices
//
// Created by Sam Cake on 6/2/2014
@ -9,46 +9,37 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_LeapMotionManager_h
#define hifi_LeapMotionManager_h
#ifndef hifi_Leapmotion_h
#define hifi_Leapmotion_h
#include <QDateTime>
#include <QObject>
#include <QVector>
#include <glm/gtc/quaternion.hpp>
#include "HandTracker.h"
#include "MotionTracker.h"
#ifdef HAVE_LEAPMOTION
#include <Leap.h>
/*extern "C" {
#include <yei_skeletal_api.h>
}*/
#endif
/// Handles interaction with the LeapMotionManager skeleton tracking suit.
class LeapMotionManager : public QObject {
/// Handles interaction with the Leapmotion skeleton tracking suit.
class Leapmotion : public MotionTracker {
Q_OBJECT
public:
Leapmotion();
virtual ~Leapmotion();
void init();
bool isActive() const { return _active; }
LeapMotionManager();
virtual ~LeapMotionManager();
bool isActive() const { return !_hands.isEmpty(); }
int nbHands() const { return _hands.size(); }
glm::vec3 getHandPos( unsigned int handNb ) const;
const QVector<int>& getHumanIKJointIndices() const { return _humanIKJointIndices; }
const QVector<glm::quat>& getJointRotations() const { return _jointRotations; }
void update(float deltaTime);
void update();
void reset();
private slots:
public slots:
void renderCalibrationCountdown();
void updateEnabled();
private:
#ifdef HAVE_LEAPMOTION
@ -76,13 +67,11 @@ private:
#endif
glm::vec3 _leapBasePos;
glm::quat _leapBaseOri;
QVector<glm::vec3> _hands;
QVector<int> _humanIKJointIndices;
QVector<glm::quat> _jointRotations;
QVector<glm::quat> _lastJointRotations;
QDateTime _calibrationCountdownStarted;
void setEnabled(bool enabled);
bool _enabled;
bool _active;
};
#endif // hifi_LeapMotionManager_h
#endif // hifi_Leapmotion_h

View file

@ -0,0 +1,200 @@
//
// MotionTracker.cpp
// interface/src/devices
//
// Created by Sam Cake on 6/20/14.
// Copyright 2014 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 "MotionTracker.h"
//--------------------------------------------------------------------------------------
// glm::mult( mat43, mat43 ) just the composition of the 2 matrices assuming they are in fact mat44 with the last raw = { 0, 0, 0, 1 }
//--------------------------------------------------------------------------------------
namespace glm {
mat4x3 mult( const mat4& lhs, const mat4x3& rhs ) {
vec3 lrx( lhs[0].x, lhs[1].x, lhs[2].x );
vec3 lry( lhs[0].y, lhs[1].y, lhs[2].y );
vec3 lrz( lhs[0].z, lhs[1].z, lhs[2].z );
return mat4x3(
dot( lrx, rhs[0] ),
dot( lry, rhs[0] ),
dot( lrz, rhs[0] ),
dot( lrx, rhs[1] ),
dot( lry, rhs[1] ),
dot( lrz, rhs[1] ),
dot( lrx, rhs[2] ),
dot( lry, rhs[2] ),
dot( lrz, rhs[2] ),
dot( lrx, rhs[3] ) + lhs[3].x,
dot( lry, rhs[3] ) + lhs[3].y,
dot( lrz, rhs[3] ) + lhs[3].z
);
}
mat4x3 mult( const mat4x3& lhs, const mat4x3& rhs ) {
vec3 lrx( lhs[0].x, lhs[1].x, lhs[2].x );
vec3 lry( lhs[0].y, lhs[1].y, lhs[2].y );
vec3 lrz( lhs[0].z, lhs[1].z, lhs[2].z );
return mat4x3(
dot( lrx, rhs[0] ),
dot( lry, rhs[0] ),
dot( lrz, rhs[0] ),
dot( lrx, rhs[1] ),
dot( lry, rhs[1] ),
dot( lrz, rhs[1] ),
dot( lrx, rhs[2] ),
dot( lry, rhs[2] ),
dot( lrz, rhs[2] ),
dot( lrx, rhs[3] ) + lhs[3].x,
dot( lry, rhs[3] ) + lhs[3].y,
dot( lrz, rhs[3] ) + lhs[3].z
);
}
}
//--------------------------------------------------------------------------------------
// MotionTracker
//--------------------------------------------------------------------------------------
MotionTracker::MotionTracker() :
DeviceTracker()
{
_jointsArray.resize(1);
_jointsMap.insert( JointTracker::map::value_type( Semantic( "Root" ), 0 ) );
}
MotionTracker::~MotionTracker()
{
}
bool MotionTracker::isConnected() const
{
return false;
}
MotionTracker::Index MotionTracker::addJoint( const Semantic& semantic, Index parent )
{
// Check the parent
if ( int(parent) < 0 )
return INVALID_PARENT;
// Check that the semantic is not already in use
Index foundIndex = findJointIndex( semantic );
if ( int(foundIndex) >= 0 )
return INVALID_SEMANTIC;
// All good then allocate the joint
Index newIndex = _jointsArray.size();
_jointsArray.push_back( JointTracker( semantic, parent ) );
_jointsMap.insert( JointTracker::map::value_type( semantic, newIndex ) );
return newIndex;
}
MotionTracker::Index MotionTracker::findJointIndex( const Semantic& semantic ) const
{
auto jointIt = _jointsMap.find( semantic );
if ( jointIt != _jointsMap.end() )
return (*jointIt).second;
return INVALID_SEMANTIC;
}
void MotionTracker::updateAllAbsTransform()
{
_jointsArray[0].updateAbsFromLocTransform( 0 );
// Because we know the hierarchy is stored from root down the branches let's just traverse and update
for ( Index i = 1; i < _jointsArray.size(); i++ ) {
JointTracker* joint = _jointsArray.data() + i;
joint->updateAbsFromLocTransform( _jointsArray.data() + joint->getParent() );
}
}
//--------------------------------------------------------------------------------------
// MotionTracker::JointTracker
//--------------------------------------------------------------------------------------
MotionTracker::JointTracker::JointTracker() :
_locFrame(),
_absFrame(),
_semantic(""),
_parent(INVALID_PARENT),
_lastUpdate(0)
{
}
MotionTracker::JointTracker::JointTracker( const Semantic& semantic, Index parent ) :
_semantic( semantic ),
_parent( parent ),
_lastUpdate( 0 )
{
}
MotionTracker::JointTracker::JointTracker( const JointTracker& tracker ) :
_locFrame( tracker._locFrame ),
_absFrame( tracker._absFrame ),
_semantic( tracker._semantic ),
_parent( tracker._parent ),
_lastUpdate( tracker._lastUpdate )
{
}
void MotionTracker::JointTracker::updateAbsFromLocTransform(const JointTracker* parentJoint)
{
if ( parentJoint ) {
editAbsFrame()._transform = glm::mult( parentJoint->getAbsFrame()._transform, getLocFrame()._transform );
} else {
editAbsFrame()._transform = getLocFrame()._transform;
}
}
void MotionTracker::JointTracker::updateLocFromAbsTransform(const JointTracker* parentJoint)
{
if ( parentJoint ) {
glm::mat4 ip = glm::inverse( glm::mat4( parentJoint->getAbsFrame()._transform ) );
editLocFrame()._transform = glm::mult( ip, getAbsFrame()._transform );
} else {
editLocFrame()._transform = getAbsFrame()._transform;
}
}
//--------------------------------------------------------------------------------------
// MotionTracker::Frame
//--------------------------------------------------------------------------------------
MotionTracker::Frame::Frame() :
_transform()
{
}
void MotionTracker::Frame::setRotation( const glm::quat& rotation )
{
glm::mat3x3 rot = glm::mat3_cast( rotation );
_transform[0] = rot[0];
_transform[1] = rot[1];
_transform[2] = rot[2];
}
void MotionTracker::Frame::getRotation( glm::quat& rotation ) const
{
rotation = glm::quat_cast( glm::mat3( _transform[0], _transform[1], _transform[2] ) );
}
void MotionTracker::Frame::setTranslation( const glm::vec3& translation )
{
_transform[3] = translation;
}
void MotionTracker::Frame::getTranslation( glm::vec3& translation ) const
{
translation = _transform[3];
}

View file

@ -0,0 +1,130 @@
//
// MotionTracker.h
// interface/src/devices
//
// Created by Sam Cake on 6/20/14.
// Copyright 2014 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_MotionTracker_h
#define hifi_MotionTracker_h
#include "DeviceTracker.h"
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtc/matrix_transform.hpp>
/// Base class for device trackers.
class MotionTracker : public DeviceTracker {
Q_OBJECT
public:
class Frame
{
public:
Frame();
glm::mat4x3 _transform;
void setRotation( const glm::quat& rotation );
void getRotation( glm::quat& rotation ) const;
void setTranslation( const glm::vec3& translation );
void getTranslation( glm::vec3& translation ) const;
};
typedef std::string Semantic;
typedef unsigned int Index;
static const Index INVALID_SEMANTIC = -1;
static const Index INVALID_PARENT = -2;
class JointTracker
{
public:
typedef std::vector< JointTracker > vector;
typedef std::map< Semantic, Index > map;
JointTracker();
JointTracker( const JointTracker& tracker );
JointTracker( const Semantic& semantic, Index parent );
const Frame& getLocFrame() const { return _locFrame; }
Frame& editLocFrame() { return _locFrame; }
void setLocFrame( const Frame& frame ) { editLocFrame() = frame; }
const Frame& getAbsFrame() const { return _absFrame; }
Frame& editAbsFrame() { return _absFrame; }
void setAbsFrame( const Frame& frame ) { editAbsFrame() = frame; }
const Semantic& getSemantic() const { return _semantic; }
const Index& getParent() const { return _parent; }
bool isActive() const { return (_lastUpdate <= 0); }
void tickNewFrame() { _lastUpdate++; }
void activeFrame() { _lastUpdate = 0; }
/// Update the loc/abs transform for this joint from the current abs/loc value and the specified parent joint abs frame
void updateLocFromAbsTransform(const JointTracker* parentJoint);
void updateAbsFromLocTransform(const JointTracker* parentJoint);
protected:
Frame _locFrame;
Frame _absFrame;
Semantic _semantic;
Index _parent;
int _lastUpdate;
};
virtual bool isConnected() const;
Index numJointTrackers() const { return _jointsArray.size(); }
/// Access a Joint from it's index.
/// Index 0 is always the "Root".
/// if the index is Invalid then returns NULL.
const JointTracker* getJointTracker( Index index ) const { return ( int(index) < _jointsArray.size() ? _jointsArray.data() + index : NULL ); }
JointTracker* editJointTracker( Index index ) { return ( int(index) < _jointsArray.size() ? _jointsArray.data() + index : NULL ); }
/// From a semantic, find the Index of the Joint.
/// \return the index of the mapped Joint or INVALID_SEMANTIC if the semantic is not knowned.
Index findJointIndex( const Semantic& semantic ) const;
protected:
MotionTracker();
virtual ~MotionTracker();
JointTracker::vector _jointsArray;
JointTracker::map _jointsMap;
/// Adding joint is only done from the specialized Motion Tracker, hence this function is protected.
/// The hierarchy of joints must be created from the top down to the branches.
/// The "Root" node is at index 0 and exists at creation of the Motion Tracker.
///
/// \param semantic A joint is defined by it's semantic, the unique name mapping to it
/// \param parent The parent's index, the parent must be valid and correspond to a Joint that has been previously created
///
/// \return The Index of the newly created Joint.
/// Valid if everything went well.
/// INVALID_SEMANTIC if the semantic is already in use
/// INVALID_PARENT if the parent is not valid
Index addJoint( const Semantic& semantic, Index parent );
/// Update the absolute transform stack traversing the hierarchy from the root down the branches
/// This is a generic way to update all the Joint's absFrame by combining the locFrame going down the hierarchy branch.
void updateAllAbsTransform();
};
#endif // hifi_MotionTracker_h

View file

@ -13,6 +13,7 @@
#include "Application.h"
#include "devices/SixenseManager.h"
#include "ControllerScriptingInterface.h"
#include "devices/MotionTracker.h"
ControllerScriptingInterface::ControllerScriptingInterface() :
_mouseCaptured(false),
@ -258,3 +259,73 @@ glm::vec2 ControllerScriptingInterface::getViewportDimensions() const {
QGLWidget* widget = Application::getInstance()->getGLWidget();
return glm::vec2(widget->width(), widget->height());
}
AbstractInputController* ControllerScriptingInterface::createInputController( const QString& category, const QString& tracker )
{
// This is where we retreive the Device Tracker category and then the sub tracker within it
auto icIt = _inputControllers.find( 0 );
if ( icIt != _inputControllers.end() ) {
return (*icIt).second;
} else {
// Look for matching category
int categoryID = 0;
MotionTracker* motionTracker = dynamic_cast< MotionTracker* > ( DeviceTracker::getDevice( categoryID ) );
if ( motionTracker )
{
int trackerID = motionTracker->findJointIndex( tracker.toStdString() );
if ( trackerID > 0 )
{
AbstractInputController* inputController = new InputController(categoryID,trackerID, this );
_inputControllers.insert( InputControllerMap::value_type( inputController->getKey(), inputController ) );
return inputController;
}
}
return 0;
}
}
void ControllerScriptingInterface::updateInputControllers()
{
for ( auto it = _inputControllers.begin(); it != _inputControllers.end(); it++ ) {
(*it).second->update();
}
}
InputController::InputController(int deviceTrackerId, int subTrackerId, QObject* parent) :
AbstractInputController(),
_deviceTrackerId( deviceTrackerId ),
_subTrackerId( subTrackerId )
{
}
void InputController::update()
{
_isActive = false;
MotionTracker* motionTracker = dynamic_cast< MotionTracker*> ( DeviceTracker::getDevice( _deviceTrackerId ) );
if ( motionTracker ) {
if ( _subTrackerId < motionTracker->numJointTrackers() ) {
const MotionTracker::JointTracker* joint = motionTracker->getJointTracker( _subTrackerId );
if ( joint->isActive() ) {
joint->getAbsFrame().getTranslation( _eventCache.absTranslation );
joint->getAbsFrame().getRotation( _eventCache.absRotation );
joint->getLocFrame().getTranslation( _eventCache.locTranslation );
joint->getLocFrame().getRotation( _eventCache.locRotation );
_isActive = true;
emit spatialEvent(_eventCache);
}
}
}
}
InputController::Key InputController::getKey() const {
return (_deviceTrackerId * 10000) + _subTrackerId;
}

View file

@ -17,6 +17,38 @@
#include <AbstractControllerScriptingInterface.h>
class PalmData;
class InputController : public AbstractInputController {
Q_OBJECT
public:
InputController(int deviceTrackerId, int subTrackerId, QObject* parent = NULL);
virtual void update();
virtual Key getKey() const;
public slots:
virtual bool isActive() const { return _isActive; }
virtual glm::vec3 getAbsTranslation() const { return _eventCache.absTranslation; }
virtual glm::quat getAbsRotation() const { return _eventCache.absRotation; }
virtual glm::vec3 getLocTranslation() const { return _eventCache.locTranslation; }
virtual glm::quat getLocRotation() const { return _eventCache.locRotation; }
private:
int _deviceTrackerId;
int _subTrackerId;
// cache for the spatial
SpatialEvent _eventCache;
bool _isActive;
signals:
};
/// handles scripting of input controller commands from JS
class ControllerScriptingInterface : public AbstractControllerScriptingInterface {
Q_OBJECT
@ -43,6 +75,10 @@ public:
bool isWheelCaptured() const { return _wheelCaptured; }
bool isJoystickCaptured(int joystickIndex) const;
void updateInputControllers();
void releaseInputController( AbstractInputController* input );
public slots:
virtual bool isPrimaryButtonPressed() const;
virtual glm::vec2 getPrimaryJoystickPosition() const;
@ -78,6 +114,8 @@ public slots:
virtual glm::vec2 getViewportDimensions() const;
virtual AbstractInputController* createInputController( const QString& category, const QString& tracker );
private:
const PalmData* getPrimaryPalm() const;
const PalmData* getPalm(int palmIndex) const;
@ -89,6 +127,9 @@ private:
bool _wheelCaptured;
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;
typedef std::map< AbstractInputController::Key, AbstractInputController* > InputControllerMap;
InputControllerMap _inputControllers;
};
const int NUMBER_OF_SPATIALCONTROLS_PER_PALM = 2; // the hand and the tip
@ -98,4 +139,5 @@ const int NUMBER_OF_BUTTONS_PER_PALM = 6;
const int PALM_SPATIALCONTROL = 0;
const int TIP_SPATIALCONTROL = 1;
#endif // hifi_ControllerScriptingInterface_h

View file

@ -19,6 +19,28 @@
#include "EventTypes.h"
class AbstractInputController : public QObject {
Q_OBJECT
public:
typedef unsigned int Key;
virtual void update() = 0;
virtual Key getKey() const = 0;
public slots:
virtual bool isActive() const = 0;
virtual glm::vec3 getAbsTranslation() const = 0;
virtual glm::quat getAbsRotation() const = 0;
virtual glm::vec3 getLocTranslation() const = 0;
virtual glm::quat getLocRotation() const = 0;
signals:
void spatialEvent(const SpatialEvent& event);
};
/// handles scripting of input controller commands from JS
class AbstractControllerScriptingInterface : public QObject {
@ -60,6 +82,9 @@ public slots:
virtual glm::vec2 getViewportDimensions() const = 0;
virtual AbstractInputController* createInputController( const QString& category, const QString& tracker ) = 0;
signals:
void keyPressEvent(const KeyEvent& event);
void keyReleaseEvent(const KeyEvent& event);

View file

@ -19,6 +19,7 @@ void registerEventTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, mouseEventToScriptValue, mouseEventFromScriptValue);
qScriptRegisterMetaType(engine, touchEventToScriptValue, touchEventFromScriptValue);
qScriptRegisterMetaType(engine, wheelEventToScriptValue, wheelEventFromScriptValue);
qScriptRegisterMetaType(engine, spatialEventToScriptValue, spatialEventFromScriptValue);
}
KeyEvent::KeyEvent() :
@ -600,3 +601,34 @@ void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event) {
}
SpatialEvent::SpatialEvent() :
locTranslation(0.0f),
locRotation(),
absTranslation(0.0f),
absRotation()
{
};
SpatialEvent::SpatialEvent(const SpatialEvent& event) {
locTranslation = event.locTranslation;
locRotation = event.locRotation;
absTranslation = event.absTranslation;
absRotation = event.absRotation;
}
QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event) {
QScriptValue obj = engine->newObject();
obj.setProperty("locTranslation", vec3toScriptValue(engine, event.locTranslation) );
obj.setProperty("locRotation", quatToScriptValue(engine, event.locRotation) );
obj.setProperty("absTranslation", vec3toScriptValue(engine, event.absTranslation) );
obj.setProperty("absRotation", quatToScriptValue(engine, event.absRotation) );
return obj;
}
void spatialEventFromScriptValue(const QScriptValue& object,SpatialEvent& event) {
// nothing for now...
}

View file

@ -13,6 +13,7 @@
#define hifi_EventTypes_h
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QtScript/QScriptEngine>
@ -107,10 +108,25 @@ public:
bool isAlt;
};
class SpatialEvent {
public:
SpatialEvent();
SpatialEvent(const SpatialEvent& other);
glm::vec3 locTranslation;
glm::quat locRotation;
glm::vec3 absTranslation;
glm::quat absRotation;
private:
};
Q_DECLARE_METATYPE(KeyEvent)
Q_DECLARE_METATYPE(MouseEvent)
Q_DECLARE_METATYPE(TouchEvent)
Q_DECLARE_METATYPE(WheelEvent)
Q_DECLARE_METATYPE(SpatialEvent)
void registerEventTypes(QScriptEngine* engine);
@ -126,4 +142,7 @@ void touchEventFromScriptValue(const QScriptValue& object, TouchEvent& event);
QScriptValue wheelEventToScriptValue(QScriptEngine* engine, const WheelEvent& event);
void wheelEventFromScriptValue(const QScriptValue& object, WheelEvent& event);
QScriptValue spatialEventToScriptValue(QScriptEngine* engine, const SpatialEvent& event);
void spatialEventFromScriptValue(const QScriptValue& object, SpatialEvent& event);
#endif // hifi_EventTypes_h

View file

@ -67,6 +67,14 @@ void injectorFromScriptValue(const QScriptValue &object, AudioInjector* &out) {
out = qobject_cast<AudioInjector*>(object.toQObject());
}
QScriptValue injectorToScriptValue_InputController(QScriptEngine *engine, AbstractInputController* const &in) {
return engine->newQObject(in);
}
void injectorFromScriptValue_InputController(const QScriptValue &object, AbstractInputController* &out) {
out = qobject_cast<AbstractInputController*>(object.toQObject());
}
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
@ -248,6 +256,7 @@ void ScriptEngine::init() {
_engine.globalObject().setProperty("LocalVoxels", localVoxelsValue);
qScriptRegisterMetaType(&_engine, injectorToScriptValue, injectorFromScriptValue);
qScriptRegisterMetaType( &_engine, injectorToScriptValue_InputController, injectorFromScriptValue_InputController);
registerGlobalObject("Script", this);
registerGlobalObject("Audio", &_audioScriptingInterface);