mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Refactored TrackerPosition (#181)
This commit is contained in:
@@ -8,7 +8,7 @@ import dev.slimevr.protocol.ProtocolAPI;
|
||||
import dev.slimevr.serial.SerialHandler;
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.processor.HumanPoseProcessor;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import dev.slimevr.vr.trackers.*;
|
||||
import dev.slimevr.vr.trackers.udp.TrackersUDPServer;
|
||||
import dev.slimevr.websocketapi.WebSocketVRBridge;
|
||||
@@ -194,7 +194,7 @@ public class VRServer extends Thread {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
public void addSkeletonUpdatedCallback(Consumer<Skeleton> consumer) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.addSkeletonUpdatedCallback(consumer);
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.jme3.math.Vector3f;
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.poserecorder.*;
|
||||
import dev.slimevr.vr.processor.HumanPoseProcessor;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfig;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigValue;
|
||||
import dev.slimevr.vr.trackers.TrackerPosition;
|
||||
@@ -187,14 +187,14 @@ public class AutoBone {
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple utility method to get the {@link HumanSkeleton} from the
|
||||
* A simple utility method to get the {@link Skeleton} from the
|
||||
* {@link VRServer}
|
||||
*
|
||||
* @return The {@link HumanSkeleton} associated with the {@link VRServer},
|
||||
* or null if there is none available
|
||||
* @see {@link VRServer}, {@link HumanSkeleton}
|
||||
* @return The {@link Skeleton} associated with the {@link VRServer}, or
|
||||
* null if there is none available
|
||||
* @see {@link VRServer}, {@link Skeleton}
|
||||
*/
|
||||
private HumanSkeleton getSkeleton() {
|
||||
private Skeleton getSkeleton() {
|
||||
HumanPoseProcessor humanPoseProcessor = server != null ? server.humanPoseProcessor : null;
|
||||
return humanPoseProcessor != null ? humanPoseProcessor.getSkeleton() : null;
|
||||
}
|
||||
@@ -206,7 +206,7 @@ public class AutoBone {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean applyConfigToSkeleton(HumanSkeleton skeleton) {
|
||||
public boolean applyConfigToSkeleton(Skeleton skeleton) {
|
||||
if (skeleton == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -351,7 +351,7 @@ public class AutoBone {
|
||||
// If target height isn't specified, auto-detect
|
||||
if (targetHeight < 0f) {
|
||||
// Get the current skeleton from the server
|
||||
HumanSkeleton skeleton = getSkeleton();
|
||||
Skeleton skeleton = getSkeleton();
|
||||
if (skeleton != null) {
|
||||
// If there is a skeleton available, calculate the target height
|
||||
// from its
|
||||
@@ -647,7 +647,7 @@ public class AutoBone {
|
||||
}
|
||||
|
||||
Vector3f nodePos = skeleton
|
||||
.getComputedTracker(trackerFrame.designation.trackerRole).position;
|
||||
.getComputedTracker(trackerFrame.designation.trackerRole.get()).position;
|
||||
if (nodePos != null) {
|
||||
offset += FastMath.abs(nodePos.distance(trackerFrame.position));
|
||||
offsetCount++;
|
||||
@@ -682,13 +682,13 @@ public class AutoBone {
|
||||
}
|
||||
|
||||
Vector3f nodePos1 = skeleton1
|
||||
.getComputedTracker(trackerFrame1.designation.trackerRole).position;
|
||||
.getComputedTracker(trackerFrame1.designation.trackerRole.get()).position;
|
||||
if (nodePos1 == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3f nodePos2 = skeleton2
|
||||
.getComputedTracker(trackerFrame2.designation.trackerRole).position;
|
||||
.getComputedTracker(trackerFrame2.designation.trackerRole.get()).position;
|
||||
if (nodePos2 == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package dev.slimevr.gui;
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.gui.swing.ButtonTimer;
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigValue;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
@@ -35,7 +35,7 @@ public class SkeletonConfigGUI extends EJBagNoStretch {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
public void skeletonUpdated(Skeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import dev.slimevr.VRServer;
|
||||
import dev.slimevr.gui.swing.EJBagNoStretch;
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import io.eiren.util.StringUtils;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
import io.eiren.util.collections.FastList;
|
||||
@@ -36,7 +36,7 @@ public class SkeletonList extends EJBagNoStretch {
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
public void skeletonUpdated(Skeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
nodes.clear();
|
||||
|
||||
@@ -185,7 +185,7 @@ public class TrackersList extends EJBoxNoStretch {
|
||||
desSelect.addItem(p.name());
|
||||
}
|
||||
if (cfg.designation != null) {
|
||||
TrackerPosition p = TrackerPosition.getByDesignation(cfg.designation);
|
||||
TrackerPosition p = TrackerPosition.getByDesignation(cfg.designation).get();
|
||||
if (p != null)
|
||||
desSelect.setSelectedItem(p.name());
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public class WindowsNamedPipeBridge extends ProtobufBridge<VRTracker> implements
|
||||
);
|
||||
TrackerRole role = TrackerRole.getById(trackerAdded.getTrackerRole());
|
||||
if (role != null) {
|
||||
tracker.setBodyPosition(TrackerPosition.getByRole(role));
|
||||
tracker.setBodyPosition(TrackerPosition.getByTrackerRole(role).get());
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
|
||||
@@ -1,360 +0,0 @@
|
||||
package dev.slimevr.platform.windows;
|
||||
|
||||
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.VRServer;
|
||||
import dev.slimevr.bridge.Bridge;
|
||||
import dev.slimevr.bridge.PipeState;
|
||||
import dev.slimevr.vr.trackers.ShareableTracker;
|
||||
import dev.slimevr.vr.trackers.TrackerPosition;
|
||||
import dev.slimevr.vr.trackers.TrackerStatus;
|
||||
import dev.slimevr.vr.trackers.VRTracker;
|
||||
import io.eiren.util.collections.FastList;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
public class WindowsSteamVRPipeInputBridge extends Thread implements Bridge {
|
||||
|
||||
public static final String PipeName = "\\\\.\\pipe\\SlimeVRInput";
|
||||
private static final int MAX_COMMAND_LENGTH = 2048;
|
||||
private final byte[] buffArray = new byte[1024];
|
||||
private final VRServer server;
|
||||
private final StringBuilder commandBuilder = new StringBuilder(1024);
|
||||
private final List<VRTracker> trackers = new FastList<>();
|
||||
private final Map<Integer, VRTracker> trackersInternal = new HashMap<>();
|
||||
private final Vector3f vBuffer = new Vector3f();
|
||||
private final Quaternion qBuffer = new Quaternion();
|
||||
private final AtomicBoolean newData = new AtomicBoolean(false);
|
||||
private WindowsPipe pipe;
|
||||
|
||||
public WindowsSteamVRPipeInputBridge(VRServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
createPipes();
|
||||
while (true) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updatePipes() throws IOException {
|
||||
if (pipe.state == PipeState.OPEN) {
|
||||
IntByReference bytesAvailable = new IntByReference(0);
|
||||
if (
|
||||
Kernel32.INSTANCE
|
||||
.PeekNamedPipe(pipe.pipeHandle, null, 0, null, bytesAvailable, null)
|
||||
) {
|
||||
if (bytesAvailable.getValue() > 0) {
|
||||
while (
|
||||
Kernel32.INSTANCE
|
||||
.ReadFile(
|
||||
pipe.pipeHandle,
|
||||
buffArray,
|
||||
buffArray.length,
|
||||
bytesAvailable,
|
||||
null
|
||||
)
|
||||
) {
|
||||
int bytesRead = bytesAvailable.getValue();
|
||||
for (int i = 0; i < bytesRead; ++i) {
|
||||
char c = (char) buffArray[i];
|
||||
if (c == '\n') {
|
||||
executeInputCommand();
|
||||
commandBuilder.setLength(0);
|
||||
} else {
|
||||
commandBuilder.append(c);
|
||||
if (commandBuilder.length() >= MAX_COMMAND_LENGTH) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] Command from the pipe is too long, flushing buffer"
|
||||
);
|
||||
commandBuilder.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytesRead < buffArray.length)
|
||||
return true; // All pipe data read
|
||||
}
|
||||
} else {
|
||||
return false; // Pipe was empty, it's okay
|
||||
}
|
||||
}
|
||||
// PeekNamedPipe or ReadFile returned an error
|
||||
pipe.state = PipeState.ERROR;
|
||||
LogManager
|
||||
.severe("[SteamVRPipeInputBridge] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void executeInputCommand() throws IOException {
|
||||
String[] command = commandBuilder.toString().split(" ");
|
||||
switch (command[0]) {
|
||||
case "ADD": // Add new tracker
|
||||
if (command.length < 4) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] Error in ADD command. Command requires at least 4 arguments. Supplied: "
|
||||
+ commandBuilder
|
||||
);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
VRTracker oldTracker;
|
||||
synchronized (trackersInternal) {
|
||||
oldTracker = trackersInternal
|
||||
.put(internalTracker.getTrackerId(), internalTracker);
|
||||
}
|
||||
if (oldTracker != null) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] New tracker added with the same id. Supplied: "
|
||||
+ commandBuilder
|
||||
);
|
||||
return;
|
||||
}
|
||||
newData.set(true);
|
||||
break;
|
||||
case "UPD": // Update tracker data
|
||||
if (command.length < 9) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] Error in UPD command. Command requires at least 9 arguments. Supplied: "
|
||||
+ commandBuilder
|
||||
);
|
||||
return;
|
||||
}
|
||||
int id = Integer.parseInt(command[1]);
|
||||
double x = Double.parseDouble(command[2]);
|
||||
double y = Double.parseDouble(command[3]);
|
||||
double z = Double.parseDouble(command[4]);
|
||||
double qw = Double.parseDouble(command[5]);
|
||||
double qx = Double.parseDouble(command[6]);
|
||||
double qy = Double.parseDouble(command[7]);
|
||||
double qz = Double.parseDouble(command[8]);
|
||||
internalTracker = trackersInternal.get(id);
|
||||
if (internalTracker != null) {
|
||||
internalTracker.position.set((float) x, (float) y, (float) z);
|
||||
internalTracker.rotation.set((float) qx, (float) qy, (float) qz, (float) qw);
|
||||
internalTracker.dataTick();
|
||||
newData.set(true);
|
||||
}
|
||||
break;
|
||||
case "STA": // Update tracker status
|
||||
if (command.length < 3) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] Error in STA command. Command requires at least 3 arguments. Supplied: "
|
||||
+ commandBuilder
|
||||
);
|
||||
return;
|
||||
}
|
||||
id = Integer.parseInt(command[1]);
|
||||
int status = Integer.parseInt(command[2]);
|
||||
TrackerStatus st = TrackerStatus.getById(status);
|
||||
if (st == null) {
|
||||
LogManager
|
||||
.severe(
|
||||
"[SteamVRPipeInputBridge] Unrecognized status id. Supplied: "
|
||||
+ commandBuilder
|
||||
);
|
||||
return;
|
||||
}
|
||||
internalTracker = trackersInternal.get(id);
|
||||
if (internalTracker != null) {
|
||||
internalTracker.setStatus(st);
|
||||
newData.set(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
if (newData.getAndSet(false)) {
|
||||
if (trackers.size() < trackersInternal.size()) {
|
||||
// Add new trackers
|
||||
synchronized (trackersInternal) {
|
||||
Iterator<VRTracker> iterator = trackersInternal.values().iterator();
|
||||
internal: while (iterator.hasNext()) {
|
||||
VRTracker internalTracker = iterator.next();
|
||||
for (VRTracker t : trackers) {
|
||||
if (t.getTrackerId() == internalTracker.getTrackerId())
|
||||
continue internal;
|
||||
}
|
||||
// Tracker is not found in current trackers
|
||||
VRTracker tracker = new VRTracker(
|
||||
internalTracker.getTrackerId(),
|
||||
internalTracker.getName(),
|
||||
true,
|
||||
true
|
||||
);
|
||||
tracker.bodyPosition = internalTracker.bodyPosition;
|
||||
trackers.add(tracker);
|
||||
server.registerTracker(tracker);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VRTracker tracker : trackers) {
|
||||
VRTracker internal = trackersInternal.get(tracker.getTrackerId());
|
||||
if (internal == null)
|
||||
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))
|
||||
tracker.rotation.set(qBuffer);
|
||||
tracker.setStatus(internal.getStatus());
|
||||
tracker.dataTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// Not used, only input
|
||||
}
|
||||
|
||||
private void resetPipe() {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
// Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
|
||||
private boolean tryOpeningPipe(WindowsPipe pipe) {
|
||||
if (
|
||||
Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null)
|
||||
|| Kernel32.INSTANCE.GetLastError() == WinError.ERROR_PIPE_CONNECTED
|
||||
) {
|
||||
pipe.state = PipeState.OPEN;
|
||||
LogManager.info("[SteamVRPipeInputBridge] Pipe " + pipe.name + " is open");
|
||||
return true;
|
||||
}
|
||||
|
||||
LogManager
|
||||
.info(
|
||||
"[SteamVRPipeInputBridge] Error connecting to pipe "
|
||||
+ pipe.name
|
||||
+ ": "
|
||||
+ Kernel32.INSTANCE.GetLastError()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void createPipes() throws IOException {
|
||||
try {
|
||||
pipe = new WindowsPipe(
|
||||
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.info("[SteamVRPipeInputBridge] Pipe " + pipe.name + " created");
|
||||
if (WinBase.INVALID_HANDLE_VALUE.equals(pipe.pipeHandle))
|
||||
throw new IOException(
|
||||
"Can't open " + PipeName + " pipe: " + Kernel32.INSTANCE.GetLastError()
|
||||
);
|
||||
LogManager.info("[SteamVRPipeInputBridge] Pipes are open");
|
||||
} catch (IOException e) {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
throw 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();
|
||||
}
|
||||
|
||||
public enum SteamVRInputRoles {
|
||||
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.LEFT_FOREARM),
|
||||
RIGHT_ELBOW(TrackerPosition.RIGHT_FOREARM), LEFT_KNEE(TrackerPosition.LEFT_KNEE),
|
||||
RIGHT_KNEE(TrackerPosition.RIGHT_KNEE), WAIST(TrackerPosition.WAIST),
|
||||
CHEST(TrackerPosition.CHEST),;
|
||||
|
||||
private static final SteamVRInputRoles[] values = values();
|
||||
public final TrackerPosition bodyPosition;
|
||||
|
||||
SteamVRInputRoles(TrackerPosition slimeVrPosition) {
|
||||
this.bodyPosition = slimeVrPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public final class PoseFrameIO {
|
||||
|
||||
TrackerPosition designation = null;
|
||||
if (TrackerFrameData.DESIGNATION.check(dataFlags)) {
|
||||
designation = TrackerPosition.getByDesignation(inputStream.readUTF());
|
||||
designation = TrackerPosition.getByDesignation(inputStream.readUTF()).get();
|
||||
}
|
||||
|
||||
Quaternion rotation = null;
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.slimevr.poserecorder;
|
||||
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.vr.processor.ComputedHumanPoseTracker;
|
||||
import dev.slimevr.vr.processor.skeleton.SimpleSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigValue;
|
||||
import dev.slimevr.vr.trackers.Tracker;
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class PoseFrameSkeleton extends SimpleSkeleton {
|
||||
public class PoseFrameSkeleton extends HumanSkeleton {
|
||||
|
||||
private int frameCursor = 0;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Transform;
|
||||
import com.jme3.math.Vector3f;
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
@@ -23,7 +23,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
private float[] angleBuf = new float[3];
|
||||
private Quaternion rotBuf = new Quaternion();
|
||||
|
||||
private HumanSkeleton wrappedSkeleton;
|
||||
private Skeleton wrappedSkeleton;
|
||||
private TransformNodeWrapper rootNode;
|
||||
|
||||
public BVHFileStream(OutputStream outputStream) {
|
||||
@@ -48,7 +48,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
return bufferCount > 0 ? frameString + StringUtils.repeat(' ', bufferCount) : frameString;
|
||||
}
|
||||
|
||||
private TransformNodeWrapper wrapSkeletonIfNew(HumanSkeleton skeleton) {
|
||||
private TransformNodeWrapper wrapSkeletonIfNew(Skeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = rootNode;
|
||||
|
||||
// If the wrapped skeleton is missing or the skeleton is updated
|
||||
@@ -59,7 +59,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private TransformNodeWrapper wrapSkeleton(HumanSkeleton skeleton) {
|
||||
private TransformNodeWrapper wrapSkeleton(Skeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = wrapSkeletonNodes(skeleton.getRootNode());
|
||||
|
||||
wrappedSkeleton = skeleton;
|
||||
@@ -134,7 +134,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
public void writeHeader(Skeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
@@ -249,7 +249,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFrame(HumanSkeleton skeleton) throws IOException {
|
||||
public void writeFrame(Skeleton skeleton) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
@@ -276,7 +276,7 @@ public class BVHFileStream extends PoseDataStream {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
public void writeFooter(Skeleton skeleton) throws IOException {
|
||||
// Write the final frame count for files
|
||||
if (outputStream instanceof FileOutputStream) {
|
||||
FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.slimevr.posestreamer;
|
||||
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -22,12 +22,12 @@ public abstract class PoseDataStream implements AutoCloseable {
|
||||
this(new FileOutputStream(file));
|
||||
}
|
||||
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
public void writeHeader(Skeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
}
|
||||
|
||||
abstract void writeFrame(HumanSkeleton skeleton) throws IOException;
|
||||
abstract void writeFrame(Skeleton skeleton) throws IOException;
|
||||
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
public void writeFooter(Skeleton skeleton) throws IOException {
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.slimevr.posestreamer;
|
||||
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -10,10 +10,10 @@ public class PoseStreamer {
|
||||
|
||||
protected long frameRecordingInterval = 60L;
|
||||
|
||||
protected HumanSkeleton skeleton;
|
||||
protected Skeleton skeleton;
|
||||
protected PoseDataStream poseFileStream;
|
||||
|
||||
public PoseStreamer(HumanSkeleton skeleton) {
|
||||
public PoseStreamer(Skeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class PoseStreamer {
|
||||
this.frameRecordingInterval = intervalMs;
|
||||
}
|
||||
|
||||
public synchronized HumanSkeleton getSkeleton() {
|
||||
public synchronized Skeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.slimevr.posestreamer;
|
||||
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
|
||||
|
||||
public class ServerPoseStreamer extends TickPoseStreamer {
|
||||
@@ -19,7 +19,7 @@ public class ServerPoseStreamer extends TickPoseStreamer {
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void onSkeletonUpdated(HumanSkeleton skeleton) {
|
||||
public void onSkeletonUpdated(Skeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.slimevr.posestreamer;
|
||||
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -9,7 +9,7 @@ public class TickPoseStreamer extends PoseStreamer {
|
||||
|
||||
protected long nextFrameTimeMs = -1L;
|
||||
|
||||
public TickPoseStreamer(HumanSkeleton skeleton) {
|
||||
public TickPoseStreamer(Skeleton skeleton) {
|
||||
super(skeleton);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class TickPoseStreamer extends PoseStreamer {
|
||||
return;
|
||||
}
|
||||
|
||||
HumanSkeleton skeleton = this.skeleton;
|
||||
Skeleton skeleton = this.skeleton;
|
||||
if (skeleton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DataFeedBuilder {
|
||||
|
||||
TrackerInfo.startTrackerInfo(fbb);
|
||||
if (tracker.getBodyPosition() != null)
|
||||
TrackerInfo.addBodyPart(fbb, tracker.getBodyPosition().id);
|
||||
TrackerInfo.addBodyPart(fbb, tracker.getBodyPosition().bodyPart);
|
||||
TrackerInfo.addEditable(fbb, tracker.userEditable());
|
||||
TrackerInfo.addComputed(fbb, tracker.isComputed());
|
||||
// TODO need support: TrackerInfo.addImuType(fbb, tracker.im);
|
||||
|
||||
@@ -197,7 +197,7 @@ public class RPCHandler extends ProtocolHandler<RpcMessageHeader>
|
||||
if (tracker == null)
|
||||
return;
|
||||
|
||||
tracker.setBodyPosition(TrackerPosition.getById(req.bodyPosition()));
|
||||
tracker.setBodyPosition(TrackerPosition.getByBodyPart(req.bodyPosition()).get());
|
||||
|
||||
if (tracker instanceof ReferenceAdjustedTracker) {
|
||||
ReferenceAdjustedTracker refTracker = (ReferenceAdjustedTracker) tracker;
|
||||
|
||||
@@ -24,7 +24,8 @@ public class ComputedHumanPoseTracker extends ComputedTracker
|
||||
super(trackerId, "human://" + skeletonPosition.name(), true, true);
|
||||
this.skeletonPosition = skeletonPosition;
|
||||
this.trackerRole = role;
|
||||
this.bodyPosition = TrackerPosition.getByRole(role);
|
||||
// TODO: Use `TrackerPosition` instead of `TrackerRole`
|
||||
this.bodyPosition = TrackerPosition.getByTrackerRole(role).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,8 +2,8 @@ package dev.slimevr.vr.processor;
|
||||
|
||||
import dev.slimevr.VRServer;
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.processor.skeleton.Skeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.SimpleSkeleton;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfig;
|
||||
import dev.slimevr.vr.processor.skeleton.SkeletonConfigValue;
|
||||
import dev.slimevr.vr.trackers.*;
|
||||
@@ -18,8 +18,8 @@ public class HumanPoseProcessor {
|
||||
|
||||
private final VRServer server;
|
||||
private final List<ComputedHumanPoseTracker> computedTrackers = new FastList<>();
|
||||
private final List<Consumer<HumanSkeleton>> onSkeletonUpdated = new FastList<>();
|
||||
private HumanSkeleton skeleton;
|
||||
private final List<Consumer<Skeleton>> onSkeletonUpdated = new FastList<>();
|
||||
private Skeleton skeleton;
|
||||
|
||||
public HumanPoseProcessor(VRServer server, HMDTracker hmd) {
|
||||
this.server = server;
|
||||
@@ -105,12 +105,12 @@ public class HumanPoseProcessor {
|
||||
);
|
||||
}
|
||||
|
||||
public HumanSkeleton getSkeleton() {
|
||||
public Skeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
public void addSkeletonUpdatedCallback(Consumer<Skeleton> consumer) {
|
||||
onSkeletonUpdated.add(consumer);
|
||||
if (skeleton != null)
|
||||
consumer.accept(skeleton);
|
||||
@@ -165,8 +165,8 @@ public class HumanPoseProcessor {
|
||||
@VRServerThread
|
||||
private void updateSekeltonModel() {
|
||||
disconnectAllTrackers();
|
||||
skeleton = new SimpleSkeleton(server, computedTrackers);
|
||||
for (Consumer<HumanSkeleton> sc : onSkeletonUpdated)
|
||||
skeleton = new HumanSkeleton(server, computedTrackers);
|
||||
for (Consumer<Skeleton> sc : onSkeletonUpdated)
|
||||
sc.accept(skeleton);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.slimevr.vr.processor.skeleton;
|
||||
|
||||
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
|
||||
|
||||
public class BoneInfo {
|
||||
|
||||
public final BoneType boneType;
|
||||
public final TransformNode node;
|
||||
public float length;
|
||||
|
||||
public BoneInfo(BoneType boneType, TransformNode node) {
|
||||
this.boneType = boneType;
|
||||
this.node = node;
|
||||
updateLength();
|
||||
}
|
||||
|
||||
public void updateLength() {
|
||||
this.length = node.localTransform.getTranslation().length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package dev.slimevr.vr.processor.skeleton;
|
||||
|
||||
import solarxr_protocol.datatypes.BodyPart;
|
||||
|
||||
|
||||
/**
|
||||
* Keys for all bones in the skeleton. TODO: Some bones are deprecated because
|
||||
* they are still used as SkeletonNodeOffset, and represent both left and right
|
||||
* offsets, but they should be split into two.
|
||||
*/
|
||||
public enum BoneType {
|
||||
|
||||
HEAD(BodyPart.HMD),
|
||||
NECK(BodyPart.NECK),
|
||||
CHEST(BodyPart.CHEST),
|
||||
CHEST_TRACKER(BodyPart.CHEST),
|
||||
WAIST(BodyPart.WAIST),
|
||||
WAIST_TRACKER(BodyPart.WAIST),
|
||||
HIP(BodyPart.HIP),
|
||||
HIP_TRACKER(BodyPart.HIP),
|
||||
LEFT_HIP,
|
||||
RIGHT_HIP,
|
||||
@Deprecated
|
||||
UPPER_LEG,
|
||||
LEFT_UPPER_LEG(BodyPart.LEFT_KNEE),
|
||||
RIGHT_UPPER_LEG(BodyPart.RIGHT_KNEE),
|
||||
@Deprecated
|
||||
KNEE_TRACKER,
|
||||
LEFT_KNEE_TRACKER,
|
||||
RIGHT_KNEE_TRACKER,
|
||||
@Deprecated
|
||||
LOWER_LEG,
|
||||
LEFT_LOWER_LEG(BodyPart.LEFT_ANKLE),
|
||||
RIGHT_LOWER_LEG(BodyPart.RIGHT_ANKLE),
|
||||
@Deprecated
|
||||
FOOT,
|
||||
LEFT_FOOT(BodyPart.LEFT_FOOT),
|
||||
RIGHT_FOOT(BodyPart.RIGHT_FOOT),
|
||||
@Deprecated
|
||||
FOOT_TRACKER,
|
||||
LEFT_FOOT_TRACKER(BodyPart.LEFT_FOOT),
|
||||
RIGHT_FOOT_TRACKER(BodyPart.RIGHT_FOOT),
|
||||
@Deprecated
|
||||
CONTROLLER,
|
||||
LEFT_CONTROLLER(BodyPart.LEFT_CONTROLLER),
|
||||
RIGHT_CONTROLLER(BodyPart.RIGHT_CONTROLLER),
|
||||
@Deprecated
|
||||
LOWER_ARM,
|
||||
LEFT_LOWER_ARM(BodyPart.LEFT_FOREARM),
|
||||
RIGHT_LOWER_ARM(BodyPart.RIGHT_FOREARM),
|
||||
@Deprecated
|
||||
LOWER_ARM_HMD,
|
||||
@Deprecated
|
||||
ELBOW_TRACKER,
|
||||
LEFT_ELBOW_TRACKER,
|
||||
RIGHT_ELBOW_TRACKER,
|
||||
@Deprecated
|
||||
UPPER_ARM,
|
||||
LEFT_UPPER_ARM,
|
||||
RIGHT_UPPER_ARM,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
@Deprecated
|
||||
HAND,
|
||||
LEFT_HAND,
|
||||
RIGHT_HAND,
|
||||
@Deprecated
|
||||
HAND_TRACKER,
|
||||
LEFT_HAND_TRACKER,
|
||||
RIGHT_HAND_TRACKER;
|
||||
|
||||
public static final BoneType[] values = values();
|
||||
|
||||
public final int bodyPart;
|
||||
|
||||
private BoneType() {
|
||||
this.bodyPart = BodyPart.NONE;
|
||||
}
|
||||
|
||||
private BoneType(int associatedBodyPart) {
|
||||
this.bodyPart = associatedBodyPart;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
package dev.slimevr.vr.processor.skeleton;
|
||||
|
||||
import dev.slimevr.util.ann.VRServerThread;
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
import io.eiren.util.ann.ThreadSafe;
|
||||
|
||||
|
||||
public abstract class Skeleton {
|
||||
|
||||
@VRServerThread
|
||||
public abstract void updatePose();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract TransformNode getRootNode();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract TransformNode[] getAllNodes();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract SkeletonConfig getSkeletonConfig();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract void resetSkeletonConfig(SkeletonConfigValue config);
|
||||
|
||||
@ThreadSafe
|
||||
public void resetAllSkeletonConfigs() {
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
resetSkeletonConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersFull();
|
||||
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersYaw();
|
||||
}
|
||||
@@ -16,8 +16,8 @@ public class SkeletonConfig {
|
||||
protected final EnumMap<SkeletonConfigToggle, Boolean> toggles = new EnumMap<SkeletonConfigToggle, Boolean>(
|
||||
SkeletonConfigToggle.class
|
||||
);
|
||||
protected final EnumMap<SkeletonNodeOffset, Vector3f> nodeOffsets = new EnumMap<SkeletonNodeOffset, Vector3f>(
|
||||
SkeletonNodeOffset.class
|
||||
protected final EnumMap<BoneType, Vector3f> nodeOffsets = new EnumMap<BoneType, Vector3f>(
|
||||
BoneType.class
|
||||
);
|
||||
|
||||
protected final boolean autoUpdateOffsets;
|
||||
@@ -144,7 +144,7 @@ public class SkeletonConfig {
|
||||
|
||||
// Re-compute the affected offsets
|
||||
if (computeOffsets && autoUpdateOffsets && config.affectedOffsets != null) {
|
||||
for (SkeletonNodeOffset offset : config.affectedOffsets) {
|
||||
for (BoneType offset : config.affectedOffsets) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
@@ -227,7 +227,7 @@ public class SkeletonConfig {
|
||||
return getToggle(SkeletonConfigToggle.getByStringValue(config));
|
||||
}
|
||||
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, float x, float y, float z) {
|
||||
protected void setNodeOffset(BoneType nodeOffset, float x, float y, float z) {
|
||||
Vector3f offset = nodeOffsets.get(nodeOffset);
|
||||
|
||||
if (offset == null) {
|
||||
@@ -246,7 +246,7 @@ public class SkeletonConfig {
|
||||
}
|
||||
}
|
||||
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset) {
|
||||
protected void setNodeOffset(BoneType nodeOffset, Vector3f offset) {
|
||||
if (offset == null) {
|
||||
setNodeOffset(nodeOffset, 0f, 0f, 0f);
|
||||
return;
|
||||
@@ -255,11 +255,11 @@ public class SkeletonConfig {
|
||||
setNodeOffset(nodeOffset, offset.x, offset.y, offset.z);
|
||||
}
|
||||
|
||||
public Vector3f getNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
public Vector3f getNodeOffset(BoneType nodeOffset) {
|
||||
return nodeOffsets.getOrDefault(nodeOffset, Vector3f.ZERO);
|
||||
}
|
||||
|
||||
public void computeNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
public void computeNodeOffset(BoneType nodeOffset) {
|
||||
switch (nodeOffset) {
|
||||
case HEAD:
|
||||
setNodeOffset(nodeOffset, 0, 0, getConfig(SkeletonConfigValue.HEAD));
|
||||
@@ -302,7 +302,7 @@ public class SkeletonConfig {
|
||||
setNodeOffset(nodeOffset, getConfig(SkeletonConfigValue.HIPS_WIDTH) / 2f, 0, 0);
|
||||
break;
|
||||
|
||||
case KNEE:
|
||||
case UPPER_LEG:
|
||||
setNodeOffset(
|
||||
nodeOffset,
|
||||
0,
|
||||
@@ -314,7 +314,7 @@ public class SkeletonConfig {
|
||||
case KNEE_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case ANKLE:
|
||||
case LOWER_LEG:
|
||||
setNodeOffset(
|
||||
nodeOffset,
|
||||
0,
|
||||
@@ -345,10 +345,10 @@ public class SkeletonConfig {
|
||||
-getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Z)
|
||||
);
|
||||
break;
|
||||
case FOREARM:
|
||||
case LOWER_ARM:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case FOREARM_HMD:
|
||||
case LOWER_ARM_HMD:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case ELBOW_TRACKER:
|
||||
@@ -379,7 +379,7 @@ public class SkeletonConfig {
|
||||
}
|
||||
|
||||
public void computeAllNodeOffsets() {
|
||||
for (SkeletonNodeOffset offset : SkeletonNodeOffset.values) {
|
||||
for (BoneType offset : BoneType.values) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ public interface SkeletonConfigCallback {
|
||||
|
||||
void updateToggleState(SkeletonConfigToggle configToggle, boolean newValue);
|
||||
|
||||
void updateNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset);
|
||||
void updateNodeOffset(BoneType nodeOffset, Vector3f offset);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public enum SkeletonConfigValue {
|
||||
"headShift",
|
||||
"Head shift",
|
||||
0.1f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.HEAD }
|
||||
new BoneType[] { BoneType.HEAD }
|
||||
),
|
||||
NECK(
|
||||
2,
|
||||
@@ -19,7 +19,7 @@ public enum SkeletonConfigValue {
|
||||
"neckLength",
|
||||
"Neck length",
|
||||
0.1f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.NECK }
|
||||
new BoneType[] { BoneType.NECK }
|
||||
),
|
||||
TORSO(
|
||||
3,
|
||||
@@ -27,7 +27,7 @@ public enum SkeletonConfigValue {
|
||||
"torsoLength",
|
||||
"Torso length",
|
||||
0.56f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.WAIST }
|
||||
new BoneType[] { BoneType.WAIST }
|
||||
),
|
||||
CHEST(
|
||||
4,
|
||||
@@ -35,8 +35,8 @@ public enum SkeletonConfigValue {
|
||||
"chestDistance",
|
||||
"Chest distance",
|
||||
0.32f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.CHEST, SkeletonNodeOffset.WAIST,
|
||||
SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER }
|
||||
new BoneType[] { BoneType.CHEST, BoneType.WAIST,
|
||||
BoneType.LEFT_SHOULDER, BoneType.RIGHT_SHOULDER }
|
||||
),
|
||||
WAIST(
|
||||
5,
|
||||
@@ -44,7 +44,7 @@ public enum SkeletonConfigValue {
|
||||
"waistDistance",
|
||||
"Waist distance",
|
||||
0.04f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.WAIST, SkeletonNodeOffset.HIP }
|
||||
new BoneType[] { BoneType.WAIST, BoneType.HIP }
|
||||
),
|
||||
HIP_OFFSET(
|
||||
6,
|
||||
@@ -52,7 +52,7 @@ public enum SkeletonConfigValue {
|
||||
"hipOffset",
|
||||
"Hip offset",
|
||||
0.0f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.HIP_TRACKER }
|
||||
new BoneType[] { BoneType.HIP_TRACKER }
|
||||
),
|
||||
HIPS_WIDTH(
|
||||
7,
|
||||
@@ -60,7 +60,7 @@ public enum SkeletonConfigValue {
|
||||
"hipsWidth",
|
||||
"Hips width",
|
||||
0.26f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.LEFT_HIP, SkeletonNodeOffset.RIGHT_HIP }
|
||||
new BoneType[] { BoneType.LEFT_HIP, BoneType.RIGHT_HIP }
|
||||
),
|
||||
LEGS_LENGTH(
|
||||
8,
|
||||
@@ -68,7 +68,7 @@ public enum SkeletonConfigValue {
|
||||
"legsLength",
|
||||
"Legs length",
|
||||
0.92f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.KNEE }
|
||||
new BoneType[] { BoneType.UPPER_LEG }
|
||||
),
|
||||
KNEE_HEIGHT(
|
||||
9,
|
||||
@@ -76,7 +76,7 @@ public enum SkeletonConfigValue {
|
||||
"kneeHeight",
|
||||
"Knee height",
|
||||
0.50f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.KNEE, SkeletonNodeOffset.ANKLE }
|
||||
new BoneType[] { BoneType.UPPER_LEG, BoneType.LOWER_LEG }
|
||||
),
|
||||
FOOT_LENGTH(
|
||||
10,
|
||||
@@ -84,7 +84,7 @@ public enum SkeletonConfigValue {
|
||||
"footLength",
|
||||
"Foot length",
|
||||
0.05f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.FOOT }
|
||||
new BoneType[] { BoneType.FOOT }
|
||||
),
|
||||
FOOT_OFFSET(
|
||||
11,
|
||||
@@ -92,7 +92,7 @@ public enum SkeletonConfigValue {
|
||||
"footOffset",
|
||||
"Foot offset",
|
||||
-0.05f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.ANKLE }
|
||||
new BoneType[] { BoneType.LOWER_LEG }
|
||||
),
|
||||
SKELETON_OFFSET(
|
||||
12,
|
||||
@@ -100,8 +100,8 @@ public enum SkeletonConfigValue {
|
||||
"skeletonOffset",
|
||||
"Skeleton offset",
|
||||
0.0f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.CHEST_TRACKER, SkeletonNodeOffset.HIP_TRACKER,
|
||||
SkeletonNodeOffset.KNEE_TRACKER, SkeletonNodeOffset.FOOT_TRACKER }
|
||||
new BoneType[] { BoneType.CHEST_TRACKER, BoneType.HIP_TRACKER,
|
||||
BoneType.KNEE_TRACKER, BoneType.FOOT_TRACKER }
|
||||
),
|
||||
CONTROLLER_DISTANCE_Z(
|
||||
13,
|
||||
@@ -109,7 +109,7 @@ public enum SkeletonConfigValue {
|
||||
"controllerDistanceZ",
|
||||
"Controller distance z",
|
||||
0.15f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND }
|
||||
new BoneType[] { BoneType.CONTROLLER, BoneType.HAND }
|
||||
),
|
||||
CONTROLLER_DISTANCE_Y(
|
||||
14,
|
||||
@@ -117,7 +117,7 @@ public enum SkeletonConfigValue {
|
||||
"controllerDistanceY",
|
||||
"Controller distance y",
|
||||
0.05f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND }
|
||||
new BoneType[] { BoneType.CONTROLLER, BoneType.HAND }
|
||||
),
|
||||
FOREARM_LENGTH(
|
||||
15,
|
||||
@@ -125,8 +125,8 @@ public enum SkeletonConfigValue {
|
||||
"forearmLength",
|
||||
"Forearm length",
|
||||
0.25f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.FOREARM,
|
||||
SkeletonNodeOffset.FOREARM_HMD }
|
||||
new BoneType[] { BoneType.LOWER_ARM,
|
||||
BoneType.LOWER_ARM_HMD }
|
||||
),
|
||||
SHOULDERS_DISTANCE(
|
||||
16,
|
||||
@@ -134,8 +134,8 @@ public enum SkeletonConfigValue {
|
||||
"shoulersDistance",
|
||||
"Shoulders distance",
|
||||
0.08f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.LEFT_SHOULDER,
|
||||
SkeletonNodeOffset.RIGHT_SHOULDER }
|
||||
new BoneType[] { BoneType.LEFT_SHOULDER,
|
||||
BoneType.RIGHT_SHOULDER }
|
||||
),
|
||||
SHOULDERS_WIDTH(
|
||||
17,
|
||||
@@ -143,8 +143,8 @@ public enum SkeletonConfigValue {
|
||||
"shoulersWidth",
|
||||
"Shoulders width",
|
||||
0.36f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.LEFT_SHOULDER,
|
||||
SkeletonNodeOffset.RIGHT_SHOULDER }
|
||||
new BoneType[] { BoneType.LEFT_SHOULDER,
|
||||
BoneType.RIGHT_SHOULDER }
|
||||
),
|
||||
UPPER_ARM_LENGTH(
|
||||
18,
|
||||
@@ -152,7 +152,7 @@ public enum SkeletonConfigValue {
|
||||
"upperArmLength",
|
||||
"Upper arm length",
|
||||
0.25f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.UPPER_ARM }
|
||||
new BoneType[] { BoneType.UPPER_ARM }
|
||||
),
|
||||
ELBOW_OFFSET(
|
||||
19,
|
||||
@@ -160,7 +160,7 @@ public enum SkeletonConfigValue {
|
||||
"elbowOffset",
|
||||
"Elbow offset",
|
||||
0f,
|
||||
new SkeletonNodeOffset[] { SkeletonNodeOffset.ELBOW_TRACKER }
|
||||
new BoneType[] { BoneType.ELBOW_TRACKER }
|
||||
),;
|
||||
|
||||
public static final SkeletonConfigValue[] values = values();
|
||||
@@ -180,7 +180,7 @@ public enum SkeletonConfigValue {
|
||||
public final String configKey;
|
||||
public final String label;
|
||||
public final float defaultValue;
|
||||
public final SkeletonNodeOffset[] affectedOffsets;
|
||||
public final BoneType[] affectedOffsets;
|
||||
|
||||
SkeletonConfigValue(
|
||||
int id,
|
||||
@@ -188,7 +188,7 @@ public enum SkeletonConfigValue {
|
||||
String configKey,
|
||||
String label,
|
||||
float defaultValue,
|
||||
SkeletonNodeOffset[] affectedOffsets
|
||||
BoneType[] affectedOffsets
|
||||
) {
|
||||
this.id = id;
|
||||
this.stringVal = stringVal;
|
||||
@@ -198,7 +198,7 @@ public enum SkeletonConfigValue {
|
||||
this.defaultValue = defaultValue;
|
||||
|
||||
this.affectedOffsets = affectedOffsets
|
||||
== null ? new SkeletonNodeOffset[0] : affectedOffsets;
|
||||
== null ? new BoneType[0] : affectedOffsets;
|
||||
}
|
||||
|
||||
public static SkeletonConfigValue getByStringValue(String stringVal) {
|
||||
|
||||
@@ -9,14 +9,18 @@ import java.util.Map;
|
||||
import dev.slimevr.vr.processor.TransformNode;
|
||||
|
||||
|
||||
/**
|
||||
* WIP Saved as part of skeleton rework. Is not finished.
|
||||
*/
|
||||
@Deprecated
|
||||
public class SkeletonData {
|
||||
|
||||
public final Joint[] joints;
|
||||
public final List<Bone> bones = new ArrayList<>();
|
||||
private final SkeletonConfig config;
|
||||
|
||||
private Map<SkeletonNodeOffset, List<Bone>> bonesByOffsetKey = new EnumMap<>(
|
||||
SkeletonNodeOffset.class
|
||||
private Map<BoneType, List<Bone>> bonesByOffsetKey = new EnumMap<>(
|
||||
BoneType.class
|
||||
);
|
||||
|
||||
// #region Upper body nodes (torso)
|
||||
@@ -70,68 +74,68 @@ public class SkeletonData {
|
||||
// Forward is Negative Z, left iz Negative X. See head joint and hip
|
||||
// joints as examples.
|
||||
// #region Assemble skeleton from hmd to hip
|
||||
hmdJoint.attachJoint(headJoint, SkeletonNodeOffset.HEAD);
|
||||
headJoint.attachJoint(neckJoint, SkeletonNodeOffset.NECK);
|
||||
neckJoint.attachJoint(chestJoint, SkeletonNodeOffset.CHEST);
|
||||
chestJoint.attachJoint(waistJoint, SkeletonNodeOffset.WAIST);
|
||||
waistJoint.attachJoint(hipJoint, SkeletonNodeOffset.HIP);
|
||||
hmdJoint.attachJoint(headJoint, BoneType.HEAD);
|
||||
headJoint.attachJoint(neckJoint, BoneType.NECK);
|
||||
neckJoint.attachJoint(chestJoint, BoneType.CHEST);
|
||||
chestJoint.attachJoint(waistJoint, BoneType.WAIST);
|
||||
waistJoint.attachJoint(hipJoint, BoneType.HIP);
|
||||
// #endregion
|
||||
|
||||
// #region Assemble skeleton from hips to feet
|
||||
hipJoint.attachJoint(leftHipJoint, SkeletonNodeOffset.LEFT_HIP);
|
||||
hipJoint.attachJoint(rightHipJoint, SkeletonNodeOffset.RIGHT_HIP);
|
||||
hipJoint.attachJoint(leftHipJoint, BoneType.LEFT_HIP);
|
||||
hipJoint.attachJoint(rightHipJoint, BoneType.RIGHT_HIP);
|
||||
|
||||
leftHipJoint.attachJoint(leftKneeJoint, SkeletonNodeOffset.KNEE);
|
||||
rightHipJoint.attachJoint(rightKneeJoint, SkeletonNodeOffset.KNEE);
|
||||
leftHipJoint.attachJoint(leftKneeJoint, BoneType.UPPER_LEG);
|
||||
rightHipJoint.attachJoint(rightKneeJoint, BoneType.UPPER_LEG);
|
||||
|
||||
leftKneeJoint.attachJoint(leftAnkleJoint, SkeletonNodeOffset.ANKLE);
|
||||
rightKneeJoint.attachJoint(rightAnkleJoint, SkeletonNodeOffset.ANKLE);
|
||||
leftKneeJoint.attachJoint(leftAnkleJoint, BoneType.LOWER_LEG);
|
||||
rightKneeJoint.attachJoint(rightAnkleJoint, BoneType.LOWER_LEG);
|
||||
|
||||
leftAnkleJoint.attachJoint(leftFootJoint, SkeletonNodeOffset.FOOT);
|
||||
rightAnkleJoint.attachJoint(rightFootJoint, SkeletonNodeOffset.FOOT);
|
||||
leftAnkleJoint.attachJoint(leftFootJoint, BoneType.FOOT);
|
||||
rightAnkleJoint.attachJoint(rightFootJoint, BoneType.FOOT);
|
||||
// #endregion
|
||||
|
||||
// #region Assemble skeleton arms from controllers
|
||||
// TODO : Rebuild skeleton depending on if it's from controllers or from
|
||||
// shoulders
|
||||
// if (fromControllers)
|
||||
leftHandJoint.attachJoint(leftWristJoint, SkeletonNodeOffset.HAND);
|
||||
rightHandJoint.attachJoint(rightWristJoint, SkeletonNodeOffset.HAND);
|
||||
rightWristJoint.attachJoint(leftElbowJoint, SkeletonNodeOffset.FOREARM);
|
||||
leftWristJoint.attachJoint(rightElbowJoint, SkeletonNodeOffset.FOREARM);
|
||||
leftHandJoint.attachJoint(leftWristJoint, BoneType.HAND);
|
||||
rightHandJoint.attachJoint(rightWristJoint, BoneType.HAND);
|
||||
rightWristJoint.attachJoint(leftElbowJoint, BoneType.LOWER_ARM);
|
||||
leftWristJoint.attachJoint(rightElbowJoint, BoneType.LOWER_ARM);
|
||||
// } else {
|
||||
// #endregion
|
||||
|
||||
// #region Assemble skeleton arms from chest
|
||||
chestJoint.attachJoint(leftShoulderJoint, SkeletonNodeOffset.LEFT_SHOULDER);
|
||||
chestJoint.attachJoint(rightShoulderJoint, SkeletonNodeOffset.RIGHT_SHOULDER);
|
||||
chestJoint.attachJoint(leftShoulderJoint, BoneType.LEFT_SHOULDER);
|
||||
chestJoint.attachJoint(rightShoulderJoint, BoneType.RIGHT_SHOULDER);
|
||||
|
||||
leftShoulderJoint.attachJoint(leftElbowJoint, SkeletonNodeOffset.FOREARM);
|
||||
rightShoulderJoint.attachJoint(rightElbowJoint, SkeletonNodeOffset.FOREARM);
|
||||
leftShoulderJoint.attachJoint(leftElbowJoint, BoneType.LOWER_ARM);
|
||||
rightShoulderJoint.attachJoint(rightElbowJoint, BoneType.LOWER_ARM);
|
||||
|
||||
leftElbowJoint.attachJoint(leftWristJoint, SkeletonNodeOffset.HAND);
|
||||
rightElbowJoint.attachJoint(rightWristJoint, SkeletonNodeOffset.HAND);
|
||||
leftElbowJoint.attachJoint(leftWristJoint, BoneType.HAND);
|
||||
rightElbowJoint.attachJoint(rightWristJoint, BoneType.HAND);
|
||||
|
||||
leftWristJoint.attachJoint(leftHandJoint, SkeletonNodeOffset.HAND);
|
||||
rightWristJoint.attachJoint(rightHandJoint, SkeletonNodeOffset.HAND);
|
||||
leftWristJoint.attachJoint(leftHandJoint, BoneType.HAND);
|
||||
rightWristJoint.attachJoint(rightHandJoint, BoneType.HAND);
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Attach tracker nodes for offsets
|
||||
chestJoint.attachJoint(trackerChestJoint, SkeletonNodeOffset.CHEST_TRACKER);
|
||||
hipJoint.attachJoint(trackerWaistJoint, SkeletonNodeOffset.WAIST_TRACKER);
|
||||
chestJoint.attachJoint(trackerChestJoint, BoneType.CHEST_TRACKER);
|
||||
hipJoint.attachJoint(trackerWaistJoint, BoneType.WAIST_TRACKER);
|
||||
|
||||
leftKneeJoint.attachJoint(trackerLeftKneeJoint, SkeletonNodeOffset.KNEE_TRACKER);
|
||||
rightKneeJoint.attachJoint(trackerRightKneeJoint, SkeletonNodeOffset.KNEE_TRACKER);
|
||||
leftKneeJoint.attachJoint(trackerLeftKneeJoint, BoneType.KNEE_TRACKER);
|
||||
rightKneeJoint.attachJoint(trackerRightKneeJoint, BoneType.KNEE_TRACKER);
|
||||
|
||||
leftFootJoint.attachJoint(trackerLeftFootJoint, SkeletonNodeOffset.FOOT_TRACKER);
|
||||
rightFootJoint.attachJoint(trackerRightFootJoint, SkeletonNodeOffset.FOOT_TRACKER);
|
||||
leftFootJoint.attachJoint(trackerLeftFootJoint, BoneType.FOOT_TRACKER);
|
||||
rightFootJoint.attachJoint(trackerRightFootJoint, BoneType.FOOT_TRACKER);
|
||||
|
||||
leftElbowJoint.attachJoint(trackerLeftElbowJoint, SkeletonNodeOffset.ELBOW_TRACKER);
|
||||
rightElbowJoint.attachJoint(trackerRightElbowJoint, SkeletonNodeOffset.ELBOW_TRACKER);
|
||||
leftElbowJoint.attachJoint(trackerLeftElbowJoint, BoneType.ELBOW_TRACKER);
|
||||
rightElbowJoint.attachJoint(trackerRightElbowJoint, BoneType.ELBOW_TRACKER);
|
||||
|
||||
leftHandJoint.attachJoint(trackerLeftHandJoint, SkeletonNodeOffset.HAND_TRACKER);
|
||||
rightHandJoint.attachJoint(trackerRightHandJoint, SkeletonNodeOffset.HAND_TRACKER);
|
||||
leftHandJoint.attachJoint(trackerLeftHandJoint, BoneType.HAND_TRACKER);
|
||||
rightHandJoint.attachJoint(trackerRightHandJoint, BoneType.HAND_TRACKER);
|
||||
// #endregion
|
||||
}
|
||||
|
||||
@@ -144,7 +148,7 @@ public class SkeletonData {
|
||||
node = new TransformNode(name, false);
|
||||
}
|
||||
|
||||
public Bone attachJoint(Joint childJoint, SkeletonNodeOffset offsetKey) {
|
||||
public Bone attachJoint(Joint childJoint, BoneType offsetKey) {
|
||||
Bone bone = childrenBones.get(childJoint);
|
||||
if (bone == null) {
|
||||
bone = new Bone(
|
||||
@@ -193,13 +197,13 @@ public class SkeletonData {
|
||||
public class Bone {
|
||||
public final Joint parent;
|
||||
public final Joint child;
|
||||
public SkeletonNodeOffset offsetKey;
|
||||
public BoneType offsetKey;
|
||||
|
||||
public Bone(
|
||||
String name,
|
||||
Joint firstJoint,
|
||||
Joint secondJoint,
|
||||
SkeletonNodeOffset offsetKey
|
||||
BoneType offsetKey
|
||||
) {
|
||||
this.parent = firstJoint;
|
||||
this.child = secondJoint;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package dev.slimevr.vr.processor.skeleton;
|
||||
|
||||
public enum SkeletonNodeOffset {
|
||||
|
||||
HEAD,
|
||||
NECK,
|
||||
CHEST,
|
||||
CHEST_TRACKER,
|
||||
WAIST,
|
||||
WAIST_TRACKER,
|
||||
HIP,
|
||||
HIP_TRACKER,
|
||||
LEFT_HIP,
|
||||
RIGHT_HIP,
|
||||
KNEE,
|
||||
KNEE_TRACKER,
|
||||
ANKLE,
|
||||
FOOT,
|
||||
FOOT_TRACKER,
|
||||
CONTROLLER,
|
||||
FOREARM,
|
||||
FOREARM_HMD,
|
||||
ELBOW_TRACKER,
|
||||
UPPER_ARM,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
HAND,
|
||||
HAND_TRACKER;
|
||||
|
||||
public static final SkeletonNodeOffset[] values = values();
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class ComputedTracker implements Tracker, TrackerWithTPS {
|
||||
// not be
|
||||
// allowed if editing is not allowed
|
||||
if (userEditable()) {
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation).get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation).get();
|
||||
setFilter(
|
||||
vrserver.config.getString("filters.type"),
|
||||
vrserver.config.getFloat("filters.amount", 0.3f),
|
||||
|
||||
@@ -2,7 +2,6 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import dev.slimevr.vr.trackers.udp.UDPDevice;
|
||||
|
||||
|
||||
public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
@@ -177,7 +176,7 @@ public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UDPDevice getDevice() {
|
||||
public Device getDevice() {
|
||||
return tracker.getDevice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import dev.slimevr.vr.trackers.udp.UDPDevice;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@@ -51,7 +50,7 @@ public interface Tracker {
|
||||
|
||||
int getTrackerNum();
|
||||
|
||||
UDPDevice getDevice();
|
||||
Device getDevice();
|
||||
|
||||
default String getDescriptiveName() {
|
||||
return getName();
|
||||
|
||||
@@ -1,87 +1,127 @@
|
||||
package dev.slimevr.vr.trackers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import solarxr_protocol.datatypes.BodyPart;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a position on the body that a tracker could be placed. Any bone is
|
||||
* a valid position.
|
||||
*
|
||||
* TrackerPosition intentionally lacks a numerical id to avoid breakage.
|
||||
*/
|
||||
public enum TrackerPosition {
|
||||
|
||||
NONE(0, "", TrackerRole.NONE),
|
||||
HMD(1, "HMD", TrackerRole.HMD),
|
||||
NECK(2, "body:neck", null),
|
||||
CHEST(3, "body:chest", TrackerRole.CHEST),
|
||||
WAIST(4, "body:waist", TrackerRole.WAIST),
|
||||
HIP(5, "body:hip", null),
|
||||
LEFT_KNEE(6, "body:left_knee", TrackerRole.LEFT_KNEE),
|
||||
RIGHT_KNEE(7, "body:right_knee", TrackerRole.RIGHT_KNEE),
|
||||
LEFT_ANKLE(8, "body:left_ankle", null),
|
||||
RIGHT_ANKLE(9, "body:right_ankle", null),
|
||||
LEFT_FOOT(10, "body:left_foot", TrackerRole.LEFT_FOOT),
|
||||
RIGHT_FOOT(11, "body:right_foot", TrackerRole.RIGHT_FOOT),
|
||||
LEFT_CONTROLLER(12, "body:left_controller", TrackerRole.LEFT_CONTROLLER),
|
||||
RIGHT_CONTROLLER(13, "body:right_controller", TrackerRole.RIGHT_CONTROLLER),
|
||||
LEFT_FOREARM(14, "body:left_forearm", TrackerRole.LEFT_ELBOW),
|
||||
RIGHT_FOREARM(15, "body:right_forearm", TrackerRole.RIGHT_ELBOW),
|
||||
LEFT_UPPER_ARM(16, "body:left_upperarm", null),
|
||||
RIGHT_UPPER_ARM(17, "body:right_upperarm", null),
|
||||
LEFT_HAND(18, "body:left_hand", TrackerRole.LEFT_HAND),
|
||||
RIGHT_HAND(19, "body:right_hand", TrackerRole.RIGHT_HAND),;
|
||||
// @formatter:off
|
||||
HMD("HMD", TrackerRole.HMD, BodyPart.HMD),
|
||||
NECK("body:neck", TrackerRole.NECK, BodyPart.NECK),
|
||||
CHEST("body:chest", TrackerRole.CHEST, BodyPart.CHEST),
|
||||
WAIST("body:waist", Optional.empty(), BodyPart.WAIST),
|
||||
HIP("body:hip", TrackerRole.WAIST, BodyPart.HIP),
|
||||
LEFT_KNEE("body:left_knee", TrackerRole.LEFT_KNEE, BodyPart.LEFT_KNEE),
|
||||
RIGHT_KNEE("body:right_knee", TrackerRole.RIGHT_KNEE, BodyPart.RIGHT_KNEE),
|
||||
LEFT_ANKLE("body:left_ankle", Optional.empty(), BodyPart.LEFT_ANKLE),
|
||||
RIGHT_ANKLE("body:right_ankle", Optional.empty(), BodyPart.RIGHT_ANKLE),
|
||||
LEFT_FOOT("body:left_foot", TrackerRole.LEFT_FOOT, BodyPart.LEFT_FOOT),
|
||||
RIGHT_FOOT("body:right_foot", TrackerRole.RIGHT_FOOT, BodyPart.RIGHT_FOOT),
|
||||
LEFT_CONTROLLER("body:left_controller", TrackerRole.LEFT_CONTROLLER, BodyPart.LEFT_CONTROLLER),
|
||||
RIGHT_CONTROLLER("body:right_controller", TrackerRole.RIGHT_CONTROLLER, BodyPart.RIGHT_CONTROLLER),
|
||||
LEFT_FOREARM("body:left_forearm", TrackerRole.LEFT_ELBOW, BodyPart.LEFT_FOREARM),
|
||||
RIGHT_FOREARM("body:right_forearm", TrackerRole.RIGHT_ELBOW, BodyPart.RIGHT_FOREARM),
|
||||
LEFT_UPPER_ARM("body:left_upperarm", TrackerRole.LEFT_SHOULDER, BodyPart.LEFT_UPPER_ARM),
|
||||
RIGHT_UPPER_ARM("body:right_upperarm", TrackerRole.RIGHT_SHOULDER, BodyPart.RIGHT_UPPER_ARM),
|
||||
LEFT_HAND("body:left_hand", TrackerRole.LEFT_HAND, BodyPart.LEFT_HAND),
|
||||
RIGHT_HAND("body:right_hand", TrackerRole.RIGHT_HAND, BodyPart.RIGHT_HAND),;
|
||||
// @formatter:on
|
||||
|
||||
public static final TrackerPosition[] values = values();
|
||||
private static final Map<Integer, TrackerPosition> byId = new HashMap<>();
|
||||
private static final Map<String, TrackerPosition> byDesignation = new HashMap<>();
|
||||
private static final EnumMap<TrackerRole, TrackerPosition> byRole = new EnumMap<>(
|
||||
TrackerRole.class
|
||||
);
|
||||
|
||||
static {
|
||||
for (TrackerPosition tbp : values()) {
|
||||
byDesignation.put(tbp.designation.toLowerCase(), tbp);
|
||||
byId.put(tbp.id, 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);
|
||||
}
|
||||
}
|
||||
public final String designation;
|
||||
public final Optional<TrackerRole> trackerRole;
|
||||
/** The associated `BodyPart` */
|
||||
public final int bodyPart;
|
||||
|
||||
private TrackerPosition(String designation, TrackerRole nullableTrackerRole, int bodyPart) {
|
||||
this(designation, Optional.ofNullable(nullableTrackerRole), bodyPart);
|
||||
}
|
||||
|
||||
public final int id;
|
||||
public final String designation;
|
||||
public final TrackerRole trackerRole;
|
||||
|
||||
TrackerPosition(int id, String designation, TrackerRole trackerRole) {
|
||||
this.id = id;
|
||||
private TrackerPosition(String designation, Optional<TrackerRole> trackerRole, int bodyPart) {
|
||||
this.designation = designation;
|
||||
this.trackerRole = trackerRole;
|
||||
this.bodyPart = bodyPart;
|
||||
}
|
||||
|
||||
public static TrackerPosition getByDesignation(String designation) {
|
||||
// Support old configs. leg was renamed to knee.
|
||||
if (designation != null) {
|
||||
if (designation.equals("body:left_leg"))
|
||||
designation = "body:left_knee";
|
||||
if (designation.equals("body:right_leg"))
|
||||
designation = "body:right_knee";
|
||||
/** Indexed by `BodyPart` int value. EFFICIENCY FTW */
|
||||
private static final TrackerPosition[] byBodyPart;
|
||||
static {
|
||||
// Determine maximum value of BodyPart. Kinda hacky, but this will
|
||||
// prevent breakage if the max value changes.
|
||||
int max = 0;
|
||||
for (var field : BodyPart.class.getFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers()) || !field.getType().equals(int.class)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
var v = field.getInt(null);
|
||||
max = Math.max(max, v);
|
||||
} catch (IllegalAccessException e) {
|
||||
// unreachable
|
||||
java.util.logging.Logger.getGlobal().log(Level.SEVERE, "Reached unreachable code");
|
||||
}
|
||||
}
|
||||
byBodyPart = new TrackerPosition[max + 1];
|
||||
|
||||
for (var tp : TrackerPosition.values) {
|
||||
byBodyPart[tp.bodyPart] = tp;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<String, TrackerPosition> byDesignation = new HashMap<>();
|
||||
private static final EnumMap<TrackerRole, TrackerPosition> byTrackerRole = new EnumMap<>(
|
||||
TrackerRole.class
|
||||
);
|
||||
static {
|
||||
for (TrackerPosition tp : values()) {
|
||||
byDesignation.put(tp.designation.toLowerCase(), tp);
|
||||
tp.trackerRole.ifPresent((tr) -> byTrackerRole.put(tr, tp));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the `TrackerPosition` by its string designation.
|
||||
*
|
||||
* @return Returns an optional as not all strings are valid designators.
|
||||
*/
|
||||
public static Optional<TrackerPosition> getByDesignation(String designation) {
|
||||
if (designation == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return designation == null ? null : byDesignation.get(designation.toLowerCase());
|
||||
// Support old configs. leg was renamed to knee.
|
||||
if (designation.equalsIgnoreCase("body:left_leg"))
|
||||
designation = "body:left_knee";
|
||||
if (designation.equalsIgnoreCase("body:right_leg"))
|
||||
designation = "body:right_knee";
|
||||
|
||||
|
||||
return Optional.ofNullable(byDesignation.get(designation.toLowerCase()));
|
||||
}
|
||||
|
||||
public static TrackerPosition getByRole(TrackerRole role) {
|
||||
return byRole.get(role);
|
||||
public static Optional<TrackerPosition> getByTrackerRole(TrackerRole role) {
|
||||
return Optional.ofNullable(byTrackerRole.get(role));
|
||||
}
|
||||
|
||||
public static TrackerPosition getById(int id) {
|
||||
return byId.get(id);
|
||||
public static Optional<TrackerPosition> getByBodyPart(int bodyPart) {
|
||||
if (bodyPart < 0 || bodyPart >= TrackerPosition.byBodyPart.length) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(TrackerPosition.byBodyPart[bodyPart]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
package dev.slimevr.vr.trackers;
|
||||
|
||||
/**
|
||||
* The SteamVR tracker role.
|
||||
*
|
||||
* The tracker role classifies the position and the role of a tracker on user's
|
||||
* body or playspace (like CAMERA or BEACON), using SteamVR naming. Tracker
|
||||
* roles are hints for interacting programs what the tracker means, and they do
|
||||
* not correspond to body's bones on purpose. Example: virtual vive trackers for
|
||||
* SteamVR vs actual SlimeVR trackers.
|
||||
*/
|
||||
public enum TrackerRole {
|
||||
|
||||
// @formatter:off
|
||||
NONE(0, "", "", null),
|
||||
WAIST(1, "vive_tracker_waist", "TrackerRole_Waist", DeviceType.TRACKER),
|
||||
LEFT_FOOT(2, "vive_tracker_left_foot", "TrackerRole_LeftFoot", DeviceType.TRACKER),
|
||||
@@ -12,12 +22,7 @@ public enum TrackerRole {
|
||||
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
|
||||
),
|
||||
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),
|
||||
@@ -29,6 +34,7 @@ public enum TrackerRole {
|
||||
HMD(19, "", "", DeviceType.HMD),
|
||||
BEACON(20, "", "", DeviceType.TRACKING_REFERENCE),
|
||||
GENERIC_CONTROLLER(21, "vive_tracker_handed", "TrackerRole_Handed", DeviceType.CONTROLLER);
|
||||
// @formatter:on
|
||||
|
||||
public static final TrackerRole[] values = values();
|
||||
private static final TrackerRole[] byId = new TrackerRole[22];
|
||||
@@ -53,7 +59,7 @@ public enum TrackerRole {
|
||||
public final String viveRole;
|
||||
public final DeviceType deviceType;
|
||||
|
||||
TrackerRole(int id, String roleHint, String viveRole, DeviceType deviceType) {
|
||||
private TrackerRole(int id, String roleHint, String viveRole, DeviceType deviceType) {
|
||||
this.id = id;
|
||||
this.roleHint = roleHint;
|
||||
this.viveRole = viveRole;
|
||||
|
||||
Reference in New Issue
Block a user