diff --git a/cmake/macros/TargetKinect.cmake b/cmake/macros/TargetKinect.cmake new file mode 100644 index 0000000000..ca9c853d8d --- /dev/null +++ b/cmake/macros/TargetKinect.cmake @@ -0,0 +1,17 @@ +# +# Created by Brad Hefta-Gaub on 2016/12/7 +# Copyright 2016 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 +# +macro(TARGET_KINECT) + # Kinect SDK data reader is only available on these platforms + if (WIN32) + #add_dependency_external_projects(kinect) + find_package(Kinect REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${KINECT_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${KINECT_LIBRARIES}) + add_definitions(-DHAVE_KINECT) + endif(WIN32) +endmacro() diff --git a/cmake/modules/FindKinect.cmake b/cmake/modules/FindKinect.cmake new file mode 100644 index 0000000000..7607de1f44 --- /dev/null +++ b/cmake/modules/FindKinect.cmake @@ -0,0 +1,59 @@ +# +# FindKinect.cmake +# +# Try to find the Perception Kinect SDK +# +# You must provide a KINECT_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# KINECT_FOUND - system found Kinect SDK +# KINECT_INCLUDE_DIRS - the Kinect SDK include directory +# KINECT_LIBRARIES - Link this to use Kinect +# +# Created by Brad Hefta-Gaub on 2016/12/7 +# Copyright 2016 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake") +hifi_library_search_hints("kinect") + +find_path(KINECT_INCLUDE_DIRS Kinect.h PATH_SUFFIXES inc HINTS $ENV{KINECT_ROOT_DIR}) + +if (WIN32) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64") + else() + set(ARCH_DIR "x86") + endif() + + find_library( + KINECT_LIBRARY_RELEASE Kinect20 + PATH_SUFFIXES "Lib/${ARCH_DIR}" "lib" + HINTS ${KINECT_SEARCH_DIRS} + PATH $ENV{KINECT_ROOT_DIR}) + + set(KINECT_LIBRARIES ${KINECT_LIBRARY}) + + # DLL not needed yet?? + #find_path(KINECT_DLL_PATH Kinect20.Face.dll PATH_SUFFIXES "bin" HINTS ${KINECT_SEARCH_DIRS}) + + +endif () + +include(SelectLibraryConfigurations) +select_library_configurations(KINECT) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(KINECT DEFAULT_MSG KINECT_INCLUDE_DIRS KINECT_LIBRARY) + +# DLLs not needed yet +#if (WIN32) +# add_paths_to_fixup_libs(${KINECT_DLL_PATH}) +#endif () + +mark_as_advanced(KINECT_INCLUDE_DIRS KINECT_LIBRARIES KINECT_SEARCH_DIRS) diff --git a/interface/resources/controllers/kinect.json b/interface/resources/controllers/kinect.json new file mode 100644 index 0000000000..96a504030c --- /dev/null +++ b/interface/resources/controllers/kinect.json @@ -0,0 +1,7 @@ +{ + "name": "Kinect to Standard", + "channels": [ + { "from": "Kinect.LeftHand", "to": "Standard.LeftHand" }, + { "from": "Kinect.RightHand", "to": "Standard.RightHand" } + ] +} diff --git a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml index fec836626f..9be1c30e55 100644 --- a/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml +++ b/interface/resources/qml/hifi/dialogs/GeneralPreferencesDialog.qml @@ -17,7 +17,7 @@ PreferencesDialog { id: root objectName: "GeneralPreferencesDialog" title: "General Settings" - showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron"] + showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect"] property var settings: Settings { category: root.objectName property alias x: root.x diff --git a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h index 7fe1a5467e..dfa728d2b6 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/StandardEndpoint.h @@ -44,7 +44,7 @@ public: } virtual void apply(const Pose& value, const Pointer& source) override { - if (value != Pose()) { + if (value != Pose() && value.isValid()) { _written = true; } VirtualEndpoint::apply(value, source); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6dbc57431e..4553b80793 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -26,6 +26,9 @@ if (NOT SERVER_ONLY AND NOT ANDROID) add_subdirectory(${DIR}) set(DIR "hifiNeuron") add_subdirectory(${DIR}) + + set(DIR "hifiKinect") + add_subdirectory(${DIR}) endif() # server-side plugins diff --git a/plugins/hifiKinect/CMakeLists.txt b/plugins/hifiKinect/CMakeLists.txt new file mode 100644 index 0000000000..fc4c2f6f7c --- /dev/null +++ b/plugins/hifiKinect/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Created by Brad Hefta-Gaub on 2016/12/7 +# Copyright 2016 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 +# + +if (WIN32) + find_package(KINECT) + if (KINECT_FOUND) + set(TARGET_NAME hifiKinect) + setup_hifi_plugin(Script Qml Widgets) + link_hifi_libraries(shared controllers ui plugins input-plugins) + + # need to setup appropriate externals... + target_kinect() + endif() +endif() diff --git a/plugins/hifiKinect/src/KinectPlugin.cpp b/plugins/hifiKinect/src/KinectPlugin.cpp new file mode 100644 index 0000000000..844d4af962 --- /dev/null +++ b/plugins/hifiKinect/src/KinectPlugin.cpp @@ -0,0 +1,532 @@ +// +// KinectPlugin.cpp +// +// Created by Brad Hefta-Gaub on 2016/12/7 +// Copyright 2016 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 "KinectPlugin.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(inputplugins) +Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") + + +const char* KinectPlugin::NAME = "Kinect"; +const char* KinectPlugin::KINECT_ID_STRING = "Kinect"; + +QStringList kinectJointNames = { + "SpineBase", + "SpineMid", + "Neck", + "Head", + "ShoulderLeft", + "ElbowLeft", + "WristLeft", + "HandLeft", + "ShoulderRight", + "ElbowRight", + "WristRight", + "HandRight", + "HipLeft", + "KneeLeft", + "AnkleLeft", + "FootLeft", + "HipRight", + "KneeRight", + "AnkleRight", + "FootRight", + "SpineShoulder", + "HandTipLeft", + "ThumbLeft", + "HandTipRight", + "ThumbRight" +}; + +const bool DEFAULT_ENABLED = false; + +enum KinectJointIndex { + SpineBase = 0, + SpineMid, + Neck, + Head, + + ShoulderLeft, + ElbowLeft, + WristLeft, + HandLeft, + + ShoulderRight, + ElbowRight, + WristRight, + HandRight, + + HipLeft, + KneeLeft, + AnkleLeft, + FootLeft, + + HipRight, + KneeRight, + AnkleRight, + FootRight, + + SpineShoulder, + + HandTipLeft, + ThumbLeft, + + HandTipRight, + ThumbRight, + + Size +}; + +#define UNKNOWN_JOINT (controller::StandardPoseChannel)0 + +static controller::StandardPoseChannel KinectJointIndexToPoseIndexMap[KinectJointIndex::Size] = { + controller::HIPS, + controller::SPINE, + controller::NECK, + controller::HEAD, + + controller::LEFT_SHOULDER, + controller::LEFT_ARM, + controller::LEFT_FORE_ARM, + controller::LEFT_HAND, + + controller::RIGHT_SHOULDER, + controller::RIGHT_ARM, + controller::RIGHT_FORE_ARM, + controller::RIGHT_HAND, + + controller::RIGHT_UP_LEG, // hip socket + controller::RIGHT_LEG, // knee? + controller::RIGHT_FOOT, // ankle? + UNKNOWN_JOINT, // ???? + + controller::LEFT_UP_LEG, // hip socket + controller::LEFT_LEG, // knee? + controller::LEFT_FOOT, // ankle? + UNKNOWN_JOINT, // ???? + + UNKNOWN_JOINT, /* SpineShoulder */ + + controller::LEFT_HAND_INDEX4, + controller::LEFT_HAND_THUMB4, + + controller::RIGHT_HAND_INDEX4, + controller::RIGHT_HAND_THUMB4, + +}; + +// in rig frame +static glm::vec3 rightHandThumb1DefaultAbsTranslation(-2.155500650405884, -0.7610001564025879, 2.685631036758423); +static glm::vec3 leftHandThumb1DefaultAbsTranslation(2.1555817127227783, -0.7603635787963867, 2.6856393814086914); + +static controller::StandardPoseChannel KinectJointIndexToPoseIndex(KinectJointIndex i) { + assert(i >= 0 && i < KinectJointIndex::Size); + if (i >= 0 && i < KinectJointIndex::Size) { + return KinectJointIndexToPoseIndexMap[i]; + } else { + return UNKNOWN_JOINT; // not sure what to do here, but don't crash! + } +} + +QStringList controllerJointNames = { + "Hips", + "RightUpLeg", + "RightLeg", + "RightFoot", + "LeftUpLeg", + "LeftLeg", + "LeftFoot", + "Spine", + "Spine1", + "Spine2", + "Spine3", + "Neck", + "Head", + "RightShoulder", + "RightArm", + "RightForeArm", + "RightHand", + "RightHandThumb1", + "RightHandThumb2", + "RightHandThumb3", + "RightHandThumb4", + "RightHandIndex1", + "RightHandIndex2", + "RightHandIndex3", + "RightHandIndex4", + "RightHandMiddle1", + "RightHandMiddle2", + "RightHandMiddle3", + "RightHandMiddle4", + "RightHandRing1", + "RightHandRing2", + "RightHandRing3", + "RightHandRing4", + "RightHandPinky1", + "RightHandPinky2", + "RightHandPinky3", + "RightHandPinky4", + "LeftShoulder", + "LeftArm", + "LeftForeArm", + "LeftHand", + "LeftHandThumb1", + "LeftHandThumb2", + "LeftHandThumb3", + "LeftHandThumb4", + "LeftHandIndex1", + "LeftHandIndex2", + "LeftHandIndex3", + "LeftHandIndex4", + "LeftHandMiddle1", + "LeftHandMiddle2", + "LeftHandMiddle3", + "LeftHandMiddle4", + "LeftHandRing1", + "LeftHandRing2", + "LeftHandRing3", + "LeftHandRing4", + "LeftHandPinky1", + "LeftHandPinky2", + "LeftHandPinky3", + "LeftHandPinky4" +}; + +static const char* getControllerJointName(controller::StandardPoseChannel i) { + if (i >= 0 && i < controller::NUM_STANDARD_POSES) { + return qPrintable(controllerJointNames[i]); + } + return "unknown"; +} + +// +// KinectPlugin +// +void KinectPlugin::init() { + loadSettings(); + + auto preferences = DependencyManager::get(); + static const QString KINECT_PLUGIN { "Kinect" }; + { + auto getter = [this]()->bool { return _enabled; }; + auto setter = [this](bool value) { _enabled = value; saveSettings(); }; + auto preference = new CheckPreference(KINECT_PLUGIN, "Enabled", getter, setter); + preferences->addPreference(preference); + } +} + +bool KinectPlugin::isSupported() const { + // FIXME -- check to see if there's a camera or not... + return true; +} + +bool KinectPlugin::activate() { + InputPlugin::activate(); + + loadSettings(); + + if (_enabled) { + + // register with userInputMapper + auto userInputMapper = DependencyManager::get(); + userInputMapper->registerDevice(_inputDevice); + + return initializeDefaultSensor(); + } else { + return false; + } +} + +bool KinectPlugin::initializeDefaultSensor() { +#ifdef HAVE_KINECT + HRESULT hr; + + hr = GetDefaultKinectSensor(&_kinectSensor); + if (FAILED(hr)) { + return false; + } + + if (_kinectSensor) { + // Initialize the Kinect and get coordinate mapper and the body reader + IBodyFrameSource* bodyFrameSource = NULL; + + hr = _kinectSensor->Open(); + + if (SUCCEEDED(hr)) { + hr = _kinectSensor->get_CoordinateMapper(&_coordinateMapper); + } + + if (SUCCEEDED(hr)) { + hr = _kinectSensor->get_BodyFrameSource(&bodyFrameSource); + } + + if (SUCCEEDED(hr)) { + hr = bodyFrameSource->OpenReader(&_bodyFrameReader); + } + + SafeRelease(bodyFrameSource); + } + + if (!_kinectSensor || FAILED(hr)) { + qDebug() << "No ready Kinect found!"; + return false; + } + + qDebug() << "Kinect found WOOT!"; + + return true; +#else + return false; +#endif +} + +void KinectPlugin::updateBody() { +#ifndef HAVE_KINECT + return; +#else + if (!_bodyFrameReader) { + return; + } + + IBodyFrame* pBodyFrame = NULL; + + HRESULT hr = _bodyFrameReader->AcquireLatestFrame(&pBodyFrame); + + if (SUCCEEDED(hr)) { + INT64 nTime = 0; + hr = pBodyFrame->get_RelativeTime(&nTime); + IBody* bodies[BODY_COUNT] = {0}; + if (SUCCEEDED(hr)) { + hr = pBodyFrame->GetAndRefreshBodyData(_countof(bodies), bodies); + } + + if (SUCCEEDED(hr)) { + ProcessBody(nTime, BODY_COUNT, bodies); + } + + for (int i = 0; i < _countof(bodies); ++i) { + SafeRelease(bodies[i]); + } + } + + SafeRelease(pBodyFrame); +#endif +} + +#ifdef HAVE_KINECT +void KinectPlugin::ProcessBody(INT64 time, int bodyCount, IBody** bodies) { + bool foundOneBody = false; + if (_coordinateMapper) { + for (int i = 0; i < bodyCount; ++i) { + if (foundOneBody) { + break; + } + IBody* body = bodies[i]; + if (body) { + BOOLEAN tracked = false; + HRESULT hr = body->get_IsTracked(&tracked); + + if (SUCCEEDED(hr) && tracked) { + foundOneBody = true; + + if (_joints.size() != JointType_Count) { + _joints.resize(JointType_Count, { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }); + } + + Joint joints[JointType_Count]; + JointOrientation jointOrientations[JointType_Count]; + HandState leftHandState = HandState_Unknown; + HandState rightHandState = HandState_Unknown; + + body->get_HandLeftState(&leftHandState); + body->get_HandRightState(&rightHandState); + + hr = body->GetJoints(_countof(joints), joints); + hr = body->GetJointOrientations(_countof(jointOrientations), jointOrientations); + + if (SUCCEEDED(hr)) { + auto jointCount = _countof(joints); + //qDebug() << __FUNCTION__ << "nBodyCount:" << nBodyCount << "body:" << i << "jointCount:" << jointCount; + for (int j = 0; j < jointCount; ++j) { + //QString jointName = kinectJointNames[joints[j].JointType]; + + glm::vec3 jointPosition { joints[j].Position.X, + joints[j].Position.Y, + joints[j].Position.Z }; + + // Kinect Documentation is unclear on what these orientations are, are they absolute? + // or are the relative to the parent bones. It appears as if it has changed between the + // older 1.x SDK and the 2.0 sdk + // + // https://social.msdn.microsoft.com/Forums/en-US/31c9aff6-7dab-433d-9af9-59942dfd3d69/kinect-v20-preview-sdk-jointorientation-vs-boneorientation?forum=kinectv2sdk + // seems to suggest these are absolute... + // "These quaternions are absolute, so you can take a mesh in local space, transform it by the quaternion, + // and it will match the exact orientation of the bone. If you want relative orientation quaternion, you + // can multiply the absolute quaternion by the inverse of the parent joint's quaternion." + // + // - Bone direction(Y green) - always matches the skeleton. + // - Normal(Z blue) - joint roll, perpendicular to the bone + // - Binormal(X orange) - perpendicular to the bone and normal + + glm::quat jointOrientation { jointOrientations[j].Orientation.x, + jointOrientations[j].Orientation.y, + jointOrientations[j].Orientation.z, + jointOrientations[j].Orientation.w }; + + // filling in the _joints data... + if (joints[j].TrackingState != TrackingState_NotTracked) { + _joints[j].position = jointPosition; + //_joints[j].orientation = jointOrientation; + } + } + } + } + } + } + } +} +#endif + + +void KinectPlugin::deactivate() { + // unregister from userInputMapper + if (_inputDevice->_deviceID != controller::Input::INVALID_DEVICE) { + auto userInputMapper = DependencyManager::get(); + userInputMapper->removeDevice(_inputDevice->_deviceID); + } + + InputPlugin::deactivate(); + saveSettings(); + +#ifdef HAVE_KINECT + // done with body frame reader + SafeRelease(_bodyFrameReader); + + // done with coordinate mapper + SafeRelease(_coordinateMapper); + + // close the Kinect Sensor + if (_kinectSensor) { + _kinectSensor->Close(); + } + + SafeRelease(_kinectSensor); +#endif // HAVE_KINECT + +} + +void KinectPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { + + if (!_enabled) { + return; + } + + updateBody(); // updates _joints + + std::vector joints = _joints; + + auto userInputMapper = DependencyManager::get(); + userInputMapper->withLock([&, this]() { + _inputDevice->update(deltaTime, inputCalibrationData, joints, _prevJoints); + }); + + _prevJoints = joints; +} + +void KinectPlugin::saveSettings() const { + Settings settings; + QString idString = getID(); + settings.beginGroup(idString); + { + settings.setValue(QString("enabled"), _enabled); + } + settings.endGroup(); +} + +void KinectPlugin::loadSettings() { + Settings settings; + QString idString = getID(); + settings.beginGroup(idString); + { + // enabled + _enabled = settings.value("enabled", QVariant(DEFAULT_ENABLED)).toBool(); + } + settings.endGroup(); +} + +// +// InputDevice +// + +// FIXME - we probably should only return the inputs we ACTUALLY have +controller::Input::NamedVector KinectPlugin::InputDevice::getAvailableInputs() const { + static controller::Input::NamedVector availableInputs; + if (availableInputs.size() == 0) { + for (int i = 0; i < KinectJointIndex::Size; i++) { + auto channel = KinectJointIndexToPoseIndex(static_cast(i)); + availableInputs.push_back(makePair(channel, getControllerJointName(channel))); + } + }; + return availableInputs; +} + +QString KinectPlugin::InputDevice::getDefaultMappingConfig() const { + static const QString MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/kinect.json"; + return MAPPING_JSON; +} + +void KinectPlugin::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, + const std::vector& joints, const std::vector& prevJoints) { + + glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; + glm::quat controllerToAvatarRotation = glmExtractRotation(controllerToAvatar); + + vec3 kinectHipPos; + if (joints.size() > JointType_SpineBase) { + kinectHipPos = joints[JointType_SpineBase].position; + } + + for (size_t i = 0; i < joints.size(); i++) { + int poseIndex = KinectJointIndexToPoseIndex((KinectJointIndex)i); + glm::vec3 linearVel, angularVel; + + // Adjust the position to be hip (avatar) relative, and rotated to match the avatar rotation + const glm::vec3& pos = controllerToAvatarRotation * (joints[i].position - kinectHipPos); + + if (Vectors::ZERO == pos) { + _poseStateMap[poseIndex] = controller::Pose(); + continue; + } + + // FIXME - determine the correct orientation transform + glm::quat rot = joints[i].orientation; + + if (i < prevJoints.size()) { + linearVel = (pos - (prevJoints[i].position * METERS_PER_CENTIMETER)) / deltaTime; // m/s + // quat log imaginary part points along the axis of rotation, with length of one half the angle of rotation. + glm::quat d = glm::log(rot * glm::inverse(prevJoints[i].orientation)); + angularVel = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); // radians/s + } + + _poseStateMap[poseIndex] = controller::Pose(pos, rot, linearVel, angularVel); + } +} + diff --git a/plugins/hifiKinect/src/KinectPlugin.h b/plugins/hifiKinect/src/KinectPlugin.h new file mode 100644 index 0000000000..c66d746427 --- /dev/null +++ b/plugins/hifiKinect/src/KinectPlugin.h @@ -0,0 +1,117 @@ +// +// KinectPlugin.h +// +// Created by Brad Hefta-Gaub on 2016/12/7 +// Copyright 2016 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_KinectPlugin_h +#define hifi_KinectPlugin_h + +#ifdef HAVE_KINECT +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#endif + +// Windows Header Files +#include + +#include + +// Kinect Header files +#include + +// Safe release for interfaces +template inline void SafeRelease(Interface *& pInterfaceToRelease) { + if (pInterfaceToRelease != NULL) { + pInterfaceToRelease->Release(); + pInterfaceToRelease = NULL; + } +} +#endif + +#include +#include +#include + +// Handles interaction with the Kinect SDK +class KinectPlugin : public InputPlugin { + Q_OBJECT +public: + bool isHandController() const override { return true; } + + // Plugin functions + virtual void init() override; + virtual bool isSupported() const override; + virtual const QString getName() const override { return NAME; } + const QString getID() const override { return KINECT_ID_STRING; } + + virtual bool activate() override; + virtual void deactivate() override; + + virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; + + virtual void saveSettings() const override; + virtual void loadSettings() override; + +protected: + + struct KinectJoint { + glm::vec3 position; + glm::quat orientation; + }; + + class InputDevice : public controller::InputDevice { + public: + friend class KinectPlugin; + + InputDevice() : controller::InputDevice("Kinect") {} + + // Device functions + virtual controller::Input::NamedVector getAvailableInputs() const override; + virtual QString getDefaultMappingConfig() const override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override {}; + virtual void focusOutEvent() override {}; + + void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, + const std::vector& joints, const std::vector& prevJoints); + }; + + std::shared_ptr _inputDevice { std::make_shared() }; + + static const char* NAME; + static const char* KINECT_ID_STRING; + + bool _enabled; + + // copy of data directly from the KinectDataReader SDK + std::vector _joints; + + // one frame old copy of _joints, used to caluclate angular and linear velocity. + std::vector _prevJoints; + + + // Kinect SDK related items... + + bool KinectPlugin::initializeDefaultSensor(); + void updateBody(); + +#ifdef HAVE_KINECT + void ProcessBody(INT64 time, int bodyCount, IBody** bodies); + + // Current Kinect + IKinectSensor* _kinectSensor { nullptr }; + ICoordinateMapper* _coordinateMapper { nullptr }; + + // Body reader + IBodyFrameReader* _bodyFrameReader { nullptr }; +#endif + +}; + +#endif // hifi_KinectPlugin_h + diff --git a/plugins/hifiKinect/src/KinectProvider.cpp b/plugins/hifiKinect/src/KinectProvider.cpp new file mode 100644 index 0000000000..269ec50b60 --- /dev/null +++ b/plugins/hifiKinect/src/KinectProvider.cpp @@ -0,0 +1,49 @@ +// +// Created by Brad Hefta-Gaub on 2016/12/7 +// Copyright 2016 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 + +#include +#include +#include + +#include +#include + +#include "KinectPlugin.h" + +class KinectProvider : public QObject, public InputProvider +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID InputProvider_iid FILE "plugin.json") + Q_INTERFACES(InputProvider) + +public: + KinectProvider(QObject* parent = nullptr) : QObject(parent) {} + virtual ~KinectProvider() {} + + virtual InputPluginList getInputPlugins() override { + static std::once_flag once; + std::call_once(once, [&] { + InputPluginPointer plugin(new KinectPlugin()); + if (plugin->isSupported()) { + _inputPlugins.push_back(plugin); + } + }); + return _inputPlugins; + } + + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + +private: + InputPluginList _inputPlugins; +}; + +#include "KinectProvider.moc" diff --git a/plugins/hifiKinect/src/plugin.json b/plugins/hifiKinect/src/plugin.json new file mode 100644 index 0000000000..daa3a668dd --- /dev/null +++ b/plugins/hifiKinect/src/plugin.json @@ -0,0 +1 @@ +{"name":"Kinect"}