mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-09 02:42:19 +02:00
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:
parent
fe03743163
commit
3ce455aba4
33 changed files with 7828 additions and 215 deletions
181
examples/leapOfFaith.js
Normal file
181
examples/leapOfFaith.js
Normal 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() {
|
||||
});
|
4792
interface/external/leapmotion/include/Leap.h
vendored
Normal file
4792
interface/external/leapmotion/include/Leap.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
787
interface/external/leapmotion/include/Leap.i
vendored
Normal file
787
interface/external/leapmotion/include/Leap.i
vendored
Normal 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"
|
1050
interface/external/leapmotion/include/LeapMath.h
vendored
Normal file
1050
interface/external/leapmotion/include/LeapMath.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
interface/external/leapmotion/lib/x64/Leap.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/Leap.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/Leap.lib
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/Leap.lib
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/Leapd.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/Leapd.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/Leapd.lib
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/Leapd.lib
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/msvcp120.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/msvcp120.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/msvcp120d.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/msvcp120d.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/msvcr120.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/msvcr120.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x64/msvcr120d.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x64/msvcr120d.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x86/Leap.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x86/Leap.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x86/Leap.lib
vendored
Normal file
BIN
interface/external/leapmotion/lib/x86/Leap.lib
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x86/msvcp120.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x86/msvcp120.dll
vendored
Normal file
Binary file not shown.
BIN
interface/external/leapmotion/lib/x86/msvcr120.dll
vendored
Normal file
BIN
interface/external/leapmotion/lib/x86/msvcr120.dll
vendored
Normal file
Binary file not shown.
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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]);
|
||||
|
|
91
interface/src/devices/DeviceTracker.cpp
Normal file
91
interface/src/devices/DeviceTracker.cpp
Normal 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()
|
||||
{
|
||||
}
|
91
interface/src/devices/DeviceTracker.h
Normal file
91
interface/src/devices/DeviceTracker.h
Normal 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
|
16
interface/src/devices/HandTracker.cpp
Normal file
16
interface/src/devices/HandTracker.cpp
Normal 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() {
|
||||
}
|
||||
|
58
interface/src/devices/HandTracker.h
Normal file
58
interface/src/devices/HandTracker.h
Normal 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
|
|
@ -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
|
||||
}
|
|
@ -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
|
200
interface/src/devices/MotionTracker.cpp
Normal file
200
interface/src/devices/MotionTracker.cpp
Normal 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];
|
||||
}
|
||||
|
130
interface/src/devices/MotionTracker.h
Normal file
130
interface/src/devices/MotionTracker.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue