├── src
├── java
│ └── VRE.Vridge.API
│ │ ├── settings.gradle
│ │ ├── VRE.Vridge.API.Client
│ │ ├── src
│ │ │ └── main
│ │ │ │ ├── javalite
│ │ │ │ └── com
│ │ │ │ │ └── riftcat
│ │ │ │ │ └── vridge
│ │ │ │ │ └── api
│ │ │ │ │ └── client
│ │ │ │ │ └── java
│ │ │ │ │ └── proto
│ │ │ │ │ └── .gitignore
│ │ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── riftcat
│ │ │ │ │ └── vridge
│ │ │ │ │ └── api
│ │ │ │ │ └── client
│ │ │ │ │ └── java
│ │ │ │ │ ├── proxy
│ │ │ │ │ ├── VRidgeApiProxy.java
│ │ │ │ │ ├── IBroadcastListener.java
│ │ │ │ │ ├── ClientProxyBase.java
│ │ │ │ │ ├── BroadcastProxy.java
│ │ │ │ │ ├── ControllerProxy.java
│ │ │ │ │ └── HeadTrackingProxy.java
│ │ │ │ │ ├── utils
│ │ │ │ │ ├── ILog.java
│ │ │ │ │ ├── APILogger.java
│ │ │ │ │ ├── SocketHelpers.java
│ │ │ │ │ ├── SerializationUtils.java
│ │ │ │ │ └── ButtonMask.java
│ │ │ │ │ ├── control
│ │ │ │ │ ├── BaseControlMessage.java
│ │ │ │ │ ├── ControlRequestCode.java
│ │ │ │ │ ├── responses
│ │ │ │ │ │ ├── EndpointCreated.java
│ │ │ │ │ │ ├── APIStatus.java
│ │ │ │ │ │ ├── EndpointStatus.java
│ │ │ │ │ │ └── ControlResponseHeader.java
│ │ │ │ │ ├── requests
│ │ │ │ │ │ ├── RequestEndpoint.java
│ │ │ │ │ │ └── ControlRequestHeader.java
│ │ │ │ │ └── ControlResponseCode.java
│ │ │ │ │ ├── codes
│ │ │ │ │ ├── TrackedDeviceStatus.java
│ │ │ │ │ ├── ControllerStateRequestCodes.java
│ │ │ │ │ ├── HeadTrackingResponseCodes.java
│ │ │ │ │ └── HeadTrackingRequestCodes.java
│ │ │ │ │ ├── Capabilities.java
│ │ │ │ │ ├── EndpointNames.java
│ │ │ │ │ ├── remotes
│ │ │ │ │ ├── VridgeRemoteConnectionStatus.java
│ │ │ │ │ ├── RemoteBase.java
│ │ │ │ │ ├── beacons
│ │ │ │ │ │ ├── VridgeServerBeacon.java
│ │ │ │ │ │ └── VridgeServerBeaconList.java
│ │ │ │ │ ├── DiscoveryClient.java
│ │ │ │ │ ├── HeadRemote.java
│ │ │ │ │ └── ControllerRemote.java
│ │ │ │ │ └── APIClient.java
│ │ │ │ └── proto
│ │ │ │ └── VridgeApiProtoDefinition.proto
│ │ └── build.gradle
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── .idea
│ │ ├── encodings.xml
│ │ ├── modules.xml
│ │ ├── runConfigurations.xml
│ │ ├── misc.xml
│ │ └── codeStyles
│ │ │ └── Project.xml
│ │ ├── build.gradle
│ │ ├── gradle.properties
│ │ ├── .gitignore
│ │ ├── gradlew.bat
│ │ └── gradlew
├── csharp
│ ├── VRE.Vridge.API.Client
│ │ ├── Messages
│ │ │ ├── OpenVR
│ │ │ │ ├── readme.txt
│ │ │ │ ├── VRControllerAxis_t.cs
│ │ │ │ ├── VRController.cs
│ │ │ │ ├── VRControllerState_t.cs
│ │ │ │ └── EVRButtonId.cs
│ │ │ ├── BasicTypes
│ │ │ │ └── HandType.cs
│ │ │ ├── v3
│ │ │ │ ├── Discovery
│ │ │ │ │ ├── BeaconOrigin.cs
│ │ │ │ │ └── Beacon.cs
│ │ │ │ ├── TrackedDeviceStatus.cs
│ │ │ │ ├── Controller
│ │ │ │ │ ├── Responses
│ │ │ │ │ │ └── ControllerStateResponse.cs
│ │ │ │ │ ├── HeadRelation.cs
│ │ │ │ │ ├── VRController.cs
│ │ │ │ │ └── Requests
│ │ │ │ │ │ └── ControllerStateRequest.cs
│ │ │ │ ├── HeadTracking
│ │ │ │ │ └── Responses
│ │ │ │ │ │ ├── TrackedPose.cs
│ │ │ │ │ │ └── HeadTrackingResponse.cs
│ │ │ │ └── Broadcast
│ │ │ │ │ └── HapticPulse.cs
│ │ │ ├── Control
│ │ │ │ ├── ControlRequestCode.cs
│ │ │ │ ├── Responses
│ │ │ │ │ ├── APIStatus.cs
│ │ │ │ │ ├── EndpointCreated.cs
│ │ │ │ │ ├── EndpointStatus.cs
│ │ │ │ │ └── ControlResponseHeader.cs
│ │ │ │ ├── Requests
│ │ │ │ │ ├── RequestEndpoint.cs
│ │ │ │ │ └── ControlRequestHeader.cs
│ │ │ │ ├── BaseControlMessage.cs
│ │ │ │ └── ControlResponseCode.cs
│ │ │ └── KeepAlive.cs
│ │ ├── Remotes
│ │ │ ├── Capabilities.cs
│ │ │ ├── VridgeRemoteConnectionStatus.cs
│ │ │ ├── Beacons
│ │ │ │ ├── VridgeServerBeaconList.cs
│ │ │ │ └── VridgeServerBeacon.cs
│ │ │ ├── RemoteBase.cs
│ │ │ ├── DiscoveryClient.cs
│ │ │ ├── HeadRemote.cs
│ │ │ └── ControllerRemote.cs
│ │ ├── EndpointNames.cs
│ │ ├── Helpers
│ │ │ ├── Logger.cs
│ │ │ ├── MathHelpers.cs
│ │ │ └── SerializationHelpers.cs
│ │ ├── VRE.Vridge.API.Client.csproj
│ │ └── Proxy
│ │ │ ├── ClientProxyBasePB.cs
│ │ │ ├── Broadcasts
│ │ │ └── BroadcastProxy.cs
│ │ │ ├── Controller
│ │ │ └── ControllerProxy.cs
│ │ │ ├── ClientProxyBase.cs
│ │ │ ├── APIClient.cs
│ │ │ └── HeadTracking
│ │ │ └── HeadTrackingProxy.cs
│ ├── examples
│ │ └── VRE.Vridge.API.DesktopClient
│ │ │ ├── icon.ico
│ │ │ ├── icon.png
│ │ │ ├── App.config
│ │ │ ├── Properties
│ │ │ ├── Settings.settings
│ │ │ ├── Settings.Designer.cs
│ │ │ ├── AssemblyInfo.cs
│ │ │ ├── Resources.Designer.cs
│ │ │ └── Resources.resx
│ │ │ ├── App.xaml.cs
│ │ │ ├── ViewModel
│ │ │ ├── ControlTarget.cs
│ │ │ ├── TrackingType.cs
│ │ │ └── ControllerMode.cs
│ │ │ ├── App.xaml
│ │ │ ├── packages.config
│ │ │ ├── Helpers.cs
│ │ │ ├── Converters
│ │ │ └── BoolToVisibilityConverter.cs
│ │ │ ├── Extensions.cs
│ │ │ ├── View
│ │ │ ├── LabeledSlider.xaml
│ │ │ ├── LabeledSlider.xaml.cs
│ │ │ ├── ControlWindow.xaml.cs
│ │ │ └── ControlWindow.xaml
│ │ │ └── VRE.Vridge.API.DesktopTester.csproj
│ └── VRE.Vridge.API.sln
└── vridge-api.proto
├── .gitignore
├── LICENSE
└── README.md
/src/java/VRE.Vridge.API/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':VRE.Vridge.API.Client'
2 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/javalite/com/riftcat/vridge/api/client/java/proto/.gitignore:
--------------------------------------------------------------------------------
1 | *.java
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/OpenVR/readme.txt:
--------------------------------------------------------------------------------
1 | Classes in OpenVR folder are 1:1 copies of OpenVR structs. See OpenVR reference for details.
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RiftCat/vridge-api/HEAD/src/csharp/examples/VRE.Vridge.API.DesktopClient/icon.ico
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RiftCat/vridge-api/HEAD/src/csharp/examples/VRE.Vridge.API.DesktopClient/icon.png
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RiftCat/vridge-api/HEAD/src/java/VRE.Vridge.API/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/BasicTypes/HandType.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.BasicTypes
2 | {
3 | public enum HandType : byte
4 | {
5 | Left,
6 | Right
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Discovery/BeaconOrigin.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.v3.Discovery
2 | {
3 | public enum BeaconOrigin
4 | {
5 | Server,
6 | Client
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/VRidgeApiProxy.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | public interface VRidgeApiProxy {
4 | void disconnect();
5 | }
6 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/utils/ILog.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.utils;
2 |
3 | public interface ILog {
4 | void debug(String s);
5 | void error(String s);
6 | }
7 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/ControlRequestCode.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.Control
2 | {
3 | public enum ControlRequestCode
4 | {
5 | RequestEndpoint = 1,
6 | RequestStatus = 2,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | NuGet Packages
2 | *.nupkg
3 | # The packages folder can be ignored because of Package Restore
4 | **/packages/*
5 |
6 | [Dd]ebug/
7 | [Dd]ebugPublic/
8 | [Rr]elease/
9 | [Rr]eleases/
10 | x64/
11 | x86/
12 | bld/
13 | [Bb]in/
14 | [Oo]bj/
15 | [Ll]og/
16 |
17 | .vs
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/BaseControlMessage.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control;
2 |
3 | public class BaseControlMessage {
4 |
5 | public int ProtocolVersion = 3;
6 | public int Code;
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace VRE.Vridge.API.DesktopTester
4 | {
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/KeepAlive.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages
2 | {
3 | // Send this with one zero byte to API service (excluding control) to keep the connection from timing out
4 | public struct KeepAlive
5 | {
6 | public byte[] Zero;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jan 22 19:43:41 CET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/ControlRequestCode.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control;
2 |
3 | public class ControlRequestCode {
4 |
5 | public static int RequestEndpoint = 1;
6 | public static int RequestStatus = 2;
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/responses/EndpointCreated.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.responses;
2 |
3 | public class EndpointCreated extends ControlResponseHeader {
4 | public int TimeoutSec;
5 | public int Port;
6 | }
7 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/Capabilities.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace VRE.Vridge.API.Client.Remotes
6 | {
7 | [Flags]
8 | public enum Capabilities
9 | {
10 | HeadTracking = 1,
11 | Controllers = 2
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/ViewModel/ControlTarget.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.DesktopTester.ViewModel
2 | {
3 | public enum ControlTarget
4 | {
5 | Head = 0,
6 | Controller1 = 1,
7 | Controller2 = 2,
8 | Controller3 = 3,
9 | Controller4 = 4,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/IBroadcastListener.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | import com.riftcat.vridge.api.client.java.proto.HapticPulse;
4 |
5 | public interface IBroadcastListener{
6 | void onHapticPulse(HapticPulse pulse);
7 | }
8 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/codes/TrackedDeviceStatus.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.codes;
2 |
3 | public class TrackedDeviceStatus {
4 | public static final byte Active = 0;
5 | public static final byte TempUnavailable = 1;
6 | public static final byte Disabled = 2;
7 | }
8 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/Capabilities.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java;
2 |
3 | public enum Capabilities {
4 | HeadTracking(1),
5 | Controllers(2);
6 |
7 | private final int value;
8 |
9 | Capabilities(int value) {
10 | this.value = value;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/EndpointNames.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java;
2 |
3 | public class EndpointNames {
4 | public static final String HeadTracking = "HeadTracking";
5 | public static final String Controller = "Controller";
6 | public static final String Broadcast = "Broadcast";
7 | }
8 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/VridgeRemoteConnectionStatus.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes;
2 |
3 | public enum VridgeRemoteConnectionStatus {
4 |
5 | /** Connected or will be auto-connected on first call */
6 | Okay,
7 | Unreachable,
8 | InUse,
9 | UnexpectedError
10 | }
11 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/ViewModel/TrackingType.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.DesktopTester.ViewModel
2 | {
3 | ///
4 | /// Tracking mode which decides how to use user values.
5 | ///
6 | public enum TrackingType
7 | {
8 | Position,
9 | PositionAndRotation,
10 | SyncOffset,
11 | AsyncOffset
12 | }
13 | }
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/codes/ControllerStateRequestCodes.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.codes;
2 |
3 | public class ControllerStateRequestCodes {
4 | public static int Disconnect = 255;
5 | public static int SendFullState = 1;
6 | public static int RecenterHead = 2;
7 |
8 | public static int Origin_Zero = 0;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/EndpointNames.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client
2 | {
3 | ///
4 | /// Endpoint names for API services.
5 | ///
6 | public static class EndpointNames
7 | {
8 | public static string HeadTracking = "HeadTracking";
9 | public static string Controller = "Controller";
10 | public static string Broadcast = "Broadcast";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Helpers/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 | using NetMQ;
6 |
7 | namespace VRE.Vridge.API.Client.Helpers
8 | {
9 | internal static class Logger
10 | {
11 | internal static void Debug(string msg)
12 | {
13 |
14 | }
15 |
16 | internal static void Error(string msg)
17 | {
18 |
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/VridgeRemoteConnectionStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace VRE.Vridge.API.Client.Remotes
6 | {
7 | public enum VridgeRemoteConnectionStatus
8 | {
9 | ///
10 | /// Connected or will be auto-connected on method call.
11 | ///
12 | Okay,
13 |
14 | Unreachable,
15 | InUse,
16 | UnexpectedError
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/codes/HeadTrackingResponseCodes.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.codes;
2 |
3 | public class HeadTrackingResponseCodes {
4 |
5 | public static int AcceptedYourData = 0;
6 |
7 | public static int SendingCurrentTrackedPose = 2;
8 |
9 | public static int PhoneDataTimeout = 253;
10 | public static int BadRequest = 254;
11 | public static int Disconnecting = 255;
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Responses/APIStatus.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace VRE.Vridge.API.Client.Messages.Control.Responses
4 | {
5 | ///
6 | /// Contains list of available (or not) API services.
7 | ///
8 | public class APIStatus : ControlResponseHeader
9 | {
10 | public List Endpoints;
11 |
12 | public APIStatus(ControlResponseCode code) : base(code)
13 | {
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Requests/RequestEndpoint.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.Control.Requests
2 | {
3 | public class RequestEndpoint : ControlRequestHeader
4 | {
5 | public string RequestedEndpointName;
6 |
7 | public RequestEndpoint(string name, string requestingAppName)
8 | : base(requestingAppName, ControlRequestCode.RequestEndpoint)
9 | {
10 | RequestedEndpointName = name;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/TrackedDeviceStatus.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.v3
2 | {
3 | public enum TrackedDeviceStatus
4 | {
5 | ///
6 | /// Currently tracked.
7 | ///
8 | Active = 0,
9 |
10 | ///
11 | /// Not in tracking range or tracking unavailable due to other reasons.
12 | ///
13 | TempUnavailable = 1,
14 |
15 | ///
16 | /// Permamently gone.
17 | ///
18 | Disabled = 2
19 | }
20 | }
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/BaseControlMessage.cs:
--------------------------------------------------------------------------------
1 | using ProtoBuf;
2 |
3 |
4 | namespace VRE.Vridge.API.Client.Messages.Control
5 | {
6 | public class BaseControlMessage
7 | {
8 | public int ProtocolVersion;
9 | public int Code;
10 |
11 | public BaseControlMessage(int versionCode, int code)
12 | {
13 | ProtocolVersion = versionCode;
14 | Code = code;
15 | }
16 |
17 | public BaseControlMessage()
18 | {
19 | // Deserialization only
20 | }
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/OpenVR/VRControllerAxis_t.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using ProtoBuf;
3 |
4 | namespace VRE.Vridge.API.Client.Messages.OpenVR
5 | {
6 | [StructLayout(LayoutKind.Sequential, Size = 8)]
7 | [ProtoContract]
8 | public struct VRControllerAxis_t
9 | {
10 | [ProtoMember(1)]
11 | public float x;
12 |
13 | [ProtoMember(2)]
14 | public float y;
15 |
16 | public VRControllerAxis_t(float x, float y)
17 | {
18 | this.x = x;
19 | this.y = y;
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/requests/RequestEndpoint.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.requests;
2 |
3 | import com.riftcat.vridge.api.client.java.control.ControlRequestCode;
4 |
5 | public class RequestEndpoint extends ControlRequestHeader{
6 |
7 | public String RequestedEndpointName;
8 |
9 | public RequestEndpoint(String name, String appName){
10 | super(appName);
11 | Code = ControlRequestCode.RequestEndpoint;
12 | RequestedEndpointName = name;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Requests/ControlRequestHeader.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.Control.Requests
2 | {
3 | public class ControlRequestHeader : BaseControlMessage
4 | {
5 | public string RequestingAppName;
6 |
7 | public ControlRequestHeader(string requestingAppName, ControlRequestCode code) : base(3, (int)code)
8 | {
9 | RequestingAppName = requestingAppName;
10 | }
11 |
12 | public ControlRequestHeader() : base()
13 | {
14 | // Deserialization only
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Discovery/Beacon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using ProtoBuf;
5 |
6 | namespace VRE.Vridge.API.Client.Messages.v3.Discovery
7 | {
8 | [ProtoContract]
9 | public class Beacon
10 | {
11 | [ProtoMember(1)]
12 | public BeaconOrigin Role;
13 |
14 | [ProtoMember(2)]
15 | public string MachineName { get; set; }
16 |
17 | [ProtoMember(3)]
18 | public string UserName { get; set; }
19 |
20 | [ProtoMember(4)]
21 | public string HumanReadableVersion { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/requests/ControlRequestHeader.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.requests;
2 |
3 | import com.riftcat.vridge.api.client.java.control.BaseControlMessage;
4 | import com.riftcat.vridge.api.client.java.control.ControlRequestCode;
5 |
6 | public class ControlRequestHeader extends BaseControlMessage {
7 | public String RequestingAppName;
8 |
9 | public ControlRequestHeader(String requestingAppName){
10 | RequestingAppName = requestingAppName;
11 | }
12 |
13 | public ControlRequestHeader(int reqCode){
14 | Code = reqCode;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/VRE.Vridge.API.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;net47
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | mavenCentral()
7 | google()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.0'
11 | classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | google()
21 | maven {
22 | url 'https://maven.google.com/'
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/RemoteBase.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes;
2 |
3 | import com.riftcat.vridge.api.client.java.proxy.ClientProxyBase;
4 | import com.riftcat.vridge.api.client.java.proxy.VRidgeApiProxy;
5 |
6 | class RemoteBase {
7 |
8 | private boolean isDisposed;
9 | private VRidgeApiProxy proxy;
10 |
11 | protected RemoteBase(VRidgeApiProxy proxy){
12 | this.proxy = proxy;
13 | }
14 |
15 | public boolean isDisposed() {
16 | return isDisposed;
17 | }
18 |
19 | public void dispose(){
20 | isDisposed = true;
21 | if(proxy != null){
22 | proxy.disconnect();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/utils/APILogger.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.utils;
2 |
3 | import java.util.LinkedList;
4 |
5 | public class APILogger {
6 |
7 | private static LinkedList loggers = new LinkedList();
8 |
9 | public static void AddLogListener(ILog logger){
10 | loggers.add(logger);
11 | }
12 |
13 | public static void debug(String s){
14 | for (ILog log : loggers) {
15 | log.debug(s);
16 | }
17 | }
18 |
19 | public static void zmq(String s) {
20 | //debug("ZMQ: " + s);
21 | }
22 |
23 | public static void error(String s) {
24 | for (ILog log : loggers) {
25 | log.error(s);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/utils/SocketHelpers.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.utils;
2 |
3 | import com.google.gson.Gson;
4 |
5 | import org.zeromq.ZMQ;
6 |
7 | public class SocketHelpers {
8 |
9 | public static Gson Serializer;
10 |
11 | static{
12 | Serializer = new Gson();
13 | }
14 |
15 | public static boolean SendAsJson(ZMQ.Socket socket, Object obj){
16 |
17 | String json = Serializer.toJson(obj);
18 | return socket.send(json);
19 | }
20 |
21 | public static T ReceiveByJson(ZMQ.Socket socket, Class type){
22 | String json = socket.recvStr();
23 | Object obj = Serializer.fromJson(json, type);
24 |
25 | return (T) obj;
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Helpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Media.Media3D;
3 |
4 | namespace VRE.Vridge.API.DesktopTester
5 | {
6 | public static class Helpers
7 | {
8 | public static Quaternion QuaternionFromYawPitchRoll(float yaw, float pitch, float roll)
9 | {
10 | double angleSquared = pitch * pitch + yaw * yaw + roll * roll;
11 | double s = 0;
12 | double c = 1;
13 | if (angleSquared > 0)
14 | {
15 | double angle = Math.Sqrt(angleSquared);
16 | s = Math.Sin(angle * 0.5f) / angle;
17 | c = Math.Cos(angle * 0.5f);
18 | }
19 |
20 | return new Quaternion(s * pitch, s * yaw, s * roll, c);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Responses/EndpointCreated.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using VRE.Vridge.API.Client.Proxy;
3 |
4 | namespace VRE.Vridge.API.Client.Messages.Control.Responses
5 | {
6 | public class EndpointCreated : ControlResponseHeader
7 | {
8 | public int Port { get; set; }
9 |
10 | ///
11 | /// Timeout after which the API server will disconnect you after not sending data for given amount of seconds.
12 | /// Use keep-alive (byte[1] {0}) packets if you want to stay silent but connected.
13 | /// See for example impl.
14 | ///
15 | public int TimeoutSec { get; set; }
16 |
17 | public EndpointCreated(ControlResponseCode code) : base(code)
18 | {
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Controller/Responses/ControllerStateResponse.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using ProtoBuf;
3 |
4 | namespace VRE.Vridge.API.Client.Messages.v3.Controller.Responses
5 | {
6 | [ProtoContract]
7 | public struct ControllerStateResponse
8 | {
9 | [ProtoMember(1)]
10 | public int Version;
11 |
12 | [ProtoMember(2)]
13 | public byte ReplyCode;
14 |
15 | public enum Response
16 | {
17 | ///
18 | /// In response to disconnect request.
19 | ///
20 | Disconnecting = 255,
21 |
22 | ///
23 | /// When request was not understood
24 | ///
25 | BadRequest = 254,
26 |
27 | AcceptedYourData = 0
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Converters/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows;
4 | using System.Windows.Data;
5 |
6 | namespace VRE.Vridge.API.DesktopTester.Converters
7 | {
8 | ///
9 | /// Converts between bool and WPF control visibility.
10 | ///
11 | public class BoolToVisibilityConverter : IValueConverter
12 | {
13 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
14 | {
15 | return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
16 | }
17 |
18 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
19 | {
20 | return value is Visibility && (Visibility)value == Visibility.Visible;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/OpenVR/VRController.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace VRE.Vridge.API.Client.Messages.OpenVR
4 | {
5 | [StructLayout(LayoutKind.Sequential, Size = 196)]
6 | public struct VRController
7 | {
8 | public int ControllerId;
9 |
10 | public int Status;
11 |
12 | public double Timestamp;
13 |
14 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
15 | public float[] OrientationMatrix;
16 |
17 | public VRControllerState_t ButtonState;
18 |
19 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
20 | public double[] Acceleration;
21 |
22 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
23 | public double[] Velocity;
24 |
25 | //0-undefined, 1-left, 2-right
26 | public int Role;
27 |
28 | public double PoseTimeOffset;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/ClientProxyBasePB.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using System.Timers;
4 | using NetMQ;
5 | using NetMQ.Sockets;
6 | using VRE.Vridge.API.Client.Helpers;
7 |
8 | namespace VRE.Vridge.API.Client.Proxy
9 | {
10 | ///
11 | /// Updated to use ProtoBufs instead of default C# marshalling.
12 | ///
13 | public class ClientProxyBasePB : ClientProxyBase
14 | {
15 | public ClientProxyBasePB(string endpointAddress, bool keepAlive = false) : base(endpointAddress, keepAlive) { }
16 |
17 | protected sealed override byte[] Serialize(object o)
18 | {
19 | return SerializationHelpers.ProtoSerialize(o);
20 | }
21 |
22 | protected sealed override T Deserialize(byte[] array)
23 | {
24 | return SerializationHelpers.ProtoDeserialize(array);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Controller/HeadRelation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace VRE.Vridge.API.Client.Messages.v3.Controller
6 | {
7 | public enum HeadRelation : byte
8 | {
9 | ///
10 | /// Pose is unrelated to current head pose.
11 | ///
12 | Unrelated = 0,
13 |
14 | ///
15 | /// Pose already is in head space.
16 | /// Will be auto-adjusted when head is recentered.
17 | ///
18 | IsInHeadSpace = 1,
19 |
20 | ///
21 | /// Pose is unrelated but is to be remapped in a way that assumes that pose forward
22 | /// should always be aligned to head's forward. Effectively the given pose is relative angle from current's head forward.
23 | ///
24 | SticksToHead = 2
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/responses/APIStatus.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.responses;
2 |
3 | import com.riftcat.vridge.api.client.java.EndpointNames;
4 |
5 | import java.util.List;
6 |
7 | public class APIStatus {
8 |
9 | public List Endpoints;
10 |
11 | @Override
12 | public String toString() {
13 |
14 | String strStatus = "";
15 |
16 | for(EndpointStatus status : Endpoints){
17 | strStatus += status.Name + "(" + status.codeString() + ") | ";
18 | }
19 |
20 | return strStatus;
21 | }
22 |
23 | public EndpointStatus findEndpoint(String name){
24 | for (EndpointStatus endpoint : Endpoints) {
25 | if(endpoint.Name.equals(name)){
26 | return endpoint;
27 | }
28 | }
29 |
30 | return null; }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/codes/HeadTrackingRequestCodes.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.codes;
2 |
3 | public class HeadTrackingRequestCodes {
4 |
5 | public static int Disconnect = 255;
6 |
7 | public static int ChangeState = 254;
8 | public static int Recenter = 50;
9 |
10 | public static int SendPoseMatrixRotationOnly = 0;
11 | public static int SendPoseMatrixFull = 6;
12 | public static int SendRotationMatrix = 1;
13 | public static int SendRadRotationAndPosition = 3;
14 | public static int SendQuatRotationAndPosition = 4;
15 | public static int SendPositionOnly = 5;
16 |
17 | public static int RequestSyncOffset = 100;
18 | public static int RequestReadOnlyPose = 199;
19 | public static int RequestReadOnlyPhonePose = 200;
20 |
21 | public static int SetYawOffset = 201;
22 | public static int ResetYawOffset = 21;
23 | }
24 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/responses/EndpointStatus.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.responses;
2 |
3 | import com.riftcat.vridge.api.client.java.control.ControlResponseCode;
4 |
5 | public class EndpointStatus extends ControlResponseHeader {
6 |
7 | public String Name;
8 | public String InUseBy;
9 |
10 | public EndpointStatus(String endpointName){
11 | this.Code = ControlResponseCode.OK;
12 | this.Name = endpointName;
13 | }
14 |
15 | public String codeString(){
16 | if(Code == ControlResponseCode.NotAvailable){
17 | return "n/a";
18 | }
19 | if(Code == ControlResponseCode.InUse){
20 | return "In use by " + InUseBy;
21 | }
22 | if(Code == ControlResponseCode.OK){
23 | return "Ready";
24 | }
25 |
26 | return "unknown";
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Responses/EndpointStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace VRE.Vridge.API.Client.Messages.Control.Responses
4 | {
5 | public class EndpointStatus : ControlResponseHeader
6 | {
7 | [JsonProperty("Name")]
8 | public string Name;
9 |
10 | [JsonProperty("InUseBy")]
11 | public string InUseBy;
12 |
13 | public EndpointStatus(string endpointName) : base(ControlResponseCode.OK)
14 | {
15 | this.Name = endpointName;
16 | }
17 |
18 | public override string ToString()
19 | {
20 | if (Code == (int) ControlResponseCode.InUse)
21 | {
22 | return Name + ": " + (ControlResponseCode)Code + " by " + InUseBy;
23 | }
24 | else
25 | {
26 | return Name + ": " + (ControlResponseCode)Code;
27 | }
28 |
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/ControlResponseCode.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.Control
2 | {
3 | public enum ControlResponseCode
4 | {
5 | ///
6 | /// API awaits connection at given endpoint.
7 | ///
8 | OK = 0,
9 |
10 | ///
11 | /// API is not available because of undefined reason.
12 | ///
13 | NotAvailable = 1,
14 |
15 | ///
16 | /// API is in use by another client
17 | ///
18 | InUse = 2,
19 |
20 | ///
21 | /// Client is trying to use something that requires API client to be updated to more recent version
22 | ///
23 | ClientOutdated = 3,
24 |
25 | ///
26 | /// VRidge needs to be updated or client is not following protocol
27 | ///
28 | ServerOutdated = 4,
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/Control/Responses/ControlResponseHeader.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.Control.Responses
2 | {
3 | public class ControlResponseHeader : BaseControlMessage
4 | {
5 | // Predefined responses
6 | public static ControlResponseHeader ResponseInUse =
7 | new ControlResponseHeader(ControlResponseCode.InUse);
8 |
9 | public static ControlResponseHeader ResponseClientOutdated =
10 | new ControlResponseHeader(ControlResponseCode.ClientOutdated);
11 |
12 | public static ControlResponseHeader ResponseNotAvailable =
13 | new ControlResponseHeader(ControlResponseCode.NotAvailable);
14 |
15 | public static ControlResponseHeader ResponseServerOutdated =
16 | new ControlResponseHeader(ControlResponseCode.ServerOutdated);
17 |
18 | public ControlResponseHeader(ControlResponseCode code) : base(3, (int) code)
19 | {
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/ControlResponseCode.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control;
2 |
3 | public class ControlResponseCode {
4 |
5 | ///
6 | /// API awaits connection at given endpoint.
7 | ///
8 | public static int OK = 0;
9 |
10 | ///
11 | /// API is not available because of undefined reason.
12 | ///
13 | public static int NotAvailable = 1;
14 |
15 | ///
16 | /// API is in use by another client
17 | ///
18 | public static int InUse = 2;
19 |
20 | ///
21 | /// Client is trying to use something that requires API client to be updated to more recent version
22 | ///
23 | public static int ClientOutdated = 3;
24 |
25 | ///
26 | /// VRidge needs to be updated or client is not following protocol
27 | ///
28 | public static int ServerOutdated = 4;
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/OpenVR/VRControllerState_t.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using ProtoBuf;
3 |
4 | namespace VRE.Vridge.API.Client.Messages.OpenVR
5 | {
6 | ///
7 | /// See VRControllerState_t in OpenVR docs.
8 | ///
9 | [StructLayout(LayoutKind.Sequential, Size = 60)]
10 | [ProtoContract]
11 | public struct VRControllerState_t
12 | {
13 | [ProtoMember(1)]
14 | public uint unPacketNum;
15 |
16 | [ProtoMember(2)]
17 | public ulong ulButtonPressed;
18 |
19 | [ProtoMember(3)]
20 | public ulong ulButtonTouched;
21 |
22 | [ProtoMember(4)]
23 | public VRControllerAxis_t rAxis0;
24 |
25 | [ProtoMember(5)]
26 | public VRControllerAxis_t rAxis1;
27 |
28 | [ProtoMember(7)]
29 | public VRControllerAxis_t rAxis2;
30 |
31 | [ProtoMember(8)]
32 | public VRControllerAxis_t rAxis3;
33 |
34 | [ProtoMember(9)]
35 | public VRControllerAxis_t rAxis4;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 RiftCat
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/control/responses/ControlResponseHeader.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.control.responses;
2 |
3 | import com.riftcat.vridge.api.client.java.control.BaseControlMessage;
4 | import com.riftcat.vridge.api.client.java.control.ControlResponseCode;
5 |
6 | public class ControlResponseHeader extends BaseControlMessage {
7 |
8 | // Predefined responses
9 | public static ControlResponseHeader ResponseInUse;
10 | public static ControlResponseHeader ResponseClientOutdated;
11 | public static ControlResponseHeader ResponseNotAvailable;
12 |
13 | static{
14 | // Predefined responses
15 | ResponseNotAvailable = new ControlResponseHeader();
16 | ResponseNotAvailable.Code = ControlResponseCode.NotAvailable;
17 |
18 | ResponseClientOutdated = new ControlResponseHeader();
19 | ResponseClientOutdated.Code = ControlResponseCode.ClientOutdated;
20 |
21 | ResponseInUse = new ControlResponseHeader();
22 | ResponseInUse.Code = ControlResponseCode.InUse;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/utils/SerializationUtils.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.utils;
2 |
3 | import com.google.protobuf.ByteString;
4 |
5 | import java.nio.ByteBuffer;
6 | import java.nio.ByteOrder;
7 |
8 | public class SerializationUtils {
9 |
10 | public static ByteString byteStringFromFloats(float...args){
11 | return ByteString.copyFrom(byteArrayFromFloats(args));
12 | }
13 |
14 | public static byte[] byteArrayFromFloats(float... args){
15 | ByteBuffer data = ByteBuffer.allocate(args.length * 4);
16 | data.order(ByteOrder.LITTLE_ENDIAN);
17 | for (float arg : args) {
18 | data.putFloat(arg);
19 | }
20 |
21 | return data.array();
22 | }
23 |
24 | public static ByteString byteStringFromFloatArray(float[] array){
25 | ByteBuffer data = ByteBuffer.allocate(array.length * 4);
26 | data.order(ByteOrder.LITTLE_ENDIAN);
27 | for (float arg : array) {
28 | data.putFloat(arg);
29 | }
30 |
31 | return ByteString.copyFrom(data.array());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace VRE.Vridge.API.DesktopTester.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/Beacons/VridgeServerBeaconList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using VRE.Vridge.API.Client.Messages.v3.Discovery;
5 |
6 | namespace VRE.Vridge.API.Client.Remotes.Beacons
7 | {
8 | class VridgeServerBeaconList
9 | {
10 | private readonly Dictionary timedList = new Dictionary();
11 |
12 | public void Add(Beacon beacon, string endpoint)
13 | {
14 | if (timedList.ContainsKey(endpoint))
15 | {
16 | timedList.Remove(endpoint);
17 | }
18 |
19 | timedList.Add(endpoint, new VridgeServerBeacon(beacon, endpoint));
20 | }
21 |
22 | public List FreshServers
23 | {
24 | get
25 | {
26 | var beacons = new List();
27 | foreach (var beacon in timedList.Values)
28 | {
29 | if (beacon.IsFresh)
30 | {
31 | beacons.Add(beacon);
32 | }
33 | }
34 |
35 | return beacons;
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/HeadTracking/Responses/TrackedPose.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using ProtoBuf;
5 |
6 | namespace VRE.Vridge.API.Client.Messages.v3.HeadTracking.Responses
7 | {
8 | [ProtoContract]
9 | public class TrackedPose
10 | {
11 | ///
12 | /// Current head orientation as 4 element XYZW quaternion.
13 | ///
14 | [ProtoMember(1)]
15 | public float[] HeadOrientation;
16 |
17 | ///
18 | /// Current head position as 3 element XYZ vector.
19 | ///
20 | [ProtoMember(2)]
21 | public float[] HeadPosition;
22 |
23 | ///
24 | /// Current offset applied to each head-related (Controller w/ HeadRelation.IsInHeadSpace or internal VRidge mobile tracking data) pose due to user recenter.
25 | /// In 99% cases, you can forget about it.
26 | ///
27 | [ProtoMember(3)]
28 | public float RecenterYawOffset;
29 |
30 | ///
31 | /// Current offset applied to each pose due to API SetYawOffset call.
32 | ///
33 | [ProtoMember(4)]
34 | public float ApiYawOffset;
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/beacons/VridgeServerBeacon.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes.beacons;
2 |
3 | import com.riftcat.vridge.api.client.java.proto.Beacon;
4 |
5 | import java.net.InetAddress;
6 |
7 | public class VridgeServerBeacon {
8 | private static long timeoutMs = 5000;
9 |
10 | private Beacon beacon;
11 | private InetAddress endpoint;
12 | private long timestmapMs;
13 |
14 | public VridgeServerBeacon(Beacon beacon, InetAddress endpoint) {
15 | this.beacon = beacon;
16 | this.endpoint = endpoint;
17 | timestmapMs = System.currentTimeMillis();
18 | }
19 |
20 | public Beacon getBeacon() {
21 | return beacon;
22 | }
23 |
24 | public InetAddress getEndpoint() {
25 | return endpoint;
26 | }
27 |
28 | public boolean isFresh(){
29 | return timestmapMs + timeoutMs > System.currentTimeMillis();
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return beacon.getRole() + "|" +
35 | beacon.getHumanReadableVersion() + "|" +
36 | beacon.getMachineName() + "|" +
37 | beacon.getUserName() + "@" +
38 | endpoint.getHostAddress();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/beacons/VridgeServerBeaconList.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes.beacons;
2 |
3 | import com.riftcat.vridge.api.client.java.proto.Beacon;
4 |
5 | import java.net.InetAddress;
6 | import java.util.ArrayList;
7 | import java.util.Dictionary;
8 | import java.util.HashMap;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 |
12 | public class VridgeServerBeaconList {
13 | private HashMap timedList = new HashMap();
14 |
15 | public synchronized void add(Beacon beacon, InetAddress endpoint){
16 | if(timedList.containsKey(endpoint)){
17 | timedList.remove(endpoint);
18 | }
19 |
20 | timedList.put(endpoint, new VridgeServerBeacon(beacon, endpoint));
21 | }
22 |
23 | public synchronized List getFreshServers(){
24 | LinkedList beacons = new LinkedList();
25 | for (VridgeServerBeacon vridgeServerBeacon : timedList.values()) {
26 | if(vridgeServerBeacon.isFresh()){
27 | beacons.add(vridgeServerBeacon);
28 | }
29 | }
30 |
31 | return beacons;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'com.google.protobuf'
3 |
4 | dependencies {
5 | compile fileTree(dir: 'libs', include: ['*.jar'])
6 | compile 'com.google.protobuf:protobuf-lite:3.0.0'
7 | compile group: 'org.zeromq', name: 'jeromq', version: '0.4.3'
8 | compile group: 'com.google.code.gson', name: 'gson', version: '1.7.2'
9 |
10 | }
11 |
12 | sourceCompatibility = "1.6"
13 | targetCompatibility = "1.6"
14 |
15 | sourceSets{
16 | main{
17 | proto{
18 |
19 | }
20 | java{
21 | main.java.srcDirs += 'src/main/javalite'
22 | }
23 | }
24 | }
25 |
26 |
27 | protobuf {
28 | protoc {
29 | // Download from repositories
30 | artifact = 'com.google.protobuf:protoc:3.0.0'
31 | }
32 | plugins {
33 | javalite {
34 | // The codegen for lite comes as a separate artifact
35 | artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
36 | }
37 | }
38 | generateProtoTasks {
39 | all().each { task ->
40 | task.builtins {
41 | remove java
42 | }
43 | task.plugins {
44 | javalite { }
45 | }
46 | }
47 | }
48 |
49 | generatedFilesBaseDir = "$projectDir/src"
50 | }
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/Beacons/VridgeServerBeacon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 | using VRE.Vridge.API.Client.Messages.v3.Discovery;
6 |
7 | namespace VRE.Vridge.API.Client.Remotes.Beacons
8 | {
9 | public class VridgeServerBeacon
10 | {
11 | private const long TimeoutMs = 5000;
12 | private static readonly Stopwatch Timer = Stopwatch.StartNew();
13 |
14 | private readonly Beacon beacon;
15 | private readonly string endpoint;
16 | private readonly long timestmapMs;
17 |
18 | public VridgeServerBeacon(Beacon beacon, string endpoint)
19 | {
20 | this.beacon = beacon;
21 | this.endpoint = endpoint;
22 | timestmapMs = Timer.ElapsedMilliseconds;
23 | }
24 |
25 | public Beacon Beacon => beacon;
26 | public string Endpoint => endpoint;
27 | public bool IsFresh => timestmapMs + TimeoutMs > Timer.ElapsedMilliseconds;
28 |
29 | public override string ToString()
30 | {
31 | return beacon.Role + "|" +
32 | beacon.HumanReadableVersion + "|" +
33 | beacon.MachineName + "|" +
34 | beacon.UserName + "@" +
35 | endpoint;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Broadcast/HapticPulse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using ProtoBuf;
8 |
9 | namespace VRE.Vridge.API.Client.Messages.v3.Broadcast
10 | {
11 | [ProtoContract]
12 | public struct HapticPulse
13 | {
14 | ///
15 | /// Identifier defined by controller when it sends its requests to OpenVR.
16 | ///
17 | [ProtoMember(1)]
18 | public int ControllerId;
19 |
20 |
21 | ///
22 | /// Duration of pulse in microseconds, provided by VR game.
23 | ///
24 | [ProtoMember(2)]
25 | public uint LengthUs;
26 |
27 | ///
28 | /// High resolution (1us) timestamp in microseconds - based on QueryPerformanceCounter().
29 | /// Can be optionally used to smooth out or join pulses together.
30 | ///
31 | ///
32 | /// Timestamp is created when the pulse was submitted to HMD driver.
33 | /// Wrap-arounds will happen so use it for interval measurement, not absolute timings.
34 | ///
35 | ///
36 | [ProtoMember(3)]
37 | public uint TimestampUs;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using System.Windows.Media.Media3D;
5 |
6 | namespace VRE.Vridge.API.DesktopTester
7 | {
8 | public static class Extensions
9 | {
10 | ///
11 | /// Converts 4x4 matrix into flat array with column-major layout.
12 | ///
13 | ///
14 | ///
15 | public static float[] FlattenAsColumnMajor(this Matrix3D matrix)
16 | {
17 | var array = new float[16];
18 | array[0] = (float)matrix.M11;
19 | array[1] = (float)matrix.M21;
20 | array[2] = (float)matrix.M31;
21 | array[3] = (float)matrix.OffsetX;
22 | array[4] = (float)matrix.M12;
23 | array[5] = (float)matrix.M22;
24 | array[6] = (float)matrix.M32;
25 | array[7] = (float)matrix.OffsetY;
26 | array[8] = (float)matrix.M13;
27 | array[9] = (float)matrix.M23;
28 | array[10] = (float)matrix.M33;
29 | array[11] = (float)matrix.OffsetZ;
30 | array[12] = (float)matrix.M14;
31 | array[13] = (float)matrix.M24;
32 | array[14] = (float)matrix.M34;
33 | array[15] = (float)matrix.M44;
34 |
35 | return array;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea/workspace.xml
39 | .idea/tasks.xml
40 | .idea/gradle.xml
41 | .idea/assetWizardSettings.xml
42 | .idea/dictionaries
43 | .idea/libraries
44 | .idea/caches
45 |
46 | # Keystore files
47 | # Uncomment the following lines if you do not want to check your keystore files in.
48 | #*.jks
49 | #*.keystore
50 |
51 | # External native build folder generated in Android Studio 2.2 and later
52 | .externalNativeBuild
53 |
54 | # Google Services (e.g. APIs or Firebase)
55 | # google-services.json
56 |
57 | # Freeline
58 | freeline.py
59 | freeline/
60 | freeline_project_description.json
61 |
62 | # fastlane
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 | fastlane/readme.md
68 |
69 | # Version control
70 | vcs.xml
71 |
72 | # lint
73 | lint/intermediates/
74 | lint/generated/
75 | lint/outputs/
76 | lint/tmp/
77 | # lint/reports/
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/ViewModel/ControllerMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace VRE.Vridge.API.DesktopTester.ViewModel
8 | {
9 | public enum ControllerMode
10 | {
11 | ///
12 | /// Pose is unrelated to current head pose.
13 | ///
14 | Unrelated = 0,
15 |
16 | ///
17 | /// Pose already is in head space.
18 | /// Will be auto-adjusted when head is recentered.
19 | ///
20 | IsInHeadSpace = 1,
21 |
22 | ///
23 | /// Pose is unrelated but is to be remapped in a way that assumes that pose forward
24 | /// should always be aligned to head's forward. Effectively the given pose is relative angle from current's head forward.
25 | /// HeadRelation = SticksToHead, Position = defined
26 | ///
27 | SticksToHead = 2,
28 |
29 | ///
30 | /// Equivalent to setting position to NULL from API perspective.
31 | /// It won't auto-follow head when controller data is not being sent.
32 | /// HeadRelation = Unrelated, Position = null
33 | ///
34 | ThreeDof = 3,
35 |
36 | ///
37 | /// Equivalent to setting position to NULL from API perspective.
38 | /// Also instructs API server to keep updating the controller pose whenever head pose changes.
39 | /// HeadRelation = SticksToHead, Position = null
40 | ///
41 | StickyThreeDof = 4
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.2002
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VRE.Vridge.API.Client", "VRE.Vridge.API.Client\VRE.Vridge.API.Client.csproj", "{11FB8F50-AE40-42C2-AC82-7A8D84A7B76E}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VRE.Vridge.API.DesktopTester", "examples\VRE.Vridge.API.DesktopClient\VRE.Vridge.API.DesktopTester.csproj", "{97ECBE1C-03EF-461D-A389-312C729A7EA6}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {11FB8F50-AE40-42C2-AC82-7A8D84A7B76E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {11FB8F50-AE40-42C2-AC82-7A8D84A7B76E}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {11FB8F50-AE40-42C2-AC82-7A8D84A7B76E}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {11FB8F50-AE40-42C2-AC82-7A8D84A7B76E}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {97ECBE1C-03EF-461D-A389-312C729A7EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {97ECBE1C-03EF-461D-A389-312C729A7EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {97ECBE1C-03EF-461D-A389-312C729A7EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {97ECBE1C-03EF-461D-A389-312C729A7EA6}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {4360A98A-0C26-4BA7-A3F6-5DF6C7A0E8A7}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Controller/VRController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using ProtoBuf;
4 | using VRE.Vridge.API.Client.Messages.BasicTypes;
5 | using VRE.Vridge.API.Client.Messages.OpenVR;
6 |
7 | namespace VRE.Vridge.API.Client.Messages.v3.Controller
8 | {
9 | [ProtoContract]
10 | public struct VRController
11 | {
12 | [ProtoMember(1)]
13 | public int ControllerId;
14 |
15 |
16 | ///
17 | ///
18 | ///
19 | [ProtoMember(2)]
20 | public int Status;
21 |
22 | [ProtoMember(9)]
23 | public double Timestamp;
24 |
25 | [ProtoMember(3), Obsolete("Use Position + Orientation instead.")]
26 | public float[] OrientationMatrix;
27 |
28 | [ProtoMember(4)]
29 | public VRControllerState_t ButtonState;
30 |
31 | [ProtoMember(5)]
32 | public double[] Acceleration;
33 |
34 | [ProtoMember(6)]
35 | public double[] Velocity;
36 |
37 | [ProtoMember(7)] // TODO: GitHub API docs
38 | public HeadRelation HeadRelation;
39 |
40 |
41 | [ProtoMember(8)] // TODO: GitHub API docs
42 | public HandType SuggestedHand;
43 |
44 | [ProtoMember(11)]
45 | public string Name;
46 |
47 | ///
48 | /// XYZ vector.
49 | ///
50 | [ProtoMember(12)]
51 | public float[] Position;
52 |
53 |
54 | ///
55 | /// XYZW quaternion.
56 | ///
57 | [ProtoMember(13)]
58 | public float[] Orientation;
59 |
60 | // [ProtoMember(14)]
61 |
62 | public bool ShouldRemap3To6Dof => OrientationMatrix == null && Position == null;
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/View/LabeledSlider.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
27 |
28 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/HeadTracking/Responses/HeadTrackingResponse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 | using ProtoBuf;
4 |
5 | namespace VRE.Vridge.API.Client.Messages.v3.HeadTracking.Responses
6 | {
7 | [ProtoContract]
8 | public struct HeadTrackingResponse
9 | {
10 | [ProtoMember(1)]
11 | public int Version;
12 |
13 | [ProtoMember(2)]
14 | public byte ReplyCode;
15 |
16 | [ProtoMember(3)]
17 | public float[] Data;
18 |
19 | [ProtoMember(4)]
20 | public TrackedPose TrackedPose;
21 |
22 | public enum Response
23 | {
24 | ///
25 | /// In response to disconnect request.
26 | ///
27 | Disconnecting = 255,
28 |
29 | ///
30 | /// When request was not understood
31 | ///
32 | BadRequest = 254,
33 |
34 | ///
35 | /// No new data was received from the phone for 5 seconds, possibly phone lost connection
36 | ///
37 | PhoneDataTimeout = 253,
38 |
39 |
40 | AcceptedYourData = 0,
41 |
42 | ///
43 | /// Pose is contained in TrackedPose field.
44 | ///
45 | SendingCurrentTrackedPose = 2,
46 |
47 | ///
48 | /// Data contains float[6] (24 bytes total):
49 | /// pitch(+up), yaw (+to left), roll(+left), X, Y, Z
50 | /// X Y Z position is always zero because no phone-side positional
51 | /// tracking exists currently. This may change in the future.
52 | ///
53 | [Obsolete]
54 | SendingCurrentPhonePose = 1,
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/v3/Controller/Requests/ControllerStateRequest.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using ProtoBuf;
3 | using VRE.Vridge.API.Client.Messages.v3.Controller.Responses;
4 |
5 |
6 | namespace VRE.Vridge.API.Client.Messages.v3.Controller.Requests
7 | {
8 | ///
9 | /// Request to a VRidge API server that contains current motion controller state.
10 | /// will be returned as a response.
11 | ///
12 | [ProtoContract]
13 | public struct ControllerStateRequest
14 | {
15 | public const int CurrentVersion = 3;
16 |
17 | [ProtoMember(1)]
18 | public int Version;
19 |
20 | ///
21 | /// Describes how API should handle the incoming data, see .
22 | ///
23 | [ProtoMember(2)]
24 | public byte TaskType;
25 |
26 |
27 | // Origin is removed, was never used, see VRController.HeadRelation for replacement
28 | // [ProtoMember(3)] public byte Origin;
29 |
30 |
31 | [ProtoMember(4)]
32 | public VRController ControllerState;
33 | }
34 |
35 | public enum ControllerTask
36 | {
37 | ///
38 | /// Packet closes your controller API connection and lets other clients use it.
39 | ///
40 | Disconnect = 255,
41 |
42 | ///
43 | /// Packet contains full controller state as defined in struct.
44 | /// It will be used immediately.
45 | ///
46 | SendFullState = 1,
47 |
48 | ///
49 | /// Recenter head tracking. Works the same as pressing recenter hotkey as configured in VRidge settings.
50 | ///
51 | RecenterHead = 2
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Messages/OpenVR/EVRButtonId.cs:
--------------------------------------------------------------------------------
1 | namespace VRE.Vridge.API.Client.Messages.OpenVR
2 | {
3 | public enum EVRButtonId
4 | {
5 | k_EButton_System = 0, // 0
6 | k_EButton_ApplicationMenu = 1, // 1
7 | k_EButton_Grip = 2, // 01
8 | k_EButton_DPad_Left = 3, // 11
9 | k_EButton_DPad_Up = 4,
10 | k_EButton_DPad_Right = 5,
11 | k_EButton_DPad_Down = 6,
12 | k_EButton_A = 7,
13 |
14 | k_EButton_ProximitySensor = 31,
15 |
16 | k_EButton_Axis0 = 32,
17 | k_EButton_Axis1 = 33,
18 | k_EButton_Axis2 = 34,
19 | k_EButton_Axis3 = 35,
20 | k_EButton_Axis4 = 36,
21 |
22 | // aliases for well known controllers
23 | k_EButton_SteamVR_Touchpad = k_EButton_Axis0,
24 | k_EButton_SteamVR_Trigger = k_EButton_Axis1,
25 |
26 | k_EButton_Dashboard_Back = k_EButton_Grip,
27 |
28 | k_EButton_Max = 64
29 | };
30 |
31 | public class ButtonMask
32 | {
33 | public const ulong System = (1ul << (int)EVRButtonId.k_EButton_System);
34 | public const ulong ApplicationMenu = (1ul << (int)EVRButtonId.k_EButton_ApplicationMenu);
35 | public const ulong Grip = (1ul << (int)EVRButtonId.k_EButton_Grip);
36 | public const ulong Axis0 = (1ul << (int)EVRButtonId.k_EButton_Axis0);
37 | public const ulong Axis1 = (1ul << (int)EVRButtonId.k_EButton_Axis1);
38 | public const ulong Axis2 = (1ul << (int)EVRButtonId.k_EButton_Axis2);
39 | public const ulong Axis3 = (1ul << (int)EVRButtonId.k_EButton_Axis3);
40 | public const ulong Axis4 = (1ul << (int)EVRButtonId.k_EButton_Axis4);
41 | public const ulong Touchpad = (1ul << (int)EVRButtonId.k_EButton_SteamVR_Touchpad);
42 | public const ulong Trigger = (1ul << (int)EVRButtonId.k_EButton_SteamVR_Trigger);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/utils/ButtonMask.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.utils;
2 |
3 | public class ButtonMask{
4 | private static int k_EButton_System = 0;
5 | private static int k_EButton_ApplicationMenu = 1;
6 | private static int k_EButton_Grip = 2;
7 | private static int k_EButton_DPad_Left = 3;
8 | private static int k_EButton_DPad_Up = 4;
9 | private static int k_EButton_DPad_Right = 5;
10 | private static int k_EButton_DPad_Down = 6;
11 | private static int k_EButton_A = 7;
12 |
13 | private static int k_EButton_ProximitySensor = 31;
14 |
15 | private static int k_EButton_Axis0 = 32;
16 | private static int k_EButton_Axis1 = 33;
17 | private static int k_EButton_Axis2 = 34;
18 | private static int k_EButton_Axis3 = 35;
19 | private static int k_EButton_Axis4 = 36;
20 |
21 | // aliases for well known controllers
22 | private static int k_EButton_SteamVR_Touchpad = k_EButton_Axis0;
23 | private static int k_EButton_SteamVR_Trigger = k_EButton_Axis1;
24 | private static int k_EButton_Dashboard_Back = k_EButton_Grip;
25 | private static int k_EButton_Max = 64;
26 |
27 | public static long System = (1L << (int)k_EButton_System);
28 | public static long ApplicationMenu = (1L << (int)k_EButton_ApplicationMenu);
29 | public static long Grip = (1L << (int)k_EButton_Grip);
30 | public static long Axis0 = (1L << (int)k_EButton_Axis0);
31 | public static long Axis1 = (1L << (int)k_EButton_Axis1);
32 | public static long Axis2 = (1L << (int)k_EButton_Axis2);
33 | public static long Axis3 = (1L << (int)k_EButton_Axis3);
34 | public static long Axis4 = (1L << (int)k_EButton_Axis4);
35 | public static long Touchpad = (1L << (int)k_EButton_SteamVR_Touchpad);
36 | public static long Trigger = (1L << (int)k_EButton_SteamVR_Trigger);
37 | }
38 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/RemoteBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using VRE.Vridge.API.Client.Proxy;
5 |
6 | namespace VRE.Vridge.API.Client.Remotes
7 | {
8 | public abstract class RemoteBase where T : ClientProxyBasePB
9 | {
10 | public bool IsDisposed { get; private set; }
11 | protected T Proxy;
12 |
13 | protected RemoteBase(T proxy)
14 | {
15 | this.Proxy = proxy;
16 | //EnsureSocketExists();
17 | }
18 |
19 | internal virtual void Dispose()
20 | {
21 | IsDisposed = true;
22 | Proxy?.Dispose();
23 | }
24 |
25 | protected T WrapTimeouts(Func action)
26 | {
27 | if (!Proxy.IsSocketOpen)
28 | {
29 | Dispose();
30 | return default(T);
31 | }
32 |
33 | try
34 | {
35 | return action();
36 | }
37 | catch (Exception x)
38 | {
39 | Dispose();
40 | return default(T);
41 | }
42 | }
43 |
44 | protected void WrapTimeouts(Action action)
45 | {
46 | try
47 | {
48 | action();
49 | }
50 | catch (Exception x)
51 | {
52 | Dispose();
53 | }
54 | }
55 |
56 |
57 |
58 | /*internal void EnsureSocketExists()
59 | {
60 | // This can't fail because opening socket doesn't actually open the socket but only creates abstraction.
61 | // It is created on first send.
62 | if(!Proxy.IsSocketOpen)
63 | {
64 | Proxy?.Dispose();
65 | Proxy = (T)Activator.CreateInstance(typeof(T), endpoint, true);
66 | }
67 | } */
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/View/LabeledSlider.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | namespace VRE.Vridge.API.DesktopTester.View
5 | {
6 | ///
7 | /// Interaction logic for LabeledSlider.xaml
8 | ///
9 | public partial class LabeledSlider : UserControl
10 | {
11 |
12 | public static readonly DependencyProperty SliderValueProperty = DependencyProperty.Register("SliderValue", typeof(double), typeof(LabeledSlider), new PropertyMetadata(default(double)));
13 | public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabeledSlider), new PropertyMetadata(default(string)));
14 | public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(LabeledSlider), new PropertyMetadata(default(double)));
15 | public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(LabeledSlider), new PropertyMetadata(default(double)));
16 |
17 | public string Label
18 | {
19 | get { return (string) GetValue(LabelProperty); }
20 | set { SetValue(LabelProperty, value); }
21 | }
22 | public double SliderValue
23 | {
24 | get { return (double)GetValue(SliderValueProperty); }
25 | set { SetValue(SliderValueProperty, value); }
26 | }
27 |
28 | public double Minimum
29 | {
30 | get { return (double) GetValue(MinimumProperty); }
31 | set { SetValue(MinimumProperty, value); }
32 | }
33 |
34 | public double Maximum
35 | {
36 | get { return (double) GetValue(MaximumProperty); }
37 | set { SetValue(MaximumProperty, value); }
38 | }
39 |
40 | public LabeledSlider()
41 | {
42 | InitializeComponent();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/DiscoveryClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using NetMQ;
6 | using ProtoBuf;
7 | using VRE.Vridge.API.Client.Messages.v3.Discovery;
8 | using VRE.Vridge.API.Client.Remotes.Beacons;
9 |
10 | namespace VRE.Vridge.API.Client.Remotes
11 | {
12 | internal class DiscoveryClient
13 | {
14 | private readonly VridgeServerBeaconList beaconList;
15 | private readonly NetMQBeacon beaconClient;
16 | private readonly NetMQPoller beaconPoller;
17 |
18 | public DiscoveryClient()
19 | {
20 | beaconList = new VridgeServerBeaconList();
21 | beaconClient = new NetMQBeacon();
22 | beaconClient.ConfigureAllInterfaces(38219);
23 | beaconClient.Subscribe("");
24 | beaconClient.ReceiveReady += OnBeaconReceived;
25 | beaconPoller = new NetMQPoller() { beaconClient };
26 | beaconPoller.RunAsync();
27 | }
28 |
29 | public List ActiveVridgeServers => beaconList.FreshServers;
30 |
31 | public void Dispose()
32 | {
33 | if(beaconPoller != null && beaconPoller.IsRunning) beaconPoller.Stop();
34 | beaconClient?.Dispose();
35 | }
36 |
37 | private void OnBeaconReceived(object sender, NetMQBeaconEventArgs e)
38 | {
39 | var beaconMessage = e.Beacon.Receive();
40 | var hostname = beaconMessage.PeerHost;
41 | var buffer = beaconMessage.Bytes;
42 | using (var ms = new MemoryStream(buffer))
43 | {
44 | try
45 | {
46 | var beacon = Serializer.Deserialize(ms);
47 | beaconList.Add(beacon, hostname);
48 | }
49 | catch (Exception)
50 | {
51 | // Ignore stray packets
52 | }
53 | }
54 |
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/View/ControlWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 | using VRE.Vridge.API.DesktopTester.ViewModel;
4 |
5 | namespace VRE.Vridge.API.DesktopTester.View
6 | {
7 | ///
8 | /// Interaction logic for MainWindow.xaml
9 | ///
10 | public partial class ControlWindow : Window
11 | {
12 |
13 | private bool isMarkerBeingDragged = false;
14 | private Point lastMousePosition;
15 |
16 | public ControlWindow()
17 | {
18 | InitializeComponent();
19 | this.DataContext = new ControlViewModel();
20 | }
21 | private void FrameworkElement_OnSizeChanged(object sender, SizeChangedEventArgs e)
22 | {
23 | (DataContext as ControlViewModel)?.UpdateDrawingBounds(e);
24 | }
25 |
26 | private void Marker_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
27 | {
28 | Mouse.Capture((UIElement) sender);
29 | isMarkerBeingDragged = true;
30 | lastMousePosition = e.GetPosition(Canvas);
31 | }
32 |
33 | private void Marker_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
34 | {
35 | ((UIElement) sender).ReleaseMouseCapture();
36 | isMarkerBeingDragged = false;
37 | }
38 |
39 | private void Canvas_OnMouseMove(object sender, MouseEventArgs e)
40 | {
41 | if (!isMarkerBeingDragged)
42 | return;
43 |
44 | // If mouse release event was skipped because window focus was taken by something else
45 | if (Mouse.LeftButton == MouseButtonState.Released)
46 | {
47 | isMarkerBeingDragged = false;
48 | return;
49 | }
50 |
51 | var delta = e.GetPosition(Canvas) - lastMousePosition;
52 | (DataContext as ControlViewModel)?.NotifyCanvasDrag(delta);
53 |
54 | lastMousePosition = e.GetPosition(Canvas);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/Broadcasts/BroadcastProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Timers;
7 | using NetMQ;
8 | using NetMQ.Sockets;
9 | using VRE.Vridge.API.Client.Messages.v3.Broadcast;
10 |
11 | namespace VRE.Vridge.API.Client.Proxy.Broadcasts
12 | {
13 | public class BroadcastProxy : IDisposable
14 | {
15 | private readonly SubscriberSocket socket;
16 | private readonly NetMQPoller poller;
17 | private bool isDisposed = false;
18 |
19 | public BroadcastProxy(string endpointAddr)
20 | {
21 | socket = new SubscriberSocket(endpointAddr);
22 | socket.Subscribe("haptic");
23 | socket.Options.Linger = TimeSpan.FromSeconds(1);
24 | socket.ReceiveReady += BroadcastReceived;
25 |
26 | poller = new NetMQPoller {socket};
27 | poller.RunAsync();
28 | }
29 |
30 | public event EventHandler HapticPulseReceived;
31 |
32 | public void Disconnect()
33 | {
34 | if(poller != null && poller.IsRunning) poller.Stop();
35 | socket?.Close();
36 |
37 | HapticPulseReceived = null;
38 | }
39 |
40 | private void BroadcastReceived(object sender, NetMQSocketEventArgs ev)
41 | {
42 | var topic = ev.Socket.ReceiveFrameString();
43 | var msg = ev.Socket.ReceiveFrameBytes();
44 |
45 | if (topic == "haptic")
46 | {
47 | var hapticPulse = Helpers.SerializationHelpers.ProtoDeserialize(msg);
48 | HapticPulseReceived?.Invoke(this, hapticPulse);
49 | }
50 | }
51 |
52 | public void Dispose()
53 | {
54 | lock (this)
55 | {
56 | if (!isDisposed)
57 | {
58 | isDisposed = true;
59 | HapticPulseReceived = null;
60 | Disconnect();
61 | }
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/HeadRemote.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using VRE.Vridge.API.Client.Proxy.HeadTracking;
5 |
6 | namespace VRE.Vridge.API.Client.Remotes
7 | {
8 | public class HeadRemote : RemoteBase
9 | {
10 | internal HeadRemote(HeadTrackingProxy proxy) : base(proxy)
11 | {
12 |
13 | }
14 |
15 | ///
16 | /// Reorients tracking system and sets new center to current head direction.
17 | ///
18 | public void Recenter()
19 | {
20 | WrapTimeouts(() => Proxy.RecenterView());
21 | }
22 |
23 | public void SetPosition(float x, float y, float z)
24 | {
25 | WrapTimeouts(() => Proxy.SetPosition(x, y, z));
26 | }
27 |
28 | public void SetRotationAndPosition(float yaw, float pitch, float roll, float x, float y, float z)
29 | {
30 | WrapTimeouts(() => Proxy.SetRotationAndPosition(yaw, pitch, roll, x, y, z));
31 | }
32 |
33 | public void SetAsyncOffset(float yaw)
34 | {
35 | WrapTimeouts(() => Proxy.SetAsyncOffset(yaw));
36 | }
37 |
38 | public float[] GetCurrentPose()
39 | {
40 | return WrapTimeouts(() => Proxy.GetCurrentPhonePose());
41 | }
42 |
43 | public void SetStatus(bool isInTrackingRange)
44 | {
45 | WrapTimeouts(() => Proxy.ChangeTrackingState(isInTrackingRange));
46 | }
47 |
48 | // Type-cast-methods
49 | public void SetAsyncOffset(double yaw) =>
50 | SetAsyncOffset((float)yaw);
51 |
52 | public void SetRotationAndPosition(double yaw, double pitch, double roll, double x, double y, double z) =>
53 | SetRotationAndPosition((float) yaw, (float) pitch, (float) roll, (float) x, (float) y, (float) z);
54 |
55 | public void SetPosition(double x, double y, double z) =>
56 | SetPosition((float) x, (float) y, (float) z);
57 |
58 | internal override void Dispose()
59 | {
60 | Proxy?.Disconnect();
61 | base.Dispose();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Helpers/MathHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Numerics;
3 |
4 | namespace VRE.Vridge.API.Client.Helpers
5 | {
6 | public static class MathHelpers
7 | {
8 | public static double RadToDeg(double rad)
9 | {
10 | return rad * (180.0 / Math.PI);
11 | }
12 |
13 | public static double DegToRad(double deg)
14 | {
15 | return Math.PI * deg / 180.0;
16 | }
17 |
18 | ///
19 | /// Converts 4x4 matrix into flat array with column-major layout.
20 | /// https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/geometry/row-major-vs-column-major-vector
21 | ///
22 | public static float[] FlattenAsColumnMajor(this Matrix4x4 matrix)
23 | {
24 | var array = new float[16];
25 | array[0] = (float)matrix.M11;
26 | array[1] = (float)matrix.M21;
27 | array[2] = (float)matrix.M31;
28 | array[3] = (float)matrix.M41;
29 | array[4] = (float)matrix.M12;
30 | array[5] = (float)matrix.M22;
31 | array[6] = (float)matrix.M32;
32 | array[7] = (float)matrix.M42;
33 | array[8] = (float)matrix.M13;
34 | array[9] = (float)matrix.M23;
35 | array[10] = (float)matrix.M33;
36 | array[11] = (float)matrix.M43;
37 | array[12] = (float)matrix.M14;
38 | array[13] = (float)matrix.M24;
39 | array[14] = (float)matrix.M34;
40 | array[15] = (float)matrix.M44;
41 |
42 | return array;
43 | }
44 |
45 | public static float[] Flatten(this Matrix4x4 matrix)
46 | {
47 | var array = new float[16];
48 | array[0] = (float)matrix.M11;
49 | array[1] = (float)matrix.M12;
50 | array[2] = (float)matrix.M13;
51 | array[3] = (float)matrix.M14;
52 | array[4] = (float)matrix.M21;
53 | array[5] = (float)matrix.M22;
54 | array[6] = (float)matrix.M23;
55 | array[7] = (float)matrix.M24;
56 | array[8] = (float)matrix.M31;
57 | array[9] = (float)matrix.M32;
58 | array[10] = (float)matrix.M33;
59 | array[11] = (float)matrix.M34;
60 | array[12] = (float)matrix.M41;
61 | array[13] = (float)matrix.M42;
62 | array[14] = (float)matrix.M43;
63 | array[15] = (float)matrix.M44;
64 |
65 | return array;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("VRE.Vridge.API.DesktopClient")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("VRE.Vridge.API.DesktopClient")]
15 | [assembly: AssemblyCopyright("Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/proto/VridgeApiProtoDefinition.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 | option java_multiple_files = true;
3 | option optimize_for = LITE_RUNTIME;
4 |
5 | package com.riftcat.vridge.api.client.java.proto;
6 | message Beacon {
7 | optional BeaconOrigin Role = 1 [default = Server];
8 | optional string MachineName = 2;
9 | optional string UserName = 3;
10 | optional string HumanReadableVersion = 4;
11 | }
12 | enum BeaconOrigin {
13 | Server = 0;
14 | Client = 1;
15 | }
16 | message ControllerStateRequest {
17 | optional int32 Version = 1 [default = 0];
18 | optional uint32 TaskType = 2 [default = 0];
19 | optional VRController ControllerState = 4;
20 | }
21 | message ControllerStateResponse {
22 | optional int32 Version = 1 [default = 0];
23 | optional uint32 ReplyCode = 2 [default = 0];
24 | }
25 | enum HandType {
26 | Left = 0;
27 | Right = 1;
28 | }
29 | message HapticPulse {
30 | optional int32 ControllerId = 1 [default = 0];
31 | optional uint32 LengthUs = 2 [default = 0];
32 | optional uint32 TimestampUs = 3 [default = 0];
33 | }
34 | enum HeadRelation {
35 | Unrelated = 0;
36 | IsInHeadSpace = 1;
37 | SticksToHead = 2;
38 | }
39 | message HeadTrackingRequest {
40 | optional int32 Version = 1 [default = 0];
41 | optional uint32 TaskType = 2 [default = 0];
42 | optional bytes Data = 3;
43 | }
44 | message HeadTrackingResponse {
45 | optional int32 Version = 1 [default = 0];
46 | optional uint32 ReplyCode = 2 [default = 0];
47 | repeated float Data = 3;
48 | optional TrackedPose TrackedPose = 4;
49 | }
50 | message TrackedPose {
51 | repeated float HeadOrientation = 1;
52 | repeated float HeadPosition = 2;
53 | optional float RecenterYawOffset = 3 [default = 0];
54 | optional float ApiYawOffset = 4 [default = 0];
55 | }
56 | message VRController {
57 | optional int32 ControllerId = 1 [default = 0];
58 | optional int32 Status = 2 [default = 0];
59 | repeated float OrientationMatrix = 3;
60 | optional VRControllerState_t ButtonState = 4;
61 | repeated double Acceleration = 5;
62 | repeated double Velocity = 6;
63 | optional HeadRelation HeadRelation = 7 [default = Unrelated];
64 | optional HandType SuggestedHand = 8 [default = Left];
65 | optional double Timestamp = 9 [default = 0];
66 | optional string Name = 11;
67 | repeated float Position = 12;
68 | repeated float Orientation = 13;
69 | }
70 | message VRControllerAxis_t {
71 | optional float x = 1 [default = 0];
72 | optional float y = 2 [default = 0];
73 | }
74 | message VRControllerState_t {
75 | optional uint32 unPacketNum = 1 [default = 0];
76 | optional uint64 ulButtonPressed = 2 [default = 0];
77 | optional uint64 ulButtonTouched = 3 [default = 0];
78 | optional VRControllerAxis_t rAxis0 = 4;
79 | optional VRControllerAxis_t rAxis1 = 5;
80 | optional VRControllerAxis_t rAxis2 = 7;
81 | optional VRControllerAxis_t rAxis3 = 8;
82 | optional VRControllerAxis_t rAxis4 = 9;
83 | }
84 |
--------------------------------------------------------------------------------
/src/vridge-api.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto2";
2 |
3 | option java_multiple_files = true;
4 | option java_package = "com.riftcat.vridge.api.client.java";
5 | option optimize_for = LITE_RUNTIME;
6 |
7 | package com.riftcat.vridge.api.client.java.proto;
8 | message Beacon {
9 | optional BeaconOrigin Role = 1 [default = Server];
10 | optional string MachineName = 2;
11 | optional string UserName = 3;
12 | optional string HumanReadableVersion = 4;
13 | }
14 | enum BeaconOrigin {
15 | Server = 0;
16 | Client = 1;
17 | }
18 | message ControllerStateRequest {
19 | optional int32 Version = 1 [default = 0];
20 | optional uint32 TaskType = 2 [default = 0];
21 | optional VRController ControllerState = 4;
22 | }
23 | message ControllerStateResponse {
24 | optional int32 Version = 1 [default = 0];
25 | optional uint32 ReplyCode = 2 [default = 0];
26 | }
27 | enum HandType {
28 | Left = 0;
29 | Right = 1;
30 | }
31 | message HapticPulse {
32 | optional int32 ControllerId = 1 [default = 0];
33 | optional uint32 LengthUs = 2 [default = 0];
34 | optional uint32 TimestampUs = 3 [default = 0];
35 | }
36 | enum HeadRelation {
37 | Unrelated = 0;
38 | IsInHeadSpace = 1;
39 | SticksToHead = 2;
40 | }
41 | message HeadTrackingRequest {
42 | optional int32 Version = 1 [default = 0];
43 | optional uint32 TaskType = 2 [default = 0];
44 | optional bytes Data = 3;
45 | }
46 | message HeadTrackingResponse {
47 | optional int32 Version = 1 [default = 0];
48 | optional uint32 ReplyCode = 2 [default = 0];
49 | repeated float Data = 3;
50 | optional TrackedPose TrackedPose = 4;
51 | }
52 | message TrackedPose {
53 | repeated float HeadOrientation = 1;
54 | repeated float HeadPosition = 2;
55 | optional float RecenterYawOffset = 3 [default = 0];
56 | optional float ApiYawOffset = 4 [default = 0];
57 | }
58 | message VRController {
59 | optional int32 ControllerId = 1 [default = 0];
60 | optional int32 Status = 2 [default = 0];
61 | repeated float OrientationMatrix = 3;
62 | optional VRControllerState_t ButtonState = 4;
63 | repeated double Acceleration = 5;
64 | repeated double Velocity = 6;
65 | optional HeadRelation HeadRelation = 7 [default = Unrelated];
66 | optional HandType SuggestedHand = 8 [default = Left];
67 | optional double Timestamp = 9 [default = 0];
68 | optional string Name = 11;
69 | repeated float Position = 12;
70 | repeated float Orientation = 13;
71 | }
72 | message VRControllerAxis_t {
73 | optional float x = 1 [default = 0];
74 | optional float y = 2 [default = 0];
75 | }
76 | message VRControllerState_t {
77 | optional uint32 unPacketNum = 1 [default = 0];
78 | optional uint64 ulButtonPressed = 2 [default = 0];
79 | optional uint64 ulButtonTouched = 3 [default = 0];
80 | optional VRControllerAxis_t rAxis0 = 4;
81 | optional VRControllerAxis_t rAxis1 = 5;
82 | optional VRControllerAxis_t rAxis2 = 7;
83 | optional VRControllerAxis_t rAxis3 = 8;
84 | optional VRControllerAxis_t rAxis4 = 9;
85 | }
86 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/DiscoveryClient.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes;
2 |
3 | import com.google.protobuf.InvalidProtocolBufferException;
4 | import com.riftcat.vridge.api.client.java.proto.Beacon;
5 | import com.riftcat.vridge.api.client.java.proto.BeaconOrigin;
6 | import com.riftcat.vridge.api.client.java.remotes.beacons.VridgeServerBeacon;
7 | import com.riftcat.vridge.api.client.java.remotes.beacons.VridgeServerBeaconList;
8 |
9 | import org.zeromq.ZBeacon;
10 |
11 | import java.net.InetAddress;
12 | import java.util.List;
13 |
14 | class DiscoveryClient implements Thread.UncaughtExceptionHandler {
15 |
16 | private final byte[] identity;
17 | private VridgeServerBeaconList beaconList;
18 | private ZBeacon beaconClient;
19 |
20 | DiscoveryClient(){
21 |
22 | identity = Beacon.newBuilder()
23 | .setRole(BeaconOrigin.Client)
24 | // We don't use information below
25 | .setMachineName("Android")
26 | .setHumanReadableVersion("Android")
27 | .setUserName("Android")
28 | .build()
29 | .toByteArray();
30 |
31 | beaconList = new VridgeServerBeaconList();
32 | reset();
33 | }
34 |
35 | public void reset(){
36 | dispose();
37 | beaconClient = new ZBeacon("255.255.255.255",38219, identity, true, true);
38 | beaconClient.setBroadcastInterval(1000);
39 | beaconClient.setListener(new ZBeacon.Listener() {
40 | @Override
41 | public void onBeacon(InetAddress sender, byte[] buffer) {
42 |
43 | Beacon beacon;
44 | try {
45 | beacon = Beacon.parser().parseFrom(buffer);
46 | } catch (InvalidProtocolBufferException e) {
47 | // Ignore stray packets
48 | return;
49 | }
50 |
51 | if(beacon.getRole() != BeaconOrigin.Server){
52 | // Skip other clients
53 | return;
54 | }
55 |
56 | beaconList.add(beacon, sender);
57 | }
58 | });
59 | beaconClient.setUncaughtExceptionHandlers(this, this);
60 | beaconClient.start();
61 | }
62 |
63 | public List getFreshServers() {
64 | return beaconList.getFreshServers();
65 | }
66 |
67 | public synchronized void dispose() {
68 | try {
69 | if(beaconClient != null){
70 | beaconClient.stop();
71 | beaconClient = null;
72 | }
73 | } catch (InterruptedException e) {
74 | e.printStackTrace();
75 | }
76 | }
77 |
78 | @Override
79 | public void uncaughtException(Thread t, Throwable e) {
80 | try {
81 | Thread.sleep(3000);
82 | } catch (InterruptedException ignored) {
83 |
84 | }
85 |
86 | reset();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace VRE.Vridge.API.DesktopTester.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VRE.Vridge.API.DesktopTester.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/ClientProxyBase.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | import com.google.protobuf.InvalidProtocolBufferException;
4 | import com.google.protobuf.MessageLite;
5 | import com.google.protobuf.Parser;
6 | import com.riftcat.vridge.api.client.java.APIClient;
7 | import com.riftcat.vridge.api.client.java.utils.APILogger;
8 |
9 | import org.zeromq.ZContext;
10 | import org.zeromq.ZMQ;
11 |
12 | import java.util.TimerTask;
13 | import java.util.concurrent.Executors;
14 | import java.util.concurrent.ScheduledExecutorService;
15 | import java.util.concurrent.TimeUnit;
16 | import java.util.concurrent.TimeoutException;
17 |
18 | public abstract class ClientProxyBase implements VRidgeApiProxy{
19 |
20 | private TimerTask keepAliveTimer;
21 | private Runnable keepAlivePing;
22 |
23 | private byte[] keepAlivePacket = { 0 };
24 |
25 | int CurrentVersion = 3;
26 | ZMQ.Socket socket;
27 |
28 | ClientProxyBase(String endpointAddress, boolean keepAlive){
29 |
30 | if(APIClient.ZContext == null) APIClient.ZContext = new ZContext(4);
31 | socket = APIClient.ZContext.createSocket(ZMQ.REQ);
32 | socket.setLinger(1000);
33 | socket.setSendTimeOut(15000);
34 | socket.setReceiveTimeOut(15000);
35 | socket.connect(endpointAddress);
36 | socket.setHWM(1);
37 |
38 | if (!keepAlive) return;
39 |
40 | keepAlivePing = new Runnable() {
41 | @Override
42 | public void run() {
43 | sendKeepAlivePing();
44 | }
45 | };
46 |
47 | ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
48 | executor.scheduleAtFixedRate(keepAlivePing, 1, 5, TimeUnit.SECONDS);
49 | }
50 |
51 | void CloseSocket(){
52 | APIClient.ZContext.destroySocket(socket);
53 | }
54 |
55 | synchronized T SendMessage(MessageLite msg, Parser parser) throws TimeoutException {
56 |
57 | APILogger.zmq("send begin");
58 | long timestamp = System.nanoTime();
59 | socket.send(msg.toByteArray());
60 | byte[] responseBytes = socket.recv();
61 | APILogger.zmq("recv end - " + (System.nanoTime() - timestamp) / 1000000.0);
62 |
63 | if (responseBytes != null){
64 | try {
65 | T response = parser.parseFrom(responseBytes);
66 | return response;
67 | } catch (InvalidProtocolBufferException e) {
68 | // whoops
69 | }
70 | }
71 |
72 | APILogger.zmq("timeout");
73 | APIClient.ZContext.destroySocket(socket);
74 | throw new TimeoutException();
75 | }
76 |
77 | public abstract void disconnect();
78 |
79 | public synchronized boolean sendKeepAlivePing(){
80 | boolean error = false;
81 | APILogger.zmq("ping begin: ");
82 | error = error || !socket.send(keepAlivePacket);
83 | error = error || socket.recv() == null;
84 | APILogger.zmq("ping end - error: " + error);
85 |
86 | return !error;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/HeadRemote.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes;
2 |
3 | import com.riftcat.vridge.api.client.java.proto.TrackedPose;
4 | import com.riftcat.vridge.api.client.java.proxy.HeadTrackingProxy;
5 |
6 | import java.util.concurrent.TimeoutException;
7 |
8 | public class HeadRemote extends RemoteBase {
9 | private HeadTrackingProxy proxy;
10 |
11 | HeadRemote(HeadTrackingProxy proxy) {
12 | super(proxy);
13 |
14 | this.proxy = proxy;
15 | }
16 |
17 | /**
18 | * Reorients tracking system and sets new center to current head direction.
19 | */
20 | public void recenter(){
21 | try{
22 | proxy.recenterView();
23 | }
24 | catch (Exception x){
25 | dispose();
26 | }
27 |
28 | }
29 |
30 | /**
31 | * Gets current head pose and related offsets. May return null on connection issues.
32 | */
33 | public TrackedPose getCurrentPose() {
34 |
35 | try{
36 | return proxy.getCurrentPose();
37 | }
38 | catch (Exception e){
39 | dispose();
40 | return null;
41 | }
42 | }
43 |
44 | /**
45 | * Sets head position to new location.
46 | */
47 | public void setPosition(float x, float y, float z){
48 | try{
49 | proxy.setPosition(x, y, z);
50 | }
51 | catch (Exception e){
52 | dispose();
53 | }
54 | }
55 |
56 | /**
57 | * Sets head position to new location and orientation.
58 | * This won't work for headsets with reprojection enabled.
59 | */
60 | public void setRotationAndPosition(float yaw, float pitch, float roll, float x, float y, float z){
61 | try{
62 | proxy.setRotationAndPosition(yaw, pitch, roll, x, y, z);
63 | }
64 | catch (Exception e){
65 | dispose();
66 | }
67 | }
68 |
69 |
70 | /**
71 | * Sets offsets in yaw axis to be applied to each head and controller pose processed by the system.
72 | * @param yaw Offset in radians.
73 | */
74 | public void setYawOffset(float yaw){
75 | try{
76 | proxy.setYawOffset(yaw);
77 | }
78 | catch (Exception x){
79 | dispose();
80 | }
81 | }
82 |
83 | /**
84 | * Marks the headset as in/outside of tracking range. Setting it to false will most likely
85 | * stop rendering on SteamVR side as pose data will be considered invalid.
86 | */
87 | public void setStatus(boolean isInTrackingRange)
88 | {
89 | try{
90 | proxy.changeTrackingState(isInTrackingRange);
91 | }
92 | catch (Exception e){
93 | dispose();
94 | }
95 | }
96 |
97 | // Type-cast-methods
98 | /**
99 | * Sets head position to new location and orientation.
100 | * This won't work for headsets with reprojection enabled.
101 | */
102 | public void setRotationAndPosition(double yaw, double pitch, double roll, double x, double y, double z){
103 | setRotationAndPosition((float) yaw, (float) pitch, (float) roll, (float) x, (float) y, (float) z);
104 | }
105 |
106 | /**
107 | * Sets head position to new location.
108 | */
109 | public void setPosition(double x, double y, double z) {
110 | setPosition((float) x, (float) y, (float) z);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/BroadcastProxy.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | import com.google.protobuf.InvalidProtocolBufferException;
4 | import com.riftcat.vridge.api.client.java.APIClient;
5 | import com.riftcat.vridge.api.client.java.proto.HapticPulse;
6 | import com.riftcat.vridge.api.client.java.utils.APILogger;
7 |
8 | import org.zeromq.ZMQ;
9 | import java.nio.charset.Charset;
10 | import java.util.LinkedList;
11 | import java.util.List;
12 |
13 |
14 | public class BroadcastProxy implements VRidgeApiProxy {
15 |
16 | private final String endpointAddr;
17 | private ZMQ.Socket socket;
18 | private List listeners = new LinkedList();
19 |
20 | private Thread threadPolling;
21 |
22 | public BroadcastProxy(String endpointAddr){
23 | this.endpointAddr = endpointAddr;
24 | }
25 |
26 | public void startPolling(){
27 |
28 | if(threadPolling != null) threadPolling.interrupt();
29 |
30 | threadPolling = new Thread(new Runnable() {
31 | @Override
32 | public void run() {
33 |
34 | socket = APIClient.ZContext.createSocket(ZMQ.SUB);
35 | socket.connect(endpointAddr);
36 | socket.subscribe("haptic".getBytes(Charset.forName("UTF-8")));
37 | socket.setLinger(1000);
38 |
39 | ZMQ.Poller poller = APIClient.ZContext.createPoller(1);
40 | poller.register(socket, ZMQ.Poller.POLLIN);
41 |
42 | while(!Thread.currentThread().isInterrupted()){
43 |
44 | int result = poller.poll(1000);
45 | if(result > 0){
46 |
47 | // we can ignore topic here, it's filtered at socket level
48 | // but we need to consume it from socket to continue
49 | socket.recvStr();
50 |
51 | byte[] bufMsg = socket.recv();
52 |
53 | try {
54 |
55 | // Deserialize
56 | HapticPulse pulse = HapticPulse.parseFrom(bufMsg);
57 |
58 | // Notify listeners
59 | for(IBroadcastListener listener : listeners){
60 | listener.onHapticPulse(pulse);
61 | }
62 |
63 | } catch (InvalidProtocolBufferException e) {
64 | // Invalid data - could not be deserialized
65 | }
66 | }
67 | } // while(!Thread.currentThread().isInterrupted())
68 |
69 | poller.close();
70 | }
71 | });
72 |
73 | threadPolling.start();
74 | }
75 |
76 | public void disconnect(){
77 | try {
78 | if(threadPolling != null){
79 | threadPolling.interrupt();
80 | threadPolling.join();
81 | }
82 |
83 | if(socket != null){
84 | socket.close();
85 | }
86 |
87 | listeners.clear();
88 | } catch (InterruptedException e) {
89 | APILogger.error("Can't close Broadcast endpoint.");
90 | e.printStackTrace();
91 | }
92 |
93 | }
94 |
95 | public void addListener(IBroadcastListener listener){
96 | listeners.add(listener);
97 | }
98 |
99 | public void removeListener(IBroadcastListener listener){
100 | listeners.remove(listener);
101 | }
102 |
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/Controller/ControllerProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Runtime.CompilerServices;
5 | using NetMQ;
6 | using VRE.Vridge.API.Client.Messages.OpenVR;
7 | using VRE.Vridge.API.Client.Messages.v3.Controller;
8 | using VRE.Vridge.API.Client.Messages.v3.Controller.Requests;
9 | using VRE.Vridge.API.Client.Messages.v3.Controller.Responses;
10 | using VRController = VRE.Vridge.API.Client.Messages.v3.Controller.VRController;
11 | using VRE.Vridge.API.Client.Remotes;
12 |
13 |
14 | namespace VRE.Vridge.API.Client.Proxy.Controller
15 | {
16 | ///
17 | /// Lower level access method for sending controller data to VRidge. Consider using
18 | /// with for easier operation.
19 | ///
20 | public class ControllerProxy : ClientProxyBasePB
21 | {
22 | private ControllerStateRequest controller;
23 |
24 | ///
25 | /// Creates controller proxy and establishes connection.
26 | ///
27 | ///
28 | /// Endpoint address (ip:port). Should be requested from control connection.
29 | ///
30 | ///
31 | /// True if automatic pings should keep connection alive even if caller doesn't send data.
32 | ///
33 | public ControllerProxy(string endpointAddress, bool keepAlive = false)
34 | : base(endpointAddress, keepAlive)
35 | {
36 | controller = new ControllerStateRequest()
37 | {
38 | TaskType = (byte) ControllerTask.SendFullState,
39 | Version = ControllerStateRequest.CurrentVersion
40 | };
41 | }
42 |
43 | ///
44 | /// Send full single VR controller state to VR.
45 | ///
46 | [MethodImpl(MethodImplOptions.Synchronized)]
47 | public void SendControllerData(VRController state)
48 | {
49 | controller.ControllerState = state;
50 | controller.Version = ControllerStateRequest.CurrentVersion;
51 | SendMessage(controller);
52 | }
53 |
54 | ///
55 | /// Recenter head tracking. Works the same as pressing recenter hotkey as configured in VRidge settings.
56 | ///
57 | public void RecenterHead()
58 | {
59 | SendMessage(new ControllerStateRequest()
60 | {
61 | ControllerState = default(VRController),
62 | TaskType = (byte) ControllerTask.RecenterHead,
63 | Version = ControllerStateRequest.CurrentVersion
64 | });
65 | }
66 |
67 | ///
68 | /// Disconnected from controller API and frees the API for other clients.
69 | ///
70 | public void Disconnect()
71 | {
72 | var disconnectRequest = new ControllerStateRequest()
73 | {
74 | TaskType = (byte)ControllerTask.Disconnect
75 | };
76 |
77 | try
78 | {
79 | SendMessage(disconnectRequest);
80 | }
81 | catch (TimeoutException)
82 | {
83 | // Connection probably dropped another way, ignoring
84 | }
85 | catch (FiniteStateMachineException)
86 | {
87 | // Connection state invalid, close anyway
88 | }
89 | CloseSocket();
90 | }
91 |
92 | private ControllerStateResponse SendMessage(ControllerStateRequest obj) => SendMessage(obj);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/ControllerProxy.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | import com.riftcat.vridge.api.client.java.codes.ControllerStateRequestCodes;
4 | import com.riftcat.vridge.api.client.java.proto.ControllerStateRequest;
5 | import com.riftcat.vridge.api.client.java.proto.ControllerStateResponse;
6 | import com.riftcat.vridge.api.client.java.proto.HandType;
7 | import com.riftcat.vridge.api.client.java.proto.VRController;
8 | import com.riftcat.vridge.api.client.java.proto.VRControllerAxis_t;
9 | import com.riftcat.vridge.api.client.java.proto.VRControllerState_t;
10 |
11 | import java.util.ArrayList;
12 | import java.util.Arrays;
13 | import java.util.LinkedList;
14 | import java.util.List;
15 | import java.util.concurrent.TimeoutException;
16 |
17 | public class ControllerProxy extends ClientProxyBase {
18 |
19 | private int packetNum = 0;
20 |
21 | public ControllerProxy(String endpointAddress){
22 | super(endpointAddress, true);
23 | }
24 |
25 | ///
26 | /// Send full single VR controller state to VR.
27 | ///
28 | public synchronized void sendControllerState(VRController state) throws TimeoutException {
29 | ControllerStateRequest data = ControllerStateRequest
30 | .newBuilder()
31 | .setTaskType(ControllerStateRequestCodes.SendFullState)
32 | .setControllerState(state)
33 | .build();
34 |
35 | sendMessage(data);
36 | }
37 |
38 | /**
39 | * Send full single VR controller state to VR.
40 | */
41 | public synchronized void sendControllerState(int controllerId, long touchedMask, long pressedMask,
42 | List orientationMatrix,
43 | float triggerValue,
44 | float analogX, float analogY, float[] velocity,
45 | HandType hand) throws TimeoutException {
46 |
47 | VRControllerState_t.Builder buttonState = VRControllerState_t.newBuilder()
48 | .setRAxis0(VRControllerAxis_t.newBuilder()
49 | .setX(analogX)
50 | .setY(analogY))
51 | .setRAxis1(VRControllerAxis_t.newBuilder()
52 | .setX(triggerValue))
53 | .setUlButtonPressed(pressedMask)
54 | .setUlButtonTouched(touchedMask)
55 | .setUnPacketNum(++packetNum);
56 |
57 |
58 |
59 | VRController.Builder controllerState = VRController.newBuilder()
60 | .setControllerId(controllerId)
61 | .addAllOrientationMatrix(orientationMatrix)
62 | .setStatus(0)
63 | .setSuggestedHand(hand)
64 | .setButtonState(buttonState);
65 |
66 | if(velocity != null){
67 | controllerState
68 | .addVelocity(velocity[0])
69 | .addVelocity(velocity[1])
70 | .addVelocity(velocity[2]);
71 | }
72 |
73 | ControllerStateRequest request = ControllerStateRequest.newBuilder()
74 | .setTaskType(ControllerStateRequestCodes.SendFullState)
75 | .setControllerState(controllerState)
76 | .build();
77 |
78 | sendMessage(request);
79 | }
80 |
81 | /** Recenter head tracking. Works the same as pressing recenter hotkey as configured in VRidge settings. */
82 | public void recenterHead() throws TimeoutException{
83 | ControllerStateRequest request = ControllerStateRequest
84 | .newBuilder()
85 | .setVersion(CurrentVersion)
86 | .setTaskType(ControllerStateRequestCodes.RecenterHead)
87 | .build();
88 | sendMessage(request);
89 | }
90 |
91 | /**
92 | * Disconnected from controller API and frees the API for other clients.
93 | */
94 | public void disconnect(){
95 | ControllerStateRequest disconnectRequest = ControllerStateRequest
96 | .newBuilder()
97 | .setVersion(CurrentVersion)
98 | .setTaskType(ControllerStateRequestCodes.Disconnect)
99 | .build();
100 |
101 | try{
102 | sendMessage(disconnectRequest);
103 | }
104 | catch (Exception x){
105 | // ignored
106 | }
107 | CloseSocket();
108 | }
109 |
110 | private ControllerStateResponse sendMessage(ControllerStateRequest req) throws TimeoutException {
111 | return SendMessage(req, ControllerStateResponse.parser());
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Helpers/SerializationHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using NetMQ;
5 | using Newtonsoft.Json;
6 | using ProtoBuf;
7 |
8 | namespace VRE.Vridge.API.Client.Helpers
9 | {
10 | public static class SerializationHelpers
11 | {
12 | ///
13 | /// Sends object as JSON-serialized data through given socket.
14 | ///
15 | public static void SendAsJson(this IOutgoingSocket socket, object obj)
16 | {
17 | var json = JsonConvert.SerializeObject(obj);
18 | socket.SendFrame(json);
19 | }
20 |
21 | ///
22 | /// Tries to send object as JSON-serialized data through given socket.
23 | /// Returns false if operation times out.
24 | ///
25 | public static bool TrySendAsJson(this IOutgoingSocket socket, object obj, int timeoutMs)
26 | {
27 | var json = JsonConvert.SerializeObject(obj);
28 | return socket.TrySendFrame(TimeSpan.FromMilliseconds(timeoutMs), json);
29 | }
30 |
31 | ///
32 | /// Awaits T object as given socket received as JSON.
33 | ///
34 | public static T ReceiveJson(this IReceivingSocket socket)
35 | {
36 | var json = socket.ReceiveFrameString();
37 | return JsonConvert.DeserializeObject(json);
38 | }
39 |
40 | ///
41 | /// Awaits T object as given socket received as JSON.
42 | /// Returns default(T) if operation times out.
43 | ///
44 | public static bool TryReceiveJson(this IReceivingSocket socket, out T response, int timeoutMs)
45 | {
46 | string responseStr;
47 | var success = socket.TryReceiveFrameString(TimeSpan.FromMilliseconds(timeoutMs), out responseStr);
48 |
49 | if (string.IsNullOrEmpty(responseStr))
50 | {
51 | response = default(T);
52 | return false;
53 | }
54 |
55 | response = JsonConvert.DeserializeObject(responseStr);
56 | return success;
57 | }
58 |
59 | ///
60 | /// Converts given structure to byte array.
61 | ///
62 | public static byte[] ProtoSerialize(object obj)
63 | {
64 | using (var ms = new MemoryStream())
65 | {
66 | Serializer.Serialize(ms, obj);
67 | return ms.ToArray();
68 | }
69 | }
70 |
71 | ///
72 | /// Converts given byte array to structure T.
73 | ///
74 | public static T ProtoDeserialize(byte[] data)
75 | {
76 | using (var ms = new MemoryStream(data))
77 | {
78 | return Serializer.Deserialize(ms);
79 | }
80 | }
81 |
82 | ///
83 | /// Converts structure to pointer. Caller needs to free IntPtr.
84 | ///
85 | public static IntPtr StructureToIntPtr(object str, out int size)
86 | {
87 | size = Marshal.SizeOf(str);
88 | IntPtr ptr = Marshal.AllocHGlobal(size);
89 | Marshal.StructureToPtr(str, ptr, false);
90 | return ptr;
91 | }
92 |
93 | ///
94 | /// Converts array to pointer. Caller needs to free IntPtr.
95 | ///
96 | public static IntPtr ArrayToIntPtr(byte[] array)
97 | {
98 | IntPtr ptr = Marshal.AllocHGlobal(array.Length);
99 | Marshal.Copy(array, 0, ptr, array.Length);
100 | return ptr;
101 | }
102 |
103 | ///
104 | /// Converts given structure to byte array.
105 | ///
106 | public static byte[] StructureToByteArray(object str)
107 | {
108 | int size = Marshal.SizeOf(str);
109 | byte[] arr = new byte[size];
110 |
111 | IntPtr ptr = Marshal.AllocHGlobal(size);
112 | Marshal.StructureToPtr(str, ptr, false);
113 | Marshal.Copy(ptr, arr, 0, size);
114 | Marshal.FreeHGlobal(ptr);
115 | return arr;
116 | }
117 |
118 | ///
119 | /// Converts given byte array to structure T.
120 | ///
121 | public static T ByteArrayToStructure(byte[] data)
122 | {
123 | GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
124 | T packet = (T)Marshal.PtrToStructure(pin.AddrOfPinnedObject(), typeof(T));
125 | pin.Free();
126 |
127 | return packet;
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/ClientProxyBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using System.Timers;
4 | using NetMQ;
5 | using NetMQ.Sockets;
6 | using VRE.Vridge.API.Client.Helpers;
7 |
8 | namespace VRE.Vridge.API.Client.Proxy
9 | {
10 | public class ClientProxyBase : IDisposable
11 | {
12 | protected bool AutoRestartOnTimeout = false;
13 |
14 | private readonly string endpointAddress;
15 | private readonly bool shouldKeepAlive;
16 |
17 | private Timer keepAliveTimer;
18 |
19 | private RequestSocket socket;
20 |
21 |
22 | protected ClientProxyBase(string endpointAddress, bool keepAlive = false)
23 | {
24 | this.endpointAddress = endpointAddress;
25 | this.shouldKeepAlive = keepAlive;
26 |
27 | CreateSocket();
28 | }
29 |
30 | internal bool IsSocketOpen => socket != null;
31 |
32 | ///
33 | /// Sends a struct message and deserializes response bytes into response struct.
34 | /// No timeout handling.
35 | ///
36 | public T OptimisticSendMessage(object msg)
37 | {
38 | socket.SendFrame(Serialize(msg));
39 | var reply = socket.ReceiveFrameBytes();
40 |
41 | return Deserialize(reply);
42 | }
43 |
44 | ///
45 | /// Sends a struct message and deserializes response bytes into response struct.
46 | /// Throws System.TimeoutException if timeout occurs and closes socket.
47 | ///
48 | [MethodImpl(MethodImplOptions.Synchronized)]
49 | public T SendMessage(object msg, int timeoutMs = 1000)
50 | {
51 | if (socket == null)
52 | {
53 | throw Timeout();
54 | }
55 |
56 | var stillAlive = socket.TrySendFrame(TimeSpan.FromMilliseconds(timeoutMs), Serialize(msg));
57 |
58 | if (!stillAlive)
59 | {
60 | throw Timeout();
61 | }
62 |
63 | stillAlive = socket.TryReceiveFrameBytes(TimeSpan.FromMilliseconds(timeoutMs), out var reply);
64 |
65 | if (!stillAlive)
66 | {
67 | throw Timeout();
68 | }
69 |
70 | return Deserialize(reply);
71 | }
72 |
73 | ///
74 | /// Sends a struct message and deserializes response bytes into response struct.
75 | /// Throws System.TimeoutException if timeout occurs and closes socket.
76 | /// Skips inputserialization.
77 | ///
78 | [MethodImpl(MethodImplOptions.Synchronized)]
79 | public T SendRawFrame(byte[] msgFrame, int timeoutMs = 1000)
80 | {
81 | byte[] reply;
82 |
83 | socket.SendFrame(msgFrame);
84 | var success = socket.TryReceiveFrameBytes(TimeSpan.FromMilliseconds(timeoutMs), out reply);
85 |
86 | if (success)
87 | {
88 | return Deserialize(reply);
89 | }
90 |
91 | throw Timeout();
92 | }
93 |
94 | ///
95 | /// Sends a zero byte to prevent connection from timing out.
96 | ///
97 | [MethodImpl(MethodImplOptions.Synchronized)]
98 | public void SendKeepAlivePing()
99 | {
100 | var isStillAlive = socket.TrySendFrame(TimeSpan.FromMilliseconds(30), new byte[]{0});
101 |
102 | if (!isStillAlive)
103 | {
104 | Timeout();
105 | return;
106 | }
107 |
108 | isStillAlive = socket.TryReceiveFrameBytes(TimeSpan.FromMilliseconds(30), out var bytes);
109 |
110 | if (!isStillAlive)
111 | {
112 | Timeout();
113 | }
114 |
115 | }
116 |
117 | private void CreateSocket()
118 | {
119 | socket = new RequestSocket();
120 | socket.Options.Linger = TimeSpan.FromSeconds(1);
121 | socket.Connect(endpointAddress);
122 |
123 | if (!shouldKeepAlive) return;
124 |
125 | /* Very basic keep alive mechanism
126 | * generally you should provide a steady stream of data yourself
127 | * or reconnect after a period if inactivity */
128 | keepAliveTimer = new Timer(5000);
129 | keepAliveTimer.Elapsed += (s, e) => SendKeepAlivePing();
130 | keepAliveTimer.Start();
131 | }
132 |
133 | private TimeoutException Timeout()
134 | {
135 | CloseSocket();
136 |
137 | if (AutoRestartOnTimeout)
138 | {
139 | CreateSocket();
140 | }
141 |
142 | return new TimeoutException();
143 | }
144 |
145 |
146 | protected void CloseSocket()
147 | {
148 | keepAliveTimer?.Stop();
149 | socket?.Dispose();
150 | socket = null;
151 | }
152 |
153 | protected virtual byte[] Serialize(object o)
154 | {
155 | return SerializationHelpers.StructureToByteArray(o);
156 | }
157 |
158 | protected virtual T Deserialize(byte[] array)
159 | {
160 | return SerializationHelpers.ByteArrayToStructure(array);
161 | }
162 |
163 | public void Dispose()
164 | {
165 | CloseSocket();
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/APIClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NetMQ.Sockets;
4 | using VRE.Vridge.API.Client.Helpers;
5 | using VRE.Vridge.API.Client.Messages;
6 | using VRE.Vridge.API.Client.Messages.Control;
7 | using VRE.Vridge.API.Client.Messages.Control.Requests;
8 | using VRE.Vridge.API.Client.Messages.Control.Responses;
9 | using VRE.Vridge.API.Client.Proxy.Broadcasts;
10 | using VRE.Vridge.API.Client.Proxy.Controller;
11 | using VRE.Vridge.API.Client.Proxy.HeadTracking;
12 |
13 | namespace VRE.Vridge.API.Client.Proxy
14 | {
15 | public class APIClient
16 | {
17 | public enum Endpoints
18 | {
19 | HeadTracking,
20 | Controller,
21 | Broadcast
22 | }
23 |
24 | private RequestSocket controlSocket;
25 |
26 | private readonly string serverAddress = "localhost";
27 | private readonly string appName = "default";
28 |
29 | public APIClient(string appName)
30 | {
31 | this.appName = appName;
32 | }
33 |
34 | public APIClient(string ip, string appName)
35 | {
36 | serverAddress = ip;
37 | this.appName = appName;
38 | }
39 |
40 | ///
41 | /// Sends control request to see what APIs are available.
42 | /// May return null if control connection dies (automatic reconnect will follow).
43 | ///
44 | public APIStatus GetStatus(int timeoutMs = 500)
45 | {
46 | APIStatus status;
47 |
48 | ConnectToControlSocket();
49 |
50 | controlSocket.SendAsJson(new ControlRequestHeader(appName, ControlRequestCode.RequestStatus));
51 | var success = controlSocket.TryReceiveJson(out status, timeoutMs);
52 |
53 | controlSocket.Close();
54 |
55 | if (success)
56 | {
57 | return status;
58 | }
59 |
60 | return null;
61 | }
62 |
63 | public T CreateProxy(bool keepAlive = true, int timeoutMs = 100)
64 | {
65 | // Find out which endpoint name should be used
66 | string endpointName;
67 | if (typeof(T) == typeof(HeadTrackingProxy))
68 | {
69 | endpointName = EndpointNames.HeadTracking;
70 | }
71 | else if (typeof(T) == typeof(ControllerProxy))
72 | {
73 | endpointName = EndpointNames.Controller;
74 | }
75 | else if (typeof(T) == typeof(BroadcastProxy))
76 | {
77 | endpointName = EndpointNames.Broadcast;
78 | }
79 | else
80 | {
81 | throw new ArgumentException("Invalid proxy requested.");
82 | }
83 |
84 | ConnectToControlSocket();
85 |
86 | // Try requesting given endpoint
87 | bool success = controlSocket.TrySendAsJson(new RequestEndpoint(endpointName, appName), timeoutMs);
88 |
89 | if (!success)
90 | {
91 | HandleControlConnectionException(new Exception("API server timeout."));
92 | }
93 |
94 |
95 | EndpointCreated response;
96 | success = controlSocket.TryReceiveJson(out response, timeoutMs);
97 |
98 | controlSocket.Close();
99 |
100 | if (!success)
101 | {
102 | HandleControlConnectionException(new Exception("API server timeout."));
103 | }
104 |
105 | if (response.Code == (int) ControlResponseCode.InUse)
106 | {
107 | HandleControlConnectionException(new Exception("API already in use by another client."));
108 | }
109 |
110 | // Initialize the proxy of requested type
111 | var connectionString = $"tcp://{serverAddress}:{response.Port}";
112 | if (typeof(T) == typeof(HeadTrackingProxy))
113 | {
114 | return (T) Convert.ChangeType(new HeadTrackingProxy(connectionString, keepAlive), typeof(T));
115 | }
116 | if (typeof(T) == typeof(ControllerProxy))
117 | {
118 | return (T) Convert.ChangeType(new ControllerProxy(connectionString, keepAlive), typeof(T));
119 | }
120 | if (typeof(T) == typeof(BroadcastProxy))
121 | {
122 | return (T) Convert.ChangeType(new BroadcastProxy(connectionString), typeof(T));
123 | }
124 |
125 | throw new ArgumentException("Invalid proxy requested.");
126 | }
127 |
128 | private void ConnectToControlSocket()
129 | {
130 | controlSocket = new RequestSocket();
131 | controlSocket.Connect(ControlEndpoint);
132 | }
133 |
134 | protected void HandleControlConnectionException(Exception x)
135 | {
136 | // Reset socket state to continue accepting new requests*
137 | controlSocket.Close();
138 | controlSocket = new RequestSocket();
139 | controlSocket.Connect(ControlEndpoint);
140 |
141 | // Let client know that something went wrong
142 | throw x;
143 |
144 | /* *This can be also done with ZMQ_REQ_RELAXED + ZMQ_REQ_CORRELATE
145 | options instead of brute-force-like restarting the socket
146 | but NetMQ does not seem to support these options */
147 | }
148 |
149 | private string ControlEndpoint => $"tcp://{serverAddress}:38219";
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/remotes/ControllerRemote.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.remotes;
2 |
3 | import com.riftcat.vridge.api.client.java.proto.HandType;
4 | import com.riftcat.vridge.api.client.java.proto.HeadRelation;
5 | import com.riftcat.vridge.api.client.java.proto.VRController;
6 | import com.riftcat.vridge.api.client.java.proto.VRControllerAxis_t;
7 | import com.riftcat.vridge.api.client.java.proto.VRControllerState_t;
8 | import com.riftcat.vridge.api.client.java.proto.VRControllerState_tOrBuilder;
9 | import com.riftcat.vridge.api.client.java.proxy.ControllerProxy;
10 | import com.riftcat.vridge.api.client.java.utils.ButtonMask;
11 |
12 | import java.util.concurrent.TimeoutException;
13 |
14 | public class ControllerRemote extends RemoteBase {
15 |
16 | private static int packetNum = 0;
17 | private ControllerProxy proxy;
18 |
19 | ControllerRemote(ControllerProxy proxy) {
20 | super(proxy);
21 | this.proxy = proxy;
22 | }
23 |
24 | /**
25 | * Sets VR controller to a new state
26 | * @param controllerId Unique ID of given controller
27 | * @param headRelation How given pose relates to the head. Usually unrelated is the best pick.
28 | * @param orientation Orientation as XYZW float[4].
29 | * @param position Position as XYZ float[3].
30 | * @param analogX (-1,1) horizontal touchpad position.
31 | * @param analogY (-1,1) vertical touchpad position.
32 | * @param analogTrigger (0,1) trigger state (1 is fully pulled)
33 | * @param isMenuPressed
34 | * @param isSystemPressed
35 | * @param isTriggerPressed
36 | * @param isGripPressed
37 | * @param isTouchpadPressed
38 | * @param isTouchpadTouched
39 | */
40 | public void setControllerState(
41 | // Controller ID
42 | int controllerId,
43 | HandType handType,
44 | boolean disableController,
45 | // Pose data
46 | HeadRelation headRelation,
47 | float[] orientation,
48 | float[] position,
49 | // Touchpad state [-1,1]
50 | double analogX,
51 | double analogY,
52 |
53 | // Trigger state
54 | double analogTrigger,
55 |
56 | // Button states
57 | boolean isMenuPressed,
58 | boolean isSystemPressed,
59 | boolean isTriggerPressed,
60 | boolean isGripPressed,
61 | boolean isTouchpadPressed,
62 | boolean isTouchpadTouched){
63 |
64 | // See openvr.h in OpenVR SDK for mappings and masks
65 | // https://github.com/ValveSoftware/openvr/blob/master/headers/openvr.h
66 |
67 | long pressedMask = buildPressedMask(isMenuPressed, isSystemPressed, isTriggerPressed, isGripPressed, isTouchpadPressed);
68 | long touchedMask = buildTouchedMask(isTouchpadTouched, isTriggerPressed);
69 |
70 | int controllerStatus = 0;
71 | if(disableController == true) {
72 | controllerStatus = 2;
73 | }
74 |
75 | VRControllerState_tOrBuilder buttons = VRControllerState_t.newBuilder()
76 | .setRAxis0(VRControllerAxis_t.newBuilder()
77 | .setX((float) analogX)
78 | .setY((float) analogY))
79 | .setRAxis1(VRControllerAxis_t.newBuilder()
80 | .setX((float) analogTrigger))
81 | .setUlButtonPressed(pressedMask)
82 | .setUlButtonTouched(touchedMask)
83 | .setUnPacketNum(++packetNum); // Touchpad
84 |
85 |
86 | VRController.Builder controllerState = VRController.newBuilder()
87 | .setControllerId(controllerId)
88 | .addOrientation(orientation[0])
89 | .addOrientation(orientation[1])
90 | .addOrientation(orientation[2])
91 | .addOrientation(orientation[3])
92 | .setStatus(controllerStatus)
93 | .setSuggestedHand(handType)
94 | .setHeadRelation(headRelation)
95 | .setButtonState((VRControllerState_t.Builder) buttons);
96 |
97 | if(position != null){
98 | controllerState.addPosition(position[0]);
99 | controllerState.addPosition(position[1]);
100 | controllerState.addPosition(position[2]);
101 | }
102 |
103 | try {
104 | proxy.sendControllerState(controllerState.build());
105 | } catch (Exception e) {
106 | dispose();
107 | }
108 | }
109 |
110 | /** Recenter head tracking. Works the same as pressing recenter hotkey as configured in VRidge settings. */
111 | public void recenterHead(){
112 | try{
113 | proxy.recenterHead();
114 | }
115 | catch (Exception e){
116 | dispose();
117 | }
118 | }
119 |
120 | private long buildTouchedMask(boolean isTouchpadTouched, boolean isTriggerTouched) {
121 | long mask = 0;
122 | if (isTouchpadTouched) mask |= ButtonMask.Touchpad;
123 | if (isTriggerTouched) mask |= ButtonMask.Trigger;
124 | return mask;
125 | }
126 |
127 | private long buildPressedMask(
128 | boolean isMenuPressed,
129 | boolean isSystemPressed,
130 | boolean isTriggerPressed,
131 | boolean isGripPressed,
132 | boolean isTouchpadPressed) {
133 |
134 | long mask = 0;
135 | if (isMenuPressed) mask |= ButtonMask.ApplicationMenu;
136 | if (isSystemPressed) mask |= ButtonMask.System;
137 | if (isTriggerPressed) mask |= ButtonMask.Trigger;
138 | if (isGripPressed) mask |= ButtonMask.Grip;
139 | if (isTouchpadPressed) mask |= ButtonMask.Touchpad;
140 | return mask;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Remotes/ControllerRemote.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Numerics;
5 | using System.Text;
6 | using VRE.Vridge.API.Client.Helpers;
7 | using VRE.Vridge.API.Client.Messages.BasicTypes;
8 | using VRE.Vridge.API.Client.Messages.OpenVR;
9 | using VRE.Vridge.API.Client.Messages.v3.Broadcast;
10 | using VRE.Vridge.API.Client.Messages.v3.Controller;
11 | using VRE.Vridge.API.Client.Proxy.Controller;
12 | using VRController = VRE.Vridge.API.Client.Messages.v3.Controller.VRController;
13 |
14 | namespace VRE.Vridge.API.Client.Remotes
15 | {
16 | public class ControllerRemote : RemoteBase
17 | {
18 | private uint packetNum = 0;
19 |
20 | internal ControllerRemote(ControllerProxy proxy) : base(proxy)
21 | {
22 | }
23 |
24 | ///
25 | /// Sends full controller state as defined by arguments.
26 | ///
27 | public void SetControllerState(
28 | // Controller ID
29 | int controllerId,
30 |
31 | // Pose data
32 | HeadRelation headRelation,
33 | HandType suggestedHand,
34 | Quaternion orientation,
35 | Vector3? position,
36 |
37 | // Touchpad state [-1,1]
38 | double analogX,
39 | double analogY,
40 |
41 | // Trigger state
42 | double analogTrigger,
43 |
44 | // Button states
45 | bool isMenuPressed,
46 | bool isSystemPressed,
47 | bool isTriggerPressed,
48 | bool isGripPressed,
49 | bool isTouchpadPressed,
50 | bool isTouchpadTouched)
51 | {
52 |
53 | // See openvr.h in OpenVR SDK for mappings and masks
54 | // https://github.com/ValveSoftware/openvr/blob/master/headers/openvr.h
55 |
56 | var buttons = new VRControllerState_t()
57 | {
58 | rAxis0 = new VRControllerAxis_t((float)analogX, (float)analogY), // Touchpad
59 | rAxis1 = new VRControllerAxis_t((float)analogTrigger, 0), // Trigger
60 | rAxis2 = new VRControllerAxis_t(0, 0),
61 | rAxis3 = new VRControllerAxis_t(0, 0),
62 | rAxis4 = new VRControllerAxis_t(0, 0),
63 | ulButtonPressed = BuildButtonPressedMask(isMenuPressed, isSystemPressed, isTriggerPressed, isGripPressed, isTouchpadPressed),
64 | ulButtonTouched = BuildButtonTouchedMask(isTouchpadTouched, true),
65 | unPacketNum = ++packetNum
66 |
67 | };
68 |
69 | var controllerState = new VRController()
70 | {
71 | ButtonState = buttons,
72 | Status = 0,
73 | ControllerId = controllerId,
74 | Position = position.HasValue ? new[] { position.Value.X, position.Value.Y, position.Value.Z } : null,
75 | Orientation = new [] {orientation.X, orientation.Y, orientation.Z, orientation.W },
76 | HeadRelation = headRelation,
77 | SuggestedHand = suggestedHand
78 | };
79 |
80 | WrapTimeouts(() => { Proxy.SendControllerData(controllerState); });
81 | }
82 |
83 | ///
84 | /// Recenter head tracking. Works the same as pressing recenter hotkey as configured in VRidge settings.
85 | ///
86 | public void RecenterHead()
87 | {
88 |
89 | WrapTimeouts(() => { Proxy?.RecenterHead(); });
90 |
91 | }
92 |
93 | internal override void Dispose()
94 | {
95 | Proxy?.Disconnect();
96 | base.Dispose();
97 | }
98 |
99 | ///
100 | /// Maps button pressed state into OpenVR packed ulong.
101 | ///
102 | private ulong BuildButtonPressedMask(
103 | bool isMenuPressed,
104 | bool isSystemPressed,
105 | bool isTriggerPressed,
106 | bool isGripPressed,
107 | bool isTouchpadPressed)
108 | {
109 | ulong mask = 0;
110 |
111 | if (isMenuPressed) mask |= ButtonMask.ApplicationMenu;
112 | if (isSystemPressed) mask |= ButtonMask.System;
113 | if (isTriggerPressed) mask |= ButtonMask.Trigger;
114 | if (isGripPressed) mask |= ButtonMask.Grip;
115 | if (isTouchpadPressed) mask |= ButtonMask.Touchpad;
116 |
117 | return mask;
118 | }
119 |
120 |
121 | ///
122 | /// Maps button touched state into OpenVR packed ulong.
123 | ///
124 | private ulong BuildButtonTouchedMask(bool isTouchpadTouched, bool isTriggerTouched)
125 | {
126 | ulong mask = 0;
127 |
128 | if (isTouchpadTouched) mask |= ButtonMask.Touchpad;
129 | if (isTriggerTouched) mask |= ButtonMask.Trigger;
130 |
131 | return mask;
132 | }
133 |
134 | ///
135 | /// Builds 4x4 combined matrix for given translation and rotation.
136 | /// Not used and not recommended anymore. Send orientation[+position] instead of matrix.
137 | ///
138 | private Matrix4x4 BuildControllerMatrix(double x, double y, double z, double yaw, double pitch, double roll)
139 | {
140 | Matrix4x4 m = Matrix4x4.Identity;
141 |
142 |
143 | m *= Matrix4x4.CreateFromYawPitchRoll(
144 | (float)MathHelpers.DegToRad(yaw),
145 | (float)MathHelpers.DegToRad(pitch),
146 | (float)MathHelpers.DegToRad(roll));
147 |
148 | m*= Matrix4x4.CreateTranslation((float)x, (float)y, (float)z);
149 |
150 | return m;
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/APIClient.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java;
2 |
3 | import com.riftcat.vridge.api.client.java.control.ControlRequestCode;
4 | import com.riftcat.vridge.api.client.java.control.ControlResponseCode;
5 | import com.riftcat.vridge.api.client.java.control.requests.ControlRequestHeader;
6 | import com.riftcat.vridge.api.client.java.control.requests.RequestEndpoint;
7 | import com.riftcat.vridge.api.client.java.control.responses.APIStatus;
8 | import com.riftcat.vridge.api.client.java.control.responses.EndpointCreated;
9 | import com.riftcat.vridge.api.client.java.proxy.BroadcastProxy;
10 | import com.riftcat.vridge.api.client.java.proxy.ClientProxyBase;
11 | import com.riftcat.vridge.api.client.java.proxy.ControllerProxy;
12 | import com.riftcat.vridge.api.client.java.proxy.HeadTrackingProxy;
13 | import com.riftcat.vridge.api.client.java.proxy.VRidgeApiProxy;
14 | import com.riftcat.vridge.api.client.java.utils.ILog;
15 | import com.riftcat.vridge.api.client.java.utils.SocketHelpers;
16 |
17 | import org.zeromq.ZContext;
18 | import org.zeromq.ZMQ;
19 |
20 | import java.util.HashMap;
21 | import java.util.LinkedList;
22 | import java.util.concurrent.TimeoutException;
23 |
24 | public class APIClient {
25 |
26 | public final static int HEADTRACKING = 0;
27 | public final static int CONTROLLER = 1;
28 | public final static int BROADCASTS = 2;
29 |
30 | public static ZContext ZContext;
31 |
32 | private HashMap proxies;
33 | private String serverAddress = "tcp://localhost";
34 |
35 | // Connections with same app name will not result in "endpoint in use" response
36 | private String appName = "";
37 |
38 | public APIClient(String appName){
39 | ZContext = new ZContext(4);
40 | proxies = new HashMap();
41 |
42 | this.appName = appName;
43 | }
44 |
45 | public APIClient(String ip, String appName){
46 | this(appName);
47 | serverAddress = ip;
48 | }
49 |
50 | ///
51 | /// Sends control request to see what APIs are available.
52 | /// May return null if control connection dies (automatic reconnect will follow).
53 | ///
54 | public APIStatus GetStatus() throws Exception {
55 |
56 | ZMQ.Socket controlSocket = createControlSocket();
57 | if (controlSocket == null)
58 | {
59 | return null;
60 | }
61 |
62 | SocketHelpers.SendAsJson(controlSocket, new ControlRequestHeader(ControlRequestCode.RequestStatus));
63 | APIStatus status = SocketHelpers.ReceiveByJson(controlSocket, APIStatus.class);
64 | APIClient.ZContext.destroySocket(controlSocket);
65 |
66 | if (status != null){
67 | return status;
68 | }
69 |
70 | throw new Exception("Could not read API status.");
71 | }
72 |
73 | public T getProxy(int proxyType) throws Exception {
74 |
75 | VRidgeApiProxy proxy = proxies.get(proxyType);
76 | ZMQ.Socket controlSocket = createControlSocket();
77 |
78 | if(proxy == null){
79 |
80 | String endpointName = null;
81 | switch (proxyType)
82 | {
83 | case HEADTRACKING:
84 | endpointName = EndpointNames.HeadTracking;
85 | break;
86 | case CONTROLLER:
87 | endpointName = EndpointNames.Controller;
88 | break;
89 | case BROADCASTS:
90 | endpointName = EndpointNames.Broadcast;
91 | break;
92 | }
93 |
94 | if(endpointName == null){{
95 | throw new IllegalArgumentException("Invalid proxy type was requested.");
96 | }}
97 |
98 | SocketHelpers.SendAsJson(controlSocket, new RequestEndpoint(endpointName, appName));
99 | EndpointCreated response = SocketHelpers.ReceiveByJson(controlSocket, EndpointCreated.class);
100 | APIClient.ZContext.destroySocket(controlSocket);
101 |
102 | if(response == null ){
103 | throw new TimeoutException("API server timeout");
104 | }
105 |
106 | if(response.Code == ControlResponseCode.InUse){
107 | throw new Exception("API endpoint in use.");
108 | }
109 |
110 | switch (proxyType){
111 | case HEADTRACKING:
112 | proxies.put(proxyType, new HeadTrackingProxy("tcp://" + serverAddress + ":" + response.Port, true));
113 | break;
114 | case CONTROLLER:
115 | proxies.put(proxyType, new ControllerProxy("tcp://" + serverAddress + ":" + response.Port));
116 | break;
117 | case BROADCASTS:
118 | proxies.put(proxyType, new BroadcastProxy("tcp://" + serverAddress + ":" + response.Port));
119 | break;
120 | }
121 | }
122 |
123 | return (T) proxies.get(proxyType);
124 | }
125 |
126 | public void disconnectProxy(int proxyType)
127 | {
128 | VRidgeApiProxy proxy = proxies.get(proxyType);
129 |
130 | if (proxy == null) return;
131 |
132 | proxy.disconnect();
133 | proxies.put(proxyType, null);
134 | }
135 |
136 | public void disconnectAll() {
137 | for(int proxyId : proxies.keySet()){
138 | disconnectProxy(proxyId);
139 | }
140 | }
141 |
142 | private String getEndpointAddress() {
143 |
144 | return "tcp://" + serverAddress + ":38219";
145 | }
146 |
147 | private ZMQ.Socket createControlSocket(){
148 | String ctrlAddress = getEndpointAddress();
149 |
150 | ZMQ.Socket controlSocket = ZContext.createSocket(ZMQ.REQ);
151 | controlSocket.connect(ctrlAddress);
152 | controlSocket.setSendTimeOut(1000);
153 | controlSocket.setReceiveTimeOut(1000);
154 | return controlSocket;
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quick description
2 |
3 | VRidge API is a way to interact with VRidge in any language of your choice. We use ZeroMQ sockets as a low latency transport. It can work both locally and remotely through network.
4 |
5 | VRidge API allows you to write full or partial head tracking data, read mobile tracking data and set offsets to correct drift or sync it to your coordinate system. You can also send controller states (buttons, triggers, touchpads), and transforms (motion controller orientation and position in 3D space).
6 |
7 | Everything is loaded as single VRidge OpenVR driver. Some of the above things can be done through writing separate OpenVR drivers but VRidge API has benefits of two-way communications with an ability to mix coordinate systems in a more elastic way. It is also more stable than separate OpenVR drivers potentially providing conflicting data.
8 |
9 | # Getting started
10 |
11 | ## General requirements
12 | * ZeroMQ (or any lib that communicate with ZMQ sockets)
13 | * JSON serializer
14 |
15 | VRidge API is accessible over TCP, abstracted by ZeroMQ sockets. This allows you to use API any language that you choose. See [ZeroMQ language bindings](http://zeromq.org/bindings:_start) page and get library for language of your choice.
16 |
17 | ## Requirements for this example
18 |
19 | This repository contains example implementation of API client in .NET. You can use it in your .NET projects by simply building and referencing the APIClient project.
20 |
21 | C# projects require:
22 |
23 | * NetMQ
24 | * Newtonsoft.Json
25 | * .NET Standard 2.0 compatible project - one of the following
26 | * .NET Framework 4.6.1 +
27 | * .NET Core 2.0 +
28 | * Mono 5.4 +
29 | * UWP 10.0.16299 +
30 | * Xamarin
31 | * iOS 10.14 +
32 | * Mac 3.8
33 | * Android 8.0 +
34 | * MvvmLight (only for WPF example project - /src/examples/VRE.Vridge.API.DesktopClient)
35 |
36 | Both are referenced as NuGet packages in .csproj and will be restored on pre-build.
37 |
38 | # API usage
39 |
40 | ## Simple fire-and-forget access
41 | If you don't want to manage connection state, you can use fire-and-forget access layer which manages the connection state for you. See [VridgeRemote](https://github.com/RiftCat/vridge-api/wiki/VridgeRemote-(fire-and-forget-layer)) for more details.
42 |
43 | ## Advanced usage
44 |
45 | ### Control endpoint
46 |
47 | This endpoint provides two functions:
48 |
49 | - You can find out what API endpoints are available and wether they are currently in use or not.
50 |
51 | - You can connect to specific API endpoint by sending a packet with requested endpoint name and your version number. This will open a listener on the server side compatible with your requested version. Response message will contain ip:port endpoint that can be connected.
52 |
53 | See [control channel wiki page](https://github.com/RiftCat/vridge-api/wiki/Control-channel) for details.
54 |
55 | ### Data endpoints
56 |
57 | Data channels are used to interact with VRidge and send/receive actual data. Currently we have two endpoints. See pages below for details.
58 |
59 | Controller API allows you to send VR motion controller state without writing a full OpenVR driver. This allows a more stable experience since only one driver is loaded in SteamVR.
60 |
61 | See [Controller API](https://github.com/RiftCat/vridge-api/wiki/Controller-API) for protocol and details.
62 |
63 | Head tracking endpoint allows you to control head tracking in a variety of modes. You can use it to provide positional, rotational or combined data. You can also read mobile sensor data and provide an offset. You can also modify phone tracking data in real time before it's used for rendering in VR.
64 |
65 | See [Head Tracking API](https://github.com/RiftCat/vridge-api/wiki/Head-Tracking-API) for protocol and available modes
66 |
67 | Broadcast endpoint carries one-way notifications. Currently only haptic pulses are propagated through broadcast channel. It is implemented as ZMQ PUB-SUB sockets.
68 |
69 | See [Listening to broadcasts](https://github.com/RiftCat/vridge-api/wiki/Listening-to-haptic-feedback).
70 |
71 | ## Changelog
72 |
73 | ### API v3.1 (VRidge 2.3+)
74 |
75 | #### Additions
76 | * Added Java API client.
77 | * Added VridgeRemote class as a fire-and-forget access layer to use API without managing connection state.
78 | * Added a way to remap 3DOF controllers into 6DOF controllers, attached to head.
79 | * Added HeadRelation which configures how the pose is affected by recenter calls. Default "Unrelated" should cover most cases.
80 | * Added discovery UDP broadcast which lets you find active VRidge servers on the local network.
81 |
82 |
83 | #### Changes
84 |
85 | * Removed async offset's pitch and roll axes. Old calls will discard pitch and roll data and only use yaw offset. [Discussion](https://github.com/RiftCat/vridge-api/issues/15).
86 | * When using reprojection-enabled device, rotational head tracking input will be discarded. External rotational data doesn't play well with devices expecting to use late reprojection based on their own sensor data.
87 | * Controllers will now disappear after 5 seconds without new data.
88 | * Deprecated OrientationMatrix as pose format. Added separate rotation quaternion and position vector instead. Removes ambiguity of pose matrix format and byte layout. Old format still works.
89 | * C# API client now multi-targets .NET Standard 2.0 and .NET Framework 4.7.
90 |
91 |
92 |
93 |
94 |
95 |
96 | ### API v3 (VRidge 2.0+)
97 | * Added velocity and acceleration to controller data packets.
98 | * Migrated protocol to Protobuf serialization scheme to make it easier to write cross-platform code.
99 | * Migrated client library to .NET Standard 2.0 to make the SDK cross-platform.
100 | * Updated WPF example to use v3.
101 | * Fixed a bug that prevented remote connections without the issue #6 workaround.
102 | * Removed v1 and v2 definitions from the project. VRidge runtime still supports projects using those versions but we recommend using v3 for new projects.
103 |
104 | ### API v2 (VRidge 1.5)
105 |
106 | * Added haptic pulses as PUB-SUB sockets.
107 | * Added recenter head tracking call to mirror recenter hotkey function.
108 | * Added ChangeState to flag HMD as inside/outside of tracking range.
109 |
--------------------------------------------------------------------------------
/src/java/VRE.Vridge.API/VRE.Vridge.API.Client/src/main/java/com/riftcat/vridge/api/client/java/proxy/HeadTrackingProxy.java:
--------------------------------------------------------------------------------
1 | package com.riftcat.vridge.api.client.java.proxy;
2 |
3 | import com.google.protobuf.ByteString;
4 | import com.riftcat.vridge.api.client.java.codes.HeadTrackingRequestCodes;
5 | import com.riftcat.vridge.api.client.java.codes.HeadTrackingResponseCodes;
6 | import com.riftcat.vridge.api.client.java.codes.TrackedDeviceStatus;
7 | import com.riftcat.vridge.api.client.java.proto.HeadTrackingRequest;
8 | import com.riftcat.vridge.api.client.java.proto.HeadTrackingResponse;
9 | import com.riftcat.vridge.api.client.java.proto.TrackedPose;
10 | import com.riftcat.vridge.api.client.java.utils.APILogger;
11 | import com.riftcat.vridge.api.client.java.utils.SerializationUtils;
12 |
13 | import java.nio.ByteBuffer;
14 | import java.nio.ByteOrder;
15 | import java.util.concurrent.TimeoutException;
16 |
17 | public class HeadTrackingProxy extends ClientProxyBase {
18 |
19 | // This is only partial implementation of API calls
20 |
21 | public HeadTrackingProxy(String endpointAddress, boolean shouldKeepAlive){
22 | super(endpointAddress, shouldKeepAlive);
23 | }
24 |
25 | /**
26 | * Sets head position to new location.
27 | */
28 | public boolean setPosition(float x, float y, float z) throws TimeoutException {
29 | HeadTrackingRequest request = HeadTrackingRequest
30 | .newBuilder()
31 | .setVersion(CurrentVersion)
32 | .setTaskType(HeadTrackingRequestCodes.SendPositionOnly)
33 | .setData(SerializationUtils.byteStringFromFloats(x, y, z))
34 | .build();
35 |
36 | HeadTrackingResponse reply = sendMessage(request);
37 |
38 | return reply.getReplyCode() == HeadTrackingResponseCodes.AcceptedYourData;
39 | }
40 |
41 | /**
42 | Sets position and rotation and returns true if the value was accepted.
43 | This won't work for headsets with reprojection enabled.
44 | */
45 | public boolean setRotationAndPosition(float yaw, float pitch, float roll, float x, float y, float z) throws TimeoutException {
46 | HeadTrackingRequest request = HeadTrackingRequest
47 | .newBuilder()
48 | .setVersion(CurrentVersion)
49 | .setTaskType(HeadTrackingRequestCodes.SendRadRotationAndPosition)
50 | .setData(SerializationUtils.byteStringFromFloats(pitch, yaw, roll, x, y, z))
51 | .build();
52 |
53 | HeadTrackingResponse reply = sendMessage(request);
54 |
55 | return reply.getReplyCode() == HeadTrackingResponseCodes.AcceptedYourData;
56 | }
57 |
58 | /**
59 | Sets position and rotation and returns true if the value was accepted.
60 | This won't work for headsets with reprojection enabled.
61 | */
62 | public boolean setRotationAndPosition(float quatQ, float quatY, float quatZ, float quatW, float posX, float posY, float posZ) throws TimeoutException {
63 | HeadTrackingRequest request = HeadTrackingRequest
64 | .newBuilder()
65 | .setVersion(CurrentVersion)
66 | .setTaskType(HeadTrackingRequestCodes.SendQuatRotationAndPosition)
67 | .setData(SerializationUtils.byteStringFromFloats(quatQ, quatY, quatZ, quatW, posX, posY, posZ))
68 | .build();
69 |
70 | HeadTrackingResponse reply = sendMessage(request);
71 |
72 | return reply.getReplyCode() == HeadTrackingResponseCodes.AcceptedYourData;
73 | }
74 |
75 | /**
76 | * Reorients tracking system and sets new center to current head direction.
77 | */
78 | public boolean recenterView() throws TimeoutException {
79 | HeadTrackingRequest request = HeadTrackingRequest
80 | .newBuilder()
81 | .setVersion(CurrentVersion)
82 | .setTaskType(HeadTrackingRequestCodes.Recenter)
83 | .build();
84 |
85 | HeadTrackingResponse reply = sendMessage(request);
86 |
87 | return reply.getReplyCode() == HeadTrackingResponseCodes.AcceptedYourData;
88 | }
89 |
90 |
91 | /**
92 | * Gets current head pose and related offsets.
93 | */
94 | public TrackedPose getCurrentPose() throws TimeoutException {
95 |
96 | HeadTrackingRequest request = HeadTrackingRequest
97 | .newBuilder()
98 | .setVersion(CurrentVersion)
99 | .setTaskType(HeadTrackingRequestCodes.RequestReadOnlyPose)
100 | .build();
101 |
102 | HeadTrackingResponse reply = sendMessage(request);
103 |
104 | if(reply.getReplyCode() == HeadTrackingResponseCodes.SendingCurrentTrackedPose){
105 | return reply.getTrackedPose();
106 | }
107 | else{
108 | return null;
109 | }
110 | }
111 |
112 | public void setYawOffset(float yaw) throws TimeoutException {
113 | HeadTrackingRequest request = HeadTrackingRequest
114 | .newBuilder()
115 | .setVersion(CurrentVersion)
116 | .setTaskType(HeadTrackingRequestCodes.SetYawOffset)
117 | .setData(SerializationUtils.byteStringFromFloats(yaw))
118 | .build();
119 |
120 | sendMessage(request);
121 | }
122 |
123 | public void changeTrackingState(boolean isInTrackingRange) throws TimeoutException {
124 | byte[] state = new byte[1];
125 | state[0] = isInTrackingRange ? TrackedDeviceStatus.Active : TrackedDeviceStatus.TempUnavailable;
126 | HeadTrackingRequest request = HeadTrackingRequest
127 | .newBuilder()
128 | .setVersion(CurrentVersion)
129 | .setTaskType(HeadTrackingRequestCodes.ChangeState)
130 | .setData(ByteString.copyFrom(state))
131 | .build();
132 |
133 | sendMessage(request);
134 | }
135 |
136 | @Override
137 | public void disconnect() {
138 | HeadTrackingRequest disconnectRequest = HeadTrackingRequest.newBuilder()
139 | .setVersion(CurrentVersion)
140 | .setTaskType(HeadTrackingRequestCodes.Disconnect)
141 | .build();
142 |
143 | try{
144 | sendMessage(disconnectRequest);
145 | }
146 | catch (Exception x){
147 | // ignored
148 | }
149 |
150 | CloseSocket();
151 | }
152 |
153 | private HeadTrackingResponse sendMessage(HeadTrackingRequest req) throws TimeoutException {
154 | return SendMessage(req, HeadTrackingResponse.parser());
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/VRE.Vridge.API.DesktopTester.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {97ECBE1C-03EF-461D-A389-312C729A7EA6}
8 | WinExe
9 | Properties
10 | VRE.Vridge.API.DesktopTester
11 | Vridge API Tester
12 | v4.7
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 | SAK
18 | SAK
19 | SAK
20 | SAK
21 |
22 |
23 |
24 | AnyCPU
25 | true
26 | full
27 | false
28 | bin\Debug\
29 | DEBUG;TRACE
30 | prompt
31 | 4
32 |
33 |
34 | AnyCPU
35 | pdbonly
36 | true
37 | bin\Release\
38 | TRACE
39 | prompt
40 | 4
41 |
42 |
43 | icon.ico
44 |
45 |
46 |
47 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll
48 | True
49 |
50 |
51 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll
52 | True
53 |
54 |
55 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll
56 | True
57 |
58 |
59 | ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll
60 | True
61 |
62 |
63 |
64 |
65 |
66 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
67 |
68 |
69 | ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll
70 | True
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 4.0
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | MSBuild:Compile
88 | Designer
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | LabeledSlider.xaml
98 |
99 |
100 | MSBuild:Compile
101 | Designer
102 |
103 |
104 | App.xaml
105 | Code
106 |
107 |
108 |
109 | ControlWindow.xaml
110 | Code
111 |
112 |
113 | Designer
114 | MSBuild:Compile
115 |
116 |
117 |
118 |
119 | Code
120 |
121 |
122 | True
123 | True
124 | Resources.resx
125 |
126 |
127 | True
128 | Settings.settings
129 | True
130 |
131 |
132 | ResXFileCodeGenerator
133 | Resources.Designer.cs
134 |
135 |
136 | Designer
137 |
138 |
139 | SettingsSingleFileGenerator
140 | Settings.Designer.cs
141 |
142 |
143 |
144 |
145 |
146 | Designer
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | {11fb8f50-ae40-42c2-ac82-7a8d84a7b76e}
158 | VRE.Vridge.API.Client
159 |
160 |
161 |
162 |
169 |
--------------------------------------------------------------------------------
/src/csharp/examples/VRE.Vridge.API.DesktopClient/View/ControlWindow.xaml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
44 |
45 |
46 |
47 |
53 |
60 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/csharp/VRE.Vridge.API.Client/Proxy/HeadTracking/HeadTrackingProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using NetMQ;
4 | using VRE.Vridge.API.Client.Helpers;
5 | using VRE.Vridge.API.Client.Messages.v3;
6 | using VRE.Vridge.API.Client.Messages.v3.HeadTracking.Requests;
7 | using VRE.Vridge.API.Client.Messages.v3.HeadTracking.Responses;
8 | using VRE.Vridge.API.Client.Remotes;
9 |
10 | namespace VRE.Vridge.API.Client.Proxy.HeadTracking
11 | {
12 | ///
13 | /// Lower level access method for sending head tracking data to VRidge. Consider using
14 | /// with for easier operation.
15 | ///
16 | public class HeadTrackingProxy : ClientProxyBasePB
17 | {
18 | private const int CurrentVersion = 3;
19 |
20 | public Action NewSyncDataAvailable;
21 | public event EventHandler SyncModeDisconnected;
22 |
23 | private bool isProvidingOffset;
24 | private Thread offsetThread;
25 |
26 | ///
27 | /// Creates head tracking proxy and establishes connection.
28 | ///
29 | ///
30 | /// Endpoint address (ip:port). Should be requested from control connection.
31 | ///
32 | ///
33 | /// True if automatic pings should keep connection alive even if caller doesn't send data.
34 | ///
35 | public HeadTrackingProxy(string endpointAddress, bool keepAlive = false) : base(endpointAddress, keepAlive) { }
36 |
37 | ///
38 | /// Sets position only and returns true if the value was accepted.
39 | ///
40 | public bool SetPosition(float x, float y, float z)
41 | {
42 | var request = HeadTrackingRequest.CreatePositionPacket(x, y, z);
43 | var reply = SendMessage(request);
44 |
45 | return reply.ReplyCode == (int) HeadTrackingResponse.Response.AcceptedYourData;
46 | }
47 |
48 | ///
49 | /// Sets position and rotation and returns true if the value was accepted.
50 | ///
51 | public bool SetRotationAndPosition(float yaw, float pitch, float roll, float x, float y, float z)
52 | {
53 | var request = HeadTrackingRequest.CreateRotationPositionVectorPacket(yaw, pitch, roll, x, y, z);
54 | var reply = SendMessage(request);
55 |
56 | return reply.ReplyCode == (int)HeadTrackingResponse.Response.AcceptedYourData;
57 | }
58 |
59 | ///
60 | /// Sets rotational offset that will be applied to each mobile pose. Use radians.
61 | ///
62 | public bool SetAsyncOffset(float yaw)
63 | {
64 | var request = HeadTrackingRequest.CreateAsyncOffsetPacket(yaw);
65 | var reply = SendMessage(request);
66 |
67 | return reply.ReplyCode == (byte)HeadTrackingResponse.Response.AcceptedYourData;
68 | }
69 |
70 | ///
71 | /// Clear async offset that was set with
72 | ///
73 | ///
74 | public bool ResetAsyncOffset()
75 | {
76 | var request = HeadTrackingRequest.CreateEmptyPacketByType(HeadTrackingRequest.Task.ResetYawOffset);
77 | var reply = SendMessage(request);
78 |
79 | return reply.ReplyCode == (byte) HeadTrackingResponse.Response.AcceptedYourData;
80 | }
81 |
82 | ///
83 | /// Sets current orientation as new center.
84 | ///
85 | public bool RecenterView()
86 | {
87 | var request = HeadTrackingRequest.CreateRecenterPacket();
88 | var reply = SendMessage(request);
89 |
90 | return reply.ReplyCode == (byte)HeadTrackingResponse.Response.AcceptedYourData;
91 | }
92 |
93 | ///
94 | /// Toggles HMD tracking state between "actively tracked" and "out of tracking range".
95 | ///
96 | public bool ChangeTrackingState(bool isCurrentlyBeingTracked)
97 | {
98 | var request =
99 | HeadTrackingRequest.CreateStateChangePacket(isCurrentlyBeingTracked
100 | ? TrackedDeviceStatus.Active
101 | : TrackedDeviceStatus.TempUnavailable);
102 |
103 | var reply = SendMessage(request);
104 |
105 | return reply.ReplyCode == (byte)HeadTrackingResponse.Response.AcceptedYourData;
106 | }
107 |
108 | ///
109 | /// Request latest phone pose matrix. You can use it for .
110 | /// This method will block until fresh data is received from mobile phone.
111 | ///
112 | ///
113 | /// 4x4 transformation matrix flattened as column-major array.
114 | ///
115 | public float[] GetCurrentPhonePose()
116 | {
117 | var request = HeadTrackingRequest.CreateEmptyPacketByType(HeadTrackingRequest.Task.RequestReadOnlyPhonePose);
118 | var reply = SendMessage(request);
119 |
120 | var replyData = new float[16];
121 |
122 | Array.Copy(reply.Data, 0, replyData, 0, 16);
123 | return replyData;
124 | }
125 |
126 | ///
127 | /// Begins listening to mobile phone tracking data. You callback method will be called with modifiable tracking data.
128 | /// For example, you can correct drift by mixing phone tracking data with yours in real time.
129 | ///
130 | ///
131 | /// Method that will be called with a reference to a column-major phone 4x4 pose matrix.
132 | /// You can modify the array but you need to do it fast to keep latency low.
133 | ///
134 | public void BeginSyncOffset(Action callback)
135 | {
136 | NewSyncDataAvailable = callback;
137 |
138 | isProvidingOffset = true;
139 | offsetThread = new Thread(SyncOffsetLoop)
140 | {
141 | IsBackground = true
142 | };
143 | offsetThread.Start();
144 | }
145 |
146 | ///
147 | /// Stops listening to mobile phone tracking data. Use it after you no longer
148 | /// need sync offset mode started by
149 | ///
150 | public void StopSyncOffset()
151 | {
152 | NewSyncDataAvailable = null;
153 |
154 | isProvidingOffset = false;
155 | if(offsetThread != null && offsetThread.IsAlive)
156 | offsetThread.Join();
157 | }
158 |
159 | ///
160 | /// Disconnected from head tracking API and frees the API for other clients.
161 | ///
162 | public void Disconnect()
163 | {
164 | isProvidingOffset = false;
165 |
166 | var disconnectRequest = new HeadTrackingRequest()
167 | {
168 | Version = CurrentVersion,
169 | TaskType = (byte) HeadTrackingRequest.Task.Disconnect,
170 | };
171 |
172 | try
173 | {
174 | SendMessage(disconnectRequest);
175 | }
176 | catch (TimeoutException x)
177 | {
178 | // Connection probably dropped another way, ignoring
179 | }
180 | catch (FiniteStateMachineException x)
181 | {
182 | // Connection state invalid, close anyway
183 | }
184 | CloseSocket();
185 | }
186 |
187 | private void SyncOffsetLoop()
188 | {
189 | HeadTrackingRequest reqModifiable = new HeadTrackingRequest()
190 | {
191 | Version = CurrentVersion,
192 | TaskType = (byte)HeadTrackingRequest.Task.RequestSyncOffset
193 | };
194 |
195 | try
196 | {
197 | var reqFrame = SerializationHelpers.ProtoSerialize(reqModifiable);
198 |
199 | while (isProvidingOffset)
200 | {
201 | // Get current data
202 | var response = SendRawFrame(reqFrame);
203 |
204 | if (response.ReplyCode == (int) HeadTrackingResponse.Response.PhoneDataTimeout)
205 | {
206 | throw new TimeoutException("Phone is not sending new data.");
207 | }
208 |
209 | var currentPhonePose = new float[16];
210 | Array.Copy(response.Data, currentPhonePose, 16);
211 |
212 | // Notify through callback so listeners can modify the array
213 | NewSyncDataAvailable?.Invoke(currentPhonePose);
214 |
215 | // Send updated data
216 | SendMessage(HeadTrackingRequest.CreateFullPoseMatrixPacket(currentPhonePose));
217 | }
218 | }
219 | catch (Exception x)
220 | {
221 | // Signal it callers if anyone is listening
222 | SyncModeDisconnected?.Invoke(this, x);
223 | Disconnect();
224 | }
225 | }
226 |
227 | private HeadTrackingResponse SendMessage(object obj) => SendMessage(obj);
228 |
229 |
230 | }
231 | }
232 |
--------------------------------------------------------------------------------