////====================================================================================================== //// Copyright 2023, NaturalPoint Inc. ////====================================================================================================== /** * ExampleGloveAdapterSingleton class is an adapter class provided to demonstrate how communication between plugin device and * the glove SDK can be managed. A singleton instance of this class manages interaction between plugin device and the glove * device SDK. The adapter instance also stores a keeps the latest data and device info map that stores the currently detected device serials * and the latest frame data so that corresponding glove device can poll from it. Please note that this is provided only as an example, and * there could be other ways to set this up. */ #pragma once #include #include #include #include #include #include // OptiTrack Peripheral Device API #include "AnalogChannelDescriptor.h" #include "GloveDataFormat.h" #include "HardwareSimulator.h" // Rokoko Integration #include "RokokoData.h" #include "RokokoUDPReceiver.h" #include "RokokoDataParser.h" #include "RokokoDataConverter.h" namespace OptiTrackPluginDevices { namespace ExampleDevice { class ExampleGloveAdapterSingleton; static ExampleGloveAdapterSingleton* s_Instance = nullptr; static std::unique_ptr gGloveAdapter; /** * This is an example glove adapter (singleton) class provided to demonstrate how glove data can be populated. * This adapter class is reponsible for all interaction with the device SDK, and populating the glove data. * Glove data for multiple glove devices should get aggregated in here. */ class ExampleGloveAdapterSingleton { friend class ExampleGloveDevice; public: ExampleGloveAdapterSingleton(AnalogSystem::IDeviceManager* pDeviceManager); ~ExampleGloveAdapterSingleton(); // Singleton design pattern ExampleGloveAdapterSingleton(const ExampleGloveAdapterSingleton&) = delete; // Should not be cloneable ExampleGloveAdapterSingleton& operator=(const ExampleGloveAdapterSingleton& other) = delete; // Shounot be assignable /** * Should call the shutdown from the plugin SDK. In this case, shutsdown the simulator */ bool ClientShutdown(); /** * Detection thread for connecting to the glove server. */ void DoDetectionThread(); std::thread mDetectionThread; unsigned int mConnectionAttemptCount = 0; const unsigned int kMaxConnectionAttempt = 10; /** * Connect to the glove host. */ bool ConnectToHost(); /** * Connect to Rokoko Studio via UDP. */ bool ConnectToRokoko(); /** * Disconnect from Rokoko Studio. */ void DisconnectFromRokoko(); private: /** * Returns whether detector is connected to Glove Host. */ bool IsConnected(); /** * Saves the latest data to the map */ void SetLatestData(const sGloveDeviceData& gloveFingerData); /** * Pointer to device manager for additional operations */ void SetDeviceManager(AnalogSystem::IDeviceManager* pDeviceManager); /** * Saves the latest glove data to the map */ void SetLatestDeviceInfo(const sGloveDeviceBaseInfo& deviceInfo); /** * Gets the latest data for device with given unique serial */ bool GetLatestData(const std::uint64_t mDeviceSerial, sGloveDeviceData& gloveFingerData); /** * Creates new device by instantiating the factory and transferring it to Motive */ void CreateNewGloveDevice(sGloveDeviceBaseInfo& deviceInfo); /** * Prints error into Motive. */ void NotifyConnectionFail(); bool bIsConnected = false; bool bIsDetecting = true; int mCurrentDeviceIndex = 0; std::string mServerAddress = ""; /** * [Glove SDK Placeholder] * Example data map for storing aggregated device data. */ uint16_t mDeviceCount = 0; std::vector mDetectedDevices; std::unordered_map mLatestGloveData; std::unordered_map mLatestDeviceInfo; /** * Rokoko integration members */ std::unique_ptr mRokokoReceiver; bool bIsRokokoConnected = false; RokokoData::LiveFrame_v4 mLastRokokoFrame; /** * [Legacy Glove SDK Placeholder - Commented Out] * The following methods were sample callback functions for simulated hardware. * Now replaced by Rokoko UDP communication. */ // bool bIsSimulating; void StartSimulatedHardware(int deviceCount); // Legacy support static void RegisterSDKCallbacks(); // Legacy support static void OnDataCallback(std::vector& gloveFingerData); // Legacy support static void OnDeviceInfoCallback(std::vector& newGloveInfo); // Legacy support static sGloveDeviceBaseInfo ConvertDeviceInfoFormat(SimulatedPluginDevices::SimulatedDeviceInfo& glove); // Legacy support static sGloveDeviceData ConvertDataFormat(const SimulatedPluginDevices::SimulatedGloveFrameData& glove); // Legacy support /** * Rokoko UDP data callback function. */ void OnRokokoDataReceived(const std::vector& data, const std::string& senderIP); /** * Process received Rokoko data and convert to OptiTrack format. */ void ProcessRokokoData(const std::vector& data); /** * Update device information (battery, signal strength, etc.) */ void UpdateDeviceInfo(uint64_t deviceId); /** * Detect and create Rokoko devices dynamically */ void DetectAndCreateRokokoDevices(); /** * Process data for multiple devices (left/right hand) */ void ProcessMultipleDeviceData(const RokokoData::LiveFrame_v4& rokokoFrame); /** * Process hand data for a specific device */ bool ProcessHandData(const RokokoData::Body& body, uint64_t deviceId, eGloveHandSide handSide); /** * Map left hand joints from Rokoko data */ void MapLeftHandJoints(const RokokoData::Body& body, std::vector& nodes); /** * Map right hand joints from Rokoko data */ void MapRightHandJoints(const RokokoData::Body& body, std::vector& nodes); /** * Map individual joint data */ void MapJoint(const RokokoData::ActorJointFrame& rokokoJoint, sFingerNode& optiTrackNode); protected: /** * [Legacy Glove SDK Simulator - Commented Out] * Instance of simulator (now replaced by Rokoko integration) */ // SimulatedPluginDevices::HardwareSimulator* mGloveSimulator; /** * [Glove SDK Placeholder] * Example glove data mutex */ std::recursive_mutex* mGloveDataMutex; /** * Pointer to device manager in Motive for reporting error messages. */ AnalogSystem::IDeviceManager* mDeviceManager; }; } }