C++ SDK for MANUS Core 2.0
Loading...
Searching...
No Matches
SDKClient.cpp
Go to the documentation of this file.
1#include "SDKClient.hpp"
2#include "ManusSDKTypes.h"
3#include <fstream>
4#include <iostream>
5
7
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;}
10
11#define GO_TO_MENU_IF_REQUESTED() if (GetKeyDown('Q')) { ClearConsole();\
12 m_CurrentInteraction = nullptr; return ClientReturnCode::ClientReturnCode_Success;}
13
15
17{
18 s_Instance = this;
19
20 // using initializers like these ensure that the data is set to its default values.
23
25}
26
28{
29 s_Instance = nullptr;
30}
31
35{
37 {
38 return ClientReturnCode::ClientReturnCode_FailedPlatformSpecificInitialization;
39 }
40
41 // although resizewindow is not technically needed to setup the SDK , it is nice to see what we are doing in this example client.
42 // thus we make sure we have a nice console window to use.
43 // if this fails, then the window is being resized during startup (due to windows management tools) or by giving it invalid values.
45 {
46 // An error message will be logged in the function, so don't print anything here.
47 return ClientReturnCode::ClientReturnCode_FailedToResizeWindow;
48 }
49
50 const ClientReturnCode t_IntializeResult = InitializeSDK();
51 if (t_IntializeResult != ClientReturnCode::ClientReturnCode_Success)
52 {
53 spdlog::error("Failed to initialize the Core functionality. The value returned was {}.", t_IntializeResult);
54 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
55 }
56
57 return ClientReturnCode::ClientReturnCode_Success;
58}
59
63{
65
66 ClientReturnCode t_Result{};
67 while (!m_RequestedExit)
68 {
70 {
72
74 }
75
77
78 // in this example SDK Client we have several phases during our main loop to make sure the SDK is in the right state to work.
80 switch (m_State)
81 {
82 case ClientState::ClientState_PickingConnectionType:
83 {
84 t_Result = PickingConnectionType();
85 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
86 } break;
87 case ClientState::ClientState_LookingForHosts:
88 {
89 t_Result = LookingForHosts();
90 if (t_Result != ClientReturnCode::ClientReturnCode_Success &&
91 t_Result != ClientReturnCode::ClientReturnCode_FailedToFindHosts) {
92 return t_Result;
93 }
94 } break;
95 case ClientState::ClientState_NoHostsFound:
96 {
97 t_Result = NoHostsFound();
98 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
99 } break;
100 case ClientState::ClientState_PickingHost:
101 {
102 t_Result = PickingHost();
103 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
104 } break;
105 case ClientState::ClientState_ConnectingToCore:
106 {
107 t_Result = ConnectingToCore();
108 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
109 } break;
110 case ClientState::ClientState_DisplayingData:
111 {
113 if (m_CurrentInteraction == nullptr)
114 {
115 t_Result = DisplayingData();
116 }
117 else
118 {
119 t_Result = m_CurrentInteraction();
120 }
121 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
122 } break;
123 case ClientState::ClientState_Disconnected:
124 {
125 t_Result = DisconnectedFromCore();
126 if (t_Result != ClientReturnCode::ClientReturnCode_Success) { return t_Result; }
127 }break;
128 default:
129 {
130 spdlog::error("Encountered the unrecognized state {}.", static_cast<int>(m_State));
131 return ClientReturnCode::ClientReturnCode_UnrecognizedStateEncountered;
132 }
133 } // switch(m_State)
134
136 {
137 spdlog::info("Pressed escape, so the client will now close.");
138
139 m_RequestedExit = true;
140 }
141
143 std::this_thread::sleep_for(std::chrono::milliseconds(10));
144 }
145
146 return ClientReturnCode::ClientReturnCode_Success;
147}
148
153{
154 const SDKReturnCode t_Result = CoreSdk_ShutDown();
155 if (t_Result != SDKReturnCode::SDKReturnCode_Success)
156 {
157 spdlog::error("Failed to shut down the SDK wrapper. The value returned was {}.", t_Result);
158 return ClientReturnCode::ClientReturnCode_FailedToShutDownSDK;
159 }
160
162 {
163 return ClientReturnCode::ClientReturnCode_FailedPlatformSpecificShutdown;
164 }
165
166 return ClientReturnCode::ClientReturnCode_Success;
167}
168
173{
174 spdlog::info("Connected to manus core.");
175
176 //No need to initialize these as they get filled in the CoreSdk_GetVersionsAndCheckCompatibility
177 ManusVersion t_SdkVersion;
178 ManusVersion t_CoreVersion;
179 bool t_IsCompatible;
180
181 const SDKReturnCode t_Result = CoreSdk_GetVersionsAndCheckCompatibility(&t_SdkVersion, &t_CoreVersion, &t_IsCompatible);
182
183 if (t_Result == SDKReturnCode::SDKReturnCode_Success)
184 {
185 const std::string t_Versions = "Sdk version : " + std::string(t_SdkVersion.versionInfo) + ", Core version : " + std::string(t_CoreVersion.versionInfo) + ".";
186
187 if (t_IsCompatible)
188 {
189 spdlog::info("Versions are compatible.{}", t_Versions);
190 }
191 else
192 {
193 spdlog::warn("Versions are not compatible with each other.{}", t_Versions);
194 }
195 }
196 else
197 {
198 spdlog::error("Failed to get the versions from the SDK. The value returned was {}.", t_Result);
199 }
200
201 uint32_t t_SessionId;
202 const SDKReturnCode t_SessionIdResult = CoreSdk_GetSessionId(&t_SessionId);
203 if (t_SessionIdResult == SDKReturnCode::SDKReturnCode_Success && t_SessionId != 0)
204 {
205 spdlog::info("Session Id: {}", t_SessionId);
206 s_Instance->m_SessionId = t_SessionId;
207 }
208 else
209 {
210 spdlog::info("Failed to get the Session ID from Core. The value returned was{}.", t_SessionIdResult);
211 }
212
213 ManusHost t_Host(*p_Host);
214 s_Instance->m_Host = std::make_unique<ManusHost>(t_Host);
215
216 // Only setting state to displaying data on automatic reconnect
217 if (s_Instance->m_State == ClientState::ClientState_Disconnected)
218 {
219 s_Instance->m_State = ClientState::ClientState_DisplayingData;
220 }
221}
222
226{
227 spdlog::info("Disconnected from manus core.");
228 s_Instance->m_TimeSinceLastDisconnect = std::chrono::high_resolution_clock::now();
229 ManusHost t_Host(*p_Host);
230 s_Instance->m_Host = std::make_unique<ManusHost>(t_Host);
231 s_Instance->m_State = ClientState::ClientState_Disconnected;
232}
233
236void SDKClient::OnSkeletonStreamCallback(const SkeletonStreamInfo* const p_SkeletonStreamInfo)
237{
238 if (s_Instance)
239 {
240 ClientSkeletonCollection* t_NxtClientSkeleton = new ClientSkeletonCollection();
241 t_NxtClientSkeleton->skeletons.resize(p_SkeletonStreamInfo->skeletonsCount);
242
243 for (uint32_t i = 0; i < p_SkeletonStreamInfo->skeletonsCount; i++)
244 {
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);
249 }
251 if (s_Instance->m_NextSkeleton != nullptr) delete s_Instance->m_NextSkeleton;
252 s_Instance->m_NextSkeleton = t_NxtClientSkeleton;
253 s_Instance->m_SkeletonMutex.unlock();
254 }
255}
256
259void SDKClient::OnLandscapeCallback(const Landscape* const p_Landscape)
260{
261 if (s_Instance == nullptr)return;
262
263 Landscape* t_Landscape = new Landscape(*p_Landscape);
265 if (s_Instance->m_NewLandscape != nullptr) delete s_Instance->m_NewLandscape;
266 s_Instance->m_NewLandscape = t_Landscape;
268}
269
270
273void SDKClient::OnSystemCallback(const SystemMessage* const p_SystemMessage)
274{
275 if (s_Instance)
276 {
278
279 switch (p_SystemMessage->type)
280 {
281 case SystemMessageType::SystemMessageType_TemporarySkeletonModified:
282 // if the message was triggered by a temporary skeleton being modified then save the skeleton index,
283 // this information will be used to get and load the skeleton into core
284 s_Instance->m_ModifiedSkeletonIndex = p_SystemMessage->infoUInt;
285 break;
286 default:
287 s_Instance->m_SystemMessageCode = p_SystemMessage->type;
288 s_Instance->m_SystemMessage = p_SystemMessage->infoString;
289 break;
290 }
292 }
293}
294
302{
303 if (s_Instance)
304 {
305 for (uint32_t i = 0; i < p_Ergo->dataCount; i++)
306 {
307 if (p_Ergo->data[i].isUserID)continue;
308
309 ErgonomicsData* t_Ergo = nullptr;
310 if (p_Ergo->data[i].id == s_Instance->m_FirstLeftGloveID)
311 {
313 }
314 if (p_Ergo->data[i].id == s_Instance->m_FirstRightGloveID)
315 {
317 }
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++)
323 {
324 t_Ergo->data[j] = p_Ergo->data[i].data[j];
325 }
326 }
327 }
328}
329
331float SDKClient::RoundFloatValue(float p_Value, int p_NumDecimalsToKeep)
332{
333 // Since C++11, powf is supposed to be declared in <cmath>.
334 // Unfortunately, gcc decided to be non-compliant on this for no apparent
335 // reason, so now we have to do this.
336 // https://stackoverflow.com/questions/5483930/powf-is-not-a-member-of-std
337 float t_Power = static_cast<float>(std::pow(
338 10.0,
339 static_cast<double>(p_NumDecimalsToKeep)));
340 return std::round(p_Value * t_Power) / t_Power;
341}
342
346{
347 if (p_Y < 0)
348 {
350 }
351 else
352 {
354 }
355
357}
358
362{
363 // before we can use the SDK, some internal SDK bits need to be initialized.
364 // however after initializing, the SDK is not yet connected to a host or doing anything network related just yet.
365 const SDKReturnCode t_InitializeResult = CoreSdk_Initialize(m_ClientType);
366 if (t_InitializeResult != SDKReturnCode::SDKReturnCode_Success)
367 {
368 spdlog::error("Failed to initialize the Manus Core SDK. The value returned was {}.", t_InitializeResult);
369 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
370 }
371
372 const ClientReturnCode t_CallBackResults = RegisterAllCallbacks();
373 if (t_CallBackResults != ::ClientReturnCode::ClientReturnCode_Success)
374 {
375 spdlog::error("Failed to initialize callbacks.");
376 return t_CallBackResults;
377 }
378
379 // after everything is registered and initialized as seen above
380 // we must also set the coordinate system being used for the data in this client.
381 // (each client can have their own settings. unreal and unity for instance use different coordinate systems)
382 // if this is not set, the SDK will not connect to any Manus core host.
385 t_VUH.handedness = Side::Side_Left; // this is currently set to unreal mode.
386 t_VUH.up = AxisPolarity::AxisPolarity_PositiveY;
387 t_VUH.view = AxisView::AxisView_ZFromViewer;
388 t_VUH.unitScale = 1.0f; //1.0 is meters, 0.01 is cm, 0.001 is mm.
389
390 const SDKReturnCode t_CoordinateResult = CoreSdk_InitializeCoordinateSystemWithVUH(t_VUH, false);
391 /* this is an example if you want to use the other coordinate system instead of VUH
392 CoordinateSystemDirection t_Direction;
393 t_Direction.x = AxisDirection::AD_Right;
394 t_Direction.y = AxisDirection::AD_Up;
395 t_Direction.z = AxisDirection::AD_Forward;
396 const SDKReturnCode t_InitializeResult = CoreSdk_InitializeCoordinateSystemWithDirection(t_Direction);
397 */
398
399 if (t_CoordinateResult != SDKReturnCode::SDKReturnCode_Success)
400 {
401 spdlog::error("Failed to initialize the Manus Core SDK coordinate system. The value returned was {}.", t_InitializeResult);
402 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
403 }
404
405 return ClientReturnCode::ClientReturnCode_Success;
406}
407
412{
413 const SDKReturnCode t_ShutDownResult = CoreSdk_ShutDown();
414 if (t_ShutDownResult != SDKReturnCode::SDKReturnCode_Success)
415 {
416 spdlog::error("Failed to shutdown the SDK. The value returned was {}.", t_ShutDownResult);
417 return ClientReturnCode::ClientReturnCode_FailedToShutDownSDK;
418 }
419
420 const ClientReturnCode t_IntializeResult = InitializeSDK();
421 if (t_IntializeResult != ClientReturnCode::ClientReturnCode_Success)
422 {
423 spdlog::error("Failed to initialize the SDK functionality. The value returned was {}.", t_IntializeResult);
424 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
425 }
426
427 return ClientReturnCode::ClientReturnCode_Success;
428}
429
434{
435 // Register the callback for when manus core is connected to the SDK
436 // it is optional, but helps trigger your client nicely if needed.
437 // see the function OnConnectedCallback for more details
438 const SDKReturnCode t_RegisterConnectCallbackResult = CoreSdk_RegisterCallbackForOnConnect(*OnConnectedCallback);
439 if (t_RegisterConnectCallbackResult != SDKReturnCode::SDKReturnCode_Success)
440 {
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;
443 }
444
445 // Register the callback for when manus core is disconnected to the SDK
446 // it is optional, but helps trigger your client nicely if needed.
447 // see OnDisconnectedCallback for more details.
448 const SDKReturnCode t_RegisterDisconnectCallbackResult = CoreSdk_RegisterCallbackForOnDisconnect(*OnDisconnectedCallback);
449 if (t_RegisterDisconnectCallbackResult != SDKReturnCode::SDKReturnCode_Success)
450 {
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;
453 }
454
455 // Register the callback for when manus core is sending Skeleton data
456 // it is optional, but without it you can not see any resulting skeleton data.
457 // see OnSkeletonStreamCallback for more details.
459 if (t_RegisterSkeletonCallbackResult != SDKReturnCode::SDKReturnCode_Success)
460 {
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;
463 }
464
465 // Register the callback for when manus core is sending landscape data
466 // it is optional, but this allows for a reactive adjustment of device information.
467 const SDKReturnCode t_RegisterLandscapeCallbackResult = CoreSdk_RegisterCallbackForLandscapeStream(*OnLandscapeCallback);
468 if (t_RegisterLandscapeCallbackResult != SDKReturnCode::SDKReturnCode_Success)
469 {
470 spdlog::error("Failed to register callback for landscape from Manus Core. The value returned was {}.", t_RegisterLandscapeCallbackResult);
471 return ClientReturnCode::ClientReturnCode_FailedToInitialize;
472 }
473
474 // Register the callback for when manus core is sending System messages
475 // This is usually not used by client applications unless they want to show errors/events from core.
476 // see OnSystemCallback for more details.
477 const SDKReturnCode t_RegisterSystemCallbackResult = CoreSdk_RegisterCallbackForSystemStream(*OnSystemCallback);
478 if (t_RegisterSystemCallbackResult != SDKReturnCode::SDKReturnCode_Success)
479 {
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;
482 }
483
484 // Register the callback for when manus core is sending Ergonomics data
485 // it is optional, but helps trigger your client nicely if needed.
486 // see OnErgonomicsCallback for more details.
487 const SDKReturnCode t_RegisterErgonomicsCallbackResult = CoreSdk_RegisterCallbackForErgonomicsStream(*OnErgonomicsCallback);
488 if (t_RegisterErgonomicsCallbackResult != SDKReturnCode::SDKReturnCode_Success)
489 {
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;
492 }
493
494 return ClientReturnCode::ClientReturnCode_Success;
495}
496
501{
503 {
504 ClearConsole();
506
507 bool t_BuiltInDebug = false;
508 SDKReturnCode t_Result = CoreSdk_WasDllBuiltInDebugConfiguration(&t_BuiltInDebug);
509 if (t_Result == SDKReturnCode::SDKReturnCode_Success)
510 {
511 if (t_BuiltInDebug)
512 {
513 spdlog::warn("The DLL was built in debug configuration, please rebuild in release before releasing.");
514 }
515 }
516 else
517 {
518 spdlog::error("Failed to check if the DLL was built in Debug Configuration. The value returned was {}.", t_Result);
519 }
520
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).");
525 }
526
527 if (GetKeyDown('L'))
528 {
529 spdlog::info("Picked local.");
530
532 m_ShouldConnectGRPC = false;
533 m_State = ClientState::ClientState_LookingForHosts;
534 }
535 else if (GetKeyDown('H'))
536 {
537 spdlog::info("Picked host.");
538
540 m_ShouldConnectGRPC = false;
541 m_State = ClientState::ClientState_LookingForHosts;
542 }
543 if (GetKeyDown('G'))
544 {
545 spdlog::info("Picked GRPC.");
546
547 m_ShouldConnectGRPC = true;
548 m_State = ClientState::ClientState_ConnectingToCore;
549 }
550
551 return ClientReturnCode::ClientReturnCode_Success;
552}
553
557{
558 spdlog::info("Looking for hosts...");
559
560 // Underlying function will sleep for m_SecondsToFindHosts to allow servers to reply.
562 if (t_StartResult != SDKReturnCode::SDKReturnCode_Success)
563 {
564 spdlog::error("Failed to look for hosts. The error given was {}.", t_StartResult);
565
566 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
567 }
568
571 if (t_NumberResult != SDKReturnCode::SDKReturnCode_Success)
572 {
573 spdlog::error("Failed to get the number of available hosts. The error given was {}.", t_NumberResult);
574
575 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
576 }
577
578 if (m_NumberOfHostsFound == 0)
579 {
580 spdlog::warn("No hosts found.");
581 m_State = ClientState::ClientState_NoHostsFound;
582
583 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
584 }
585
588 if (t_HostsResult != SDKReturnCode::SDKReturnCode_Success)
589 {
590 spdlog::error("Failed to get the available hosts. The error given was {}.", t_HostsResult);
591
592 return ClientReturnCode::ClientReturnCode_FailedToFindHosts;
593 }
595 {
596 m_State = ClientState::ClientState_ConnectingToCore;
597 return ClientReturnCode::ClientReturnCode_Success;
598 }
599
600 m_State = ClientState::ClientState_PickingHost;
601 return ClientReturnCode::ClientReturnCode_Success;
602}
603
606{
608 {
610 spdlog::info("No hosts were found. Retry?");
611 spdlog::info("[R] retry");
612 spdlog::info("[ESC] exit");
613 }
614
615 if (GetKeyDown('R'))
616 {
617 spdlog::info("Retrying.");
618
619 m_State = ClientState::ClientState_PickingConnectionType;
620 }
621
622 // Note: escape is handled by default below.
623 return ClientReturnCode::ClientReturnCode_Success;
624}
625
628{
630 {
632
633 spdlog::info("[R] retry [ESC] exit");
634 spdlog::info("Pick a host to connect to.");
635 spdlog::info("Found the following hosts:");
636
637 // Note: only 10 hosts are shown, to match the number of number keys, for easy selection.
638 for (unsigned int t_HostNumber = 0; t_HostNumber < 10 && t_HostNumber < m_NumberOfHostsFound; t_HostNumber++)
639 {
640 spdlog::info(
641 "[{}] hostname \"{}\", IP address \"{}\" Version {}.{}.{}",
642 t_HostNumber,
643 m_AvailableHosts[t_HostNumber].hostName,
644 m_AvailableHosts[t_HostNumber].ipAddress,
645 m_AvailableHosts[t_HostNumber].manusCoreVersion.major,
646 m_AvailableHosts[t_HostNumber].manusCoreVersion.minor,
647 m_AvailableHosts[t_HostNumber].manusCoreVersion.patch);
648 }
649 }
650
651 for (unsigned int t_HostNumber = 0; t_HostNumber < 10 && t_HostNumber < m_NumberOfHostsFound; t_HostNumber++)
652 {
653 if (GetKeyDown('0' + t_HostNumber))
654 {
655 spdlog::info("Selected host {}.", t_HostNumber);
656
657 m_HostToConnectTo = t_HostNumber;
658 m_State = ClientState::ClientState_ConnectingToCore;
659
660 break;
661 }
662 }
663
664 if (GetKeyDown('R'))
665 {
666 spdlog::info("Retrying.");
667
668 m_State = ClientState::ClientState_PickingConnectionType;
669 }
670
671 return ClientReturnCode::ClientReturnCode_Success;
672}
673
676{
677 SDKReturnCode t_ConnectResult = SDKReturnCode::SDKReturnCode_Error;
678
680 {
681 t_ConnectResult = CoreSdk_ConnectGRPC();
682 }
683 else
684 {
687 }
688
689 if (t_ConnectResult == SDKReturnCode::SDKReturnCode_NotConnected)
690 {
691 m_State = ClientState::ClientState_NoHostsFound;
692
693 return ClientReturnCode::ClientReturnCode_Success; // Differentating between error and no connect
694 }
695 if (t_ConnectResult != SDKReturnCode::SDKReturnCode_Success)
696 {
697 spdlog::error("Failed to connect to Core. The error given was {}.", t_ConnectResult);
698
699 return ClientReturnCode::ClientReturnCode_FailedToConnect;
700 }
701
702 m_State = ClientState::ClientState_DisplayingData;
703
704 // Note: a log message from somewhere in the SDK during the connection process can cause text
705 // to permanently turn green after this step. Adding a sleep here of 2+ seconds "fixes" the
706 // issue. It seems to be caused by a threading issue somewhere, resulting in a log call being
707 // interrupted while it is printing the green [info] text. The log output then gets stuck in
708 // green mode.
709
710 return ClientReturnCode::ClientReturnCode_Success;
711}
712
713
718{
720
721 m_SkeletonMutex.lock();
722 if (m_NextSkeleton != nullptr)
723 {
724 if (m_Skeleton != nullptr)delete m_Skeleton;
726 m_NextSkeleton = nullptr;
727 }
728 m_SkeletonMutex.unlock();
729
730 m_LandscapeMutex.lock();
731 if (m_NewLandscape != nullptr)
732 {
733 if (m_Landscape != nullptr)
734 {
735 delete m_Landscape;
736 }
738 m_NewLandscape = nullptr;
739 }
740 m_LandscapeMutex.unlock();
741
744 if (m_Landscape == nullptr)return ClientReturnCode::ClientReturnCode_Success;
745 for (size_t i = 0; i < m_Landscape->gloveDevices.gloveCount; i++)
746 {
747 if (m_FirstLeftGloveID == 0 && m_Landscape->gloveDevices.gloves[i].side == Side::Side_Left)
748 {
750 continue;
751 }
752 if (m_FirstRightGloveID == 0 && m_Landscape->gloveDevices.gloves[i].side == Side::Side_Right)
753 {
755 continue;
756 }
757 }
758
759 return ClientReturnCode::ClientReturnCode_Success;
760}
761
762
767{
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");
774
776
782
784
785 return ClientReturnCode::ClientReturnCode_Success;
786}
787
791{
792 SPDLOG_INFO("[Q] Back <<Gloves & Dongles>> [ESC] quit");
793 SPDLOG_INFO("Haptic keys: left:([1]-[5] = pinky-thumb.) right:([6]-[0] = thumb-pinky.)");
794
796
798
800
804
805 return ClientReturnCode::ClientReturnCode_Success;
806}
807
809{
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)");
813
815
817
820
824
825 return ClientReturnCode::ClientReturnCode_Success;
826}
827
829{
830 SPDLOG_INFO("[Q] Back <<Gloves & Dongles>> [ESC] quit");
831 SPDLOG_INFO("[O] Toggle Test Tracker [G] Toggle per user tracker display");
832
834
836
838
841
842 return ClientReturnCode::ClientReturnCode_Success;
843}
844
846{
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");
851
853
855
857
862
863 return ClientReturnCode::ClientReturnCode_Success;
864}
865
867{
868 SPDLOG_INFO("[Q] Back <<Landscape Time Data>> [ESC] quit");
869
871
873
875
877
879
880 return ClientReturnCode::ClientReturnCode_Success;
881}
882
886{
887 if (m_Host == nullptr) { return ClientReturnCode::ClientReturnCode_FailedToConnect; }
888
890
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");
894
896
898 {
899 spdlog::info("Automatically trying to reconnect to GRPC address.");
900
901 ClientReturnCode t_ReconnectResult = ReconnectingToCore();
902 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
903 {
904 return t_ReconnectResult;
905 }
906 }
907 else if (m_ShouldConnectLocally)
908 {
909 spdlog::info("Automatically trying to reconnect to local host.");
910
911 ClientReturnCode t_ReconnectResult = ReconnectingToCore();
912 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
913 {
914 return t_ReconnectResult;
915 }
916 }
917 else
918 {
919 spdlog::info("[R] Try to reconnect to the last host {} at {}.", m_Host->hostName, m_Host->ipAddress);
920 if (GetKeyDown('R'))
921 {
922 spdlog::info("Reconnecting");
923
925 if (t_ReconnectResult != ClientReturnCode::ClientReturnCode_FailedToConnect)
926 {
927 return t_ReconnectResult;
928 }
929 }
930 }
931
933
934
935 if (GetKeyDown('P'))
936 {
937 spdlog::info("Picking new host.");
938
939 // Restarting and initializing CoreConnection to make sure a new connection can be set up
940 const ClientReturnCode t_RestartResult = RestartSDK();
941 if (t_RestartResult != ClientReturnCode::ClientReturnCode_Success)
942 {
943 spdlog::error("Failed to Restart CoreConnection.");
944 return ClientReturnCode::ClientReturnCode_FailedToRestart;
945 }
946
947 m_State = ClientState::ClientState_PickingConnectionType;
948 }
949
950 return ClientReturnCode::ClientReturnCode_Success;
951}
952
954ClientReturnCode SDKClient::ReconnectingToCore(int32_t p_ReconnectionTime, int32_t p_ReconnectionAttempts)
955{
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(); }
958
959 // Restarting and initializing CoreConnection to make sure a new connection can be set up
960 const ClientReturnCode t_RestartResult = RestartSDK();
961 if (t_RestartResult != ClientReturnCode::ClientReturnCode_Success)
962 {
963 spdlog::error("Failed to Restart CoreConnection.");
964 return ClientReturnCode::ClientReturnCode_FailedToRestart;
965 }
966
967 std::chrono::high_resolution_clock::time_point t_Start = std::chrono::high_resolution_clock::now();
968 int t_Attempt = 0;
969 while ((p_ReconnectionAttempts > 0) && (p_ReconnectionTime > 0))
970 {
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);
974 {
975 SDKReturnCode t_ConnectionResult = CoreSdk_ConnectGRPC();
976 if (t_ConnectionResult == SDKReturnCode::SDKReturnCode_Success)
977 {
978 spdlog::info("Reconnected to ManusCore.");
979 return ClientReturnCode::ClientReturnCode_Success;
980 }
981 }
982 else if (m_ShouldConnectLocally)
983 {
984 ClientReturnCode t_ConnectionResult = LookingForHosts();
985 if (t_ConnectionResult == ClientReturnCode::ClientReturnCode_Success)
986 {
987 spdlog::info("Reconnected to ManusCore.");
988 return ClientReturnCode::ClientReturnCode_Success;
989 }
990 }
991 else
992 {
993 SDKReturnCode t_ConnectionResult = CoreSdk_ConnectToHost(*m_Host.get());
994 if (t_ConnectionResult == SDKReturnCode::SDKReturnCode_Success)
995 {
996 spdlog::info("Reconnected to ManusCore.");
997 return ClientReturnCode::ClientReturnCode_Success;
998 }
999 }
1000 std::this_thread::sleep_for(std::chrono::milliseconds(m_SleepBetweenReconnectingAttemptsInMs));
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;
1003 ++t_Attempt;
1004 }
1005
1006 spdlog::info("Failed to reconnect to ManusCore.");
1007 m_State = ClientState::ClientState_Disconnected;
1008 return ClientReturnCode::ClientReturnCode_FailedToConnect;
1009}
1010
1011
1014void SDKClient::PrintHandErgoData(ErgonomicsData& p_ErgoData, bool p_Left)
1015{
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 " };
1019
1020 int t_DataOffset = 0;
1021 if (!p_Left)t_DataOffset = 20;
1022
1023 const std::string* t_JointNames = t_ThumbJointNames;
1024 for (unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1025 {
1026 spdlog::info("{} {} spread: {:>6}, {} stretch: {:>6}, {} stretch: {:>6}, {} stretch: {:>6} ",
1027 t_FingerNames[t_FingerNumber], // Name of the finger.
1028 t_JointNames[0],
1029 RoundFloatValue(p_ErgoData.data[t_DataOffset], 2),
1030 t_JointNames[0],
1031 RoundFloatValue(p_ErgoData.data[t_DataOffset + 1], 2),
1032 t_JointNames[1],
1033 RoundFloatValue(p_ErgoData.data[t_DataOffset + 2], 2),
1034 t_JointNames[2],
1035 RoundFloatValue(p_ErgoData.data[t_DataOffset + 3], 2));
1036 t_JointNames = t_FingerJointNames;
1037 t_DataOffset += 4;
1038 }
1039}
1040
1043{
1044 // for testing purposes we only look at the first 2 gloves available
1045 spdlog::info(" -- Ergo Timestamp {:02d}:{:02d}:{:02d}.{:03d} ~ {:02d}/{:02d}/{:d}(D/M/Y)",
1048 spdlog::info(" -- Left Glove -- 0x{:X} - Angles in degrees", m_FirstLeftGloveID);
1050 {
1052 }
1053 else
1054 {
1055 spdlog::info(" ...No Data...");
1056 }
1057 spdlog::info(" -- Right Glove -- 0x{:X} - Angles in degrees", m_FirstRightGloveID);
1059 {
1061 }
1062 else
1063 {
1064 spdlog::info(" ...No Data...");
1065 }
1066
1068}
1069
1071{
1072 switch (p_Type)
1073 {
1075 return "Dongle";
1077 return "Glove";
1079 return "Glongle (Glove Dongle)";
1080 default:
1081 return "Unknown";
1082 }
1083}
1084
1086{
1087 switch (p_Type)
1088 {
1090 return "Prime 1";
1092 return "Prime 2";
1094 return "Prime X";
1096 return "Quantum";
1097 default:
1098 return "Unknown";
1099 }
1100}
1101
1104{
1105 // get a dongle id
1106 uint32_t t_DongleCount = 0;
1107 if (CoreSdk_GetNumberOfDongles(&t_DongleCount) != SDKReturnCode::SDKReturnCode_Success) return;
1108 if (t_DongleCount == 0) return; // we got no gloves to work on anyway!
1109
1110 uint32_t* t_DongleIds = new uint32_t[t_DongleCount]();
1111 if (CoreSdk_GetDongleIds(t_DongleIds, t_DongleCount) != SDKReturnCode::SDKReturnCode_Success) return;
1112
1113 DongleLandscapeData t_DongleData;
1114
1115 for (uint32_t i = 0; i < t_DongleCount; i++)
1116 {
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)
1120 {
1121 spdlog::info(" Type: {} - {}",
1124 spdlog::info(" License: {}", t_DongleData.licenseType);
1125 }
1126 else
1127 {
1128 spdlog::info(" ...No Data...");
1129 }
1131 }
1132}
1133
1136{
1137 m_SystemMessageMutex.lock();
1138 spdlog::info("Received System data:{} / code:{}", m_SystemMessage, m_SystemMessageCode);
1139 m_SystemMessageMutex.unlock();
1141}
1142
1147{
1148 if (m_Skeleton == nullptr || m_Skeleton->skeletons.size() == 0)
1149 {
1150 return;
1151 }
1152
1153 spdlog::info("Received Skeleton data. skeletons:{} first skeleton id:{}", m_Skeleton->skeletons.size(), m_Skeleton->skeletons[0].info.id);
1154
1156}
1157
1162{
1163 spdlog::info("Tracker test active: {}.", m_TrackerTest); //To show that test tracker is being sent to core
1164 spdlog::info("Per user tracker display: {}.", m_TrackerDataDisplayPerUser);
1165
1167
1169 {
1172 }
1173 else
1174 {
1177 }
1178}
1179
1183{
1184 uint32_t t_NumberOfAvailabletrackers = 0;
1185 SDKReturnCode t_TrackerResult = CoreSdk_GetNumberOfAvailableTrackers(&t_NumberOfAvailabletrackers);
1186 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1187 {
1188 spdlog::error("Failed to get tracker data. The error given was {}.", t_TrackerResult);
1189 return;
1190 }
1191
1192 spdlog::info("received available trackers :{} ", t_NumberOfAvailabletrackers);
1193
1194 if (t_NumberOfAvailabletrackers == 0) return; // nothing else to do.
1195 TrackerId* t_TrackerId = new TrackerId[t_NumberOfAvailabletrackers];
1196 t_TrackerResult = CoreSdk_GetIdsOfAvailableTrackers(t_TrackerId, t_NumberOfAvailabletrackers);
1197 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1198 {
1199 spdlog::error("Failed to get tracker data. The error given was {}.", t_TrackerResult);
1200 return;
1201 }
1202}
1203
1206{
1207 uint32_t t_NumberOfAvailableUsers = 0;
1208 SDKReturnCode t_UserResult = CoreSdk_GetNumberOfAvailableUsers(&t_NumberOfAvailableUsers);
1209 if (t_UserResult != SDKReturnCode::SDKReturnCode_Success)
1210 {
1211 spdlog::error("Failed to get user count. The error given was {}.", t_UserResult);
1212 return;
1213 }
1214 if (t_NumberOfAvailableUsers == 0) return; // nothing to get yet
1215 // get first user (not necesarily the correct one)
1216 uint32_t* t_UserIds = new uint32_t[t_NumberOfAvailableUsers];
1217 t_UserResult = CoreSdk_GetIdsOfAvailableUsers(t_UserIds, t_NumberOfAvailableUsers);
1218 if (t_UserResult != SDKReturnCode::SDKReturnCode_Success)
1219 {
1220 spdlog::error("Failed to get user data. The error given was {}.", t_UserResult);
1221 return;
1222 }
1223
1224 for (size_t i = 0; i < t_NumberOfAvailableUsers; i++)
1225 {
1226 uint32_t t_NumberOfAvailabletrackers = 0;
1227 SDKReturnCode t_TrackerResult = CoreSdk_GetNumberOfAvailableTrackersForUserId(&t_NumberOfAvailabletrackers, t_UserIds[i]);
1228 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1229 {
1230 spdlog::error("Failed to get tracker data. The error given was {}.", t_TrackerResult);
1231 return;
1232 }
1233
1234 if (t_NumberOfAvailabletrackers == 0) continue;
1235
1236 spdlog::info("received available trackers for user id[{}] :{} ", t_UserIds[i], t_NumberOfAvailabletrackers);
1237
1238 if (t_NumberOfAvailabletrackers == 0) return; // nothing else to do.
1239 TrackerId* t_TrackerId = new TrackerId[t_NumberOfAvailabletrackers];
1240 t_TrackerResult = CoreSdk_GetIdsOfAvailableTrackersForUserId(t_TrackerId, t_UserIds[i], t_NumberOfAvailabletrackers);
1241 if (t_TrackerResult != SDKReturnCode::SDKReturnCode_Success)
1242 {
1243 spdlog::error("Failed to get tracker data. The error given was {}.", t_TrackerResult);
1244 return;
1245 }
1246 }
1247}
1248
1249std::string GetFPSEnumName(TimecodeFPS p_FPS)
1250{
1251 switch (p_FPS)
1252 {
1253 case TimecodeFPS::TimecodeFPS_23_976:
1254 return "23.976 FPS (24 dropframe)";
1255 case TimecodeFPS::TimecodeFPS_24:
1256 return "24 FPS";
1257 case TimecodeFPS::TimecodeFPS_25:
1258 return "25 FPS";
1259 case TimecodeFPS::TimecodeFPS_29_97:
1260 return "29.97 FPS (30 dropframe)";
1261 case TimecodeFPS::TimecodeFPS_30:
1262 return "30 FPS";
1263 case TimecodeFPS::TimecodeFPS_50:
1264 return "50 FPS";
1265 case TimecodeFPS::TimecodeFPS_59_94:
1266 return "59.94 FPS (60 dropframe)";
1267 case TimecodeFPS::TimecodeFPS_60:
1268 return "60 FPS";
1269 default:
1270 return "Undefined FPS";
1271 }
1272}
1273
1275{
1276 spdlog::info("Total count of Interfaces: {}", m_Landscape->time.interfaceCount);
1277 spdlog::info("Current Interface: {} {} at index {}", m_Landscape->time.currentInterface.name, m_Landscape->time.currentInterface.api, m_Landscape->time.currentInterface.index);
1278
1279 spdlog::info("FPS: {}", GetFPSEnumName(m_Landscape->time.fps));
1280 spdlog::info("Fake signal: {} | Sync Pulse: {} | Sync Status: {}", m_Landscape->time.fakeTimecode, m_Landscape->time.useSyncPulse, m_Landscape->time.syncStatus);
1281 spdlog::info("Device keep alive: {} | Timecode Status: {}", m_Landscape->time.deviceKeepAlive, m_Landscape->time.timecodeStatus);
1282
1284}
1285
1288{
1289 switch (m_ChainType)
1290 {
1291 case ChainType::ChainType_FingerIndex:
1292 {
1293 spdlog::info("received Skeleton chain type: ChainType_FingerIndex");
1294 break;
1295 }
1296 case ChainType::ChainType_FingerMiddle:
1297 {
1298 spdlog::info("received Skeleton chain type: ChainType_FingerMiddle");
1299 break;
1300 }
1301 case ChainType::ChainType_FingerPinky:
1302 {
1303 spdlog::info("received Skeleton chain type: ChainType_FingerPinky");
1304 break;
1305 }
1306 case ChainType::ChainType_FingerRing:
1307 {
1308 spdlog::info("received Skeleton chain type: ChainType_FingerRing");
1309 break;
1310 }
1311 case ChainType::ChainType_FingerThumb:
1312 {
1313 spdlog::info("received Skeleton chain type: ChainType_FingerThumb");
1314 break;
1315 }
1316 case ChainType::ChainType_Hand:
1317 {
1318 spdlog::info("received Skeleton chain type: ChainType_Hand");
1319 break;
1320 }
1321 case ChainType::ChainType_Head:
1322 {
1323 spdlog::info("received Skeleton chain type: ChainType_Head");
1324 break;
1325 }
1326 case ChainType::ChainType_Leg:
1327 {
1328 spdlog::info("received Skeleton chain type: ChainType_Leg");
1329 break;
1330 }
1331 case ChainType::ChainType_Neck:
1332 {
1333 spdlog::info("received Skeleton chain type: ChainType_Neck");
1334 break;
1335 }
1336 case ChainType::ChainType_Pelvis:
1337 {
1338 spdlog::info("received Skeleton chain type: ChainType_Pelvis");
1339 break;
1340 }
1341 case ChainType::ChainType_Shoulder:
1342 {
1343 spdlog::info("received Skeleton chain type: ChainType_Shoulder");
1344 break;
1345 }
1346 case ChainType::ChainType_Spine:
1347 {
1348 spdlog::info("received Skeleton chain type: ChainType_Spine");
1349 break;
1350 }
1351 case ChainType::ChainType_Arm:
1352 {
1353 spdlog::info("received Skeleton chain type: ChainType_Arm");
1354 break;
1355 }
1356 case ChainType::ChainType_Invalid:
1357 default:
1358 {
1359 spdlog::info("received Skeleton chain type: ChainType_Invalid");
1360 break;
1361 }
1362 }
1364}
1365
1370{
1371 // if a temporary skeleton associated to the current session has been modified we can get it and, potentially, load it
1372 if (m_ModifiedSkeletonIndex != UINT_MAX)
1373 {
1374 // get the temporary skeleton
1375 uint32_t t_SessionId = m_SessionId;
1377 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1378 {
1379 spdlog::error("Failed to get temporary skeleton. The error given was {}.", t_Res);
1380 return;
1381 }
1382
1383 // At this point if we are satisfied with the modifications to the skeleton we can load it into Core.
1384 // Remember to always call function CoreSdk_ClearTemporarySkeleton after loading a temporary skeleton,
1385 // this will keep the temporary skeleton list in sync between Core and the SDK.
1386
1387 //uint32_t t_ID = 0;
1388 //SDKReturnCode t_Res = CoreSdk_LoadSkeleton(m_ModifiedSkeletonIndex, &t_ID);
1389 //if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1390 //{
1391 // spdlog::error("Failed to load skeleton. The error given was {}.", t_Res);
1392 // return;
1393 //}
1394 //if (t_ID == 0)
1395 //{
1396 // spdlog::error("Failed to give skeleton an ID.");
1397 //}
1398 //m_LoadedSkeletons.push_back(t_ID);
1399 //t_Res = CoreSdk_ClearTemporarySkeleton(m_ModifiedSkeletonIndex, m_SessionId);
1400 //if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1401 //{
1402 // spdlog::error("Failed to clear temporary skeleton. The error given was {}.", t_Res);
1403 // return;
1404 //}
1405 m_ModifiedSkeletonIndex = UINT_MAX;
1406 }
1407}
1411{
1412 spdlog::info("Number of temporary skeletons in the SDK: {} ", m_TemporarySkeletons.size());
1413
1414 static uint32_t t_TotalNumberOfTemporarySkeletonsInCore = 0;
1415 auto t_TimeSinceLastTemporarySkeletonUpdate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_LastTemporarySkeletonUpdate).count();
1416 if (t_TimeSinceLastTemporarySkeletonUpdate < static_cast<unsigned int>(MILLISECONDS_BETWEEN_TEMPORARY_SKELETONS_UPDATE))
1417 {
1418 spdlog::info("Total number of temporary skeletons in core: {} ", t_TotalNumberOfTemporarySkeletonsInCore);
1419 return;
1420 }
1421 TemporarySkeletonSessionsData t_TemporarySkeletonSessionsData;
1422 SDKReturnCode t_Res = CoreSdk_GetTemporarySkeletonsForAllSessions(&t_TemporarySkeletonSessionsData);
1423 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1424 {
1425 spdlog::error("Failed to get all temporary skeletons. The error given was {}.", t_Res);
1426 return;
1427 }
1428
1429 t_TotalNumberOfTemporarySkeletonsInCore = 0;
1430 for (uint32_t i = 0; i < t_TemporarySkeletonSessionsData.sessionsCount; i++)
1431 {
1432 for (uint32_t s = 0; s < t_TemporarySkeletonSessionsData.temporarySkeletonsSessions[i].skeletonCount; s++)
1433 {
1434 if (t_TemporarySkeletonSessionsData.temporarySkeletonsSessions[i].skeletonInfo[s].index == UINT32_MAX)
1435 {
1436 continue;
1437 }
1438 t_TotalNumberOfTemporarySkeletonsInCore++;
1439 }
1440 }
1441
1442 // print total number of temporary skeletons:
1443 spdlog::info("Total number of temporary skeletons in core: {} ", t_TotalNumberOfTemporarySkeletonsInCore);
1444 m_LastTemporarySkeletonUpdate = std::chrono::high_resolution_clock::now();
1445}
1446
1451{
1452 if (m_FirstLeftGloveID == 0 && m_FirstRightGloveID == 0) return; // we got no gloves to work on anyway!
1453
1454 // get a dongle id
1455 uint32_t t_DongleId = 0;
1456 uint32_t t_GloveIds[2] = { 0,0 };
1457 uint32_t t_DongleCount = 0;
1458 if (CoreSdk_GetNumberOfDongles(&t_DongleCount) != SDKReturnCode::SDKReturnCode_Success) return;
1459 if (t_DongleCount == 0) return; // we got no gloves to work on anyway!
1460
1461 uint32_t* t_DongleIds = new uint32_t[t_DongleCount]();
1462 if (CoreSdk_GetDongleIds(t_DongleIds, t_DongleCount) != SDKReturnCode::SDKReturnCode_Success) return;
1463
1464 for (uint32_t i = 0; i < t_DongleCount; i++)
1465 {
1466 // now lets see if it has gloves. otherwise its still not useful
1467 CoreSdk_GetGlovesForDongle(t_DongleIds[i], &t_GloveIds[0], &t_GloveIds[1]);
1468 if (!t_GloveIds[0] && !t_GloveIds[1]) continue;
1469 t_DongleId = t_DongleIds[i]; // during tests we only expect 1 or 2 gloves, so this code is ok, in more real situation we want to make sure we got the right dongle instead of the first available.
1470 break;
1471 }
1472 if (t_DongleId == 0) return; // still no valid data. (though this is very unlikely)
1473
1475 const int t_LeftHand = 0;
1476 const int t_RightHand = 1;
1477
1478 // The strange key number sequence here results from having gloves lie in front of you, and have the keys and haptics in the same order.
1479 t_HapticState[t_LeftHand].shouldHapticFinger[0] = GetKey('5'); // left thumb
1480 t_HapticState[t_LeftHand].shouldHapticFinger[1] = GetKey('4'); // left index
1481 t_HapticState[t_LeftHand].shouldHapticFinger[2] = GetKey('3'); // left middle
1482 t_HapticState[t_LeftHand].shouldHapticFinger[3] = GetKey('2'); // left ring
1483 t_HapticState[t_LeftHand].shouldHapticFinger[4] = GetKey('1'); // left pinky
1484 t_HapticState[t_RightHand].shouldHapticFinger[0] = GetKey('6'); // right thumb
1485 t_HapticState[t_RightHand].shouldHapticFinger[1] = GetKey('7'); // right index
1486 t_HapticState[t_RightHand].shouldHapticFinger[2] = GetKey('8'); // right middle
1487 t_HapticState[t_RightHand].shouldHapticFinger[3] = GetKey('9'); // right ring
1488 t_HapticState[t_RightHand].shouldHapticFinger[4] = GetKey('0'); // right pinky
1489
1490 // Note: this timer is apparently not very accurate.
1491 // It is good enough for this test client, but should probably be replaced for other uses.
1492 static std::chrono::high_resolution_clock::time_point s_TimeOfLastHapticsCommandSent;
1493 const std::chrono::high_resolution_clock::time_point s_Now = std::chrono::high_resolution_clock::now();
1494 const long long s_MillisecondsSinceLastHapticCommand = std::chrono::duration_cast<std::chrono::milliseconds>(s_Now - s_TimeOfLastHapticsCommandSent).count();
1495
1496 if (s_MillisecondsSinceLastHapticCommand < static_cast<unsigned int>(MINIMUM_MILLISECONDS_BETWEEN_HAPTICS_COMMANDS))
1497 {
1498 return;
1499 }
1500
1501 const Side s_Hands[NUMBER_OF_HANDS_SUPPORTED] = { Side::Side_Left, Side::Side_Right };
1502 const float s_FullPower = 1.0f;
1503
1504 for (unsigned int t_HandNumber = 0; t_HandNumber < NUMBER_OF_HANDS_SUPPORTED; t_HandNumber++)
1505 {
1506 if (t_GloveIds[t_HandNumber] == 0) continue; // no glove available. skip.
1507
1508 GloveLandscapeData t_Glove;
1509 if (CoreSdk_GetDataForGlove_UsingGloveId(t_GloveIds[t_HandNumber], &t_Glove) != SDKReturnCode::SDKReturnCode_Success)
1510 {
1511 continue;
1512 }
1513
1514 if (t_Glove.familyType != DeviceFamilyType::DeviceFamilyType_Prime1)
1515 {
1516 continue;
1517 }
1518 }
1519
1520 // This is an example that shows how to send the haptics commands based on dongle id:
1521 uint32_t* t_HapticsDongles = new uint32_t[MAX_NUMBER_OF_DONGLES];
1522 for (unsigned int t_HandNumber = 0; t_HandNumber < NUMBER_OF_HANDS_SUPPORTED; t_HandNumber++)
1523 {
1524 uint32_t t_NumberOfHapticsDongles = 0;
1525 if ((CoreSdk_GetNumberOfHapticsDongles(&t_NumberOfHapticsDongles) != SDKReturnCode::SDKReturnCode_Success) ||
1526 (t_NumberOfHapticsDongles == 0))
1527 {
1528 continue;
1529 }
1530
1531 if (CoreSdk_GetHapticsDongleIds(t_HapticsDongles, t_NumberOfHapticsDongles) != SDKReturnCode::SDKReturnCode_Success)
1532 {
1533 continue;
1534 }
1535
1536 float t_HapticsPowers[NUM_FINGERS_ON_HAND]{};
1537 for (unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1538 {
1539 t_HapticsPowers[t_FingerNumber] = t_HapticState[t_HandNumber].shouldHapticFinger[t_FingerNumber] ? s_FullPower : 0.0f;
1540 }
1541
1542 GloveLandscapeData t_GloveLandscapeData;
1543 if (CoreSdk_GetDataForGlove_UsingGloveId(t_GloveIds[t_HandNumber], &t_GloveLandscapeData) != SDKReturnCode::SDKReturnCode_Success)
1544 {
1545 continue;
1546 }
1547 if (!t_GloveLandscapeData.isHaptics) // if the glove is not Haptics do not vibrate.
1548 {
1549 continue;
1550 }
1551
1552 CoreSdk_VibrateFingers(t_HapticsDongles[0], s_Hands[t_HandNumber], t_HapticsPowers);
1553 }
1554 delete[] t_HapticsDongles;
1555}
1556
1559{
1560 if (GetKeyDown('N'))
1561 {
1563 }
1564 if (GetKeyDown('M'))
1565 {
1567 }
1568}
1569
1574{
1575 if (m_Skeleton == nullptr || m_Skeleton->skeletons.size() == 0)
1576 {
1577 return;
1578 }
1579
1581 const int t_LeftHand = 0;
1582 const int t_RightHand = 1;
1583
1584 // The strange key number sequence here results from having gloves lie in front of you, and have the keys and haptics in the same order.
1585 t_HapticState[t_LeftHand].shouldHapticFinger[0] = GetKey('5'); // left thumb
1586 t_HapticState[t_LeftHand].shouldHapticFinger[1] = GetKey('4'); // left index
1587 t_HapticState[t_LeftHand].shouldHapticFinger[2] = GetKey('3'); // left middle
1588 t_HapticState[t_LeftHand].shouldHapticFinger[3] = GetKey('2'); // left ring
1589 t_HapticState[t_LeftHand].shouldHapticFinger[4] = GetKey('1'); // left pinky
1590 t_HapticState[t_RightHand].shouldHapticFinger[0] = GetKey('6'); // right thumb
1591 t_HapticState[t_RightHand].shouldHapticFinger[1] = GetKey('7'); // right index
1592 t_HapticState[t_RightHand].shouldHapticFinger[2] = GetKey('8'); // right middle
1593 t_HapticState[t_RightHand].shouldHapticFinger[3] = GetKey('9'); // right ring
1594 t_HapticState[t_RightHand].shouldHapticFinger[4] = GetKey('0'); // right pinky
1595
1596 // Note: this timer is apparently not very accurate.
1597 // It is good enough for this test client, but should probably be replaced for other uses.
1598 static std::chrono::high_resolution_clock::time_point s_TimeOfLastHapticsCommandSent;
1599 const std::chrono::high_resolution_clock::time_point s_Now = std::chrono::high_resolution_clock::now();
1600 const long long s_MillisecondsSinceLastHapticCommand = std::chrono::duration_cast<std::chrono::milliseconds>(s_Now - s_TimeOfLastHapticsCommandSent).count();
1601
1602 if (s_MillisecondsSinceLastHapticCommand < static_cast<unsigned int>(MINIMUM_MILLISECONDS_BETWEEN_HAPTICS_COMMANDS))
1603 {
1604 return;
1605 }
1606
1607 const Side s_Hands[NUMBER_OF_HANDS_SUPPORTED] = { Side::Side_Left, Side::Side_Right };
1608 const float s_FullPower = 1.0f;
1609
1610 // The preferred way of sending the haptics commands is based on skeleton id
1611
1612 for (unsigned int t_HandNumber = 0; t_HandNumber < NUMBER_OF_HANDS_SUPPORTED; t_HandNumber++)
1613 {
1614 float t_HapticsPowers[NUM_FINGERS_ON_HAND]{};
1615 for (unsigned int t_FingerNumber = 0; t_FingerNumber < NUM_FINGERS_ON_HAND; t_FingerNumber++)
1616 {
1617 t_HapticsPowers[t_FingerNumber] = t_HapticState[t_HandNumber].shouldHapticFinger[t_FingerNumber] ? s_FullPower : 0.0f;
1618 }
1619 bool t_IsHaptics = false;
1620 if (CoreSdk_DoesSkeletonGloveSupportHaptics(m_Skeleton->skeletons[0].info.id, s_Hands[t_HandNumber], &t_IsHaptics) != SDKReturnCode::SDKReturnCode_Success)
1621 {
1622 continue;
1623 }
1624 if (!t_IsHaptics)
1625 {
1626 continue;
1627 }
1628 CoreSdk_VibrateFingersForSkeleton(m_Skeleton->skeletons[0].info.id, s_Hands[t_HandNumber], t_HapticsPowers);
1629 }
1630}
1631
1634{
1635 if (GetKeyDown('A'))
1636 {
1638 }
1639 if (GetKeyDown('B'))
1640 {
1642 }
1643 if (GetKeyDown('C'))
1644 {
1646 }
1647 if (GetKeyDown('D'))
1648 {
1650 }
1651 if (GetKeyDown('E'))
1652 {
1654 }
1655 if (GetKeyDown('F'))
1656 {
1658 }
1659}
1660
1663{
1664 if (GetKeyDown('O'))
1665 {
1667 }
1668
1669 if (GetKeyDown('G'))
1670 {
1672 }
1673
1674 if (m_TrackerTest)
1675 {
1676 m_TrackerOffset += 0.0005f;
1677 if (m_TrackerOffset >= 10.0f)
1678 {
1679 m_TrackerOffset = 0.0f;
1680 }
1681
1682 TrackerId t_TrackerId;
1683 CopyString(t_TrackerId.id, sizeof(t_TrackerId.id), std::string("Test Tracker"));
1684 TrackerData t_TrackerData = {};
1685 t_TrackerData.isHmd = false;
1686 t_TrackerData.trackerId = t_TrackerId;
1687 t_TrackerData.trackerType = TrackerType::TrackerType_Unknown;
1688 t_TrackerData.position = { 0.0f, m_TrackerOffset, 0.0f };
1689 t_TrackerData.rotation = { 1.0f, 0.0f, 0.0f, 0.0f };
1690 t_TrackerData.quality = TrackerQuality::TrackingQuality_Trackable;
1691 TrackerData t_TrackerDatas[MAX_NUMBER_OF_TRACKERS];
1692 t_TrackerDatas[0] = t_TrackerData;
1693
1694 const SDKReturnCode t_TrackerSend = CoreSdk_SendDataForTrackers(t_TrackerDatas, 1);
1695 if (t_TrackerSend != SDKReturnCode::SDKReturnCode_Success)
1696 {
1697 spdlog::error("Failed to send tracker data. The error given was {}.", t_TrackerSend);
1698 return;
1699 }
1700 }
1701}
1702
1716NodeSetup SDKClient::CreateNodeSetup(uint32_t p_Id, uint32_t p_ParentId, float p_PosX, float p_PosY, float p_PosZ, std::string p_Name)
1717{
1718 NodeSetup t_Node;
1719 NodeSetup_Init(&t_Node);
1720 t_Node.id = p_Id; //Every ID needs to be unique per node in a skeleton.
1721 CopyString(t_Node.name, sizeof(t_Node.name), p_Name);
1722 t_Node.type = NodeType::NodeType_Joint;
1723 //Every node should have a parent unless it is the Root node.
1724 t_Node.parentID = p_ParentId; //Setting the node ID to its own ID ensures it has no parent.
1725 t_Node.settings.usedSettings = NodeSettingsFlag::NodeSettingsFlag_None;
1726
1727 t_Node.transform.position.x = p_PosX;
1728 t_Node.transform.position.y = p_PosY;
1729 t_Node.transform.position.z = p_PosZ;
1730 return t_Node;
1731}
1732
1733ManusVec3 SDKClient::CreateManusVec3(float p_X, float p_Y, float p_Z)
1734{
1735 ManusVec3 t_Vec;
1736 t_Vec.x = p_X;
1737 t_Vec.y = p_Y;
1738 t_Vec.z = p_Z;
1739 return t_Vec;
1740}
1741
1748bool SDKClient::SetupHandNodes(uint32_t p_SklIndex)
1749{
1750 // Define number of fingers per hand and number of joints per finger
1751 const uint32_t t_NumFingers = 5;
1752 const uint32_t t_NumJoints = 4;
1753
1754 // Create an array with the initial position of each hand node.
1755 // Note, these values are just an example of node positions and refer to the hand laying on a flat surface.
1756 ManusVec3 t_Fingers[t_NumFingers * t_NumJoints] = {
1757 CreateManusVec3(0.024950f, 0.000000f, 0.025320f), //Thumb CMC joint
1758 CreateManusVec3(0.000000f, 0.000000f, 0.032742f), //Thumb MCP joint
1759 CreateManusVec3(0.000000f, 0.000000f, 0.028739f), //Thumb IP joint
1760 CreateManusVec3(0.000000f, 0.000000f, 0.028739f), //Thumb Tip joint
1761
1762 //CreateManusVec3(0.011181f, 0.031696f, 0.000000f), //Index CMC joint // Note: we are not adding the matacarpal bones in this example, if you want to animate the metacarpals add each of them to the corresponding finger chain.
1763 CreateManusVec3(0.011181f, 0.000000f, 0.052904f), //Index MCP joint, if metacarpal is present: CreateManusVec3(0.000000f, 0.000000f, 0.052904f)
1764 CreateManusVec3(0.000000f, 0.000000f, 0.038257f), //Index PIP joint
1765 CreateManusVec3(0.000000f, 0.000000f, 0.020884f), //Index DIP joint
1766 CreateManusVec3(0.000000f, 0.000000f, 0.018759f), //Index Tip joint
1767
1768 //CreateManusVec3(0.000000f, 0.033452f, 0.000000f), //Middle CMC joint
1769 CreateManusVec3(0.000000f, 0.000000f, 0.051287f), //Middle MCP joint
1770 CreateManusVec3(0.000000f, 0.000000f, 0.041861f), //Middle PIP joint
1771 CreateManusVec3(0.000000f, 0.000000f, 0.024766f), //Middle DIP joint
1772 CreateManusVec3(0.000000f, 0.000000f, 0.019683f), //Middle Tip joint
1773
1774 //CreateManusVec3(-0.011274f, 0.031696f, 0.000000f), //Ring CMC joint
1775 CreateManusVec3(-0.011274f, 0.000000f, 0.049802f), //Ring MCP joint, if metacarpal is present: CreateManusVec3(0.000000f, 0.000000f, 0.049802f),
1776 CreateManusVec3(0.000000f, 0.000000f, 0.039736f), //Ring PIP joint
1777 CreateManusVec3(0.000000f, 0.000000f, 0.023564f), //Ring DIP joint
1778 CreateManusVec3(0.000000f, 0.000000f, 0.019868f), //Ring Tip joint
1779
1780 //CreateManusVec3(-0.020145f, 0.027538f, 0.000000f), //Pinky CMC joint
1781 CreateManusVec3(-0.020145f, 0.000000f, 0.047309f), //Pinky MCP joint, if metacarpal is present: CreateManusVec3(0.000000f, 0.000000f, 0.047309f),
1782 CreateManusVec3(0.000000f, 0.000000f, 0.033175f), //Pinky PIP joint
1783 CreateManusVec3(0.000000f, 0.000000f, 0.018020f), //Pinky DIP joint
1784 CreateManusVec3(0.000000f, 0.000000f, 0.019129f), //Pinky Tip joint
1785 };
1786
1787 // skeleton entry is already done. just the nodes now.
1788 // setup a very simple node hierarchy for fingers
1789 // first setup the root node
1790 //
1791 // root, This node has ID 0 and parent ID 0, to indicate it has no parent.
1792 SDKReturnCode t_Res = CoreSdk_AddNodeToSkeletonSetup(p_SklIndex, CreateNodeSetup(0, 0, 0, 0, 0, "Hand"));
1793 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1794 {
1795 spdlog::error("Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
1796 return false;
1797 }
1798
1799 // then loop for 5 fingers
1800 int t_FingerId = 0;
1801 for (uint32_t i = 0; i < t_NumFingers; i++)
1802 {
1803 uint32_t t_ParentID = 0;
1804 // then the digits of the finger that are linked to the root of the finger.
1805 for (uint32_t j = 0; j < t_NumJoints; j++)
1806 {
1807 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"));
1808 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1809 {
1810 printf("Failed to Add Node To Skeleton Setup. The error given %d.", t_Res);
1811 return false;
1812 }
1813 t_ParentID = 1 + t_FingerId + j;
1814 }
1815 t_FingerId += t_NumJoints;
1816 }
1817 return true;
1818}
1819
1825bool SDKClient::SetupHandChains(uint32_t p_SklIndex)
1826{
1827 // Add the Hand chain, this identifies the wrist of the hand
1828 {
1829 ChainSettings t_ChainSettings;
1830 ChainSettings_Init(&t_ChainSettings);
1831 t_ChainSettings.usedSettings = ChainType::ChainType_Hand;
1832 t_ChainSettings.hand.handMotion = HandMotion::HandMotion_IMU;
1833 t_ChainSettings.hand.fingerChainIdsUsed = 5; //we will have 5 fingers
1834 t_ChainSettings.hand.fingerChainIds[0] = 1; //links to the other chains we will define further down
1835 t_ChainSettings.hand.fingerChainIds[1] = 2;
1836 t_ChainSettings.hand.fingerChainIds[2] = 3;
1837 t_ChainSettings.hand.fingerChainIds[3] = 4;
1838 t_ChainSettings.hand.fingerChainIds[4] = 5;
1839
1840 ChainSetup t_Chain;
1841 ChainSetup_Init(&t_Chain);
1842 t_Chain.id = 0; //Every ID needs to be unique per chain in a skeleton.
1843 t_Chain.type = ChainType::ChainType_Hand;
1844 t_Chain.dataType = ChainType::ChainType_Hand;
1845 t_Chain.side = Side::Side_Left;
1846 t_Chain.dataIndex = 0;
1847 t_Chain.nodeIdCount = 1;
1848 t_Chain.nodeIds[0] = 0; //this links to the hand node created in the SetupHandNodes
1849 t_Chain.settings = t_ChainSettings;
1850
1851 SDKReturnCode t_Res = CoreSdk_AddChainToSkeletonSetup(p_SklIndex, t_Chain);
1852 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1853 {
1854 spdlog::error("Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
1855 return false;
1856 }
1857 }
1858
1859 // Add the 5 finger chains
1860 const ChainType t_FingerTypes[5] = { ChainType::ChainType_FingerThumb,
1861 ChainType::ChainType_FingerIndex,
1862 ChainType::ChainType_FingerMiddle,
1863 ChainType::ChainType_FingerRing,
1864 ChainType::ChainType_FingerPinky };
1865 for (int i = 0; i < 5; i++)
1866 {
1867 ChainSettings t_ChainSettings;
1868 ChainSettings_Init(&t_ChainSettings);
1869 t_ChainSettings.usedSettings = t_FingerTypes[i];
1870 t_ChainSettings.finger.handChainId = 0; //This links to the wrist chain above.
1871 //This identifies the metacarpal bone, if none exists, or the chain is a thumb it should be set to -1.
1872 //The metacarpal bone should not be part of the finger chain, unless you are defining a thumb which does need it.
1873 t_ChainSettings.finger.metacarpalBoneId = -1;
1874 t_ChainSettings.finger.useLeafAtEnd = false; //this is set to true if there is a leaf bone to the tip of the finger.
1875 ChainSetup t_Chain;
1876 ChainSetup_Init(&t_Chain);
1877 t_Chain.id = i + 1; //Every ID needs to be unique per chain in a skeleton.
1878 t_Chain.type = t_FingerTypes[i];
1879 t_Chain.dataType = t_FingerTypes[i];
1880 t_Chain.side = Side::Side_Left;
1881 t_Chain.dataIndex = 0;
1882 if (i == 0) // Thumb
1883 {
1884 t_Chain.nodeIdCount = 4; //The amount of node id's used in the array
1885 t_Chain.nodeIds[0] = 1; //this links to the hand node created in the SetupHandNodes
1886 t_Chain.nodeIds[1] = 2; //this links to the hand node created in the SetupHandNodes
1887 t_Chain.nodeIds[2] = 3; //this links to the hand node created in the SetupHandNodes
1888 t_Chain.nodeIds[3] = 4; //this links to the hand node created in the SetupHandNodes
1889 }
1890 else // All other fingers
1891 {
1892 t_Chain.nodeIdCount = 4; //The amount of node id's used in the array
1893 t_Chain.nodeIds[0] = (i * 4) + 1; //this links to the hand node created in the SetupHandNodes
1894 t_Chain.nodeIds[1] = (i * 4) + 2; //this links to the hand node created in the SetupHandNodes
1895 t_Chain.nodeIds[2] = (i * 4) + 3; //this links to the hand node created in the SetupHandNodes
1896 t_Chain.nodeIds[3] = (i * 4) + 4; //this links to the hand node created in the SetupHandNodes
1897 }
1898 t_Chain.settings = t_ChainSettings;
1899
1900 SDKReturnCode t_Res = CoreSdk_AddChainToSkeletonSetup(p_SklIndex, t_Chain);
1901 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1902 {
1903 return false;
1904 }
1905 }
1906 return true;
1907}
1908
1916{
1917 uint32_t t_SklIndex = 0;
1918
1919 SkeletonSetupInfo t_SKL;
1920 SkeletonSetupInfo_Init(&t_SKL);
1921 t_SKL.type = SkeletonType::SkeletonType_Hand;
1922 t_SKL.settings.scaleToTarget = true;
1924 t_SKL.settings.targetType = SkeletonTargetType::SkeletonTarget_UserIndexData;
1925 //If the user does not exist then the added skeleton will not be animated.
1926 //Same goes for any other skeleton made for invalid users/gloves.
1928
1929 CopyString(t_SKL.name, sizeof(t_SKL.name), std::string("LeftHand"));
1930
1931 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
1932 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1933 {
1934 spdlog::error("Failed to Create Skeleton Setup. The error given was {}.", t_Res);
1935 return;
1936 }
1937 m_TemporarySkeletons.push_back(t_SklIndex);
1938
1939 // setup nodes and chains for the skeleton hand
1940 if (!SetupHandNodes(t_SklIndex)) return;
1941 if (!SetupHandChains(t_SklIndex)) return;
1942
1943 // load skeleton
1944 uint32_t t_ID = 0;
1945 t_Res = CoreSdk_LoadSkeleton(t_SklIndex, &t_ID);
1946 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1947 {
1948 spdlog::error("Failed to load skeleton. The error given was {}.", t_Res);
1949 return;
1950 }
1952
1953 if (t_ID == 0)
1954 {
1955 spdlog::error("Failed to give skeleton an ID.");
1956 }
1957 m_LoadedSkeletons.push_back(t_ID);
1958}
1959
1962{
1963 if (m_LoadedSkeletons.size() == 0)
1964 {
1965 spdlog::error("There was no skeleton for us to unload.");
1966 return;
1967 }
1969 m_LoadedSkeletons.erase(m_LoadedSkeletons.begin());
1970 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
1971 {
1972 spdlog::error("Failed to unload skeleton. The error given was {}.", t_Res);
1973
1974 return;
1975 }
1976}
1977
1978
1979
1982{
1983 m_ChainType = ChainType::ChainType_Invalid;
1984
1985 uint32_t t_SklIndex = 0;
1986
1987 SkeletonSettings t_Settings;
1988 SkeletonSettings_Init(&t_Settings);
1989 t_Settings.scaleToTarget = true;
1990 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_UserData;
1991 t_Settings.skeletonTargetUserData.userID = 0;
1992
1993 SkeletonSetupInfo t_SKL;
1994 SkeletonSetupInfo_Init(&t_SKL);
1995 t_SKL.id = 0;
1996 t_SKL.type = SkeletonType::SkeletonType_Hand;
1997 t_SKL.settings = t_Settings;
1998 CopyString(t_SKL.name, sizeof(t_SKL.name), std::string("hand"));
1999
2000 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2001 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2002 {
2003 spdlog::error("Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2004 return;
2005 }
2006 m_TemporarySkeletons.push_back(t_SklIndex);
2007
2008 // setup nodes for the skeleton hand
2009 SetupHandNodes(t_SklIndex);
2010
2011 // allocate chains for skeleton
2012 t_Res = CoreSdk_AllocateChainsForSkeletonSetup(t_SklIndex);
2013 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2014 {
2015 spdlog::error("Failed to allocate chains for skeleton. The error given was {}.", t_Res);
2016 return;
2017 }
2018
2019 // get the skeleton info
2020 SkeletonSetupArraySizes t_SkeletonInfo;
2021 t_Res = CoreSdk_GetSkeletonSetupArraySizes(t_SklIndex, &t_SkeletonInfo);
2022 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2023 {
2024 spdlog::error("Failed to get info about skeleton. The error given was {}.", t_Res);
2025 return;
2026 }
2027
2028 ChainSetup* t_Chains = new ChainSetup[t_SkeletonInfo.chainsCount];
2029 // now get the chain data
2030 t_Res = CoreSdk_GetSkeletonSetupChains(t_SklIndex, t_Chains);
2031 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2032 {
2033 spdlog::error("Failed to get skeleton setup chains. The error given was {}.", t_Res);
2034 delete[] t_Chains;
2035 return;
2036 }
2037 // as proof store the first chain type
2038 m_ChainType = t_Chains[0].dataType;
2039
2040 // but since we want to cleanly load the skeleton without holding everything up
2041 // we need to set its side first
2042 for (size_t i = 0; i < t_SkeletonInfo.chainsCount; i++)
2043 {
2044 if (t_Chains[i].dataType == ChainType::ChainType_Hand)
2045 {
2046 t_Chains[i].side = Side::Side_Left; // we're just picking a side here.
2047
2048 t_Res = CoreSdk_OverwriteChainToSkeletonSetup(t_SklIndex, t_Chains[i]);
2049 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2050 {
2051 spdlog::error("Failed to overwrite Chain To Skeleton Setup. The error given was {}.", t_Res);
2052 delete[] t_Chains;
2053 return;
2054 }
2055 break; // no need to continue checking the others.
2056 }
2057 }
2058 // cleanup
2059 delete[] t_Chains;
2060
2061 // load skeleton so it is done.
2062 uint32_t t_ID = 0;
2063 t_Res = CoreSdk_LoadSkeleton(t_SklIndex, &t_ID);
2064 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2065 {
2066 spdlog::error("Failed to load skeleton. The error given was {}.", t_Res);
2067 return;
2068 }
2070
2071 if (t_ID == 0)
2072 {
2073 spdlog::error("Failed to give skeleton an ID.");
2074 }
2075 m_LoadedSkeletons.push_back(t_ID);
2076}
2077
2086{
2087 // define the session Id for which we want to save
2088 // in this example we want to save a skeleton for the current session so we use our own Session Id
2089 uint32_t t_SessionId = m_SessionId;
2090
2091 bool t_IsSkeletonModified = false; // this bool is set to true by the Dev Tools after saving any modification to the skeleton,
2092 // this triggers the OnSyStemCallback which is used in the SDK to be notified about a change to its temporary skeletons.
2093 // for the purpose of this example setting this bool to true is not really necessary.
2094
2095 // first create a skeleton setup of type Body
2096 uint32_t t_SklIndex = 0;
2097
2098 SkeletonSettings t_Settings;
2099 SkeletonSettings_Init(&t_Settings);
2100 t_Settings.scaleToTarget = true;
2101 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_UserData;
2102 t_Settings.skeletonTargetUserData.userID = 0; // this needs to be a real user Id when retargeting, when editing the temporary skeleton this may (hopefully) not cause issues
2103
2104 SkeletonSetupInfo t_SKL;
2105 SkeletonSetupInfo_Init(&t_SKL);
2106 t_SKL.id = 0;
2107 t_SKL.type = SkeletonType::SkeletonType_Body;
2108 t_SKL.settings = t_Settings;
2109 CopyString(t_SKL.name, sizeof(t_SKL.name), std::string("body"));
2110
2111 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2112 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2113 {
2114 spdlog::error("Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2115 return;
2116 }
2117 m_TemporarySkeletons.push_back(t_SklIndex);
2118 //Add 3 nodes to the skeleton setup
2119 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex, CreateNodeSetup(0, 0, 0, 0, 0, "root"));
2120 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2121 {
2122 spdlog::error("Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2123 return;
2124 }
2125
2126 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex, CreateNodeSetup(1, 0, 0, 1, 0, "branch"));
2127 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2128 {
2129 spdlog::error("Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2130 return;
2131 }
2132
2133 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex, CreateNodeSetup(2, 1, 0, 2, 0, "leaf"));
2134 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2135 {
2136 spdlog::error("Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2137 return;
2138 }
2139
2140 //Add one chain of type Leg to the skeleton setup
2141 ChainSettings t_ChainSettings;
2142 ChainSettings_Init(&t_ChainSettings);
2143 t_ChainSettings.usedSettings = ChainType::ChainType_Leg;
2144 t_ChainSettings.leg.footForwardOffset = 0;
2145 t_ChainSettings.leg.footSideOffset = 0;
2146 t_ChainSettings.leg.reverseKneeDirection = false;
2147 t_ChainSettings.leg.kneeRotationOffset = 0;
2148
2149 ChainSetup t_Chain;
2150 ChainSetup_Init(&t_Chain);
2151 t_Chain.id = 0;
2152 t_Chain.type = ChainType::ChainType_Leg;
2153 t_Chain.dataType = ChainType::ChainType_Leg;
2154 t_Chain.dataIndex = 0;
2155 t_Chain.nodeIdCount = 3;
2156 t_Chain.nodeIds[0] = 0;
2157 t_Chain.nodeIds[1] = 1;
2158 t_Chain.nodeIds[2] = 2;
2159 t_Chain.settings = t_ChainSettings;
2160 t_Chain.side = Side::Side_Left;
2161
2162 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chain);
2163 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2164 {
2165 spdlog::error("Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
2166 return;
2167 }
2168
2169 // save the temporary skeleton
2170 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2171 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2172 {
2173 spdlog::error("Failed to save temporary skeleton. The error given was {}.", t_Res);
2174 return;
2175 }
2176
2177 // if we want to go on with the modifications to the same temporary skeleton
2178 // get the skeleton
2179 t_Res = CoreSdk_GetTemporarySkeleton(t_SklIndex, t_SessionId);
2180 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2181 {
2182 spdlog::error("Failed to get temporary skeleton. The error given was {}.", t_Res);
2183 return;
2184 }
2185
2186 // now add second chain to the same temporary skeleton
2187 t_ChainSettings.usedSettings = ChainType::ChainType_Head;
2188
2189 t_Chain.id = 1;
2190 t_Chain.type = ChainType::ChainType_Head;
2191 t_Chain.dataType = ChainType::ChainType_Head;
2192 t_Chain.dataIndex = 0;
2193 t_Chain.nodeIdCount = 1;
2194 t_Chain.nodeIds[0] = 0;
2195 t_Chain.settings = t_ChainSettings;
2196 t_Chain.side = Side::Side_Center;
2197
2198 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chain);
2199 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2200 {
2201 spdlog::error("Failed to Add Chain To Skeleton Setup. The error given was {}.", t_Res);
2202 return;
2203 }
2204
2205 // save the temporary skeleton
2206 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2207 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2208 {
2209 spdlog::error("Failed to save temporary skeleton. The error given was {}.", t_Res);
2210 return;
2211 }
2212
2213 // get the skeleton info (number of nodes and chains for that skeleton)
2214 SkeletonSetupArraySizes t_SkeletonInfo;
2215 t_Res = CoreSdk_GetSkeletonSetupArraySizes(t_SklIndex, &t_SkeletonInfo);
2216 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2217 {
2218 spdlog::error("Failed to get info about skeleton. The error given was {}.", t_Res);
2219 return;
2220 }
2221
2222 // now get the chain data
2223 ChainSetup* t_Chains = new ChainSetup[t_SkeletonInfo.chainsCount];
2224 t_Res = CoreSdk_GetSkeletonSetupChains(t_SklIndex, t_Chains);
2225 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2226 {
2227 spdlog::error("Failed to get skeleton setup chains. The error given was {}.", t_Res);
2228 return;
2229 }
2230
2231 // get the node data
2232 NodeSetup* t_Nodes = new NodeSetup[t_SkeletonInfo.nodesCount];
2233 t_Res = CoreSdk_GetSkeletonSetupNodes(t_SklIndex, t_Nodes);
2234 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2235 {
2236 spdlog::error("Failed to get skeleton setup nodes. The error given was {}.", t_Res);
2237 return;
2238 }
2239
2240 // just as an example try to get the skeleton setup info
2241 SkeletonSetupInfo t_SKeletonSetupInfo;
2242 SkeletonSetupInfo_Init(&t_SKeletonSetupInfo);
2243 t_Res = CoreSdk_GetSkeletonSetupInfo(t_SklIndex, &t_SKeletonSetupInfo);
2244 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2245 {
2246 spdlog::error("Failed to overwrite Skeleton Setup. The error given was {}.", t_Res);
2247 return;
2248 }
2249
2250 // if we want to modify the skeleton setup or if we want to apply some changes to the chains or nodes:
2251 // first overwrite the existing skeleton setup and then re-add all the chains and nodes to it
2252 SkeletonSettings_Init(&t_Settings);
2253 t_Settings.targetType = SkeletonTargetType::SkeletonTarget_GloveData;
2254
2255 t_SKL.settings = t_Settings;
2256 CopyString(t_SKL.name, sizeof(t_SKL.name), std::string("body2"));
2257
2258 // this way we overwrite the temporary skeleton with index t_SklIndex with the modified skeleton setup
2259 t_Res = CoreSdk_OverwriteSkeletonSetup(t_SklIndex, t_SKL);
2260 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2261 {
2262 spdlog::error("Failed to overwrite Skeleton Setup. The error given was {}.", t_Res);
2263 return;
2264 }
2265
2266 // modify chains and nodes
2267 t_Chains[0].side = Side::Side_Right;
2268 t_Nodes[0].type = NodeType::NodeType_Mesh;
2269
2270 // add all the existing nodes to the new skeleton setup
2271 for (size_t i = 0; i < t_SkeletonInfo.nodesCount; i++)
2272 {
2273 t_Res = CoreSdk_AddNodeToSkeletonSetup(t_SklIndex, t_Nodes[i]);
2274 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2275 {
2276 spdlog::error("Failed to Add Node To Skeleton Setup. The error given was {}.", t_Res);
2277 return;
2278 }
2279 }
2280
2281 // then add all the existing chains to the new skeleton setup
2282 for (size_t i = 0; i < t_SkeletonInfo.chainsCount; i++)
2283 {
2284 t_Res = CoreSdk_AddChainToSkeletonSetup(t_SklIndex, t_Chains[i]);
2285 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2286 {
2287 spdlog::error("Failed to Add Chains To Skeleton Setup. The error given was {}.", t_Res);
2288 return;
2289 }
2290 }
2291
2292 // cleanup
2293 delete[] t_Chains;
2294 delete[] t_Nodes;
2295
2296 // save temporary skeleton
2297 // in the Dev Tools this bool is set to true when saving the temporary skeleton, this triggers OnSystemCallback which
2298 // notifies the SDK sessions about a modifications to one of their temporary skeletons.
2299 // setting the bool to true in this example is not really necessary, it's just for testing purposes.
2300 t_IsSkeletonModified = true;
2301 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2302 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2303 {
2304 spdlog::error("Failed to save temporary skeleton. The error given was {}.", t_Res);
2305 return;
2306 }
2307}
2308
2312{
2313 // clear the first element of the temporary skeleton list
2314 if (m_TemporarySkeletons.size() == 0)
2315 {
2316 spdlog::error("There are no Temporary Skeletons to clear!");
2317 return;
2318 }
2319 uint32_t t_SklIndex = m_TemporarySkeletons[0];
2321 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2322 {
2323 spdlog::error("Failed to Clear Temporary Skeleton. The error given was {}.", t_Res);
2324 return;
2325 }
2327}
2328
2332{
2333 if (m_TemporarySkeletons.size() == 0)
2334 {
2335 spdlog::error("There are no Temporary Skeletons to clear!");
2336 return;
2337 }
2339 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2340 {
2341 spdlog::error("Failed to Clear All Temporary Skeletons. The error given was {}.", t_Res);
2342 return;
2343 }
2344 m_TemporarySkeletons.clear();
2345}
2346
2348{
2349 // this example shows how to save a temporary skeleton to a file
2350 // first create a temporary skeleton:
2351
2352 // define the session Id for which we want to save
2353 uint32_t t_SessionId = m_SessionId;
2354
2355 bool t_IsSkeletonModified = false; // setting this bool to true is not necessary here, it is mostly used by the Dev Tools
2356 // to notify the SDK sessions about their skeleton being modified.
2357
2358 // first create a skeleton setup
2359 uint32_t t_SklIndex = 0;
2360
2361 SkeletonSetupInfo t_SKL;
2362 SkeletonSetupInfo_Init(&t_SKL);
2363 t_SKL.type = SkeletonType::SkeletonType_Hand;
2364 t_SKL.settings.scaleToTarget = true;
2365 t_SKL.settings.targetType = SkeletonTargetType::SkeletonTarget_GloveData;
2367
2368 CopyString(t_SKL.name, sizeof(t_SKL.name), std::string("LeftHand"));
2369
2370 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2371 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2372 {
2373 spdlog::error("Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2374 return;
2375 }
2376 m_TemporarySkeletons.push_back(t_SklIndex);
2377
2378 // setup nodes and chains for the skeleton hand
2379 if (!SetupHandNodes(t_SklIndex)) return;
2380 if (!SetupHandChains(t_SklIndex)) return;
2381
2382 // save the temporary skeleton
2383 t_Res = CoreSdk_SaveTemporarySkeleton(t_SklIndex, t_SessionId, t_IsSkeletonModified);
2384 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2385 {
2386 spdlog::error("Failed to save temporary skeleton. The error given was {}.", t_Res);
2387 return;
2388 }
2389
2390 // now compress the temporary skeleton data and get the size of the compressed data:
2391 uint32_t t_TemporarySkeletonLengthInBytes;
2392
2393 t_Res = CoreSdk_CompressTemporarySkeletonAndGetSize(t_SklIndex, t_SessionId, &t_TemporarySkeletonLengthInBytes);
2394 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2395 {
2396 spdlog::error("Failed to compress temporary skeleton and get size. The error given was {}.", t_Res);
2397 return;
2398 }
2399 unsigned char* t_TemporarySkeletonData = new unsigned char[t_TemporarySkeletonLengthInBytes];
2400
2401 // get the array of bytes with the compressed temporary skeleton data, remember to always call function CoreSdk_CompressTemporarySkeletonAndGetSize
2402 // before trying to get the compressed temporary skeleton data
2403 t_Res = CoreSdk_GetCompressedTemporarySkeletonData(t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2404 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2405 {
2406 spdlog::error("Failed to get compressed temporary skeleton data. The error given was {}.", t_Res);
2407 return;
2408 }
2409
2410 // now save the data into a .mskl file
2411 // as an example we save the temporary skeleton in a folder called ManusTemporarySkeleton inside the documents directory
2412 // get the path for the documents directory
2413 std::string t_DirectoryPathString = GetDocumentsDirectoryPath_UTF8();
2414
2415 // create directory name and file name for storing the temporary skeleton
2416 std::string t_DirectoryPath =
2417 t_DirectoryPathString
2419 + "ManusTemporarySkeleton";
2420
2421 CreateFolderIfItDoesNotExist(t_DirectoryPath);
2422
2423 std::string t_DirectoryPathAndFileName =
2424 t_DirectoryPath
2426 + "TemporarySkeleton.mskl";
2427
2428 // write the temporary skeleton data to .mskl file
2429 std::ofstream t_File = GetOutputFileStream(t_DirectoryPathAndFileName);
2430 t_File.write((char*)t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2431 t_File.close();
2432
2433 t_Res = CoreSdk_ClearTemporarySkeleton(t_SklIndex, t_SessionId);
2434 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2435 {
2436 spdlog::error("Failed to Clear Temporary Skeleton after saving. The error given was {}.", t_Res);
2437 return;
2438 }
2440}
2441
2442
2444{
2445 // this example shows how to load a temporary skeleton data from a file
2446
2447 // as an example we try to get the temporary skeleton data previously saved as .mskl file in directory Documents/ManusTemporarySkeleton
2448 // get the path for the documents directory
2449 std::string t_DirectoryPathString = GetDocumentsDirectoryPath_UTF8();
2450
2451 // check if directory exists
2452 std::string t_DirectoryPath =
2453 t_DirectoryPathString
2455 + "ManusTemporarySkeleton";
2456
2457 if (!DoesFolderOrFileExist(t_DirectoryPath))
2458 {
2459 SPDLOG_WARN("Failed to read from client file, the mentioned directory does not exist");
2460 return;
2461 }
2462
2463 // create string with file name
2464 std::string t_DirectoryPathAndFileName =
2465 t_DirectoryPath
2467 + "TemporarySkeleton.mskl";
2468
2469 // read from file
2470 std::ifstream t_File = GetInputFileStream(t_DirectoryPathAndFileName);
2471
2472 if (!t_File)
2473 {
2474 SPDLOG_WARN("Failed to read from client file, the file does not exist in the mentioned directory");
2475 return;
2476 }
2477
2478 // get file dimension
2479 t_File.seekg(0, t_File.end);
2480 int t_FileLength = (int)t_File.tellg();
2481 t_File.seekg(0, t_File.beg);
2482
2483 // get temporary skeleton data from file
2484 unsigned char* t_TemporarySkeletonData = new unsigned char[t_FileLength];
2485 t_File.read((char*)t_TemporarySkeletonData, t_FileLength);
2486 t_File.close();
2487
2488
2489 // save the zipped temporary skeleton information, they will be used internally for sending the data to Core
2490 uint32_t t_TemporarySkeletonLengthInBytes = t_FileLength;
2491
2492 if (t_TemporarySkeletonData == nullptr)
2493 {
2494 SPDLOG_WARN("Failed to read the compressed temporary skeleton data from file");
2495 delete[] t_TemporarySkeletonData;
2496 return;
2497 }
2498
2499 // create a skeleton setup where we will store the temporary skeleton retrieved from file
2500 SkeletonSetupInfo t_SKL;
2501 SkeletonSetupInfo_Init(&t_SKL);
2502 uint32_t t_SklIndex = 0;
2503 SDKReturnCode t_Res = CoreSdk_CreateSkeletonSetup(t_SKL, &t_SklIndex);
2504 if (t_Res != SDKReturnCode::SDKReturnCode_Success)
2505 {
2506 spdlog::error("Failed to Create Skeleton Setup. The error given was {}.", t_Res);
2507 return;
2508 }
2509 m_TemporarySkeletons.push_back(t_SklIndex);
2510
2511 // associate the retrieved temporary skeleton to the current session id
2512 uint32_t t_SessionId = m_SessionId;
2513
2514 // load the temporary skeleton data retrieved from the zipped file and save it with index t_SklIndex and session id of the current session
2515 SDKReturnCode t_Result = CoreSdk_GetTemporarySkeletonFromCompressedData(t_SklIndex, t_SessionId, t_TemporarySkeletonData, t_TemporarySkeletonLengthInBytes);
2516 if (t_Result != SDKReturnCode::SDKReturnCode_Success)
2517 {
2518 SPDLOG_WARN("Failed to load temporary skeleton data from client file in Core, the error code was: {}.", t_Result);
2519 return;
2520 }
2521
2522 delete[] t_TemporarySkeletonData;
2523}
2524
2526{
2527 ManusTimestamp t_TS;
2528 ManusTimestamp_Init(&t_TS);
2529 ManusTimestampInfo t_TSInfo;
2530 ManusTimestampInfo_Init(&t_TSInfo);
2531 t_TSInfo.fraction = 69;
2532 t_TSInfo.second = 6;
2533 t_TSInfo.minute = 9;
2534 t_TSInfo.hour = 6;
2535 t_TSInfo.day = 9;
2536 t_TSInfo.month = 6;
2537 t_TSInfo.year = 6969;
2538 t_TSInfo.timecode = true;
2539
2540 CoreSdk_SetTimestampInfo(&t_TS, t_TSInfo);
2541
2542 ManusTimestampInfo t_TSInfo2;
2543 CoreSdk_GetTimestampInfo(t_TS, &t_TSInfo2);
2544}
2545
2547{
2548 for (int i = 0; i < m_TemporarySkeletons.size(); i++)
2549 {
2550 if (m_TemporarySkeletons[i] == p_Idx)
2551 {
2552 m_TemporarySkeletons.erase(m_TemporarySkeletons.begin() + i);
2553 }
2554 }
2555}
std::string ConvertDeviceClassTypeToString(DeviceClassType p_Type)
Definition: SDKClient.cpp:1070
std::string ConvertDeviceFamilyTypeToString(DeviceFamilyType p_Type)
Definition: SDKClient.cpp:1085
#define GO_TO_DISPLAY(p_Key, p_Function)
Definition: SDKClient.cpp:8
std::string GetFPSEnumName(TimecodeFPS p_FPS)
Definition: SDKClient.cpp:1249
#define GO_TO_MENU_IF_REQUESTED()
Definition: SDKClient.cpp:11
CORESDK_API SDKReturnCode CoreSdk_GetDataForDongle(uint32_t p_DongleId, DongleLandscapeData *p_DongleData)
Gets the data for a dongle with the given id.
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonSetupNodes(uint32_t p_SkeletonSetupIndex, NodeSetup *p_SDK)
Get setup nodes for a SkeletonSetup at a given index. The size of the given array must match the node...
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfAvailableTrackersForUserId(uint32_t *p_NumberOfAvailableTrackers, uint32_t p_UserId)
Get the number of available trackers for a user with given Id.
CORESDK_API SDKReturnCode CoreSdk_SaveTemporarySkeleton(uint32_t p_SkeletonSetupIndex, uint32_t p_SessionId, bool p_IsSkeletonModified)
Save a SkeletonSetup at a given index and sessionId into Manus Core for use in the Dev Tools....
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonSetupChains(uint32_t p_SkeletonSetupIndex, ChainSetup *p_SDK)
Get setup chains for a SkeletonSetup at a given index. The size of the given array must match the cha...
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfHapticsDongles(uint32_t *p_NumberOfHapticsDongles)
Get the number of available haptics dongles.
CORESDK_API SDKReturnCode CoreSdk_CompressTemporarySkeletonAndGetSize(uint32_t p_SkeletonSetupIndex, uint32_t p_SessionId, uint32_t *p_TemporarySkeletonLengthInBytes)
Send a temporary skeleton to Core to compress it (convert it into an array of bytes) and then get the...
CORESDK_API SDKReturnCode CoreSdk_OverwriteSkeletonSetup(uint32_t p_SkeletonSetupIndex, SkeletonSetupInfo p_SkeletonSetup)
Overwrite an existing SkeletonSetup at a given index. This will remove all chains and nodes from the ...
CORESDK_API SDKReturnCode CoreSdk_AllocateChainsForSkeletonSetup(uint32_t p_SkeletonSetupIndex)
Allocate chains for a SkeletonSetup at a given index.
CORESDK_API SDKReturnCode CoreSdk_GetAvailableHostsFound(ManusHost *p_AvailableHostsFound, const uint32_t p_NumberOfHostsThatFitInArray)
Fill the given array with information on the hosts that were found. This is the third and final funct...
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfAvailableTrackers(uint32_t *p_NumberOfAvailableTrackers)
Get the number of available trackers.
CORESDK_API SDKReturnCode CoreSdk_GetIdsOfAvailableTrackers(TrackerId *p_IdsOfAvailableTrackers, uint32_t p_NumberOfIdsThatFitInArray)
Fill the given array with the IDs of available trackers. The size of the given array must match the n...
CORESDK_API SDKReturnCode CoreSdk_GetDongleIds(uint32_t *p_DongleIds, uint32_t p_NumberOfIdsThatFitInArray)
Fill the given array with the IDs of all available dongles. The size of the given array must match th...
CORESDK_API SDKReturnCode CoreSdk_ConnectGRPC()
Connect to the preset GRPC address.
CORESDK_API SDKReturnCode CoreSdk_Initialize(SessionType p_TypeOfSession)
Initialize the wrapper. Call this before using the wrapper.
CORESDK_API SDKReturnCode CoreSdk_ShutDown()
Shut down the wrapper. This needs to be called last.
CORESDK_API SDKReturnCode CoreSdk_GetDataForGlove_UsingGloveId(uint32_t p_GloveId, GloveLandscapeData *p_GloveData)
Get data for the glove with the given glove ID.
CORESDK_API SDKReturnCode CoreSdk_LoadSkeleton(uint32_t p_SkeletonSetupIndex, uint32_t *p_SkeletonId)
Sends a skeleton setup to core to become a skeleton upon which data is applied. Returns the skeleton ...
CORESDK_API SDKReturnCode CoreSdk_GetCompressedTemporarySkeletonData(unsigned char *p_TemporarySkeletonData, uint32_t p_TemporarySkeletonLengthInBytes)
Get the compressed temporary skeleton data which are stored internally when calling function CoreSdk_...
CORESDK_API SDKReturnCode CoreSdk_VibrateFingersForSkeleton(uint32_t p_SkeletonId, Side p_HandType, const float *p_Powers)
Vibrate the motor on the fingers of a haptic glove associated to skeleton with given id....
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonInfo(uint32_t p_SkeletonIndex, SkeletonInfo *p_Info)
Get information about the final animated skeleton with given index.
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfDongles(uint32_t *p_NumberOfDongles)
Get the number of available dongles.
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfAvailableUsers(uint32_t *p_NumberOfAvailableUsers)
Get the number of available users. Note that this is reliant on the landscape, and the first second a...
CORESDK_API SDKReturnCode CoreSdk_CreateSkeletonSetup(SkeletonSetupInfo p_Skeleton, uint32_t *p_SkeletonSetupIndex)
Create a new SkeletonSetup with the given information and returns the index on which it is saved.
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForSkeletonStream(SkeletonStreamCallback_t p_SkeletonStreamCallback)
Register the callback function that is called when skeleton data comes in.
CORESDK_API SDKReturnCode CoreSdk_GetTemporarySkeleton(uint32_t p_SkeletonSetupIndex, uint32_t p_SessionId)
Get a SkeletonSetup at a given index and sessionId from Manus Core. This function does NOT return a l...
CORESDK_API SDKReturnCode CoreSdk_GetTemporarySkeletonFromCompressedData(uint32_t p_SkeletonSetupIndex, uint32_t p_SessionId, unsigned char *p_TemporarySkeletonData, uint32_t p_TemporarySkeletonLengthInBytes)
Send the compressed data (an array of bytes) retrieved from a file to Core to be decompressed and con...
CORESDK_API SDKReturnCode CoreSdk_ClearAllTemporarySkeletons()
Clear all temporary skeletons associated to the current session both in the sdk and core....
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForOnConnect(ConnectedToCoreCallback_t p_ConnectedCallback)
Register the callback function that is called when manus core gets connected to the sdk.
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonSetupInfo(uint32_t p_SkeletonSetupIndex, SkeletonSetupInfo *p_SDK)
Get setup info for a SkeletonSetup at a given index.
CORESDK_API SDKReturnCode CoreSdk_UnloadSkeleton(uint32_t p_SkeletonId)
Unload a skeleton with a certain ID from Manus Core, so data will no longer be generated for it.
CORESDK_API SDKReturnCode CoreSdk_ClearTemporarySkeleton(uint32_t p_SkeletonSetupIndex, uint32_t p_SessionId)
Clear a SkeletonSetup at a given index and sessionId in Manus Core and the SDK. The given setup index...
CORESDK_API SDKReturnCode CoreSdk_SetTimestampInfo(ManusTimestamp *p_Timestamp, ManusTimestampInfo p_Info)
Sets the timestamp according to the info (more readable form of timestamp).
CORESDK_API SDKReturnCode CoreSdk_GetTemporarySkeletonsForAllSessions(TemporarySkeletonSessionsData *p_temporarySkeletonSessionsData)
Get information (name and index) for the SkeletonSetups of the all sessions connected to Core.
CORESDK_API SDKReturnCode CoreSdk_AddNodeToSkeletonSetup(uint32_t p_SkeletonSetupIndex, NodeSetup p_Node)
Add a node to a SkeletonSetup at a given index.
CORESDK_API SDKReturnCode CoreSdk_WasDllBuiltInDebugConfiguration(bool *p_WasBuiltInDebugConfiguration)
Check if the wrapper DLL was built in the debug configuration.
CORESDK_API SDKReturnCode CoreSdk_GetHapticsDongleIds(uint32_t *p_HapticsDongleIds, uint32_t p_NumberOfIdsThatFitInArray)
Fill the given array with the IDs of all available haptics dongles. The size of the given array must ...
CORESDK_API SDKReturnCode CoreSdk_InitializeCoordinateSystemWithVUH(CoordinateSystemVUH p_CoordinateSystem, bool p_UseWorldCoordinates)
Initialize a coordinate system of type CoordinateSystemVUH. (View Up Handedness) This has to be calle...
CORESDK_API SDKReturnCode CoreSdk_GetVersionsAndCheckCompatibility(ManusVersion *p_SdkVersion, ManusVersion *p_CoreVersion, bool *p_AreVersionsCompatible)
Get the SDK and Core version used and check if they are compatible with each other.
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForLandscapeStream(LandscapeStreamCallback_t p_LandscapeStreamCallback)
Register the callback function that is called when the landscape data comes in.
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForErgonomicsStream(ErgonomicsStreamCallback_t p_ErgonomicsStreamCallback)
Register the callback function that is called when ergonomics data comes in.
CORESDK_API SDKReturnCode CoreSdk_GetNumberOfAvailableHostsFound(uint32_t *p_NumberOfAvailableHostsFound)
Get the number of hosts running Manus Core that were found. This is the second function to call when ...
CORESDK_API SDKReturnCode CoreSdk_DoesSkeletonGloveSupportHaptics(uint32_t p_SkeletonId, Side p_HandType, bool *p_IsHaptics)
Identifies if the glove associated to the skeleton with given id and side is a haptic one.
CORESDK_API SDKReturnCode CoreSdk_GetIdsOfAvailableUsers(uint32_t *p_IdsOfAvailableUsers, uint32_t p_NumberOfIdsThatFitInArray)
Fill the given array with the IDs of all available users. The size of the given array must match the ...
CORESDK_API SDKReturnCode CoreSdk_GetIdsOfAvailableTrackersForUserId(TrackerId *p_IdsOfAvailableTrackers, uint32_t p_UserId, uint32_t p_NumberOfIdsThatFitInArray)
Fill the given array with the IDs of available trackers for a user with given Id. The size of the giv...
CORESDK_API SDKReturnCode CoreSdk_ConnectToHost(ManusHost p_Host)
Connect to a host using the given host information.
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForSystemStream(SystemStreamCallback_t p_SystemStreamCallback)
Register the callback function that is called when core system related data comes in.
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonSetupArraySizes(uint32_t p_SkeletonSetupIndex, SkeletonSetupArraySizes *p_SkeletonInfo)
Get the skeleton info (number of nodes and chains) for a SkeletonSetup at a given index.
CORESDK_API SDKReturnCode CoreSdk_GetSessionId(uint32_t *p_SessionId)
Get the current session Id.
CORESDK_API SDKReturnCode CoreSdk_SendDataForTrackers(const TrackerData *p_TrackerData, uint32_t p_NumberOfTrackers)
Send data to Core for a tracker.
CORESDK_API SDKReturnCode CoreSdk_OverwriteChainToSkeletonSetup(uint32_t p_SkeletonSetupIndex, ChainSetup p_Chain)
Overwrite a chain in a SkeletonSetup, the chain to be overwritten is idenfified by p_Chain....
CORESDK_API SDKReturnCode CoreSdk_VibrateFingers(uint32_t p_DongleId, Side p_HandType, const float *p_Powers)
Vibrate the motor on the given fingers of a haptic glove. The order of the fingers is Thumb,...
CORESDK_API SDKReturnCode CoreSdk_AddChainToSkeletonSetup(uint32_t p_SkeletonSetupIndex, ChainSetup p_Chain)
Add a chain to a SkeletonSetup at a given index.
CORESDK_API SDKReturnCode CoreSdk_RegisterCallbackForOnDisconnect(DisconnectedFromCoreCallback_t p_DisconnectedCallback)
Register the callback function that is called when manus core gets disconnected from the sdk.
CORESDK_API SDKReturnCode CoreSdk_GetSkeletonData(uint32_t p_SkeletonIndex, SkeletonNode *p_Nodes, uint32_t p_NodeCount)
Get data for the final animated skeleton with given index. The size of the given array must match the...
CORESDK_API SDKReturnCode CoreSdk_LookForHosts(uint32_t p_WaitSeconds=1, bool p_LoopbackOnly=false)
Start a background task that looks for hosts running Manus Core. Call this first when looking for hos...
CORESDK_API SDKReturnCode CoreSdk_GetGlovesForDongle(uint32_t p_DongleId, uint32_t *p_LeftGloveId, uint32_t *p_RightGloveId)
Get glove id's for given dongle id.
CORESDK_API SDKReturnCode CoreSdk_GetTimestampInfo(ManusTimestamp p_Timestamp, ManusTimestampInfo *p_Info)
Gets the timestamp info (more readable form of timestamp).
CORESDK_API void ErgonomicsData_Init(ErgonomicsData *p_Val)
Initializer for a ErgonomicsData struct.
CORESDK_API void SkeletonSettings_Init(SkeletonSettings *p_Val)
Initializer for a SkeletonSettings struct.
CORESDK_API void CoordinateSystemVUH_Init(CoordinateSystemVUH *p_Val)
Initializer for a CoordinateSystemVUH struct.
CORESDK_API void SkeletonSetupInfo_Init(SkeletonSetupInfo *p_Val)
Initializer for a SkeletonSetupInfo struct.
CORESDK_API void ManusTimestampInfo_Init(ManusTimestampInfo *p_Val)
Initializer for a ManusTimestampInfo struct.
CORESDK_API void ChainSettings_Init(ChainSettings *p_Val)
Initializer for a ChainSettings struct.
CORESDK_API void NodeSetup_Init(NodeSetup *p_Val)
Initializer for a NodeSetup struct.
CORESDK_API void ManusTimestamp_Init(ManusTimestamp *p_Val)
Initializer for a ManusTimestamp struct.
CORESDK_API void ChainSetup_Init(ChainSetup *p_Val)
Initializer for a ChainSetup struct.
ChainType dataType
SkeletonType type
int32_t fingerChainIdsUsed
ManusVec3 position
char api[MAX_NUM_CHARS_IN_TIMECODE_INTERFACE_STRINGS]
TemporarySkeletonInfo skeletonInfo[MAX_NUMBER_OF_SKELETONS_PER_SESSION]
ManusQuaternion rotation
DeviceLandscape gloveDevices
TimecodeInterface currentInterface
ManusTimestamp publishTime
TimeLandscape time
bool useEndPointApproximations
NodeType type
TrackerId trackerId
ChainSettings settings
uint32_t parentID
SkeletonTargetType targetType
ChainType type
char versionInfo[MAX_NUM_CHARS_IN_VERSION]
TrackerType_t trackerType
NodeSettings settings
char infoString[MAX_NUM_CHARS_IN_SYSTEM_ERROR_MESSAGE]
char name[MAX_NUM_CHARS_IN_TIMECODE_INTERFACE_STRINGS]
SystemMessageType type
SkeletonSettings settings
char id[MAX_NUM_CHARS_IN_TRACKER_ID]
uint32_t infoUInt
ChainSettingsFinger finger
uint32_t dataIndex
uint32_t nodeIds[MAX_CHAIN_LENGTH]
HandMotion handMotion
SkeletonTargetUserIndexData skeletonTargetUserIndexData
int32_t fingerChainIds[MAX_NUM_FINGER_IDS]
char name[MAX_NUM_CHARS_IN_SKELETON_NAME]
SkeletonTargetUserData skeletonTargetUserData
uint32_t nodeIdCount
ChainSettingsHand hand
ChainSettingsLeg leg
char name[MAX_NUM_CHARS_IN_NODE_NAME]
ErgonomicsData data[MAX_NUMBER_OF_ERGONOMICS_DATA]
char licenseType[MAX_NUM_CHARS_IN_LICENSE_TYPE]
TimecodeFPS fps
TrackingQuality quality
float data[ErgonomicsDataType_MAX_SIZE]
DeviceFamilyType familyType
GloveLandscapeData gloves[MAX_NUMBER_OF_GLOVES]
ChainType usedSettings
ManusTransform transform
DeviceClassType classType
TemporarySkeletonsForSession temporarySkeletonsSessions[MAX_NUMBER_OF_SESSIONS]
uint32_t interfaceCount
NodeSettingsFlag usedSettings
SDKReturnCode
The return values that can be given by SDK wrapper functions.
#define MAX_NUMBER_OF_DONGLES
Used to descriptively refer to the max number of supported dongles. Used with arrays and loops to mak...
Definition: ManusSDKTypes.h:89
ChainType
Describes the possible chain types used when setting up the skeleton.
Side
Describes the possible chain side.
#define MAX_NUMBER_OF_TRACKERS
Constants for the maximum number of trackers. Used with arrays and loops to make them more descriptiv...
DeviceClassType
Describes the different types of device classes.
DeviceFamilyType
Describes the different types of Manus devices.
#define NUM_FINGERS_ON_HAND
Used to descriptively refer to the number of fingers on a hand. Used with arrays and loops to make th...
Definition: ManusSDKTypes.h:23
TimecodeFPS
The possible FPS rates.
@ DeviceClassType_Glove
@ DeviceClassType_Dongle
@ DeviceClassType_Glongle
@ DeviceFamilyType_Prime1
@ DeviceFamilyType_Quantum
@ DeviceFamilyType_PrimeX
@ DeviceFamilyType_Prime2
Stores all chain settings.
Stores the chain setup information.
Stores the information regarding the coordinate system used by the client, defined as VUH (view,...
Stores all the received dongle data.
Stores the received ergonomics data.
Stores the information sent by the ergonomics stream.
Stores all the received glove data.
Stores the landscape data.
Contains information for connecting to a host running Manus Core. Note that if one of these values is...
A compressed timestamp.
A 3D vector, used for translations.
Stores a single version string.
Stores the node setup information. Each node represents a segment of the skeleton that can be animate...
Stores all the possible skeleton settings.
Stores the amount of nodes and chains in the skeleton setup.
Stores the skeleton setup information.
Stores the information sent by the skeleton stream.
Stores the data associated to System messages received from Core.
Stores the temporary skeleton available for all sessions connected to Core.
Stores all the tracker data that can be sent or received.
Stores the name of a tracker.
std::string m_SystemMessage
Definition: SDKClient.hpp:225
void PrintSystemMessage()
Prints the last received system messages received from Core.
Definition: SDKClient.cpp:1135
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.
Definition: SDKClient.cpp:605
void ClearAllTemporarySkeletons()
This support function is used to clear all temporary skeletons associated to the current SDK session,...
Definition: SDKClient.cpp:2331
SessionType m_ClientType
Definition: SDKClient.hpp:185
ClientReturnCode ShutDown()
When you are done with the SDK, don't forget to nicely shut it down this will close all connections t...
Definition: SDKClient.cpp:152
virtual ClientReturnCode DisplayingDataTracker()
Definition: SDKClient.cpp:828
ClientReturnCode Run()
The main SDKClient loop. This is a simple state machine which switches between different substates.
Definition: SDKClient.cpp:62
virtual ClientReturnCode DisplayingLandscapeTimeData()
Definition: SDKClient.cpp:866
ManusTimestampInfo m_ErgoTimestampInfo
Definition: SDKClient.hpp:229
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.
Definition: SDKClient.cpp:1287
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...
Definition: SDKClient.cpp:954
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...
Definition: SDKClient.cpp:345
void PrintHandErgoData(ErgonomicsData &p_ErgoData, bool p_Left)
Prints the ergonomics data of a hand.
Definition: SDKClient.cpp:1014
ClientSkeletonCollection * m_NextSkeleton
Definition: SDKClient.hpp:217
ErgonomicsData m_RightGloveErgoData
Definition: SDKClient.hpp:231
bool m_TrackerDataDisplayPerUser
Definition: SDKClient.hpp:236
void ClearTemporarySkeleton()
This support function is used to clear a temporary skeleton from the temporary skeleton list,...
Definition: SDKClient.cpp:2311
void UpdateInput(void)
Update the current keyboard state.
uint32_t m_FirstRightGloveID
Definition: SDKClient.hpp:244
std::chrono::time_point< std::chrono::high_resolution_clock > m_TimeSinceLastDisconnect
Definition: SDKClient.hpp:221
const short int m_ConsoleWidth
Definition: SDKClient.hpp:180
ClientReturnCode Initialize()
Initialize the sample console and the SDK. This function attempts to resize the console window and th...
Definition: SDKClient.cpp:34
bool PlatformSpecificInitialization(void)
Initialise things only needed for this platform.
uint32_t m_SecondsToFindHosts
Definition: SDKClient.hpp:198
bool m_ShouldConnectLocally
Definition: SDKClient.hpp:193
virtual ClientReturnCode UpdateBeforeDisplayingData()
Some things happen before every display update, no matter what state. They happen here,...
Definition: SDKClient.cpp:717
virtual ClientReturnCode LookingForHosts()
Simple example of the SDK looking for manus core hosts on the network and display them on screen.
Definition: SDKClient.cpp:556
virtual ClientReturnCode InitializeSDK()
Initialize the sdk, register the callbacks and set the coordinate system. This needs to be done befor...
Definition: SDKClient.cpp:361
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...
Definition: SDKClient.cpp:1825
static void OnSystemCallback(const SystemMessage *const p_SystemMessage)
This gets called when receiving a system message from Core.
Definition: SDKClient.cpp:273
virtual ClientReturnCode RegisterAllCallbacks()
Used to register the callbacks between sdk and core. Callbacks that are registered functions that get...
Definition: SDKClient.cpp:433
uint32_t m_ConsoleClearTickCount
Definition: SDKClient.hpp:179
static SDKClient * s_Instance
Definition: SDKClient.hpp:174
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...
Definition: SDKClient.cpp:1161
void PrintDongleData()
Print the ergonomics data received from Core.
Definition: SDKClient.cpp:1103
virtual ClientReturnCode PickingConnectionType()
Overridable switch states of how the client flow is done. This is the first option screen in the clie...
Definition: SDKClient.cpp:500
void PrintSkeletonData()
Prints the finalized skeleton data received from Core. Since our console cannot render this data visu...
Definition: SDKClient.cpp:1146
std::chrono::time_point< std::chrono::high_resolution_clock > m_LastTemporarySkeletonUpdate
Definition: SDKClient.hpp:222
float m_TrackerOffset
Definition: SDKClient.hpp:237
virtual ClientReturnCode ConnectingToCore()
After a connection option was selected, the client will now try to connect to manus core via the SDK.
Definition: SDKClient.cpp:675
void LoadTestSkeleton()
This function sets up a very minimalistic hand skeleton. In order to have any 3d positional/rotationa...
Definition: SDKClient.cpp:1915
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()
Definition: SDKClient.cpp:845
std::unique_ptr< ManusHost[]> m_AvailableHosts
Definition: SDKClient.hpp:204
void PrintTrackerDataGlobal()
Prints the tracker data without taking users into account. This shows how one can get the tracker dat...
Definition: SDKClient.cpp:1182
virtual ClientReturnCode PickingHost()
Print the found hosts and give the user the option to select one.
Definition: SDKClient.cpp:627
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.
Definition: SDKClient.cpp:331
virtual ClientReturnCode DisplayingData()
Once the connections are made we loop this function it calls all the input handlers for different asp...
Definition: SDKClient.cpp:766
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...
bool m_TrackerTest
Definition: SDKClient.hpp:235
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 ...
Definition: SDKClient.cpp:301
uint32_t m_SleepBetweenReconnectingAttemptsInMs
Definition: SDKClient.hpp:202
void HandleSkeletonCommands()
Handles the console commands for the skeletons.
Definition: SDKClient.cpp:1558
SystemMessageType m_SystemMessageCode
Definition: SDKClient.hpp:226
uint32_t m_ModifiedSkeletonIndex
Definition: SDKClient.hpp:227
static void OnConnectedCallback(const ManusHost *const p_Host)
Gets called when the client is connects to manus core Using this callback is optional....
Definition: SDKClient.cpp:172
uint32_t m_HostToConnectTo
Definition: SDKClient.hpp:196
void RemoveIndexFromTemporarySkeletonList(uint32_t p_Idx)
Definition: SDKClient.cpp:2546
std::mutex m_LandscapeMutex
Definition: SDKClient.hpp:239
std::mutex m_SkeletonMutex
Definition: SDKClient.hpp:215
static ManusVec3 CreateManusVec3(float p_X, float p_Y, float p_Z)
Definition: SDKClient.cpp:1733
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
Definition: SDKClient.hpp:183
std::vector< uint32_t > m_LoadedSkeletons
Definition: SDKClient.hpp:212
void HandleHapticCommands()
This showcases haptics support on gloves. Send haptics commands to connected gloves if specific keys ...
Definition: SDKClient.cpp:1450
uint32_t m_SessionId
Definition: SDKClient.hpp:208
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...
Definition: SDKClient.cpp:1748
std::function< ClientReturnCode()> m_CurrentInteraction
Definition: SDKClient.hpp:190
virtual ClientReturnCode DisplayingDataSkeleton()
Definition: SDKClient.cpp:808
std::vector< uint32_t > m_TemporarySkeletons
Definition: SDKClient.hpp:213
void TestTimestamp()
Definition: SDKClient.cpp:2525
bool PlatformSpecificShutdown(void)
Shut down things only needed for this platform.
bool m_RequestedExit
Definition: SDKClient.hpp:176
void GetTemporarySkeletonFromFile()
Definition: SDKClient.cpp:2443
bool m_ShouldConnectGRPC
Definition: SDKClient.hpp:194
void AllocateChains()
This support function sets up an incomplete hand skeleton and then uses manus core to allocate chains...
Definition: SDKClient.cpp:1981
void HandleTrackerCommands()
This support function is used to set a test tracker and add it to the landscape.
Definition: SDKClient.cpp:1662
void SaveTemporarySkeletonToFile()
Definition: SDKClient.cpp:2347
virtual ClientReturnCode RestartSDK()
Used to restart and initialize the SDK to make sure a new connection can be set up....
Definition: SDKClient.cpp:411
const short int m_ConsoleScrollback
Definition: SDKClient.hpp:182
void PrintLandscapeTimeData()
Definition: SDKClient.cpp:1274
virtual ClientReturnCode DisplayingDataGlove()
display the ergonomics data of the gloves, and handles haptic commands.
Definition: SDKClient.cpp:790
virtual ClientReturnCode DisconnectedFromCore()
When the SDK loses the connection with Core the user can either close the sdk or try to reconnect to ...
Definition: SDKClient.cpp:885
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 ...
Definition: SDKClient.cpp:225
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.
Definition: SDKClient.cpp:1961
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
Definition: SDKClient.hpp:200
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
Definition: SDKClient.hpp:205
void PrintTrackerDataPerUser()
Prints the tracker data per user, this shows how to access this data for each user.
Definition: SDKClient.cpp:1205
void HandleTemporarySkeletonCommands()
Handles the console commands for the temporary skeletons.
Definition: SDKClient.cpp:1633
Landscape * m_Landscape
Definition: SDKClient.hpp:241
static void OnSkeletonStreamCallback(const SkeletonStreamInfo *const p_Skeleton)
This gets called when the client is connected to manus core.
Definition: SDKClient.cpp:236
std::mutex m_SystemMessageMutex
Definition: SDKClient.hpp:224
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...
Definition: SDKClient.cpp:1369
void BuildTemporarySkeleton()
This support function is used for the manual allocation of the skeleton chains with means of a tempor...
Definition: SDKClient.cpp:2085
void PrintErgonomicsData()
Print the ergonomics data received from Core.
Definition: SDKClient.cpp:1042
bool shouldHapticFinger[NUM_FINGERS_ON_HAND]
Definition: SDKClient.hpp:68
uint32_t m_NumberOfHostsFound
Definition: SDKClient.hpp:197
static void OnLandscapeCallback(const Landscape *const p_Landscape)
This gets called when receiving landscape information from core.
Definition: SDKClient.cpp:259
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...
Definition: SDKClient.cpp:1716
void PrintTemporarySkeletonInfo()
This support function gets the temporary skeletons for all sessions connected to Core and it prints t...
Definition: SDKClient.cpp:1410
Landscape * m_NewLandscape
Definition: SDKClient.hpp:240
void HandleSkeletonHapticCommands()
This showcases haptics support on the skeletons. Send haptics commands to the gloves connected to a s...
Definition: SDKClient.cpp:1573
ErgonomicsData m_LeftGloveErgoData
Definition: SDKClient.hpp:230
ChainType m_ChainType
Definition: SDKClient.hpp:233
ClientState m_PreviousState
Definition: SDKClient.hpp:188
std::vector< ClientSkeleton > skeletons
Definition: SDKClient.hpp:83
const short int m_ConsoleHeight
Definition: SDKClient.hpp:181
int32_t m_MaxReconnectionAttempts
Definition: SDKClient.hpp:201
ClientState m_State
Definition: SDKClient.hpp:187
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
Definition: SDKClient.hpp:243
ClientSkeletonCollection * m_Skeleton
Definition: SDKClient.hpp:218
Used to store all the final animated skeletons received from Core.
Definition: SDKClient.hpp:81
constexpr unsigned long long int MINIMUM_MILLISECONDS_BETWEEN_HAPTICS_COMMANDS
Constant expression used to define the time between two possible haptics commands sent.
Definition: SDKClient.hpp:26
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...
Definition: SDKClient.hpp:29
constexpr unsigned int NUMBER_OF_HANDS_SUPPORTED
Constant expression: number of hands supported by demo.
Definition: SDKClient.hpp:23
ClientReturnCode
Values that can be returned by this application.
Definition: SDKClient.hpp:47
Haptic settings for a single glove.
Definition: SDKClient.hpp:67