mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c49af7fb33 | ||
|
|
4f042de2f4 | ||
|
|
f3e2b2ca40 | ||
|
|
a690447391 | ||
|
|
01593352ab | ||
|
|
0e4618529d | ||
|
|
57c97cd5e1 | ||
|
|
8606c0daa3 | ||
|
|
e94551d4f7 | ||
|
|
ffcd4f32ed | ||
|
|
2248f577df | ||
|
|
8a57553986 | ||
|
|
bb01ce776b | ||
|
|
631870846c | ||
|
|
a45abb7992 | ||
|
|
c7aaffa5e6 | ||
|
|
7def0d0b4e | ||
|
|
c035135fb7 | ||
|
|
15ffdeeeb8 | ||
|
|
74f6902a1b | ||
|
|
b2ae71333a | ||
|
|
fc88269f2d | ||
|
|
a191fcf803 | ||
|
|
37b109bd73 | ||
|
|
27b2a77f48 | ||
|
|
0f34dd0967 | ||
|
|
10fc717500 | ||
|
|
250068c6c2 | ||
|
|
488838752b | ||
|
|
dd0f4deae3 | ||
|
|
2df4106c92 | ||
|
|
ed58076c68 | ||
|
|
a4b300198d | ||
|
|
6980023c5a | ||
|
|
9f4d956345 | ||
|
|
ce4a90dc55 | ||
|
|
82ba193bb4 | ||
|
|
a3a004536d | ||
|
|
bb1d7e06c2 | ||
|
|
3689e6723c | ||
|
|
ef504c40b6 | ||
|
|
5e4a128d25 | ||
|
|
67d93d87b5 |
@@ -26,8 +26,8 @@
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-11.0.1"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/Slime Java Commons"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/slime-java-commons"/>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
</classpath>
|
||||
|
||||
22
.github/workflows/gradle.yml
vendored
22
.github/workflows/gradle.yml
vendored
@@ -11,18 +11,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Clone Slime Java Commons
|
||||
uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
repository: Eirenliel/slime-java-commons
|
||||
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||
path: Slime Java Commons
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up JDK 8
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2.1.0
|
||||
with:
|
||||
java-version: '8'
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: 'gradle' # will restore cache of dependencies and wrappers
|
||||
|
||||
@@ -37,18 +32,13 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
|
||||
- name: Clone Slime Java Commons
|
||||
uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
repository: Eirenliel/slime-java-commons
|
||||
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||
path: Slime Java Commons
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up JDK 8
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2.1.0
|
||||
with:
|
||||
java-version: '8'
|
||||
java-version: '11'
|
||||
distribution: 'adopt'
|
||||
cache: 'gradle' # will restore cache of dependencies and wrappers
|
||||
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "slime-java-commons"]
|
||||
path = slime-java-commons
|
||||
url = https://github.com/Eirenliel/slime-java-commons.git
|
||||
@@ -21,8 +21,7 @@ You need to execute these commands in the folder where you want this project.
|
||||
|
||||
```bash
|
||||
# Clone repositories
|
||||
git clone https://github.com/SlimeVR/SlimeVR-Server.git
|
||||
git clone https://github.com/Eirenliel/slime-java-commons.git
|
||||
git clone --recursive https://github.com/SlimeVR/SlimeVR-Server.git
|
||||
|
||||
# Enter the directory and build the runnable server JAR
|
||||
cd SlimeVR-Server
|
||||
|
||||
18
build.gradle
18
build.gradle
@@ -34,15 +34,17 @@ tasks.withType(Javadoc) {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
allprojects {
|
||||
repositories {
|
||||
// Use jcenter for resolving dependencies.
|
||||
// You can declare any Maven/Ivy/file repository here.
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':Slime Java Commons')
|
||||
compile project(':slime-java-commons')
|
||||
|
||||
// This dependency is exported to consumers, that is to say found on their compile classpath.
|
||||
compile 'org.apache.commons:commons-math3:3.6.1'
|
||||
@@ -51,11 +53,13 @@ dependencies {
|
||||
compile 'net.java.dev.jna:jna-platform:5.6.0'
|
||||
compile 'com.illposed.osc:javaosc-core:0.8'
|
||||
compile 'com.fazecast:jSerialComm:[2.0.0,3.0.0)'
|
||||
compile 'com.google.protobuf:protobuf-java:3.17.3'
|
||||
compile "org.java-websocket:Java-WebSocket:1.5.1"
|
||||
compile 'com.melloware:jintellitype:1.4.0'
|
||||
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
implementation 'com.google.guava:guava:28.2-jre'
|
||||
|
||||
|
||||
// Use JUnit test framework
|
||||
testImplementation platform('org.junit:junit-bom:5.7.2')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
|
||||
1
protobuf_update.bat
Normal file
1
protobuf_update.bat
Normal file
@@ -0,0 +1 @@
|
||||
protoc --proto_path=../SlimeVR-OpenVR-Driver/src/bridge --java_out=./src/main/java ProtobufMessages.proto
|
||||
@@ -1,13 +1,17 @@
|
||||
@echo off
|
||||
echo Installing firewall rules...
|
||||
|
||||
rem Rotational data default port
|
||||
netsh advfirewall firewall add rule name="UDP 6969 incoming" dir=in action=allow protocol=UDP localport=6969
|
||||
netsh advfirewall firewall add rule name="UDP 6969 outgoing" dir=out action=allow protocol=UDP localport=6969
|
||||
rem Discovery defauly port
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 35903 incoming" dir=in action=allow protocol=UDP localport=35903
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 35903 outgoing" dir=out action=allow protocol=UDP localport=35903
|
||||
|
||||
rem Info server allowing automatic discovery
|
||||
netsh advfirewall firewall add rule name="UDP 35903 incoming" dir=in action=allow protocol=UDP localport=35903
|
||||
netsh advfirewall firewall add rule name="UDP 35903 outgoing" dir=out action=allow protocol=UDP localport=35903
|
||||
rem Rotational data default port
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 6969 incoming" dir=in action=allow protocol=UDP localport=6969
|
||||
netsh advfirewall firewall add rule name="SlimeVR UDP 6969 outgoing" dir=out action=allow protocol=UDP localport=6969
|
||||
|
||||
rem WebSocket server default port
|
||||
netsh advfirewall firewall add rule name="SlimeVR TCP 21110 incoming" dir=in action=allow protocol=TCP localport=21110
|
||||
netsh advfirewall firewall add rule name="SlimeVR TCP 21110 outgoing" dir=out action=allow protocol=TCP localport=21110
|
||||
|
||||
echo Done!
|
||||
pause
|
||||
17
resources/firewall_uninstall.bat
Normal file
17
resources/firewall_uninstall.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
echo Installing firewall rules...
|
||||
|
||||
rem Discovery defauly port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 35903 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 35903 outgoing"
|
||||
|
||||
rem Rotational data default port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 6969 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR UDP 6969 outgoing"
|
||||
|
||||
rem WebSocket server default port
|
||||
netsh advfirewall firewall delete rule name="SlimeVR TCP 21110 incoming"
|
||||
netsh advfirewall firewall delete rule name="SlimeVR TCP 21110 outgoing"
|
||||
|
||||
echo Done!
|
||||
pause
|
||||
@@ -8,19 +8,4 @@
|
||||
*/
|
||||
|
||||
rootProject.name = 'SlimeVR Server'
|
||||
include('Slime Java Commons')
|
||||
|
||||
def commonsDirs = [
|
||||
new File(settingsDir, 'Slime Java Commons'),
|
||||
new File(settingsDir, 'slime-java-commons'),
|
||||
new File(settingsDir, '../Slime Java Commons'),
|
||||
new File(settingsDir, '../slime-java-commons')
|
||||
]
|
||||
|
||||
for (commonsDir in commonsDirs) {
|
||||
if (commonsDir.isDirectory()) {
|
||||
logger.info('\"Slime Java Commons\" subproject detected at \"{}\"', commonsDir.getCanonicalPath())
|
||||
project(':Slime Java Commons').projectDir = commonsDir
|
||||
break
|
||||
}
|
||||
}
|
||||
include ':slime-java-commons'
|
||||
|
||||
1
slime-java-commons
Submodule
1
slime-java-commons
Submodule
Submodule slime-java-commons added at 35f5a78c20
@@ -17,7 +17,7 @@ import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.processor.HumanSkeleton;
|
||||
import io.eiren.vr.processor.HumanSkeletonWithLegs;
|
||||
import io.eiren.vr.processor.HumanSkeletonWithWaist;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerUtils;
|
||||
|
||||
public class AutoBone {
|
||||
@@ -93,7 +93,7 @@ public class AutoBone {
|
||||
staticConfigs.put("Neck", server.config.getFloat("body.neckLength", HumanSkeletonWithWaist.NECK_LENGTH_DEFAULT));
|
||||
configs.put("Waist", server.config.getFloat("body.waistDistance", 0.85f));
|
||||
|
||||
if(server.config.getBoolean("autobone.forceChestTracker", false) || (frame != null && TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.CHEST) != null) || TrackerUtils.findTrackerForBodyPosition(server.getAllTrackers(), TrackerBodyPosition.CHEST) != null) {
|
||||
if(server.config.getBoolean("autobone.forceChestTracker", false) || (frame != null && TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.CHEST) != null) || TrackerUtils.findTrackerForBodyPosition(server.getAllTrackers(), TrackerPosition.CHEST) != null) {
|
||||
// If force enabled or has a chest tracker
|
||||
configs.put("Chest", server.config.getFloat("body.chestDistance", 0.42f));
|
||||
} else {
|
||||
@@ -201,7 +201,7 @@ public class AutoBone {
|
||||
public float getMaxHmdHeight(PoseFrame frames) {
|
||||
float maxHeight = 0f;
|
||||
for(TrackerFrame[] frame : frames) {
|
||||
TrackerFrame hmd = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.HMD);
|
||||
TrackerFrame hmd = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.HMD);
|
||||
if(hmd != null && hmd.hasData(TrackerFrameData.POSITION) && hmd.position.y > maxHeight) {
|
||||
maxHeight = hmd.position.y;
|
||||
}
|
||||
@@ -361,8 +361,8 @@ public class AutoBone {
|
||||
|
||||
// The change in position of the ankle over time
|
||||
protected float getSlideErrorDeriv(SimpleSkeleton skeleton1, SimpleSkeleton skeleton2) {
|
||||
float slideLeft = skeleton1.getNodePosition(TrackerBodyPosition.LEFT_ANKLE).distance(skeleton2.getNodePosition(TrackerBodyPosition.LEFT_ANKLE));
|
||||
float slideRight = skeleton1.getNodePosition(TrackerBodyPosition.RIGHT_ANKLE).distance(skeleton2.getNodePosition(TrackerBodyPosition.RIGHT_ANKLE));
|
||||
float slideLeft = skeleton1.getNodePosition(TrackerPosition.LEFT_ANKLE).distance(skeleton2.getNodePosition(TrackerPosition.LEFT_ANKLE));
|
||||
float slideRight = skeleton1.getNodePosition(TrackerPosition.RIGHT_ANKLE).distance(skeleton2.getNodePosition(TrackerPosition.RIGHT_ANKLE));
|
||||
|
||||
// Divide by 4 to halve and average, it's halved because you want to approach a midpoint, not the other point
|
||||
return (slideLeft + slideRight) / 4f;
|
||||
@@ -370,11 +370,11 @@ public class AutoBone {
|
||||
|
||||
// The offset between both feet at one instant and over time
|
||||
protected float getOffsetErrorDeriv(SimpleSkeleton skeleton1, SimpleSkeleton skeleton2) {
|
||||
float skeleton1Left = skeleton1.getNodePosition(TrackerBodyPosition.LEFT_ANKLE).getY();
|
||||
float skeleton1Right = skeleton1.getNodePosition(TrackerBodyPosition.RIGHT_ANKLE).getY();
|
||||
float skeleton1Left = skeleton1.getNodePosition(TrackerPosition.LEFT_ANKLE).getY();
|
||||
float skeleton1Right = skeleton1.getNodePosition(TrackerPosition.RIGHT_ANKLE).getY();
|
||||
|
||||
float skeleton2Left = skeleton2.getNodePosition(TrackerBodyPosition.LEFT_ANKLE).getY();
|
||||
float skeleton2Right = skeleton2.getNodePosition(TrackerBodyPosition.RIGHT_ANKLE).getY();
|
||||
float skeleton2Left = skeleton2.getNodePosition(TrackerPosition.LEFT_ANKLE).getY();
|
||||
float skeleton2Right = skeleton2.getNodePosition(TrackerPosition.RIGHT_ANKLE).getY();
|
||||
|
||||
float dist1 = Math.abs(skeleton1Left - skeleton1Right);
|
||||
float dist2 = Math.abs(skeleton2Left - skeleton2Right);
|
||||
|
||||
@@ -10,8 +10,8 @@ import dev.slimevr.poserecorder.TrackerFrame;
|
||||
import dev.slimevr.poserecorder.TrackerFrameData;
|
||||
import io.eiren.vr.processor.HumanSkeletonWithLegs;
|
||||
import io.eiren.vr.processor.HumanSkeletonWithWaist;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.processor.TransformNode;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerUtils;
|
||||
import io.eiren.yaml.YamlFile;
|
||||
|
||||
@@ -121,7 +121,7 @@ public class SimpleSkeleton {
|
||||
|
||||
public void setPoseFromFrame(TrackerFrame[] frame) {
|
||||
|
||||
TrackerFrame hmd = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.HMD);
|
||||
TrackerFrame hmd = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.HMD);
|
||||
|
||||
if(hmd != null) {
|
||||
if(hmd.hasData(TrackerFrameData.ROTATION)) {
|
||||
@@ -134,24 +134,24 @@ public class SimpleSkeleton {
|
||||
}
|
||||
}
|
||||
|
||||
TrackerFrame chest = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.CHEST, TrackerBodyPosition.WAIST);
|
||||
TrackerFrame chest = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.CHEST, TrackerPosition.WAIST);
|
||||
setRotation(chest, neckNode);
|
||||
|
||||
TrackerFrame waist = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.WAIST, TrackerBodyPosition.CHEST);
|
||||
TrackerFrame waist = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.WAIST, TrackerPosition.CHEST);
|
||||
setRotation(waist, chestNode);
|
||||
|
||||
TrackerFrame leftLeg = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.LEFT_LEG);
|
||||
TrackerFrame rightLeg = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.RIGHT_LEG);
|
||||
TrackerFrame leftLeg = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.LEFT_LEG);
|
||||
TrackerFrame rightLeg = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.RIGHT_LEG);
|
||||
|
||||
averagePelvis(waist, leftLeg, rightLeg);
|
||||
|
||||
setRotation(leftLeg, leftHipNode);
|
||||
setRotation(rightLeg, rightHipNode);
|
||||
|
||||
TrackerFrame leftAnkle = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.LEFT_ANKLE);
|
||||
TrackerFrame leftAnkle = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.LEFT_ANKLE);
|
||||
setRotation(leftAnkle, rightKneeNode);
|
||||
|
||||
TrackerFrame rightAnkle = TrackerUtils.findTrackerForBodyPosition(frame, TrackerBodyPosition.RIGHT_ANKLE);
|
||||
TrackerFrame rightAnkle = TrackerUtils.findTrackerForBodyPosition(frame, TrackerPosition.RIGHT_ANKLE);
|
||||
setRotation(rightAnkle, leftKneeNode);
|
||||
|
||||
updatePose();
|
||||
@@ -292,11 +292,11 @@ public class SimpleSkeleton {
|
||||
return nodes.get(node);
|
||||
}
|
||||
|
||||
public TransformNode getNode(TrackerBodyPosition bodyPosition) {
|
||||
public TransformNode getNode(TrackerPosition bodyPosition) {
|
||||
return getNode(bodyPosition, false);
|
||||
}
|
||||
|
||||
public TransformNode getNode(TrackerBodyPosition bodyPosition, boolean rotationNode) {
|
||||
public TransformNode getNode(TrackerPosition bodyPosition, boolean rotationNode) {
|
||||
if(bodyPosition == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -328,7 +328,7 @@ public class SimpleSkeleton {
|
||||
return transformNode != null ? transformNode.worldTransform.getTranslation() : null;
|
||||
}
|
||||
|
||||
public Vector3f getNodePosition(TrackerBodyPosition bodyPosition) {
|
||||
public Vector3f getNodePosition(TrackerPosition bodyPosition) {
|
||||
TransformNode node = getNode(bodyPosition);
|
||||
if(node == null) {
|
||||
return null;
|
||||
|
||||
43
src/main/java/dev/slimevr/bridge/Bridge.java
Normal file
43
src/main/java/dev/slimevr/bridge/Bridge.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
|
||||
/**
|
||||
* Bridge handles sending and recieving tracker data
|
||||
* between SlimeVR and other systems like VR APIs (SteamVR, OpenXR, etc),
|
||||
* apps and protocols (VMC, WebSocket, TIP). It can create and manage
|
||||
* tracker recieved from the <b>remote side</b> or send shared <b>local
|
||||
* trackers</b> to the other side.
|
||||
*/
|
||||
public interface Bridge {
|
||||
|
||||
@VRServerThread
|
||||
public void dataRead();
|
||||
|
||||
@VRServerThread
|
||||
public void dataWrite();
|
||||
|
||||
/**
|
||||
* Adds shared tracker to the bridge. Bridge should notify the
|
||||
* other side of this tracker, if it's the type of tracker
|
||||
* this bridge serves, and start sending data each update
|
||||
* @param tracker
|
||||
*/
|
||||
@VRServerThread
|
||||
public void addSharedTracker(ShareableTracker tracker);
|
||||
|
||||
/**
|
||||
* Removes tracker from a bridge. If the other side supports
|
||||
* tracker removal, bridge should notify it and stop sending
|
||||
* new data. If it doesn't support tracker removal, the bridge
|
||||
* can either stop sending new data, or keep sending it if it's
|
||||
* available.
|
||||
* @param tracker
|
||||
*/
|
||||
@VRServerThread
|
||||
public void removeSharedTracker(ShareableTracker tracker);
|
||||
|
||||
@VRServerThread
|
||||
public void startBridge();
|
||||
}
|
||||
9
src/main/java/dev/slimevr/bridge/BridgeThread.java
Normal file
9
src/main/java/dev/slimevr/bridge/BridgeThread.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(value = RetentionPolicy.SOURCE)
|
||||
public @interface BridgeThread {
|
||||
|
||||
}
|
||||
224
src/main/java/dev/slimevr/bridge/NamedPipeBridge.java
Normal file
224
src/main/java/dev/slimevr/bridge/NamedPipeBridge.java
Normal file
@@ -0,0 +1,224 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.protobuf.CodedOutputStream;
|
||||
import com.sun.jna.platform.win32.Kernel32;
|
||||
import com.sun.jna.platform.win32.WinBase;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
import dev.slimevr.bridge.Pipe.PipeState;
|
||||
import dev.slimevr.bridge.ProtobufMessages.ProtobufMessage;
|
||||
import dev.slimevr.bridge.ProtobufMessages.TrackerAdded;
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import io.eiren.vr.Main;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
import io.eiren.vr.trackers.VRTracker;
|
||||
|
||||
public class NamedPipeBridge extends ProtobufBridge<VRTracker> implements Runnable {
|
||||
|
||||
private final TrackerRole[] defaultRoles = new TrackerRole[] {TrackerRole.WAIST, TrackerRole.LEFT_FOOT, TrackerRole.RIGHT_FOOT};
|
||||
|
||||
private final byte[] buffArray = new byte[2048];
|
||||
|
||||
protected Pipe pipe;
|
||||
protected final String pipeName;
|
||||
protected final String bridgeSettingsKey;
|
||||
protected final Thread runnerThread;
|
||||
private final List<? extends ShareableTracker> shareableTrackers;
|
||||
|
||||
public NamedPipeBridge(HMDTracker hmd, String bridgeSettingsKey, String bridgeName, String pipeName, List<? extends ShareableTracker> shareableTrackers) {
|
||||
super(bridgeName, hmd);
|
||||
this.pipeName = pipeName;
|
||||
this.bridgeSettingsKey = bridgeSettingsKey;
|
||||
this.runnerThread = new Thread(this, "Named pipe thread");
|
||||
this.shareableTrackers = shareableTrackers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void startBridge() {
|
||||
for(TrackerRole role : defaultRoles) {
|
||||
changeShareSettings(role, Main.vrServer.config.getBoolean("bridge." + bridgeSettingsKey + ".trackers." + role.name().toLowerCase(), true));
|
||||
}
|
||||
for(int i = 0; i < shareableTrackers.size(); ++i) {
|
||||
ShareableTracker tr = shareableTrackers.get(i);
|
||||
TrackerRole role = tr.getTrackerRole();
|
||||
changeShareSettings(role, Main.vrServer.config.getBoolean("bridge." + bridgeSettingsKey + ".trackers." + role.name().toLowerCase(), false));
|
||||
}
|
||||
runnerThread.start();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public boolean getShareSetting(TrackerRole role) {
|
||||
for(int i = 0; i < shareableTrackers.size(); ++i) {
|
||||
ShareableTracker tr = shareableTrackers.get(i);
|
||||
if(tr.getTrackerRole() == role) {
|
||||
return sharedTrackers.contains(tr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void changeShareSettings(TrackerRole role, boolean share) {
|
||||
if(role == null)
|
||||
return;
|
||||
for(int i = 0; i < shareableTrackers.size(); ++i) {
|
||||
ShareableTracker tr = shareableTrackers.get(i);
|
||||
if(tr.getTrackerRole() == role) {
|
||||
if(share) {
|
||||
addSharedTracker(tr);
|
||||
} else {
|
||||
removeSharedTracker(tr);
|
||||
}
|
||||
Main.vrServer.config.setProperty("bridge." + bridgeSettingsKey + ".trackers." + role.name().toLowerCase(), share);
|
||||
Main.vrServer.saveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@VRServerThread
|
||||
protected VRTracker createNewTracker(TrackerAdded trackerAdded) {
|
||||
VRTracker tracker = new VRTracker(trackerAdded.getTrackerId(), trackerAdded.getTrackerSerial(), trackerAdded.getTrackerName(), true, true);
|
||||
TrackerRole role = TrackerRole.getById(trackerAdded.getTrackerRole());
|
||||
if(role != null) {
|
||||
tracker.setBodyPosition(TrackerPosition.getByRole(role));
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
@BridgeThread
|
||||
public void run() {
|
||||
try {
|
||||
createPipe();
|
||||
while(true) {
|
||||
boolean pipesUpdated = false;
|
||||
if(pipe.state == PipeState.CREATED) {
|
||||
tryOpeningPipe(pipe);
|
||||
}
|
||||
if(pipe.state == PipeState.OPEN) {
|
||||
pipesUpdated = updatePipe();
|
||||
updateMessageQueue();
|
||||
}
|
||||
if(pipe.state == PipeState.ERROR) {
|
||||
resetPipe();
|
||||
}
|
||||
if(!pipesUpdated) {
|
||||
try {
|
||||
Thread.sleep(5); // Up to 200Hz
|
||||
} catch(InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@BridgeThread
|
||||
protected boolean sendMessageReal(ProtobufMessage message) {
|
||||
if(pipe.state == PipeState.OPEN) {
|
||||
try {
|
||||
int size = message.getSerializedSize();
|
||||
CodedOutputStream os = CodedOutputStream.newInstance(buffArray, 4, size);
|
||||
message.writeTo(os);
|
||||
size += 4;
|
||||
buffArray[0] = (byte) (size & 0xFF);
|
||||
buffArray[1] = (byte) ((size >> 8) & 0xFF);
|
||||
buffArray[2] = (byte) ((size >> 16) & 0xFF);
|
||||
buffArray[3] = (byte) ((size >> 24) & 0xFF);
|
||||
if(Kernel32.INSTANCE.WriteFile(pipe.pipeHandle, buffArray, size, null, null)) {
|
||||
return true;
|
||||
}
|
||||
pipe.state = PipeState.ERROR;
|
||||
LogManager.log.severe("[" + bridgeName + "] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean updatePipe() throws IOException {
|
||||
if(pipe.state == PipeState.OPEN) {
|
||||
boolean readAnything = false;
|
||||
IntByReference bytesAvailable = new IntByReference(0);
|
||||
while(Kernel32.INSTANCE.PeekNamedPipe(pipe.pipeHandle, buffArray, 4, null, bytesAvailable, null)) {
|
||||
if(bytesAvailable.getValue() >= 4) { // Got size
|
||||
int messageLength = (buffArray[3] << 24) | (buffArray[2] << 16) | (buffArray[1] << 8) | buffArray[0];
|
||||
if(messageLength > 1024) { // Overflow
|
||||
LogManager.log.severe("[" + bridgeName + "] Pipe overflow. Message length: " + messageLength);
|
||||
pipe.state = PipeState.ERROR;
|
||||
return readAnything;
|
||||
}
|
||||
if(bytesAvailable.getValue() >= messageLength) {
|
||||
if(Kernel32.INSTANCE.ReadFile(pipe.pipeHandle, buffArray, messageLength, bytesAvailable, null)) {
|
||||
ProtobufMessage message = ProtobufMessage.parser().parseFrom(buffArray, 4, messageLength - 4);
|
||||
messageRecieved(message);
|
||||
readAnything = true;
|
||||
} else {
|
||||
pipe.state = PipeState.ERROR;
|
||||
LogManager.log.severe("[" + bridgeName + "] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
return readAnything;
|
||||
}
|
||||
} else {
|
||||
return readAnything; // Wait for more data
|
||||
}
|
||||
} else {
|
||||
return readAnything; // Wait for more data
|
||||
}
|
||||
}
|
||||
pipe.state = PipeState.ERROR;
|
||||
LogManager.log.severe("[" + bridgeName + "] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void resetPipe() {
|
||||
Pipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
|
||||
private void createPipe() throws IOException {
|
||||
try {
|
||||
pipe = new Pipe(Kernel32.INSTANCE.CreateNamedPipe(pipeName, WinBase.PIPE_ACCESS_DUPLEX, // dwOpenMode
|
||||
WinBase.PIPE_TYPE_BYTE | WinBase.PIPE_READMODE_BYTE | WinBase.PIPE_WAIT, // dwPipeMode
|
||||
1, // nMaxInstances,
|
||||
1024 * 16, // nOutBufferSize,
|
||||
1024 * 16, // nInBufferSize,
|
||||
0, // nDefaultTimeOut,
|
||||
null), pipeName); // lpSecurityAttributes
|
||||
LogManager.log.info("[" + bridgeName + "] Pipe " + pipe.name + " created");
|
||||
if(WinBase.INVALID_HANDLE_VALUE.equals(pipe.pipeHandle))
|
||||
throw new IOException("Can't open " + pipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
LogManager.log.info("[" + bridgeName + "] Pipes are created");
|
||||
} catch(IOException e) {
|
||||
Pipe.safeDisconnect(pipe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryOpeningPipe(Pipe pipe) {
|
||||
if(Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null) || Kernel32.INSTANCE.GetLastError() == WinError.ERROR_PIPE_CONNECTED) {
|
||||
pipe.state = PipeState.OPEN;
|
||||
LogManager.log.info("[" + bridgeName + "] Pipe " + pipe.name + " is open");
|
||||
Main.vrServer.queueTask(this::reconnected);
|
||||
return true;
|
||||
}
|
||||
LogManager.log.info("[" + bridgeName + "] Error connecting to pipe " + pipe.name + ": " + Kernel32.INSTANCE.GetLastError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.vr.bridge;
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -12,15 +12,17 @@ import com.sun.jna.platform.win32.WinBase;
|
||||
import com.sun.jna.platform.win32.WinNT.HANDLE;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
import dev.slimevr.bridge.Pipe.PipeState;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public class NamedPipeVRBridge extends Thread implements VRBridge {
|
||||
public class NamedPipeVRBridge extends Thread implements Bridge {
|
||||
|
||||
private static final int MAX_COMMAND_LENGTH = 2048;
|
||||
public static final String HMDPipeName = "\\\\.\\pipe\\HMDPipe";
|
||||
@@ -52,7 +54,7 @@ public class NamedPipeVRBridge extends Thread implements VRBridge {
|
||||
this.internalTrackers = new FastList<>(shareTrackers.size());
|
||||
for(int i = 0; i < shareTrackers.size(); ++i) {
|
||||
Tracker t = shareTrackers.get(i);
|
||||
ComputedTracker ct = new ComputedTracker("internal://" + t.getName(), true, true);
|
||||
ComputedTracker ct = new ComputedTracker(t.getTrackerId(), "internal://" + t.getName(), true, true);
|
||||
ct.setStatus(TrackerStatus.OK);
|
||||
this.internalTrackers.add(ct);
|
||||
}
|
||||
@@ -268,4 +270,21 @@ public class NamedPipeVRBridge extends Thread implements VRBridge {
|
||||
} catch(Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
}
|
||||
30
src/main/java/dev/slimevr/bridge/Pipe.java
Normal file
30
src/main/java/dev/slimevr/bridge/Pipe.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import com.sun.jna.platform.win32.Kernel32;
|
||||
import com.sun.jna.platform.win32.WinNT.HANDLE;
|
||||
|
||||
public class Pipe {
|
||||
|
||||
public final String name;
|
||||
public final HANDLE pipeHandle;
|
||||
public PipeState state = PipeState.CREATED;
|
||||
|
||||
public Pipe(HANDLE pipeHandle, String name) {
|
||||
this.pipeHandle = pipeHandle;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static void safeDisconnect(Pipe pipe) {
|
||||
try {
|
||||
if(pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch(Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
enum PipeState {
|
||||
CREATED,
|
||||
OPEN,
|
||||
ERROR;
|
||||
}
|
||||
}
|
||||
241
src/main/java/dev/slimevr/bridge/ProtobufBridge.java
Normal file
241
src/main/java/dev/slimevr/bridge/ProtobufBridge.java
Normal file
@@ -0,0 +1,241 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import dev.slimevr.bridge.ProtobufMessages.Position;
|
||||
import dev.slimevr.bridge.ProtobufMessages.ProtobufMessage;
|
||||
import dev.slimevr.bridge.ProtobufMessages.TrackerAdded;
|
||||
import dev.slimevr.bridge.ProtobufMessages.TrackerStatus;
|
||||
import dev.slimevr.bridge.ProtobufMessages.UserAction;
|
||||
import io.eiren.util.ann.Synchronize;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.vr.Main;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
import io.eiren.vr.trackers.VRTracker;
|
||||
|
||||
public abstract class ProtobufBridge<T extends VRTracker> implements Bridge {
|
||||
|
||||
private final Vector3f vec1 = new Vector3f();
|
||||
private final Quaternion quat1 = new Quaternion();
|
||||
|
||||
@ThreadSafe
|
||||
private final Queue<ProtobufMessage> inputQueue = new LinkedBlockingQueue<>();
|
||||
@ThreadSafe
|
||||
private final Queue<ProtobufMessage> outputQueue = new LinkedBlockingQueue<>();
|
||||
@VRServerThread
|
||||
protected final List<ShareableTracker> sharedTrackers = new FastList<>();
|
||||
@Synchronize("self")
|
||||
private final Map<String, T> remoteTrackersBySerial = new HashMap<>();
|
||||
@Synchronize("self")
|
||||
private final Map<Integer, T> remoteTrackersByTrackerId = new HashMap<>();
|
||||
|
||||
private boolean hadNewData = false;
|
||||
|
||||
private T hmdTracker;
|
||||
private final HMDTracker hmd;
|
||||
protected final String bridgeName;
|
||||
|
||||
public ProtobufBridge(String bridgeName, HMDTracker hmd) {
|
||||
this.bridgeName = bridgeName;
|
||||
this.hmd = hmd;
|
||||
}
|
||||
|
||||
@BridgeThread
|
||||
protected abstract boolean sendMessageReal(ProtobufMessage message);
|
||||
|
||||
@BridgeThread
|
||||
protected void messageRecieved(ProtobufMessage message) {
|
||||
inputQueue.add(message);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
protected void sendMessage(ProtobufMessage message) {
|
||||
outputQueue.add(message);
|
||||
}
|
||||
|
||||
@BridgeThread
|
||||
protected void updateMessageQueue() {
|
||||
ProtobufMessage message = null;
|
||||
while((message = outputQueue.poll()) != null) {
|
||||
if(!sendMessageReal(message))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void dataRead() {
|
||||
hadNewData = false;
|
||||
ProtobufMessage message = null;
|
||||
while((message = inputQueue.poll()) != null) {
|
||||
processMessageRecieved(message);
|
||||
hadNewData = true;
|
||||
}
|
||||
if(hadNewData && hmdTracker != null) {
|
||||
trackerOverrideUpdate(hmdTracker, hmd);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void trackerOverrideUpdate(T source, ComputedTracker target) {
|
||||
target.position.set(source.position);
|
||||
target.rotation.set(source.rotation);
|
||||
target.setStatus(source.getStatus());
|
||||
target.dataTick();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
if(!hadNewData) // Don't write anything if no message were recieved, we always process at the speed of the other side
|
||||
return;
|
||||
for(int i = 0; i < sharedTrackers.size(); ++i) {
|
||||
writeTrackerUpdate(sharedTrackers.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void writeTrackerUpdate(ShareableTracker localTracker) {
|
||||
Position.Builder builder = Position.newBuilder().setTrackerId(localTracker.getTrackerId());
|
||||
if(localTracker.getPosition(vec1)) {
|
||||
builder.setX(vec1.x);
|
||||
builder.setY(vec1.y);
|
||||
builder.setZ(vec1.z);
|
||||
}
|
||||
if(localTracker.getRotation(quat1)) {
|
||||
builder.setQx(quat1.getX());
|
||||
builder.setQy(quat1.getY());
|
||||
builder.setQz(quat1.getZ());
|
||||
builder.setQw(quat1.getW());
|
||||
}
|
||||
sendMessage(ProtobufMessage.newBuilder().setPosition(builder).build());
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void processMessageRecieved(ProtobufMessage message) {
|
||||
//if(!message.hasPosition())
|
||||
// LogManager.log.info("[" + bridgeName + "] MSG: " + message);
|
||||
if(message.hasPosition()) {
|
||||
positionRecieved(message.getPosition());
|
||||
} else if(message.hasUserAction()) {
|
||||
userActionRecieved(message.getUserAction());
|
||||
} else if(message.hasTrackerStatus()) {
|
||||
trackerStatusRecieved(message.getTrackerStatus());
|
||||
} else if(message.hasTrackerAdded()) {
|
||||
trackerAddedRecieved(message.getTrackerAdded());
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void positionRecieved(Position positionMessage) {
|
||||
T tracker = getInternalRemoteTrackerById(positionMessage.getTrackerId());
|
||||
if(tracker != null) {
|
||||
if(positionMessage.hasX())
|
||||
tracker.position.set(positionMessage.getX(), positionMessage.getY(), positionMessage.getZ());
|
||||
tracker.rotation.set(positionMessage.getQx(), positionMessage.getQy(), positionMessage.getQz(), positionMessage.getQw());
|
||||
tracker.dataTick();
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected abstract T createNewTracker(TrackerAdded trackerAdded);
|
||||
|
||||
@VRServerThread
|
||||
protected void trackerAddedRecieved(TrackerAdded trackerAdded) {
|
||||
T tracker = getInternalRemoteTrackerById(trackerAdded.getTrackerId());
|
||||
if(tracker != null) {
|
||||
// TODO reinit?
|
||||
return;
|
||||
}
|
||||
tracker = createNewTracker(trackerAdded);
|
||||
synchronized(remoteTrackersBySerial) {
|
||||
remoteTrackersBySerial.put(tracker.getName(), tracker);
|
||||
}
|
||||
synchronized(remoteTrackersByTrackerId) {
|
||||
remoteTrackersByTrackerId.put(tracker.getTrackerId(), tracker);
|
||||
}
|
||||
if(trackerAdded.getTrackerRole() == TrackerRole.HMD.id) {
|
||||
hmdTracker = tracker;
|
||||
} else {
|
||||
Main.vrServer.registerTracker(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void userActionRecieved(UserAction userAction) {
|
||||
switch(userAction.getName()) {
|
||||
case "calibrate":
|
||||
// TODO : Check pose field
|
||||
Main.vrServer.resetTrackers();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void trackerStatusRecieved(TrackerStatus trackerStatus) {
|
||||
T tracker = getInternalRemoteTrackerById(trackerStatus.getTrackerId());
|
||||
if(tracker != null) {
|
||||
tracker.setStatus(io.eiren.vr.trackers.TrackerStatus.getById(trackerStatus.getStatusValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
protected T getInternalRemoteTrackerById(int trackerId) {
|
||||
synchronized(remoteTrackersByTrackerId) {
|
||||
return remoteTrackersByTrackerId.get(trackerId);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void reconnected() {
|
||||
for(int i = 0; i < sharedTrackers.size(); ++i) {
|
||||
ShareableTracker tracker = sharedTrackers.get(i);
|
||||
TrackerAdded.Builder builder = TrackerAdded.newBuilder().setTrackerId(tracker.getTrackerId()).setTrackerName(tracker.getDescriptiveName()).setTrackerSerial(tracker.getName()).setTrackerRole(tracker.getTrackerRole().id);
|
||||
sendMessage(ProtobufMessage.newBuilder().setTrackerAdded(builder).build());
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void disconnected() {
|
||||
synchronized(remoteTrackersByTrackerId) {
|
||||
Iterator<Entry<Integer, T>> iterator = remoteTrackersByTrackerId.entrySet().iterator();
|
||||
while(iterator.hasNext()) {
|
||||
iterator.next().getValue().setStatus(io.eiren.vr.trackers.TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
if(hmdTracker != null) {
|
||||
hmd.setStatus(io.eiren.vr.trackers.TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
if(sharedTrackers.contains(tracker))
|
||||
return;
|
||||
sharedTrackers.add(tracker);
|
||||
TrackerAdded.Builder builder = TrackerAdded.newBuilder().setTrackerId(tracker.getTrackerId()).setTrackerName(tracker.getDescriptiveName()).setTrackerSerial(tracker.getName()).setTrackerRole(tracker.getTrackerRole().id);
|
||||
sendMessage(ProtobufMessage.newBuilder().setTrackerAdded(builder).build());
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
sharedTrackers.remove(tracker);
|
||||
// No message can be sent to the remote side, protocol doesn't support tracker removal (yet)
|
||||
}
|
||||
}
|
||||
6409
src/main/java/dev/slimevr/bridge/ProtobufMessages.java
Normal file
6409
src/main/java/dev/slimevr/bridge/ProtobufMessages.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
package io.eiren.vr.bridge;
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
@@ -13,16 +13,19 @@ import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.sun.jna.platform.win32.Kernel32;
|
||||
import com.sun.jna.platform.win32.WinBase;
|
||||
import com.sun.jna.platform.win32.WinError;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
|
||||
import dev.slimevr.bridge.Pipe.PipeState;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.SteamVRTracker;
|
||||
import io.eiren.vr.trackers.VRTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
public class SteamVRPipeInputBridge extends Thread implements Bridge {
|
||||
|
||||
private static final int MAX_COMMAND_LENGTH = 2048;
|
||||
public static final String PipeName = "\\\\.\\pipe\\SlimeVRInput";
|
||||
@@ -30,8 +33,8 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
private final byte[] buffArray = new byte[1024];
|
||||
private final VRServer server;
|
||||
private final StringBuilder commandBuilder = new StringBuilder(1024);
|
||||
private final List<SteamVRTracker> trackers = new FastList<>();
|
||||
private final Map<Integer, SteamVRTracker> trackersInternal = new HashMap<>();
|
||||
private final List<VRTracker> trackers = new FastList<>();
|
||||
private final Map<Integer, VRTracker> trackersInternal = new HashMap<>();
|
||||
private AtomicBoolean newData = new AtomicBoolean(false);
|
||||
private final Vector3f vBuffer = new Vector3f();
|
||||
private final Quaternion qBuffer = new Quaternion();
|
||||
@@ -46,14 +49,22 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
try {
|
||||
createPipes();
|
||||
while(true) {
|
||||
waitForPipesToOpen();
|
||||
if(areAllPipesOpen()) {
|
||||
boolean pipesUpdated = updatePipes(); // Update at HMDs frequency
|
||||
if(!pipesUpdated) {
|
||||
boolean pipesUpdated = false;
|
||||
if(pipe.state == PipeState.CREATED) {
|
||||
tryOpeningPipe(pipe);
|
||||
}
|
||||
if(pipe.state == PipeState.OPEN) {
|
||||
pipesUpdated = updatePipes();
|
||||
}
|
||||
if(pipe.state == PipeState.ERROR) {
|
||||
resetPipe();
|
||||
}
|
||||
if(!pipesUpdated) {
|
||||
try {
|
||||
Thread.sleep(5); // Up to 200Hz
|
||||
} catch(InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
@@ -61,12 +72,6 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForPipesToOpen() {
|
||||
if(pipe.state == PipeState.CREATED) {
|
||||
tryOpeningPipe(pipe);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updatePipes() throws IOException {
|
||||
if(pipe.state == PipeState.OPEN) {
|
||||
IntByReference bytesAvailable = new IntByReference(0);
|
||||
@@ -88,11 +93,15 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
}
|
||||
}
|
||||
if(bytesRead < buffArray.length)
|
||||
break; // Don't repeat, we read all available bytes
|
||||
return true; // All pipe data read
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false; // Pipe was empty, it's okay
|
||||
}
|
||||
}
|
||||
// PeekNamedPipe or ReadFile returned an error
|
||||
pipe.state = PipeState.ERROR;
|
||||
LogManager.log.severe("[SteamVRPipeInputBridge] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -105,15 +114,15 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
LogManager.log.severe("[SteamVRPipeInputBridge] Error in ADD command. Command requires at least 4 arguments. Supplied: " + commandBuilder.toString());
|
||||
return;
|
||||
}
|
||||
SteamVRTracker internalTracker = new SteamVRTracker(Integer.parseInt(command[1]), StringUtils.join(command, " ", 3, command.length), true, true);
|
||||
VRTracker internalTracker = new VRTracker(Integer.parseInt(command[1]), StringUtils.join(command, " ", 3, command.length), true, true);
|
||||
int roleId = Integer.parseInt(command[2]);
|
||||
if(roleId >= 0 && roleId < SteamVRInputRoles.values.length) {
|
||||
SteamVRInputRoles svrRole = SteamVRInputRoles.values[roleId];
|
||||
internalTracker.bodyPosition = svrRole.bodyPosition;
|
||||
}
|
||||
SteamVRTracker oldTracker;
|
||||
VRTracker oldTracker;
|
||||
synchronized(trackersInternal) {
|
||||
oldTracker = trackersInternal.put(internalTracker.id, internalTracker);
|
||||
oldTracker = trackersInternal.put(internalTracker.getTrackerId(), internalTracker);
|
||||
}
|
||||
if(oldTracker != null) {
|
||||
LogManager.log.severe("[SteamVRPipeInputBridge] New tracker added with the same id. Supplied: " + commandBuilder.toString());
|
||||
@@ -165,25 +174,20 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
// Not used, only input
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
if(newData.getAndSet(false)) {
|
||||
if(trackers.size() < trackersInternal.size()) {
|
||||
// Add new trackers
|
||||
synchronized(trackersInternal) {
|
||||
Iterator<SteamVRTracker> iterator = trackersInternal.values().iterator();
|
||||
Iterator<VRTracker> iterator = trackersInternal.values().iterator();
|
||||
internal: while(iterator.hasNext()) {
|
||||
SteamVRTracker internalTracker = iterator.next();
|
||||
VRTracker internalTracker = iterator.next();
|
||||
for(int i = 0; i < trackers.size(); ++i) {
|
||||
SteamVRTracker t = trackers.get(i);
|
||||
if(t.id == internalTracker.id)
|
||||
VRTracker t = trackers.get(i);
|
||||
if(t.getTrackerId() == internalTracker.getTrackerId())
|
||||
continue internal;
|
||||
}
|
||||
// Tracker is not found in current trackers
|
||||
SteamVRTracker tracker = new SteamVRTracker(internalTracker.id, internalTracker.getName(), true, true);
|
||||
VRTracker tracker = new VRTracker(internalTracker.getTrackerId(), internalTracker.getName(), true, true);
|
||||
tracker.bodyPosition = internalTracker.bodyPosition;
|
||||
trackers.add(tracker);
|
||||
server.registerTracker(tracker);
|
||||
@@ -191,10 +195,10 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < trackers.size(); ++i) {
|
||||
SteamVRTracker tracker = trackers.get(i);
|
||||
SteamVRTracker internal = trackersInternal.get(tracker.id);
|
||||
VRTracker tracker = trackers.get(i);
|
||||
VRTracker internal = trackersInternal.get(tracker.getTrackerId());
|
||||
if(internal == null)
|
||||
throw new NullPointerException("Lost internal tracker somehow: " + tracker.id); // Shouln't really happen even, but better to catch it like this
|
||||
throw new NullPointerException("Lost internal tracker somehow: " + tracker.getTrackerId()); // Shouln't really happen even, but better to catch it like this
|
||||
if(internal.getPosition(vBuffer))
|
||||
tracker.position.set(vBuffer);
|
||||
if(internal.getRotation(qBuffer))
|
||||
@@ -205,8 +209,19 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// Not used, only input
|
||||
}
|
||||
|
||||
private void resetPipe() {
|
||||
Pipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
//Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
|
||||
private boolean tryOpeningPipe(Pipe pipe) {
|
||||
if(Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null)) {
|
||||
if(Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null) || Kernel32.INSTANCE.GetLastError() == WinError.ERROR_PIPE_CONNECTED) {
|
||||
pipe.state = PipeState.OPEN;
|
||||
LogManager.log.info("[SteamVRPipeInputBridge] Pipe " + pipe.name + " is open");
|
||||
return true;
|
||||
@@ -216,13 +231,6 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean areAllPipesOpen() {
|
||||
if(pipe == null || pipe.state == PipeState.CREATED) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void createPipes() throws IOException {
|
||||
try {
|
||||
pipe = new Pipe(Kernel32.INSTANCE.CreateNamedPipe(PipeName, WinBase.PIPE_ACCESS_DUPLEX, // dwOpenMode
|
||||
@@ -237,40 +245,49 @@ public class SteamVRPipeInputBridge extends Thread implements VRBridge {
|
||||
throw new IOException("Can't open " + PipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
LogManager.log.info("[SteamVRPipeInputBridge] Pipes are open");
|
||||
} catch(IOException e) {
|
||||
safeDisconnect(pipe);
|
||||
Pipe.safeDisconnect(pipe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void safeDisconnect(Pipe pipe) {
|
||||
try {
|
||||
if(pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch(Exception e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public enum SteamVRInputRoles {
|
||||
HEAD(TrackerBodyPosition.HMD),
|
||||
LEFT_HAND(TrackerBodyPosition.LEFT_CONTROLLER),
|
||||
RIGHT_HAND(TrackerBodyPosition.RIGHT_CONTROLLER),
|
||||
LEFT_FOOT(TrackerBodyPosition.LEFT_FOOT),
|
||||
RIGHT_FOOT(TrackerBodyPosition.RIGHT_FOOT),
|
||||
LEFT_SHOULDER(TrackerBodyPosition.NONE),
|
||||
RIGHT_SHOULDER(TrackerBodyPosition.NONE),
|
||||
LEFT_ELBOW(TrackerBodyPosition.NONE),
|
||||
RIGHT_ELBOW(TrackerBodyPosition.NONE),
|
||||
LEFT_KNEE(TrackerBodyPosition.LEFT_LEG),
|
||||
RIGHT_KNEE(TrackerBodyPosition.RIGHT_LEG),
|
||||
WAIST(TrackerBodyPosition.WAIST),
|
||||
CHEST(TrackerBodyPosition.CHEST),
|
||||
HEAD(TrackerPosition.HMD),
|
||||
LEFT_HAND(TrackerPosition.LEFT_CONTROLLER),
|
||||
RIGHT_HAND(TrackerPosition.RIGHT_CONTROLLER),
|
||||
LEFT_FOOT(TrackerPosition.LEFT_FOOT),
|
||||
RIGHT_FOOT(TrackerPosition.RIGHT_FOOT),
|
||||
LEFT_SHOULDER(TrackerPosition.NONE),
|
||||
RIGHT_SHOULDER(TrackerPosition.NONE),
|
||||
LEFT_ELBOW(TrackerPosition.NONE),
|
||||
RIGHT_ELBOW(TrackerPosition.NONE),
|
||||
LEFT_KNEE(TrackerPosition.LEFT_LEG),
|
||||
RIGHT_KNEE(TrackerPosition.RIGHT_LEG),
|
||||
WAIST(TrackerPosition.WAIST),
|
||||
CHEST(TrackerPosition.CHEST),
|
||||
;
|
||||
|
||||
private static final SteamVRInputRoles[] values = values();
|
||||
public final TrackerBodyPosition bodyPosition;
|
||||
public final TrackerPosition bodyPosition;
|
||||
|
||||
private SteamVRInputRoles(TrackerBodyPosition slimeVrPosition) {
|
||||
private SteamVRInputRoles(TrackerPosition slimeVrPosition) {
|
||||
this.bodyPosition = slimeVrPosition;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
package io.eiren.vr.bridge;
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class VMCBridge extends Thread implements VRBridge {
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
|
||||
public class VMCBridge extends Thread implements Bridge {
|
||||
|
||||
public final int readPort;
|
||||
public final int writePort;
|
||||
@@ -28,5 +31,22 @@ public class VMCBridge extends Thread implements VRBridge {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
|
||||
}
|
||||
194
src/main/java/dev/slimevr/bridge/WebSocketVRBridge.java
Normal file
194
src/main/java/dev/slimevr/bridge/WebSocketVRBridge.java
Normal file
@@ -0,0 +1,194 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.drafts.Draft;
|
||||
import org.java_websocket.drafts.Draft_6455;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import io.eiren.vr.Main;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public class WebSocketVRBridge extends WebSocketServer implements Bridge {
|
||||
|
||||
private final Vector3f vBuffer = new Vector3f();
|
||||
private final Quaternion qBuffer = new Quaternion();
|
||||
|
||||
private final HMDTracker hmd;
|
||||
private final List<? extends ShareableTracker> shareTrackers;
|
||||
private final List<ComputedTracker> internalTrackers;
|
||||
|
||||
private final HMDTracker internalHMDTracker = new HMDTracker("itnernal://HMD");
|
||||
private final AtomicBoolean newHMDData = new AtomicBoolean(false);
|
||||
|
||||
public WebSocketVRBridge(HMDTracker hmd, List<? extends ShareableTracker> shareTrackers, VRServer server) {
|
||||
super(new InetSocketAddress(21110), Collections.<Draft>singletonList(new Draft_6455()));
|
||||
this.hmd = hmd;
|
||||
this.shareTrackers = new FastList<>(shareTrackers);
|
||||
this.internalTrackers = new FastList<>(shareTrackers.size());
|
||||
for(int i = 0; i < shareTrackers.size(); ++i) {
|
||||
Tracker t = shareTrackers.get(i);
|
||||
ComputedTracker ct = new ComputedTracker(t.getTrackerId(), "internal://" + t.getName(), true, true);
|
||||
ct.setStatus(TrackerStatus.OK);
|
||||
ct.bodyPosition = t.getBodyPosition();
|
||||
this.internalTrackers.add(ct);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
if(newHMDData.compareAndSet(true, false)) {
|
||||
hmd.position.set(internalHMDTracker.position);
|
||||
hmd.rotation.set(internalHMDTracker.rotation);
|
||||
hmd.dataTick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
for(int i = 0; i < shareTrackers.size(); ++i) {
|
||||
Tracker t = shareTrackers.get(i);
|
||||
ComputedTracker it = this.internalTrackers.get(i);
|
||||
if(t.getPosition(vBuffer))
|
||||
it.position.set(vBuffer);
|
||||
if(t.getRotation(qBuffer))
|
||||
it.rotation.set(qBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||
LogManager.log.info("[WebSocket] New connection from: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
|
||||
// Register trackers
|
||||
for(int i = 0; i < internalTrackers.size(); ++i) {
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("type", "config");
|
||||
message.put("tracker_id", "SlimeVR Tracker " + (i + 1));
|
||||
message.put("location", shareTrackers.get(i).getTrackerRole().name().toLowerCase());
|
||||
message.put("tracker_type", message.optString("location"));
|
||||
conn.send(message.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
|
||||
LogManager.log.info("[WebSocket] Disconnected: " + conn.getRemoteSocketAddress().getAddress().getHostAddress() + ", (" + code + ") " + reason + ". Remote: " + remote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, ByteBuffer message) {
|
||||
StringBuilder sb = new StringBuilder(message.limit());
|
||||
while(message.hasRemaining()) {
|
||||
sb.append((char) message.get());
|
||||
}
|
||||
onMessage(conn, sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket conn, String message) {
|
||||
//LogManager.log.info(message);
|
||||
try {
|
||||
JSONObject json = new JSONObject(message);
|
||||
if(json.has("type")) {
|
||||
switch(json.optString("type")) {
|
||||
case "pos":
|
||||
parsePosition(json, conn);
|
||||
return;
|
||||
case "action":
|
||||
parseAction(json, conn);
|
||||
return;
|
||||
case "config": // TODO Ignore it for now, it should only register HMD in our test case with id 0
|
||||
LogManager.log.info("[WebSocket] Config recieved: " + json.toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogManager.log.warning("[WebSocket] Unrecognized message from " + conn.getRemoteSocketAddress().getAddress().getHostAddress() + ": " + message);
|
||||
} catch(Exception e) {
|
||||
LogManager.log.severe("[WebSocket] Exception parsing message from " + conn.getRemoteSocketAddress().getAddress().getHostAddress() + ". Message: " + message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void parsePosition(JSONObject json, WebSocket conn) throws JSONException {
|
||||
if(json.optInt("tracker_id") == 0) {
|
||||
// Read HMD information
|
||||
internalHMDTracker.position.set(json.optFloat("x"), json.optFloat("y") + 0.2f, json.optFloat("z")); // TODO Wtf is this hack? VRWorkout issue?
|
||||
internalHMDTracker.rotation.set(json.optFloat("qx"), json.optFloat("qy"), json.optFloat("qz"), json.optFloat("qw"));
|
||||
internalHMDTracker.dataTick();
|
||||
newHMDData.set(true);
|
||||
|
||||
// Send tracker info in reply
|
||||
for(int i = 0; i < internalTrackers.size(); ++i) {
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("type", "pos");
|
||||
message.put("src", "full");
|
||||
message.put("tracker_id", "SlimeVR Tracker " + (i + 1));
|
||||
|
||||
ComputedTracker t = internalTrackers.get(i);
|
||||
message.put("x", t.position.x);
|
||||
message.put("y", t.position.y);
|
||||
message.put("z", t.position.z);
|
||||
message.put("qx", t.rotation.getX());
|
||||
message.put("qy", t.rotation.getY());
|
||||
message.put("qz", t.rotation.getZ());
|
||||
message.put("qw", t.rotation.getW());
|
||||
|
||||
conn.send(message.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseAction(JSONObject json, WebSocket conn) throws JSONException {
|
||||
switch(json.optString("name")) {
|
||||
case "calibrate":
|
||||
Main.vrServer.resetTrackersYaw();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket conn, Exception ex) {
|
||||
LogManager.log.severe("[WebSocket] Exception on connection " + (conn != null ? conn.getRemoteSocketAddress().getAddress().getHostAddress() : null), ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
LogManager.log.info("[WebSocket] Web Socket VR Bridge started on port " + getPort());
|
||||
setConnectionLostTimeout(0);
|
||||
setConnectionLostTimeout(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowListener;
|
||||
@@ -13,8 +13,6 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import io.eiren.gui.EJBox;
|
||||
import io.eiren.gui.SkeletonConfig;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.util.collections.FastList;
|
||||
@@ -26,6 +24,7 @@ import javax.swing.event.MouseInputAdapter;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import dev.slimevr.autobone.AutoBone;
|
||||
import dev.slimevr.gui.swing.EJBox;
|
||||
import dev.slimevr.poserecorder.PoseFrame;
|
||||
import dev.slimevr.poserecorder.PoseFrameIO;
|
||||
import dev.slimevr.poserecorder.PoseRecorder;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
|
||||
import java.awt.Container;
|
||||
@@ -12,6 +12,7 @@ import javax.swing.JTextArea;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import dev.slimevr.gui.swing.EJBox;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.vr.trackers.CalibratingTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.text.AttributedCharacterIterator.Attribute;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
@@ -8,13 +8,14 @@ import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import dev.slimevr.gui.AutoBoneWindow;
|
||||
import dev.slimevr.gui.swing.ButtonTimer;
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.processor.HumanSkeleton;
|
||||
|
||||
public class SkeletonConfig extends EJBag {
|
||||
public class SkeletonConfig extends EJBagNoStretch {
|
||||
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
@@ -22,7 +23,7 @@ public class SkeletonConfig extends EJBag {
|
||||
private Map<String, SkeletonLabel> labels = new HashMap<>();
|
||||
|
||||
public SkeletonConfig(VRServer server, VRServerGUI gui) {
|
||||
super();
|
||||
super(false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
this.autoBone = new AutoBoneWindow(server, this);
|
||||
@@ -61,7 +62,7 @@ public class SkeletonConfig extends EJBag {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
setSelected(hswl.getSkeletonConfigBoolean("Extended pelvis model"));
|
||||
}
|
||||
}}, s(c(0, row, 1), 3, 1));
|
||||
}}, s(c(0, row, 2), 3, 1));
|
||||
row++;
|
||||
//*/
|
||||
/*
|
||||
@@ -86,11 +87,11 @@ public class SkeletonConfig extends EJBag {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
setSelected(hswl.getSkeletonConfigBoolean("Extended knee model"));
|
||||
}
|
||||
}}, s(c(0, row, 1), 3, 1));
|
||||
}}, s(c(0, row, 2), 3, 1));
|
||||
row++;
|
||||
//*/
|
||||
|
||||
add(new TimedResetButton("Reset All", "All"), s(c(1, row, 1), 3, 1));
|
||||
add(new TimedResetButton("Reset All", "All"), s(c(1, row, 2), 3, 1));
|
||||
add(new JButton("Auto") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
@@ -99,70 +100,70 @@ public class SkeletonConfig extends EJBag {
|
||||
autoBone.toFront();
|
||||
}
|
||||
});
|
||||
}}, s(c(4, row, 1), 3, 1));
|
||||
}}, s(c(4, row, 2), 3, 1));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Chest"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Chest", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Chest"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Chest", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Chest"), c(4, row, 1));
|
||||
add(new JLabel("Chest"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Chest", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Chest"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Chest", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Chest"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Waist"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Waist", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Waist"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Waist", -0.01f), c(3, row, 1));
|
||||
add(new TimedResetButton("Reset", "Waist"), c(4, row, 1));
|
||||
add(new JLabel("Waist"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Waist", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Waist"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Waist", -0.01f), c(3, row, 2));
|
||||
add(new TimedResetButton("Reset", "Waist"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Hips width"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Hips width", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Hips width"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Hips width", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Hips width"), c(4, row, 1));
|
||||
add(new JLabel("Hips width"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Hips width", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Hips width"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Hips width", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Hips width"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Legs length"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Legs length", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Legs length"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Legs length", -0.01f), c(3, row, 1));
|
||||
add(new TimedResetButton("Reset", "Legs length"), c(4, row, 1));
|
||||
add(new JLabel("Legs length"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Legs length", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Legs length"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Legs length", -0.01f), c(3, row, 2));
|
||||
add(new TimedResetButton("Reset", "Legs length"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Knee height"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Knee height", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Knee height"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Knee height", -0.01f), c(3, row, 1));
|
||||
add(new TimedResetButton("Reset", "Knee height"), c(4, row, 1));
|
||||
add(new JLabel("Knee height"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Knee height", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Knee height"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Knee height", -0.01f), c(3, row, 2));
|
||||
add(new TimedResetButton("Reset", "Knee height"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Foot length"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Foot length", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Foot length"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Foot length", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Foot length"), c(4, row, 1));
|
||||
add(new JLabel("Foot length"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Foot length", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Foot length"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Foot length", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Foot length"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Head offset"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Head", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Head"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Head", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Head"), c(4, row, 1));
|
||||
add(new JLabel("Head offset"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Head", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Head"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Head", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Head"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Neck length"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Neck", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Neck"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Neck", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Neck"), c(4, row, 1));
|
||||
add(new JLabel("Neck length"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Neck", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Neck"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Neck", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Neck"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
add(new JLabel("Virtual waist"), c(0, row, 1));
|
||||
add(new AdjButton("+", "Virtual waist", 0.01f), c(1, row, 1));
|
||||
add(new SkeletonLabel("Virtual waist"), c(2, row, 1));
|
||||
add(new AdjButton("-", "Virtual waist", -0.01f), c(3, row, 1));
|
||||
add(new ResetButton("Reset", "Virtual waist"), c(4, row, 1));
|
||||
add(new JLabel("Virtual waist"), c(0, row, 2));
|
||||
add(new AdjButton("+", "Virtual waist", 0.01f), c(1, row, 2));
|
||||
add(new SkeletonLabel("Virtual waist"), c(2, row, 2));
|
||||
add(new AdjButton("-", "Virtual waist", -0.01f), c(3, row, 2));
|
||||
add(new ResetButton("Reset", "Virtual waist"), c(4, row, 2));
|
||||
row++;
|
||||
|
||||
gui.refresh();
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.util.List;
|
||||
@@ -9,6 +9,7 @@ import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
@@ -17,7 +18,7 @@ import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.processor.HumanSkeleton;
|
||||
import io.eiren.vr.processor.TransformNode;
|
||||
|
||||
public class SkeletonList extends EJBag {
|
||||
public class SkeletonList extends EJBagNoStretch {
|
||||
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
|
||||
@@ -25,14 +26,12 @@ public class SkeletonList extends EJBag {
|
||||
Vector3f v = new Vector3f();
|
||||
float[] angles = new float[3];
|
||||
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
private final List<NodeStatus> nodes = new FastList<>();
|
||||
private long lastUpdate = 0;
|
||||
|
||||
public SkeletonList(VRServer server, VRServerGUI gui) {
|
||||
super();
|
||||
this.server = server;
|
||||
super(false, true);
|
||||
this.gui = gui;
|
||||
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
@@ -17,12 +17,13 @@ import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import dev.slimevr.gui.swing.EJBoxNoStretch;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.ReferenceAdjustedTracker;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
@@ -30,10 +31,11 @@ import io.eiren.vr.trackers.IMUTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerConfig;
|
||||
import io.eiren.vr.trackers.TrackerMountingRotation;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerWithBattery;
|
||||
import io.eiren.vr.trackers.TrackerWithTPS;
|
||||
|
||||
public class TrackersList extends EJBox {
|
||||
public class TrackersList extends EJBoxNoStretch {
|
||||
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
|
||||
@@ -48,7 +50,7 @@ public class TrackersList extends EJBox {
|
||||
private long lastUpdate = 0;
|
||||
|
||||
public TrackersList(VRServer server, VRServerGUI gui) {
|
||||
super(BoxLayout.PAGE_AXIS);
|
||||
super(BoxLayout.PAGE_AXIS, false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
|
||||
@@ -65,7 +67,7 @@ public class TrackersList extends EJBox {
|
||||
|
||||
Class<? extends Tracker> currentClass = null;
|
||||
|
||||
EJBox line = null;
|
||||
EJBoxNoStretch line = null;
|
||||
boolean first = true;
|
||||
|
||||
for(int i = 0; i < trackers.size(); ++i) {
|
||||
@@ -78,7 +80,7 @@ public class TrackersList extends EJBox {
|
||||
if(line != null)
|
||||
line.add(Box.createHorizontalGlue());
|
||||
line = null;
|
||||
line = new EJBox(BoxLayout.LINE_AXIS);
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
line.add(Box.createHorizontalGlue());
|
||||
JLabel nameLabel;
|
||||
line.add(nameLabel = new JLabel(currentClass.getSimpleName()));
|
||||
@@ -89,7 +91,7 @@ public class TrackersList extends EJBox {
|
||||
}
|
||||
|
||||
if(line == null) {
|
||||
line = new EJBox(BoxLayout.LINE_AXIS);
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
add(Box.createVerticalStrut(3));
|
||||
add(line);
|
||||
first = true;
|
||||
@@ -125,7 +127,7 @@ public class TrackersList extends EJBox {
|
||||
});
|
||||
}
|
||||
|
||||
private class TrackerPanel extends EJBag {
|
||||
private class TrackerPanel extends EJBagNoStretch {
|
||||
|
||||
final Tracker t;
|
||||
JLabel position;
|
||||
@@ -144,7 +146,8 @@ public class TrackersList extends EJBox {
|
||||
|
||||
@AWTThread
|
||||
public TrackerPanel(Tracker t) {
|
||||
super();
|
||||
super(false, true);
|
||||
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@@ -158,26 +161,26 @@ public class TrackersList extends EJBox {
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
removeAll();
|
||||
JLabel nameLabel;
|
||||
add(nameLabel = new JLabel(t.getName()), s(c(0, row, 0, GridBagConstraints.FIRST_LINE_START), 4, 1));
|
||||
add(nameLabel = new JLabel(t.getDescriptiveName()), s(c(0, row, 2, GridBagConstraints.FIRST_LINE_START), 4, 1));
|
||||
nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD));
|
||||
row++;
|
||||
|
||||
if(t.userEditable()) {
|
||||
TrackerConfig cfg = server.getTrackerConfig(t);
|
||||
JComboBox<String> desSelect;
|
||||
add(desSelect = new JComboBox<>(), s(c(0, row, 0, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for(TrackerBodyPosition p : TrackerBodyPosition.values) {
|
||||
add(desSelect = new JComboBox<>(), s(c(0, row, 2, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for(TrackerPosition p : TrackerPosition.values) {
|
||||
desSelect.addItem(p.name());
|
||||
}
|
||||
if(cfg.designation != null) {
|
||||
TrackerBodyPosition p = TrackerBodyPosition.getByDesignation(cfg.designation);
|
||||
TrackerPosition p = TrackerPosition.getByDesignation(cfg.designation);
|
||||
if(p != null)
|
||||
desSelect.setSelectedItem(p.name());
|
||||
}
|
||||
desSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TrackerBodyPosition p = TrackerBodyPosition.valueOf(String.valueOf(desSelect.getSelectedItem()));
|
||||
TrackerPosition p = TrackerPosition.valueOf(String.valueOf(desSelect.getSelectedItem()));
|
||||
t.setBodyPosition(p);
|
||||
server.trackerUpdated(t);
|
||||
}
|
||||
@@ -186,7 +189,7 @@ public class TrackersList extends EJBox {
|
||||
IMUTracker imu = (IMUTracker) realTracker;
|
||||
TrackerMountingRotation tr = imu.getMountingRotation();
|
||||
JComboBox<String> mountSelect;
|
||||
add(mountSelect = new JComboBox<>(), s(c(2, row, 0, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
add(mountSelect = new JComboBox<>(), s(c(2, row, 2, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for(TrackerMountingRotation p : TrackerMountingRotation.values) {
|
||||
mountSelect.addItem(p.name());
|
||||
}
|
||||
@@ -207,53 +210,59 @@ public class TrackersList extends EJBox {
|
||||
row++;
|
||||
}
|
||||
if(t.hasRotation())
|
||||
add(new JLabel("Rotation"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Rotation"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if(t.hasPosition())
|
||||
add(new JLabel("Position"), c(1, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Ping"), c(2, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("TPS"), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
if(t.hasRotation())
|
||||
add(rotation = new JLabel("0 0 0"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
if(t.hasPosition())
|
||||
add(position = new JLabel("0 0 0"), c(1, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(ping = new JLabel(""), c(2, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
if(realTracker instanceof TrackerWithTPS) {
|
||||
add(tps = new JLabel("0"), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
} else {
|
||||
add(new JLabel(""), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Position"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("TPS"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if(realTracker instanceof IMUTracker) {
|
||||
add(new JLabel("Ping"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
add(new JLabel("Status:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(status = new JLabel(t.getStatus().toString().toLowerCase()), c(1, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Battery:"), c(2, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(bat = new JLabel("0"), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
if(t.hasRotation())
|
||||
add(rotation = new JLabel("0 0 0"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if(t.hasPosition())
|
||||
add(position = new JLabel("0 0 0"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if(realTracker instanceof IMUTracker) {
|
||||
add(ping = new JLabel(""), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
if(realTracker instanceof TrackerWithTPS) {
|
||||
add(tps = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
} else {
|
||||
add(new JLabel(""), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
add(new JLabel("Raw:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(raw = new JLabel("0 0 0"), s(c(1, row, 0, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
add(new JLabel("Status:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(status = new JLabel(t.getStatus().toString().toLowerCase()), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if(realTracker instanceof TrackerWithBattery) {
|
||||
add(new JLabel("Battery:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(bat = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
add(new JLabel("Raw:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(raw = new JLabel("0 0 0"), s(c(1, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
row++;
|
||||
if(realTracker instanceof IMUTracker) {
|
||||
add(new JLabel("Raw mag:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rawMag = new JLabel("0 0 0"), s(c(1, row, 0, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
add(new JLabel("Raw mag:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rawMag = new JLabel("0 0 0"), s(c(1, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
row++;
|
||||
add(new JLabel("Cal:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(calibration = new JLabel("0"), c(1, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Mag acc:"), c(2, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(magAccuracy = new JLabel("0°"), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Cal:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(calibration = new JLabel("0"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Mag acc:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(magAccuracy = new JLabel("0°"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
add(new JLabel("Correction:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(correction = new JLabel("0 0 0"), s(c(1, row, 0, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
add(new JLabel("Correction:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(correction = new JLabel("0 0 0"), s(c(1, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
row++;
|
||||
}
|
||||
|
||||
if(t instanceof ReferenceAdjustedTracker) {
|
||||
add(new JLabel("Adj:"), c(0, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adj = new JLabel("0 0 0 0"), c(1, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("AdjY:"), c(2, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjYaw = new JLabel("0 0 0 0"), c(3, row, 0, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Adj:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adj = new JLabel("0 0 0 0"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("AdjY:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjYaw = new JLabel("0 0 0 0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
|
||||
setBorder(BorderFactory.createLineBorder(new Color(0x663399), 4, true));
|
||||
setBorder(BorderFactory.createLineBorder(new Color(0x663399), 2, false));
|
||||
TrackersList.this.add(this);
|
||||
return this;
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import dev.slimevr.bridge.NamedPipeBridge;
|
||||
import dev.slimevr.bridge.NamedPipeVRBridge;
|
||||
import dev.slimevr.gui.swing.ButtonTimer;
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import dev.slimevr.gui.swing.EJBox;
|
||||
import dev.slimevr.gui.swing.EJBoxNoStretch;
|
||||
import io.eiren.util.MacOSX;
|
||||
import io.eiren.util.OperatingSystem;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.vr.Main;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
@@ -134,7 +141,7 @@ public class VRServerGUI extends JFrame {
|
||||
private void build() {
|
||||
pane.removeAll();
|
||||
|
||||
pane.add(new EJBox(LINE_AXIS) {{
|
||||
pane.add(new EJBoxNoStretch(LINE_AXIS, false, true) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
|
||||
add(Box.createHorizontalGlue());
|
||||
@@ -180,72 +187,95 @@ public class VRServerGUI extends JFrame {
|
||||
|
||||
pane.add(new EJBox(LINE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new EJBox(PAGE_AXIS) {{
|
||||
add(new EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
add(new JLabel("SteamVR Trackers:"));
|
||||
JComboBox<String> trackersSelect;
|
||||
add(trackersSelect = new JComboBox<>());
|
||||
trackersSelect.addItem("Waist");
|
||||
trackersSelect.addItem("Waist + Legs");
|
||||
trackersSelect.addItem("Waist + Legs + Chest");
|
||||
trackersSelect.addItem("Waist + Legs + Knees");
|
||||
trackersSelect.addItem("Waist + Legs + Chest + Knees");
|
||||
switch(server.config.getInt("virtualtrackers", 3)) {
|
||||
case 1:
|
||||
trackersSelect.setSelectedIndex(0);
|
||||
break;
|
||||
case 3:
|
||||
trackersSelect.setSelectedIndex(1);
|
||||
break;
|
||||
case 4:
|
||||
trackersSelect.setSelectedIndex(2);
|
||||
break;
|
||||
case 5:
|
||||
trackersSelect.setSelectedIndex(3);
|
||||
break;
|
||||
case 6:
|
||||
trackersSelect.setSelectedIndex(4);
|
||||
break;
|
||||
}
|
||||
trackersSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
switch(trackersSelect.getSelectedIndex()) {
|
||||
case 0:
|
||||
server.config.setProperty("virtualtrackers", 1);
|
||||
break;
|
||||
case 1:
|
||||
server.config.setProperty("virtualtrackers", 3);
|
||||
break;
|
||||
case 2:
|
||||
server.config.setProperty("virtualtrackers", 4);
|
||||
break;
|
||||
case 3:
|
||||
server.config.setProperty("virtualtrackers", 5);
|
||||
break;
|
||||
case 4:
|
||||
server.config.setProperty("virtualtrackers", 6);
|
||||
break;
|
||||
}
|
||||
server.saveConfig();
|
||||
}
|
||||
});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
|
||||
add(new JLabel("Trackers list"));
|
||||
JLabel l;
|
||||
add(l = new JLabel("Trackers list"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(trackersList);
|
||||
add(Box.createVerticalGlue());
|
||||
}});
|
||||
|
||||
add(new EJBox(PAGE_AXIS) {{
|
||||
add(new EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
add(new JLabel("Body proportions"));
|
||||
JLabel l;
|
||||
add(l = new JLabel("Body proportions"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(new SkeletonConfig(server, VRServerGUI.this));
|
||||
add(Box.createVerticalStrut(10));
|
||||
if(server.hasBridge(NamedPipeBridge.class)) {
|
||||
NamedPipeBridge br = server.getVRBridge(NamedPipeBridge.class);
|
||||
add(l = new JLabel("SteamVR Trackers"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(l = new JLabel("Changes may require restart of SteamVR"));
|
||||
l.setFont(l.getFont().deriveFont(Font.ITALIC));
|
||||
l.setAlignmentX(0.5f);
|
||||
|
||||
add(new EJBagNoStretch(false, true) {{
|
||||
JCheckBox waistCb;
|
||||
add(waistCb = new JCheckBox("Waist"), c(1, 1));
|
||||
waistCb.setSelected(br.getShareSetting(TrackerRole.WAIST));
|
||||
waistCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.WAIST, waistCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox legsCb;
|
||||
add(legsCb = new JCheckBox("Legs"), c(2, 1));
|
||||
legsCb.setSelected(br.getShareSetting(TrackerRole.LEFT_FOOT) && br.getShareSetting(TrackerRole.RIGHT_FOOT));
|
||||
legsCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_FOOT, legsCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_FOOT, legsCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox chestCb;
|
||||
add(chestCb = new JCheckBox("Chest"), c(1, 2));
|
||||
chestCb.setSelected(br.getShareSetting(TrackerRole.CHEST));
|
||||
chestCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.CHEST, chestCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox kneesCb;
|
||||
add(kneesCb = new JCheckBox("Knees"), c(2, 2));
|
||||
kneesCb.setSelected(br.getShareSetting(TrackerRole.LEFT_KNEE) && br.getShareSetting(TrackerRole.RIGHT_KNEE));
|
||||
kneesCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_KNEE, kneesCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_KNEE, kneesCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}});
|
||||
|
||||
|
||||
add(Box.createVerticalStrut(10));
|
||||
}
|
||||
add(new JLabel("Skeleton data"));
|
||||
add(skeletonList);
|
||||
add(Box.createVerticalGlue());
|
||||
}});
|
||||
}});
|
||||
pane.add(Box.createVerticalGlue());
|
||||
|
||||
refresh();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -26,6 +26,7 @@ import javax.swing.event.MouseInputAdapter;
|
||||
|
||||
import com.fazecast.jSerialComm.SerialPort;
|
||||
|
||||
import dev.slimevr.gui.swing.EJBox;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
|
||||
public class WiFiWindow extends JFrame {
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import java.awt.GridBagLayout;
|
||||
|
||||
33
src/main/java/dev/slimevr/gui/swing/EJBagNoStretch.java
Normal file
33
src/main/java/dev/slimevr/gui/swing/EJBagNoStretch.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagLayout;
|
||||
|
||||
public class EJBagNoStretch extends EJPanel {
|
||||
|
||||
public EJBagNoStretch(boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super(new EGridBagLayoutNoStretch(stretchVertical, stretchHorizontal));
|
||||
}
|
||||
|
||||
private static class EGridBagLayoutNoStretch extends GridBagLayout {
|
||||
|
||||
private final boolean stretchVertical;
|
||||
private final boolean stretchHorizontal;
|
||||
|
||||
public EGridBagLayoutNoStretch(boolean stretchVertical, boolean stretchHorizontal) {
|
||||
this.stretchVertical = stretchVertical;
|
||||
this.stretchHorizontal = stretchHorizontal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension maximumLayoutSize(Container target) {
|
||||
Dimension pref = preferredLayoutSize(target);
|
||||
if(stretchVertical)
|
||||
pref.height = Integer.MAX_VALUE;
|
||||
if(stretchHorizontal)
|
||||
pref.width = Integer.MAX_VALUE;
|
||||
return pref;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
|
||||
36
src/main/java/dev/slimevr/gui/swing/EJBoxNoStretch.java
Normal file
36
src/main/java/dev/slimevr/gui/swing/EJBoxNoStretch.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
|
||||
public class EJBoxNoStretch extends EJPanel {
|
||||
|
||||
public EJBoxNoStretch(int layout, boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super();
|
||||
setLayout(new BoxLayoutNoStretch(this, layout, stretchVertical, stretchHorizontal));
|
||||
}
|
||||
|
||||
private static class BoxLayoutNoStretch extends BoxLayout {
|
||||
|
||||
private final boolean stretchVertical;
|
||||
private final boolean stretchHorizontal;
|
||||
|
||||
public BoxLayoutNoStretch(Container target, int axis, boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super(target, axis);
|
||||
this.stretchVertical = stretchVertical;
|
||||
this.stretchHorizontal = stretchHorizontal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension maximumLayoutSize(Container target) {
|
||||
Dimension pref = preferredLayoutSize(target);
|
||||
if(stretchVertical)
|
||||
pref.height = Integer.MAX_VALUE;
|
||||
if(stretchHorizontal)
|
||||
pref.width = Integer.MAX_VALUE;
|
||||
return pref;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.eiren.gui;
|
||||
package dev.slimevr.gui.swing;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
|
||||
public final class PoseFrameIO {
|
||||
|
||||
@@ -91,9 +91,9 @@ public final class PoseFrameIO {
|
||||
for(int j = 0; j < trackerFrameCount; j++) {
|
||||
int dataFlags = inputStream.readInt();
|
||||
|
||||
TrackerBodyPosition designation = null;
|
||||
TrackerPosition designation = null;
|
||||
if(TrackerFrameData.DESIGNATION.check(dataFlags)) {
|
||||
designation = TrackerBodyPosition.getByDesignation(inputStream.readUTF());
|
||||
designation = TrackerPosition.getByDesignation(inputStream.readUTF());
|
||||
}
|
||||
|
||||
Quaternion rotation = null;
|
||||
|
||||
@@ -6,9 +6,9 @@ import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerConfig;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public class PoseFrameTracker implements Tracker, Iterable<TrackerFrame> {
|
||||
@@ -17,6 +17,7 @@ public class PoseFrameTracker implements Tracker, Iterable<TrackerFrame> {
|
||||
|
||||
private final FastList<TrackerFrame> frames;
|
||||
private int frameCursor = 0;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
|
||||
public PoseFrameTracker(String name, FastList<TrackerFrame> frames) {
|
||||
if(frames == null) {
|
||||
@@ -193,13 +194,13 @@ public class PoseFrameTracker implements Tracker, Iterable<TrackerFrame> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerBodyPosition getBodyPosition() {
|
||||
public TrackerPosition getBodyPosition() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame == null ? null : frame.designation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerBodyPosition position) {
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not allow setting the body position");
|
||||
}
|
||||
|
||||
@@ -230,4 +231,9 @@ public class PoseFrameTracker implements Tracker, Iterable<TrackerFrame> {
|
||||
public Iterator<TrackerFrame> iterator() {
|
||||
return frames.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,21 @@ package dev.slimevr.poserecorder;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerConfig;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public final class TrackerFrame implements Tracker {
|
||||
|
||||
private int dataFlags = 0;
|
||||
|
||||
public final TrackerBodyPosition designation;
|
||||
public final TrackerPosition designation;
|
||||
public final Quaternion rotation;
|
||||
public final Vector3f position;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
|
||||
public TrackerFrame(TrackerBodyPosition designation, Quaternion rotation, Vector3f position) {
|
||||
public TrackerFrame(TrackerPosition designation, Quaternion rotation, Vector3f position) {
|
||||
this.designation = designation;
|
||||
if(designation != null) {
|
||||
dataFlags |= TrackerFrameData.DESIGNATION.flag;
|
||||
@@ -141,12 +142,12 @@ public final class TrackerFrame implements Tracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerBodyPosition getBodyPosition() {
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return designation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerBodyPosition position) {
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not allow setting the body position");
|
||||
}
|
||||
|
||||
@@ -170,4 +171,9 @@ public final class TrackerFrame implements Tracker {
|
||||
return true;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
}
|
||||
|
||||
52
src/main/java/io/eiren/vr/Keybinding.java
Normal file
52
src/main/java/io/eiren/vr/Keybinding.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package io.eiren.vr;
|
||||
|
||||
import com.melloware.jintellitype.JIntellitype;
|
||||
import com.melloware.jintellitype.HotkeyListener;
|
||||
import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
|
||||
public class Keybinding implements HotkeyListener {
|
||||
public final VRServer server;
|
||||
private static final int RESET = 1;
|
||||
private static final int QUICK_RESET = 2;
|
||||
|
||||
@AWTThread
|
||||
public Keybinding(VRServer server) {
|
||||
this.server = server;
|
||||
|
||||
if(JIntellitype.isJIntellitypeSupported()) {
|
||||
JIntellitype.getInstance().addHotKeyListener(this);
|
||||
|
||||
String resetBinding = this.server.config.getString("keybindings.reset");
|
||||
if(resetBinding == null) {
|
||||
resetBinding = "CTRL+ALT+SHIFT+Y";
|
||||
this.server.config.setProperty("keybindings.reset", resetBinding);
|
||||
}
|
||||
JIntellitype.getInstance().registerHotKey(RESET, resetBinding);
|
||||
LogManager.log.info("[Keybinding] Bound reset to " + resetBinding);
|
||||
|
||||
String quickResetBinding = this.server.config.getString("keybindings.quickReset");
|
||||
if(quickResetBinding == null) {
|
||||
quickResetBinding = "CTRL+ALT+SHIFT+U";
|
||||
this.server.config.setProperty("keybindings.quickReset", quickResetBinding);
|
||||
}
|
||||
JIntellitype.getInstance().registerHotKey(QUICK_RESET, quickResetBinding);
|
||||
LogManager.log.info("[Keybinding] Bound quick reset to " + quickResetBinding);
|
||||
}
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
@Override
|
||||
public void onHotKey(int identifier) {
|
||||
switch(identifier) {
|
||||
case RESET:
|
||||
LogManager.log.info("[Keybinding] Reset pressed");
|
||||
server.resetTrackers();
|
||||
break;
|
||||
case QUICK_RESET:
|
||||
LogManager.log.info("[Keybinding] Quick reset pressed");
|
||||
server.resetTrackersYaw();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@ package io.eiren.vr;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import io.eiren.gui.VRServerGUI;
|
||||
import dev.slimevr.gui.VRServerGUI;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static String VERSION = "0.0.19";
|
||||
public static String VERSION = "0.1.0";
|
||||
|
||||
public static VRServer vrServer;
|
||||
|
||||
@@ -26,6 +26,7 @@ public class Main {
|
||||
try {
|
||||
vrServer = new VRServer();
|
||||
vrServer.start();
|
||||
new Keybinding(vrServer);
|
||||
new VRServerGUI(vrServer);
|
||||
} catch(Throwable e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -15,17 +15,20 @@ import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import dev.slimevr.bridge.Bridge;
|
||||
import dev.slimevr.bridge.NamedPipeBridge;
|
||||
import dev.slimevr.bridge.SteamVRPipeInputBridge;
|
||||
import dev.slimevr.bridge.VMCBridge;
|
||||
import dev.slimevr.bridge.WebSocketVRBridge;
|
||||
import io.eiren.util.OperatingSystem;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.ann.ThreadSecure;
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.vr.bridge.NamedPipeVRBridge;
|
||||
import io.eiren.vr.bridge.SteamVRPipeInputBridge;
|
||||
import io.eiren.vr.bridge.VMCBridge;
|
||||
import io.eiren.vr.bridge.VRBridge;
|
||||
import io.eiren.vr.processor.HumanPoseProcessor;
|
||||
import io.eiren.vr.processor.HumanSkeleton;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.TrackersUDPServer;
|
||||
import io.eiren.yaml.YamlException;
|
||||
import io.eiren.yaml.YamlFile;
|
||||
@@ -37,14 +40,15 @@ public class VRServer extends Thread {
|
||||
|
||||
private final List<Tracker> trackers = new FastList<>();
|
||||
public final HumanPoseProcessor humanPoseProcessor;
|
||||
private final TrackersUDPServer trackersServer = new TrackersUDPServer(6969, "Sensors UDP server", this::registerTracker);
|
||||
private final List<VRBridge> bridges = new FastList<>();
|
||||
private final TrackersUDPServer trackersServer;
|
||||
private final List<Bridge> bridges = new FastList<>();
|
||||
private final Queue<Runnable> tasks = new LinkedBlockingQueue<>();
|
||||
private final Map<String, TrackerConfig> configuration = new HashMap<>();
|
||||
public final YamlFile config = new YamlFile();
|
||||
public final HMDTracker hmdTracker;
|
||||
private final List<Consumer<Tracker>> newTrackersConsumers = new FastList<>();
|
||||
private final List<Runnable> onTick = new FastList<>();
|
||||
private final List<? extends ShareableTracker> shareTrackers;
|
||||
|
||||
public VRServer() {
|
||||
super("VRServer");
|
||||
@@ -52,22 +56,39 @@ public class VRServer extends Thread {
|
||||
hmdTracker = new HMDTracker("HMD");
|
||||
hmdTracker.position.set(0, 1.8f, 0); // Set starting position for easier debugging
|
||||
// TODO Multiple processors
|
||||
humanPoseProcessor = new HumanPoseProcessor(this, hmdTracker, config.getInt("virtualtrackers", 3));
|
||||
List<? extends Tracker> shareTrackers = humanPoseProcessor.getComputedTrackers();
|
||||
humanPoseProcessor = new HumanPoseProcessor(this, hmdTracker);
|
||||
shareTrackers = humanPoseProcessor.getComputedTrackers();
|
||||
|
||||
// Create named pipe bridge for SteamVR driver
|
||||
NamedPipeVRBridge driverBridge = new NamedPipeVRBridge(hmdTracker, shareTrackers, this);
|
||||
tasks.add(() -> driverBridge.start());
|
||||
bridges.add(driverBridge);
|
||||
// Create named pipe bridge for SteamVR input
|
||||
SteamVRPipeInputBridge steamVRInput = new SteamVRPipeInputBridge(this);
|
||||
tasks.add(() -> steamVRInput.start());
|
||||
bridges.add(steamVRInput);
|
||||
// Start server for SlimeVR trackers
|
||||
trackersServer = new TrackersUDPServer(6969, "Sensors UDP server", this::registerTracker);
|
||||
|
||||
// OpenVR bridge currently only supports Windows
|
||||
if(OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) {
|
||||
/*
|
||||
// Create named pipe bridge for SteamVR driver
|
||||
NamedPipeVRBridge driverBridge = new NamedPipeVRBridge(hmdTracker, shareTrackers, this);
|
||||
tasks.add(() -> driverBridge.startBridge());
|
||||
bridges.add(driverBridge);
|
||||
//*/
|
||||
// Create named pipe bridge for SteamVR input
|
||||
SteamVRPipeInputBridge steamVRInput = new SteamVRPipeInputBridge(this);
|
||||
tasks.add(() -> steamVRInput.startBridge());
|
||||
bridges.add(steamVRInput);
|
||||
//*/
|
||||
NamedPipeBridge driverBridge = new NamedPipeBridge(hmdTracker, "steamvr", "SteamVR Driver Bridge", "\\\\.\\pipe\\SlimeVRDriver", shareTrackers);
|
||||
tasks.add(() -> driverBridge.startBridge());
|
||||
bridges.add(driverBridge);
|
||||
}
|
||||
|
||||
// Create WebSocket server
|
||||
WebSocketVRBridge wsBridge = new WebSocketVRBridge(hmdTracker, shareTrackers, this);
|
||||
tasks.add(() -> wsBridge.startBridge());
|
||||
bridges.add(wsBridge);
|
||||
|
||||
// Create VMCBridge
|
||||
try {
|
||||
VMCBridge vmcBridge = new VMCBridge(39539, 39540, InetAddress.getLocalHost());
|
||||
tasks.add(() -> vmcBridge.start());
|
||||
tasks.add(() -> vmcBridge.startBridge());
|
||||
bridges.add(vmcBridge);
|
||||
} catch(UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
@@ -78,13 +99,21 @@ public class VRServer extends Thread {
|
||||
for(int i = 0; i < shareTrackers.size(); ++i)
|
||||
registerTracker(shareTrackers.get(i));
|
||||
}
|
||||
|
||||
public boolean hasBridge(Class<? extends Bridge> bridgeClass) {
|
||||
for(int i = 0; i < bridges.size(); ++i) {
|
||||
if(bridgeClass.isAssignableFrom(bridges.get(i).getClass()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public <E extends VRBridge> E getVRBridge(Class<E> cls) {
|
||||
public <E extends Bridge> E getVRBridge(Class<E> bridgeClass) {
|
||||
for(int i = 0; i < bridges.size(); ++i) {
|
||||
VRBridge b = bridges.get(i);
|
||||
if(cls.isInstance(b))
|
||||
return cls.cast(b);
|
||||
Bridge b = bridges.get(i);
|
||||
if(bridgeClass.isAssignableFrom(b.getClass()))
|
||||
return bridgeClass.cast(b);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -94,7 +123,7 @@ public class VRServer extends Thread {
|
||||
synchronized(configuration) {
|
||||
TrackerConfig config = configuration.get(tracker.getName());
|
||||
if(config == null) {
|
||||
config = new TrackerConfig(tracker.getName());
|
||||
config = new TrackerConfig(tracker);
|
||||
configuration.put(tracker.getName(), config);
|
||||
}
|
||||
return config;
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.eiren.vr.bridge;
|
||||
|
||||
import com.sun.jna.platform.win32.WinNT.HANDLE;
|
||||
|
||||
class Pipe {
|
||||
final String name;
|
||||
final HANDLE pipeHandle;
|
||||
PipeState state = PipeState.CREATED;
|
||||
|
||||
public Pipe(HANDLE pipeHandle, String name) {
|
||||
this.pipeHandle = pipeHandle;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package io.eiren.vr.bridge;
|
||||
|
||||
enum PipeState {
|
||||
CREATED,
|
||||
OPEN,
|
||||
ERROR;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package io.eiren.vr.bridge;
|
||||
|
||||
public interface VRBridge {
|
||||
|
||||
public void dataRead();
|
||||
|
||||
public void dataWrite();
|
||||
}
|
||||
@@ -2,16 +2,20 @@ package io.eiren.vr.processor;
|
||||
|
||||
import io.eiren.util.BufferedTimer;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
import io.eiren.vr.trackers.TrackerWithTPS;
|
||||
|
||||
public class ComputedHumanPoseTracker extends ComputedTracker implements TrackerWithTPS {
|
||||
public class ComputedHumanPoseTracker extends ComputedTracker implements TrackerWithTPS, ShareableTracker {
|
||||
|
||||
public final ComputedHumanPoseTrackerPosition skeletonPosition;
|
||||
protected final TrackerRole trackerRole;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition skeletonPosition) {
|
||||
super("human://" + skeletonPosition.name(), true, true);
|
||||
public ComputedHumanPoseTracker(int trackerId, ComputedHumanPoseTrackerPosition skeletonPosition, TrackerRole role) {
|
||||
super(trackerId, "human://" + skeletonPosition.name(), true, true);
|
||||
this.skeletonPosition = skeletonPosition;
|
||||
this.trackerRole = role;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,4 +27,9 @@ public class ComputedHumanPoseTracker extends ComputedTracker implements Tracker
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerRole getTrackerRole() {
|
||||
return trackerRole;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.ShareableTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
|
||||
public class HumanPoseProcessor {
|
||||
@@ -18,20 +20,14 @@ public class HumanPoseProcessor {
|
||||
private final List<Consumer<HumanSkeleton>> onSkeletonUpdated = new FastList<>();
|
||||
private HumanSkeleton skeleton;
|
||||
|
||||
public HumanPoseProcessor(VRServer server, HMDTracker hmd, int trackersAmount) {
|
||||
public HumanPoseProcessor(VRServer server, HMDTracker hmd) {
|
||||
this.server = server;
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.WAIST));
|
||||
if(trackersAmount > 2) {
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.LEFT_FOOT));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.RIGHT_FOOT));
|
||||
if(trackersAmount == 4 || trackersAmount >= 6) {
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.CHEST));
|
||||
}
|
||||
if(trackersAmount >= 5) {
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.LEFT_KNEE));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.RIGHT_KNEE));
|
||||
}
|
||||
}
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.WAIST, TrackerRole.WAIST));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_FOOT, TrackerRole.LEFT_FOOT));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_FOOT, TrackerRole.RIGHT_FOOT));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.CHEST, TrackerRole.CHEST));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_KNEE, TrackerRole.LEFT_KNEE));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_KNEE, TrackerRole.RIGHT_KNEE));
|
||||
}
|
||||
|
||||
public HumanSkeleton getSkeleton() {
|
||||
@@ -68,7 +64,7 @@ public class HumanPoseProcessor {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public List<? extends Tracker> getComputedTrackers() {
|
||||
public List<? extends ShareableTracker> getComputedTrackers() {
|
||||
return computedTrackers;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.jme3.math.Vector3f;
|
||||
import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerRole;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
import io.eiren.vr.trackers.TrackerUtils;
|
||||
|
||||
@@ -69,12 +71,12 @@ public class HumanSkeletonWithLegs extends HumanSkeletonWithWaist {
|
||||
public HumanSkeletonWithLegs(VRServer server, List<ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(server, computedTrackers);
|
||||
List<Tracker> allTracekrs = server.getAllTrackers();
|
||||
this.leftLegTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.LEFT_LEG, TrackerBodyPosition.LEFT_ANKLE);
|
||||
this.leftAnkleTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.LEFT_ANKLE, TrackerBodyPosition.LEFT_LEG);
|
||||
this.leftFootTracker = TrackerUtils.findTrackerForBodyPosition(allTracekrs, TrackerBodyPosition.LEFT_FOOT);
|
||||
this.rightLegTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.RIGHT_LEG, TrackerBodyPosition.RIGHT_ANKLE);
|
||||
this.rightAnkleTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.RIGHT_ANKLE, TrackerBodyPosition.RIGHT_LEG);
|
||||
this.rightFootTracker = TrackerUtils.findTrackerForBodyPosition(allTracekrs, TrackerBodyPosition.RIGHT_FOOT);
|
||||
this.leftLegTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.LEFT_LEG, TrackerPosition.LEFT_ANKLE);
|
||||
this.leftAnkleTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.LEFT_ANKLE, TrackerPosition.LEFT_LEG);
|
||||
this.leftFootTracker = TrackerUtils.findTrackerForBodyPosition(allTracekrs, TrackerPosition.LEFT_FOOT);
|
||||
this.rightLegTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.RIGHT_LEG, TrackerPosition.RIGHT_ANKLE);
|
||||
this.rightAnkleTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.RIGHT_ANKLE, TrackerPosition.RIGHT_LEG);
|
||||
this.rightFootTracker = TrackerUtils.findTrackerForBodyPosition(allTracekrs, TrackerPosition.RIGHT_FOOT);
|
||||
ComputedHumanPoseTracker lat = null;
|
||||
ComputedHumanPoseTracker rat = null;
|
||||
ComputedHumanPoseTracker rkt = null;
|
||||
@@ -91,9 +93,9 @@ public class HumanSkeletonWithLegs extends HumanSkeletonWithWaist {
|
||||
rkt = t;
|
||||
}
|
||||
if(lat == null)
|
||||
lat = new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.LEFT_FOOT);
|
||||
lat = new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_FOOT, TrackerRole.LEFT_FOOT);
|
||||
if(rat == null)
|
||||
rat = new ComputedHumanPoseTracker(ComputedHumanPoseTrackerPosition.RIGHT_FOOT);
|
||||
rat = new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_FOOT, TrackerRole.RIGHT_FOOT);
|
||||
computedLeftFootTracker = lat;
|
||||
computedRightFootTracker = rat;
|
||||
computedLeftKneeTracker = lkt;
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.eiren.util.ann.VRServerThread;
|
||||
import io.eiren.vr.VRServer;
|
||||
import io.eiren.vr.trackers.HMDTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
import io.eiren.vr.trackers.TrackerPosition;
|
||||
import io.eiren.vr.trackers.TrackerStatus;
|
||||
import io.eiren.vr.trackers.TrackerUtils;
|
||||
|
||||
@@ -60,8 +61,8 @@ public class HumanSkeletonWithWaist extends HumanSkeleton {
|
||||
|
||||
public HumanSkeletonWithWaist(VRServer server, List<ComputedHumanPoseTracker> computedTrackers) {
|
||||
List<Tracker> allTracekrs = server.getAllTrackers();
|
||||
this.waistTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.WAIST, TrackerBodyPosition.CHEST);
|
||||
this.chestTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerBodyPosition.CHEST, TrackerBodyPosition.WAIST);
|
||||
this.waistTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.WAIST, TrackerPosition.CHEST);
|
||||
this.chestTracker = TrackerUtils.findTrackerForBodyPositionOrEmpty(allTracekrs, TrackerPosition.CHEST, TrackerPosition.WAIST);
|
||||
this.hmdTracker = server.hmdTracker;
|
||||
this.server = server;
|
||||
ComputedHumanPoseTracker cwt = null;
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package io.eiren.vr.processor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum TrackerBodyPosition {
|
||||
|
||||
NONE(""),
|
||||
HMD("body:HMD"),
|
||||
CHEST("body:chest"),
|
||||
WAIST("body:waist"),
|
||||
LEFT_LEG("body:left_leg"),
|
||||
RIGHT_LEG("body:right_leg"),
|
||||
LEFT_ANKLE("body:left_ankle"),
|
||||
RIGHT_ANKLE("body:right_ankle"),
|
||||
LEFT_FOOT("body:left_foot"),
|
||||
RIGHT_FOOT("body:right_foot"),
|
||||
LEFT_CONTROLLER("body:left_controller"),
|
||||
RIGHT_CONTROLLER("body:right_conroller"),
|
||||
;
|
||||
|
||||
public final String designation;
|
||||
|
||||
public static final TrackerBodyPosition[] values = values();
|
||||
private static final Map<String, TrackerBodyPosition> byDesignation = new HashMap<>();
|
||||
|
||||
private TrackerBodyPosition(String designation) {
|
||||
this.designation = designation;
|
||||
}
|
||||
|
||||
public static TrackerBodyPosition getByDesignation(String designation) {
|
||||
return designation == null ? null : byDesignation.get(designation.toLowerCase());
|
||||
}
|
||||
|
||||
static {
|
||||
for(TrackerBodyPosition tbp : values())
|
||||
byDesignation.put(tbp.designation.toLowerCase(), tbp);
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,28 @@ package io.eiren.vr.trackers;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public class ComputedTracker implements Tracker {
|
||||
public class ComputedTracker implements Tracker, TrackerWithTPS {
|
||||
|
||||
public final Vector3f position = new Vector3f();
|
||||
public final Quaternion rotation = new Quaternion();
|
||||
protected final String name;
|
||||
protected final String serial;
|
||||
protected TrackerStatus status = TrackerStatus.DISCONNECTED;
|
||||
public TrackerBodyPosition bodyPosition = null;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
protected final boolean hasRotation;
|
||||
protected final boolean hasPosition;
|
||||
protected final int trackerId;
|
||||
|
||||
public ComputedTracker(String name, boolean hasRotation, boolean hasPosition) {
|
||||
public ComputedTracker(int trackerId, String serial, String name, boolean hasRotation, boolean hasPosition) {
|
||||
this.name = name;
|
||||
this.serial = serial;
|
||||
this.hasRotation = hasRotation;
|
||||
this.hasPosition = hasPosition;
|
||||
this.trackerId = trackerId;
|
||||
}
|
||||
|
||||
public ComputedTracker(int trackerId, String name, boolean hasRotation, boolean hasPosition) {
|
||||
this(trackerId, name, name, hasRotation, hasPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -30,12 +36,17 @@ public class ComputedTracker implements Tracker {
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
// Loading a config is an act of user editing, therefore it shouldn't not be allowed if editing is not allowed
|
||||
if (userEditable()) {
|
||||
bodyPosition = TrackerBodyPosition.getByDesignation(config.designation);
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.serial;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@@ -74,12 +85,12 @@ public class ComputedTracker implements Tracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerBodyPosition getBodyPosition() {
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerBodyPosition position) {
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
|
||||
@@ -87,6 +98,10 @@ public class ComputedTracker implements Tracker {
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
@@ -106,4 +121,14 @@ public class ComputedTracker implements Tracker {
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
}
|
||||
|
||||
9
src/main/java/io/eiren/vr/trackers/DeviceType.java
Normal file
9
src/main/java/io/eiren/vr/trackers/DeviceType.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
public enum DeviceType {
|
||||
HMD,
|
||||
CONTROLLER,
|
||||
TRACKER,
|
||||
TRACKING_REFERENCE,
|
||||
;
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
import io.eiren.util.BufferedTimer;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public class HMDTracker extends ComputedTracker implements TrackerWithTPS {
|
||||
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public HMDTracker(String name) {
|
||||
super(name, true, true);
|
||||
setBodyPosition(TrackerBodyPosition.HMD);
|
||||
super(0, name, true, true);
|
||||
setBodyPosition(TrackerPosition.HMD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.math.FloatMath;
|
||||
import io.eiren.util.BufferedTimer;
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
|
||||
@@ -21,8 +20,10 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
protected final Quaternion correction = new Quaternion();
|
||||
protected TrackerMountingRotation mounting = null;
|
||||
protected TrackerStatus status = TrackerStatus.OK;
|
||||
protected final int trackerId;
|
||||
|
||||
protected final String name;
|
||||
protected final String descriptiveName;
|
||||
protected final TrackersUDPServer server;
|
||||
protected float confidence = 0;
|
||||
protected float batteryVoltage = 0;
|
||||
@@ -37,11 +38,13 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
|
||||
public StringBuilder serialBuffer = new StringBuilder();
|
||||
long lastSerialUpdate = 0;
|
||||
public TrackerBodyPosition bodyPosition = null;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
|
||||
public IMUTracker(String name, TrackersUDPServer server) {
|
||||
public IMUTracker(int trackerId, String name, String descriptiveName, TrackersUDPServer server) {
|
||||
this.name = name;
|
||||
this.server = server;
|
||||
this.trackerId = trackerId;
|
||||
this.descriptiveName = descriptiveName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,7 +67,7 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
bodyPosition = TrackerBodyPosition.getByDesignation(config.designation);
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,12 +191,12 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerBodyPosition getBodyPosition() {
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerBodyPosition position) {
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
|
||||
@@ -201,6 +204,31 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
public boolean userEditable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.descriptiveName;
|
||||
}
|
||||
|
||||
public enum CalibrationAccuracy {
|
||||
|
||||
@@ -228,19 +256,4 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
byStatus[ca.status] = ca;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ public class MPUTracker extends IMUTracker {
|
||||
|
||||
public ConfigurationData newCalibrationData;
|
||||
|
||||
public MPUTracker(String name, TrackersUDPServer server) {
|
||||
super(name, server);
|
||||
public MPUTracker(int trackerId, String name, String descriptiveName, TrackersUDPServer server) {
|
||||
super(trackerId, name, descriptiveName, server);
|
||||
}
|
||||
|
||||
public static class ConfigurationData {
|
||||
|
||||
@@ -3,8 +3,6 @@ package io.eiren.vr.trackers;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
|
||||
public final E tracker;
|
||||
@@ -133,12 +131,12 @@ public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerBodyPosition getBodyPosition() {
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return tracker.getBodyPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerBodyPosition position) {
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
tracker.setBodyPosition(position);
|
||||
}
|
||||
|
||||
@@ -161,4 +159,14 @@ public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
public boolean isComputed() {
|
||||
return tracker.isComputed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return tracker.getTrackerId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return tracker.getDescriptiveName();
|
||||
}
|
||||
}
|
||||
|
||||
6
src/main/java/io/eiren/vr/trackers/ShareableTracker.java
Normal file
6
src/main/java/io/eiren/vr/trackers/ShareableTracker.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
public interface ShareableTracker extends Tracker {
|
||||
|
||||
public TrackerRole getTrackerRole();
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public interface Tracker {
|
||||
|
||||
public static final AtomicInteger nextLocalTrackerId = new AtomicInteger();
|
||||
|
||||
public boolean getPosition(Vector3f store);
|
||||
|
||||
public boolean getRotation(Quaternion store);
|
||||
@@ -27,9 +29,9 @@ public interface Tracker {
|
||||
|
||||
public void tick();
|
||||
|
||||
public TrackerBodyPosition getBodyPosition();
|
||||
public TrackerPosition getBodyPosition();
|
||||
|
||||
public void setBodyPosition(TrackerBodyPosition position);
|
||||
public void setBodyPosition(TrackerPosition position);
|
||||
|
||||
public boolean userEditable();
|
||||
|
||||
@@ -38,4 +40,14 @@ public interface Tracker {
|
||||
public boolean hasPosition();
|
||||
|
||||
public boolean isComputed();
|
||||
|
||||
public int getTrackerId();
|
||||
|
||||
public default String getDescriptiveName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
public static int getNextLocalTrackerId() {
|
||||
return nextLocalTrackerId.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,20 @@ public class TrackerConfig {
|
||||
|
||||
public final String trackerName;
|
||||
public String designation;
|
||||
public String description;
|
||||
public boolean hide;
|
||||
public Quaternion adjustment;
|
||||
public String mountingRotation;
|
||||
|
||||
public TrackerConfig(String trackerName) {
|
||||
this.trackerName = trackerName;
|
||||
public TrackerConfig(Tracker tracker) {
|
||||
this.trackerName = tracker.getName();
|
||||
this.description = tracker.getDescriptiveName();
|
||||
this.designation = tracker.getBodyPosition() != null ? tracker.getBodyPosition().designation : null;
|
||||
}
|
||||
|
||||
public TrackerConfig(YamlNode node) {
|
||||
this.trackerName = node.getString("name");
|
||||
this.description = node.getString("description");
|
||||
this.designation = node.getString("designation");
|
||||
this.hide = node.getBoolean("hide", false);
|
||||
this.mountingRotation = node.getString("rotation");
|
||||
@@ -54,5 +58,10 @@ public class TrackerConfig {
|
||||
} else {
|
||||
configNode.removeProperty("rotation");
|
||||
}
|
||||
if(description != null) {
|
||||
configNode.setProperty("description", description);
|
||||
} else {
|
||||
configNode.removeProperty("description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
src/main/java/io/eiren/vr/trackers/TrackerPosition.java
Normal file
54
src/main/java/io/eiren/vr/trackers/TrackerPosition.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum TrackerPosition {
|
||||
|
||||
NONE("", TrackerRole.NONE),
|
||||
HMD("HMD", TrackerRole.HMD),
|
||||
CHEST("body:chest", TrackerRole.CHEST),
|
||||
WAIST("body:waist", TrackerRole.WAIST),
|
||||
LEFT_LEG("body:left_leg", TrackerRole.LEFT_KNEE),
|
||||
RIGHT_LEG("body:right_leg", TrackerRole.RIGHT_KNEE),
|
||||
LEFT_ANKLE("body:left_ankle", null),
|
||||
RIGHT_ANKLE("body:right_ankle", null),
|
||||
LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT),
|
||||
RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT),
|
||||
LEFT_CONTROLLER("body:left_controller", TrackerRole.LEFT_CONTROLLER),
|
||||
RIGHT_CONTROLLER("body:right_conroller", TrackerRole.RIGHT_CONTROLLER),
|
||||
;
|
||||
|
||||
public final String designation;
|
||||
public final TrackerRole trackerRole;
|
||||
|
||||
public static final TrackerPosition[] values = values();
|
||||
private static final Map<String, TrackerPosition> byDesignation = new HashMap<>();
|
||||
private static final EnumMap<TrackerRole, TrackerPosition> byRole = new EnumMap<>(TrackerRole.class);
|
||||
|
||||
private TrackerPosition(String designation, TrackerRole trackerRole) {
|
||||
this.designation = designation;
|
||||
this.trackerRole = trackerRole;
|
||||
}
|
||||
|
||||
public static TrackerPosition getByDesignation(String designation) {
|
||||
return designation == null ? null : byDesignation.get(designation.toLowerCase());
|
||||
}
|
||||
|
||||
public static TrackerPosition getByRole(TrackerRole role) {
|
||||
return byRole.get(role);
|
||||
}
|
||||
|
||||
static {
|
||||
for(TrackerPosition tbp : values()) {
|
||||
byDesignation.put(tbp.designation.toLowerCase(), tbp);
|
||||
if(tbp.trackerRole != null) {
|
||||
TrackerPosition old = byRole.get(tbp.trackerRole);
|
||||
if(old != null)
|
||||
throw new AssertionError("Only one tracker position can match tracker role. " + tbp.trackerRole + " is occupied by " + old + " when adding " + tbp);
|
||||
byRole.put(tbp.trackerRole, tbp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/main/java/io/eiren/vr/trackers/TrackerRole.java
Normal file
55
src/main/java/io/eiren/vr/trackers/TrackerRole.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package io.eiren.vr.trackers;
|
||||
|
||||
public enum TrackerRole {
|
||||
|
||||
NONE(0, "", "", null),
|
||||
WAIST(1, "vive_tracker_waist", "TrackerRole_Waist", DeviceType.TRACKER),
|
||||
LEFT_FOOT(2, "vive_tracker_left_foot", "TrackerRole_LeftFoot", DeviceType.TRACKER),
|
||||
RIGHT_FOOT(3, "vive_tracker_right_foot", "TrackerRole_RightFoot", DeviceType.TRACKER),
|
||||
CHEST(4, "vive_tracker_chest", "TrackerRole_Chest", DeviceType.TRACKER),
|
||||
LEFT_KNEE(5, "vive_tracker_left_knee", "TrackerRole_LeftKnee", DeviceType.TRACKER),
|
||||
RIGHT_KNEE(6, "vive_tracker_right_knee", "TrackerRole_RightKnee", DeviceType.TRACKER),
|
||||
LEFT_ELBOW(7, "vive_tracker_left_elbow", "TrackerRole_LeftElbow", DeviceType.TRACKER),
|
||||
RIGHT_ELBOW(8, "vive_tracker_right_elbow", "TrackerRole_RightElbow", DeviceType.TRACKER),
|
||||
LEFT_SHOULDER(9, "vive_tracker_left_shoulder", "TrackerRole_LeftShoulder", DeviceType.TRACKER),
|
||||
RIGHT_SHOULDER(10, "vive_tracker_right_shoulder", "TrackerRole_RightShoulder", DeviceType.TRACKER),
|
||||
LEFT_HAND(11, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.TRACKER),
|
||||
RIGHT_HAND(12, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.TRACKER),
|
||||
LEFT_CONTROLLER(13, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.CONTROLLER),
|
||||
RIGHT_CONTROLLER(14, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.CONTROLLER),
|
||||
HEAD(15, "", "", DeviceType.TRACKER),
|
||||
NECK(16, "", "", DeviceType.TRACKER),
|
||||
CAMERA(17, "vive_tracker_camera", "TrackerRole_Camera", DeviceType.TRACKER),
|
||||
KEYBOARD(18, "vive_tracker_keyboard", "TrackerRole_Keyboard", DeviceType.TRACKER),
|
||||
HMD(19, "", "", DeviceType.HMD),
|
||||
BEACON(20, "", "", DeviceType.TRACKING_REFERENCE),
|
||||
GENERIC_CONTROLLER(21, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.CONTROLLER),
|
||||
;
|
||||
|
||||
public final int id;
|
||||
public final String roleHint;
|
||||
public final String viveRole;
|
||||
public final DeviceType deviceType;
|
||||
|
||||
public static final TrackerRole[] values = values();
|
||||
private static final TrackerRole[] byId = new TrackerRole[22];
|
||||
|
||||
private TrackerRole(int id, String roleHint, String viveRole, DeviceType deviceType) {
|
||||
this.id = id;
|
||||
this.roleHint = roleHint;
|
||||
this.viveRole = viveRole;
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public static TrackerRole getById(int id) {
|
||||
return id < 0 || id >= byId.length ? null : byId[id];
|
||||
}
|
||||
|
||||
static {
|
||||
for(TrackerRole tr : values) {
|
||||
if(byId[tr.id] != null)
|
||||
throw new AssertionError("Tracker role id " + tr.id + " occupied by " + byId[tr.id] + " when adding " + tr);
|
||||
byId[tr.id] = tr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,12 @@ package io.eiren.vr.trackers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.eiren.vr.processor.TrackerBodyPosition;
|
||||
|
||||
public class TrackerUtils {
|
||||
|
||||
private TrackerUtils() {
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerBodyPosition position) {
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerPosition position) {
|
||||
for(int i = 0; i < allTrackers.length; ++i) {
|
||||
T t = allTrackers[i];
|
||||
if(t != null && t.getBodyPosition() == position)
|
||||
@@ -18,7 +16,7 @@ public class TrackerUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerBodyPosition position) {
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerPosition position) {
|
||||
for(int i = 0; i < allTrackers.size(); ++i) {
|
||||
T t = allTrackers.get(i);
|
||||
if(t != null && t.getBodyPosition() == position)
|
||||
@@ -27,37 +25,37 @@ public class TrackerUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerBodyPosition position, TrackerBodyPosition altPosition) {
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerPosition position, TrackerPosition altPosition) {
|
||||
T t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if(t != null)
|
||||
return t;
|
||||
return findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerBodyPosition position, TrackerBodyPosition altPosition) {
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerPosition position, TrackerPosition altPosition) {
|
||||
T t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if(t != null)
|
||||
return t;
|
||||
return findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
}
|
||||
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(List<? extends Tracker> allTrackers, TrackerBodyPosition position, TrackerBodyPosition altPosition) {
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(List<? extends Tracker> allTrackers, TrackerPosition position, TrackerPosition altPosition) {
|
||||
Tracker t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if(t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if(t != null)
|
||||
return t;
|
||||
return new ComputedTracker("Empty tracker", false, false);
|
||||
return new ComputedTracker(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(Tracker[] allTrackers, TrackerBodyPosition position, TrackerBodyPosition altPosition) {
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(Tracker[] allTrackers, TrackerPosition position, TrackerPosition altPosition) {
|
||||
Tracker t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if(t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if(t != null)
|
||||
return t;
|
||||
return new ComputedTracker("Empty tracker", false, false);
|
||||
return new ComputedTracker(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
@@ -103,7 +104,9 @@ public class TrackersUDPServer extends Thread {
|
||||
firmware.append("owoTrack");
|
||||
isOwo = true;
|
||||
}
|
||||
IMUTracker imu = new IMUTracker("udp:/" + handshakePacket.getAddress().toString(), this);
|
||||
String trackerName = macString != null ? "udp://" + macString : "udp:/" + handshakePacket.getAddress().toString();
|
||||
String descriptiveName = "udp:/" + handshakePacket.getAddress().toString();
|
||||
IMUTracker imu = new IMUTracker(Tracker.getNextLocalTrackerId(), trackerName, descriptiveName, this);
|
||||
ReferenceAdjustedTracker<IMUTracker> adjustedTracker = new ReferenceAdjustedTracker<>(imu);
|
||||
trackersConsumer.accept(adjustedTracker);
|
||||
sensor = new TrackerConnection(imu, handshakePacket.getSocketAddress());
|
||||
@@ -114,16 +117,16 @@ public class TrackersUDPServer extends Thread {
|
||||
trackers.add(sensor);
|
||||
trackersMap.put(addr, sensor);
|
||||
}
|
||||
System.out.println("[TrackerServer] Sensor " + i + " added with address " + handshakePacket.getSocketAddress() + ". Board type: " + boardType + ", imu type: " + imuType + ", firmware: " + firmware + " (" + firmwareBuild + "), mac: " + macString);
|
||||
System.out.println("[TrackerServer] Sensor " + i + " added with address " + handshakePacket.getSocketAddress() + ". Board type: " + boardType + ", imu type: " + imuType + ", firmware: " + firmware + " (" + firmwareBuild + "), mac: " + macString + ", name: " + trackerName);
|
||||
}
|
||||
sensor.tracker.setStatus(TrackerStatus.OK);
|
||||
sensor.sensors.get(0).setStatus(TrackerStatus.OK);
|
||||
socket.send(new DatagramPacket(HANDSHAKE_BUFFER, HANDSHAKE_BUFFER.length, handshakePacket.getAddress(), handshakePacket.getPort()));
|
||||
}
|
||||
|
||||
private void setUpAuxilarySensor(TrackerConnection connection) throws IOException {
|
||||
System.out.println("[TrackerServer] Setting up auxilary sensor for " + connection.tracker.getName());
|
||||
IMUTracker imu = new IMUTracker(connection.tracker.getName() + "/1", this);
|
||||
connection.secondTracker = imu;
|
||||
private void setUpAuxilarySensor(TrackerConnection connection, int trackerId) throws IOException {
|
||||
System.out.println("[TrackerServer] Setting up auxilary sensor for " + connection.sensors.get(0).getName());
|
||||
IMUTracker imu = new IMUTracker(Tracker.getNextLocalTrackerId(), connection.sensors.get(0).getName() + "/" + trackerId, connection.sensors.get(0).getDescriptiveName() + "/" + trackerId, this);
|
||||
connection.sensors.put(trackerId, imu);
|
||||
ReferenceAdjustedTracker<IMUTracker> adjustedTracker = new ReferenceAdjustedTracker<>(imu);
|
||||
trackersConsumer.accept(adjustedTracker);
|
||||
System.out.println("[TrackerServer] Sensor added with address " + imu.getName());
|
||||
@@ -166,9 +169,9 @@ public class TrackersUDPServer extends Thread {
|
||||
buf.set(bb.getFloat(), bb.getFloat(), bb.getFloat(), bb.getFloat());
|
||||
offset.mult(buf, buf);
|
||||
if(packetId == 1) {
|
||||
tracker = connection.tracker;
|
||||
tracker = connection.sensors.get(0);
|
||||
} else {
|
||||
tracker = connection.secondTracker;
|
||||
tracker = connection.sensors.get(1);
|
||||
}
|
||||
if(tracker == null)
|
||||
break;
|
||||
@@ -182,11 +185,7 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
bb.getLong();
|
||||
int sensorId = bb.get() & 0xFF;
|
||||
if(sensorId == 0) {
|
||||
tracker = connection.tracker;
|
||||
} else if(sensorId == 1) {
|
||||
tracker = connection.secondTracker;
|
||||
}
|
||||
tracker = connection.sensors.get(sensorId);
|
||||
if(tracker == null)
|
||||
break;
|
||||
|
||||
@@ -215,11 +214,7 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
bb.getLong();
|
||||
sensorId = bb.get() & 0xFF;
|
||||
if(sensorId == 0) {
|
||||
tracker = connection.tracker;
|
||||
} else if(sensorId == 1) {
|
||||
tracker = connection.secondTracker;
|
||||
}
|
||||
tracker = connection.sensors.get(sensorId);
|
||||
if(tracker == null)
|
||||
break;
|
||||
float accuracyInfo = bb.getFloat();
|
||||
@@ -230,7 +225,7 @@ public class TrackersUDPServer extends Thread {
|
||||
if(connection == null)
|
||||
break;
|
||||
bb.getLong();
|
||||
connection.tracker.gyroVector.set(bb.getFloat(), bb.getFloat(), bb.getFloat());
|
||||
connection.sensors.get(0).gyroVector.set(bb.getFloat(), bb.getFloat(), bb.getFloat());
|
||||
break;
|
||||
case 4:
|
||||
if(connection == null)
|
||||
@@ -239,7 +234,7 @@ public class TrackersUDPServer extends Thread {
|
||||
float x = bb.getFloat();
|
||||
float z = bb.getFloat();
|
||||
float y = bb.getFloat();
|
||||
connection.tracker.accelVector.set(x, y, z);
|
||||
connection.sensors.get(0).accelVector.set(x, y, z);
|
||||
break;
|
||||
case 5:
|
||||
if(connection == null)
|
||||
@@ -250,23 +245,7 @@ public class TrackersUDPServer extends Thread {
|
||||
x = bb.getFloat();
|
||||
z = bb.getFloat();
|
||||
y = bb.getFloat();
|
||||
connection.tracker.magVector.set(x, y, z);
|
||||
break;
|
||||
case 6: // PACKET_RAW_CALIBRATION_DATA
|
||||
if(connection == null)
|
||||
break;
|
||||
if(connection.isOwoTrack)
|
||||
break;
|
||||
bb.getLong();
|
||||
//sensor.rawCalibrationData.add(new double[] {bb.getInt(), bb.getInt(), bb.getInt(), bb.getInt(), bb.getInt(), bb.getInt()});
|
||||
break;
|
||||
case 7: // PACKET_GYRO_CALIBRATION_DATA
|
||||
if(connection == null)
|
||||
break;
|
||||
if(connection.isOwoTrack)
|
||||
break;
|
||||
bb.getLong();
|
||||
//sensor.gyroCalibrationData = new double[] {bb.getFloat(), bb.getFloat(), bb.getFloat()};
|
||||
connection.sensors.get(0).magVector.set(x, y, z);
|
||||
break;
|
||||
case 8: // PACKET_CONFIG
|
||||
if(connection == null)
|
||||
@@ -275,7 +254,7 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
bb.getLong();
|
||||
MPUTracker.ConfigurationData data = new MPUTracker.ConfigurationData(bb);
|
||||
Consumer<String> dataConsumer = calibrationDataRequests.remove(connection.tracker);
|
||||
Consumer<String> dataConsumer = calibrationDataRequests.remove(connection.sensors.get(0));
|
||||
if(dataConsumer != null) {
|
||||
dataConsumer.accept(data.toTextMatrix());
|
||||
}
|
||||
@@ -289,7 +268,7 @@ public class TrackersUDPServer extends Thread {
|
||||
float mx = bb.getFloat();
|
||||
float my = bb.getFloat();
|
||||
float mz = bb.getFloat();
|
||||
connection.tracker.confidence = (float) Math.sqrt(mx * mx + my * my + mz * mz);
|
||||
connection.sensors.get(0).confidence = (float) Math.sqrt(mx * mx + my * my + mz * mz);
|
||||
break;
|
||||
case 10: // PACKET_PING_PONG:
|
||||
if(connection == null)
|
||||
@@ -298,7 +277,7 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
int pingId = bb.getInt();
|
||||
if(connection.lastPingPacketId == pingId) {
|
||||
tracker = connection.tracker;
|
||||
tracker = connection.sensors.get(0);
|
||||
tracker.ping = (int) (System.currentTimeMillis() - connection.lastPingPacketTime) / 2;
|
||||
}
|
||||
break;
|
||||
@@ -307,7 +286,7 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
if(connection.isOwoTrack)
|
||||
break;
|
||||
tracker = connection.tracker;
|
||||
tracker = connection.sensors.get(0);
|
||||
bb.getLong();
|
||||
int length = bb.getInt();
|
||||
for(int i = 0; i < length; ++i) {
|
||||
@@ -325,7 +304,7 @@ public class TrackersUDPServer extends Thread {
|
||||
case 12: // PACKET_BATTERY_VOLTAGE
|
||||
if(connection == null)
|
||||
break;
|
||||
tracker = connection.tracker;
|
||||
tracker = connection.sensors.get(0);
|
||||
bb.getLong();
|
||||
tracker.setBatteryVoltage(bb.getFloat());
|
||||
break;
|
||||
@@ -334,14 +313,11 @@ public class TrackersUDPServer extends Thread {
|
||||
break;
|
||||
if(connection.isOwoTrack)
|
||||
break;
|
||||
tracker = connection.tracker;
|
||||
bb.getLong();
|
||||
sensorId = bb.get() & 0xFF;
|
||||
if(sensorId == 0) {
|
||||
tracker = connection.tracker;
|
||||
} else if(sensorId == 1) {
|
||||
tracker = connection.secondTracker;
|
||||
}
|
||||
tracker = connection.sensors.get(sensorId);
|
||||
if(tracker == null)
|
||||
break;
|
||||
int tap = bb.get() & 0xFF;
|
||||
BnoTap tapObj = new BnoTap(tap);
|
||||
System.out.println("[TrackerServer] Tap packet received from " + tracker.getName() + "/" + sensorId + ": " + tapObj + " (b" + Integer.toBinaryString(tap) + ")");
|
||||
@@ -352,7 +328,7 @@ public class TrackersUDPServer extends Thread {
|
||||
System.out.println("[TrackerServer] Reset recieved from " + recieve.getSocketAddress() + ": " + reason);
|
||||
if(connection == null)
|
||||
break;
|
||||
tracker = connection.tracker;
|
||||
tracker = connection.sensors.get(0);
|
||||
tracker.setStatus(TrackerStatus.ERROR);
|
||||
break;
|
||||
case 15: // PACKET_SENSOR_INFO
|
||||
@@ -361,15 +337,15 @@ public class TrackersUDPServer extends Thread {
|
||||
bb.getLong();
|
||||
sensorId = bb.get() & 0xFF;
|
||||
int sensorStatus = bb.get() & 0xFF;
|
||||
if(sensorId == 1 && sensorStatus == 1 && connection.secondTracker == null) {
|
||||
setUpAuxilarySensor(connection);
|
||||
if(sensorId > 0 && sensorStatus == 1 && !connection.sensors.containsKey(sensorId)) {
|
||||
setUpAuxilarySensor(connection, sensorId);
|
||||
}
|
||||
bb.rewind();
|
||||
bb.putInt(15);
|
||||
bb.put((byte) sensorId);
|
||||
bb.put((byte) sensorStatus);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), connection.address));
|
||||
System.out.println("[TrackerServer] Sensor info for " + connection.tracker.getName() + "/" + sensorId + ": " + sensorStatus);
|
||||
System.out.println("[TrackerServer] Sensor info for " + connection.sensors.get(0).getName() + "/" + sensorId + ": " + sensorStatus);
|
||||
break;
|
||||
default:
|
||||
System.out.println("[TrackerServer] Unknown data received: " + packetId + " from " + recieve.getSocketAddress());
|
||||
@@ -384,18 +360,20 @@ public class TrackersUDPServer extends Thread {
|
||||
synchronized(trackers) {
|
||||
for(int i = 0; i < trackers.size(); ++i) {
|
||||
TrackerConnection conn = trackers.get(i);
|
||||
IMUTracker tracker = conn.tracker;
|
||||
IMUTracker tracker = conn.sensors.get(0);
|
||||
socket.send(new DatagramPacket(KEEPUP_BUFFER, KEEPUP_BUFFER.length, conn.address));
|
||||
if(conn.lastPacket + 1000 < System.currentTimeMillis()) {
|
||||
if(tracker.getStatus() != TrackerStatus.DISCONNECTED) {
|
||||
tracker.setStatus(TrackerStatus.DISCONNECTED);
|
||||
if(conn.secondTracker != null)
|
||||
conn.secondTracker.setStatus(TrackerStatus.DISCONNECTED);
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while(iterator.hasNext())
|
||||
iterator.next().setStatus(TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
} else if(tracker.getStatus() != TrackerStatus.ERROR && tracker.getStatus() != TrackerStatus.BUSY) {
|
||||
tracker.setStatus(TrackerStatus.OK);
|
||||
if(conn.secondTracker != null)
|
||||
conn.secondTracker.setStatus(TrackerStatus.OK);
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while(iterator.hasNext())
|
||||
iterator.next().setStatus(TrackerStatus.OK);
|
||||
}
|
||||
if(tracker.serialBuffer.length() > 0) {
|
||||
if(tracker.lastSerialUpdate + 500L < System.currentTimeMillis()) {
|
||||
@@ -426,8 +404,7 @@ public class TrackersUDPServer extends Thread {
|
||||
|
||||
private class TrackerConnection {
|
||||
|
||||
IMUTracker tracker;
|
||||
IMUTracker secondTracker;
|
||||
Map<Integer, IMUTracker> sensors = new HashMap<>();
|
||||
SocketAddress address;
|
||||
public long lastPacket = System.currentTimeMillis();
|
||||
public int lastPingPacketId = -1;
|
||||
@@ -435,7 +412,7 @@ public class TrackersUDPServer extends Thread {
|
||||
public boolean isOwoTrack = false;
|
||||
|
||||
public TrackerConnection(IMUTracker tracker, SocketAddress address) {
|
||||
this.tracker = tracker;
|
||||
this.sensors.put(0, tracker);
|
||||
this.address = address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@ package io.eiren.vr.trackers;
|
||||
|
||||
import io.eiren.util.BufferedTimer;
|
||||
|
||||
public class SteamVRTracker extends ComputedTracker implements TrackerWithTPS {
|
||||
public class VRTracker extends ComputedTracker {
|
||||
|
||||
public final int id;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public SteamVRTracker(int id, String name, boolean hasRotation, boolean hasPosition) {
|
||||
super(name, hasRotation, hasPosition);
|
||||
this.id = id;
|
||||
public VRTracker(int id, String serial, String name, boolean hasRotation, boolean hasPosition) {
|
||||
super(id, serial, name, hasRotation, hasPosition);
|
||||
}
|
||||
|
||||
public VRTracker(int id, String name, boolean hasRotation, boolean hasPosition) {
|
||||
super(id, name, name, hasRotation, hasPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -8,6 +8,7 @@ import io.eiren.util.StringUtils;
|
||||
import io.eiren.vr.processor.TransformNode;
|
||||
import io.eiren.vr.trackers.ComputedTracker;
|
||||
import io.eiren.vr.trackers.ReferenceAdjustedTracker;
|
||||
import io.eiren.vr.trackers.Tracker;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
@@ -67,7 +68,7 @@ public class ReferenceAdjustmentsTests {
|
||||
|
||||
public void checkReferenceAdjustmentFull(Quaternion trackerQuat, int refPitch, int refYaw, int refRoll) {
|
||||
Quaternion referenceQuat = q(refPitch, refYaw, refRoll);
|
||||
ComputedTracker tracker = new ComputedTracker("test", true, false);
|
||||
ComputedTracker tracker = new ComputedTracker(Tracker.getNextLocalTrackerId(), "test", true, false);
|
||||
tracker.rotation.set(trackerQuat);
|
||||
ReferenceAdjustedTracker<ComputedTracker> adj = new ReferenceAdjustedTracker<>(tracker);
|
||||
adj.resetFull(referenceQuat);
|
||||
@@ -86,7 +87,7 @@ public class ReferenceAdjustmentsTests {
|
||||
|
||||
public void checkReferenceAdjustmentYaw(Quaternion trackerQuat, int refPitch, int refYaw, int refRoll) {
|
||||
Quaternion referenceQuat = q(refPitch, refYaw, refRoll);
|
||||
ComputedTracker tracker = new ComputedTracker("test", true, false);
|
||||
ComputedTracker tracker = new ComputedTracker(Tracker.getNextLocalTrackerId(), "test", true, false);
|
||||
tracker.rotation.set(trackerQuat);
|
||||
ReferenceAdjustedTracker<ComputedTracker> adj = new ReferenceAdjustedTracker<>(tracker);
|
||||
adj.resetYaw(referenceQuat);
|
||||
@@ -98,7 +99,7 @@ public class ReferenceAdjustmentsTests {
|
||||
|
||||
private void testAdjustedTrackerRotation(Quaternion trackerQuat, int refPitch, int refYaw, int refRoll) {
|
||||
Quaternion referenceQuat = q(refPitch, refYaw, refRoll);
|
||||
ComputedTracker tracker = new ComputedTracker("test", true, false);
|
||||
ComputedTracker tracker = new ComputedTracker(Tracker.getNextLocalTrackerId(), "test", true, false);
|
||||
tracker.rotation.set(trackerQuat);
|
||||
ReferenceAdjustedTracker<ComputedTracker> adj = new ReferenceAdjustedTracker<>(tracker);
|
||||
adj.resetFull(referenceQuat);
|
||||
|
||||
Reference in New Issue
Block a user