2#include "ManusSDKTypes.h"
8#define GO_TO_DISPLAY(p_Key,p_Function) if (GetKeyDown(p_Key)) { ClearConsole();\
9 m_CurrentInteraction = std::bind(&SDKClient::p_Function, this); return ClientReturnCode::ClientReturnCode_Success;}
11#define GO_TO_MENU_IF_REQUESTED() if (GetKeyDown('Q')) { ClearConsole();\
12 m_CurrentInteraction = nullptr; return ClientReturnCode::ClientReturnCode_Success;}
38 return ClientReturnCode::ClientReturnCode_FailedPlatformSpecificInitialization;
47 return ClientReturnCode::ClientReturnCode_FailedToResizeWindow;
51 if (t_IntializeResult != ClientReturnCode::ClientReturnCode_Success)
53 spdlog::error(
"Failed to initialize the Core functionality. The value returned was {}.", t_IntializeResult);
54 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
57 return ClientReturnCode::ClientReturnCode_Success;
82 case ClientState::ClientState_PickingConnectionType:
85 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
87 case ClientState::ClientState_LookingForHosts:
90 if (t_Result != ClientReturnCode::ClientReturnCode_Success &&
91 t_Result != ClientReturnCode::ClientReturnCode_FailedToFindHosts) {
95 case ClientState::ClientState_NoHostsFound:
98 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
100 case ClientState::ClientState_PickingHost:
103 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
105 case ClientState::ClientState_ConnectingToCore:
108 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
110 case ClientState::ClientState_DisplayingData:
121 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
123 case ClientState::ClientState_Disconnected:
126 if (t_Result != ClientReturnCode::ClientReturnCode_Success) {
return t_Result; }
130 spdlog::error(
"Encountered the unrecognized state {}.",
static_cast<int>(
m_State));
131 return ClientReturnCode::ClientReturnCode_UnrecognizedStateEncountered;
137 spdlog::info(
"Pressed escape, so the client will now close.");
143 std::this_thread::sleep_for(std::chrono::milliseconds(10));
146 return ClientReturnCode::ClientReturnCode_Success;
154 const SDKReturnCode t_Result = CoreSdk_ShutDown();
155 if (t_Result != SDKReturnCode::SDKReturnCode_Success)
157 spdlog::error(
"Failed to shut down the SDK wrapper. The value returned was {}.", t_Result);
158 return ClientReturnCode::ClientReturnCode_FailedToShutDownSDK;
163 return ClientReturnCode::ClientReturnCode_FailedPlatformSpecificShutdown;
166 return ClientReturnCode::ClientReturnCode_Success;
174 spdlog::info(
"Connected to manus core.");
177 ManusVersion t_SdkVersion;
178 ManusVersion t_CoreVersion;
181 const SDKReturnCode t_Result = CoreSdk_GetVersionsAndCheckCompatibility(&t_SdkVersion, &t_CoreVersion, &t_IsCompatible);
183 if (t_Result == SDKReturnCode::SDKReturnCode_Success)
185 const std::string t_Versions =
"Sdk version : " + std::string(t_SdkVersion.versionInfo) +
", Core version : " + std::string(t_CoreVersion.versionInfo) +
".";
189 spdlog::info(
"Versions are compatible.{}", t_Versions);
193 spdlog::warn(
"Versions are not compatible with each other.{}", t_Versions);
198 spdlog::error(
"Failed to get the versions from the SDK. The value returned was {}.", t_Result);
201 uint32_t t_SessionId;
202 const SDKReturnCode t_SessionIdResult = CoreSdk_GetSessionId(&t_SessionId);
203 if (t_SessionIdResult == SDKReturnCode::SDKReturnCode_Success && t_SessionId != 0)
205 spdlog::info(
"Session Id: {}", t_SessionId);
210 spdlog::info(
"Failed to get the Session ID from Core. The value returned was{}.", t_SessionIdResult);
213 ManusHost t_Host(*p_Host);
227 spdlog::info(
"Disconnected from manus core.");
229 ManusHost t_Host(*p_Host);
241 t_NxtClientSkeleton->
skeletons.resize(p_SkeletonStreamInfo->skeletonsCount);
243 for (uint32_t i = 0; i < p_SkeletonStreamInfo->skeletonsCount; i++)
245 CoreSdk_GetSkeletonInfo(i, &t_NxtClientSkeleton->
skeletons[i].info);
246 t_NxtClientSkeleton->
skeletons[i].nodes.resize(t_NxtClientSkeleton->
skeletons[i].info.nodesCount);
247 t_NxtClientSkeleton->
skeletons[i].info.publishTime = p_SkeletonStreamInfo->publishTime;
248 CoreSdk_GetSkeletonData(i, t_NxtClientSkeleton->
skeletons[i].nodes.data(), t_NxtClientSkeleton->
skeletons[i].info.nodesCount);
263 Landscape* t_Landscape =
new Landscape(*p_Landscape);
279 switch (p_SystemMessage->type)
281 case SystemMessageType::SystemMessageType_TemporarySkeletonModified:
305 for (uint32_t i = 0; i < p_Ergo->dataCount; i++)
307 if (p_Ergo->data[i].isUserID)
continue;
309 ErgonomicsData* t_Ergo =
nullptr;
318 if (t_Ergo ==
nullptr)
continue;
320 t_Ergo->id = p_Ergo->data[i].id;
321 t_Ergo->isUserID = p_Ergo->data[i].isUserID;
322 for (
int j = 0; j < ErgonomicsDataType::ErgonomicsDataType_MAX_SIZE; j++)
324 t_Ergo->data[j] = p_Ergo->data[i].data[j];
337 float t_Power =
static_cast<float>(std::pow(
339 static_cast<double>(p_NumDecimalsToKeep)));
340 return std::round(p_Value * t_Power) / t_Power;
365 const SDKReturnCode t_InitializeResult = CoreSdk_Initialize(
m_ClientType);
366 if (t_InitializeResult != SDKReturnCode::SDKReturnCode_Success)
368 spdlog::error(
"Failed to initialize the Manus Core SDK. The value returned was {}.", t_InitializeResult);
369 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
373 if (t_CallBackResults != ::ClientReturnCode::ClientReturnCode_Success)
375 spdlog::error(
"Failed to initialize callbacks.");
376 return t_CallBackResults;
383 CoordinateSystemVUH t_VUH;
384 CoordinateSystemVUH_Init(&t_VUH);
385 t_VUH.handedness = Side::Side_Left;
386 t_VUH.up = AxisPolarity::AxisPolarity_PositiveY;
387 t_VUH.view = AxisView::AxisView_ZFromViewer;
388 t_VUH.unitScale = 1.0f;
390 const SDKReturnCode t_CoordinateResult = CoreSdk_InitializeCoordinateSystemWithVUH(t_VUH,
false);
399 if (t_CoordinateResult != SDKReturnCode::SDKReturnCode_Success)
401 spdlog::error(
"Failed to initialize the Manus Core SDK coordinate system. The value returned was {}.", t_InitializeResult);
402 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
405 return ClientReturnCode::ClientReturnCode_Success;
413 const SDKReturnCode t_ShutDownResult = CoreSdk_ShutDown();
414 if (t_ShutDownResult != SDKReturnCode::SDKReturnCode_Success)
416 spdlog::error(
"Failed to shutdown the SDK. The value returned was {}.", t_ShutDownResult);
417 return ClientReturnCode::ClientReturnCode_FailedToShutDownSDK;
421 if (t_IntializeResult != ClientReturnCode::ClientReturnCode_Success)
423 spdlog::error(
"Failed to initialize the SDK functionality. The value returned was {}.", t_IntializeResult);
424 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
427 return ClientReturnCode::ClientReturnCode_Success;
438 const SDKReturnCode t_RegisterConnectCallbackResult = CoreSdk_RegisterCallbackForOnConnect(*
OnConnectedCallback);
439 if (t_RegisterConnectCallbackResult != SDKReturnCode::SDKReturnCode_Success)
441 spdlog::error(
"Failed to register callback function for after connecting to Manus Core. The value returned was {}.", t_RegisterConnectCallbackResult);
442 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
448 const SDKReturnCode t_RegisterDisconnectCallbackResult = CoreSdk_RegisterCallbackForOnDisconnect(*
OnDisconnectedCallback);
449 if (t_RegisterDisconnectCallbackResult != SDKReturnCode::SDKReturnCode_Success)
451 spdlog::error(
"Failed to register callback function for after disconnecting from Manus Core. The value returned was {}.", t_RegisterDisconnectCallbackResult);
452 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
458 const SDKReturnCode t_RegisterSkeletonCallbackResult = CoreSdk_RegisterCallbackForSkeletonStream(*
OnSkeletonStreamCallback);
459 if (t_RegisterSkeletonCallbackResult != SDKReturnCode::SDKReturnCode_Success)
461 spdlog::error(
"Failed to register callback function for processing skeletal data from Manus Core. The value returned was {}.", t_RegisterSkeletonCallbackResult);
462 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
467 const SDKReturnCode t_RegisterLandscapeCallbackResult = CoreSdk_RegisterCallbackForLandscapeStream(*
OnLandscapeCallback);
468 if (t_RegisterLandscapeCallbackResult != SDKReturnCode::SDKReturnCode_Success)
470 spdlog::error(
"Failed to register callback for landscape from Manus Core. The value returned was {}.", t_RegisterLandscapeCallbackResult);
471 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
477 const SDKReturnCode t_RegisterSystemCallbackResult = CoreSdk_RegisterCallbackForSystemStream(*
OnSystemCallback);
478 if (t_RegisterSystemCallbackResult != SDKReturnCode::SDKReturnCode_Success)
480 spdlog::error(
"Failed to register callback function for system feedback from Manus Core. The value returned was {}.", t_RegisterSystemCallbackResult);
481 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
487 const SDKReturnCode t_RegisterErgonomicsCallbackResult = CoreSdk_RegisterCallbackForErgonomicsStream(*
OnErgonomicsCallback);
488 if (t_RegisterErgonomicsCallbackResult != SDKReturnCode::SDKReturnCode_Success)
490 spdlog::error(
"Failed to register callback function for ergonomics data from Manus Core. The value returned was {}.", t_RegisterErgonomicsCallbackResult);
491 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
494 return ClientReturnCode::ClientReturnCode_Success;
507 bool t_BuiltInDebug =
false;
508 SDKReturnCode t_Result = CoreSdk_WasDllBuiltInDebugConfiguration(&t_BuiltInDebug);
509 if (t_Result == SDKReturnCode::SDKReturnCode_Success)
513 spdlog::warn(
"The DLL was built in debug configuration, please rebuild in release before releasing.");
518 spdlog::error(
"Failed to check if the DLL was built in Debug Configuration. The value returned was {}.", t_Result);
521 spdlog::info(
"Press a key to choose a connection type, or [ESC] to exit.");
522 spdlog::info(
"[L] Local -> Automatically connect to Core running on this computer.");
523 spdlog::info(
"[H] Host -> Find a host running Core anywhere on the network.");
524 spdlog::info(
"[G] GRPC -> Try to connect to the preset GRPC address (See settings folder).");
529 spdlog::info(
"Picked local.");
533 m_State = ClientState::ClientState_LookingForHosts;
537 spdlog::info(
"Picked host.");
541 m_State = ClientState::ClientState_LookingForHosts;
545 spdlog::info(
"Picked GRPC.");
548 m_State = ClientState::ClientState_ConnectingToCore;
551 return ClientReturnCode::ClientReturnCode_Success;
558 spdlog::info(
"Looking for hosts...");
562 if (t_StartResult != SDKReturnCode::SDKReturnCode_Success)
564 spdlog::error(
"Failed to look for hosts. The error given was {}.", t_StartResult);
566 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
570 const SDKReturnCode t_NumberResult = CoreSdk_GetNumberOfAvailableHostsFound(&
m_NumberOfHostsFound);
571 if (t_NumberResult != SDKReturnCode::SDKReturnCode_Success)
573 spdlog::error(
"Failed to get the number of available hosts. The error given was {}.", t_NumberResult);
575 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
580 spdlog::warn(
"No hosts found.");
581 m_State = ClientState::ClientState_NoHostsFound;
583 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
588 if (t_HostsResult != SDKReturnCode::SDKReturnCode_Success)
590 spdlog::error(
"Failed to get the available hosts. The error given was {}.", t_HostsResult);
592 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
596 m_State = ClientState::ClientState_ConnectingToCore;
597 return ClientReturnCode::ClientReturnCode_Success;
600 m_State = ClientState::ClientState_PickingHost;
601 return ClientReturnCode::ClientReturnCode_Success;
610 spdlog::info(
"No hosts were found. Retry?");
611 spdlog::info(
"[R] retry");
612 spdlog::info(
"[ESC] exit");
617 spdlog::info(
"Retrying.");
619 m_State = ClientState::ClientState_PickingConnectionType;
623 return ClientReturnCode::ClientReturnCode_Success;
633 spdlog::info(
"[R] retry [ESC] exit");
634 spdlog::info(
"Pick a host to connect to.");
635 spdlog::info(
"Found the following hosts:");
638 for (
unsigned int t_HostNumber = 0; t_HostNumber < 10 && t_HostNumber <
m_NumberOfHostsFound; t_HostNumber++)
641 "[{}] hostname \"{}\", IP address \"{}\" Version {}.{}.{}",
651 for (
unsigned int t_HostNumber = 0; t_HostNumber < 10 && t_HostNumber <
m_NumberOfHostsFound; t_HostNumber++)
655 spdlog::info(
"Selected host {}.", t_HostNumber);
658 m_State = ClientState::ClientState_ConnectingToCore;
666 spdlog::info(
"Retrying.");
668 m_State = ClientState::ClientState_PickingConnectionType;
671 return ClientReturnCode::ClientReturnCode_Success;
677 SDKReturnCode t_ConnectResult = SDKReturnCode::SDKReturnCode_Error;
681 t_ConnectResult = CoreSdk_ConnectGRPC();
689 if (t_ConnectResult == SDKReturnCode::SDKReturnCode_NotConnected)
691 m_State = ClientState::ClientState_NoHostsFound;
693 return ClientReturnCode::ClientReturnCode_Success;
695 if (t_ConnectResult != SDKReturnCode::SDKReturnCode_Success)
697 spdlog::error(
"Failed to connect to Core. The error given was {}.", t_ConnectResult);
699 return ClientReturnCode::ClientReturnCode_FailedToConnect;
702 m_State = ClientState::ClientState_DisplayingData;
710 return ClientReturnCode::ClientReturnCode_Success;
744 if (
m_Landscape ==
nullptr)
return ClientReturnCode::ClientReturnCode_Success;
745 for (
size_t i = 0; i <
m_Landscape->gloveDevices.gloveCount; i++)
759 return ClientReturnCode::ClientReturnCode_Success;
768 SPDLOG_INFO(
"<<Main Menu>> [ESC] quit");
769 SPDLOG_INFO(
"[G] Go To Gloves & Dongle Menu");
770 SPDLOG_INFO(
"[S] Go To Skeleton Menu");
771 SPDLOG_INFO(
"[X] Go To Temporary Skeleton Menu");
772 SPDLOG_INFO(
"[T] Go To Tracker Menu");
773 SPDLOG_INFO(
"[D] Go To Landscape Time Info");
785 return ClientReturnCode::ClientReturnCode_Success;
792 SPDLOG_INFO(
"[Q] Back <<Gloves & Dongles>> [ESC] quit");
793 SPDLOG_INFO(
"Haptic keys: left:([1]-[5] = pinky-thumb.) right:([6]-[0] = thumb-pinky.)");
805 return ClientReturnCode::ClientReturnCode_Success;
810 SPDLOG_INFO(
"[Q] Back <<Skeleton>> [ESC] quit");
811 SPDLOG_INFO(
"<Skeleton>[N] Load Skeleton [M] Unload Skeleton");
812 SPDLOG_INFO(
"<Skeleton Haptics> left:([1]-[5] = pinky-thumb) right:([6]-[0] = thumb-pinky)");
825 return ClientReturnCode::ClientReturnCode_Success;
830 SPDLOG_INFO(
"[Q] Back <<Gloves & Dongles>> [ESC] quit");
831 SPDLOG_INFO(
"[O] Toggle Test Tracker [G] Toggle per user tracker display");
842 return ClientReturnCode::ClientReturnCode_Success;
847 SPDLOG_INFO(
"[Q] Back <<Temporary Skeleton>> [ESC] quit");
848 SPDLOG_INFO(
"<Skeleton>[A] Auto allocate chains and load skeleton");
849 SPDLOG_INFO(
"<Skeleton>[B] Build Temporary Skeleton [C] Clear Temporary Skeleton [D] Clear All Temporary Skeletons For The Current Session");
850 SPDLOG_INFO(
"<Skeleton>[E] Save Temporary Skeleton To File, [F] Get Temporary Skeleton From File");
863 return ClientReturnCode::ClientReturnCode_Success;
868 SPDLOG_INFO(
"[Q] Back <<Landscape Time Data>> [ESC] quit");
880 return ClientReturnCode::ClientReturnCode_Success;
887 if (
m_Host ==
nullptr) {
return ClientReturnCode::ClientReturnCode_FailedToConnect; }
891 auto t_Duration = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() -
m_TimeSinceLastDisconnect).count();
892 spdlog::info(
"The SDK lost connection with Manus Core {} seconds ago.", t_Duration);
893 spdlog::info(
"[P] Pick a new host. [ESC] exit");
899 spdlog::info(
"Automatically trying to reconnect to GRPC address.");
902 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
904 return t_ReconnectResult;
909 spdlog::info(
"Automatically trying to reconnect to local host.");
912 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
914 return t_ReconnectResult;
919 spdlog::info(
"[R] Try to reconnect to the last host {} at {}.",
m_Host->hostName,
m_Host->ipAddress);
922 spdlog::info(
"Reconnecting");
925 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
927 return t_ReconnectResult;
937 spdlog::info(
"Picking new host.");
941 if (t_RestartResult != ClientReturnCode::ClientReturnCode_Success)
943 spdlog::error(
"Failed to Restart CoreConnection.");
944 return ClientReturnCode::ClientReturnCode_FailedToRestart;
947 m_State = ClientState::ClientState_PickingConnectionType;
950 return ClientReturnCode::ClientReturnCode_Success;
956 if (p_ReconnectionTime <= 0) { p_ReconnectionTime = std::numeric_limits<int32_t>::max(); }
957 if (p_ReconnectionAttempts <= 0) { p_ReconnectionAttempts = std::numeric_limits<int32_t>::max(); }
961 if (t_RestartResult != ClientReturnCode::ClientReturnCode_Success)
963 spdlog::error(
"Failed to Restart CoreConnection.");
964 return ClientReturnCode::ClientReturnCode_FailedToRestart;
967 std::chrono::high_resolution_clock::time_point t_Start = std::chrono::high_resolution_clock::now();
969 while ((p_ReconnectionAttempts > 0) && (p_ReconnectionTime > 0))
971 spdlog::info(
"Trying to reconnect to {} at {}. Attempt {}.",
m_Host->hostName,
m_Host->ipAddress, t_Attempt);
972 spdlog::info(
"Attempts remaining: {}. Seconds before time out: {}.", p_ReconnectionAttempts, p_ReconnectionTime);
975 SDKReturnCode t_ConnectionResult = CoreSdk_ConnectGRPC();
976 if (t_ConnectionResult == SDKReturnCode::SDKReturnCode_Success)
978 spdlog::info(
"Reconnected to ManusCore.");
979 return ClientReturnCode::ClientReturnCode_Success;
985 if (t_ConnectionResult == ClientReturnCode::ClientReturnCode_Success)
987 spdlog::info(
"Reconnected to ManusCore.");
988 return ClientReturnCode::ClientReturnCode_Success;
993 SDKReturnCode t_ConnectionResult = CoreSdk_ConnectToHost(*
m_Host.get());
994 if (t_ConnectionResult == SDKReturnCode::SDKReturnCode_Success)
996 spdlog::info(
"Reconnected to ManusCore.");
997 return ClientReturnCode::ClientReturnCode_Success;
1001 p_ReconnectionTime -=
static_cast<int32_t
>(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now() - t_Start).count());
1002 --p_ReconnectionAttempts;
1006 spdlog::info(
"Failed to reconnect to ManusCore.");
1007 m_State = ClientState::ClientState_Disconnected;
1008 return ClientReturnCode::ClientReturnCode_FailedToConnect;
1016 const std::string t_FingerNames[NUM_FINGERS_ON_HAND] = {
"[thumb] ",
"[index] ",
"[middle]",
"[ring] ",
"[pinky] " };
1017 const std::string t_FingerJointNames[NUM_FINGERS_ON_HAND] = {
"mcp",
"pip",
"dip" };
1018 const std::string t_ThumbJointNames[NUM_FINGERS_ON_HAND] = {
"cmc",
"mcp",
"ip " };
1020 int t_DataOffset = 0;
1021 if (!p_Left)t_DataOffset = 20;
1023 const std::string* t_JointNames = t_ThumbJointNames;
1024 for (
unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1026 spdlog::info(
"{} {} spread: {:>6}, {} stretch: {:>6}, {} stretch: {:>6}, {} stretch: {:>6} ",
1027 t_FingerNames[t_FingerNumber],
1036 t_JointNames = t_FingerJointNames;
1045 spdlog::info(
" -- Ergo Timestamp {:02d}:{:02d}:{:02d}.{:03d} ~ {:02d}/{:02d}/{:d}(D/M/Y)",
1055 spdlog::info(
" ...No Data...");
1064 spdlog::info(
" ...No Data...");
1074 case DeviceClassType_Dongle:
1076 case DeviceClassType_Glove:
1078 case DeviceClassType_Glongle:
1079 return "Glongle (Glove Dongle)";
1089 case DeviceFamilyType_Prime1:
1091 case DeviceFamilyType_Prime2:
1093 case DeviceFamilyType_PrimeX:
1095 case DeviceFamilyType_Quantum:
1106 uint32_t t_DongleCount = 0;
1107 if (CoreSdk_GetNumberOfDongles(&t_DongleCount) != SDKReturnCode::SDKReturnCode_Success)
return;
1108 if (t_DongleCount == 0)
return;
1110 uint32_t* t_DongleIds =
new uint32_t[t_DongleCount]();
1111 if (CoreSdk_GetDongleIds(t_DongleIds, t_DongleCount) != SDKReturnCode::SDKReturnCode_Success)
return;
1113 DongleLandscapeData t_DongleData;
1115 for (uint32_t i = 0; i < t_DongleCount; i++)
1117 SDKReturnCode t_Result = CoreSdk_GetDataForDongle(t_DongleIds[i], &t_DongleData);
1118 spdlog::info(
" -- Dongle -- 0x{:X}", t_DongleData.id);
1119 if (t_Result == SDKReturnCode::SDKReturnCode_Success)
1121 spdlog::info(
" Type: {} - {}",
1124 spdlog::info(
" License: {}", t_DongleData.licenseType);
1128 spdlog::info(
" ...No Data...");
1184 uint32_t t_NumberOfAvailabletrackers = 0;
1185 SDKReturnCode t_TrackerResult = CoreSdk_GetNumberOfAvailableTrackers(&t_NumberOfAvailabletrackers);
1186 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1188 spdlog::error(
"Failed to get tracker data. The error given was {}.", t_TrackerResult);
1192 spdlog::info(
"received available trackers :{} ", t_NumberOfAvailabletrackers);
1194 if (t_NumberOfAvailabletrackers == 0)
return;
1195 TrackerId* t_TrackerId =
new TrackerId[t_NumberOfAvailabletrackers];
1196 t_TrackerResult = CoreSdk_GetIdsOfAvailableTrackers(t_TrackerId, t_NumberOfAvailabletrackers);
1197 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1199 spdlog::error(
"Failed to get tracker data. The error given was {}.", t_TrackerResult);
1207 uint32_t t_NumberOfAvailableUsers = 0;
1208 SDKReturnCode t_UserResult = CoreSdk_GetNumberOfAvailableUsers(&t_NumberOfAvailableUsers);
1209 if (t_UserResult != SDKReturnCode::SDKReturnCode_Success)
1211 spdlog::error(
"Failed to get user count. The error given was {}.", t_UserResult);
1214 if (t_NumberOfAvailableUsers == 0)
return;
1217 for (uint32_t i = 0; i < t_NumberOfAvailableUsers; i++)
1219 uint32_t t_NumberOfAvailabletrackers = 0;
1220 SDKReturnCode t_TrackerResult = CoreSdk_GetNumberOfAvailableTrackersForUserIndex(&t_NumberOfAvailabletrackers, i);
1221 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1223 spdlog::error(
"Failed to get tracker data. The error given was {}.", t_TrackerResult);
1227 if (t_NumberOfAvailabletrackers == 0)
continue;
1229 spdlog::info(
"received available trackers for user index[{}] :{} ", i, t_NumberOfAvailabletrackers);
1231 if (t_NumberOfAvailabletrackers == 0)
return;
1232 TrackerId* t_TrackerId =
new TrackerId[t_NumberOfAvailabletrackers];
1233 t_TrackerResult = CoreSdk_GetIdsOfAvailableTrackersForUserIndex(t_TrackerId, i, t_NumberOfAvailabletrackers);
1234 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1236 spdlog::error(
"Failed to get tracker data. The error given was {}.", t_TrackerResult);
1246 case TimecodeFPS::TimecodeFPS_23_976:
1247 return "23.976 FPS (24 dropframe)";
1248 case TimecodeFPS::TimecodeFPS_24:
1250 case TimecodeFPS::TimecodeFPS_25:
1252 case TimecodeFPS::TimecodeFPS_29_97:
1253 return "29.97 FPS (30 dropframe)";
1254 case TimecodeFPS::TimecodeFPS_30:
1256 case TimecodeFPS::TimecodeFPS_50:
1258 case TimecodeFPS::TimecodeFPS_59_94:
1259 return "59.94 FPS (60 dropframe)";
1260 case TimecodeFPS::TimecodeFPS_60:
1263 return "Undefined FPS";
1269 spdlog::info(
"Total count of Interfaces: {}",
m_Landscape->time.interfaceCount);
1270 spdlog::info(
"Current Interface: {} {} at index {}",
m_Landscape->time.currentInterface.name,
m_Landscape->time.currentInterface.api,
m_Landscape->time.currentInterface.index);
1273 spdlog::info(
"Fake signal: {} | Sync Pulse: {} | Sync Status: {}",
m_Landscape->time.fakeTimecode,
m_Landscape->time.useSyncPulse,
m_Landscape->time.syncStatus);
1274 spdlog::info(
"Device keep alive: {} | Timecode Status: {}",
m_Landscape->time.deviceKeepAlive,
m_Landscape->time.timecodeStatus);
1284 case ChainType::ChainType_FingerIndex:
1286 spdlog::info(
"received Skeleton chain type: ChainType_FingerIndex");
1289 case ChainType::ChainType_FingerMiddle:
1291 spdlog::info(
"received Skeleton chain type: ChainType_FingerMiddle");
1294 case ChainType::ChainType_FingerPinky:
1296 spdlog::info(
"received Skeleton chain type: ChainType_FingerPinky");
1299 case ChainType::ChainType_FingerRing:
1301 spdlog::info(
"received Skeleton chain type: ChainType_FingerRing");
1304 case ChainType::ChainType_FingerThumb:
1306 spdlog::info(
"received Skeleton chain type: ChainType_FingerThumb");
1309 case ChainType::ChainType_Hand:
1311 spdlog::info(
"received Skeleton chain type: ChainType_Hand");
1314 case ChainType::ChainType_Head:
1316 spdlog::info(
"received Skeleton chain type: ChainType_Head");
1319 case ChainType::ChainType_Leg:
1321 spdlog::info(
"received Skeleton chain type: ChainType_Leg");
1324 case ChainType::ChainType_Neck:
1326 spdlog::info(
"received Skeleton chain type: ChainType_Neck");
1329 case ChainType::ChainType_Pelvis:
1331 spdlog::info(
"received Skeleton chain type: ChainType_Pelvis");
1334 case ChainType::ChainType_Shoulder:
1336 spdlog::info(
"received Skeleton chain type: ChainType_Shoulder");
1339 case ChainType::ChainType_Spine:
1341 spdlog::info(
"received Skeleton chain type: ChainType_Spine");
1344 case ChainType::ChainType_Arm:
1346 spdlog::info(
"received Skeleton chain type: ChainType_Arm");
1349 case ChainType::ChainType_Invalid:
1352 spdlog::info(
"received Skeleton chain type: ChainType_Invalid");
1370 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1372 spdlog::error(
"Failed to get temporary skeleton. The error given was {}.", t_Res);
1407 static uint32_t t_TotalNumberOfTemporarySkeletonsInCore = 0;
1408 auto t_TimeSinceLastTemporarySkeletonUpdate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() -
m_LastTemporarySkeletonUpdate).count();
1411 spdlog::info(
"Total number of temporary skeletons in core: {} ", t_TotalNumberOfTemporarySkeletonsInCore);
1414 TemporarySkeletonCountForAllSessions t_TemporarySkeletonCountForAllSessions;
1415 SDKReturnCode t_Res = CoreSdk_GetTemporarySkeletonCountForAllSessions(&t_TemporarySkeletonCountForAllSessions);
1416 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1418 spdlog::error(
"Failed to get all temporary skeletons. The error given was {}.", t_Res);
1422 t_TotalNumberOfTemporarySkeletonsInCore = 0;
1423 for (uint32_t i = 0; i < t_TemporarySkeletonCountForAllSessions.sessionsCount; i++)
1425 t_TotalNumberOfTemporarySkeletonsInCore += t_TemporarySkeletonCountForAllSessions.temporarySkeletonCountForSessions[i].skeletonCount;
1429 spdlog::info(
"Total number of temporary skeletons in core: {} ", t_TotalNumberOfTemporarySkeletonsInCore);
1441 uint32_t t_DongleId = 0;
1442 uint32_t t_GloveIds[2] = { 0,0 };
1443 uint32_t t_DongleCount = 0;
1444 if (CoreSdk_GetNumberOfDongles(&t_DongleCount) != SDKReturnCode::SDKReturnCode_Success)
return;
1445 if (t_DongleCount == 0)
return;
1447 uint32_t* t_DongleIds =
new uint32_t[t_DongleCount]();
1448 if (CoreSdk_GetDongleIds(t_DongleIds, t_DongleCount) != SDKReturnCode::SDKReturnCode_Success)
return;
1450 for (uint32_t i = 0; i < t_DongleCount; i++)
1453 CoreSdk_GetGlovesForDongle(t_DongleIds[i], &t_GloveIds[0], &t_GloveIds[1]);
1454 if (!t_GloveIds[0] && !t_GloveIds[1])
continue;
1455 t_DongleId = t_DongleIds[i];
1458 if (t_DongleId == 0)
return;
1461 const int t_LeftHand = 0;
1462 const int t_RightHand = 1;
1466 t_HapticState[t_LeftHand].shouldHapticFinger[1] =
GetKey(
'4');
1467 t_HapticState[t_LeftHand].shouldHapticFinger[2] =
GetKey(
'3');
1468 t_HapticState[t_LeftHand].shouldHapticFinger[3] =
GetKey(
'2');
1469 t_HapticState[t_LeftHand].shouldHapticFinger[4] =
GetKey(
'1');
1470 t_HapticState[t_RightHand].shouldHapticFinger[0] =
GetKey(
'6');
1471 t_HapticState[t_RightHand].shouldHapticFinger[1] =
GetKey(
'7');
1472 t_HapticState[t_RightHand].shouldHapticFinger[2] =
GetKey(
'8');
1473 t_HapticState[t_RightHand].shouldHapticFinger[3] =
GetKey(
'9');
1474 t_HapticState[t_RightHand].shouldHapticFinger[4] =
GetKey(
'0');
1478 static std::chrono::high_resolution_clock::time_point s_TimeOfLastHapticsCommandSent;
1479 const std::chrono::high_resolution_clock::time_point s_Now = std::chrono::high_resolution_clock::now();
1480 const long long s_MillisecondsSinceLastHapticCommand = std::chrono::duration_cast<std::chrono::milliseconds>(s_Now - s_TimeOfLastHapticsCommandSent).count();
1488 const float s_FullPower = 1.0f;
1492 if (t_GloveIds[t_HandNumber] == 0)
continue;
1494 GloveLandscapeData t_Glove;
1495 if (CoreSdk_GetDataForGlove_UsingGloveId(t_GloveIds[t_HandNumber], &t_Glove) != SDKReturnCode::SDKReturnCode_Success)
1500 if (t_Glove.familyType != DeviceFamilyType::DeviceFamilyType_Prime1)
1507 uint32_t* t_HapticsDongles =
new uint32_t[MAX_NUMBER_OF_DONGLES];
1510 uint32_t t_NumberOfHapticsDongles = 0;
1511 if ((CoreSdk_GetNumberOfHapticsDongles(&t_NumberOfHapticsDongles) != SDKReturnCode::SDKReturnCode_Success) ||
1512 (t_NumberOfHapticsDongles == 0))
1517 if (CoreSdk_GetHapticsDongleIds(t_HapticsDongles, t_NumberOfHapticsDongles) != SDKReturnCode::SDKReturnCode_Success)
1522 float t_HapticsPowers[NUM_FINGERS_ON_HAND]{};
1523 for (
unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1525 t_HapticsPowers[t_FingerNumber] = t_HapticState[t_HandNumber].shouldHapticFinger[t_FingerNumber] ? s_FullPower : 0.0f;
1528 GloveLandscapeData t_GloveLandscapeData;
1529 if (CoreSdk_GetDataForGlove_UsingGloveId(t_GloveIds[t_HandNumber], &t_GloveLandscapeData) != SDKReturnCode::SDKReturnCode_Success)
1533 if (!t_GloveLandscapeData.isHaptics)
1538 CoreSdk_VibrateFingers(t_HapticsDongles[0], s_Hands[t_HandNumber], t_HapticsPowers);
1540 delete[] t_HapticsDongles;
1567 const int t_LeftHand = 0;
1568 const int t_RightHand = 1;
1572 t_HapticState[t_LeftHand].shouldHapticFinger[1] =
GetKey(
'4');
1573 t_HapticState[t_LeftHand].shouldHapticFinger[2] =
GetKey(
'3');
1574 t_HapticState[t_LeftHand].shouldHapticFinger[3] =
GetKey(
'2');
1575 t_HapticState[t_LeftHand].shouldHapticFinger[4] =
GetKey(
'1');
1576 t_HapticState[t_RightHand].shouldHapticFinger[0] =
GetKey(
'6');
1577 t_HapticState[t_RightHand].shouldHapticFinger[1] =
GetKey(
'7');
1578 t_HapticState[t_RightHand].shouldHapticFinger[2] =
GetKey(
'8');
1579 t_HapticState[t_RightHand].shouldHapticFinger[3] =
GetKey(
'9');
1580 t_HapticState[t_RightHand].shouldHapticFinger[4] =
GetKey(
'0');
1584 static std::chrono::high_resolution_clock::time_point s_TimeOfLastHapticsCommandSent;
1585 const std::chrono::high_resolution_clock::time_point s_Now = std::chrono::high_resolution_clock::now();
1586 const long long s_MillisecondsSinceLastHapticCommand = std::chrono::duration_cast<std::chrono::milliseconds>(s_Now - s_TimeOfLastHapticsCommandSent).count();
1594 const float s_FullPower = 1.0f;
1600 float t_HapticsPowers[NUM_FINGERS_ON_HAND]{};
1601 for (
unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1603 t_HapticsPowers[t_FingerNumber] = t_HapticState[t_HandNumber].shouldHapticFinger[t_FingerNumber] ? s_FullPower : 0.0f;
1605 bool t_IsHaptics =
false;
1606 if (CoreSdk_DoesSkeletonGloveSupportHaptics(
m_Skeleton->
skeletons[0].info.id, s_Hands[t_HandNumber], &t_IsHaptics) != SDKReturnCode::SDKReturnCode_Success)
1614 CoreSdk_VibrateFingersForSkeleton(
m_Skeleton->
skeletons[0].info.id, s_Hands[t_HandNumber], t_HapticsPowers);
1668 TrackerId t_TrackerId;
1669 CopyString(t_TrackerId.id,
sizeof(t_TrackerId.id), std::string(
"Test Tracker"));
1670 TrackerData t_TrackerData = {};
1671 t_TrackerData.isHmd =
false;
1672 t_TrackerData.trackerId = t_TrackerId;
1673 t_TrackerData.trackerType = TrackerType::TrackerType_Unknown;
1675 t_TrackerData.rotation = { 1.0f, 0.0f, 0.0f, 0.0f };
1676 t_TrackerData.quality = TrackerQuality::TrackingQuality_Trackable;
1677 TrackerData t_TrackerDatas[MAX_NUMBER_OF_TRACKERS];
1678 t_TrackerDatas[0] = t_TrackerData;
1680 const SDKReturnCode t_TrackerSend = CoreSdk_SendDataForTrackers(t_TrackerDatas, 1);
1681 if (t_TrackerSend != SDKReturnCode::SDKReturnCode_Success)
1683 spdlog::error(
"Failed to send tracker data. The error given was {}.", t_TrackerSend);
1705 NodeSetup_Init(&t_Node);
1707 CopyString(t_Node.name,
sizeof(t_Node.name), p_Name);
1708 t_Node.type = NodeType::NodeType_Joint;
1710 t_Node.parentID = p_ParentId;
1711 t_Node.settings.usedSettings = NodeSettingsFlag::NodeSettingsFlag_None;
1713 t_Node.transform.position.x = p_PosX;
1714 t_Node.transform.position.y = p_PosY;
1715 t_Node.transform.position.z = p_PosZ;
1737 const uint32_t t_NumFingers = 5;
1738 const uint32_t t_NumJoints = 4;
1742 ManusVec3 t_Fingers[t_NumFingers * t_NumJoints] = {
1778 SDKReturnCode t_Res = CoreSdk_AddNodeToSkeletonSetup(p_SklIndex,
CreateNodeSetup(0, 0, 0, 0, 0,
"Hand"));
1779 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1781 spdlog::error(
"Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
1787 for (uint32_t i = 0; i < t_NumFingers; i++)
1789 uint32_t t_ParentID = 0;
1791 for (uint32_t j = 0; j < t_NumJoints; j++)
1793 t_Res = CoreSdk_AddNodeToSkeletonSetup(p_SklIndex,
CreateNodeSetup(1 + t_FingerId + j, t_ParentID, t_Fingers[i * 4 + j].x, t_Fingers[i * 4 + j].y, t_Fingers[i * 4 + j].z,
"fingerdigit"));
1794 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1796 printf(
"Failed to Add Node To Skeleton Setup. The error given %d.", t_Res);
1799 t_ParentID = 1 + t_FingerId + j;
1801 t_FingerId += t_NumJoints;
1815 ChainSettings t_ChainSettings;
1816 ChainSettings_Init(&t_ChainSettings);
1817 t_ChainSettings.usedSettings = ChainType::ChainType_Hand;
1818 t_ChainSettings.hand.handMotion = HandMotion::HandMotion_IMU;
1819 t_ChainSettings.hand.fingerChainIdsUsed = 5;
1820 t_ChainSettings.hand.fingerChainIds[0] = 1;
1821 t_ChainSettings.hand.fingerChainIds[1] = 2;
1822 t_ChainSettings.hand.fingerChainIds[2] = 3;
1823 t_ChainSettings.hand.fingerChainIds[3] = 4;
1824 t_ChainSettings.hand.fingerChainIds[4] = 5;
1827 ChainSetup_Init(&t_Chain);
1829 t_Chain.type = ChainType::ChainType_Hand;
1830 t_Chain.dataType = ChainType::ChainType_Hand;
1831 t_Chain.side = Side::Side_Left;
1832 t_Chain.dataIndex = 0;
1833 t_Chain.nodeIdCount = 1;
1834 t_Chain.nodeIds[0] = 0;
1835 t_Chain.settings = t_ChainSettings;
1837 SDKReturnCode t_Res = CoreSdk_AddChainToSkeletonSetup(p_SklIndex, t_Chain);
1838 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1840 spdlog::error(
"Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
1846 const ChainType t_FingerTypes[5] = { ChainType::ChainType_FingerThumb,
1847 ChainType::ChainType_FingerIndex,
1848 ChainType::ChainType_FingerMiddle,
1849 ChainType::ChainType_FingerRing,
1850 ChainType::ChainType_FingerPinky };
1851 for (
int i = 0; i < 5; i++)
1853 ChainSettings t_ChainSettings;
1854 ChainSettings_Init(&t_ChainSettings);
1855 t_ChainSettings.usedSettings = t_FingerTypes[i];
1856 t_ChainSettings.finger.handChainId = 0;
1859 t_ChainSettings.finger.metacarpalBoneId = -1;
1860 t_ChainSettings.finger.useLeafAtEnd =
false;
1862 ChainSetup_Init(&t_Chain);
1864 t_Chain.type = t_FingerTypes[i];
1865 t_Chain.dataType = t_FingerTypes[i];
1866 t_Chain.side = Side::Side_Left;
1867 t_Chain.dataIndex = 0;
1870 t_Chain.nodeIdCount = 4;
1871 t_Chain.nodeIds[0] = 1;
1872 t_Chain.nodeIds[1] = 2;
1873 t_Chain.nodeIds[2] = 3;
1874 t_Chain.nodeIds[3] = 4;
1878 t_Chain.nodeIdCount = 4;
1879 t_Chain.nodeIds[0] = (i * 4) + 1;
1880 t_Chain.nodeIds[1] = (i * 4) + 2;
1881 t_Chain.nodeIds[2] = (i * 4) + 3;
1882 t_Chain.nodeIds[3] = (i * 4) + 4;
1884 t_Chain.settings = t_ChainSettings;
1886 SDKReturnCode t_Res = CoreSdk_AddChainToSkeletonSetup(p_SklIndex, t_Chain);
1887 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1903 uint32_t t_SklIndex = 0;
1905 SkeletonSetupInfo t_SKL;
1906 SkeletonSetupInfo_Init(&t_SKL);
1907 t_SKL.type = SkeletonType::SkeletonType_Hand;
1908 t_SKL.settings.scaleToTarget =
true;
1909 t_SKL.settings.useEndPointApproximations =
true;
1910 t_SKL.settings.targetType = SkeletonTargetType::SkeletonTarget_UserIndexData;
1913 t_SKL.settings.skeletonTargetUserIndexData.userIndex = 0;
1915 CopyString(t_SKL.name,
sizeof(t_SKL.name), std::string(
"LeftHand"));
1917 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
1918 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1920 spdlog::error(
"Failed to Create Skeleton Setup. The error given was {}.", t_Res);
1931 t_Res = CoreSdk_LoadSkeleton(t_SklIndex, &t_ID);
1932 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1934 spdlog::error(
"Failed to load skeleton. The error given was {}.", t_Res);
1941 spdlog::error(
"Failed to give skeleton an ID.");
1951 spdlog::error(
"There was no skeleton for us to unload.");
1956 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1958 spdlog::error(
"Failed to unload skeleton. The error given was {}.", t_Res);
1971 uint32_t t_SklIndex = 0;
1973 SkeletonSettings t_Settings;
1974 SkeletonSettings_Init(&t_Settings);
1975 t_Settings.scaleToTarget =
true;
1976 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_UserData;
1977 t_Settings.skeletonTargetUserData.userID = 0;
1979 SkeletonSetupInfo t_SKL;
1980 SkeletonSetupInfo_Init(&t_SKL);
1982 t_SKL.type = SkeletonType::SkeletonType_Hand;
1983 t_SKL.settings = t_Settings;
1984 CopyString(t_SKL.name,
sizeof(t_SKL.name), std::string(
"hand"));
1986 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
1987 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1989 spdlog::error(
"Failed to Create Skeleton Setup. The error given was {}.", t_Res);
1998 t_Res = CoreSdk_AllocateChainsForSkeletonSetup(t_SklIndex);
1999 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2001 spdlog::error(
"Failed to allocate chains for skeleton. The error given was {}.", t_Res);
2006 SkeletonSetupArraySizes t_SkeletonInfo;
2007 t_Res = CoreSdk_GetSkeletonSetupArraySizes(t_SklIndex, &t_SkeletonInfo);
2008 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2010 spdlog::error(
"Failed to get info about skeleton. The error given was {}.", t_Res);
2014 ChainSetup* t_Chains =
new ChainSetup[t_SkeletonInfo.chainsCount];
2016 t_Res = CoreSdk_GetSkeletonSetupChains(t_SklIndex, t_Chains);
2017 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2019 spdlog::error(
"Failed to get skeleton setup chains. The error given was {}.", t_Res);
2028 for (
size_t i = 0; i < t_SkeletonInfo.chainsCount; i++)
2030 if (t_Chains[i].dataType == ChainType::ChainType_Hand)
2032 t_Chains[i].side = Side::Side_Left;
2034 t_Res = CoreSdk_OverwriteChainToSkeletonSetup(t_SklIndex, t_Chains[i]);
2035 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2037 spdlog::error(
"Failed to overwrite Chain To Skeleton Setup. The error given was {}.", t_Res);
2049 t_Res = CoreSdk_LoadSkeleton(t_SklIndex, &t_ID);
2050 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2052 spdlog::error(
"Failed to load skeleton. The error given was {}.", t_Res);
2059 spdlog::error(
"Failed to give skeleton an ID.");
2077 bool t_IsSkeletonModified =
false;
2082 uint32_t t_SklIndex = 0;
2084 SkeletonSettings t_Settings;
2085 SkeletonSettings_Init(&t_Settings);
2086 t_Settings.scaleToTarget =
true;
2087 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_UserData;
2088 t_Settings.skeletonTargetUserData.userID = 0;
2090 SkeletonSetupInfo t_SKL;
2091 SkeletonSetupInfo_Init(&t_SKL);
2093 t_SKL.type = SkeletonType::SkeletonType_Body;
2094 t_SKL.settings = t_Settings;
2095 CopyString(t_SKL.name,
sizeof(t_SKL.name), std::string(
"body"));
2097 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2098 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2100 spdlog::error(
"Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2105 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex,
CreateNodeSetup(0, 0, 0, 0, 0,
"root"));
2106 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2108 spdlog::error(
"Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2112 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex,
CreateNodeSetup(1, 0, 0, 1, 0,
"branch"));
2113 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2115 spdlog::error(
"Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2119 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex,
CreateNodeSetup(2, 1, 0, 2, 0,
"leaf"));
2120 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2122 spdlog::error(
"Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2127 ChainSettings t_ChainSettings;
2128 ChainSettings_Init(&t_ChainSettings);
2129 t_ChainSettings.usedSettings = ChainType::ChainType_Leg;
2130 t_ChainSettings.leg.footForwardOffset = 0;
2131 t_ChainSettings.leg.footSideOffset = 0;
2132 t_ChainSettings.leg.reverseKneeDirection =
false;
2133 t_ChainSettings.leg.kneeRotationOffset = 0;
2136 ChainSetup_Init(&t_Chain);
2138 t_Chain.type = ChainType::ChainType_Leg;
2139 t_Chain.dataType = ChainType::ChainType_Leg;
2140 t_Chain.dataIndex = 0;
2141 t_Chain.nodeIdCount = 3;
2142 t_Chain.nodeIds[0] = 0;
2143 t_Chain.nodeIds[1] = 1;
2144 t_Chain.nodeIds[2] = 2;
2145 t_Chain.settings = t_ChainSettings;
2146 t_Chain.side = Side::Side_Left;
2148 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chain);
2149 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2151 spdlog::error(
"Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
2156 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2157 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2159 spdlog::error(
"Failed to save temporary skeleton. The error given was {}.", t_Res);
2165 t_Res = CoreSdk_GetTemporarySkeleton(t_SklIndex, t_SessionId);
2166 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2168 spdlog::error(
"Failed to get temporary skeleton. The error given was {}.", t_Res);
2173 t_ChainSettings.usedSettings = ChainType::ChainType_Head;
2176 t_Chain.type = ChainType::ChainType_Head;
2177 t_Chain.dataType = ChainType::ChainType_Head;
2178 t_Chain.dataIndex = 0;
2179 t_Chain.nodeIdCount = 1;
2180 t_Chain.nodeIds[0] = 0;
2181 t_Chain.settings = t_ChainSettings;
2182 t_Chain.side = Side::Side_Center;
2184 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chain);
2185 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2187 spdlog::error(
"Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
2192 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2193 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2195 spdlog::error(
"Failed to save temporary skeleton. The error given was {}.", t_Res);
2200 SkeletonSetupArraySizes t_SkeletonInfo;
2201 t_Res = CoreSdk_GetSkeletonSetupArraySizes(t_SklIndex, &t_SkeletonInfo);
2202 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2204 spdlog::error(
"Failed to get info about skeleton. The error given was {}.", t_Res);
2209 ChainSetup* t_Chains =
new ChainSetup[t_SkeletonInfo.chainsCount];
2210 t_Res = CoreSdk_GetSkeletonSetupChains(t_SklIndex, t_Chains);
2211 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2213 spdlog::error(
"Failed to get skeleton setup chains. The error given was {}.", t_Res);
2218 NodeSetup* t_Nodes =
new NodeSetup[t_SkeletonInfo.nodesCount];
2219 t_Res = CoreSdk_GetSkeletonSetupNodes(t_SklIndex, t_Nodes);
2220 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2222 spdlog::error(
"Failed to get skeleton setup nodes. The error given was {}.", t_Res);
2227 SkeletonSetupInfo t_SKeletonSetupInfo;
2228 SkeletonSetupInfo_Init(&t_SKeletonSetupInfo);
2229 t_Res = CoreSdk_GetSkeletonSetupInfo(t_SklIndex, &t_SKeletonSetupInfo);
2230 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2232 spdlog::error(
"Failed to overwrite Skeleton Setup. The error given was {}.", t_Res);
2238 SkeletonSettings_Init(&t_Settings);
2239 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_GloveData;
2241 t_SKL.settings = t_Settings;
2242 CopyString(t_SKL.name,
sizeof(t_SKL.name), std::string(
"body2"));
2245 t_Res = CoreSdk_OverwriteSkeletonSetup(t_SklIndex, t_SKL);
2246 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2248 spdlog::error(
"Failed to overwrite Skeleton Setup. The error given was {}.", t_Res);
2253 t_Chains[0].side = Side::Side_Right;
2254 t_Nodes[0].type = NodeType::NodeType_Mesh;
2257 for (
size_t i = 0; i < t_SkeletonInfo.nodesCount; i++)
2259 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex, t_Nodes[i]);
2260 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2262 spdlog::error(
"Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2268 for (
size_t i = 0; i < t_SkeletonInfo.chainsCount; i++)
2270 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chains[i]);
2271 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2273 spdlog::error(
"Failed to Add Chains To Skeleton Setup. The error given was {}.", t_Res);
2286 t_IsSkeletonModified =
true;
2287 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2288 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2290 spdlog::error(
"Failed to save temporary skeleton. The error given was {}.", t_Res);
2302 spdlog::error(
"There are no Temporary Skeletons to clear!");
2306 SDKReturnCode t_Res = CoreSdk_ClearTemporarySkeleton(t_SklIndex,
m_SessionId);
2307 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2309 spdlog::error(
"Failed to Clear Temporary Skeleton. The error given was {}.", t_Res);
2321 spdlog::error(
"There are no Temporary Skeletons to clear!");
2324 SDKReturnCode t_Res = CoreSdk_ClearAllTemporarySkeletons();
2325 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2327 spdlog::error(
"Failed to Clear All Temporary Skeletons. The error given was {}.", t_Res);
2341 bool t_IsSkeletonModified =
false;
2345 uint32_t t_SklIndex = 0;
2347 SkeletonSetupInfo t_SKL;
2348 SkeletonSetupInfo_Init(&t_SKL);
2349 t_SKL.type = SkeletonType::SkeletonType_Hand;
2350 t_SKL.settings.scaleToTarget =
true;
2351 t_SKL.settings.targetType = SkeletonTargetType::SkeletonTarget_GloveData;
2352 t_SKL.settings.skeletonTargetUserIndexData.userIndex = 0;
2354 CopyString(t_SKL.name,
sizeof(t_SKL.name), std::string(
"LeftHand"));
2356 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2357 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2359 spdlog::error(
"Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2369 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2370 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2372 spdlog::error(
"Failed to save temporary skeleton. The error given was {}.", t_Res);
2377 uint32_t t_TemporarySkeletonLengthInBytes;
2379 t_Res = CoreSdk_CompressTemporarySkeletonAndGetSize(t_SklIndex, t_SessionId, &t_TemporarySkeletonLengthInBytes);
2380 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2382 spdlog::error(
"Failed to compress temporary skeleton and get size. The error given was {}.", t_Res);
2385 unsigned char* t_TemporarySkeletonData =
new unsigned char[t_TemporarySkeletonLengthInBytes];
2389 t_Res = CoreSdk_GetCompressedTemporarySkeletonData(t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2390 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2392 spdlog::error(
"Failed to get compressed temporary skeleton data. The error given was {}.", t_Res);
2402 std::string t_DirectoryPath =
2403 t_DirectoryPathString
2405 +
"ManusTemporarySkeleton";
2409 std::string t_DirectoryPathAndFileName =
2412 +
"TemporarySkeleton.mskl";
2416 t_File.write((
char*)t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2419 t_Res = CoreSdk_ClearTemporarySkeleton(t_SklIndex, t_SessionId);
2420 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2422 spdlog::error(
"Failed to Clear Temporary Skeleton after saving. The error given was {}.", t_Res);
2438 std::string t_DirectoryPath =
2439 t_DirectoryPathString
2441 +
"ManusTemporarySkeleton";
2445 SPDLOG_WARN(
"Failed to read from client file, the mentioned directory does not exist");
2450 std::string t_DirectoryPathAndFileName =
2453 +
"TemporarySkeleton.mskl";
2460 SPDLOG_WARN(
"Failed to read from client file, the file does not exist in the mentioned directory");
2465 t_File.seekg(0, t_File.end);
2466 int t_FileLength = (int)t_File.tellg();
2467 t_File.seekg(0, t_File.beg);
2470 unsigned char* t_TemporarySkeletonData =
new unsigned char[t_FileLength];
2471 t_File.read((
char*)t_TemporarySkeletonData, t_FileLength);
2476 uint32_t t_TemporarySkeletonLengthInBytes = t_FileLength;
2478 if (t_TemporarySkeletonData ==
nullptr)
2480 SPDLOG_WARN(
"Failed to read the compressed temporary skeleton data from file");
2481 delete[] t_TemporarySkeletonData;
2486 SkeletonSetupInfo t_SKL;
2487 SkeletonSetupInfo_Init(&t_SKL);
2488 uint32_t t_SklIndex = 0;
2489 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2490 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2492 spdlog::error(
"Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2501 SDKReturnCode t_Result = CoreSdk_GetTemporarySkeletonFromCompressedData(t_SklIndex, t_SessionId, t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2502 if (t_Result != SDKReturnCode::SDKReturnCode_Success)
2504 SPDLOG_WARN(
"Failed to load temporary skeleton data from client file in Core, the error code was: {}.", t_Result);
2508 delete[] t_TemporarySkeletonData;
2513 ManusTimestamp t_TS;
2514 ManusTimestamp_Init(&t_TS);
2515 ManusTimestampInfo t_TSInfo;
2516 ManusTimestampInfo_Init(&t_TSInfo);
2517 t_TSInfo.fraction = 69;
2518 t_TSInfo.second = 6;
2519 t_TSInfo.minute = 9;
2523 t_TSInfo.year = 6969;
2524 t_TSInfo.timecode =
true;
2526 CoreSdk_SetTimestampInfo(&t_TS, t_TSInfo);
2528 ManusTimestampInfo t_TSInfo2;
2529 CoreSdk_GetTimestampInfo(t_TS, &t_TSInfo2);
std::string ConvertDeviceClassTypeToString(DeviceClassType p_Type)
std::string ConvertDeviceFamilyTypeToString(DeviceFamilyType p_Type)
#define GO_TO_DISPLAY(p_Key, p_Function)
std::string GetFPSEnumName(TimecodeFPS p_FPS)
#define GO_TO_MENU_IF_REQUESTED()
std::string m_SystemMessage
void PrintSystemMessage()
Prints the last received system messages received from Core.
void ApplyConsolePosition(const int p_ConsoleCurrentOffset)
Set the current console position. This handles the platform-specific part of advancing the console po...
virtual ClientReturnCode NoHostsFound()
When no available hosts are found the user can either retry or exit.
void ClearAllTemporarySkeletons()
This support function is used to clear all temporary skeletons associated to the current SDK session,...
ClientReturnCode ShutDown()
When you are done with the SDK, don't forget to nicely shut it down this will close all connections t...
virtual ClientReturnCode DisplayingDataTracker()
ClientReturnCode Run()
The main SDKClient loop. This is a simple state machine which switches between different substates.
virtual ClientReturnCode DisplayingLandscapeTimeData()
ManusTimestampInfo m_ErgoTimestampInfo
static void ClearConsole(void)
Clear the console window.
void PrintSkeletonInfo()
Prints the type of the first chain generated by the AllocateChain function, this is used for testing.
virtual ClientReturnCode ReconnectingToCore(int32_t p_ReconnectionTime=0, int32_t p_ReconnectionAttempts=0)
It is called when the sdk is disconnected from Core and the user select one of the options to reconne...
void AdvanceConsolePosition(short int p_Y)
Set the position that the next log message will appear at. Using this allows us to have somewhat of a...
void PrintHandErgoData(ErgonomicsData &p_ErgoData, bool p_Left)
Prints the ergonomics data of a hand.
ClientSkeletonCollection * m_NextSkeleton
ErgonomicsData m_RightGloveErgoData
bool m_TrackerDataDisplayPerUser
void ClearTemporarySkeleton()
This support function is used to clear a temporary skeleton from the temporary skeleton list,...
void UpdateInput(void)
Update the current keyboard state.
uint32_t m_FirstRightGloveID
std::chrono::time_point< std::chrono::high_resolution_clock > m_TimeSinceLastDisconnect
const short int m_ConsoleWidth
ClientReturnCode Initialize()
Initialize the sample console and the SDK. This function attempts to resize the console window and th...
bool PlatformSpecificInitialization(void)
Initialise things only needed for this platform.
uint32_t m_SecondsToFindHosts
bool m_ShouldConnectLocally
virtual ClientReturnCode UpdateBeforeDisplayingData()
Some things happen before every display update, no matter what state. They happen here,...
virtual ClientReturnCode LookingForHosts()
Simple example of the SDK looking for manus core hosts on the network and display them on screen.
virtual ClientReturnCode InitializeSDK()
Initialize the sdk, register the callbacks and set the coordinate system. This needs to be done befor...
bool SetupHandChains(uint32_t p_SklIndex)
This function sets up some basic hand chains. Chains are required for a Skeleton to be able to be ani...
static void OnSystemCallback(const SystemMessage *const p_SystemMessage)
This gets called when receiving a system message from Core.
virtual ClientReturnCode RegisterAllCallbacks()
Used to register the callbacks between sdk and core. Callbacks that are registered functions that get...
uint32_t m_ConsoleClearTickCount
static SDKClient * s_Instance
bool GetKeyDown(const int p_Key)
Returns true first time it is called when key is pressed.
void PrintTrackerData()
Prints the tracker data Since our console cannot render this data visually in 3d (its not in the scop...
void PrintDongleData()
Print the ergonomics data received from Core.
virtual ClientReturnCode PickingConnectionType()
Overridable switch states of how the client flow is done. This is the first option screen in the clie...
void PrintSkeletonData()
Prints the finalized skeleton data received from Core. Since our console cannot render this data visu...
std::chrono::time_point< std::chrono::high_resolution_clock > m_LastTemporarySkeletonUpdate
virtual ClientReturnCode ConnectingToCore()
After a connection option was selected, the client will now try to connect to manus core via the SDK.
void LoadTestSkeleton()
This function sets up a very minimalistic hand skeleton. In order to have any 3d positional/rotationa...
static bool CopyString(char *const p_Target, const size_t p_MaxLengthThatWillFitInTarget, const std::string &p_Source)
Copy the given string into the given target.
virtual ClientReturnCode DisplayingDataTemporarySkeleton()
std::unique_ptr< ManusHost[]> m_AvailableHosts
void PrintTrackerDataGlobal()
Prints the tracker data without taking users into account. This shows how one can get the tracker dat...
virtual ClientReturnCode PickingHost()
Print the found hosts and give the user the option to select one.
float RoundFloatValue(float p_Value, int p_NumDecimalsToKeep)
Round the given float value so that it has no more than the given number of decimals.
virtual ClientReturnCode DisplayingData()
Once the connections are made we loop this function it calls all the input handlers for different asp...
bool ResizeWindow(const short int p_ConsoleWidth, const short int p_ConsoleHeight, const short int p_ConsoleScrollback)
Resize the window, so the log messages will fit. Make sure not to enter illegal sizes in here or SetC...
static void OnErgonomicsCallback(const ErgonomicsStream *const p_Ergo)
This gets called when receiving ergonomics data from Manus Core In our sample we only save the first ...
uint32_t m_SleepBetweenReconnectingAttemptsInMs
void HandleSkeletonCommands()
Handles the console commands for the skeletons.
SystemMessageType m_SystemMessageCode
uint32_t m_ModifiedSkeletonIndex
static void OnConnectedCallback(const ManusHost *const p_Host)
Gets called when the client is connects to manus core Using this callback is optional....
uint32_t m_HostToConnectTo
void RemoveIndexFromTemporarySkeletonList(uint32_t p_Idx)
std::mutex m_LandscapeMutex
std::mutex m_SkeletonMutex
static ManusVec3 CreateManusVec3(float p_X, float p_Y, float p_Z)
bool DoesFolderOrFileExist(std::string p_Path_UTF8)
Check if the given folder or file exists. The folder path given should be in UTF-8 format.
int m_ConsoleCurrentOffset
std::vector< uint32_t > m_LoadedSkeletons
void HandleHapticCommands()
This showcases haptics support on gloves. Send haptics commands to connected gloves if specific keys ...
bool SetupHandNodes(uint32_t p_SklIndex)
This support function sets up the nodes for the skeleton hand In order to have any 3d positional/rota...
std::function< ClientReturnCode()> m_CurrentInteraction
virtual ClientReturnCode DisplayingDataSkeleton()
std::vector< uint32_t > m_TemporarySkeletons
bool PlatformSpecificShutdown(void)
Shut down things only needed for this platform.
void GetTemporarySkeletonFromFile()
void AllocateChains()
This support function sets up an incomplete hand skeleton and then uses manus core to allocate chains...
void HandleTrackerCommands()
This support function is used to set a test tracker and add it to the landscape.
void SaveTemporarySkeletonToFile()
virtual ClientReturnCode RestartSDK()
Used to restart and initialize the SDK to make sure a new connection can be set up....
const short int m_ConsoleScrollback
void PrintLandscapeTimeData()
virtual ClientReturnCode DisplayingDataGlove()
display the ergonomics data of the gloves, and handles haptic commands.
virtual ClientReturnCode DisconnectedFromCore()
When the SDK loses the connection with Core the user can either close the sdk or try to reconnect to ...
static void OnDisconnectedCallback(const ManusHost *const p_Host)
Gets called when the client disconnects from manus core. This callback is optional and in the sample ...
bool GetKey(const int p_Key)
Gets key's current state. True is pressed false is not pressed.
void UnloadTestSkeleton()
This support function is used to unload a skeleton from Core.
std::ofstream GetOutputFileStream(std::string p_Path_UTF8)
Get an output stream for the given file. The file's path should be in UTF-8 format.
int32_t m_SecondsToAttemptReconnecting
std::string GetDocumentsDirectoryPath_UTF8(void)
Get the path to the user's Documents folder. The string should be in UTF-8 format.
std::unique_ptr< ManusHost > m_Host
void PrintTrackerDataPerUser()
Prints the tracker data per user, this shows how to access this data for each user.
void HandleTemporarySkeletonCommands()
Handles the console commands for the temporary skeletons.
static void OnSkeletonStreamCallback(const SkeletonStreamInfo *const p_Skeleton)
This gets called when the client is connected to manus core.
std::mutex m_SystemMessageMutex
void CreateFolderIfItDoesNotExist(std::string p_Path_UTF8)
Create the given folder if it does not exist. The folder path given should be in UTF-8 format.
void GetTemporarySkeletonIfModified()
This support function checks if a temporary skeleton related to the current session has been modified...
void BuildTemporarySkeleton()
This support function is used for the manual allocation of the skeleton chains with means of a tempor...
void PrintErgonomicsData()
Print the ergonomics data received from Core.
bool shouldHapticFinger[NUM_FINGERS_ON_HAND]
uint32_t m_NumberOfHostsFound
static void OnLandscapeCallback(const Landscape *const p_Landscape)
This gets called when receiving landscape information from core.
static NodeSetup CreateNodeSetup(uint32_t p_Id, uint32_t p_ParentId, float p_PosX, float p_PosY, float p_PosZ, std::string p_Name)
Skeletons are pretty extensive in their data setup so we have several support functions so we can cor...
void PrintTemporarySkeletonInfo()
This support function gets the temporary skeletons for all sessions connected to Core and it prints t...
Landscape * m_NewLandscape
void HandleSkeletonHapticCommands()
This showcases haptics support on the skeletons. Send haptics commands to the gloves connected to a s...
ErgonomicsData m_LeftGloveErgoData
ClientState m_PreviousState
std::vector< ClientSkeleton > skeletons
const short int m_ConsoleHeight
int32_t m_MaxReconnectionAttempts
static const std::string s_SlashForFilesystemPath
The slash character that is used in the filesystem.
std::ifstream GetInputFileStream(std::string p_Path_UTF8)
Get an input stream for the given file. The file's path should be in UTF-8 format.
uint32_t m_FirstLeftGloveID
ClientSkeletonCollection * m_Skeleton
Used to store all the final animated skeletons received from Core.
constexpr unsigned long long int MINIMUM_MILLISECONDS_BETWEEN_HAPTICS_COMMANDS
Constant expression used to define the time between two possible haptics commands sent.
constexpr unsigned long long int MILLISECONDS_BETWEEN_TEMPORARY_SKELETONS_UPDATE
Constant expression used to define the time between two updates of the temporary skeleton count print...
constexpr unsigned int NUMBER_OF_HANDS_SUPPORTED
Constant expression: number of hands supported by demo.
ClientReturnCode
Values that can be returned by this application.
Haptic settings for a single glove.