mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Change the formating to tabs
This commit is contained in:
@@ -46,6 +46,7 @@ indent_size = 2
|
||||
ij_haml_keep_indents_on_empty_lines = false
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
|
||||
@@ -14,82 +14,82 @@ import java.net.ServerSocket;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static String VERSION = "0.1.6";
|
||||
public static String VERSION = "0.1.6";
|
||||
|
||||
public static VRServer vrServer;
|
||||
public static VRServer vrServer;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
@SuppressWarnings("unused")
|
||||
public static void main(String[] args) {
|
||||
System.setProperty("awt.useSystemAAFontSettings", "on");
|
||||
System.setProperty("swing.aatext", "true");
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
CommandLine cmd = null;
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
CommandLine cmd = null;
|
||||
|
||||
Options options = new Options();
|
||||
Options options = new Options();
|
||||
|
||||
Option noGui = new Option("g", "no-gui", false, "disable swing gui (allow for other gui to be used)");
|
||||
Option help = new Option("h", "help", false, "Show help");
|
||||
Option noGui = new Option("g", "no-gui", false, "disable swing gui (allow for other gui to be used)");
|
||||
Option help = new Option("h", "help", false, "Show help");
|
||||
|
||||
options.addOption(noGui);
|
||||
options.addOption(help);
|
||||
try {
|
||||
cmd = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
System.out.println(e.getMessage());
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(1);
|
||||
}
|
||||
options.addOption(noGui);
|
||||
options.addOption(help);
|
||||
try {
|
||||
cmd = parser.parse(options, args);
|
||||
} catch (ParseException e) {
|
||||
System.out.println(e.getMessage());
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if (cmd.hasOption("help")) {
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(0);
|
||||
}
|
||||
if (cmd.hasOption("help")) {
|
||||
formatter.printHelp("slimevr.jar", options);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
File dir = new File("").getAbsoluteFile();
|
||||
try {
|
||||
LogManager.initialize(new File(dir, "logs/"), dir);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
File dir = new File("").getAbsoluteFile();
|
||||
try {
|
||||
LogManager.initialize(new File(dir, "logs/"), dir);
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
if (!SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_11)) {
|
||||
LogManager.log.severe("SlimeVR start-up error! A minimum of Java 11 is required.");
|
||||
JOptionPane.showMessageDialog(null, "SlimeVR start-up error! A minimum of Java 11 is required.", "SlimeVR: Java Runtime Mismatch", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (!SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_11)) {
|
||||
LogManager.log.severe("SlimeVR start-up error! A minimum of Java 11 is required.");
|
||||
JOptionPane.showMessageDialog(null, "SlimeVR start-up error! A minimum of Java 11 is required.", "SlimeVR: Java Runtime Mismatch", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
new ServerSocket(6969).close();
|
||||
new ServerSocket(35903).close();
|
||||
new ServerSocket(21110).close();
|
||||
} catch (IOException e) {
|
||||
LogManager.log.severe("SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.");
|
||||
JOptionPane.showMessageDialog(null, "SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.", "SlimeVR: Ports are busy", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
new ServerSocket(6969).close();
|
||||
new ServerSocket(35903).close();
|
||||
new ServerSocket(21110).close();
|
||||
} catch (IOException e) {
|
||||
LogManager.log.severe("SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.");
|
||||
JOptionPane.showMessageDialog(null, "SlimeVR start-up error! Required ports are busy. Make sure there is no other instance of SlimeVR Server running.", "SlimeVR: Ports are busy", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
vrServer = new VRServer();
|
||||
vrServer.start();
|
||||
new Keybinding(vrServer);
|
||||
if (!cmd.hasOption("no-gui"))
|
||||
new VRServerGUI(vrServer);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e2) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(1); // Exit in case error happened on init and window not appeared, but some thread started
|
||||
} finally {
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
vrServer = new VRServer();
|
||||
vrServer.start();
|
||||
new Keybinding(vrServer);
|
||||
if (!cmd.hasOption("no-gui"))
|
||||
new VRServerGUI(vrServer);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e2) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.exit(1); // Exit in case error happened on init and window not appeared, but some thread started
|
||||
} finally {
|
||||
try {
|
||||
Thread.sleep(2000L);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dev.slimevr;
|
||||
|
||||
public enum NetworkProtocol {
|
||||
OWO_LEGACY,
|
||||
SLIMEVR_RAW,
|
||||
SLIMEVR_FLATBUFFER,
|
||||
SLIMEVR_WEBSOCKET
|
||||
OWO_LEGACY,
|
||||
SLIMEVR_RAW,
|
||||
SLIMEVR_FLATBUFFER,
|
||||
SLIMEVR_WEBSOCKET
|
||||
}
|
||||
|
||||
@@ -30,309 +30,309 @@ import java.util.function.Consumer;
|
||||
|
||||
public class VRServer extends Thread {
|
||||
|
||||
public final HumanPoseProcessor humanPoseProcessor;
|
||||
public final YamlFile config = new YamlFile();
|
||||
public final HMDTracker hmdTracker;
|
||||
private final List<Tracker> trackers = 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<>();
|
||||
private final List<Consumer<Tracker>> newTrackersConsumers = new FastList<>();
|
||||
private final List<Runnable> onTick = new FastList<>();
|
||||
private final List<? extends ShareableTracker> shareTrackers;
|
||||
private final BVHRecorder bvhRecorder;
|
||||
private final SerialHandler serialHandler;
|
||||
private final ProtocolAPI protocolAPI;
|
||||
private final String configPath;
|
||||
public final HumanPoseProcessor humanPoseProcessor;
|
||||
public final YamlFile config = new YamlFile();
|
||||
public final HMDTracker hmdTracker;
|
||||
private final List<Tracker> trackers = 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<>();
|
||||
private final List<Consumer<Tracker>> newTrackersConsumers = new FastList<>();
|
||||
private final List<Runnable> onTick = new FastList<>();
|
||||
private final List<? extends ShareableTracker> shareTrackers;
|
||||
private final BVHRecorder bvhRecorder;
|
||||
private final SerialHandler serialHandler;
|
||||
private final ProtocolAPI protocolAPI;
|
||||
private final String configPath;
|
||||
|
||||
public VRServer() {
|
||||
this("vrconfig.yml");
|
||||
}
|
||||
public VRServer() {
|
||||
this("vrconfig.yml");
|
||||
}
|
||||
|
||||
public VRServer(String configPath) {
|
||||
super("VRServer");
|
||||
this.configPath = configPath;
|
||||
loadConfig();
|
||||
public VRServer(String configPath) {
|
||||
super("VRServer");
|
||||
this.configPath = configPath;
|
||||
loadConfig();
|
||||
|
||||
serialHandler = new SerialHandler();
|
||||
protocolAPI = new ProtocolAPI(this);
|
||||
serialHandler = new SerialHandler();
|
||||
protocolAPI = new ProtocolAPI(this);
|
||||
|
||||
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);
|
||||
shareTrackers = humanPoseProcessor.getComputedTrackers();
|
||||
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);
|
||||
shareTrackers = humanPoseProcessor.getComputedTrackers();
|
||||
|
||||
// Start server for SlimeVR trackers
|
||||
trackersServer = new TrackersUDPServer(6969, "Sensors UDP server", this::registerTracker);
|
||||
// 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) {
|
||||
// OpenVR bridge currently only supports Windows
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.WINDOWS) {
|
||||
|
||||
// Create named pipe bridge for SteamVR driver
|
||||
WindowsNamedPipeBridge driverBridge = new WindowsNamedPipeBridge(hmdTracker, "steamvr", "SteamVR Driver Bridge", "\\\\.\\pipe\\SlimeVRDriver", shareTrackers);
|
||||
tasks.add(() -> driverBridge.startBridge());
|
||||
bridges.add(driverBridge);
|
||||
// Create named pipe bridge for SteamVR driver
|
||||
WindowsNamedPipeBridge driverBridge = new WindowsNamedPipeBridge(hmdTracker, "steamvr", "SteamVR Driver Bridge", "\\\\.\\pipe\\SlimeVRDriver", shareTrackers);
|
||||
tasks.add(() -> driverBridge.startBridge());
|
||||
bridges.add(driverBridge);
|
||||
|
||||
// Create named pipe bridge for SteamVR input
|
||||
// TODO: how do we want to handle HMD input from the feeder app?
|
||||
WindowsNamedPipeBridge feederBridge = new WindowsNamedPipeBridge(null, "steamvr_feeder", "SteamVR Feeder Bridge", "\\\\.\\pipe\\SlimeVRInput", new FastList<ShareableTracker>());
|
||||
tasks.add(() -> feederBridge.startBridge());
|
||||
bridges.add(feederBridge);
|
||||
}
|
||||
// Create named pipe bridge for SteamVR input
|
||||
// TODO: how do we want to handle HMD input from the feeder app?
|
||||
WindowsNamedPipeBridge feederBridge = new WindowsNamedPipeBridge(null, "steamvr_feeder", "SteamVR Feeder Bridge", "\\\\.\\pipe\\SlimeVRInput", new FastList<ShareableTracker>());
|
||||
tasks.add(() -> feederBridge.startBridge());
|
||||
bridges.add(feederBridge);
|
||||
}
|
||||
|
||||
// Create WebSocket server
|
||||
WebSocketVRBridge wsBridge = new WebSocketVRBridge(hmdTracker, shareTrackers, this);
|
||||
tasks.add(() -> wsBridge.startBridge());
|
||||
bridges.add(wsBridge);
|
||||
// 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.startBridge());
|
||||
bridges.add(vmcBridge);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Create VMCBridge
|
||||
try {
|
||||
VMCBridge vmcBridge = new VMCBridge(39539, 39540, InetAddress.getLocalHost());
|
||||
tasks.add(() -> vmcBridge.startBridge());
|
||||
bridges.add(vmcBridge);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
bvhRecorder = new BVHRecorder(this);
|
||||
bvhRecorder = new BVHRecorder(this);
|
||||
|
||||
registerTracker(hmdTracker);
|
||||
for (int i = 0; i < shareTrackers.size(); ++i)
|
||||
registerTracker(shareTrackers.get(i));
|
||||
}
|
||||
registerTracker(hmdTracker);
|
||||
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;
|
||||
}
|
||||
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 Bridge> E getVRBridge(Class<E> bridgeClass) {
|
||||
for (int i = 0; i < bridges.size(); ++i) {
|
||||
Bridge b = bridges.get(i);
|
||||
if (bridgeClass.isAssignableFrom(b.getClass()))
|
||||
return bridgeClass.cast(b);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ThreadSafe
|
||||
public <E extends Bridge> E getVRBridge(Class<E> bridgeClass) {
|
||||
for (int i = 0; i < bridges.size(); ++i) {
|
||||
Bridge b = bridges.get(i);
|
||||
if (bridgeClass.isAssignableFrom(b.getClass()))
|
||||
return bridgeClass.cast(b);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public TrackerConfig getTrackerConfig(Tracker tracker) {
|
||||
synchronized (configuration) {
|
||||
TrackerConfig config = configuration.get(tracker.getName());
|
||||
if (config == null) {
|
||||
config = new TrackerConfig(tracker);
|
||||
configuration.put(tracker.getName(), config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@ThreadSafe
|
||||
public TrackerConfig getTrackerConfig(Tracker tracker) {
|
||||
synchronized (configuration) {
|
||||
TrackerConfig config = configuration.get(tracker.getName());
|
||||
if (config == null) {
|
||||
config = new TrackerConfig(tracker);
|
||||
configuration.put(tracker.getName(), config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
try {
|
||||
config.load(new FileInputStream(new File(this.configPath)));
|
||||
} catch (FileNotFoundException e) {
|
||||
// Config file didn't exist, is not an error
|
||||
} catch (YamlException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
List<YamlNode> trackersConfig = config.getNodeList("trackers", null);
|
||||
for (int i = 0; i < trackersConfig.size(); ++i) {
|
||||
TrackerConfig cfg = new TrackerConfig(trackersConfig.get(i));
|
||||
synchronized (configuration) {
|
||||
configuration.put(cfg.trackerName, cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void loadConfig() {
|
||||
try {
|
||||
config.load(new FileInputStream(new File(this.configPath)));
|
||||
} catch (FileNotFoundException e) {
|
||||
// Config file didn't exist, is not an error
|
||||
} catch (YamlException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
List<YamlNode> trackersConfig = config.getNodeList("trackers", null);
|
||||
for (int i = 0; i < trackersConfig.size(); ++i) {
|
||||
TrackerConfig cfg = new TrackerConfig(trackersConfig.get(i));
|
||||
synchronized (configuration) {
|
||||
configuration.put(cfg.trackerName, cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addOnTick(Runnable runnable) {
|
||||
this.onTick.add(runnable);
|
||||
}
|
||||
public void addOnTick(Runnable runnable) {
|
||||
this.onTick.add(runnable);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void addNewTrackerConsumer(Consumer<Tracker> consumer) {
|
||||
queueTask(() -> {
|
||||
newTrackersConsumers.add(consumer);
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
consumer.accept(trackers.get(i));
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void addNewTrackerConsumer(Consumer<Tracker> consumer) {
|
||||
queueTask(() -> {
|
||||
newTrackersConsumers.add(consumer);
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
consumer.accept(trackers.get(i));
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void trackerUpdated(Tracker tracker) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.trackerUpdated(tracker);
|
||||
TrackerConfig tc = getTrackerConfig(tracker);
|
||||
tracker.saveConfig(tc);
|
||||
saveConfig();
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void trackerUpdated(Tracker tracker) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.trackerUpdated(tracker);
|
||||
TrackerConfig tc = getTrackerConfig(tracker);
|
||||
tracker.saveConfig(tc);
|
||||
saveConfig();
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.addSkeletonUpdatedCallback(consumer);
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.addSkeletonUpdatedCallback(consumer);
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public synchronized void saveConfig() {
|
||||
List<YamlNode> nodes = config.getNodeList("trackers", null);
|
||||
List<Map<String, Object>> trackersConfig = new FastList<>(nodes.size());
|
||||
for (int i = 0; i < nodes.size(); ++i) {
|
||||
trackersConfig.add(nodes.get(i).root);
|
||||
}
|
||||
config.setProperty("trackers", trackersConfig);
|
||||
synchronized (configuration) {
|
||||
Iterator<TrackerConfig> iterator = configuration.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TrackerConfig tc = iterator.next();
|
||||
Map<String, Object> cfg = null;
|
||||
for (int i = 0; i < trackersConfig.size(); ++i) {
|
||||
Map<String, Object> c = trackersConfig.get(i);
|
||||
if (tc.trackerName.equals(c.get("name"))) {
|
||||
cfg = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cfg == null) {
|
||||
cfg = new HashMap<>();
|
||||
trackersConfig.add(cfg);
|
||||
}
|
||||
tc.saveConfig(new YamlNode(cfg));
|
||||
}
|
||||
}
|
||||
File cfgFile = new File(this.configPath);
|
||||
try {
|
||||
config.save(new FileOutputStream(cfgFile));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@ThreadSafe
|
||||
public synchronized void saveConfig() {
|
||||
List<YamlNode> nodes = config.getNodeList("trackers", null);
|
||||
List<Map<String, Object>> trackersConfig = new FastList<>(nodes.size());
|
||||
for (int i = 0; i < nodes.size(); ++i) {
|
||||
trackersConfig.add(nodes.get(i).root);
|
||||
}
|
||||
config.setProperty("trackers", trackersConfig);
|
||||
synchronized (configuration) {
|
||||
Iterator<TrackerConfig> iterator = configuration.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
TrackerConfig tc = iterator.next();
|
||||
Map<String, Object> cfg = null;
|
||||
for (int i = 0; i < trackersConfig.size(); ++i) {
|
||||
Map<String, Object> c = trackersConfig.get(i);
|
||||
if (tc.trackerName.equals(c.get("name"))) {
|
||||
cfg = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cfg == null) {
|
||||
cfg = new HashMap<>();
|
||||
trackersConfig.add(cfg);
|
||||
}
|
||||
tc.saveConfig(new YamlNode(cfg));
|
||||
}
|
||||
}
|
||||
File cfgFile = new File(this.configPath);
|
||||
try {
|
||||
config.save(new FileOutputStream(cfgFile));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void run() {
|
||||
trackersServer.start();
|
||||
while (true) {
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void run() {
|
||||
trackersServer.start();
|
||||
while (true) {
|
||||
// final long start = System.currentTimeMillis();
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task == null)
|
||||
break;
|
||||
task.run();
|
||||
} while (true);
|
||||
for (int i = 0; i < onTick.size(); ++i) {
|
||||
this.onTick.get(i).run();
|
||||
}
|
||||
for (int i = 0; i < bridges.size(); ++i)
|
||||
bridges.get(i).dataRead();
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
trackers.get(i).tick();
|
||||
humanPoseProcessor.update();
|
||||
for (int i = 0; i < bridges.size(); ++i)
|
||||
bridges.get(i).dataWrite();
|
||||
do {
|
||||
Runnable task = tasks.poll();
|
||||
if (task == null)
|
||||
break;
|
||||
task.run();
|
||||
} while (true);
|
||||
for (int i = 0; i < onTick.size(); ++i) {
|
||||
this.onTick.get(i).run();
|
||||
}
|
||||
for (int i = 0; i < bridges.size(); ++i)
|
||||
bridges.get(i).dataRead();
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
trackers.get(i).tick();
|
||||
humanPoseProcessor.update();
|
||||
for (int i = 0; i < bridges.size(); ++i)
|
||||
bridges.get(i).dataWrite();
|
||||
// final long time = System.currentTimeMillis() - start;
|
||||
try {
|
||||
Thread.sleep(1); // 1000Hz
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1); // 1000Hz
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void queueTask(Runnable r) {
|
||||
tasks.add(r);
|
||||
}
|
||||
@ThreadSafe
|
||||
public void queueTask(Runnable r) {
|
||||
tasks.add(r);
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
private void trackerAdded(Tracker tracker) {
|
||||
humanPoseProcessor.trackerAdded(tracker);
|
||||
}
|
||||
@VRServerThread
|
||||
private void trackerAdded(Tracker tracker) {
|
||||
humanPoseProcessor.trackerAdded(tracker);
|
||||
}
|
||||
|
||||
@ThreadSecure
|
||||
public void registerTracker(Tracker tracker) {
|
||||
TrackerConfig config = getTrackerConfig(tracker);
|
||||
tracker.loadConfig(config);
|
||||
queueTask(() -> {
|
||||
trackers.add(tracker);
|
||||
trackerAdded(tracker);
|
||||
for (int i = 0; i < newTrackersConsumers.size(); ++i)
|
||||
newTrackersConsumers.get(i).accept(tracker);
|
||||
});
|
||||
}
|
||||
@ThreadSecure
|
||||
public void registerTracker(Tracker tracker) {
|
||||
TrackerConfig config = getTrackerConfig(tracker);
|
||||
tracker.loadConfig(config);
|
||||
queueTask(() -> {
|
||||
trackers.add(tracker);
|
||||
trackerAdded(tracker);
|
||||
for (int i = 0; i < newTrackersConsumers.size(); ++i)
|
||||
newTrackersConsumers.get(i).accept(tracker);
|
||||
});
|
||||
}
|
||||
|
||||
public void updateTrackersFilters(TrackerFilters filter, float amount, int ticks) {
|
||||
config.setProperty("filters.type", filter.name());
|
||||
config.setProperty("filters.amount", amount);
|
||||
config.setProperty("filters.tickCount", ticks);
|
||||
saveConfig();
|
||||
public void updateTrackersFilters(TrackerFilters filter, float amount, int ticks) {
|
||||
config.setProperty("filters.type", filter.name());
|
||||
config.setProperty("filters.amount", amount);
|
||||
config.setProperty("filters.tickCount", ticks);
|
||||
saveConfig();
|
||||
|
||||
IMUTracker imu;
|
||||
for (Tracker t : this.getAllTrackers()) {
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
imu = (IMUTracker) realTracker;
|
||||
imu.setFilter(filter.name(), amount, ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
IMUTracker imu;
|
||||
for (Tracker t : this.getAllTrackers()) {
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
imu = (IMUTracker) realTracker;
|
||||
imu.setFilter(filter.name(), amount, ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void resetTrackers() {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.resetTrackers();
|
||||
});
|
||||
}
|
||||
public void resetTrackers() {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.resetTrackers();
|
||||
});
|
||||
}
|
||||
|
||||
public void resetTrackersYaw() {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.resetTrackersYaw();
|
||||
});
|
||||
}
|
||||
public void resetTrackersYaw() {
|
||||
queueTask(() -> {
|
||||
humanPoseProcessor.resetTrackersYaw();
|
||||
});
|
||||
}
|
||||
|
||||
public int getTrackersCount() {
|
||||
return trackers.size();
|
||||
}
|
||||
public int getTrackersCount() {
|
||||
return trackers.size();
|
||||
}
|
||||
|
||||
public List<Tracker> getAllTrackers() {
|
||||
return new FastList<>(trackers);
|
||||
}
|
||||
public List<Tracker> getAllTrackers() {
|
||||
return new FastList<>(trackers);
|
||||
}
|
||||
|
||||
public Tracker getTrackerById(TrackerIdT id) {
|
||||
for (Tracker tracker : trackers) {
|
||||
if (tracker.getTrackerNum() != id.getTrackerNum())
|
||||
continue;
|
||||
if (tracker.getDevice() == null && id.getDeviceId() != null)
|
||||
continue;
|
||||
if (tracker.getDevice() != null && id.getDeviceId() == null)
|
||||
continue;
|
||||
if (tracker.getDevice().getId() != id.getDeviceId().getId())
|
||||
continue;
|
||||
return tracker;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public Tracker getTrackerById(TrackerIdT id) {
|
||||
for (Tracker tracker : trackers) {
|
||||
if (tracker.getTrackerNum() != id.getTrackerNum())
|
||||
continue;
|
||||
if (tracker.getDevice() == null && id.getDeviceId() != null)
|
||||
continue;
|
||||
if (tracker.getDevice() != null && id.getDeviceId() == null)
|
||||
continue;
|
||||
if (tracker.getDevice().getId() != id.getDeviceId().getId())
|
||||
continue;
|
||||
return tracker;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BVHRecorder getBvhRecorder() {
|
||||
return this.bvhRecorder;
|
||||
}
|
||||
public BVHRecorder getBvhRecorder() {
|
||||
return this.bvhRecorder;
|
||||
}
|
||||
|
||||
public SerialHandler getSerialHandler() {
|
||||
return this.serialHandler;
|
||||
}
|
||||
public SerialHandler getSerialHandler() {
|
||||
return this.serialHandler;
|
||||
}
|
||||
|
||||
public ProtocolAPI getProtocolAPI() {
|
||||
return protocolAPI;
|
||||
}
|
||||
public ProtocolAPI getProtocolAPI() {
|
||||
return protocolAPI;
|
||||
}
|
||||
|
||||
public TrackersUDPServer getTrackersServer() {
|
||||
return trackersServer;
|
||||
}
|
||||
public TrackersUDPServer getTrackersServer() {
|
||||
return trackersServer;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,34 +12,34 @@ import dev.slimevr.vr.trackers.ShareableTracker;
|
||||
*/
|
||||
public interface Bridge {
|
||||
|
||||
@VRServerThread
|
||||
void dataRead();
|
||||
@VRServerThread
|
||||
void dataRead();
|
||||
|
||||
@VRServerThread
|
||||
void dataWrite();
|
||||
@VRServerThread
|
||||
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
|
||||
void addSharedTracker(ShareableTracker tracker);
|
||||
/**
|
||||
* 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
|
||||
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
|
||||
void removeSharedTracker(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
|
||||
void removeSharedTracker(ShareableTracker tracker);
|
||||
|
||||
@VRServerThread
|
||||
void startBridge();
|
||||
@VRServerThread
|
||||
void startBridge();
|
||||
}
|
||||
|
||||
@@ -5,37 +5,37 @@ import dev.slimevr.vr.trackers.ShareableTracker;
|
||||
|
||||
public class OpenVRNativeBridge implements Bridge {
|
||||
|
||||
public OpenVRNativeBridge() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
public OpenVRNativeBridge() {
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void dataRead() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// 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 removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void startBridge() {
|
||||
@Override
|
||||
@VRServerThread
|
||||
public void startBridge() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package dev.slimevr.bridge;
|
||||
|
||||
public enum PipeState {
|
||||
CREATED,
|
||||
OPEN,
|
||||
ERROR
|
||||
CREATED,
|
||||
OPEN,
|
||||
ERROR
|
||||
}
|
||||
|
||||
@@ -17,210 +17,210 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public abstract class ProtobufBridge<T extends VRTracker> implements Bridge {
|
||||
|
||||
@VRServerThread
|
||||
protected final List<ShareableTracker> sharedTrackers = new FastList<>();
|
||||
protected final String bridgeName;
|
||||
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<>();
|
||||
@Synchronize("self")
|
||||
private final Map<String, T> remoteTrackersBySerial = new HashMap<>();
|
||||
@Synchronize("self")
|
||||
private final Map<Integer, T> remoteTrackersByTrackerId = new HashMap<>();
|
||||
private final HMDTracker hmd;
|
||||
private boolean hadNewData = false;
|
||||
private T hmdTracker;
|
||||
@VRServerThread
|
||||
protected final List<ShareableTracker> sharedTrackers = new FastList<>();
|
||||
protected final String bridgeName;
|
||||
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<>();
|
||||
@Synchronize("self")
|
||||
private final Map<String, T> remoteTrackersBySerial = new HashMap<>();
|
||||
@Synchronize("self")
|
||||
private final Map<Integer, T> remoteTrackersByTrackerId = new HashMap<>();
|
||||
private final HMDTracker hmd;
|
||||
private boolean hadNewData = false;
|
||||
private T hmdTracker;
|
||||
|
||||
public ProtobufBridge(String bridgeName, HMDTracker hmd) {
|
||||
this.bridgeName = bridgeName;
|
||||
this.hmd = hmd;
|
||||
}
|
||||
public ProtobufBridge(String bridgeName, HMDTracker hmd) {
|
||||
this.bridgeName = bridgeName;
|
||||
this.hmd = hmd;
|
||||
}
|
||||
|
||||
@BridgeThread
|
||||
protected abstract boolean sendMessageReal(ProtobufMessage message);
|
||||
@BridgeThread
|
||||
protected abstract boolean sendMessageReal(ProtobufMessage message);
|
||||
|
||||
@BridgeThread
|
||||
protected void messageReceived(ProtobufMessage message) {
|
||||
inputQueue.add(message);
|
||||
}
|
||||
@BridgeThread
|
||||
protected void messageReceived(ProtobufMessage message) {
|
||||
inputQueue.add(message);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
protected void sendMessage(ProtobufMessage message) {
|
||||
outputQueue.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;
|
||||
}
|
||||
}
|
||||
@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) {
|
||||
processMessageReceived(message);
|
||||
hadNewData = true;
|
||||
}
|
||||
if (hadNewData && hmdTracker != null) {
|
||||
trackerOverrideUpdate(hmdTracker, hmd);
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void dataRead() {
|
||||
hadNewData = false;
|
||||
ProtobufMessage message = null;
|
||||
while ((message = inputQueue.poll()) != null) {
|
||||
processMessageReceived(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
|
||||
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 received, we always process at the speed of the other side
|
||||
return;
|
||||
for (int i = 0; i < sharedTrackers.size(); ++i) {
|
||||
writeTrackerUpdate(sharedTrackers.get(i));
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
if (!hadNewData) // Don't write anything if no message were received, 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 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 processMessageReceived(ProtobufMessage message) {
|
||||
//if(!message.hasPosition())
|
||||
// LogManager.log.info("[" + bridgeName + "] MSG: " + message);
|
||||
if (message.hasPosition()) {
|
||||
positionReceived(message.getPosition());
|
||||
} else if (message.hasUserAction()) {
|
||||
userActionReceived(message.getUserAction());
|
||||
} else if (message.hasTrackerStatus()) {
|
||||
trackerStatusReceived(message.getTrackerStatus());
|
||||
} else if (message.hasTrackerAdded()) {
|
||||
trackerAddedReceived(message.getTrackerAdded());
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
protected void processMessageReceived(ProtobufMessage message) {
|
||||
//if(!message.hasPosition())
|
||||
// LogManager.log.info("[" + bridgeName + "] MSG: " + message);
|
||||
if (message.hasPosition()) {
|
||||
positionReceived(message.getPosition());
|
||||
} else if (message.hasUserAction()) {
|
||||
userActionReceived(message.getUserAction());
|
||||
} else if (message.hasTrackerStatus()) {
|
||||
trackerStatusReceived(message.getTrackerStatus());
|
||||
} else if (message.hasTrackerAdded()) {
|
||||
trackerAddedReceived(message.getTrackerAdded());
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void positionReceived(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 void positionReceived(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 abstract T createNewTracker(TrackerAdded trackerAdded);
|
||||
|
||||
@VRServerThread
|
||||
protected void trackerAddedReceived(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 trackerAddedReceived(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 userActionReceived(UserAction userAction) {
|
||||
switch (userAction.getName()) {
|
||||
case "calibrate":
|
||||
// TODO : Check pose field
|
||||
Main.vrServer.resetTrackers();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
protected void userActionReceived(UserAction userAction) {
|
||||
switch (userAction.getName()) {
|
||||
case "calibrate":
|
||||
// TODO : Check pose field
|
||||
Main.vrServer.resetTrackers();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
protected void trackerStatusReceived(TrackerStatus trackerStatus) {
|
||||
T tracker = getInternalRemoteTrackerById(trackerStatus.getTrackerId());
|
||||
if (tracker != null) {
|
||||
tracker.setStatus(dev.slimevr.vr.trackers.TrackerStatus.getById(trackerStatus.getStatusValue()));
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
protected void trackerStatusReceived(TrackerStatus trackerStatus) {
|
||||
T tracker = getInternalRemoteTrackerById(trackerStatus.getTrackerId());
|
||||
if (tracker != null) {
|
||||
tracker.setStatus(dev.slimevr.vr.trackers.TrackerStatus.getById(trackerStatus.getStatusValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
protected T getInternalRemoteTrackerById(int trackerId) {
|
||||
synchronized (remoteTrackersByTrackerId) {
|
||||
return remoteTrackersByTrackerId.get(trackerId);
|
||||
}
|
||||
}
|
||||
@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 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(dev.slimevr.vr.trackers.TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
if (hmdTracker != null) {
|
||||
hmd.setStatus(dev.slimevr.vr.trackers.TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
protected void disconnected() {
|
||||
synchronized (remoteTrackersByTrackerId) {
|
||||
Iterator<Entry<Integer, T>> iterator = remoteTrackersByTrackerId.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
iterator.next().getValue().setStatus(dev.slimevr.vr.trackers.TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
if (hmdTracker != null) {
|
||||
hmd.setStatus(dev.slimevr.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 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)
|
||||
}
|
||||
@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)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,45 +6,45 @@ import java.net.InetAddress;
|
||||
|
||||
public class VMCBridge extends Thread implements Bridge {
|
||||
|
||||
public final int readPort;
|
||||
public final int writePort;
|
||||
public final InetAddress writeAddr;
|
||||
public final int readPort;
|
||||
public final int writePort;
|
||||
public final InetAddress writeAddr;
|
||||
|
||||
public VMCBridge(int readPort, int writePort, InetAddress writeAddr) {
|
||||
super("Virtual Motion Capture bridge");
|
||||
if (readPort == writePort)
|
||||
throw new IllegalArgumentException("Read and write port shouldn't be the same!");
|
||||
this.readPort = readPort;
|
||||
this.writePort = writePort;
|
||||
this.writeAddr = writeAddr;
|
||||
}
|
||||
public VMCBridge(int readPort, int writePort, InetAddress writeAddr) {
|
||||
super("Virtual Motion Capture bridge");
|
||||
if (readPort == writePort)
|
||||
throw new IllegalArgumentException("Read and write port shouldn't be the same!");
|
||||
this.readPort = readPort;
|
||||
this.writePort = writePort;
|
||||
this.writeAddr = writeAddr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void dataRead() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// 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 removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,19 @@ import java.awt.event.ComponentListener;
|
||||
|
||||
public abstract class AbstractComponentListener implements ComponentListener {
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,31 +5,31 @@ import java.awt.event.WindowListener;
|
||||
|
||||
public abstract class AbstractWindowListener implements WindowListener {
|
||||
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowOpened(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent e) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,331 +21,331 @@ import java.util.concurrent.Future;
|
||||
|
||||
public class AutoBoneWindow extends JFrame {
|
||||
|
||||
private final transient VRServer server;
|
||||
private final transient SkeletonConfigGUI skeletonConfig;
|
||||
private final transient PoseRecorder poseRecorder;
|
||||
private final transient AutoBone autoBone;
|
||||
private final EJBox pane;
|
||||
private transient Thread recordingThread = null;
|
||||
private transient Thread saveRecordingThread = null;
|
||||
private transient Thread autoBoneThread = null;
|
||||
private final transient VRServer server;
|
||||
private final transient SkeletonConfigGUI skeletonConfig;
|
||||
private final transient PoseRecorder poseRecorder;
|
||||
private final transient AutoBone autoBone;
|
||||
private final EJBox pane;
|
||||
private transient Thread recordingThread = null;
|
||||
private transient Thread saveRecordingThread = null;
|
||||
private transient Thread autoBoneThread = null;
|
||||
|
||||
private JButton saveRecordingButton;
|
||||
private JButton adjustButton;
|
||||
private JButton applyButton;
|
||||
private JButton saveRecordingButton;
|
||||
private JButton adjustButton;
|
||||
private JButton applyButton;
|
||||
|
||||
private JLabel processLabel;
|
||||
private JLabel lengthsLabel;
|
||||
private JLabel processLabel;
|
||||
private JLabel lengthsLabel;
|
||||
|
||||
public AutoBoneWindow(VRServer server, SkeletonConfigGUI skeletonConfig) {
|
||||
super("Skeleton Auto-Configuration");
|
||||
public AutoBoneWindow(VRServer server, SkeletonConfigGUI skeletonConfig) {
|
||||
super("Skeleton Auto-Configuration");
|
||||
|
||||
this.server = server;
|
||||
this.skeletonConfig = skeletonConfig;
|
||||
this.poseRecorder = new PoseRecorder(server);
|
||||
this.autoBone = new AutoBone(server);
|
||||
this.server = server;
|
||||
this.skeletonConfig = skeletonConfig;
|
||||
this.poseRecorder = new PoseRecorder(server);
|
||||
this.autoBone = new AutoBone(server);
|
||||
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
|
||||
add(new JScrollPane(pane = new EJBox(BoxLayout.PAGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
|
||||
add(new JScrollPane(pane = new EJBox(BoxLayout.PAGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
|
||||
|
||||
build();
|
||||
}
|
||||
build();
|
||||
}
|
||||
|
||||
private float processFrames(PoseFrames frames) {
|
||||
return autoBone.processFrames(frames, autoBone.calcInitError, autoBone.targetHeight, (epoch) -> {
|
||||
processLabel.setText(epoch.toString());
|
||||
lengthsLabel.setText(autoBone.getLengthsString());
|
||||
});
|
||||
}
|
||||
private float processFrames(PoseFrames frames) {
|
||||
return autoBone.processFrames(frames, autoBone.calcInitError, autoBone.targetHeight, (epoch) -> {
|
||||
processLabel.setText(epoch.toString());
|
||||
lengthsLabel.setText(autoBone.getLengthsString());
|
||||
});
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void build() {
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JButton("Start Recording") {
|
||||
{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || recordingThread != null) {
|
||||
return;
|
||||
}
|
||||
@AWTThread
|
||||
private void build() {
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JButton("Start Recording") {
|
||||
{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || recordingThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (poseRecorder.isReadyToRecord()) {
|
||||
setText("Recording...");
|
||||
// 1000 samples at 20 ms per sample is 20 seconds
|
||||
int sampleCount = server.config.getInt("autobone.sampleCount", 1000);
|
||||
long sampleRate = server.config.getLong("autobone.sampleRateMs", 20L);
|
||||
Future<PoseFrames> framesFuture = poseRecorder.startFrameRecording(sampleCount, sampleRate);
|
||||
PoseFrames frames = framesFuture.get();
|
||||
LogManager.log.info("[AutoBone] Done recording!");
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (poseRecorder.isReadyToRecord()) {
|
||||
setText("Recording...");
|
||||
// 1000 samples at 20 ms per sample is 20 seconds
|
||||
int sampleCount = server.config.getInt("autobone.sampleCount", 1000);
|
||||
long sampleRate = server.config.getLong("autobone.sampleRateMs", 20L);
|
||||
Future<PoseFrames> framesFuture = poseRecorder.startFrameRecording(sampleCount, sampleRate);
|
||||
PoseFrames frames = framesFuture.get();
|
||||
LogManager.log.info("[AutoBone] Done recording!");
|
||||
|
||||
saveRecordingButton.setEnabled(true);
|
||||
adjustButton.setEnabled(true);
|
||||
saveRecordingButton.setEnabled(true);
|
||||
adjustButton.setEnabled(true);
|
||||
|
||||
if (server.config.getBoolean("autobone.saveRecordings", false)) {
|
||||
setText("Saving...");
|
||||
autoBone.saveRecording(frames);
|
||||
}
|
||||
} else {
|
||||
setText("Not Ready...");
|
||||
LogManager.log.severe("[AutoBone] Unable to record...");
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setText("Recording Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed recording!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Start Recording");
|
||||
recordingThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (server.config.getBoolean("autobone.saveRecordings", false)) {
|
||||
setText("Saving...");
|
||||
autoBone.saveRecording(frames);
|
||||
}
|
||||
} else {
|
||||
setText("Not Ready...");
|
||||
LogManager.log.severe("[AutoBone] Unable to record...");
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setText("Recording Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed recording!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Start Recording");
|
||||
recordingThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
recordingThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
recordingThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add(saveRecordingButton = new JButton("Save Recording") {
|
||||
{
|
||||
setEnabled(poseRecorder.hasRecording());
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || saveRecordingThread != null) {
|
||||
return;
|
||||
}
|
||||
add(saveRecordingButton = new JButton("Save Recording") {
|
||||
{
|
||||
setEnabled(poseRecorder.hasRecording());
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || saveRecordingThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
setText("Waiting for Recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
setText("Waiting for Recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
|
||||
setText("Saving...");
|
||||
autoBone.saveRecording(frames);
|
||||
setText("Saving...");
|
||||
autoBone.saveRecording(frames);
|
||||
|
||||
setText("Recording Saved!");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} else {
|
||||
setText("No Recording...");
|
||||
LogManager.log.severe("[AutoBone] Unable to save, no recording was done...");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setText("Saving Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed to save recording!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Save Recording");
|
||||
saveRecordingThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
setText("Recording Saved!");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} else {
|
||||
setText("No Recording...");
|
||||
LogManager.log.severe("[AutoBone] Unable to save, no recording was done...");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setText("Saving Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed to save recording!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Save Recording");
|
||||
saveRecordingThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
saveRecordingThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
saveRecordingThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add(adjustButton = new JButton("Auto-Adjust") {
|
||||
{
|
||||
// If there are files to load, enable the button
|
||||
setEnabled(poseRecorder.hasRecording() || (AutoBone.getLoadDir().isDirectory() && AutoBone.getLoadDir().list().length > 0));
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || autoBoneThread != null) {
|
||||
return;
|
||||
}
|
||||
add(adjustButton = new JButton("Auto-Adjust") {
|
||||
{
|
||||
// If there are files to load, enable the button
|
||||
setEnabled(poseRecorder.hasRecording() || (AutoBone.getLoadDir().isDirectory() && AutoBone.getLoadDir().list().length > 0));
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// Prevent running multiple times
|
||||
if (!isEnabled() || autoBoneThread != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
setText("Load...");
|
||||
List<Pair<String, PoseFrames>> frameRecordings = autoBone.loadRecordings();
|
||||
Thread thread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
setText("Load...");
|
||||
List<Pair<String, PoseFrames>> frameRecordings = autoBone.loadRecordings();
|
||||
|
||||
if (!frameRecordings.isEmpty()) {
|
||||
LogManager.log.info("[AutoBone] Done loading frames!");
|
||||
} else {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
setText("Waiting for Recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
if (!frameRecordings.isEmpty()) {
|
||||
LogManager.log.info("[AutoBone] Done loading frames!");
|
||||
} else {
|
||||
Future<PoseFrames> framesFuture = poseRecorder.getFramesAsync();
|
||||
if (framesFuture != null) {
|
||||
setText("Waiting for Recording...");
|
||||
PoseFrames frames = framesFuture.get();
|
||||
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
if (frames.getTrackerCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no trackers");
|
||||
}
|
||||
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
if (frames.getMaxFrameCount() <= 0) {
|
||||
throw new IllegalStateException("Recording has no frames");
|
||||
}
|
||||
|
||||
frameRecordings.add(Pair.of("<Recording>", frames));
|
||||
} else {
|
||||
setText("No Recordings...");
|
||||
LogManager.log.severe("[AutoBone] No recordings found in \"" + AutoBone.getLoadDir().getPath() + "\" and no recording was done...");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
frameRecordings.add(Pair.of("<Recording>", frames));
|
||||
} else {
|
||||
setText("No Recordings...");
|
||||
LogManager.log.severe("[AutoBone] No recordings found in \"" + AutoBone.getLoadDir().getPath() + "\" and no recording was done...");
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setText("Processing...");
|
||||
LogManager.log.info("[AutoBone] Processing frames...");
|
||||
FastList<Float> heightPercentError = new FastList<Float>(frameRecordings.size());
|
||||
for (Pair<String, PoseFrames> recording : frameRecordings) {
|
||||
LogManager.log.info("[AutoBone] Processing frames from \"" + recording.getKey() + "\"...");
|
||||
setText("Processing...");
|
||||
LogManager.log.info("[AutoBone] Processing frames...");
|
||||
FastList<Float> heightPercentError = new FastList<Float>(frameRecordings.size());
|
||||
for (Pair<String, PoseFrames> recording : frameRecordings) {
|
||||
LogManager.log.info("[AutoBone] Processing frames from \"" + recording.getKey() + "\"...");
|
||||
|
||||
heightPercentError.add(processFrames(recording.getValue()));
|
||||
LogManager.log.info("[AutoBone] Done processing!");
|
||||
applyButton.setEnabled(true);
|
||||
heightPercentError.add(processFrames(recording.getValue()));
|
||||
LogManager.log.info("[AutoBone] Done processing!");
|
||||
applyButton.setEnabled(true);
|
||||
|
||||
//#region Stats/Values
|
||||
Float neckLength = autoBone.getConfig(SkeletonConfigValue.NECK);
|
||||
Float chestDistance = autoBone.getConfig(SkeletonConfigValue.CHEST);
|
||||
Float torsoLength = autoBone.getConfig(SkeletonConfigValue.TORSO);
|
||||
Float hipWidth = autoBone.getConfig(SkeletonConfigValue.HIPS_WIDTH);
|
||||
Float legsLength = autoBone.getConfig(SkeletonConfigValue.LEGS_LENGTH);
|
||||
Float kneeHeight = autoBone.getConfig(SkeletonConfigValue.KNEE_HEIGHT);
|
||||
//#region Stats/Values
|
||||
Float neckLength = autoBone.getConfig(SkeletonConfigValue.NECK);
|
||||
Float chestDistance = autoBone.getConfig(SkeletonConfigValue.CHEST);
|
||||
Float torsoLength = autoBone.getConfig(SkeletonConfigValue.TORSO);
|
||||
Float hipWidth = autoBone.getConfig(SkeletonConfigValue.HIPS_WIDTH);
|
||||
Float legsLength = autoBone.getConfig(SkeletonConfigValue.LEGS_LENGTH);
|
||||
Float kneeHeight = autoBone.getConfig(SkeletonConfigValue.KNEE_HEIGHT);
|
||||
|
||||
float neckTorso = neckLength != null && torsoLength != null ? neckLength / torsoLength : 0f;
|
||||
float chestTorso = chestDistance != null && torsoLength != null ? chestDistance / torsoLength : 0f;
|
||||
float torsoWaist = hipWidth != null && torsoLength != null ? hipWidth / torsoLength : 0f;
|
||||
float legTorso = legsLength != null && torsoLength != null ? legsLength / torsoLength : 0f;
|
||||
float legBody = legsLength != null && torsoLength != null && neckLength != null ? legsLength / (torsoLength + neckLength) : 0f;
|
||||
float kneeLeg = kneeHeight != null && legsLength != null ? kneeHeight / legsLength : 0f;
|
||||
float neckTorso = neckLength != null && torsoLength != null ? neckLength / torsoLength : 0f;
|
||||
float chestTorso = chestDistance != null && torsoLength != null ? chestDistance / torsoLength : 0f;
|
||||
float torsoWaist = hipWidth != null && torsoLength != null ? hipWidth / torsoLength : 0f;
|
||||
float legTorso = legsLength != null && torsoLength != null ? legsLength / torsoLength : 0f;
|
||||
float legBody = legsLength != null && torsoLength != null && neckLength != null ? legsLength / (torsoLength + neckLength) : 0f;
|
||||
float kneeLeg = kneeHeight != null && legsLength != null ? kneeHeight / legsLength : 0f;
|
||||
|
||||
LogManager.log.info("[AutoBone] Ratios: [{Neck-Torso: " + StringUtils.prettyNumber(neckTorso) + "}, {Chest-Torso: " + StringUtils.prettyNumber(chestTorso) + "}, {Torso-Waist: " + StringUtils.prettyNumber(torsoWaist) + "}, {Leg-Torso: " + StringUtils.prettyNumber(legTorso) + "}, {Leg-Body: " + StringUtils.prettyNumber(legBody) + "}, {Knee-Leg: " + StringUtils.prettyNumber(kneeLeg) + "}]");
|
||||
LogManager.log.info("[AutoBone] Ratios: [{Neck-Torso: " + StringUtils.prettyNumber(neckTorso) + "}, {Chest-Torso: " + StringUtils.prettyNumber(chestTorso) + "}, {Torso-Waist: " + StringUtils.prettyNumber(torsoWaist) + "}, {Leg-Torso: " + StringUtils.prettyNumber(legTorso) + "}, {Leg-Body: " + StringUtils.prettyNumber(legBody) + "}, {Knee-Leg: " + StringUtils.prettyNumber(kneeLeg) + "}]");
|
||||
|
||||
String lengthsString = autoBone.getLengthsString();
|
||||
LogManager.log.info("[AutoBone] Length values: " + lengthsString);
|
||||
lengthsLabel.setText(lengthsString);
|
||||
}
|
||||
String lengthsString = autoBone.getLengthsString();
|
||||
LogManager.log.info("[AutoBone] Length values: " + lengthsString);
|
||||
lengthsLabel.setText(lengthsString);
|
||||
}
|
||||
|
||||
if (!heightPercentError.isEmpty()) {
|
||||
float mean = 0f;
|
||||
for (float val : heightPercentError) {
|
||||
mean += val;
|
||||
}
|
||||
mean /= heightPercentError.size();
|
||||
if (!heightPercentError.isEmpty()) {
|
||||
float mean = 0f;
|
||||
for (float val : heightPercentError) {
|
||||
mean += val;
|
||||
}
|
||||
mean /= heightPercentError.size();
|
||||
|
||||
float std = 0f;
|
||||
for (float val : heightPercentError) {
|
||||
float stdVal = val - mean;
|
||||
std += stdVal * stdVal;
|
||||
}
|
||||
std = (float) Math.sqrt(std / heightPercentError.size());
|
||||
float std = 0f;
|
||||
for (float val : heightPercentError) {
|
||||
float stdVal = val - mean;
|
||||
std += stdVal * stdVal;
|
||||
}
|
||||
std = (float) Math.sqrt(std / heightPercentError.size());
|
||||
|
||||
LogManager.log.info("[AutoBone] Average height error: " + StringUtils.prettyNumber(mean, 6) + " (SD " + StringUtils.prettyNumber(std, 6) + ")");
|
||||
}
|
||||
//#endregion
|
||||
} catch (Exception e) {
|
||||
setText("Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed adjustment!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Auto-Adjust");
|
||||
autoBoneThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
LogManager.log.info("[AutoBone] Average height error: " + StringUtils.prettyNumber(mean, 6) + " (SD " + StringUtils.prettyNumber(std, 6) + ")");
|
||||
}
|
||||
//#endregion
|
||||
} catch (Exception e) {
|
||||
setText("Failed...");
|
||||
LogManager.log.severe("[AutoBone] Failed adjustment!", e);
|
||||
try {
|
||||
Thread.sleep(3000); // Wait for 3 seconds
|
||||
} catch (Exception e1) {
|
||||
// Ignore
|
||||
}
|
||||
} finally {
|
||||
setText("Auto-Adjust");
|
||||
autoBoneThread = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
autoBoneThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
autoBoneThread = thread;
|
||||
thread.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
add(applyButton = new JButton("Apply Values") {
|
||||
{
|
||||
setEnabled(false);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
add(applyButton = new JButton("Apply Values") {
|
||||
{
|
||||
setEnabled(false);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoBone.applyConfig();
|
||||
// Update GUI values after applying
|
||||
skeletonConfig.refreshAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
autoBone.applyConfig();
|
||||
// Update GUI values after applying
|
||||
skeletonConfig.refreshAll();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(processLabel = new JLabel("Processing has not been started..."));
|
||||
}
|
||||
});
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(processLabel = new JLabel("Processing has not been started..."));
|
||||
}
|
||||
});
|
||||
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(lengthsLabel = new JLabel(autoBone.getLengthsString()));
|
||||
}
|
||||
});
|
||||
pane.add(new EJBox(BoxLayout.LINE_AXIS) {
|
||||
{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(lengthsLabel = new JLabel(autoBone.getLengthsString()));
|
||||
}
|
||||
});
|
||||
|
||||
// Pack and display
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(false);
|
||||
}
|
||||
// Pack and display
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,71 +13,71 @@ import java.awt.event.MouseEvent;
|
||||
|
||||
public class CalibrationWindow extends JFrame {
|
||||
|
||||
public final Tracker tracker;
|
||||
private JTextArea currentCalibration;
|
||||
private JTextArea newCalibration;
|
||||
private JButton calibrateButton;
|
||||
public final Tracker tracker;
|
||||
private JTextArea currentCalibration;
|
||||
private JTextArea newCalibration;
|
||||
private JButton calibrateButton;
|
||||
|
||||
public CalibrationWindow(Tracker t) {
|
||||
super(t.getName() + " calibration");
|
||||
this.tracker = t;
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.LINE_AXIS));
|
||||
public CalibrationWindow(Tracker t) {
|
||||
super(t.getName() + " calibration");
|
||||
this.tracker = t;
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.LINE_AXIS));
|
||||
|
||||
build();
|
||||
}
|
||||
build();
|
||||
}
|
||||
|
||||
public void currentCalibrationReceived(String str) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
currentCalibration.setText(str);
|
||||
pack();
|
||||
});
|
||||
}
|
||||
public void currentCalibrationReceived(String str) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
currentCalibration.setText(str);
|
||||
pack();
|
||||
});
|
||||
}
|
||||
|
||||
public void newCalibrationReceived(String str) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
calibrateButton.setText("Calibrate");
|
||||
newCalibration.setText(str);
|
||||
pack();
|
||||
});
|
||||
}
|
||||
public void newCalibrationReceived(String str) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
calibrateButton.setText("Calibrate");
|
||||
newCalibration.setText(str);
|
||||
pack();
|
||||
});
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void build() {
|
||||
Container pane = getContentPane();
|
||||
@AWTThread
|
||||
private void build() {
|
||||
Container pane = getContentPane();
|
||||
|
||||
pane.add(calibrateButton = new JButton("Calibrate") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
calibrateButton.setText("Calibrating...");
|
||||
((CalibratingTracker) tracker).startCalibration(CalibrationWindow.this::newCalibrationReceived);
|
||||
}
|
||||
});
|
||||
}});
|
||||
pane.add(calibrateButton = new JButton("Calibrate") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
calibrateButton.setText("Calibrating...");
|
||||
((CalibratingTracker) tracker).startCalibration(CalibrationWindow.this::newCalibrationReceived);
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JLabel("Current calibration"));
|
||||
add(currentCalibration = new JTextArea(10, 25));
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JLabel("Current calibration"));
|
||||
add(currentCalibration = new JTextArea(10, 25));
|
||||
|
||||
((CalibratingTracker) tracker).requestCalibrationData(CalibrationWindow.this::currentCalibrationReceived);
|
||||
}});
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JLabel("New calibration"));
|
||||
add(newCalibration = new JTextArea(10, 25));
|
||||
}});
|
||||
((CalibratingTracker) tracker).requestCalibrationData(CalibrationWindow.this::currentCalibrationReceived);
|
||||
}});
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new JLabel("New calibration"));
|
||||
add(newCalibration = new JTextArea(10, 25));
|
||||
}});
|
||||
|
||||
// Pack and display
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
toFront();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
// Pack and display
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
toFront();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,56 +8,56 @@ import io.eiren.util.ann.AWTThread;
|
||||
import io.eiren.util.logging.LogManager;
|
||||
|
||||
public class Keybinding implements HotkeyListener {
|
||||
private static final int RESET = 1;
|
||||
private static final int QUICK_RESET = 2;
|
||||
public final VRServer server;
|
||||
private static final int RESET = 1;
|
||||
private static final int QUICK_RESET = 2;
|
||||
public final VRServer server;
|
||||
|
||||
@AWTThread
|
||||
public Keybinding(VRServer server) {
|
||||
this.server = server;
|
||||
@AWTThread
|
||||
public Keybinding(VRServer server) {
|
||||
this.server = server;
|
||||
|
||||
if (OperatingSystem.getCurrentPlatform() != OperatingSystem.WINDOWS) {
|
||||
LogManager.log.info("[Keybinding] Currently only supported on Windows. Keybindings will be disabled.");
|
||||
return;
|
||||
}
|
||||
if (OperatingSystem.getCurrentPlatform() != OperatingSystem.WINDOWS) {
|
||||
LogManager.log.info("[Keybinding] Currently only supported on Windows. Keybindings will be disabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (JIntellitype.getInstance() instanceof JIntellitype) {
|
||||
JIntellitype.getInstance().addHotKeyListener(this);
|
||||
try {
|
||||
if (JIntellitype.getInstance() instanceof JIntellitype) {
|
||||
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 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);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LogManager.log.info("[Keybinding] JIntellitype initialization failed. Keybindings will be disabled. Try restarting your computer.");
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LogManager.log.info("[Keybinding] JIntellitype initialization failed. Keybindings will be disabled. Try restarting your computer.");
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,85 +6,85 @@ import java.util.Map;
|
||||
|
||||
public class ScalableFont extends Font {
|
||||
|
||||
protected float scale = 1.0f;
|
||||
protected float scale = 1.0f;
|
||||
|
||||
protected int initSize;
|
||||
protected float initPointSize;
|
||||
protected int initSize;
|
||||
protected float initPointSize;
|
||||
|
||||
public ScalableFont(Map<? extends Attribute, ?> attributes) {
|
||||
super(attributes);
|
||||
public ScalableFont(Map<? extends Attribute, ?> attributes) {
|
||||
super(attributes);
|
||||
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
|
||||
public ScalableFont(Font font) {
|
||||
super(font);
|
||||
public ScalableFont(Font font) {
|
||||
super(font);
|
||||
|
||||
if (font instanceof ScalableFont) {
|
||||
ScalableFont sourceFont = (ScalableFont) font;
|
||||
if (font instanceof ScalableFont) {
|
||||
ScalableFont sourceFont = (ScalableFont) font;
|
||||
|
||||
this.initSize = sourceFont.getInitSize();
|
||||
this.initPointSize = sourceFont.getInitSize2D();
|
||||
this.initSize = sourceFont.getInitSize();
|
||||
this.initPointSize = sourceFont.getInitSize2D();
|
||||
|
||||
this.size = this.initSize;
|
||||
this.pointSize = this.initPointSize;
|
||||
} else {
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
}
|
||||
this.size = this.initSize;
|
||||
this.pointSize = this.initPointSize;
|
||||
} else {
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
}
|
||||
|
||||
public ScalableFont(Font font, float scale) {
|
||||
super(font);
|
||||
public ScalableFont(Font font, float scale) {
|
||||
super(font);
|
||||
|
||||
if (font instanceof ScalableFont) {
|
||||
ScalableFont sourceFont = (ScalableFont) font;
|
||||
if (font instanceof ScalableFont) {
|
||||
ScalableFont sourceFont = (ScalableFont) font;
|
||||
|
||||
this.initSize = sourceFont.getInitSize();
|
||||
this.initPointSize = sourceFont.getInitSize2D();
|
||||
} else {
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
this.initSize = sourceFont.getInitSize();
|
||||
this.initPointSize = sourceFont.getInitSize2D();
|
||||
} else {
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
|
||||
setScale(scale);
|
||||
}
|
||||
setScale(scale);
|
||||
}
|
||||
|
||||
public ScalableFont(String name, int style, int size) {
|
||||
super(name, style, size);
|
||||
public ScalableFont(String name, int style, int size) {
|
||||
super(name, style, size);
|
||||
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
}
|
||||
|
||||
public ScalableFont(String name, int style, int size, float scale) {
|
||||
super(name, style, size);
|
||||
public ScalableFont(String name, int style, int size, float scale) {
|
||||
super(name, style, size);
|
||||
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
this.initSize = this.size;
|
||||
this.initPointSize = this.pointSize;
|
||||
|
||||
setScale(scale);
|
||||
}
|
||||
setScale(scale);
|
||||
}
|
||||
|
||||
public int getInitSize() {
|
||||
return initSize;
|
||||
}
|
||||
public int getInitSize() {
|
||||
return initSize;
|
||||
}
|
||||
|
||||
public float getInitSize2D() {
|
||||
return initPointSize;
|
||||
}
|
||||
public float getInitSize2D() {
|
||||
return initPointSize;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
private void setScale(float scale) {
|
||||
this.scale = scale;
|
||||
private void setScale(float scale) {
|
||||
this.scale = scale;
|
||||
|
||||
float newPointSize = initPointSize * scale;
|
||||
float newPointSize = initPointSize * scale;
|
||||
|
||||
this.size = (int) (newPointSize + 0.5);
|
||||
this.pointSize = newPointSize;
|
||||
}
|
||||
this.size = (int) (newPointSize + 0.5);
|
||||
this.pointSize = newPointSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,54 +16,54 @@ import java.util.Map;
|
||||
|
||||
public class SkeletonConfigGUI extends EJBagNoStretch {
|
||||
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
private final AutoBoneWindow autoBone;
|
||||
private final Map<SkeletonConfigValue, SkeletonLabel> labels = new HashMap<>();
|
||||
private JCheckBox precisionCb;
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
private final AutoBoneWindow autoBone;
|
||||
private final Map<SkeletonConfigValue, SkeletonLabel> labels = new HashMap<>();
|
||||
private JCheckBox precisionCb;
|
||||
|
||||
public SkeletonConfigGUI(VRServer server, VRServerGUI gui) {
|
||||
super(false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
this.autoBone = new AutoBoneWindow(server, this);
|
||||
public SkeletonConfigGUI(VRServer server, VRServerGUI gui) {
|
||||
super(false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
this.autoBone = new AutoBoneWindow(server, this);
|
||||
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
server.humanPoseProcessor.addSkeletonUpdatedCallback(this::skeletonUpdated);
|
||||
skeletonUpdated(null);
|
||||
}
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
server.humanPoseProcessor.addSkeletonUpdatedCallback(this::skeletonUpdated);
|
||||
skeletonUpdated(null);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
|
||||
int row = 0;
|
||||
int row = 0;
|
||||
|
||||
/**
|
||||
add(new JCheckBox("Extended pelvis model") {{
|
||||
addItemListener(new ItemListener() {
|
||||
@Override public void itemStateChanged(ItemEvent e) {
|
||||
if(e.getStateChange() == ItemEvent.SELECTED) {//checkbox has been selected
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
hswl.setSkeletonConfigBoolean("Extended pelvis model", true);
|
||||
}
|
||||
} else {
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
hswl.setSkeletonConfigBoolean("Extended pelvis model", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
setSelected(hswl.getSkeletonConfigBoolean("Extended pelvis model"));
|
||||
}
|
||||
}}, s(c(0, row, 2), 3, 1));
|
||||
row++;
|
||||
//*/
|
||||
/**
|
||||
add(new JCheckBox("Extended pelvis model") {{
|
||||
addItemListener(new ItemListener() {
|
||||
@Override public void itemStateChanged(ItemEvent e) {
|
||||
if(e.getStateChange() == ItemEvent.SELECTED) {//checkbox has been selected
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
hswl.setSkeletonConfigBoolean("Extended pelvis model", true);
|
||||
}
|
||||
} else {
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
hswl.setSkeletonConfigBoolean("Extended pelvis model", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if(newSkeleton != null && newSkeleton instanceof HumanSkeletonWithLegs) {
|
||||
HumanSkeletonWithLegs hswl = (HumanSkeletonWithLegs) newSkeleton;
|
||||
setSelected(hswl.getSkeletonConfigBoolean("Extended pelvis model"));
|
||||
}
|
||||
}}, s(c(0, row, 2), 3, 1));
|
||||
row++;
|
||||
//*/
|
||||
/*
|
||||
add(new JCheckBox("Extended knee model") {{
|
||||
addItemListener(new ItemListener() {
|
||||
@@ -90,151 +90,151 @@ public class SkeletonConfigGUI extends EJBagNoStretch {
|
||||
row++;
|
||||
//*/
|
||||
|
||||
add(new TimedResetButton("Reset All"), s(c(1, row, 2), 3, 1));
|
||||
add(new JButton("Auto") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
autoBone.setVisible(true);
|
||||
autoBone.toFront();
|
||||
}
|
||||
});
|
||||
}}, s(c(4, row, 2), 3, 1));
|
||||
add(new TimedResetButton("Reset All"), s(c(1, row, 2), 3, 1));
|
||||
add(new JButton("Auto") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
autoBone.setVisible(true);
|
||||
autoBone.toFront();
|
||||
}
|
||||
});
|
||||
}}, s(c(4, row, 2), 3, 1));
|
||||
|
||||
add(precisionCb = new JCheckBox("Precision adjust"), c(0, row, 2));
|
||||
precisionCb.setSelected(false);
|
||||
add(precisionCb = new JCheckBox("Precision adjust"), c(0, row, 2));
|
||||
precisionCb.setSelected(false);
|
||||
|
||||
row++;
|
||||
row++;
|
||||
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
add(new JLabel(config.label), c(0, row, 2));
|
||||
add(new AdjButton("+", config, false), c(1, row, 2));
|
||||
add(new SkeletonLabel(config), c(2, row, 2));
|
||||
add(new AdjButton("-", config, true), c(3, row, 2));
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
add(new JLabel(config.label), c(0, row, 2));
|
||||
add(new AdjButton("+", config, false), c(1, row, 2));
|
||||
add(new SkeletonLabel(config), c(2, row, 2));
|
||||
add(new AdjButton("-", config, true), c(3, row, 2));
|
||||
|
||||
// Only use a timer on configs that need time to get into position for
|
||||
switch (config) {
|
||||
case TORSO:
|
||||
case LEGS_LENGTH:
|
||||
add(new TimedResetButton("Reset", config), c(4, row, 2));
|
||||
break;
|
||||
default:
|
||||
add(new ResetButton("Reset", config), c(4, row, 2));
|
||||
break;
|
||||
}
|
||||
// Only use a timer on configs that need time to get into position for
|
||||
switch (config) {
|
||||
case TORSO:
|
||||
case LEGS_LENGTH:
|
||||
add(new TimedResetButton("Reset", config), c(4, row, 2));
|
||||
break;
|
||||
default:
|
||||
add(new ResetButton("Reset", config), c(4, row, 2));
|
||||
break;
|
||||
}
|
||||
|
||||
row++;
|
||||
}
|
||||
row++;
|
||||
}
|
||||
|
||||
gui.refresh();
|
||||
});
|
||||
}
|
||||
gui.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
float proportionsIncrement(Boolean negative) {
|
||||
float increment = 0.01f;
|
||||
if (negative) increment = -0.01f;
|
||||
if (precisionCb.isSelected()) increment /= 2f;
|
||||
return increment;
|
||||
}
|
||||
float proportionsIncrement(Boolean negative) {
|
||||
float increment = 0.01f;
|
||||
if (negative) increment = -0.01f;
|
||||
if (precisionCb.isSelected()) increment /= 2f;
|
||||
return increment;
|
||||
}
|
||||
|
||||
String getBoneLengthString(SkeletonConfigValue joint) { // Rounded to the nearest 0.5
|
||||
return (StringUtils.prettyNumber(Math.round(server.humanPoseProcessor.getSkeletonConfig(joint) * 200) / 2.0f, 1));
|
||||
}
|
||||
String getBoneLengthString(SkeletonConfigValue joint) { // Rounded to the nearest 0.5
|
||||
return (StringUtils.prettyNumber(Math.round(server.humanPoseProcessor.getSkeletonConfig(joint) * 200) / 2.0f, 1));
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void refreshAll() {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
labels.forEach((joint, label) -> {
|
||||
label.setText(getBoneLengthString(joint));
|
||||
});
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void refreshAll() {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
labels.forEach((joint, label) -> {
|
||||
label.setText(getBoneLengthString(joint));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void change(SkeletonConfigValue joint, float diff) {
|
||||
// Update config value
|
||||
float current = server.humanPoseProcessor.getSkeletonConfig(joint);
|
||||
server.humanPoseProcessor.setSkeletonConfig(joint, current + diff);
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
private void change(SkeletonConfigValue joint, float diff) {
|
||||
// Update config value
|
||||
float current = server.humanPoseProcessor.getSkeletonConfig(joint);
|
||||
server.humanPoseProcessor.setSkeletonConfig(joint, current + diff);
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
|
||||
// Update GUI
|
||||
labels.get(joint).setText(getBoneLengthString(joint));
|
||||
}
|
||||
// Update GUI
|
||||
labels.get(joint).setText(getBoneLengthString(joint));
|
||||
}
|
||||
|
||||
private void reset(SkeletonConfigValue joint) {
|
||||
// Update config value
|
||||
server.humanPoseProcessor.resetSkeletonConfig(joint);
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
private void reset(SkeletonConfigValue joint) {
|
||||
// Update config value
|
||||
server.humanPoseProcessor.resetSkeletonConfig(joint);
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
|
||||
// Update GUI
|
||||
labels.get(joint).setText(getBoneLengthString(joint));
|
||||
}
|
||||
// Update GUI
|
||||
labels.get(joint).setText(getBoneLengthString(joint));
|
||||
}
|
||||
|
||||
private void resetAll() {
|
||||
// Update config value
|
||||
server.humanPoseProcessor.resetAllSkeletonConfigs();
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
private void resetAll() {
|
||||
// Update config value
|
||||
server.humanPoseProcessor.resetAllSkeletonConfigs();
|
||||
server.humanPoseProcessor.getSkeletonConfig().saveToConfig(server.config);
|
||||
server.saveConfig();
|
||||
|
||||
// Update GUI
|
||||
refreshAll();
|
||||
}
|
||||
// Update GUI
|
||||
refreshAll();
|
||||
}
|
||||
|
||||
private class SkeletonLabel extends JLabel {
|
||||
private class SkeletonLabel extends JLabel {
|
||||
|
||||
public SkeletonLabel(SkeletonConfigValue joint) {
|
||||
super(getBoneLengthString(joint));
|
||||
labels.put(joint, this);
|
||||
}
|
||||
}
|
||||
public SkeletonLabel(SkeletonConfigValue joint) {
|
||||
super(getBoneLengthString(joint));
|
||||
labels.put(joint, this);
|
||||
}
|
||||
}
|
||||
|
||||
private class AdjButton extends JButton {
|
||||
private class AdjButton extends JButton {
|
||||
|
||||
public AdjButton(String text, SkeletonConfigValue joint, boolean negative) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
change(joint, proportionsIncrement(negative));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public AdjButton(String text, SkeletonConfigValue joint, boolean negative) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
change(joint, proportionsIncrement(negative));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class ResetButton extends JButton {
|
||||
private class ResetButton extends JButton {
|
||||
|
||||
public ResetButton(String text, SkeletonConfigValue joint) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
reset(joint);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public ResetButton(String text, SkeletonConfigValue joint) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
reset(joint);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class TimedResetButton extends JButton {
|
||||
private class TimedResetButton extends JButton {
|
||||
|
||||
public TimedResetButton(String text, SkeletonConfigValue joint) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ButtonTimer.runTimer(TimedResetButton.this, 3, text, () -> reset(joint));
|
||||
}
|
||||
});
|
||||
}
|
||||
public TimedResetButton(String text, SkeletonConfigValue joint) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ButtonTimer.runTimer(TimedResetButton.this, 3, text, () -> reset(joint));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public TimedResetButton(String text) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ButtonTimer.runTimer(TimedResetButton.this, 3, text, () -> resetAll());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public TimedResetButton(String text) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
ButtonTimer.runTimer(TimedResetButton.this, 3, text, () -> resetAll());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,89 +18,89 @@ import java.util.List;
|
||||
|
||||
public class SkeletonList extends EJBagNoStretch {
|
||||
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
private final VRServerGUI gui;
|
||||
private final List<NodeStatus> nodes = new FastList<>();
|
||||
Quaternion q = new Quaternion();
|
||||
Vector3f v = new Vector3f();
|
||||
float[] angles = new float[3];
|
||||
private long lastUpdate = 0;
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
private final VRServerGUI gui;
|
||||
private final List<NodeStatus> nodes = new FastList<>();
|
||||
Quaternion q = new Quaternion();
|
||||
Vector3f v = new Vector3f();
|
||||
float[] angles = new float[3];
|
||||
private long lastUpdate = 0;
|
||||
|
||||
public SkeletonList(VRServer server, VRServerGUI gui) {
|
||||
super(false, true);
|
||||
this.gui = gui;
|
||||
public SkeletonList(VRServer server, VRServerGUI gui) {
|
||||
super(false, true);
|
||||
this.gui = gui;
|
||||
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
server.addSkeletonUpdatedCallback(this::skeletonUpdated);
|
||||
}
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
server.addSkeletonUpdatedCallback(this::skeletonUpdated);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
nodes.clear();
|
||||
@ThreadSafe
|
||||
public void skeletonUpdated(HumanSkeleton newSkeleton) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
removeAll();
|
||||
nodes.clear();
|
||||
|
||||
add(new JLabel("Joint"), c(0, 0, 2));
|
||||
add(new JLabel("X"), c(1, 0, 2));
|
||||
add(new JLabel("Y"), c(2, 0, 2));
|
||||
add(new JLabel("Z"), c(3, 0, 2));
|
||||
add(new JLabel("Pitch"), c(4, 0, 2));
|
||||
add(new JLabel("Yaw"), c(5, 0, 2));
|
||||
add(new JLabel("Roll"), c(6, 0, 2));
|
||||
add(new JLabel("Joint"), c(0, 0, 2));
|
||||
add(new JLabel("X"), c(1, 0, 2));
|
||||
add(new JLabel("Y"), c(2, 0, 2));
|
||||
add(new JLabel("Z"), c(3, 0, 2));
|
||||
add(new JLabel("Pitch"), c(4, 0, 2));
|
||||
add(new JLabel("Yaw"), c(5, 0, 2));
|
||||
add(new JLabel("Roll"), c(6, 0, 2));
|
||||
|
||||
TransformNode[] allNodes = newSkeleton.getAllNodes();
|
||||
TransformNode[] allNodes = newSkeleton.getAllNodes();
|
||||
|
||||
for (int i = 0; i < allNodes.length; i++) {
|
||||
nodes.add(new NodeStatus(allNodes[i], i + 1));
|
||||
}
|
||||
for (int i = 0; i < allNodes.length; i++) {
|
||||
nodes.add(new NodeStatus(allNodes[i], i + 1));
|
||||
}
|
||||
|
||||
gui.refresh();
|
||||
});
|
||||
}
|
||||
gui.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void updateBones() {
|
||||
if (lastUpdate + UPDATE_DELAY > System.currentTimeMillis())
|
||||
return;
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
for (int i = 0; i < nodes.size(); ++i)
|
||||
nodes.get(i).update();
|
||||
});
|
||||
}
|
||||
@VRServerThread
|
||||
public void updateBones() {
|
||||
if (lastUpdate + UPDATE_DELAY > System.currentTimeMillis())
|
||||
return;
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
for (int i = 0; i < nodes.size(); ++i)
|
||||
nodes.get(i).update();
|
||||
});
|
||||
}
|
||||
|
||||
private class NodeStatus {
|
||||
private class NodeStatus {
|
||||
|
||||
TransformNode n;
|
||||
JLabel x;
|
||||
JLabel y;
|
||||
JLabel z;
|
||||
JLabel a1;
|
||||
JLabel a2;
|
||||
JLabel a3;
|
||||
TransformNode n;
|
||||
JLabel x;
|
||||
JLabel y;
|
||||
JLabel z;
|
||||
JLabel a1;
|
||||
JLabel a2;
|
||||
JLabel a3;
|
||||
|
||||
public NodeStatus(TransformNode node, int n) {
|
||||
this.n = node;
|
||||
add(new JLabel(node.getName()), c(0, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(x = new JLabel("0"), c(1, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(y = new JLabel("0"), c(2, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(z = new JLabel("0"), c(3, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a1 = new JLabel("0"), c(4, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a2 = new JLabel("0"), c(5, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a3 = new JLabel("0"), c(6, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
public NodeStatus(TransformNode node, int n) {
|
||||
this.n = node;
|
||||
add(new JLabel(node.getName()), c(0, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(x = new JLabel("0"), c(1, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(y = new JLabel("0"), c(2, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(z = new JLabel("0"), c(3, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a1 = new JLabel("0"), c(4, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a2 = new JLabel("0"), c(5, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(a3 = new JLabel("0"), c(6, n, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
|
||||
public void update() {
|
||||
n.worldTransform.getTranslation(v);
|
||||
n.worldTransform.getRotation(q);
|
||||
q.toAngles(angles);
|
||||
public void update() {
|
||||
n.worldTransform.getTranslation(v);
|
||||
n.worldTransform.getRotation(q);
|
||||
q.toAngles(angles);
|
||||
|
||||
x.setText(StringUtils.prettyNumber(v.x, 2));
|
||||
y.setText(StringUtils.prettyNumber(v.y, 2));
|
||||
z.setText(StringUtils.prettyNumber(v.z, 2));
|
||||
a1.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0));
|
||||
a2.setText(StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0));
|
||||
a3.setText(StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
}
|
||||
x.setText(StringUtils.prettyNumber(v.x, 2));
|
||||
y.setText(StringUtils.prettyNumber(v.y, 2));
|
||||
z.setText(StringUtils.prettyNumber(v.z, 2));
|
||||
a1.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0));
|
||||
a2.setText(StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0));
|
||||
a3.setText(StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,87 +14,87 @@ import java.awt.event.MouseEvent;
|
||||
|
||||
public class TrackersFiltersGUI extends EJBagNoStretch {
|
||||
|
||||
private final VRServer server;
|
||||
private final JLabel amountLabel;
|
||||
private final JLabel ticksLabel;
|
||||
TrackerFilters filterType;
|
||||
float filterAmount;
|
||||
int filterTicks;
|
||||
private final VRServer server;
|
||||
private final JLabel amountLabel;
|
||||
private final JLabel ticksLabel;
|
||||
TrackerFilters filterType;
|
||||
float filterAmount;
|
||||
int filterTicks;
|
||||
|
||||
public TrackersFiltersGUI(VRServer server, VRServerGUI gui) {
|
||||
public TrackersFiltersGUI(VRServer server, VRServerGUI gui) {
|
||||
|
||||
super(false, true);
|
||||
this.server = server;
|
||||
super(false, true);
|
||||
this.server = server;
|
||||
|
||||
int row = 0;
|
||||
int row = 0;
|
||||
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
add(Box.createVerticalStrut(10));
|
||||
filterType = TrackerFilters.valueOf(server.config.getString("filters.type", "NONE"));
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
add(Box.createVerticalStrut(10));
|
||||
filterType = TrackerFilters.valueOf(server.config.getString("filters.type", "NONE"));
|
||||
|
||||
JComboBox<String> filterSelect;
|
||||
add(filterSelect = new JComboBox<>(), s(c(0, row, 2), 4, 1));
|
||||
JComboBox<String> filterSelect;
|
||||
add(filterSelect = new JComboBox<>(), s(c(0, row, 2), 4, 1));
|
||||
|
||||
for (TrackerFilters f : TrackerFilters.values()) {
|
||||
filterSelect.addItem(f.name());
|
||||
}
|
||||
filterSelect.setSelectedItem(filterType.toString());
|
||||
for (TrackerFilters f : TrackerFilters.values()) {
|
||||
filterSelect.addItem(f.name());
|
||||
}
|
||||
filterSelect.setSelectedItem(filterType.toString());
|
||||
|
||||
filterSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
filterType = TrackerFilters.valueOf(filterSelect.getSelectedItem().toString());
|
||||
server.updateTrackersFilters(filterType, filterAmount, filterTicks);
|
||||
}
|
||||
});
|
||||
add(Box.createVerticalStrut(40));
|
||||
row++;
|
||||
filterSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
filterType = TrackerFilters.valueOf(filterSelect.getSelectedItem().toString());
|
||||
server.updateTrackersFilters(filterType, filterAmount, filterTicks);
|
||||
}
|
||||
});
|
||||
add(Box.createVerticalStrut(40));
|
||||
row++;
|
||||
|
||||
filterAmount = FastMath.clamp(server.config.getFloat("filters.amount", 0.3f), 0, 1);
|
||||
filterAmount = FastMath.clamp(server.config.getFloat("filters.amount", 0.3f), 0, 1);
|
||||
|
||||
add(new JLabel("Intensity"), c(0, row, 2));
|
||||
add(new AdjButton("+", 0, false), c(1, row, 2));
|
||||
add(amountLabel = new JLabel(StringUtils.prettyNumber(filterAmount * 100f) + "%"), c(2, row, 2));
|
||||
add(new AdjButton("-", 0, true), c(3, row, 2));
|
||||
row++;
|
||||
filterTicks = (int) FastMath.clamp(server.config.getInt("filters.tickCount", 1), 0, 80);
|
||||
add(new JLabel("Intensity"), c(0, row, 2));
|
||||
add(new AdjButton("+", 0, false), c(1, row, 2));
|
||||
add(amountLabel = new JLabel(StringUtils.prettyNumber(filterAmount * 100f) + "%"), c(2, row, 2));
|
||||
add(new AdjButton("-", 0, true), c(3, row, 2));
|
||||
row++;
|
||||
filterTicks = (int) FastMath.clamp(server.config.getInt("filters.tickCount", 1), 0, 80);
|
||||
|
||||
add(new JLabel("Ticks"), c(0, row, 2));
|
||||
add(new AdjButton("+", 1, false), c(1, row, 2));
|
||||
add(ticksLabel = new JLabel(StringUtils.prettyNumber(filterTicks)), c(2, row, 2));
|
||||
add(new AdjButton("-", 1, true), c(3, row, 2));
|
||||
}
|
||||
add(new JLabel("Ticks"), c(0, row, 2));
|
||||
add(new AdjButton("+", 1, false), c(1, row, 2));
|
||||
add(ticksLabel = new JLabel(StringUtils.prettyNumber(filterTicks)), c(2, row, 2));
|
||||
add(new AdjButton("-", 1, true), c(3, row, 2));
|
||||
}
|
||||
|
||||
void adjustValues(int cat, boolean neg) {
|
||||
if (cat == 0) {
|
||||
if (neg) {
|
||||
filterAmount = FastMath.clamp(filterAmount - 0.1f, 0, 1);
|
||||
} else {
|
||||
filterAmount = FastMath.clamp(filterAmount + 0.1f, 0, 1);
|
||||
}
|
||||
amountLabel.setText((StringUtils.prettyNumber(filterAmount * 100f)) + "%");
|
||||
} else if (cat == 1) {
|
||||
if (neg) {
|
||||
filterTicks = (int) FastMath.clamp(filterTicks - 1, 0, 80);
|
||||
} else {
|
||||
filterTicks = (int) FastMath.clamp(filterTicks + 1, 0, 80);
|
||||
}
|
||||
ticksLabel.setText((StringUtils.prettyNumber(filterTicks)));
|
||||
}
|
||||
void adjustValues(int cat, boolean neg) {
|
||||
if (cat == 0) {
|
||||
if (neg) {
|
||||
filterAmount = FastMath.clamp(filterAmount - 0.1f, 0, 1);
|
||||
} else {
|
||||
filterAmount = FastMath.clamp(filterAmount + 0.1f, 0, 1);
|
||||
}
|
||||
amountLabel.setText((StringUtils.prettyNumber(filterAmount * 100f)) + "%");
|
||||
} else if (cat == 1) {
|
||||
if (neg) {
|
||||
filterTicks = (int) FastMath.clamp(filterTicks - 1, 0, 80);
|
||||
} else {
|
||||
filterTicks = (int) FastMath.clamp(filterTicks + 1, 0, 80);
|
||||
}
|
||||
ticksLabel.setText((StringUtils.prettyNumber(filterTicks)));
|
||||
}
|
||||
|
||||
server.updateTrackersFilters(filterType, filterAmount, filterTicks);
|
||||
}
|
||||
server.updateTrackersFilters(filterType, filterAmount, filterTicks);
|
||||
}
|
||||
|
||||
private class AdjButton extends JButton {
|
||||
private class AdjButton extends JButton {
|
||||
|
||||
public AdjButton(String text, int category, boolean neg) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
adjustValues(category, neg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
public AdjButton(String text, int category, boolean neg) {
|
||||
super(text);
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
adjustValues(category, neg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,389 +21,389 @@ import java.util.Objects;
|
||||
|
||||
public class TrackersList extends EJBoxNoStretch {
|
||||
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
private final List<TrackerPanel> trackers = new FastList<>();
|
||||
Quaternion q = new Quaternion();
|
||||
Vector3f v = new Vector3f();
|
||||
float[] angles = new float[3];
|
||||
private long lastUpdate = 0;
|
||||
private boolean debug = false;
|
||||
private static final long UPDATE_DELAY = 50;
|
||||
private final VRServer server;
|
||||
private final VRServerGUI gui;
|
||||
private final List<TrackerPanel> trackers = new FastList<>();
|
||||
Quaternion q = new Quaternion();
|
||||
Vector3f v = new Vector3f();
|
||||
float[] angles = new float[3];
|
||||
private long lastUpdate = 0;
|
||||
private boolean debug = false;
|
||||
|
||||
public TrackersList(VRServer server, VRServerGUI gui) {
|
||||
super(BoxLayout.PAGE_AXIS, false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
public TrackersList(VRServer server, VRServerGUI gui) {
|
||||
super(BoxLayout.PAGE_AXIS, false, true);
|
||||
this.server = server;
|
||||
this.gui = gui;
|
||||
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
|
||||
server.addNewTrackerConsumer(this::newTrackerAdded);
|
||||
}
|
||||
server.addNewTrackerConsumer(this::newTrackerAdded);
|
||||
}
|
||||
|
||||
private static int getTrackerSort(Tracker t) {
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
t = ((ReferenceAdjustedTracker<?>) t).getTracker();
|
||||
if (t instanceof IMUTracker)
|
||||
return 0;
|
||||
if (t instanceof HMDTracker)
|
||||
return 100;
|
||||
if (t instanceof ComputedTracker)
|
||||
return 200;
|
||||
return 1000;
|
||||
}
|
||||
private static int getTrackerSort(Tracker t) {
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
t = ((ReferenceAdjustedTracker<?>) t).getTracker();
|
||||
if (t instanceof IMUTracker)
|
||||
return 0;
|
||||
if (t instanceof HMDTracker)
|
||||
return 100;
|
||||
if (t instanceof ComputedTracker)
|
||||
return 200;
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
build();
|
||||
}
|
||||
@AWTThread
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
build();
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void build() {
|
||||
removeAll();
|
||||
@AWTThread
|
||||
private void build() {
|
||||
removeAll();
|
||||
|
||||
trackers.sort((tr1, tr2) -> getTrackerSort(tr1.t) - getTrackerSort(tr2.t));
|
||||
trackers.sort((tr1, tr2) -> getTrackerSort(tr1.t) - getTrackerSort(tr2.t));
|
||||
|
||||
Class<? extends Tracker> currentClass = null;
|
||||
Class<? extends Tracker> currentClass = null;
|
||||
|
||||
EJBoxNoStretch line = null;
|
||||
boolean first = true;
|
||||
EJBoxNoStretch line = null;
|
||||
boolean first = true;
|
||||
|
||||
for (int i = 0; i < trackers.size(); ++i) {
|
||||
TrackerPanel tr = trackers.get(i);
|
||||
Tracker t = tr.t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
t = ((ReferenceAdjustedTracker<?>) t).getTracker();
|
||||
if (currentClass != t.getClass()) {
|
||||
currentClass = t.getClass();
|
||||
if (line != null)
|
||||
line.add(Box.createHorizontalGlue());
|
||||
line = null;
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
line.add(Box.createHorizontalGlue());
|
||||
JLabel nameLabel;
|
||||
line.add(nameLabel = new JLabel(currentClass.getSimpleName()));
|
||||
nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD));
|
||||
line.add(Box.createHorizontalGlue());
|
||||
add(line);
|
||||
line = null;
|
||||
}
|
||||
for (int i = 0; i < trackers.size(); ++i) {
|
||||
TrackerPanel tr = trackers.get(i);
|
||||
Tracker t = tr.t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
t = ((ReferenceAdjustedTracker<?>) t).getTracker();
|
||||
if (currentClass != t.getClass()) {
|
||||
currentClass = t.getClass();
|
||||
if (line != null)
|
||||
line.add(Box.createHorizontalGlue());
|
||||
line = null;
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
line.add(Box.createHorizontalGlue());
|
||||
JLabel nameLabel;
|
||||
line.add(nameLabel = new JLabel(currentClass.getSimpleName()));
|
||||
nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD));
|
||||
line.add(Box.createHorizontalGlue());
|
||||
add(line);
|
||||
line = null;
|
||||
}
|
||||
|
||||
if (line == null) {
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
add(Box.createVerticalStrut(3));
|
||||
add(line);
|
||||
first = true;
|
||||
} else {
|
||||
line.add(Box.createHorizontalStrut(3));
|
||||
first = false;
|
||||
}
|
||||
tr.build();
|
||||
line.add(tr);
|
||||
if (!first)
|
||||
line = null;
|
||||
}
|
||||
validate();
|
||||
gui.refresh();
|
||||
}
|
||||
if (line == null) {
|
||||
line = new EJBoxNoStretch(BoxLayout.LINE_AXIS, false, true);
|
||||
add(Box.createVerticalStrut(3));
|
||||
add(line);
|
||||
first = true;
|
||||
} else {
|
||||
line.add(Box.createHorizontalStrut(3));
|
||||
first = false;
|
||||
}
|
||||
tr.build();
|
||||
line.add(tr);
|
||||
if (!first)
|
||||
line = null;
|
||||
}
|
||||
validate();
|
||||
gui.refresh();
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void updateTrackers() {
|
||||
if (lastUpdate + UPDATE_DELAY > System.currentTimeMillis())
|
||||
return;
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
trackers.get(i).update();
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void updateTrackers() {
|
||||
if (lastUpdate + UPDATE_DELAY > System.currentTimeMillis())
|
||||
return;
|
||||
lastUpdate = System.currentTimeMillis();
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
for (int i = 0; i < trackers.size(); ++i)
|
||||
trackers.get(i).update();
|
||||
});
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void newTrackerAdded(Tracker t) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
trackers.add(new TrackerPanel(t));
|
||||
build();
|
||||
});
|
||||
}
|
||||
@ThreadSafe
|
||||
public void newTrackerAdded(Tracker t) {
|
||||
java.awt.EventQueue.invokeLater(() -> {
|
||||
trackers.add(new TrackerPanel(t));
|
||||
build();
|
||||
});
|
||||
}
|
||||
|
||||
private class TrackerPanel extends EJBagNoStretch {
|
||||
private class TrackerPanel extends EJBagNoStretch {
|
||||
|
||||
final Tracker t;
|
||||
JLabel position;
|
||||
JLabel rotation;
|
||||
JLabel status;
|
||||
JLabel tps;
|
||||
JLabel bat;
|
||||
JLabel ping;
|
||||
JLabel raw;
|
||||
JLabel rawMag;
|
||||
JLabel calibration;
|
||||
JLabel magAccuracy;
|
||||
JLabel adj;
|
||||
JLabel adjYaw;
|
||||
JLabel adjGyro;
|
||||
JLabel correction;
|
||||
JLabel signalStrength;
|
||||
JLabel rotQuat;
|
||||
JLabel rotAdj;
|
||||
JLabel temperature;
|
||||
final Tracker t;
|
||||
JLabel position;
|
||||
JLabel rotation;
|
||||
JLabel status;
|
||||
JLabel tps;
|
||||
JLabel bat;
|
||||
JLabel ping;
|
||||
JLabel raw;
|
||||
JLabel rawMag;
|
||||
JLabel calibration;
|
||||
JLabel magAccuracy;
|
||||
JLabel adj;
|
||||
JLabel adjYaw;
|
||||
JLabel adjGyro;
|
||||
JLabel correction;
|
||||
JLabel signalStrength;
|
||||
JLabel rotQuat;
|
||||
JLabel rotAdj;
|
||||
JLabel temperature;
|
||||
|
||||
@AWTThread
|
||||
public TrackerPanel(Tracker t) {
|
||||
super(false, true);
|
||||
@AWTThread
|
||||
public TrackerPanel(Tracker t) {
|
||||
super(false, true);
|
||||
|
||||
this.t = t;
|
||||
}
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@AWTThread
|
||||
public TrackerPanel build() {
|
||||
int row = 0;
|
||||
@SuppressWarnings("unchecked")
|
||||
@AWTThread
|
||||
public TrackerPanel build() {
|
||||
int row = 0;
|
||||
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
removeAll();
|
||||
JLabel nameLabel;
|
||||
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++;
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
removeAll();
|
||||
JLabel nameLabel;
|
||||
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, 2, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for (TrackerPosition p : TrackerPosition.values) {
|
||||
desSelect.addItem(p.name());
|
||||
}
|
||||
if (cfg.designation != null) {
|
||||
TrackerPosition p = TrackerPosition.getByDesignation(cfg.designation);
|
||||
if (p != null)
|
||||
desSelect.setSelectedItem(p.name());
|
||||
}
|
||||
desSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TrackerPosition p = TrackerPosition.valueOf(String.valueOf(desSelect.getSelectedItem()));
|
||||
t.setBodyPosition(p);
|
||||
server.trackerUpdated(t);
|
||||
}
|
||||
});
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) realTracker;
|
||||
JComboBox<String> mountSelect;
|
||||
add(mountSelect = new JComboBox<>(), s(c(2, row, 2, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for (TrackerMountingRotation p : TrackerMountingRotation.values) {
|
||||
mountSelect.addItem(p.name());
|
||||
}
|
||||
if (t.userEditable()) {
|
||||
TrackerConfig cfg = server.getTrackerConfig(t);
|
||||
JComboBox<String> desSelect;
|
||||
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) {
|
||||
TrackerPosition p = TrackerPosition.getByDesignation(cfg.designation);
|
||||
if (p != null)
|
||||
desSelect.setSelectedItem(p.name());
|
||||
}
|
||||
desSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TrackerPosition p = TrackerPosition.valueOf(String.valueOf(desSelect.getSelectedItem()));
|
||||
t.setBodyPosition(p);
|
||||
server.trackerUpdated(t);
|
||||
}
|
||||
});
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) realTracker;
|
||||
JComboBox<String> mountSelect;
|
||||
add(mountSelect = new JComboBox<>(), s(c(2, row, 2, GridBagConstraints.FIRST_LINE_START), 2, 1));
|
||||
for (TrackerMountingRotation p : TrackerMountingRotation.values) {
|
||||
mountSelect.addItem(p.name());
|
||||
}
|
||||
|
||||
TrackerMountingRotation selected = TrackerMountingRotation.fromQuaternion(imu.getMountingRotation());
|
||||
mountSelect.setSelectedItem(Objects.requireNonNullElse(selected, TrackerMountingRotation.BACK).name());
|
||||
mountSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TrackerMountingRotation tr = TrackerMountingRotation.valueOf(String.valueOf(mountSelect.getSelectedItem()));
|
||||
imu.setMountingRotation(tr.quaternion);
|
||||
server.trackerUpdated(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
row++;
|
||||
}
|
||||
if (t.hasRotation())
|
||||
add(new JLabel("Rotation"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if (t.hasPosition())
|
||||
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));
|
||||
add(new JLabel("Signal"), c(4, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
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));
|
||||
add(signalStrength = new JLabel(""), c(4, 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("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));
|
||||
TrackerMountingRotation selected = TrackerMountingRotation.fromQuaternion(imu.getMountingRotation());
|
||||
mountSelect.setSelectedItem(Objects.requireNonNullElse(selected, TrackerMountingRotation.BACK).name());
|
||||
mountSelect.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TrackerMountingRotation tr = TrackerMountingRotation.valueOf(String.valueOf(mountSelect.getSelectedItem()));
|
||||
imu.setMountingRotation(tr.quaternion);
|
||||
server.trackerUpdated(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
row++;
|
||||
}
|
||||
if (t.hasRotation())
|
||||
add(new JLabel("Rotation"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
if (t.hasPosition())
|
||||
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));
|
||||
add(new JLabel("Signal"), c(4, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
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));
|
||||
add(signalStrength = new JLabel(""), c(4, 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("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));
|
||||
|
||||
if (debug && realTracker instanceof IMUTracker) {
|
||||
add(new JLabel("Quat:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rotQuat = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
if (debug && realTracker instanceof IMUTracker) {
|
||||
add(new JLabel("Quat:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rotQuat = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
row++;
|
||||
|
||||
if (debug && realTracker instanceof IMUTracker) {
|
||||
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));
|
||||
add(new JLabel("Gyro fix:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel(String.format("0x%8x", realTracker.hashCode())), s(c(3, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
row++;
|
||||
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, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(correction = new JLabel("0 0 0"), s(c(1, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
add(new JLabel("RotAdj:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rotAdj = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
}
|
||||
if (debug && realTracker instanceof IMUTracker) {
|
||||
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));
|
||||
add(new JLabel("Gyro fix:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel(String.format("0x%8x", realTracker.hashCode())), s(c(3, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
row++;
|
||||
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, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(correction = new JLabel("0 0 0"), s(c(1, row, 2, GridBagConstraints.FIRST_LINE_START), 3, 1));
|
||||
add(new JLabel("RotAdj:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(rotAdj = new JLabel("0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
}
|
||||
|
||||
if (debug && t instanceof ReferenceAdjustedTracker) {
|
||||
add(new JLabel("Att fix:"), 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("Yaw Fix:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjYaw = new JLabel("0 0 0 0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
add(new JLabel("Gyro Fix:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjGyro = new JLabel("0 0 0 0"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Temp:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(temperature = new JLabel("?"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
if (debug && t instanceof ReferenceAdjustedTracker) {
|
||||
add(new JLabel("Att fix:"), 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("Yaw Fix:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjYaw = new JLabel("0 0 0 0"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
row++;
|
||||
add(new JLabel("Gyro Fix:"), c(0, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(adjGyro = new JLabel("0 0 0 0"), c(1, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(new JLabel("Temp:"), c(2, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
add(temperature = new JLabel("?"), c(3, row, 2, GridBagConstraints.FIRST_LINE_START));
|
||||
}
|
||||
|
||||
setBorder(BorderFactory.createLineBorder(new Color(0x663399), 2, false));
|
||||
TrackersList.this.add(this);
|
||||
return this;
|
||||
}
|
||||
setBorder(BorderFactory.createLineBorder(new Color(0x663399), 2, false));
|
||||
TrackersList.this.add(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@AWTThread
|
||||
public void update() {
|
||||
if (position == null && rotation == null)
|
||||
return;
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
t.getRotation(q);
|
||||
t.getPosition(v);
|
||||
q.toAngles(angles);
|
||||
@SuppressWarnings("unchecked")
|
||||
@AWTThread
|
||||
public void update() {
|
||||
if (position == null && rotation == null)
|
||||
return;
|
||||
Tracker realTracker = t;
|
||||
if (t instanceof ReferenceAdjustedTracker)
|
||||
realTracker = ((ReferenceAdjustedTracker<? extends Tracker>) t).getTracker();
|
||||
t.getRotation(q);
|
||||
t.getPosition(v);
|
||||
q.toAngles(angles);
|
||||
|
||||
if (position != null)
|
||||
position.setText(StringUtils.prettyNumber(v.x, 1)
|
||||
+ " " + StringUtils.prettyNumber(v.y, 1)
|
||||
+ " " + StringUtils.prettyNumber(v.z, 1));
|
||||
if (rotation != null)
|
||||
rotation.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
status.setText(t.getStatus().toString().toLowerCase());
|
||||
if (position != null)
|
||||
position.setText(StringUtils.prettyNumber(v.x, 1)
|
||||
+ " " + StringUtils.prettyNumber(v.y, 1)
|
||||
+ " " + StringUtils.prettyNumber(v.z, 1));
|
||||
if (rotation != null)
|
||||
rotation.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
status.setText(t.getStatus().toString().toLowerCase());
|
||||
|
||||
if (realTracker instanceof TrackerWithTPS) {
|
||||
tps.setText(StringUtils.prettyNumber(((TrackerWithTPS) realTracker).getTPS(), 1));
|
||||
}
|
||||
if (realTracker instanceof TrackerWithBattery) {
|
||||
TrackerWithBattery twb = (TrackerWithBattery) realTracker;
|
||||
float level = twb.getBatteryLevel();
|
||||
float voltage = twb.getBatteryVoltage();
|
||||
if (level == 0.0f) {
|
||||
bat.setText(String.format("%sV", StringUtils.prettyNumber(voltage, 2)));
|
||||
} else if (voltage == 0.0f) {
|
||||
bat.setText(String.format("%d%%", Math.round(level)));
|
||||
} else {
|
||||
bat.setText(String.format("%d%% (%sV)", Math.round(level), StringUtils.prettyNumber(voltage, 2)));
|
||||
}
|
||||
}
|
||||
if (t instanceof ReferenceAdjustedTracker) {
|
||||
ReferenceAdjustedTracker<Tracker> rat = (ReferenceAdjustedTracker<Tracker>) t;
|
||||
if (adj != null) {
|
||||
rat.attachmentFix.toAngles(angles);
|
||||
adj.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (adjYaw != null) {
|
||||
rat.yawFix.toAngles(angles);
|
||||
adjYaw.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (adjGyro != null) {
|
||||
rat.gyroFix.toAngles(angles);
|
||||
adjGyro.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
}
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
if (ping != null)
|
||||
ping.setText(String.valueOf(((IMUTracker) realTracker).ping));
|
||||
if (signalStrength != null) {
|
||||
int signal = ((IMUTracker) realTracker).signalStrength;
|
||||
if (signal == -1) {
|
||||
signalStrength.setText("N/A");
|
||||
} else {
|
||||
// -40 dBm is excellent, -95 dBm is very poor
|
||||
int percentage = (signal - -95) * (100 - 0) / (-40 - -95) + 0;
|
||||
percentage = Math.max(Math.min(percentage, 100), 0);
|
||||
signalStrength.setText(percentage + "% " + "(" + signal + " dBm" + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
realTracker.getRotation(q);
|
||||
q.toAngles(angles);
|
||||
raw.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) realTracker;
|
||||
if (rawMag != null) {
|
||||
imu.rotMagQuaternion.toAngles(angles);
|
||||
rawMag.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (calibration != null)
|
||||
calibration.setText(imu.calibrationStatus + " / " + imu.magCalibrationStatus);
|
||||
if (magAccuracy != null)
|
||||
magAccuracy.setText(StringUtils.prettyNumber(imu.magnetometerAccuracy * FastMath.RAD_TO_DEG, 1) + "°");
|
||||
if (correction != null) {
|
||||
imu.getCorrection(q);
|
||||
q.toAngles(angles);
|
||||
correction.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (rotQuat != null) {
|
||||
imu.rotQuaternion.toAngles(angles);
|
||||
rotQuat.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (rotAdj != null) {
|
||||
imu.rotAdjust.toAngles(angles);
|
||||
rotAdj.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (temperature != null) {
|
||||
if (imu.temperature == 0.0f) {
|
||||
// Can't be exact 0, so no info received
|
||||
temperature.setText("?");
|
||||
} else {
|
||||
temperature.setText(StringUtils.prettyNumber(imu.temperature, 1) + "∘C");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (realTracker instanceof TrackerWithTPS) {
|
||||
tps.setText(StringUtils.prettyNumber(((TrackerWithTPS) realTracker).getTPS(), 1));
|
||||
}
|
||||
if (realTracker instanceof TrackerWithBattery) {
|
||||
TrackerWithBattery twb = (TrackerWithBattery) realTracker;
|
||||
float level = twb.getBatteryLevel();
|
||||
float voltage = twb.getBatteryVoltage();
|
||||
if (level == 0.0f) {
|
||||
bat.setText(String.format("%sV", StringUtils.prettyNumber(voltage, 2)));
|
||||
} else if (voltage == 0.0f) {
|
||||
bat.setText(String.format("%d%%", Math.round(level)));
|
||||
} else {
|
||||
bat.setText(String.format("%d%% (%sV)", Math.round(level), StringUtils.prettyNumber(voltage, 2)));
|
||||
}
|
||||
}
|
||||
if (t instanceof ReferenceAdjustedTracker) {
|
||||
ReferenceAdjustedTracker<Tracker> rat = (ReferenceAdjustedTracker<Tracker>) t;
|
||||
if (adj != null) {
|
||||
rat.attachmentFix.toAngles(angles);
|
||||
adj.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (adjYaw != null) {
|
||||
rat.yawFix.toAngles(angles);
|
||||
adjYaw.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (adjGyro != null) {
|
||||
rat.gyroFix.toAngles(angles);
|
||||
adjGyro.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
}
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
if (ping != null)
|
||||
ping.setText(String.valueOf(((IMUTracker) realTracker).ping));
|
||||
if (signalStrength != null) {
|
||||
int signal = ((IMUTracker) realTracker).signalStrength;
|
||||
if (signal == -1) {
|
||||
signalStrength.setText("N/A");
|
||||
} else {
|
||||
// -40 dBm is excellent, -95 dBm is very poor
|
||||
int percentage = (signal - -95) * (100 - 0) / (-40 - -95) + 0;
|
||||
percentage = Math.max(Math.min(percentage, 100), 0);
|
||||
signalStrength.setText(percentage + "% " + "(" + signal + " dBm" + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
realTracker.getRotation(q);
|
||||
q.toAngles(angles);
|
||||
raw.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
if (realTracker instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) realTracker;
|
||||
if (rawMag != null) {
|
||||
imu.rotMagQuaternion.toAngles(angles);
|
||||
rawMag.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (calibration != null)
|
||||
calibration.setText(imu.calibrationStatus + " / " + imu.magCalibrationStatus);
|
||||
if (magAccuracy != null)
|
||||
magAccuracy.setText(StringUtils.prettyNumber(imu.magnetometerAccuracy * FastMath.RAD_TO_DEG, 1) + "°");
|
||||
if (correction != null) {
|
||||
imu.getCorrection(q);
|
||||
q.toAngles(angles);
|
||||
correction.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (rotQuat != null) {
|
||||
imu.rotQuaternion.toAngles(angles);
|
||||
rotQuat.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (rotAdj != null) {
|
||||
imu.rotAdjust.toAngles(angles);
|
||||
rotAdj.setText(StringUtils.prettyNumber(angles[0] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[1] * FastMath.RAD_TO_DEG, 0)
|
||||
+ " " + StringUtils.prettyNumber(angles[2] * FastMath.RAD_TO_DEG, 0));
|
||||
}
|
||||
if (temperature != null) {
|
||||
if (imu.temperature == 0.0f) {
|
||||
// Can't be exact 0, so no info received
|
||||
temperature.setText("?");
|
||||
} else {
|
||||
temperature.setText(StringUtils.prettyNumber(imu.temperature, 1) + "∘C");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,362 +32,362 @@ import static javax.swing.BoxLayout.PAGE_AXIS;
|
||||
|
||||
public class VRServerGUI extends JFrame {
|
||||
|
||||
public static final String TITLE = "SlimeVR Server (" + Main.VERSION + ")";
|
||||
public static final String TITLE = "SlimeVR Server (" + Main.VERSION + ")";
|
||||
|
||||
public final VRServer server;
|
||||
private final TrackersList trackersList;
|
||||
private final TrackersFiltersGUI trackersFiltersGUI;
|
||||
private final SkeletonList skeletonList;
|
||||
private final EJBox pane;
|
||||
private JButton resetButton;
|
||||
private float zoom = 1.5f;
|
||||
private float initZoom = zoom;
|
||||
public final VRServer server;
|
||||
private final TrackersList trackersList;
|
||||
private final TrackersFiltersGUI trackersFiltersGUI;
|
||||
private final SkeletonList skeletonList;
|
||||
private final EJBox pane;
|
||||
private JButton resetButton;
|
||||
private float zoom = 1.5f;
|
||||
private float initZoom = zoom;
|
||||
|
||||
@AWTThread
|
||||
public VRServerGUI(VRServer server) {
|
||||
super(TITLE);
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX)
|
||||
MacOSX.setTitle(TITLE);
|
||||
try {
|
||||
List<BufferedImage> images = new ArrayList<BufferedImage>(6);
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon16.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon32.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon48.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon64.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon128.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon256.png")));
|
||||
setIconImages(images);
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX) {
|
||||
MacOSX.setIcons(images);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
@AWTThread
|
||||
public VRServerGUI(VRServer server) {
|
||||
super(TITLE);
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX)
|
||||
MacOSX.setTitle(TITLE);
|
||||
try {
|
||||
List<BufferedImage> images = new ArrayList<BufferedImage>(6);
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon16.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon32.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon48.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon64.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon128.png")));
|
||||
images.add(ImageIO.read(VRServerGUI.class.getResource("/icon256.png")));
|
||||
setIconImages(images);
|
||||
if (OperatingSystem.getCurrentPlatform() == OperatingSystem.OSX) {
|
||||
MacOSX.setIcons(images);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
this.server = server;
|
||||
this.server = server;
|
||||
|
||||
this.zoom = server.config.getFloat("zoom", zoom);
|
||||
this.initZoom = zoom;
|
||||
setDefaultFontSize(zoom);
|
||||
// All components should be constructed to the current zoom level by default
|
||||
this.zoom = server.config.getFloat("zoom", zoom);
|
||||
this.initZoom = zoom;
|
||||
setDefaultFontSize(zoom);
|
||||
// All components should be constructed to the current zoom level by default
|
||||
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), PAGE_AXIS));
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), PAGE_AXIS));
|
||||
|
||||
this.trackersList = new TrackersList(server, this);
|
||||
trackersFiltersGUI = new TrackersFiltersGUI(server, this);
|
||||
this.skeletonList = new SkeletonList(server, this);
|
||||
this.trackersList = new TrackersList(server, this);
|
||||
trackersFiltersGUI = new TrackersFiltersGUI(server, this);
|
||||
this.skeletonList = new SkeletonList(server, this);
|
||||
|
||||
JScrollPane scrollPane = (JScrollPane) add(new JScrollPane(pane = new EJBox(PAGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(16);
|
||||
JScrollPane scrollPane = (JScrollPane) add(new JScrollPane(pane = new EJBox(PAGE_AXIS), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(16);
|
||||
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
setMinimumSize(new Dimension(100, 100));
|
||||
setSize(Math.min(server.config.getInt("window.width", 800), screenBounds.width), Math.min(server.config.getInt("window.height", 800), screenBounds.height));
|
||||
setLocation(server.config.getInt("window.posx", screenBounds.x + (screenBounds.width - getSize().width) / 2), screenBounds.y + server.config.getInt("window.posy", (screenBounds.height - getSize().height) / 2));
|
||||
GraphicsConfiguration gc = getGraphicsConfiguration();
|
||||
Rectangle screenBounds = gc.getBounds();
|
||||
setMinimumSize(new Dimension(100, 100));
|
||||
setSize(Math.min(server.config.getInt("window.width", 800), screenBounds.width), Math.min(server.config.getInt("window.height", 800), screenBounds.height));
|
||||
setLocation(server.config.getInt("window.posx", screenBounds.x + (screenBounds.width - getSize().width) / 2), screenBounds.y + server.config.getInt("window.posy", (screenBounds.height - getSize().height) / 2));
|
||||
|
||||
// Resize and close listeners to save position and size betwen launcher starts
|
||||
addComponentListener(new AbstractComponentListener() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
saveFrameInfo();
|
||||
}
|
||||
// Resize and close listeners to save position and size betwen launcher starts
|
||||
addComponentListener(new AbstractComponentListener() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
saveFrameInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
saveFrameInfo();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
saveFrameInfo();
|
||||
}
|
||||
});
|
||||
|
||||
build();
|
||||
}
|
||||
build();
|
||||
}
|
||||
|
||||
private static void processNewZoom(float zoom, Component comp) {
|
||||
if (comp.isFontSet()) {
|
||||
Font newFont = new ScalableFont(comp.getFont(), zoom);
|
||||
comp.setFont(newFont);
|
||||
}
|
||||
if (comp instanceof Container) {
|
||||
Container cont = (Container) comp;
|
||||
for (Component child : cont.getComponents())
|
||||
processNewZoom(zoom, child);
|
||||
}
|
||||
}
|
||||
private static void processNewZoom(float zoom, Component comp) {
|
||||
if (comp.isFontSet()) {
|
||||
Font newFont = new ScalableFont(comp.getFont(), zoom);
|
||||
comp.setFont(newFont);
|
||||
}
|
||||
if (comp instanceof Container) {
|
||||
Container cont = (Container) comp;
|
||||
for (Component child : cont.getComponents())
|
||||
processNewZoom(zoom, child);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setDefaultFontSize(float zoom) {
|
||||
java.util.Enumeration<Object> keys = UIManager.getDefaults().keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
Object key = keys.nextElement();
|
||||
Object value = UIManager.get(key);
|
||||
if (value instanceof javax.swing.plaf.FontUIResource) {
|
||||
javax.swing.plaf.FontUIResource f = (javax.swing.plaf.FontUIResource) value;
|
||||
javax.swing.plaf.FontUIResource f2 = new javax.swing.plaf.FontUIResource(f.deriveFont(f.getSize() * zoom));
|
||||
UIManager.put(key, f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void setDefaultFontSize(float zoom) {
|
||||
java.util.Enumeration<Object> keys = UIManager.getDefaults().keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
Object key = keys.nextElement();
|
||||
Object value = UIManager.get(key);
|
||||
if (value instanceof javax.swing.plaf.FontUIResource) {
|
||||
javax.swing.plaf.FontUIResource f = (javax.swing.plaf.FontUIResource) value;
|
||||
javax.swing.plaf.FontUIResource f2 = new javax.swing.plaf.FontUIResource(f.deriveFont(f.getSize() * zoom));
|
||||
UIManager.put(key, f2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveFrameInfo() {
|
||||
Rectangle b = getBounds();
|
||||
server.config.setProperty("window.width", b.width);
|
||||
server.config.setProperty("window.height", b.height);
|
||||
server.config.setProperty("window.posx", b.x);
|
||||
server.config.setProperty("window.posy", b.y);
|
||||
server.saveConfig();
|
||||
}
|
||||
protected void saveFrameInfo() {
|
||||
Rectangle b = getBounds();
|
||||
server.config.setProperty("window.width", b.width);
|
||||
server.config.setProperty("window.height", b.height);
|
||||
server.config.setProperty("window.posx", b.x);
|
||||
server.config.setProperty("window.posy", b.y);
|
||||
server.saveConfig();
|
||||
}
|
||||
|
||||
public float getZoom() {
|
||||
return this.zoom;
|
||||
}
|
||||
public float getZoom() {
|
||||
return this.zoom;
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
// Pack and display
|
||||
//pack();
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
public void refresh() {
|
||||
// Pack and display
|
||||
//pack();
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void build() {
|
||||
pane.removeAll();
|
||||
@AWTThread
|
||||
private void build() {
|
||||
pane.removeAll();
|
||||
|
||||
pane.add(new EJBoxNoStretch(LINE_AXIS, false, true) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
pane.add(new EJBoxNoStretch(LINE_AXIS, false, true) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
|
||||
add(Box.createHorizontalGlue());
|
||||
add(resetButton = new JButton("RESET") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
add(new JButton("Fast Reset") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
resetFast();
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalGlue());
|
||||
add(new JButton("Record BVH") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!server.getBvhRecorder().isRecording()) {
|
||||
setText("Stop Recording BVH...");
|
||||
server.getBvhRecorder().startRecording();
|
||||
} else {
|
||||
server.getBvhRecorder().endRecording();
|
||||
setText("Record BVH");
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalGlue());
|
||||
add(new JButton("GUI Zoom (x" + StringUtils.prettyNumber(zoom, 2) + ")") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
guiZoom();
|
||||
setText("GUI Zoom (x" + StringUtils.prettyNumber(zoom, 2) + ")");
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
add(new JButton("WiFi") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
new WiFiWindow(VRServerGUI.this);
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
}});
|
||||
add(Box.createHorizontalGlue());
|
||||
add(resetButton = new JButton("RESET") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
reset();
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
add(new JButton("Fast Reset") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
resetFast();
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalGlue());
|
||||
add(new JButton("Record BVH") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!server.getBvhRecorder().isRecording()) {
|
||||
setText("Stop Recording BVH...");
|
||||
server.getBvhRecorder().startRecording();
|
||||
} else {
|
||||
server.getBvhRecorder().endRecording();
|
||||
setText("Record BVH");
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalGlue());
|
||||
add(new JButton("GUI Zoom (x" + StringUtils.prettyNumber(zoom, 2) + ")") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
guiZoom();
|
||||
setText("GUI Zoom (x" + StringUtils.prettyNumber(zoom, 2) + ")");
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
add(new JButton("WiFi") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
new WiFiWindow(VRServerGUI.this);
|
||||
}
|
||||
});
|
||||
}});
|
||||
add(Box.createHorizontalStrut(10));
|
||||
}});
|
||||
|
||||
pane.add(new EJBox(LINE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
JLabel l;
|
||||
add(l = new JLabel("Trackers list"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(trackersList);
|
||||
add(Box.createVerticalGlue());
|
||||
}});
|
||||
pane.add(new EJBox(LINE_AXIS) {{
|
||||
setBorder(new EmptyBorder(i(5)));
|
||||
add(new EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
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 EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
add(new EJBoxNoStretch(PAGE_AXIS, false, true) {{
|
||||
setAlignmentY(TOP_ALIGNMENT);
|
||||
|
||||
JCheckBox debugCb;
|
||||
add(debugCb = new JCheckBox("Show debug information"));
|
||||
debugCb.setSelected(false);
|
||||
debugCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
trackersList.setDebug(debugCb.isSelected());
|
||||
}
|
||||
});
|
||||
JCheckBox debugCb;
|
||||
add(debugCb = new JCheckBox("Show debug information"));
|
||||
debugCb.setSelected(false);
|
||||
debugCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
trackersList.setDebug(debugCb.isSelected());
|
||||
}
|
||||
});
|
||||
|
||||
JLabel l;
|
||||
add(l = new JLabel("Body proportions"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(new SkeletonConfigGUI(server, VRServerGUI.this));
|
||||
add(Box.createVerticalStrut(10));
|
||||
if (server.hasBridge(WindowsNamedPipeBridge.class)) {
|
||||
WindowsNamedPipeBridge br = server.getVRBridge(WindowsNamedPipeBridge.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);
|
||||
JLabel l;
|
||||
add(l = new JLabel("Body proportions"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(new SkeletonConfigGUI(server, VRServerGUI.this));
|
||||
add(Box.createVerticalStrut(10));
|
||||
if (server.hasBridge(WindowsNamedPipeBridge.class)) {
|
||||
WindowsNamedPipeBridge br = server.getVRBridge(WindowsNamedPipeBridge.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());
|
||||
});
|
||||
}
|
||||
});
|
||||
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("Feet"), 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 legsCb;
|
||||
add(legsCb = new JCheckBox("Feet"), 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 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());
|
||||
});
|
||||
}
|
||||
});
|
||||
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());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox elbowsCb;
|
||||
add(elbowsCb = new JCheckBox("Elbows"), c(1, 3));
|
||||
elbowsCb.setSelected(br.getShareSetting(TrackerRole.LEFT_ELBOW) && br.getShareSetting(TrackerRole.RIGHT_ELBOW));
|
||||
elbowsCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_ELBOW, elbowsCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_ELBOW, elbowsCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
JCheckBox elbowsCb;
|
||||
add(elbowsCb = new JCheckBox("Elbows"), c(1, 3));
|
||||
elbowsCb.setSelected(br.getShareSetting(TrackerRole.LEFT_ELBOW) && br.getShareSetting(TrackerRole.RIGHT_ELBOW));
|
||||
elbowsCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_ELBOW, elbowsCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_ELBOW, elbowsCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
JCheckBox handsCb;
|
||||
add(handsCb = new JCheckBox("Hands"), c(2, 3));
|
||||
handsCb.setSelected(br.getShareSetting(TrackerRole.LEFT_HAND) && br.getShareSetting(TrackerRole.RIGHT_HAND));
|
||||
handsCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_HAND, handsCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_HAND, handsCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
}});
|
||||
JCheckBox handsCb;
|
||||
add(handsCb = new JCheckBox("Hands"), c(2, 3));
|
||||
handsCb.setSelected(br.getShareSetting(TrackerRole.LEFT_HAND) && br.getShareSetting(TrackerRole.RIGHT_HAND));
|
||||
handsCb.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
server.queueTask(() -> {
|
||||
br.changeShareSettings(TrackerRole.LEFT_HAND, handsCb.isSelected());
|
||||
br.changeShareSettings(TrackerRole.RIGHT_HAND, handsCb.isSelected());
|
||||
});
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
||||
add(Box.createVerticalStrut(10));
|
||||
}
|
||||
add(Box.createVerticalStrut(10));
|
||||
}
|
||||
|
||||
add(l = new JLabel("Trackers filtering"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(trackersFiltersGUI);
|
||||
add(l = new JLabel("Trackers filtering"));
|
||||
l.setFont(l.getFont().deriveFont(Font.BOLD));
|
||||
l.setAlignmentX(0.5f);
|
||||
add(trackersFiltersGUI);
|
||||
|
||||
add(Box.createVerticalStrut(10));
|
||||
add(Box.createVerticalStrut(10));
|
||||
|
||||
add(new JLabel("Skeleton data"));
|
||||
add(skeletonList);
|
||||
add(Box.createVerticalGlue());
|
||||
}});
|
||||
}});
|
||||
pane.add(Box.createVerticalGlue());
|
||||
add(new JLabel("Skeleton data"));
|
||||
add(skeletonList);
|
||||
add(Box.createVerticalGlue());
|
||||
}});
|
||||
}});
|
||||
pane.add(Box.createVerticalGlue());
|
||||
|
||||
refresh();
|
||||
refresh();
|
||||
|
||||
server.addOnTick(trackersList::updateTrackers);
|
||||
server.addOnTick(skeletonList::updateBones);
|
||||
}
|
||||
server.addOnTick(trackersList::updateTrackers);
|
||||
server.addOnTick(skeletonList::updateBones);
|
||||
}
|
||||
|
||||
// For now only changes font size, but should change fixed components size in the future too
|
||||
private void guiZoom() {
|
||||
if (zoom <= 1.0f) {
|
||||
zoom = 1.5f;
|
||||
} else if (zoom <= 1.5f) {
|
||||
zoom = 1.75f;
|
||||
} else if (zoom <= 1.75f) {
|
||||
zoom = 2.0f;
|
||||
} else if (zoom <= 2.0f) {
|
||||
zoom = 2.5f;
|
||||
} else {
|
||||
zoom = 1.0f;
|
||||
}
|
||||
processNewZoom(zoom / initZoom, pane);
|
||||
refresh();
|
||||
server.config.setProperty("zoom", zoom);
|
||||
server.saveConfig();
|
||||
}
|
||||
// For now only changes font size, but should change fixed components size in the future too
|
||||
private void guiZoom() {
|
||||
if (zoom <= 1.0f) {
|
||||
zoom = 1.5f;
|
||||
} else if (zoom <= 1.5f) {
|
||||
zoom = 1.75f;
|
||||
} else if (zoom <= 1.75f) {
|
||||
zoom = 2.0f;
|
||||
} else if (zoom <= 2.0f) {
|
||||
zoom = 2.5f;
|
||||
} else {
|
||||
zoom = 1.0f;
|
||||
}
|
||||
processNewZoom(zoom / initZoom, pane);
|
||||
refresh();
|
||||
server.config.setProperty("zoom", zoom);
|
||||
server.saveConfig();
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void resetFast() {
|
||||
server.resetTrackersYaw();
|
||||
}
|
||||
@AWTThread
|
||||
private void resetFast() {
|
||||
server.resetTrackersYaw();
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void reset() {
|
||||
ButtonTimer.runTimer(resetButton, 3, "RESET", server::resetTrackers);
|
||||
}
|
||||
@AWTThread
|
||||
private void reset() {
|
||||
ButtonTimer.runTimer(resetButton, 3, "RESET", server::resetTrackers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,106 +14,106 @@ import java.awt.event.WindowEvent;
|
||||
|
||||
public class WiFiWindow extends JFrame implements SerialListener {
|
||||
|
||||
private static String savedSSID = "";
|
||||
private static String savedPassword = "";
|
||||
private final VRServerGUI gui;
|
||||
JTextField ssidField;
|
||||
JPasswordField passwdField;
|
||||
JTextArea log;
|
||||
private static String savedSSID = "";
|
||||
private static String savedPassword = "";
|
||||
private final VRServerGUI gui;
|
||||
JTextField ssidField;
|
||||
JPasswordField passwdField;
|
||||
JTextArea log;
|
||||
|
||||
public WiFiWindow(VRServerGUI gui) {
|
||||
super("WiFi Settings");
|
||||
this.gui = gui;
|
||||
public WiFiWindow(VRServerGUI gui) {
|
||||
super("WiFi Settings");
|
||||
this.gui = gui;
|
||||
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.LINE_AXIS));
|
||||
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.LINE_AXIS));
|
||||
|
||||
this.gui.server.getSerialHandler().addListener(this);
|
||||
this.gui.server.getSerialHandler().addListener(this);
|
||||
|
||||
build();
|
||||
}
|
||||
build();
|
||||
}
|
||||
|
||||
@AWTThread
|
||||
private void build() {
|
||||
if (!this.gui.server.getSerialHandler().openSerial()) {
|
||||
JOptionPane.showMessageDialog(null, "Unable to open a serial connection. Check that your drivers are installed and nothing is using the serial port already (like Cura or VScode or another slimeVR server)", "SlimeVR: Serial connection error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
@AWTThread
|
||||
private void build() {
|
||||
if (!this.gui.server.getSerialHandler().openSerial()) {
|
||||
JOptionPane.showMessageDialog(null, "Unable to open a serial connection. Check that your drivers are installed and nothing is using the serial port already (like Cura or VScode or another slimeVR server)", "SlimeVR: Serial connection error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialConnected(SerialPort port) {
|
||||
Container pane = getContentPane();
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
add(new JLabel("Tracker connected to " + port.getSystemPortName() + " (" + port.getDescriptivePortName() + ")"));
|
||||
JScrollPane scroll;
|
||||
add(scroll = new JScrollPane(log = new JTextArea(10, 20), ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER));
|
||||
log.setLineWrap(true);
|
||||
scroll.setAutoscrolls(true);
|
||||
add(new JLabel("Enter WiFi credentials:"));
|
||||
add(new EJBox(BoxLayout.LINE_AXIS) {{
|
||||
add(new JLabel("Network name:"));
|
||||
add(ssidField = new JTextField(savedSSID));
|
||||
}});
|
||||
add(new EJBox(BoxLayout.LINE_AXIS) {{
|
||||
add(new JLabel("Network password:"));
|
||||
passwdField = new JPasswordField(savedPassword);
|
||||
passwdField.setEchoChar('\u25cf');
|
||||
add(passwdField);
|
||||
add(new JCheckBox("Show Password") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (isSelected())
|
||||
passwdField.setEchoChar((char) 0);
|
||||
else
|
||||
passwdField.setEchoChar('\u25cf');
|
||||
}
|
||||
});
|
||||
}});
|
||||
}});
|
||||
add(new JButton("Send") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
savedSSID = ssidField.getText();
|
||||
savedPassword = new String(passwdField.getPassword());
|
||||
gui.server.getSerialHandler().setWifi(savedSSID, savedPassword);
|
||||
}
|
||||
});
|
||||
}});
|
||||
}});
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialConnected(SerialPort port) {
|
||||
Container pane = getContentPane();
|
||||
pane.add(new EJBox(BoxLayout.PAGE_AXIS) {{
|
||||
add(new JLabel("Tracker connected to " + port.getSystemPortName() + " (" + port.getDescriptivePortName() + ")"));
|
||||
JScrollPane scroll;
|
||||
add(scroll = new JScrollPane(log = new JTextArea(10, 20), ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER));
|
||||
log.setLineWrap(true);
|
||||
scroll.setAutoscrolls(true);
|
||||
add(new JLabel("Enter WiFi credentials:"));
|
||||
add(new EJBox(BoxLayout.LINE_AXIS) {{
|
||||
add(new JLabel("Network name:"));
|
||||
add(ssidField = new JTextField(savedSSID));
|
||||
}});
|
||||
add(new EJBox(BoxLayout.LINE_AXIS) {{
|
||||
add(new JLabel("Network password:"));
|
||||
passwdField = new JPasswordField(savedPassword);
|
||||
passwdField.setEchoChar('\u25cf');
|
||||
add(passwdField);
|
||||
add(new JCheckBox("Show Password") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (isSelected())
|
||||
passwdField.setEchoChar((char) 0);
|
||||
else
|
||||
passwdField.setEchoChar('\u25cf');
|
||||
}
|
||||
});
|
||||
}});
|
||||
}});
|
||||
add(new JButton("Send") {{
|
||||
addMouseListener(new MouseInputAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
savedSSID = ssidField.getText();
|
||||
savedPassword = new String(passwdField.getPassword());
|
||||
gui.server.getSerialHandler().setWifi(savedSSID, savedPassword);
|
||||
}
|
||||
});
|
||||
}});
|
||||
}});
|
||||
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
toFront();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
final WiFiWindow window = this;
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent windowEvent) {
|
||||
gui.server.getSerialHandler().closeSerial();
|
||||
dispose();
|
||||
gui.server.getSerialHandler().removeListener(window);
|
||||
}
|
||||
});
|
||||
}
|
||||
pack();
|
||||
setLocationRelativeTo(null);
|
||||
setVisible(true);
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
toFront();
|
||||
repaint();
|
||||
}
|
||||
});
|
||||
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
final WiFiWindow window = this;
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent windowEvent) {
|
||||
gui.server.getSerialHandler().closeSerial();
|
||||
dispose();
|
||||
gui.server.getSerialHandler().removeListener(window);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialDisconnected() {
|
||||
log.append("[SERVER] Serial port disconnected");
|
||||
}
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialDisconnected() {
|
||||
log.append("[SERVER] Serial port disconnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialLog(String str) {
|
||||
log.append(str);
|
||||
}
|
||||
@Override
|
||||
@AWTThread
|
||||
public void onSerialLog(String str) {
|
||||
log.append(str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,35 +6,35 @@ import java.util.TimerTask;
|
||||
|
||||
public class ButtonTimer {
|
||||
|
||||
private static final Timer timer = new Timer();
|
||||
private static final Timer timer = new Timer();
|
||||
|
||||
public static void runTimer(AbstractButton button, int seconds, String defaultText, Runnable runnable) {
|
||||
if (seconds <= 0) {
|
||||
button.setText(defaultText);
|
||||
runnable.run();
|
||||
} else {
|
||||
button.setText(String.valueOf(seconds));
|
||||
timer.schedule(new ButtonTimerTask(button, seconds - 1, defaultText, runnable), 1000);
|
||||
}
|
||||
}
|
||||
public static void runTimer(AbstractButton button, int seconds, String defaultText, Runnable runnable) {
|
||||
if (seconds <= 0) {
|
||||
button.setText(defaultText);
|
||||
runnable.run();
|
||||
} else {
|
||||
button.setText(String.valueOf(seconds));
|
||||
timer.schedule(new ButtonTimerTask(button, seconds - 1, defaultText, runnable), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ButtonTimerTask extends TimerTask {
|
||||
private static class ButtonTimerTask extends TimerTask {
|
||||
|
||||
private final AbstractButton button;
|
||||
private final int seconds;
|
||||
private final String defaultText;
|
||||
private final Runnable runnable;
|
||||
private final AbstractButton button;
|
||||
private final int seconds;
|
||||
private final String defaultText;
|
||||
private final Runnable runnable;
|
||||
|
||||
private ButtonTimerTask(AbstractButton button, int seconds, String defaultText, Runnable runnable) {
|
||||
this.button = button;
|
||||
this.seconds = seconds;
|
||||
this.defaultText = defaultText;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
private ButtonTimerTask(AbstractButton button, int seconds, String defaultText, Runnable runnable) {
|
||||
this.button = button;
|
||||
this.seconds = seconds;
|
||||
this.defaultText = defaultText;
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
runTimer(button, seconds, defaultText, runnable);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
runTimer(button, seconds, defaultText, runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.awt.*;
|
||||
|
||||
public class EJBag extends EJPanel {
|
||||
|
||||
public EJBag() {
|
||||
super(new GridBagLayout());
|
||||
}
|
||||
public EJBag() {
|
||||
super(new GridBagLayout());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,28 +4,28 @@ import java.awt.*;
|
||||
|
||||
public class EJBagNoStretch extends EJPanel {
|
||||
|
||||
public EJBagNoStretch(boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super(new EGridBagLayoutNoStretch(stretchVertical, stretchHorizontal));
|
||||
}
|
||||
public EJBagNoStretch(boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super(new EGridBagLayoutNoStretch(stretchVertical, stretchHorizontal));
|
||||
}
|
||||
|
||||
private static class EGridBagLayoutNoStretch extends GridBagLayout {
|
||||
private static class EGridBagLayoutNoStretch extends GridBagLayout {
|
||||
|
||||
private final boolean stretchVertical;
|
||||
private final boolean stretchHorizontal;
|
||||
private final boolean stretchVertical;
|
||||
private final boolean stretchHorizontal;
|
||||
|
||||
public EGridBagLayoutNoStretch(boolean stretchVertical, boolean stretchHorizontal) {
|
||||
this.stretchVertical = stretchVertical;
|
||||
this.stretchHorizontal = 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;
|
||||
}
|
||||
}
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import javax.swing.*;
|
||||
|
||||
public class EJBox extends EJPanel {
|
||||
|
||||
public EJBox(int layout) {
|
||||
super();
|
||||
setLayout(new BoxLayout(this, layout));
|
||||
}
|
||||
public EJBox(int layout) {
|
||||
super();
|
||||
setLayout(new BoxLayout(this, layout));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,30 +5,30 @@ import java.awt.*;
|
||||
|
||||
public class EJBoxNoStretch extends EJPanel {
|
||||
|
||||
public EJBoxNoStretch(int layout, boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super();
|
||||
setLayout(new BoxLayoutNoStretch(this, layout, stretchVertical, stretchHorizontal));
|
||||
}
|
||||
public EJBoxNoStretch(int layout, boolean stretchVertical, boolean stretchHorizontal) {
|
||||
super();
|
||||
setLayout(new BoxLayoutNoStretch(this, layout, stretchVertical, stretchHorizontal));
|
||||
}
|
||||
|
||||
private static class BoxLayoutNoStretch extends BoxLayout {
|
||||
private static class BoxLayoutNoStretch extends BoxLayout {
|
||||
|
||||
private final boolean stretchVertical;
|
||||
private final boolean stretchHorizontal;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,100 +5,100 @@ import java.awt.*;
|
||||
|
||||
public abstract class EJPanel extends JPanel {
|
||||
|
||||
public static boolean NEEDS_DOWNSCALE = false;
|
||||
public static float DOWNSCALE_FACTOR = 0.75f;
|
||||
public static boolean NEEDS_DOWNSCALE = false;
|
||||
public static float DOWNSCALE_FACTOR = 0.75f;
|
||||
|
||||
public EJPanel() {
|
||||
super();
|
||||
}
|
||||
public EJPanel() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EJPanel(LayoutManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
public EJPanel(LayoutManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
public static void s(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setSize(width, height);
|
||||
Dimension d = new Dimension(width, height);
|
||||
c.setPreferredSize(d);
|
||||
c.setMaximumSize(d);
|
||||
c.setMinimumSize(d);
|
||||
}
|
||||
public static void s(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setSize(width, height);
|
||||
Dimension d = new Dimension(width, height);
|
||||
c.setPreferredSize(d);
|
||||
c.setMaximumSize(d);
|
||||
c.setMinimumSize(d);
|
||||
}
|
||||
|
||||
public static void minWidth(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setPreferredSize(new Dimension(Short.MAX_VALUE, height));
|
||||
c.setMaximumSize(new Dimension(Short.MAX_VALUE, height));
|
||||
c.setMinimumSize(new Dimension(width, height));
|
||||
}
|
||||
public static void minWidth(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setPreferredSize(new Dimension(Short.MAX_VALUE, height));
|
||||
c.setMaximumSize(new Dimension(Short.MAX_VALUE, height));
|
||||
c.setMinimumSize(new Dimension(width, height));
|
||||
}
|
||||
|
||||
public static void minHeight(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setPreferredSize(new Dimension(width, Short.MAX_VALUE));
|
||||
c.setMaximumSize(new Dimension(width, Short.MAX_VALUE));
|
||||
c.setMinimumSize(new Dimension(width, height));
|
||||
}
|
||||
public static void minHeight(Component c, int width, int height) {
|
||||
if (NEEDS_DOWNSCALE) {
|
||||
height = (int) Math.ceil(height * DOWNSCALE_FACTOR);
|
||||
width = (int) Math.ceil(width * DOWNSCALE_FACTOR);
|
||||
}
|
||||
c.setPreferredSize(new Dimension(width, Short.MAX_VALUE));
|
||||
c.setMaximumSize(new Dimension(width, Short.MAX_VALUE));
|
||||
c.setMinimumSize(new Dimension(width, height));
|
||||
}
|
||||
|
||||
public static GridBagConstraints c(int x, int y) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
return c;
|
||||
}
|
||||
public static GridBagConstraints c(int x, int y) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static GridBagConstraints c(int x, int y, int padding) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = new Insets(padding, padding, padding, padding);
|
||||
return c;
|
||||
}
|
||||
public static GridBagConstraints c(int x, int y, int padding) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = new Insets(padding, padding, padding, padding);
|
||||
return c;
|
||||
}
|
||||
|
||||
public static GridBagConstraints c(int x, int y, int padding, int anchor) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = new Insets(padding, padding, padding, padding);
|
||||
c.anchor = anchor;
|
||||
return c;
|
||||
}
|
||||
public static GridBagConstraints c(int x, int y, int padding, int anchor) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = new Insets(padding, padding, padding, padding);
|
||||
c.anchor = anchor;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static GridBagConstraints c(int x, int y, Insets insets) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = insets;
|
||||
return c;
|
||||
}
|
||||
public static GridBagConstraints c(int x, int y, Insets insets) {
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.gridx = x;
|
||||
c.gridy = y;
|
||||
c.insets = insets;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static GridBagConstraints s(GridBagConstraints c, int gridwidth, int gridheight) {
|
||||
c.gridwidth = gridwidth;
|
||||
c.gridheight = gridheight;
|
||||
return c;
|
||||
}
|
||||
public static GridBagConstraints s(GridBagConstraints c, int gridwidth, int gridheight) {
|
||||
c.gridwidth = gridwidth;
|
||||
c.gridheight = gridheight;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static Insets i(int s) {
|
||||
return new Insets(s, s, s, s);
|
||||
}
|
||||
public static Insets i(int s) {
|
||||
return new Insets(s, s, s, s);
|
||||
}
|
||||
|
||||
public static Insets i(int h, int v) {
|
||||
return new Insets(v, h, v, h);
|
||||
}
|
||||
public static Insets i(int h, int v) {
|
||||
return new Insets(v, h, v, h);
|
||||
}
|
||||
|
||||
public static Component padding(int width, int height) {
|
||||
return Box.createRigidArea(new Dimension(width, height));
|
||||
}
|
||||
public static Component padding(int width, int height) {
|
||||
return Box.createRigidArea(new Dimension(width, height));
|
||||
}
|
||||
|
||||
public static int fontSize(int baseSize) {
|
||||
return NEEDS_DOWNSCALE ? (int) Math.ceil(baseSize * DOWNSCALE_FACTOR) : baseSize;
|
||||
}
|
||||
public static int fontSize(int baseSize) {
|
||||
return NEEDS_DOWNSCALE ? (int) Math.ceil(baseSize * DOWNSCALE_FACTOR) : baseSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import com.sun.jna.Native;
|
||||
|
||||
public interface Magneto extends Library {
|
||||
|
||||
Magneto INSTANCE = Native.load("MagnetoLib", Magneto.class);
|
||||
Magneto INSTANCE = Native.load("MagnetoLib", Magneto.class);
|
||||
|
||||
void calculate(double[] data, int nlines, double nxsrej, double hm, double[] B, double[] A_1);
|
||||
void calculate(double[] data, int nlines, double nxsrej, double hm, double[] B, double[] A_1);
|
||||
|
||||
double calculateHnorm(double[] data, int nlines);
|
||||
double calculateHnorm(double[] data, int nlines);
|
||||
}
|
||||
|
||||
@@ -20,200 +20,200 @@ import java.util.List;
|
||||
|
||||
public class WindowsNamedPipeBridge extends ProtobufBridge<VRTracker> implements Runnable {
|
||||
|
||||
protected final String pipeName;
|
||||
protected final String bridgeSettingsKey;
|
||||
protected final Thread runnerThread;
|
||||
private final TrackerRole[] defaultRoles = new TrackerRole[]{TrackerRole.WAIST, TrackerRole.LEFT_FOOT, TrackerRole.RIGHT_FOOT};
|
||||
private final byte[] buffArray = new byte[2048];
|
||||
private final List<? extends ShareableTracker> shareableTrackers;
|
||||
protected WindowsPipe pipe;
|
||||
protected final String pipeName;
|
||||
protected final String bridgeSettingsKey;
|
||||
protected final Thread runnerThread;
|
||||
private final TrackerRole[] defaultRoles = new TrackerRole[]{TrackerRole.WAIST, TrackerRole.LEFT_FOOT, TrackerRole.RIGHT_FOOT};
|
||||
private final byte[] buffArray = new byte[2048];
|
||||
private final List<? extends ShareableTracker> shareableTrackers;
|
||||
protected WindowsPipe pipe;
|
||||
|
||||
public WindowsNamedPipeBridge(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;
|
||||
}
|
||||
public WindowsNamedPipeBridge(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();
|
||||
}
|
||||
@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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@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
|
||||
@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
|
||||
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;
|
||||
}
|
||||
@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);
|
||||
messageReceived(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 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);
|
||||
messageReceived(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() {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
private void resetPipe() {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
|
||||
private void createPipe() 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.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) {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
private void createPipe() 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.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) {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryOpeningPipe(WindowsPipe 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;
|
||||
}
|
||||
private boolean tryOpeningPipe(WindowsPipe 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,264 +21,264 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class WindowsNamedPipeVRBridge extends Thread implements Bridge {
|
||||
|
||||
public static final String HMDPipeName = "\\\\.\\pipe\\HMDPipe";
|
||||
public static final String TrackersPipeName = "\\\\.\\pipe\\TrackPipe";
|
||||
public static final Charset ASCII = StandardCharsets.US_ASCII;
|
||||
private static final int MAX_COMMAND_LENGTH = 2048;
|
||||
private final byte[] buffArray = new byte[1024];
|
||||
private final StringBuilder commandBuilder = new StringBuilder(1024);
|
||||
private final StringBuilder sbBuffer = new StringBuilder(1024);
|
||||
private final Vector3f vBuffer = new Vector3f();
|
||||
private final Vector3f vBuffer2 = new Vector3f();
|
||||
private final Quaternion qBuffer = new Quaternion();
|
||||
private final Quaternion qBuffer2 = new Quaternion();
|
||||
private final HMDTracker hmd;
|
||||
private final List<WindowsPipe> trackerPipes;
|
||||
private final List<? extends Tracker> shareTrackers;
|
||||
private final List<ComputedTracker> internalTrackers;
|
||||
private final HMDTracker internalHMDTracker = new HMDTracker("internal://HMD");
|
||||
private final AtomicBoolean newHMDData = new AtomicBoolean(false);
|
||||
private WindowsPipe hmdPipe;
|
||||
public static final String HMDPipeName = "\\\\.\\pipe\\HMDPipe";
|
||||
public static final String TrackersPipeName = "\\\\.\\pipe\\TrackPipe";
|
||||
public static final Charset ASCII = StandardCharsets.US_ASCII;
|
||||
private static final int MAX_COMMAND_LENGTH = 2048;
|
||||
private final byte[] buffArray = new byte[1024];
|
||||
private final StringBuilder commandBuilder = new StringBuilder(1024);
|
||||
private final StringBuilder sbBuffer = new StringBuilder(1024);
|
||||
private final Vector3f vBuffer = new Vector3f();
|
||||
private final Vector3f vBuffer2 = new Vector3f();
|
||||
private final Quaternion qBuffer = new Quaternion();
|
||||
private final Quaternion qBuffer2 = new Quaternion();
|
||||
private final HMDTracker hmd;
|
||||
private final List<WindowsPipe> trackerPipes;
|
||||
private final List<? extends Tracker> shareTrackers;
|
||||
private final List<ComputedTracker> internalTrackers;
|
||||
private final HMDTracker internalHMDTracker = new HMDTracker("internal://HMD");
|
||||
private final AtomicBoolean newHMDData = new AtomicBoolean(false);
|
||||
private WindowsPipe hmdPipe;
|
||||
|
||||
public WindowsNamedPipeVRBridge(HMDTracker hmd, List<? extends Tracker> shareTrackers, VRServer server) {
|
||||
super("Named Pipe VR Bridge");
|
||||
this.hmd = hmd;
|
||||
this.shareTrackers = new FastList<>(shareTrackers);
|
||||
this.trackerPipes = new FastList<>(shareTrackers.size());
|
||||
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);
|
||||
this.internalTrackers.add(ct);
|
||||
}
|
||||
}
|
||||
public WindowsNamedPipeVRBridge(HMDTracker hmd, List<? extends Tracker> shareTrackers, VRServer server) {
|
||||
super("Named Pipe VR Bridge");
|
||||
this.hmd = hmd;
|
||||
this.shareTrackers = new FastList<>(shareTrackers);
|
||||
this.trackerPipes = new FastList<>(shareTrackers.size());
|
||||
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);
|
||||
this.internalTrackers.add(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public static void safeDisconnect(WindowsPipe pipe) {
|
||||
try {
|
||||
if (pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
public static void safeDisconnect(WindowsPipe pipe) {
|
||||
try {
|
||||
if (pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
createPipes();
|
||||
while (true) {
|
||||
waitForPipesToOpen();
|
||||
if (areAllPipesOpen()) {
|
||||
boolean hmdUpdated = updateHMD(); // Update at HMDs frequency
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
updateTracker(i, hmdUpdated);
|
||||
}
|
||||
if (!hmdUpdated) {
|
||||
Thread.sleep(5); // Up to 200Hz
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
createPipes();
|
||||
while (true) {
|
||||
waitForPipesToOpen();
|
||||
if (areAllPipesOpen()) {
|
||||
boolean hmdUpdated = updateHMD(); // Update at HMDs frequency
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
updateTracker(i, hmdUpdated);
|
||||
}
|
||||
if (!hmdUpdated) {
|
||||
Thread.sleep(5); // Up to 200Hz
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataRead() {
|
||||
if (newHMDData.compareAndSet(true, false)) {
|
||||
hmd.position.set(internalHMDTracker.position);
|
||||
hmd.rotation.set(internalHMDTracker.rotation);
|
||||
hmd.dataTick();
|
||||
}
|
||||
}
|
||||
@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(vBuffer2))
|
||||
it.position.set(vBuffer2);
|
||||
if (t.getRotation(qBuffer2))
|
||||
it.rotation.set(qBuffer2);
|
||||
}
|
||||
}
|
||||
@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(vBuffer2))
|
||||
it.position.set(vBuffer2);
|
||||
if (t.getRotation(qBuffer2))
|
||||
it.rotation.set(qBuffer2);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForPipesToOpen() {
|
||||
if (hmdPipe.state == PipeState.CREATED) {
|
||||
if (tryOpeningPipe(hmdPipe))
|
||||
initHMDPipe(hmdPipe);
|
||||
}
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
WindowsPipe trackerPipe = trackerPipes.get(i);
|
||||
if (trackerPipe.state == PipeState.CREATED) {
|
||||
if (tryOpeningPipe(trackerPipe))
|
||||
initTrackerPipe(trackerPipe, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void waitForPipesToOpen() {
|
||||
if (hmdPipe.state == PipeState.CREATED) {
|
||||
if (tryOpeningPipe(hmdPipe))
|
||||
initHMDPipe(hmdPipe);
|
||||
}
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
WindowsPipe trackerPipe = trackerPipes.get(i);
|
||||
if (trackerPipe.state == PipeState.CREATED) {
|
||||
if (tryOpeningPipe(trackerPipe))
|
||||
initTrackerPipe(trackerPipe, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updateHMD() throws IOException {
|
||||
if (hmdPipe.state == PipeState.OPEN) {
|
||||
IntByReference bytesAvailable = new IntByReference(0);
|
||||
if (Kernel32.INSTANCE.PeekNamedPipe(hmdPipe.pipeHandle, null, 0, null, bytesAvailable, null)) {
|
||||
if (bytesAvailable.getValue() > 0) {
|
||||
while (Kernel32.INSTANCE.ReadFile(hmdPipe.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') {
|
||||
executeHMDInput();
|
||||
commandBuilder.setLength(0);
|
||||
} else {
|
||||
commandBuilder.append(c);
|
||||
if (commandBuilder.length() >= MAX_COMMAND_LENGTH) {
|
||||
LogManager.log.severe("[VRBridge] Command from the pipe is too long, flushing buffer");
|
||||
commandBuilder.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytesRead < buffArray.length)
|
||||
break; // Don't repeat, we read all available bytes
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean updateHMD() throws IOException {
|
||||
if (hmdPipe.state == PipeState.OPEN) {
|
||||
IntByReference bytesAvailable = new IntByReference(0);
|
||||
if (Kernel32.INSTANCE.PeekNamedPipe(hmdPipe.pipeHandle, null, 0, null, bytesAvailable, null)) {
|
||||
if (bytesAvailable.getValue() > 0) {
|
||||
while (Kernel32.INSTANCE.ReadFile(hmdPipe.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') {
|
||||
executeHMDInput();
|
||||
commandBuilder.setLength(0);
|
||||
} else {
|
||||
commandBuilder.append(c);
|
||||
if (commandBuilder.length() >= MAX_COMMAND_LENGTH) {
|
||||
LogManager.log.severe("[VRBridge] Command from the pipe is too long, flushing buffer");
|
||||
commandBuilder.setLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytesRead < buffArray.length)
|
||||
break; // Don't repeat, we read all available bytes
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void executeHMDInput() throws IOException {
|
||||
String[] split = commandBuilder.toString().split(" ");
|
||||
if (split.length < 7) {
|
||||
LogManager.log.severe("[VRBridge] Short HMD data received: " + commandBuilder);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
double x = Double.parseDouble(split[0]);
|
||||
double y = Double.parseDouble(split[1]);
|
||||
double z = Double.parseDouble(split[2]);
|
||||
double qw = Double.parseDouble(split[3]);
|
||||
double qx = Double.parseDouble(split[4]);
|
||||
double qy = Double.parseDouble(split[5]);
|
||||
double qz = Double.parseDouble(split[6]);
|
||||
private void executeHMDInput() throws IOException {
|
||||
String[] split = commandBuilder.toString().split(" ");
|
||||
if (split.length < 7) {
|
||||
LogManager.log.severe("[VRBridge] Short HMD data received: " + commandBuilder);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
double x = Double.parseDouble(split[0]);
|
||||
double y = Double.parseDouble(split[1]);
|
||||
double z = Double.parseDouble(split[2]);
|
||||
double qw = Double.parseDouble(split[3]);
|
||||
double qx = Double.parseDouble(split[4]);
|
||||
double qy = Double.parseDouble(split[5]);
|
||||
double qz = Double.parseDouble(split[6]);
|
||||
|
||||
internalHMDTracker.position.set((float) x, (float) y, (float) z);
|
||||
internalHMDTracker.rotation.set((float) qx, (float) qy, (float) qz, (float) qw);
|
||||
internalHMDTracker.dataTick();
|
||||
newHMDData.set(true);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
internalHMDTracker.position.set((float) x, (float) y, (float) z);
|
||||
internalHMDTracker.rotation.set((float) qx, (float) qy, (float) qz, (float) qw);
|
||||
internalHMDTracker.dataTick();
|
||||
newHMDData.set(true);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTracker(int trackerId, boolean hmdUpdated) {
|
||||
Tracker sensor = internalTrackers.get(trackerId);
|
||||
if (sensor.getStatus().sendData) {
|
||||
WindowsPipe trackerPipe = trackerPipes.get(trackerId);
|
||||
if (hmdUpdated && trackerPipe.state == PipeState.OPEN) {
|
||||
sbBuffer.setLength(0);
|
||||
sensor.getPosition(vBuffer);
|
||||
sensor.getRotation(qBuffer);
|
||||
sbBuffer.append(vBuffer.x).append(' ').append(vBuffer.y).append(' ').append(vBuffer.z).append(' ');
|
||||
sbBuffer.append(qBuffer.getW()).append(' ').append(qBuffer.getX()).append(' ').append(qBuffer.getY()).append(' ').append(qBuffer.getZ()).append('\n');
|
||||
String str = sbBuffer.toString();
|
||||
System.arraycopy(str.getBytes(ASCII), 0, buffArray, 0, str.length());
|
||||
buffArray[str.length()] = '\0';
|
||||
IntByReference lpNumberOfBytesWritten = new IntByReference(0);
|
||||
Kernel32.INSTANCE.WriteFile(trackerPipe.pipeHandle, buffArray, str.length() + 1, lpNumberOfBytesWritten, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void updateTracker(int trackerId, boolean hmdUpdated) {
|
||||
Tracker sensor = internalTrackers.get(trackerId);
|
||||
if (sensor.getStatus().sendData) {
|
||||
WindowsPipe trackerPipe = trackerPipes.get(trackerId);
|
||||
if (hmdUpdated && trackerPipe.state == PipeState.OPEN) {
|
||||
sbBuffer.setLength(0);
|
||||
sensor.getPosition(vBuffer);
|
||||
sensor.getRotation(qBuffer);
|
||||
sbBuffer.append(vBuffer.x).append(' ').append(vBuffer.y).append(' ').append(vBuffer.z).append(' ');
|
||||
sbBuffer.append(qBuffer.getW()).append(' ').append(qBuffer.getX()).append(' ').append(qBuffer.getY()).append(' ').append(qBuffer.getZ()).append('\n');
|
||||
String str = sbBuffer.toString();
|
||||
System.arraycopy(str.getBytes(ASCII), 0, buffArray, 0, str.length());
|
||||
buffArray[str.length()] = '\0';
|
||||
IntByReference lpNumberOfBytesWritten = new IntByReference(0);
|
||||
Kernel32.INSTANCE.WriteFile(trackerPipe.pipeHandle, buffArray, str.length() + 1, lpNumberOfBytesWritten, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initHMDPipe(WindowsPipe pipe) {
|
||||
hmd.setStatus(TrackerStatus.OK);
|
||||
}
|
||||
private void initHMDPipe(WindowsPipe pipe) {
|
||||
hmd.setStatus(TrackerStatus.OK);
|
||||
}
|
||||
|
||||
private void initTrackerPipe(WindowsPipe pipe, int trackerId) {
|
||||
String trackerHello = this.shareTrackers.size() + " 0";
|
||||
System.arraycopy(trackerHello.getBytes(ASCII), 0, buffArray, 0, trackerHello.length());
|
||||
buffArray[trackerHello.length()] = '\0';
|
||||
IntByReference lpNumberOfBytesWritten = new IntByReference(0);
|
||||
Kernel32.INSTANCE.WriteFile(pipe.pipeHandle,
|
||||
buffArray,
|
||||
trackerHello.length() + 1,
|
||||
lpNumberOfBytesWritten,
|
||||
null);
|
||||
}
|
||||
private void initTrackerPipe(WindowsPipe pipe, int trackerId) {
|
||||
String trackerHello = this.shareTrackers.size() + " 0";
|
||||
System.arraycopy(trackerHello.getBytes(ASCII), 0, buffArray, 0, trackerHello.length());
|
||||
buffArray[trackerHello.length()] = '\0';
|
||||
IntByReference lpNumberOfBytesWritten = new IntByReference(0);
|
||||
Kernel32.INSTANCE.WriteFile(pipe.pipeHandle,
|
||||
buffArray,
|
||||
trackerHello.length() + 1,
|
||||
lpNumberOfBytesWritten,
|
||||
null);
|
||||
}
|
||||
|
||||
private boolean tryOpeningPipe(WindowsPipe pipe) {
|
||||
if (Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null)) {
|
||||
pipe.state = PipeState.OPEN;
|
||||
LogManager.log.info("[VRBridge] Pipe " + pipe.name + " is open");
|
||||
return true;
|
||||
}
|
||||
private boolean tryOpeningPipe(WindowsPipe pipe) {
|
||||
if (Kernel32.INSTANCE.ConnectNamedPipe(pipe.pipeHandle, null)) {
|
||||
pipe.state = PipeState.OPEN;
|
||||
LogManager.log.info("[VRBridge] Pipe " + pipe.name + " is open");
|
||||
return true;
|
||||
}
|
||||
|
||||
LogManager.log.info("[VRBridge] Error connecting to pipe " + pipe.name + ": " + Kernel32.INSTANCE.GetLastError());
|
||||
return false;
|
||||
}
|
||||
LogManager.log.info("[VRBridge] Error connecting to pipe " + pipe.name + ": " + Kernel32.INSTANCE.GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean areAllPipesOpen() {
|
||||
if (hmdPipe == null || hmdPipe.state == PipeState.CREATED) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
if (trackerPipes.get(i).state == PipeState.CREATED)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private boolean areAllPipesOpen() {
|
||||
if (hmdPipe == null || hmdPipe.state == PipeState.CREATED) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < trackerPipes.size(); ++i) {
|
||||
if (trackerPipes.get(i).state == PipeState.CREATED)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void createPipes() throws IOException {
|
||||
try {
|
||||
hmdPipe = new WindowsPipe(Kernel32.INSTANCE.CreateNamedPipe(HMDPipeName, 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), HMDPipeName); // lpSecurityAttributes
|
||||
LogManager.log.info("[VRBridge] Pipe " + hmdPipe.name + " created");
|
||||
if (WinBase.INVALID_HANDLE_VALUE.equals(hmdPipe.pipeHandle))
|
||||
throw new IOException("Can't open " + HMDPipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
for (int i = 0; i < this.shareTrackers.size(); ++i) {
|
||||
String pipeName = TrackersPipeName + i;
|
||||
HANDLE pipeHandle = 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); // lpSecurityAttributes
|
||||
if (WinBase.INVALID_HANDLE_VALUE.equals(pipeHandle))
|
||||
throw new IOException("Can't open " + pipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
LogManager.log.info("[VRBridge] Pipe " + pipeName + " created");
|
||||
trackerPipes.add(new WindowsPipe(pipeHandle, pipeName));
|
||||
}
|
||||
LogManager.log.info("[VRBridge] Pipes are open");
|
||||
} catch (IOException e) {
|
||||
safeDisconnect(hmdPipe);
|
||||
for (int i = 0; i < trackerPipes.size(); ++i)
|
||||
safeDisconnect(trackerPipes.get(i));
|
||||
trackerPipes.clear();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
private void createPipes() throws IOException {
|
||||
try {
|
||||
hmdPipe = new WindowsPipe(Kernel32.INSTANCE.CreateNamedPipe(HMDPipeName, 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), HMDPipeName); // lpSecurityAttributes
|
||||
LogManager.log.info("[VRBridge] Pipe " + hmdPipe.name + " created");
|
||||
if (WinBase.INVALID_HANDLE_VALUE.equals(hmdPipe.pipeHandle))
|
||||
throw new IOException("Can't open " + HMDPipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
for (int i = 0; i < this.shareTrackers.size(); ++i) {
|
||||
String pipeName = TrackersPipeName + i;
|
||||
HANDLE pipeHandle = 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); // lpSecurityAttributes
|
||||
if (WinBase.INVALID_HANDLE_VALUE.equals(pipeHandle))
|
||||
throw new IOException("Can't open " + pipeName + " pipe: " + Kernel32.INSTANCE.GetLastError());
|
||||
LogManager.log.info("[VRBridge] Pipe " + pipeName + " created");
|
||||
trackerPipes.add(new WindowsPipe(pipeHandle, pipeName));
|
||||
}
|
||||
LogManager.log.info("[VRBridge] Pipes are open");
|
||||
} catch (IOException e) {
|
||||
safeDisconnect(hmdPipe);
|
||||
for (int i = 0; i < trackerPipes.size(); ++i)
|
||||
safeDisconnect(trackerPipes.get(i));
|
||||
trackerPipes.clear();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSharedTracker(ShareableTracker tracker) {
|
||||
// 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 removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,20 @@ import dev.slimevr.bridge.PipeState;
|
||||
|
||||
public class WindowsPipe {
|
||||
|
||||
public final String name;
|
||||
public final HANDLE pipeHandle;
|
||||
public PipeState state = PipeState.CREATED;
|
||||
public final String name;
|
||||
public final HANDLE pipeHandle;
|
||||
public PipeState state = PipeState.CREATED;
|
||||
|
||||
public WindowsPipe(HANDLE pipeHandle, String name) {
|
||||
this.pipeHandle = pipeHandle;
|
||||
this.name = name;
|
||||
}
|
||||
public WindowsPipe(HANDLE pipeHandle, String name) {
|
||||
this.pipeHandle = pipeHandle;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static void safeDisconnect(WindowsPipe pipe) {
|
||||
try {
|
||||
if (pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
public static void safeDisconnect(WindowsPipe pipe) {
|
||||
try {
|
||||
if (pipe != null && pipe.pipeHandle != null)
|
||||
Kernel32.INSTANCE.DisconnectNamedPipe(pipe.pipeHandle);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,267 +26,267 @@ 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 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;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
@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.log.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.log.severe("[SteamVRPipeInputBridge] Pipe error: " + Kernel32.INSTANCE.GetLastError());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
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.log.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.log.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.log.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.log.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.log.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.log.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.log.severe("[SteamVRPipeInputBridge] Unrecognized status id. Supplied: " + commandBuilder);
|
||||
return;
|
||||
}
|
||||
internalTracker = trackersInternal.get(id);
|
||||
if (internalTracker != null) {
|
||||
internalTracker.setStatus(st);
|
||||
newData.set(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void executeInputCommand() throws IOException {
|
||||
String[] command = commandBuilder.toString().split(" ");
|
||||
switch (command[0]) {
|
||||
case "ADD": // Add new tracker
|
||||
if (command.length < 4) {
|
||||
LogManager.log.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.log.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.log.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.log.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.log.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 (int i = 0; i < trackers.size(); ++i) {
|
||||
VRTracker t = trackers.get(i);
|
||||
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 (int i = 0; i < trackers.size(); ++i) {
|
||||
VRTracker tracker = trackers.get(i);
|
||||
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 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 (int i = 0; i < trackers.size(); ++i) {
|
||||
VRTracker t = trackers.get(i);
|
||||
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 (int i = 0; i < trackers.size(); ++i) {
|
||||
VRTracker tracker = trackers.get(i);
|
||||
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
|
||||
}
|
||||
@Override
|
||||
public void dataWrite() {
|
||||
// Not used, only input
|
||||
}
|
||||
|
||||
private void resetPipe() {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
pipe.state = PipeState.CREATED;
|
||||
//Main.vrServer.queueTask(this::disconnected);
|
||||
}
|
||||
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.log.info("[SteamVRPipeInputBridge] Pipe " + pipe.name + " is open");
|
||||
return true;
|
||||
}
|
||||
private boolean tryOpeningPipe(WindowsPipe pipe) {
|
||||
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;
|
||||
}
|
||||
|
||||
LogManager.log.info("[SteamVRPipeInputBridge] Error connecting to pipe " + pipe.name + ": " + Kernel32.INSTANCE.GetLastError());
|
||||
return false;
|
||||
}
|
||||
LogManager.log.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.log.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.log.info("[SteamVRPipeInputBridge] Pipes are open");
|
||||
} catch (IOException e) {
|
||||
WindowsPipe.safeDisconnect(pipe);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
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.log.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.log.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 addSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
@Override
|
||||
public void removeSharedTracker(ShareableTracker tracker) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startBridge() {
|
||||
start();
|
||||
}
|
||||
@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),
|
||||
;
|
||||
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;
|
||||
private static final SteamVRInputRoles[] values = values();
|
||||
public final TrackerPosition bodyPosition;
|
||||
|
||||
SteamVRInputRoles(TrackerPosition slimeVrPosition) {
|
||||
this.bodyPosition = slimeVrPosition;
|
||||
}
|
||||
}
|
||||
SteamVRInputRoles(TrackerPosition slimeVrPosition) {
|
||||
this.bodyPosition = slimeVrPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,56 +11,56 @@ import java.io.IOException;
|
||||
|
||||
public class BVHRecorder {
|
||||
|
||||
private static final File bvhSaveDir = new File("BVH Recordings");
|
||||
private final ServerPoseStreamer poseStreamer;
|
||||
private PoseDataStream poseDataStream = null;
|
||||
private static final File bvhSaveDir = new File("BVH Recordings");
|
||||
private final ServerPoseStreamer poseStreamer;
|
||||
private PoseDataStream poseDataStream = null;
|
||||
|
||||
public BVHRecorder(VRServer server) {
|
||||
this.poseStreamer = new ServerPoseStreamer(server);
|
||||
}
|
||||
public BVHRecorder(VRServer server) {
|
||||
this.poseStreamer = new ServerPoseStreamer(server);
|
||||
}
|
||||
|
||||
public void startRecording() {
|
||||
File bvhFile = getBvhFile();
|
||||
if (bvhFile != null) {
|
||||
try {
|
||||
poseDataStream = new BVHFileStream(bvhFile);
|
||||
poseStreamer.setOutput(poseDataStream, 1000L / 100L);
|
||||
} catch (IOException e1) {
|
||||
LogManager.log.severe("[BVH] Failed to create the recording file \"" + bvhFile.getPath() + "\".");
|
||||
}
|
||||
} else {
|
||||
LogManager.log.severe("[BVH] Unable to get file to save to");
|
||||
}
|
||||
}
|
||||
public void startRecording() {
|
||||
File bvhFile = getBvhFile();
|
||||
if (bvhFile != null) {
|
||||
try {
|
||||
poseDataStream = new BVHFileStream(bvhFile);
|
||||
poseStreamer.setOutput(poseDataStream, 1000L / 100L);
|
||||
} catch (IOException e1) {
|
||||
LogManager.log.severe("[BVH] Failed to create the recording file \"" + bvhFile.getPath() + "\".");
|
||||
}
|
||||
} else {
|
||||
LogManager.log.severe("[BVH] Unable to get file to save to");
|
||||
}
|
||||
}
|
||||
|
||||
public void endRecording() {
|
||||
public void endRecording() {
|
||||
|
||||
try {
|
||||
poseStreamer.closeOutput(poseDataStream);
|
||||
} catch (Exception e1) {
|
||||
LogManager.log.severe("[BVH] Exception while closing poseDataStream", e1);
|
||||
} finally {
|
||||
poseDataStream = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
poseStreamer.closeOutput(poseDataStream);
|
||||
} catch (Exception e1) {
|
||||
LogManager.log.severe("[BVH] Exception while closing poseDataStream", e1);
|
||||
} finally {
|
||||
poseDataStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
private File getBvhFile() {
|
||||
if (bvhSaveDir.isDirectory() || bvhSaveDir.mkdirs()) {
|
||||
File saveRecording;
|
||||
int recordingIndex = 1;
|
||||
do {
|
||||
saveRecording = new File(bvhSaveDir, "BVH-Recording" + recordingIndex++ + ".bvh");
|
||||
} while (saveRecording.exists());
|
||||
private File getBvhFile() {
|
||||
if (bvhSaveDir.isDirectory() || bvhSaveDir.mkdirs()) {
|
||||
File saveRecording;
|
||||
int recordingIndex = 1;
|
||||
do {
|
||||
saveRecording = new File(bvhSaveDir, "BVH-Recording" + recordingIndex++ + ".bvh");
|
||||
} while (saveRecording.exists());
|
||||
|
||||
return saveRecording;
|
||||
} else {
|
||||
LogManager.log.severe("[BVH] Failed to create the recording directory \"" + bvhSaveDir.getPath() + "\".");
|
||||
}
|
||||
return saveRecording;
|
||||
} else {
|
||||
LogManager.log.severe("[BVH] Failed to create the recording directory \"" + bvhSaveDir.getPath() + "\".");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isRecording() {
|
||||
return poseDataStream != null;
|
||||
}
|
||||
public boolean isRecording() {
|
||||
return poseDataStream != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,122 +10,122 @@ import java.io.*;
|
||||
|
||||
public final class PoseFrameIO {
|
||||
|
||||
private PoseFrameIO() {
|
||||
// Do not allow instantiating
|
||||
}
|
||||
private PoseFrameIO() {
|
||||
// Do not allow instantiating
|
||||
}
|
||||
|
||||
public static boolean writeFrames(DataOutputStream outputStream, PoseFrames frames) {
|
||||
try {
|
||||
if (frames != null) {
|
||||
outputStream.writeInt(frames.getTrackerCount());
|
||||
for (PoseFrameTracker tracker : frames.getTrackers()) {
|
||||
outputStream.writeUTF(tracker.name);
|
||||
outputStream.writeInt(tracker.getFrameCount());
|
||||
for (int i = 0; i < tracker.getFrameCount(); i++) {
|
||||
TrackerFrame trackerFrame = tracker.safeGetFrame(i);
|
||||
if (trackerFrame == null) {
|
||||
outputStream.writeInt(0);
|
||||
continue;
|
||||
}
|
||||
public static boolean writeFrames(DataOutputStream outputStream, PoseFrames frames) {
|
||||
try {
|
||||
if (frames != null) {
|
||||
outputStream.writeInt(frames.getTrackerCount());
|
||||
for (PoseFrameTracker tracker : frames.getTrackers()) {
|
||||
outputStream.writeUTF(tracker.name);
|
||||
outputStream.writeInt(tracker.getFrameCount());
|
||||
for (int i = 0; i < tracker.getFrameCount(); i++) {
|
||||
TrackerFrame trackerFrame = tracker.safeGetFrame(i);
|
||||
if (trackerFrame == null) {
|
||||
outputStream.writeInt(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
outputStream.writeInt(trackerFrame.getDataFlags());
|
||||
outputStream.writeInt(trackerFrame.getDataFlags());
|
||||
|
||||
if (trackerFrame.hasData(TrackerFrameData.DESIGNATION)) {
|
||||
outputStream.writeUTF(trackerFrame.designation.designation);
|
||||
}
|
||||
if (trackerFrame.hasData(TrackerFrameData.DESIGNATION)) {
|
||||
outputStream.writeUTF(trackerFrame.designation.designation);
|
||||
}
|
||||
|
||||
if (trackerFrame.hasData(TrackerFrameData.ROTATION)) {
|
||||
outputStream.writeFloat(trackerFrame.rotation.getX());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getY());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getZ());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getW());
|
||||
}
|
||||
if (trackerFrame.hasData(TrackerFrameData.ROTATION)) {
|
||||
outputStream.writeFloat(trackerFrame.rotation.getX());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getY());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getZ());
|
||||
outputStream.writeFloat(trackerFrame.rotation.getW());
|
||||
}
|
||||
|
||||
if (trackerFrame.hasData(TrackerFrameData.POSITION)) {
|
||||
outputStream.writeFloat(trackerFrame.position.getX());
|
||||
outputStream.writeFloat(trackerFrame.position.getY());
|
||||
outputStream.writeFloat(trackerFrame.position.getZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outputStream.writeInt(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error writing frame to stream", e);
|
||||
return false;
|
||||
}
|
||||
if (trackerFrame.hasData(TrackerFrameData.POSITION)) {
|
||||
outputStream.writeFloat(trackerFrame.position.getX());
|
||||
outputStream.writeFloat(trackerFrame.position.getY());
|
||||
outputStream.writeFloat(trackerFrame.position.getZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outputStream.writeInt(0);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error writing frame to stream", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean writeToFile(File file, PoseFrames frames) {
|
||||
try (DataOutputStream outputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
|
||||
writeFrames(outputStream, frames);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error writing frames to file", e);
|
||||
return false;
|
||||
}
|
||||
public static boolean writeToFile(File file, PoseFrames frames) {
|
||||
try (DataOutputStream outputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
|
||||
writeFrames(outputStream, frames);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error writing frames to file", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static PoseFrames readFrames(DataInputStream inputStream) {
|
||||
try {
|
||||
public static PoseFrames readFrames(DataInputStream inputStream) {
|
||||
try {
|
||||
|
||||
int trackerCount = inputStream.readInt();
|
||||
FastList<PoseFrameTracker> trackers = new FastList<PoseFrameTracker>(trackerCount);
|
||||
for (int i = 0; i < trackerCount; i++) {
|
||||
int trackerCount = inputStream.readInt();
|
||||
FastList<PoseFrameTracker> trackers = new FastList<PoseFrameTracker>(trackerCount);
|
||||
for (int i = 0; i < trackerCount; i++) {
|
||||
|
||||
String name = inputStream.readUTF();
|
||||
int trackerFrameCount = inputStream.readInt();
|
||||
FastList<TrackerFrame> trackerFrames = new FastList<TrackerFrame>(trackerFrameCount);
|
||||
for (int j = 0; j < trackerFrameCount; j++) {
|
||||
int dataFlags = inputStream.readInt();
|
||||
String name = inputStream.readUTF();
|
||||
int trackerFrameCount = inputStream.readInt();
|
||||
FastList<TrackerFrame> trackerFrames = new FastList<TrackerFrame>(trackerFrameCount);
|
||||
for (int j = 0; j < trackerFrameCount; j++) {
|
||||
int dataFlags = inputStream.readInt();
|
||||
|
||||
TrackerPosition designation = null;
|
||||
if (TrackerFrameData.DESIGNATION.check(dataFlags)) {
|
||||
designation = TrackerPosition.getByDesignation(inputStream.readUTF());
|
||||
}
|
||||
TrackerPosition designation = null;
|
||||
if (TrackerFrameData.DESIGNATION.check(dataFlags)) {
|
||||
designation = TrackerPosition.getByDesignation(inputStream.readUTF());
|
||||
}
|
||||
|
||||
Quaternion rotation = null;
|
||||
if (TrackerFrameData.ROTATION.check(dataFlags)) {
|
||||
float quatX = inputStream.readFloat();
|
||||
float quatY = inputStream.readFloat();
|
||||
float quatZ = inputStream.readFloat();
|
||||
float quatW = inputStream.readFloat();
|
||||
rotation = new Quaternion(quatX, quatY, quatZ, quatW);
|
||||
}
|
||||
Quaternion rotation = null;
|
||||
if (TrackerFrameData.ROTATION.check(dataFlags)) {
|
||||
float quatX = inputStream.readFloat();
|
||||
float quatY = inputStream.readFloat();
|
||||
float quatZ = inputStream.readFloat();
|
||||
float quatW = inputStream.readFloat();
|
||||
rotation = new Quaternion(quatX, quatY, quatZ, quatW);
|
||||
}
|
||||
|
||||
Vector3f position = null;
|
||||
if (TrackerFrameData.POSITION.check(dataFlags)) {
|
||||
float posX = inputStream.readFloat();
|
||||
float posY = inputStream.readFloat();
|
||||
float posZ = inputStream.readFloat();
|
||||
position = new Vector3f(posX, posY, posZ);
|
||||
}
|
||||
Vector3f position = null;
|
||||
if (TrackerFrameData.POSITION.check(dataFlags)) {
|
||||
float posX = inputStream.readFloat();
|
||||
float posY = inputStream.readFloat();
|
||||
float posZ = inputStream.readFloat();
|
||||
position = new Vector3f(posX, posY, posZ);
|
||||
}
|
||||
|
||||
trackerFrames.add(new TrackerFrame(designation, rotation, position));
|
||||
}
|
||||
trackerFrames.add(new TrackerFrame(designation, rotation, position));
|
||||
}
|
||||
|
||||
trackers.add(new PoseFrameTracker(name, trackerFrames));
|
||||
}
|
||||
trackers.add(new PoseFrameTracker(name, trackerFrames));
|
||||
}
|
||||
|
||||
return new PoseFrames(trackers);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error reading frame from stream", e);
|
||||
}
|
||||
return new PoseFrames(trackers);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error reading frame from stream", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PoseFrames readFromFile(File file) {
|
||||
try {
|
||||
return readFrames(new DataInputStream(new BufferedInputStream(new FileInputStream(file))));
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error reading frame from file", e);
|
||||
}
|
||||
public static PoseFrames readFromFile(File file) {
|
||||
try {
|
||||
return readFrames(new DataInputStream(new BufferedInputStream(new FileInputStream(file))));
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("Error reading frame from file", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,62 +11,62 @@ import java.util.Map;
|
||||
|
||||
public class PoseFrameSkeleton extends SimpleSkeleton {
|
||||
|
||||
private int frameCursor = 0;
|
||||
private int frameCursor = 0;
|
||||
|
||||
protected PoseFrameSkeleton(List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(computedTrackers);
|
||||
}
|
||||
protected PoseFrameSkeleton(List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(computedTrackers);
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton(VRServer server, List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(server, computedTrackers);
|
||||
}
|
||||
public PoseFrameSkeleton(VRServer server, List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(server, computedTrackers);
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(trackers, computedTrackers);
|
||||
}
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers) {
|
||||
super(trackers, computedTrackers);
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers, Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigValue, Float> altConfigs) {
|
||||
super(trackers, computedTrackers, configs, altConfigs);
|
||||
}
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers, Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigValue, Float> altConfigs) {
|
||||
super(trackers, computedTrackers, configs, altConfigs);
|
||||
}
|
||||
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers, Map<SkeletonConfigValue, Float> configs) {
|
||||
super(trackers, computedTrackers, configs);
|
||||
}
|
||||
public PoseFrameSkeleton(List<? extends Tracker> trackers, List<? extends ComputedHumanPoseTracker> computedTrackers, Map<SkeletonConfigValue, Float> configs) {
|
||||
super(trackers, computedTrackers, configs);
|
||||
}
|
||||
|
||||
private int limitCursor() {
|
||||
if (frameCursor < 0) {
|
||||
frameCursor = 0;
|
||||
}
|
||||
private int limitCursor() {
|
||||
if (frameCursor < 0) {
|
||||
frameCursor = 0;
|
||||
}
|
||||
|
||||
return frameCursor;
|
||||
}
|
||||
return frameCursor;
|
||||
}
|
||||
|
||||
public int setCursor(int index) {
|
||||
frameCursor = index;
|
||||
return limitCursor();
|
||||
}
|
||||
public int setCursor(int index) {
|
||||
frameCursor = index;
|
||||
return limitCursor();
|
||||
}
|
||||
|
||||
public int incrementCursor(int increment) {
|
||||
frameCursor += increment;
|
||||
return limitCursor();
|
||||
}
|
||||
public int incrementCursor(int increment) {
|
||||
frameCursor += increment;
|
||||
return limitCursor();
|
||||
}
|
||||
|
||||
public int incrementCursor() {
|
||||
return incrementCursor(1);
|
||||
}
|
||||
public int incrementCursor() {
|
||||
return incrementCursor(1);
|
||||
}
|
||||
|
||||
public int getCursor() {
|
||||
return frameCursor;
|
||||
}
|
||||
public int getCursor() {
|
||||
return frameCursor;
|
||||
}
|
||||
|
||||
// Get tracker for specific frame
|
||||
@Override
|
||||
protected Tracker trackerPreUpdate(Tracker tracker) {
|
||||
if (tracker instanceof PoseFrameTracker) {
|
||||
// Return frame if available, otherwise return the original tracker
|
||||
TrackerFrame frame = ((PoseFrameTracker) tracker).safeGetFrame(frameCursor);
|
||||
return frame == null ? tracker : frame;
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
// Get tracker for specific frame
|
||||
@Override
|
||||
protected Tracker trackerPreUpdate(Tracker tracker) {
|
||||
if (tracker instanceof PoseFrameTracker) {
|
||||
// Return frame if available, otherwise return the original tracker
|
||||
TrackerFrame frame = ((PoseFrameTracker) tracker).safeGetFrame(frameCursor);
|
||||
return frame == null ? tracker : frame;
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,245 +13,245 @@ import java.util.Iterator;
|
||||
|
||||
public class PoseFrameTracker implements Tracker, Iterable<TrackerFrame> {
|
||||
|
||||
public final String name;
|
||||
public final String name;
|
||||
|
||||
private final FastList<TrackerFrame> frames;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
private int frameCursor = 0;
|
||||
private final FastList<TrackerFrame> frames;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
private int frameCursor = 0;
|
||||
|
||||
public PoseFrameTracker(String name, FastList<TrackerFrame> frames) {
|
||||
if (frames == null) {
|
||||
throw new NullPointerException("frames must not be null");
|
||||
}
|
||||
public PoseFrameTracker(String name, FastList<TrackerFrame> frames) {
|
||||
if (frames == null) {
|
||||
throw new NullPointerException("frames must not be null");
|
||||
}
|
||||
|
||||
this.name = name != null ? name : "";
|
||||
this.frames = frames;
|
||||
}
|
||||
this.name = name != null ? name : "";
|
||||
this.frames = frames;
|
||||
}
|
||||
|
||||
public PoseFrameTracker(String name, int initialCapacity) {
|
||||
this(name, new FastList<TrackerFrame>(initialCapacity));
|
||||
}
|
||||
public PoseFrameTracker(String name, int initialCapacity) {
|
||||
this(name, new FastList<TrackerFrame>(initialCapacity));
|
||||
}
|
||||
|
||||
public PoseFrameTracker(Tracker parent, int initialCapacity) {
|
||||
this(parent.getName(), initialCapacity);
|
||||
}
|
||||
public PoseFrameTracker(Tracker parent, int initialCapacity) {
|
||||
this(parent.getName(), initialCapacity);
|
||||
}
|
||||
|
||||
public PoseFrameTracker(String name) {
|
||||
this(name, 5);
|
||||
}
|
||||
public PoseFrameTracker(String name) {
|
||||
this(name, 5);
|
||||
}
|
||||
|
||||
public PoseFrameTracker(Tracker parent) {
|
||||
this(parent.getName());
|
||||
}
|
||||
public PoseFrameTracker(Tracker parent) {
|
||||
this(parent.getName());
|
||||
}
|
||||
|
||||
private int limitCursor() {
|
||||
if (frameCursor < 0 || frames.isEmpty()) {
|
||||
frameCursor = 0;
|
||||
} else if (frameCursor >= frames.size()) {
|
||||
frameCursor = frames.size() - 1;
|
||||
}
|
||||
private int limitCursor() {
|
||||
if (frameCursor < 0 || frames.isEmpty()) {
|
||||
frameCursor = 0;
|
||||
} else if (frameCursor >= frames.size()) {
|
||||
frameCursor = frames.size() - 1;
|
||||
}
|
||||
|
||||
return frameCursor;
|
||||
}
|
||||
return frameCursor;
|
||||
}
|
||||
|
||||
public int setCursor(int index) {
|
||||
frameCursor = index;
|
||||
return limitCursor();
|
||||
}
|
||||
public int setCursor(int index) {
|
||||
frameCursor = index;
|
||||
return limitCursor();
|
||||
}
|
||||
|
||||
public int incrementCursor(int increment) {
|
||||
frameCursor += increment;
|
||||
return limitCursor();
|
||||
}
|
||||
public int incrementCursor(int increment) {
|
||||
frameCursor += increment;
|
||||
return limitCursor();
|
||||
}
|
||||
|
||||
public int incrementCursor() {
|
||||
return incrementCursor(1);
|
||||
}
|
||||
public int incrementCursor() {
|
||||
return incrementCursor(1);
|
||||
}
|
||||
|
||||
public int getCursor() {
|
||||
return frameCursor;
|
||||
}
|
||||
public int getCursor() {
|
||||
return frameCursor;
|
||||
}
|
||||
|
||||
public int getFrameCount() {
|
||||
return frames.size();
|
||||
}
|
||||
public int getFrameCount() {
|
||||
return frames.size();
|
||||
}
|
||||
|
||||
public TrackerFrame addFrame(int index, TrackerFrame trackerFrame) {
|
||||
frames.add(index, trackerFrame);
|
||||
return trackerFrame;
|
||||
}
|
||||
public TrackerFrame addFrame(int index, TrackerFrame trackerFrame) {
|
||||
frames.add(index, trackerFrame);
|
||||
return trackerFrame;
|
||||
}
|
||||
|
||||
public TrackerFrame addFrame(int index, Tracker tracker) {
|
||||
return addFrame(index, TrackerFrame.fromTracker(tracker));
|
||||
}
|
||||
public TrackerFrame addFrame(int index, Tracker tracker) {
|
||||
return addFrame(index, TrackerFrame.fromTracker(tracker));
|
||||
}
|
||||
|
||||
public TrackerFrame addFrame(TrackerFrame trackerFrame) {
|
||||
frames.add(trackerFrame);
|
||||
return trackerFrame;
|
||||
}
|
||||
public TrackerFrame addFrame(TrackerFrame trackerFrame) {
|
||||
frames.add(trackerFrame);
|
||||
return trackerFrame;
|
||||
}
|
||||
|
||||
public TrackerFrame addFrame(Tracker tracker) {
|
||||
return addFrame(TrackerFrame.fromTracker(tracker));
|
||||
}
|
||||
public TrackerFrame addFrame(Tracker tracker) {
|
||||
return addFrame(TrackerFrame.fromTracker(tracker));
|
||||
}
|
||||
|
||||
public TrackerFrame removeFrame(int index) {
|
||||
TrackerFrame trackerFrame = frames.remove(index);
|
||||
limitCursor();
|
||||
return trackerFrame;
|
||||
}
|
||||
public TrackerFrame removeFrame(int index) {
|
||||
TrackerFrame trackerFrame = frames.remove(index);
|
||||
limitCursor();
|
||||
return trackerFrame;
|
||||
}
|
||||
|
||||
public TrackerFrame removeFrame(TrackerFrame trackerFrame) {
|
||||
frames.remove(trackerFrame);
|
||||
limitCursor();
|
||||
return trackerFrame;
|
||||
}
|
||||
public TrackerFrame removeFrame(TrackerFrame trackerFrame) {
|
||||
frames.remove(trackerFrame);
|
||||
limitCursor();
|
||||
return trackerFrame;
|
||||
}
|
||||
|
||||
public void clearFrames() {
|
||||
frames.clear();
|
||||
limitCursor();
|
||||
}
|
||||
public void clearFrames() {
|
||||
frames.clear();
|
||||
limitCursor();
|
||||
}
|
||||
|
||||
public void fakeClearFrames() {
|
||||
frames.fakeClear();
|
||||
limitCursor();
|
||||
}
|
||||
public void fakeClearFrames() {
|
||||
frames.fakeClear();
|
||||
limitCursor();
|
||||
}
|
||||
|
||||
public TrackerFrame getFrame(int index) {
|
||||
return frames.get(index);
|
||||
}
|
||||
public TrackerFrame getFrame(int index) {
|
||||
return frames.get(index);
|
||||
}
|
||||
|
||||
public TrackerFrame getFrame() {
|
||||
return getFrame(frameCursor);
|
||||
}
|
||||
public TrackerFrame getFrame() {
|
||||
return getFrame(frameCursor);
|
||||
}
|
||||
|
||||
public TrackerFrame safeGetFrame(int index) {
|
||||
try {
|
||||
return getFrame(index);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public TrackerFrame safeGetFrame(int index) {
|
||||
try {
|
||||
return getFrame(index);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public TrackerFrame safeGetFrame() {
|
||||
return safeGetFrame(frameCursor);
|
||||
}
|
||||
public TrackerFrame safeGetFrame() {
|
||||
return safeGetFrame(frameCursor);
|
||||
}
|
||||
|
||||
//#region Tracker Interface Implementation
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
if (frame != null && frame.hasData(TrackerFrameData.ROTATION)) {
|
||||
store.set(frame.rotation);
|
||||
return true;
|
||||
}
|
||||
//#region Tracker Interface Implementation
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
if (frame != null && frame.hasData(TrackerFrameData.ROTATION)) {
|
||||
store.set(frame.rotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
store.set(Quaternion.IDENTITY);
|
||||
return false;
|
||||
}
|
||||
store.set(Quaternion.IDENTITY);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
if (frame != null && frame.hasData(TrackerFrameData.POSITION)) {
|
||||
store.set(frame.position);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
if (frame != null && frame.hasData(TrackerFrameData.POSITION)) {
|
||||
store.set(frame.position);
|
||||
return true;
|
||||
}
|
||||
|
||||
store.set(Vector3f.ZERO);
|
||||
return false;
|
||||
}
|
||||
store.set(Vector3f.ZERO);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return TrackerStatus.OK;
|
||||
}
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return TrackerStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement configuration");
|
||||
}
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement configuration");
|
||||
}
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1f;
|
||||
}
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement calibration");
|
||||
}
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement calibration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement calibration");
|
||||
}
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement calibration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement this method");
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not implement this method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame == null ? null : frame.designation;
|
||||
}
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame == null ? null : frame.designation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not allow setting the body position");
|
||||
}
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("PoseFrameTracker does not allow setting the body position");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame != null && frame.hasData(TrackerFrameData.ROTATION);
|
||||
}
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame != null && frame.hasData(TrackerFrameData.ROTATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame != null && frame.hasData(TrackerFrameData.POSITION);
|
||||
}
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
TrackerFrame frame = safeGetFrame();
|
||||
return frame != null && frame.hasData(TrackerFrameData.POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
//#endregion
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
@Override
|
||||
public Iterator<TrackerFrame> iterator() {
|
||||
return frames.iterator();
|
||||
}
|
||||
@Override
|
||||
public Iterator<TrackerFrame> iterator() {
|
||||
return frames.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,262 +10,262 @@ import java.util.NoSuchElementException;
|
||||
|
||||
public final class PoseFrames implements Iterable<TrackerFrame[]> {
|
||||
|
||||
private final FastList<PoseFrameTracker> trackers;
|
||||
private final FastList<PoseFrameTracker> trackers;
|
||||
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the provided list of {@link PoseFrameTracker}s as the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @see {@link FastList}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrames(FastList<PoseFrameTracker> trackers) {
|
||||
this.trackers = trackers;
|
||||
}
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the provided list of {@link PoseFrameTracker}s as the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @see {@link FastList}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrames(FastList<PoseFrameTracker> trackers) {
|
||||
this.trackers = trackers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the specified initial tracker capacity
|
||||
*
|
||||
* @see {@link #PoseFrames(FastList)}
|
||||
*/
|
||||
public PoseFrames(int initialCapacity) {
|
||||
this.trackers = new FastList<PoseFrameTracker>(initialCapacity);
|
||||
}
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the specified initial tracker capacity
|
||||
*
|
||||
* @see {@link #PoseFrames(FastList)}
|
||||
*/
|
||||
public PoseFrames(int initialCapacity) {
|
||||
this.trackers = new FastList<PoseFrameTracker>(initialCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the default initial tracker capacity of {@code 5}
|
||||
*
|
||||
* @see {@link #PoseFrames(int)}
|
||||
*/
|
||||
public PoseFrames() {
|
||||
this(5);
|
||||
}
|
||||
/**
|
||||
* Creates a {@link PoseFrames} object with the default initial tracker capacity of {@code 5}
|
||||
*
|
||||
* @see {@link #PoseFrames(int)}
|
||||
*/
|
||||
public PoseFrames() {
|
||||
this(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the provided {@link PoseFrameTracker} into the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return The {@link PoseFrameTracker} provided
|
||||
* @see {@link List#add(Object)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrameTracker addTracker(PoseFrameTracker tracker) {
|
||||
trackers.add(tracker);
|
||||
return tracker;
|
||||
}
|
||||
/**
|
||||
* Adds the provided {@link PoseFrameTracker} into the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return The {@link PoseFrameTracker} provided
|
||||
* @see {@link List#add(Object)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrameTracker addTracker(PoseFrameTracker tracker) {
|
||||
trackers.add(tracker);
|
||||
return tracker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@link PoseFrameTracker} at the specified index from the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return The {@link PoseFrameTracker} previously at the specified index
|
||||
* @see {@link List#remove(int)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrameTracker removeTracker(int index) {
|
||||
return trackers.remove(index);
|
||||
}
|
||||
/**
|
||||
* Removes the {@link PoseFrameTracker} at the specified index from the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return The {@link PoseFrameTracker} previously at the specified index
|
||||
* @see {@link List#remove(int)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public PoseFrameTracker removeTracker(int index) {
|
||||
return trackers.remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified {@link PoseFrameTracker} from the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return {@code true} if the internal {@link PoseFrameTracker} list contained the specified {@link PoseFrameTracker}
|
||||
* @see {@link List#remove(Object)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public boolean removeTracker(PoseFrameTracker tracker) {
|
||||
return trackers.remove(tracker);
|
||||
}
|
||||
/**
|
||||
* Removes the specified {@link PoseFrameTracker} from the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @return {@code true} if the internal {@link PoseFrameTracker} list contained the specified {@link PoseFrameTracker}
|
||||
* @see {@link List#remove(Object)}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public boolean removeTracker(PoseFrameTracker tracker) {
|
||||
return trackers.remove(tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @see {@link List#clear()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public void clearTrackers() {
|
||||
trackers.clear();
|
||||
}
|
||||
/**
|
||||
* Clears the internal {@link PoseFrameTracker} list
|
||||
*
|
||||
* @see {@link List#clear()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public void clearTrackers() {
|
||||
trackers.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake clears the internal {@link PoseFrameTracker} list by setting the size to zero
|
||||
*
|
||||
* @see {@link FastList#fakeClear()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public void fakeClearTrackers() {
|
||||
trackers.fakeClear();
|
||||
}
|
||||
/**
|
||||
* Fake clears the internal {@link PoseFrameTracker} list by setting the size to zero
|
||||
*
|
||||
* @see {@link FastList#fakeClear()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public void fakeClearTrackers() {
|
||||
trackers.fakeClear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The number of contained {@link PoseFrameTracker} objects
|
||||
* @see {@link List#size()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getTrackerCount() {
|
||||
return trackers.size();
|
||||
}
|
||||
/**
|
||||
* @return The number of contained {@link PoseFrameTracker} objects
|
||||
* @see {@link List#size()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getTrackerCount() {
|
||||
return trackers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A list of the contained {@link PoseFrameTracker} objects
|
||||
* @see {@link List}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public List<PoseFrameTracker> getTrackers() {
|
||||
return trackers;
|
||||
}
|
||||
/**
|
||||
* @return A list of the contained {@link PoseFrameTracker} objects
|
||||
* @see {@link List}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public List<PoseFrameTracker> getTrackers() {
|
||||
return trackers;
|
||||
}
|
||||
|
||||
//#region Data Utilities
|
||||
//#region Data Utilities
|
||||
|
||||
/**
|
||||
* A utility function to get the maximum Y value of the tracker associated with the {@link TrackerPosition#HMD} tracker position
|
||||
*
|
||||
* @return The maximum Y value of the tracker associated with the {@link TrackerPosition#HMD} tracker position
|
||||
* @see {@link #getMaxHeight(TrackerPosition)}, {@link TrackerPosition#HMD}
|
||||
*/
|
||||
public float getMaxHmdHeight() {
|
||||
return getMaxHeight(TrackerPosition.HMD);
|
||||
}
|
||||
/**
|
||||
* A utility function to get the maximum Y value of the tracker associated with the {@link TrackerPosition#HMD} tracker position
|
||||
*
|
||||
* @return The maximum Y value of the tracker associated with the {@link TrackerPosition#HMD} tracker position
|
||||
* @see {@link #getMaxHeight(TrackerPosition)}, {@link TrackerPosition#HMD}
|
||||
*/
|
||||
public float getMaxHmdHeight() {
|
||||
return getMaxHeight(TrackerPosition.HMD);
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility function to get the maximum Y value of the tracker associated with the specified {@link TrackerPosition}
|
||||
*
|
||||
* @return The maximum Y value of the tracker associated with the specified {@link TrackerPosition}
|
||||
* @see {@link TrackerPosition}
|
||||
*/
|
||||
public float getMaxHeight(TrackerPosition trackerPosition) {
|
||||
float maxHeight = 0f;
|
||||
/**
|
||||
* A utility function to get the maximum Y value of the tracker associated with the specified {@link TrackerPosition}
|
||||
*
|
||||
* @return The maximum Y value of the tracker associated with the specified {@link TrackerPosition}
|
||||
* @see {@link TrackerPosition}
|
||||
*/
|
||||
public float getMaxHeight(TrackerPosition trackerPosition) {
|
||||
float maxHeight = 0f;
|
||||
|
||||
PoseFrameTracker hmd = TrackerUtils.findTrackerForBodyPosition(trackers, trackerPosition);
|
||||
PoseFrameTracker hmd = TrackerUtils.findTrackerForBodyPosition(trackers, trackerPosition);
|
||||
|
||||
if (hmd == null) {
|
||||
return maxHeight;
|
||||
}
|
||||
if (hmd == null) {
|
||||
return maxHeight;
|
||||
}
|
||||
|
||||
for (TrackerFrame frame : hmd) {
|
||||
if (frame.hasData(TrackerFrameData.POSITION) && frame.position.y > maxHeight) {
|
||||
maxHeight = frame.position.y;
|
||||
}
|
||||
}
|
||||
for (TrackerFrame frame : hmd) {
|
||||
if (frame.hasData(TrackerFrameData.POSITION) && frame.position.y > maxHeight) {
|
||||
maxHeight = frame.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
return maxHeight;
|
||||
}
|
||||
//#endregion
|
||||
return maxHeight;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* @return The maximum number of {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list
|
||||
* @see {@link PoseFrameTracker#getFrameCount()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getMaxFrameCount() {
|
||||
int maxFrames = 0;
|
||||
/**
|
||||
* @return The maximum number of {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list
|
||||
* @see {@link PoseFrameTracker#getFrameCount()}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getMaxFrameCount() {
|
||||
int maxFrames = 0;
|
||||
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
if (tracker != null && tracker.getFrameCount() > maxFrames) {
|
||||
maxFrames = tracker.getFrameCount();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
if (tracker != null && tracker.getFrameCount() > maxFrames) {
|
||||
maxFrames = tracker.getFrameCount();
|
||||
}
|
||||
}
|
||||
|
||||
return maxFrames;
|
||||
}
|
||||
return maxFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the provided array buffer, get the {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
*
|
||||
* @return The number of frames written to the buffer
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getFrames(int frameIndex, TrackerFrame[] buffer) {
|
||||
int frameCount = 0;
|
||||
/**
|
||||
* Using the provided array buffer, get the {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
*
|
||||
* @return The number of frames written to the buffer
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getFrames(int frameIndex, TrackerFrame[] buffer) {
|
||||
int frameCount = 0;
|
||||
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackerFrame frame = tracker.safeGetFrame(frameIndex);
|
||||
TrackerFrame frame = tracker.safeGetFrame(frameIndex);
|
||||
|
||||
if (frame == null) {
|
||||
continue;
|
||||
}
|
||||
if (frame == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[frameCount++] = frame;
|
||||
}
|
||||
buffer[frameCount++] = frame;
|
||||
}
|
||||
|
||||
return frameCount;
|
||||
}
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the provided {@link List} buffer, get the {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
*
|
||||
* @return The number of frames written to the buffer
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link List#set(int, Object)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getFrames(int frameIndex, List<TrackerFrame> buffer) {
|
||||
int frameCount = 0;
|
||||
/**
|
||||
* Using the provided {@link List} buffer, get the {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
*
|
||||
* @return The number of frames written to the buffer
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link List#set(int, Object)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public int getFrames(int frameIndex, List<TrackerFrame> buffer) {
|
||||
int frameCount = 0;
|
||||
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
if (tracker == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TrackerFrame frame = tracker.safeGetFrame(frameIndex);
|
||||
TrackerFrame frame = tracker.safeGetFrame(frameIndex);
|
||||
|
||||
if (frame == null) {
|
||||
continue;
|
||||
}
|
||||
if (frame == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer.set(frameCount++, frame);
|
||||
}
|
||||
buffer.set(frameCount++, frame);
|
||||
}
|
||||
|
||||
return frameCount;
|
||||
}
|
||||
return frameCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public TrackerFrame[] getFrames(int frameIndex) {
|
||||
TrackerFrame[] trackerFrames = new TrackerFrame[trackers.size()];
|
||||
getFrames(frameIndex, trackerFrames);
|
||||
return trackerFrames;
|
||||
}
|
||||
/**
|
||||
* @return The {@link TrackerFrame}s contained within each {@link PoseFrameTracker} in the internal {@link PoseFrameTracker} list at the specified index
|
||||
* @see {@link PoseFrameTracker#safeGetFrame(int)}, {@link TrackerFrame}, {@link PoseFrameTracker}
|
||||
*/
|
||||
public TrackerFrame[] getFrames(int frameIndex) {
|
||||
TrackerFrame[] trackerFrames = new TrackerFrame[trackers.size()];
|
||||
getFrames(frameIndex, trackerFrames);
|
||||
return trackerFrames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<TrackerFrame[]> iterator() {
|
||||
return new PoseFrameIterator(this);
|
||||
}
|
||||
@Override
|
||||
public Iterator<TrackerFrame[]> iterator() {
|
||||
return new PoseFrameIterator(this);
|
||||
}
|
||||
|
||||
public class PoseFrameIterator implements Iterator<TrackerFrame[]> {
|
||||
public class PoseFrameIterator implements Iterator<TrackerFrame[]> {
|
||||
|
||||
private final PoseFrames poseFrame;
|
||||
private final TrackerFrame[] trackerFrameBuffer;
|
||||
private final PoseFrames poseFrame;
|
||||
private final TrackerFrame[] trackerFrameBuffer;
|
||||
|
||||
private int cursor = 0;
|
||||
private int cursor = 0;
|
||||
|
||||
public PoseFrameIterator(PoseFrames poseFrame) {
|
||||
this.poseFrame = poseFrame;
|
||||
trackerFrameBuffer = new TrackerFrame[poseFrame.getTrackerCount()];
|
||||
}
|
||||
public PoseFrameIterator(PoseFrames poseFrame) {
|
||||
this.poseFrame = poseFrame;
|
||||
trackerFrameBuffer = new TrackerFrame[poseFrame.getTrackerCount()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (trackers.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (trackers.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
if (tracker != null && cursor < tracker.getFrameCount()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
PoseFrameTracker tracker = trackers.get(i);
|
||||
if (tracker != null && cursor < tracker.getFrameCount()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerFrame[] next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
@Override
|
||||
public TrackerFrame[] next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
poseFrame.getFrames(cursor++, trackerFrameBuffer);
|
||||
poseFrame.getFrames(cursor++, trackerFrameBuffer);
|
||||
|
||||
return trackerFrameBuffer;
|
||||
}
|
||||
}
|
||||
return trackerFrameBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,164 +14,164 @@ import java.util.concurrent.Future;
|
||||
|
||||
public class PoseRecorder {
|
||||
|
||||
protected final VRServer server;
|
||||
protected PoseFrames poseFrame = null;
|
||||
protected int numFrames = -1;
|
||||
protected int frameCursor = 0;
|
||||
protected long frameRecordingInterval = 60L;
|
||||
protected long nextFrameTimeMs = -1L;
|
||||
protected CompletableFuture<PoseFrames> currentRecording;
|
||||
FastList<Pair<Tracker, PoseFrameTracker>> trackers = new FastList<Pair<Tracker, PoseFrameTracker>>();
|
||||
protected final VRServer server;
|
||||
protected PoseFrames poseFrame = null;
|
||||
protected int numFrames = -1;
|
||||
protected int frameCursor = 0;
|
||||
protected long frameRecordingInterval = 60L;
|
||||
protected long nextFrameTimeMs = -1L;
|
||||
protected CompletableFuture<PoseFrames> currentRecording;
|
||||
FastList<Pair<Tracker, PoseFrameTracker>> trackers = new FastList<Pair<Tracker, PoseFrameTracker>>();
|
||||
|
||||
public PoseRecorder(VRServer server) {
|
||||
this.server = server;
|
||||
server.addOnTick(this::onTick);
|
||||
}
|
||||
public PoseRecorder(VRServer server) {
|
||||
this.server = server;
|
||||
server.addOnTick(this::onTick);
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void onTick() {
|
||||
if (numFrames <= 0) {
|
||||
return;
|
||||
}
|
||||
@VRServerThread
|
||||
public void onTick() {
|
||||
if (numFrames <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PoseFrames poseFrame = this.poseFrame;
|
||||
List<Pair<Tracker, PoseFrameTracker>> trackers = this.trackers;
|
||||
if (poseFrame == null || trackers == null) {
|
||||
return;
|
||||
}
|
||||
PoseFrames poseFrame = this.poseFrame;
|
||||
List<Pair<Tracker, PoseFrameTracker>> trackers = this.trackers;
|
||||
if (poseFrame == null || trackers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frameCursor >= numFrames) {
|
||||
// If done and hasn't yet, send finished recording
|
||||
stopFrameRecording();
|
||||
return;
|
||||
}
|
||||
if (frameCursor >= numFrames) {
|
||||
// If done and hasn't yet, send finished recording
|
||||
stopFrameRecording();
|
||||
return;
|
||||
}
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (curTime < nextFrameTimeMs) {
|
||||
return;
|
||||
}
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (curTime < nextFrameTimeMs) {
|
||||
return;
|
||||
}
|
||||
|
||||
nextFrameTimeMs += frameRecordingInterval;
|
||||
nextFrameTimeMs += frameRecordingInterval;
|
||||
|
||||
// To prevent duplicate frames, make sure the frame time is always in the future
|
||||
if (nextFrameTimeMs <= curTime) {
|
||||
nextFrameTimeMs = curTime + frameRecordingInterval;
|
||||
}
|
||||
// To prevent duplicate frames, make sure the frame time is always in the future
|
||||
if (nextFrameTimeMs <= curTime) {
|
||||
nextFrameTimeMs = curTime + frameRecordingInterval;
|
||||
}
|
||||
|
||||
// Make sure it's synchronized since this is the server thread interacting with
|
||||
// an unknown outside thread controlling this class
|
||||
synchronized (this) {
|
||||
// A stopped recording will be accounted for by an empty "trackers" list
|
||||
int cursor = frameCursor++;
|
||||
for (Pair<Tracker, PoseFrameTracker> tracker : trackers) {
|
||||
// Add a frame for each tracker
|
||||
tracker.getRight().addFrame(cursor, tracker.getLeft());
|
||||
}
|
||||
// Make sure it's synchronized since this is the server thread interacting with
|
||||
// an unknown outside thread controlling this class
|
||||
synchronized (this) {
|
||||
// A stopped recording will be accounted for by an empty "trackers" list
|
||||
int cursor = frameCursor++;
|
||||
for (Pair<Tracker, PoseFrameTracker> tracker : trackers) {
|
||||
// Add a frame for each tracker
|
||||
tracker.getRight().addFrame(cursor, tracker.getLeft());
|
||||
}
|
||||
|
||||
// If done, send finished recording
|
||||
if (frameCursor >= numFrames) {
|
||||
stopFrameRecording();
|
||||
}
|
||||
}
|
||||
}
|
||||
// If done, send finished recording
|
||||
if (frameCursor >= numFrames) {
|
||||
stopFrameRecording();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized Future<PoseFrames> startFrameRecording(int numFrames, long intervalMs) {
|
||||
return startFrameRecording(numFrames, intervalMs, server.getAllTrackers());
|
||||
}
|
||||
public synchronized Future<PoseFrames> startFrameRecording(int numFrames, long intervalMs) {
|
||||
return startFrameRecording(numFrames, intervalMs, server.getAllTrackers());
|
||||
}
|
||||
|
||||
public synchronized Future<PoseFrames> startFrameRecording(int numFrames, long intervalMs, List<Tracker> trackers) {
|
||||
if (numFrames < 1) {
|
||||
throw new IllegalArgumentException("numFrames must at least have a value of 1");
|
||||
}
|
||||
if (intervalMs < 1) {
|
||||
throw new IllegalArgumentException("intervalMs must at least have a value of 1");
|
||||
}
|
||||
if (trackers == null) {
|
||||
throw new IllegalArgumentException("trackers must not be null");
|
||||
}
|
||||
if (trackers.isEmpty()) {
|
||||
throw new IllegalArgumentException("trackers must have at least one entry");
|
||||
}
|
||||
if (!isReadyToRecord()) {
|
||||
throw new IllegalStateException("PoseRecorder isn't ready to record!");
|
||||
}
|
||||
public synchronized Future<PoseFrames> startFrameRecording(int numFrames, long intervalMs, List<Tracker> trackers) {
|
||||
if (numFrames < 1) {
|
||||
throw new IllegalArgumentException("numFrames must at least have a value of 1");
|
||||
}
|
||||
if (intervalMs < 1) {
|
||||
throw new IllegalArgumentException("intervalMs must at least have a value of 1");
|
||||
}
|
||||
if (trackers == null) {
|
||||
throw new IllegalArgumentException("trackers must not be null");
|
||||
}
|
||||
if (trackers.isEmpty()) {
|
||||
throw new IllegalArgumentException("trackers must have at least one entry");
|
||||
}
|
||||
if (!isReadyToRecord()) {
|
||||
throw new IllegalStateException("PoseRecorder isn't ready to record!");
|
||||
}
|
||||
|
||||
cancelFrameRecording();
|
||||
cancelFrameRecording();
|
||||
|
||||
poseFrame = new PoseFrames(trackers.size());
|
||||
poseFrame = new PoseFrames(trackers.size());
|
||||
|
||||
// Update tracker list
|
||||
this.trackers.ensureCapacity(trackers.size());
|
||||
for (Tracker tracker : trackers) {
|
||||
// Ignore null and computed trackers
|
||||
if (tracker == null || tracker.isComputed()) {
|
||||
continue;
|
||||
}
|
||||
// Update tracker list
|
||||
this.trackers.ensureCapacity(trackers.size());
|
||||
for (Tracker tracker : trackers) {
|
||||
// Ignore null and computed trackers
|
||||
if (tracker == null || tracker.isComputed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a tracker recording
|
||||
PoseFrameTracker poseFrameTracker = new PoseFrameTracker(tracker, numFrames);
|
||||
poseFrame.addTracker(poseFrameTracker);
|
||||
// Create a tracker recording
|
||||
PoseFrameTracker poseFrameTracker = new PoseFrameTracker(tracker, numFrames);
|
||||
poseFrame.addTracker(poseFrameTracker);
|
||||
|
||||
// Pair tracker with recording
|
||||
this.trackers.add(Pair.of(tracker, poseFrameTracker));
|
||||
}
|
||||
// Pair tracker with recording
|
||||
this.trackers.add(Pair.of(tracker, poseFrameTracker));
|
||||
}
|
||||
|
||||
this.frameCursor = 0;
|
||||
this.numFrames = numFrames;
|
||||
this.frameCursor = 0;
|
||||
this.numFrames = numFrames;
|
||||
|
||||
frameRecordingInterval = intervalMs;
|
||||
nextFrameTimeMs = -1L;
|
||||
frameRecordingInterval = intervalMs;
|
||||
nextFrameTimeMs = -1L;
|
||||
|
||||
LogManager.log.info("[PoseRecorder] Recording " + numFrames + " samples at a " + intervalMs + " ms frame interval");
|
||||
LogManager.log.info("[PoseRecorder] Recording " + numFrames + " samples at a " + intervalMs + " ms frame interval");
|
||||
|
||||
currentRecording = new CompletableFuture<PoseFrames>();
|
||||
return currentRecording;
|
||||
}
|
||||
currentRecording = new CompletableFuture<PoseFrames>();
|
||||
return currentRecording;
|
||||
}
|
||||
|
||||
public synchronized void stopFrameRecording() {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
if (currentRecording != null && !currentRecording.isDone()) {
|
||||
// Stop the recording, returning the frames recorded
|
||||
currentRecording.complete(poseFrame);
|
||||
}
|
||||
public synchronized void stopFrameRecording() {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
if (currentRecording != null && !currentRecording.isDone()) {
|
||||
// Stop the recording, returning the frames recorded
|
||||
currentRecording.complete(poseFrame);
|
||||
}
|
||||
|
||||
numFrames = -1;
|
||||
frameCursor = 0;
|
||||
trackers.clear();
|
||||
poseFrame = null;
|
||||
}
|
||||
numFrames = -1;
|
||||
frameCursor = 0;
|
||||
trackers.clear();
|
||||
poseFrame = null;
|
||||
}
|
||||
|
||||
public synchronized void cancelFrameRecording() {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
if (currentRecording != null && !currentRecording.isDone()) {
|
||||
// Cancel the current recording and return nothing
|
||||
currentRecording.cancel(true);
|
||||
}
|
||||
public synchronized void cancelFrameRecording() {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
if (currentRecording != null && !currentRecording.isDone()) {
|
||||
// Cancel the current recording and return nothing
|
||||
currentRecording.cancel(true);
|
||||
}
|
||||
|
||||
numFrames = -1;
|
||||
frameCursor = 0;
|
||||
trackers.clear();
|
||||
poseFrame = null;
|
||||
}
|
||||
numFrames = -1;
|
||||
frameCursor = 0;
|
||||
trackers.clear();
|
||||
poseFrame = null;
|
||||
}
|
||||
|
||||
public synchronized boolean isReadyToRecord() {
|
||||
return server.getTrackersCount() > 0;
|
||||
}
|
||||
public synchronized boolean isReadyToRecord() {
|
||||
return server.getTrackersCount() > 0;
|
||||
}
|
||||
|
||||
public synchronized boolean isRecording() {
|
||||
return numFrames > frameCursor;
|
||||
}
|
||||
public synchronized boolean isRecording() {
|
||||
return numFrames > frameCursor;
|
||||
}
|
||||
|
||||
public synchronized boolean hasRecording() {
|
||||
return currentRecording != null;
|
||||
}
|
||||
public synchronized boolean hasRecording() {
|
||||
return currentRecording != null;
|
||||
}
|
||||
|
||||
public synchronized Future<PoseFrames> getFramesAsync() {
|
||||
return currentRecording;
|
||||
}
|
||||
public synchronized Future<PoseFrames> getFramesAsync() {
|
||||
return currentRecording;
|
||||
}
|
||||
|
||||
public synchronized PoseFrames getFrames() throws ExecutionException, InterruptedException {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
return currentRecording != null ? currentRecording.get() : null;
|
||||
}
|
||||
public synchronized PoseFrames getFrames() throws ExecutionException, InterruptedException {
|
||||
CompletableFuture<PoseFrames> currentRecording = this.currentRecording;
|
||||
return currentRecording != null ? currentRecording.get() : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,179 +10,179 @@ import dev.slimevr.vr.trackers.udp.Device;
|
||||
|
||||
public final class TrackerFrame implements Tracker {
|
||||
|
||||
public final TrackerPosition designation;
|
||||
public final Quaternion rotation;
|
||||
public final Vector3f position;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
private int dataFlags = 0;
|
||||
public final TrackerPosition designation;
|
||||
public final Quaternion rotation;
|
||||
public final Vector3f position;
|
||||
private final int trackerId = Tracker.getNextLocalTrackerId();
|
||||
private int dataFlags = 0;
|
||||
|
||||
public TrackerFrame(TrackerPosition designation, Quaternion rotation, Vector3f position) {
|
||||
this.designation = designation;
|
||||
if (designation != null) {
|
||||
dataFlags |= TrackerFrameData.DESIGNATION.flag;
|
||||
}
|
||||
public TrackerFrame(TrackerPosition designation, Quaternion rotation, Vector3f position) {
|
||||
this.designation = designation;
|
||||
if (designation != null) {
|
||||
dataFlags |= TrackerFrameData.DESIGNATION.flag;
|
||||
}
|
||||
|
||||
this.rotation = rotation;
|
||||
if (rotation != null) {
|
||||
dataFlags |= TrackerFrameData.ROTATION.flag;
|
||||
}
|
||||
this.rotation = rotation;
|
||||
if (rotation != null) {
|
||||
dataFlags |= TrackerFrameData.ROTATION.flag;
|
||||
}
|
||||
|
||||
this.position = position;
|
||||
if (position != null) {
|
||||
dataFlags |= TrackerFrameData.POSITION.flag;
|
||||
}
|
||||
}
|
||||
this.position = position;
|
||||
if (position != null) {
|
||||
dataFlags |= TrackerFrameData.POSITION.flag;
|
||||
}
|
||||
}
|
||||
|
||||
public static TrackerFrame fromTracker(Tracker tracker) {
|
||||
if (tracker == null) {
|
||||
return null;
|
||||
}
|
||||
public static TrackerFrame fromTracker(Tracker tracker) {
|
||||
if (tracker == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the tracker is not ready
|
||||
if (tracker.getStatus() != TrackerStatus.OK && tracker.getStatus() != TrackerStatus.BUSY && tracker.getStatus() != TrackerStatus.OCCLUDED) {
|
||||
return null;
|
||||
}
|
||||
// If the tracker is not ready
|
||||
if (tracker.getStatus() != TrackerStatus.OK && tracker.getStatus() != TrackerStatus.BUSY && tracker.getStatus() != TrackerStatus.OCCLUDED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If tracker has no data
|
||||
if (tracker.getBodyPosition() == null && !tracker.hasRotation() && !tracker.hasPosition()) {
|
||||
return null;
|
||||
}
|
||||
// If tracker has no data
|
||||
if (tracker.getBodyPosition() == null && !tracker.hasRotation() && !tracker.hasPosition()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Quaternion rotation = null;
|
||||
if (tracker.hasRotation()) {
|
||||
rotation = new Quaternion();
|
||||
if (!tracker.getRotation(rotation)) {
|
||||
// If getting the rotation failed, set it back to null
|
||||
rotation = null;
|
||||
}
|
||||
}
|
||||
Quaternion rotation = null;
|
||||
if (tracker.hasRotation()) {
|
||||
rotation = new Quaternion();
|
||||
if (!tracker.getRotation(rotation)) {
|
||||
// If getting the rotation failed, set it back to null
|
||||
rotation = null;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3f position = null;
|
||||
if (tracker.hasPosition()) {
|
||||
position = new Vector3f();
|
||||
if (!tracker.getPosition(position)) {
|
||||
// If getting the position failed, set it back to null
|
||||
position = null;
|
||||
}
|
||||
}
|
||||
Vector3f position = null;
|
||||
if (tracker.hasPosition()) {
|
||||
position = new Vector3f();
|
||||
if (!tracker.getPosition(position)) {
|
||||
// If getting the position failed, set it back to null
|
||||
position = null;
|
||||
}
|
||||
}
|
||||
|
||||
return new TrackerFrame(tracker.getBodyPosition(), rotation, position);
|
||||
}
|
||||
return new TrackerFrame(tracker.getBodyPosition(), rotation, position);
|
||||
}
|
||||
|
||||
public int getDataFlags() {
|
||||
return dataFlags;
|
||||
}
|
||||
public int getDataFlags() {
|
||||
return dataFlags;
|
||||
}
|
||||
|
||||
public boolean hasData(TrackerFrameData flag) {
|
||||
return flag.check(dataFlags);
|
||||
}
|
||||
public boolean hasData(TrackerFrameData flag) {
|
||||
return flag.check(dataFlags);
|
||||
}
|
||||
|
||||
//#region Tracker Interface Implementation
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
if (hasData(TrackerFrameData.ROTATION)) {
|
||||
store.set(rotation);
|
||||
return true;
|
||||
}
|
||||
//#region Tracker Interface Implementation
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
if (hasData(TrackerFrameData.ROTATION)) {
|
||||
store.set(rotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
store.set(Quaternion.IDENTITY);
|
||||
return false;
|
||||
}
|
||||
store.set(Quaternion.IDENTITY);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
if (hasData(TrackerFrameData.POSITION)) {
|
||||
store.set(position);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
if (hasData(TrackerFrameData.POSITION)) {
|
||||
store.set(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
store.set(Vector3f.ZERO);
|
||||
return false;
|
||||
}
|
||||
store.set(Vector3f.ZERO);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TrackerFrame:/" + (designation != null ? designation.designation : "null");
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TrackerFrame:/" + (designation != null ? designation.designation : "null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return TrackerStatus.OK;
|
||||
}
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return TrackerStatus.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement configuration");
|
||||
}
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement configuration");
|
||||
}
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1f;
|
||||
}
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement calibration");
|
||||
}
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement calibration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement calibration");
|
||||
}
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement calibration");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement this method");
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not implement this method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return designation;
|
||||
}
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return designation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not allow setting the body position");
|
||||
}
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
throw new UnsupportedOperationException("TrackerFrame does not allow setting the body position");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return hasData(TrackerFrameData.ROTATION);
|
||||
}
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return hasData(TrackerFrameData.ROTATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return hasData(TrackerFrameData.POSITION);
|
||||
}
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return hasData(TrackerFrameData.POSITION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
//#endregion
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@ package dev.slimevr.poserecorder;
|
||||
|
||||
public enum TrackerFrameData {
|
||||
|
||||
DESIGNATION(0),
|
||||
ROTATION(1),
|
||||
POSITION(2),
|
||||
;
|
||||
DESIGNATION(0),
|
||||
ROTATION(1),
|
||||
POSITION(2),
|
||||
;
|
||||
|
||||
public final int flag;
|
||||
public final int flag;
|
||||
|
||||
TrackerFrameData(int id) {
|
||||
this.flag = 1 << id;
|
||||
}
|
||||
TrackerFrameData(int id) {
|
||||
this.flag = 1 << id;
|
||||
}
|
||||
|
||||
public boolean check(int dataFlags) {
|
||||
return (dataFlags & this.flag) != 0;
|
||||
}
|
||||
public boolean check(int dataFlags) {
|
||||
return (dataFlags & this.flag) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,174 +12,174 @@ import java.io.*;
|
||||
|
||||
public class BVHFileStream extends PoseDataStream {
|
||||
|
||||
private static final int LONG_MAX_VALUE_DIGITS = Long.toString(Long.MAX_VALUE).length();
|
||||
private static final float OFFSET_SCALE = 100f;
|
||||
private static final float POSITION_SCALE = 100f;
|
||||
private final BufferedWriter writer;
|
||||
private long frameCount = 0;
|
||||
private long frameCountOffset;
|
||||
private static final int LONG_MAX_VALUE_DIGITS = Long.toString(Long.MAX_VALUE).length();
|
||||
private static final float OFFSET_SCALE = 100f;
|
||||
private static final float POSITION_SCALE = 100f;
|
||||
private final BufferedWriter writer;
|
||||
private long frameCount = 0;
|
||||
private long frameCountOffset;
|
||||
|
||||
private float[] angleBuf = new float[3];
|
||||
private Quaternion rotBuf = new Quaternion();
|
||||
private float[] angleBuf = new float[3];
|
||||
private Quaternion rotBuf = new Quaternion();
|
||||
|
||||
private HumanSkeleton wrappedSkeleton;
|
||||
private TransformNodeWrapper rootNode;
|
||||
private HumanSkeleton wrappedSkeleton;
|
||||
private TransformNodeWrapper rootNode;
|
||||
|
||||
public BVHFileStream(OutputStream outputStream) {
|
||||
super(outputStream);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
public BVHFileStream(OutputStream outputStream) {
|
||||
super(outputStream);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
|
||||
public BVHFileStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
public BVHFileStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
|
||||
public BVHFileStream(String file) throws FileNotFoundException {
|
||||
super(file);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
public BVHFileStream(String file) throws FileNotFoundException {
|
||||
super(file);
|
||||
writer = new BufferedWriter(new OutputStreamWriter(outputStream), 4096);
|
||||
}
|
||||
|
||||
private String getBufferedFrameCount(long frameCount) {
|
||||
String frameString = Long.toString(frameCount);
|
||||
int bufferCount = LONG_MAX_VALUE_DIGITS - frameString.length();
|
||||
private String getBufferedFrameCount(long frameCount) {
|
||||
String frameString = Long.toString(frameCount);
|
||||
int bufferCount = LONG_MAX_VALUE_DIGITS - frameString.length();
|
||||
|
||||
return bufferCount > 0 ? frameString + StringUtils.repeat(' ', bufferCount) : frameString;
|
||||
}
|
||||
return bufferCount > 0 ? frameString + StringUtils.repeat(' ', bufferCount) : frameString;
|
||||
}
|
||||
|
||||
private TransformNodeWrapper wrapSkeletonIfNew(HumanSkeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = rootNode;
|
||||
private TransformNodeWrapper wrapSkeletonIfNew(HumanSkeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = rootNode;
|
||||
|
||||
// If the wrapped skeleton is missing or the skeleton is updated
|
||||
if (wrapper == null || skeleton != wrappedSkeleton) {
|
||||
wrapper = wrapSkeleton(skeleton);
|
||||
}
|
||||
// If the wrapped skeleton is missing or the skeleton is updated
|
||||
if (wrapper == null || skeleton != wrappedSkeleton) {
|
||||
wrapper = wrapSkeleton(skeleton);
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private TransformNodeWrapper wrapSkeleton(HumanSkeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = wrapSkeletonNodes(skeleton.getRootNode());
|
||||
private TransformNodeWrapper wrapSkeleton(HumanSkeleton skeleton) {
|
||||
TransformNodeWrapper wrapper = wrapSkeletonNodes(skeleton.getRootNode());
|
||||
|
||||
wrappedSkeleton = skeleton;
|
||||
rootNode = wrapper;
|
||||
wrappedSkeleton = skeleton;
|
||||
rootNode = wrapper;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
protected TransformNodeWrapper wrapSkeletonNodes(TransformNode rootNode) {
|
||||
return TransformNodeWrapper.wrapFullHierarchy(rootNode);
|
||||
}
|
||||
protected TransformNodeWrapper wrapSkeletonNodes(TransformNode rootNode) {
|
||||
return TransformNodeWrapper.wrapFullHierarchy(rootNode);
|
||||
}
|
||||
|
||||
private void writeNodeHierarchy(TransformNodeWrapper node) throws IOException {
|
||||
writeNodeHierarchy(node, 0);
|
||||
}
|
||||
private void writeNodeHierarchy(TransformNodeWrapper node) throws IOException {
|
||||
writeNodeHierarchy(node, 0);
|
||||
}
|
||||
|
||||
private void writeNodeHierarchy(TransformNodeWrapper node, int level) throws IOException {
|
||||
// Don't write end sites at populated nodes
|
||||
if (node.children.isEmpty() && node.getParent().children.size() > 1) {
|
||||
return;
|
||||
}
|
||||
private void writeNodeHierarchy(TransformNodeWrapper node, int level) throws IOException {
|
||||
// Don't write end sites at populated nodes
|
||||
if (node.children.isEmpty() && node.getParent().children.size() > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
String indentLevel = StringUtils.repeat("\t", level);
|
||||
String nextIndentLevel = indentLevel + "\t";
|
||||
String indentLevel = StringUtils.repeat("\t", level);
|
||||
String nextIndentLevel = indentLevel + "\t";
|
||||
|
||||
// Handle ends
|
||||
if (node.children.isEmpty()) {
|
||||
writer.write(indentLevel + "End Site\n");
|
||||
} else {
|
||||
writer.write((level > 0 ? indentLevel + "JOINT " : "ROOT ") + node.getName() + "\n");
|
||||
}
|
||||
writer.write(indentLevel + "{\n");
|
||||
// Handle ends
|
||||
if (node.children.isEmpty()) {
|
||||
writer.write(indentLevel + "End Site\n");
|
||||
} else {
|
||||
writer.write((level > 0 ? indentLevel + "JOINT " : "ROOT ") + node.getName() + "\n");
|
||||
}
|
||||
writer.write(indentLevel + "{\n");
|
||||
|
||||
// Ignore the root offset and original root offset
|
||||
if (level > 0 && node.wrappedNode.getParent() != null) {
|
||||
Vector3f offset = node.localTransform.getTranslation();
|
||||
float reverseMultiplier = node.hasReversedHierarchy() ? -1 : 1;
|
||||
writer.write(nextIndentLevel + "OFFSET " + offset.getX() * OFFSET_SCALE * reverseMultiplier + " " + offset.getY() * OFFSET_SCALE * reverseMultiplier + " " + offset.getZ() * OFFSET_SCALE * reverseMultiplier + "\n");
|
||||
} else {
|
||||
writer.write(nextIndentLevel + "OFFSET 0.0 0.0 0.0\n");
|
||||
}
|
||||
// Ignore the root offset and original root offset
|
||||
if (level > 0 && node.wrappedNode.getParent() != null) {
|
||||
Vector3f offset = node.localTransform.getTranslation();
|
||||
float reverseMultiplier = node.hasReversedHierarchy() ? -1 : 1;
|
||||
writer.write(nextIndentLevel + "OFFSET " + offset.getX() * OFFSET_SCALE * reverseMultiplier + " " + offset.getY() * OFFSET_SCALE * reverseMultiplier + " " + offset.getZ() * OFFSET_SCALE * reverseMultiplier + "\n");
|
||||
} else {
|
||||
writer.write(nextIndentLevel + "OFFSET 0.0 0.0 0.0\n");
|
||||
}
|
||||
|
||||
// Handle ends
|
||||
if (!node.children.isEmpty()) {
|
||||
// Only give position for root
|
||||
if (level > 0) {
|
||||
writer.write(nextIndentLevel + "CHANNELS 3 Zrotation Xrotation Yrotation\n");
|
||||
} else {
|
||||
writer.write(nextIndentLevel + "CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation\n");
|
||||
}
|
||||
// Handle ends
|
||||
if (!node.children.isEmpty()) {
|
||||
// Only give position for root
|
||||
if (level > 0) {
|
||||
writer.write(nextIndentLevel + "CHANNELS 3 Zrotation Xrotation Yrotation\n");
|
||||
} else {
|
||||
writer.write(nextIndentLevel + "CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation\n");
|
||||
}
|
||||
|
||||
for (TransformNodeWrapper childNode : node.children) {
|
||||
writeNodeHierarchy(childNode, level + 1);
|
||||
}
|
||||
}
|
||||
for (TransformNodeWrapper childNode : node.children) {
|
||||
writeNodeHierarchy(childNode, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
writer.write(indentLevel + "}\n");
|
||||
}
|
||||
writer.write(indentLevel + "}\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
if (streamer == null) {
|
||||
throw new NullPointerException("streamer must not be null");
|
||||
}
|
||||
@Override
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
if (streamer == null) {
|
||||
throw new NullPointerException("streamer must not be null");
|
||||
}
|
||||
|
||||
writer.write("HIERARCHY\n");
|
||||
writeNodeHierarchy(wrapSkeletonIfNew(skeleton));
|
||||
writer.write("HIERARCHY\n");
|
||||
writeNodeHierarchy(wrapSkeletonIfNew(skeleton));
|
||||
|
||||
writer.write("MOTION\n");
|
||||
writer.write("Frames: ");
|
||||
writer.write("MOTION\n");
|
||||
writer.write("Frames: ");
|
||||
|
||||
// Get frame offset for finishing writing the file
|
||||
if (outputStream instanceof FileOutputStream) {
|
||||
FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
|
||||
// Flush buffer to get proper offset
|
||||
writer.flush();
|
||||
frameCountOffset = fileOutputStream.getChannel().position();
|
||||
}
|
||||
// Get frame offset for finishing writing the file
|
||||
if (outputStream instanceof FileOutputStream) {
|
||||
FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
|
||||
// Flush buffer to get proper offset
|
||||
writer.flush();
|
||||
frameCountOffset = fileOutputStream.getChannel().position();
|
||||
}
|
||||
|
||||
writer.write(getBufferedFrameCount(frameCount) + "\n");
|
||||
writer.write(getBufferedFrameCount(frameCount) + "\n");
|
||||
|
||||
// Frame time in seconds
|
||||
writer.write("Frame Time: " + (streamer.getFrameInterval() / 1000d) + "\n");
|
||||
}
|
||||
// Frame time in seconds
|
||||
writer.write("Frame Time: " + (streamer.getFrameInterval() / 1000d) + "\n");
|
||||
}
|
||||
|
||||
// Roughly based off code from https://github.com/TrackLab/ViRe/blob/50a987eff4db31036b2ebaeb5a28983cd473f267/Assets/Scripts/BVH/BVHRecorder.cs
|
||||
private float[] quatToXyzAngles(Quaternion q, float[] angles) {
|
||||
if (angles == null) {
|
||||
angles = new float[3];
|
||||
} else if (angles.length != 3) {
|
||||
throw new IllegalArgumentException("Angles array must have three elements");
|
||||
}
|
||||
// Roughly based off code from https://github.com/TrackLab/ViRe/blob/50a987eff4db31036b2ebaeb5a28983cd473f267/Assets/Scripts/BVH/BVHRecorder.cs
|
||||
private float[] quatToXyzAngles(Quaternion q, float[] angles) {
|
||||
if (angles == null) {
|
||||
angles = new float[3];
|
||||
} else if (angles.length != 3) {
|
||||
throw new IllegalArgumentException("Angles array must have three elements");
|
||||
}
|
||||
|
||||
float x = q.getX();
|
||||
float y = q.getY();
|
||||
float z = q.getZ();
|
||||
float w = q.getW();
|
||||
float x = q.getX();
|
||||
float y = q.getY();
|
||||
float z = q.getZ();
|
||||
float w = q.getW();
|
||||
|
||||
// Roll (X)
|
||||
float sinrCosp = -2f * (x * y - w * z);
|
||||
float cosrCosp = w * w - x * x + y * y - z * z;
|
||||
angles[0] = FastMath.atan2(sinrCosp, cosrCosp);
|
||||
// Roll (X)
|
||||
float sinrCosp = -2f * (x * y - w * z);
|
||||
float cosrCosp = w * w - x * x + y * y - z * z;
|
||||
angles[0] = FastMath.atan2(sinrCosp, cosrCosp);
|
||||
|
||||
// Pitch (Y)
|
||||
float sinp = 2f * (y * z + w * x);
|
||||
// Use 90 degrees if out of range
|
||||
angles[1] = FastMath.abs(sinp) >= 1f ? FastMath.copysign(FastMath.PI / 2f, sinp) : FastMath.asin(sinp);
|
||||
// Pitch (Y)
|
||||
float sinp = 2f * (y * z + w * x);
|
||||
// Use 90 degrees if out of range
|
||||
angles[1] = FastMath.abs(sinp) >= 1f ? FastMath.copysign(FastMath.PI / 2f, sinp) : FastMath.asin(sinp);
|
||||
|
||||
// Yaw (Z)
|
||||
float sinyCosp = -2f * (x * z - w * y);
|
||||
float cosyCosp = w * w - x * x - y * y + z * z;
|
||||
angles[2] = FastMath.atan2(sinyCosp, cosyCosp);
|
||||
// Yaw (Z)
|
||||
float sinyCosp = -2f * (x * z - w * y);
|
||||
float cosyCosp = w * w - x * x - y * y + z * z;
|
||||
angles[2] = FastMath.atan2(sinyCosp, cosyCosp);
|
||||
|
||||
return angles;
|
||||
}
|
||||
return angles;
|
||||
}
|
||||
|
||||
private void writeNodeHierarchyRotation(TransformNodeWrapper node, Quaternion inverseRootRot) throws IOException {
|
||||
Transform transform = node.worldTransform;
|
||||
private void writeNodeHierarchyRotation(TransformNodeWrapper node, Quaternion inverseRootRot) throws IOException {
|
||||
Transform transform = node.worldTransform;
|
||||
|
||||
/*
|
||||
if (node.hasReversedHierarchy()) {
|
||||
@@ -193,74 +193,74 @@ public class BVHFileStream extends PoseDataStream {
|
||||
}
|
||||
*/
|
||||
|
||||
rotBuf = transform.getRotation(rotBuf);
|
||||
rotBuf = transform.getRotation(rotBuf);
|
||||
|
||||
// Adjust to local rotation
|
||||
if (inverseRootRot != null) {
|
||||
rotBuf = inverseRootRot.mult(rotBuf, rotBuf);
|
||||
}
|
||||
// Adjust to local rotation
|
||||
if (inverseRootRot != null) {
|
||||
rotBuf = inverseRootRot.mult(rotBuf, rotBuf);
|
||||
}
|
||||
|
||||
// Yaw (Z), roll (X), pitch (Y) (intrinsic)
|
||||
// angleBuf = rotBuf.toAngles(angleBuf);
|
||||
// Yaw (Z), roll (X), pitch (Y) (intrinsic)
|
||||
// angleBuf = rotBuf.toAngles(angleBuf);
|
||||
|
||||
// Roll (X), pitch (Y), yaw (Z) (intrinsic)
|
||||
angleBuf = quatToXyzAngles(rotBuf.normalizeLocal(), angleBuf);
|
||||
// Roll (X), pitch (Y), yaw (Z) (intrinsic)
|
||||
angleBuf = quatToXyzAngles(rotBuf.normalizeLocal(), angleBuf);
|
||||
|
||||
// Output in order of roll (Z), pitch (X), yaw (Y) (extrinsic)
|
||||
writer.write(angleBuf[0] * FastMath.RAD_TO_DEG + " " + angleBuf[1] * FastMath.RAD_TO_DEG + " " + angleBuf[2] * FastMath.RAD_TO_DEG);
|
||||
// Output in order of roll (Z), pitch (X), yaw (Y) (extrinsic)
|
||||
writer.write(angleBuf[0] * FastMath.RAD_TO_DEG + " " + angleBuf[1] * FastMath.RAD_TO_DEG + " " + angleBuf[2] * FastMath.RAD_TO_DEG);
|
||||
|
||||
// Get inverse rotation for child local rotations
|
||||
if (!node.children.isEmpty()) {
|
||||
Quaternion inverseRot = transform.getRotation().inverse();
|
||||
for (TransformNodeWrapper childNode : node.children) {
|
||||
if (childNode.children.isEmpty()) {
|
||||
// If it's an end node, skip
|
||||
continue;
|
||||
}
|
||||
// Get inverse rotation for child local rotations
|
||||
if (!node.children.isEmpty()) {
|
||||
Quaternion inverseRot = transform.getRotation().inverse();
|
||||
for (TransformNodeWrapper childNode : node.children) {
|
||||
if (childNode.children.isEmpty()) {
|
||||
// If it's an end node, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add spacing
|
||||
writer.write(" ");
|
||||
writeNodeHierarchyRotation(childNode, inverseRot);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add spacing
|
||||
writer.write(" ");
|
||||
writeNodeHierarchyRotation(childNode, inverseRot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFrame(HumanSkeleton skeleton) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
@Override
|
||||
public void writeFrame(HumanSkeleton skeleton) throws IOException {
|
||||
if (skeleton == null) {
|
||||
throw new NullPointerException("skeleton must not be null");
|
||||
}
|
||||
|
||||
TransformNodeWrapper rootNode = wrapSkeletonIfNew(skeleton);
|
||||
TransformNodeWrapper rootNode = wrapSkeletonIfNew(skeleton);
|
||||
|
||||
Vector3f rootPos = rootNode.worldTransform.getTranslation();
|
||||
Vector3f rootPos = rootNode.worldTransform.getTranslation();
|
||||
|
||||
// Write root position
|
||||
writer.write(rootPos.getX() * POSITION_SCALE + " " + rootPos.getY() * POSITION_SCALE + " " + rootPos.getZ() * POSITION_SCALE + " ");
|
||||
writeNodeHierarchyRotation(rootNode, null);
|
||||
// Write root position
|
||||
writer.write(rootPos.getX() * POSITION_SCALE + " " + rootPos.getY() * POSITION_SCALE + " " + rootPos.getZ() * POSITION_SCALE + " ");
|
||||
writeNodeHierarchyRotation(rootNode, null);
|
||||
|
||||
writer.newLine();
|
||||
writer.newLine();
|
||||
|
||||
frameCount++;
|
||||
}
|
||||
frameCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
// Write the final frame count for files
|
||||
if (outputStream instanceof FileOutputStream) {
|
||||
FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
|
||||
// Flush before anything else
|
||||
writer.flush();
|
||||
// Seek to the count offset
|
||||
fileOutputStream.getChannel().position(frameCountOffset);
|
||||
// Overwrite the count with a new value
|
||||
writer.write(Long.toString(frameCount));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
// Write the final frame count for files
|
||||
if (outputStream instanceof FileOutputStream) {
|
||||
FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
|
||||
// Flush before anything else
|
||||
writer.flush();
|
||||
// Seek to the count offset
|
||||
fileOutputStream.getChannel().position(frameCountOffset);
|
||||
// Overwrite the count with a new value
|
||||
writer.write(Long.toString(frameCount));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
writer.close();
|
||||
super.close();
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
writer.close();
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,36 +6,36 @@ import java.io.*;
|
||||
|
||||
public abstract class PoseDataStream implements AutoCloseable {
|
||||
|
||||
protected final OutputStream outputStream;
|
||||
protected boolean closed = false;
|
||||
protected final OutputStream outputStream;
|
||||
protected boolean closed = false;
|
||||
|
||||
protected PoseDataStream(OutputStream outputStream) {
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
protected PoseDataStream(OutputStream outputStream) {
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
protected PoseDataStream(File file) throws FileNotFoundException {
|
||||
this(new FileOutputStream(file));
|
||||
}
|
||||
protected PoseDataStream(File file) throws FileNotFoundException {
|
||||
this(new FileOutputStream(file));
|
||||
}
|
||||
|
||||
protected PoseDataStream(String file) throws FileNotFoundException {
|
||||
this(new FileOutputStream(file));
|
||||
}
|
||||
protected PoseDataStream(String file) throws FileNotFoundException {
|
||||
this(new FileOutputStream(file));
|
||||
}
|
||||
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
}
|
||||
public void writeHeader(HumanSkeleton skeleton, PoseStreamer streamer) throws IOException {
|
||||
}
|
||||
|
||||
abstract void writeFrame(HumanSkeleton skeleton) throws IOException;
|
||||
abstract void writeFrame(HumanSkeleton skeleton) throws IOException;
|
||||
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
}
|
||||
public void writeFooter(HumanSkeleton skeleton) throws IOException {
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
closed = true;
|
||||
}
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
outputStream.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,31 +8,31 @@ import java.io.File;
|
||||
|
||||
public class PoseFrameStreamer extends PoseStreamer {
|
||||
|
||||
private final PoseFrames frames;
|
||||
private final PoseFrames frames;
|
||||
|
||||
public PoseFrameStreamer(String path) {
|
||||
this(new File(path));
|
||||
}
|
||||
public PoseFrameStreamer(String path) {
|
||||
this(new File(path));
|
||||
}
|
||||
|
||||
public PoseFrameStreamer(File file) {
|
||||
this(PoseFrameIO.readFromFile(file));
|
||||
}
|
||||
public PoseFrameStreamer(File file) {
|
||||
this(PoseFrameIO.readFromFile(file));
|
||||
}
|
||||
|
||||
public PoseFrameStreamer(PoseFrames frames) {
|
||||
super(new PoseFrameSkeleton(frames.getTrackers(), null));
|
||||
this.frames = frames;
|
||||
}
|
||||
public PoseFrameStreamer(PoseFrames frames) {
|
||||
super(new PoseFrameSkeleton(frames.getTrackers(), null));
|
||||
this.frames = frames;
|
||||
}
|
||||
|
||||
public PoseFrames getFrames() {
|
||||
return frames;
|
||||
}
|
||||
public PoseFrames getFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
public synchronized void streamAllFrames() {
|
||||
PoseFrameSkeleton skeleton = (PoseFrameSkeleton) this.skeleton;
|
||||
for (int i = 0; i < frames.getMaxFrameCount(); i++) {
|
||||
skeleton.setCursor(i);
|
||||
skeleton.updatePose();
|
||||
captureFrame();
|
||||
}
|
||||
}
|
||||
public synchronized void streamAllFrames() {
|
||||
PoseFrameSkeleton skeleton = (PoseFrameSkeleton) this.skeleton;
|
||||
for (int i = 0; i < frames.getMaxFrameCount(); i++) {
|
||||
skeleton.setCursor(i);
|
||||
skeleton.updatePose();
|
||||
captureFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,72 +7,72 @@ import java.io.IOException;
|
||||
|
||||
public class PoseStreamer {
|
||||
|
||||
protected long frameRecordingInterval = 60L;
|
||||
protected long frameRecordingInterval = 60L;
|
||||
|
||||
protected HumanSkeleton skeleton;
|
||||
protected PoseDataStream poseFileStream;
|
||||
protected HumanSkeleton skeleton;
|
||||
protected PoseDataStream poseFileStream;
|
||||
|
||||
public PoseStreamer(HumanSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
public PoseStreamer(HumanSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
public synchronized void captureFrame() {
|
||||
// Make sure the stream is open before trying to write
|
||||
if (poseFileStream.isClosed()) {
|
||||
return;
|
||||
}
|
||||
public synchronized void captureFrame() {
|
||||
// Make sure the stream is open before trying to write
|
||||
if (poseFileStream.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
poseFileStream.writeFrame(skeleton);
|
||||
} catch (Exception e) {
|
||||
// Handle any exceptions without crashing the program
|
||||
LogManager.log.severe("[PoseStreamer] Exception while saving frame", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
poseFileStream.writeFrame(skeleton);
|
||||
} catch (Exception e) {
|
||||
// Handle any exceptions without crashing the program
|
||||
LogManager.log.severe("[PoseStreamer] Exception while saving frame", e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized long getFrameInterval() {
|
||||
return frameRecordingInterval;
|
||||
}
|
||||
public synchronized long getFrameInterval() {
|
||||
return frameRecordingInterval;
|
||||
}
|
||||
|
||||
public synchronized void setFrameInterval(long intervalMs) {
|
||||
if (intervalMs < 1) {
|
||||
throw new IllegalArgumentException("intervalMs must at least have a value of 1");
|
||||
}
|
||||
public synchronized void setFrameInterval(long intervalMs) {
|
||||
if (intervalMs < 1) {
|
||||
throw new IllegalArgumentException("intervalMs must at least have a value of 1");
|
||||
}
|
||||
|
||||
this.frameRecordingInterval = intervalMs;
|
||||
}
|
||||
this.frameRecordingInterval = intervalMs;
|
||||
}
|
||||
|
||||
public synchronized HumanSkeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
public synchronized HumanSkeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream, long intervalMs) throws IOException {
|
||||
setFrameInterval(intervalMs);
|
||||
setOutput(poseFileStream);
|
||||
}
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream, long intervalMs) throws IOException {
|
||||
setFrameInterval(intervalMs);
|
||||
setOutput(poseFileStream);
|
||||
}
|
||||
|
||||
public synchronized PoseDataStream getOutput() {
|
||||
return poseFileStream;
|
||||
}
|
||||
public synchronized PoseDataStream getOutput() {
|
||||
return poseFileStream;
|
||||
}
|
||||
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
poseFileStream.writeHeader(skeleton, this);
|
||||
this.poseFileStream = poseFileStream;
|
||||
}
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
poseFileStream.writeHeader(skeleton, this);
|
||||
this.poseFileStream = poseFileStream;
|
||||
}
|
||||
|
||||
public synchronized void closeOutput() throws IOException {
|
||||
PoseDataStream poseFileStream = this.poseFileStream;
|
||||
public synchronized void closeOutput() throws IOException {
|
||||
PoseDataStream poseFileStream = this.poseFileStream;
|
||||
|
||||
if (poseFileStream != null) {
|
||||
closeOutput(poseFileStream);
|
||||
this.poseFileStream = null;
|
||||
}
|
||||
}
|
||||
if (poseFileStream != null) {
|
||||
closeOutput(poseFileStream);
|
||||
this.poseFileStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void closeOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
if (poseFileStream != null) {
|
||||
poseFileStream.writeFooter(skeleton);
|
||||
poseFileStream.close();
|
||||
}
|
||||
}
|
||||
public synchronized void closeOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
if (poseFileStream != null) {
|
||||
poseFileStream.writeFooter(skeleton);
|
||||
poseFileStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,24 +6,24 @@ import dev.slimevr.vr.processor.skeleton.HumanSkeleton;
|
||||
|
||||
public class ServerPoseStreamer extends TickPoseStreamer {
|
||||
|
||||
protected final VRServer server;
|
||||
protected final VRServer server;
|
||||
|
||||
public ServerPoseStreamer(VRServer server) {
|
||||
super(null); // Skeleton is registered later
|
||||
this.server = server;
|
||||
public ServerPoseStreamer(VRServer server) {
|
||||
super(null); // Skeleton is registered later
|
||||
this.server = server;
|
||||
|
||||
// Register callbacks/events
|
||||
server.addSkeletonUpdatedCallback(this::onSkeletonUpdated);
|
||||
server.addOnTick(this::onTick);
|
||||
}
|
||||
// Register callbacks/events
|
||||
server.addSkeletonUpdatedCallback(this::onSkeletonUpdated);
|
||||
server.addOnTick(this::onTick);
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void onSkeletonUpdated(HumanSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
@VRServerThread
|
||||
public void onSkeletonUpdated(HumanSkeleton skeleton) {
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void onTick() {
|
||||
super.doTick();
|
||||
}
|
||||
@VRServerThread
|
||||
public void onTick() {
|
||||
super.doTick();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,40 @@ import java.io.OutputStream;
|
||||
|
||||
public class StdBVHFileStream extends BVHFileStream {
|
||||
|
||||
public StdBVHFileStream(OutputStream outputStream) {
|
||||
super(outputStream);
|
||||
}
|
||||
public StdBVHFileStream(OutputStream outputStream) {
|
||||
super(outputStream);
|
||||
}
|
||||
|
||||
public StdBVHFileStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
public StdBVHFileStream(File file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
public StdBVHFileStream(String file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
public StdBVHFileStream(String file) throws FileNotFoundException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransformNodeWrapper wrapSkeletonNodes(TransformNode rootNode) {
|
||||
TransformNode newRoot = getNodeFromHierarchy(rootNode, "Hip");
|
||||
if (newRoot == null) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected TransformNodeWrapper wrapSkeletonNodes(TransformNode rootNode) {
|
||||
TransformNode newRoot = getNodeFromHierarchy(rootNode, "Hip");
|
||||
if (newRoot == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return TransformNodeWrapper.wrapFullHierarchy(newRoot);
|
||||
}
|
||||
return TransformNodeWrapper.wrapFullHierarchy(newRoot);
|
||||
}
|
||||
|
||||
private TransformNode getNodeFromHierarchy(TransformNode node, String name) {
|
||||
if (node.getName().equalsIgnoreCase(name)) {
|
||||
return node;
|
||||
}
|
||||
private TransformNode getNodeFromHierarchy(TransformNode node, String name) {
|
||||
if (node.getName().equalsIgnoreCase(name)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
for (TransformNode child : node.children) {
|
||||
TransformNode result = getNodeFromHierarchy(child, name);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (TransformNode child : node.children) {
|
||||
TransformNode result = getNodeFromHierarchy(child, name);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,41 +6,41 @@ import java.io.IOException;
|
||||
|
||||
public class TickPoseStreamer extends PoseStreamer {
|
||||
|
||||
protected long nextFrameTimeMs = -1L;
|
||||
protected long nextFrameTimeMs = -1L;
|
||||
|
||||
public TickPoseStreamer(HumanSkeleton skeleton) {
|
||||
super(skeleton);
|
||||
}
|
||||
public TickPoseStreamer(HumanSkeleton skeleton) {
|
||||
super(skeleton);
|
||||
}
|
||||
|
||||
public void doTick() {
|
||||
PoseDataStream poseFileStream = this.poseFileStream;
|
||||
if (poseFileStream == null) {
|
||||
return;
|
||||
}
|
||||
public void doTick() {
|
||||
PoseDataStream poseFileStream = this.poseFileStream;
|
||||
if (poseFileStream == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
HumanSkeleton skeleton = this.skeleton;
|
||||
if (skeleton == null) {
|
||||
return;
|
||||
}
|
||||
HumanSkeleton skeleton = this.skeleton;
|
||||
if (skeleton == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (curTime < nextFrameTimeMs) {
|
||||
return;
|
||||
}
|
||||
long curTime = System.currentTimeMillis();
|
||||
if (curTime < nextFrameTimeMs) {
|
||||
return;
|
||||
}
|
||||
|
||||
nextFrameTimeMs += frameRecordingInterval;
|
||||
nextFrameTimeMs += frameRecordingInterval;
|
||||
|
||||
// To prevent duplicate frames, make sure the frame time is always in the future
|
||||
if (nextFrameTimeMs <= curTime) {
|
||||
nextFrameTimeMs = curTime + frameRecordingInterval;
|
||||
}
|
||||
// To prevent duplicate frames, make sure the frame time is always in the future
|
||||
if (nextFrameTimeMs <= curTime) {
|
||||
nextFrameTimeMs = curTime + frameRecordingInterval;
|
||||
}
|
||||
|
||||
captureFrame();
|
||||
}
|
||||
captureFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
super.setOutput(poseFileStream);
|
||||
nextFrameTimeMs = -1L; // Reset the frame timing
|
||||
}
|
||||
@Override
|
||||
public synchronized void setOutput(PoseDataStream poseFileStream) throws IOException {
|
||||
super.setOutput(poseFileStream);
|
||||
nextFrameTimeMs = -1L; // Reset the frame timing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,158 +9,158 @@ import java.util.List;
|
||||
|
||||
public class TransformNodeWrapper {
|
||||
|
||||
public final TransformNode wrappedNode;
|
||||
public final Transform localTransform;
|
||||
public final Transform worldTransform;
|
||||
public final List<TransformNodeWrapper> children;
|
||||
protected String name;
|
||||
protected TransformNodeWrapper parent;
|
||||
private boolean reversedHierarchy = false;
|
||||
public final TransformNode wrappedNode;
|
||||
public final Transform localTransform;
|
||||
public final Transform worldTransform;
|
||||
public final List<TransformNodeWrapper> children;
|
||||
protected String name;
|
||||
protected TransformNodeWrapper parent;
|
||||
private boolean reversedHierarchy = false;
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name, boolean reversedHierarchy, int initialChildCapacity) {
|
||||
this.wrappedNode = nodeToWrap;
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name, boolean reversedHierarchy, int initialChildCapacity) {
|
||||
this.wrappedNode = nodeToWrap;
|
||||
|
||||
this.name = name;
|
||||
this.name = name;
|
||||
|
||||
this.localTransform = nodeToWrap.localTransform;
|
||||
this.worldTransform = nodeToWrap.worldTransform;
|
||||
this.localTransform = nodeToWrap.localTransform;
|
||||
this.worldTransform = nodeToWrap.worldTransform;
|
||||
|
||||
this.reversedHierarchy = reversedHierarchy;
|
||||
this.reversedHierarchy = reversedHierarchy;
|
||||
|
||||
this.children = new FastList<>(initialChildCapacity);
|
||||
}
|
||||
this.children = new FastList<>(initialChildCapacity);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name, int initialChildCapacity) {
|
||||
this(nodeToWrap, name, false, initialChildCapacity);
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name, int initialChildCapacity) {
|
||||
this(nodeToWrap, name, false, initialChildCapacity);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name) {
|
||||
this(nodeToWrap, name, false, 5);
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, String name) {
|
||||
this(nodeToWrap, name, false, 5);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, boolean reversedHierarchy, int initialChildCapacity) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), reversedHierarchy, initialChildCapacity);
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, boolean reversedHierarchy, int initialChildCapacity) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), reversedHierarchy, initialChildCapacity);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, boolean reversedHierarchy) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), reversedHierarchy, 5);
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, boolean reversedHierarchy) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), reversedHierarchy, 5);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, int initialChildCapacity) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), initialChildCapacity);
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap, int initialChildCapacity) {
|
||||
this(nodeToWrap, nodeToWrap.getName(), initialChildCapacity);
|
||||
}
|
||||
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap) {
|
||||
this(nodeToWrap, nodeToWrap.getName());
|
||||
}
|
||||
public TransformNodeWrapper(TransformNode nodeToWrap) {
|
||||
this(nodeToWrap, nodeToWrap.getName());
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapFullHierarchyWithFakeRoot(TransformNode root) {
|
||||
// Allocate a "fake" root with appropriate size depending on connections the root has
|
||||
TransformNodeWrapper fakeRoot = new TransformNodeWrapper(root, root.getParent() != null ? 2 : 1);
|
||||
public static TransformNodeWrapper wrapFullHierarchyWithFakeRoot(TransformNode root) {
|
||||
// Allocate a "fake" root with appropriate size depending on connections the root has
|
||||
TransformNodeWrapper fakeRoot = new TransformNodeWrapper(root, root.getParent() != null ? 2 : 1);
|
||||
|
||||
// Attach downwards hierarchy to the fake root
|
||||
wrapNodeHierarchyDown(root, fakeRoot);
|
||||
// Attach downwards hierarchy to the fake root
|
||||
wrapNodeHierarchyDown(root, fakeRoot);
|
||||
|
||||
// Attach upwards hierarchy to the fake root
|
||||
fakeRoot.attachChild(wrapHierarchyUp(root));
|
||||
// Attach upwards hierarchy to the fake root
|
||||
fakeRoot.attachChild(wrapHierarchyUp(root));
|
||||
|
||||
return fakeRoot;
|
||||
}
|
||||
return fakeRoot;
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapFullHierarchy(TransformNode root) {
|
||||
return wrapNodeHierarchyUp(wrapHierarchyDown(root));
|
||||
}
|
||||
public static TransformNodeWrapper wrapFullHierarchy(TransformNode root) {
|
||||
return wrapNodeHierarchyUp(wrapHierarchyDown(root));
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapHierarchyDown(TransformNode root) {
|
||||
return wrapNodeHierarchyDown(root, new TransformNodeWrapper(root, root.children.size()));
|
||||
}
|
||||
public static TransformNodeWrapper wrapHierarchyDown(TransformNode root) {
|
||||
return wrapNodeHierarchyDown(root, new TransformNodeWrapper(root, root.children.size()));
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapNodeHierarchyDown(TransformNode root, TransformNodeWrapper target) {
|
||||
for (TransformNode child : root.children) {
|
||||
target.attachChild(wrapHierarchyDown(child));
|
||||
}
|
||||
public static TransformNodeWrapper wrapNodeHierarchyDown(TransformNode root, TransformNodeWrapper target) {
|
||||
for (TransformNode child : root.children) {
|
||||
target.attachChild(wrapHierarchyDown(child));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapHierarchyUp(TransformNode root) {
|
||||
return wrapNodeHierarchyUp(new TransformNodeWrapper(root, true, root.getParent() != null ? 1 : 0));
|
||||
}
|
||||
public static TransformNodeWrapper wrapHierarchyUp(TransformNode root) {
|
||||
return wrapNodeHierarchyUp(new TransformNodeWrapper(root, true, root.getParent() != null ? 1 : 0));
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapNodeHierarchyUp(TransformNodeWrapper root) {
|
||||
return wrapNodeHierarchyUp(root.wrappedNode, root);
|
||||
}
|
||||
public static TransformNodeWrapper wrapNodeHierarchyUp(TransformNodeWrapper root) {
|
||||
return wrapNodeHierarchyUp(root.wrappedNode, root);
|
||||
}
|
||||
|
||||
public static TransformNodeWrapper wrapNodeHierarchyUp(TransformNode root, TransformNodeWrapper target) {
|
||||
TransformNode parent = root.getParent();
|
||||
if (parent == null) {
|
||||
return target;
|
||||
}
|
||||
public static TransformNodeWrapper wrapNodeHierarchyUp(TransformNode root, TransformNodeWrapper target) {
|
||||
TransformNode parent = root.getParent();
|
||||
if (parent == null) {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Flip the offset for these reversed nodes
|
||||
TransformNodeWrapper wrapper = new TransformNodeWrapper(parent, true, (parent.getParent() != null ? 1 : 0) + Math.max(0, parent.children.size() - 1));
|
||||
target.attachChild(wrapper);
|
||||
// Flip the offset for these reversed nodes
|
||||
TransformNodeWrapper wrapper = new TransformNodeWrapper(parent, true, (parent.getParent() != null ? 1 : 0) + Math.max(0, parent.children.size() - 1));
|
||||
target.attachChild(wrapper);
|
||||
|
||||
// Re-attach other children
|
||||
if (parent.children.size() > 1) {
|
||||
for (TransformNode child : parent.children) {
|
||||
// Skip the original node
|
||||
if (child == target.wrappedNode) {
|
||||
continue;
|
||||
}
|
||||
// Re-attach other children
|
||||
if (parent.children.size() > 1) {
|
||||
for (TransformNode child : parent.children) {
|
||||
// Skip the original node
|
||||
if (child == target.wrappedNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wrapper.attachChild(wrapHierarchyDown(child));
|
||||
}
|
||||
}
|
||||
wrapper.attachChild(wrapHierarchyDown(child));
|
||||
}
|
||||
}
|
||||
|
||||
// Continue up the hierarchy
|
||||
wrapNodeHierarchyUp(wrapper);
|
||||
// Return original node
|
||||
return target;
|
||||
}
|
||||
// Continue up the hierarchy
|
||||
wrapNodeHierarchyUp(wrapper);
|
||||
// Return original node
|
||||
return target;
|
||||
}
|
||||
|
||||
public boolean hasReversedHierarchy() {
|
||||
return reversedHierarchy;
|
||||
}
|
||||
public boolean hasReversedHierarchy() {
|
||||
return reversedHierarchy;
|
||||
}
|
||||
|
||||
public void setReversedHierarchy(boolean reversedHierarchy) {
|
||||
this.reversedHierarchy = reversedHierarchy;
|
||||
}
|
||||
public void setReversedHierarchy(boolean reversedHierarchy) {
|
||||
this.reversedHierarchy = reversedHierarchy;
|
||||
}
|
||||
|
||||
public boolean hasLocalRotation() {
|
||||
return wrappedNode.localRotation;
|
||||
}
|
||||
public boolean hasLocalRotation() {
|
||||
return wrappedNode.localRotation;
|
||||
}
|
||||
|
||||
public Quaternion calculateLocalRotation(Quaternion relativeTo, Quaternion result) {
|
||||
return calculateLocalRotationInverse(relativeTo.inverse(), result);
|
||||
}
|
||||
public Quaternion calculateLocalRotation(Quaternion relativeTo, Quaternion result) {
|
||||
return calculateLocalRotationInverse(relativeTo.inverse(), result);
|
||||
}
|
||||
|
||||
public Quaternion calculateLocalRotationInverse(Quaternion inverseRelativeTo, Quaternion result) {
|
||||
if (result == null) {
|
||||
result = new Quaternion();
|
||||
}
|
||||
public Quaternion calculateLocalRotationInverse(Quaternion inverseRelativeTo, Quaternion result) {
|
||||
if (result == null) {
|
||||
result = new Quaternion();
|
||||
}
|
||||
|
||||
return inverseRelativeTo.mult(worldTransform.getRotation(), result);
|
||||
}
|
||||
return inverseRelativeTo.mult(worldTransform.getRotation(), result);
|
||||
}
|
||||
|
||||
public void attachChild(TransformNodeWrapper node) {
|
||||
if (node.parent != null) {
|
||||
throw new IllegalArgumentException("The child node must not already have a parent");
|
||||
}
|
||||
public void attachChild(TransformNodeWrapper node) {
|
||||
if (node.parent != null) {
|
||||
throw new IllegalArgumentException("The child node must not already have a parent");
|
||||
}
|
||||
|
||||
this.children.add(node);
|
||||
node.parent = this;
|
||||
}
|
||||
this.children.add(node);
|
||||
node.parent = this;
|
||||
}
|
||||
|
||||
public TransformNodeWrapper getParent() {
|
||||
return parent;
|
||||
}
|
||||
public TransformNodeWrapper getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,28 +7,28 @@ import java.util.List;
|
||||
|
||||
public class ConnectionContext {
|
||||
|
||||
private final List<DataFeedConfigT> dataFeedConfigList = new ArrayList<>();
|
||||
private final List<DataFeedConfigT> dataFeedConfigList = new ArrayList<>();
|
||||
|
||||
// I did it in a separate array because it was more convenient than making a parent object of the DataFeedConfigT
|
||||
// idk if it should be a concern or not, i think it is fine tbh
|
||||
// Futurabeast
|
||||
private final List<Long> dataFeedTimers = new ArrayList<>();
|
||||
// I did it in a separate array because it was more convenient than making a parent object of the DataFeedConfigT
|
||||
// idk if it should be a concern or not, i think it is fine tbh
|
||||
// Futurabeast
|
||||
private final List<Long> dataFeedTimers = new ArrayList<>();
|
||||
|
||||
private boolean useSerial = false;
|
||||
private boolean useSerial = false;
|
||||
|
||||
public List<DataFeedConfigT> getDataFeedConfigList() {
|
||||
return dataFeedConfigList;
|
||||
}
|
||||
public List<DataFeedConfigT> getDataFeedConfigList() {
|
||||
return dataFeedConfigList;
|
||||
}
|
||||
|
||||
public List<Long> getDataFeedTimers() {
|
||||
return dataFeedTimers;
|
||||
}
|
||||
public List<Long> getDataFeedTimers() {
|
||||
return dataFeedTimers;
|
||||
}
|
||||
|
||||
public boolean useSerial() {
|
||||
return useSerial;
|
||||
}
|
||||
public boolean useSerial() {
|
||||
return useSerial;
|
||||
}
|
||||
|
||||
public void setUseSerial(boolean useSerial) {
|
||||
this.useSerial = useSerial;
|
||||
}
|
||||
public void setUseSerial(boolean useSerial) {
|
||||
this.useSerial = useSerial;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,178 +25,178 @@ import java.util.List;
|
||||
|
||||
public class DataFeedBuilder {
|
||||
|
||||
public static int createHardwareInfo(FlatBufferBuilder fbb, Device device) {
|
||||
IMUTracker tracker = device.sensors.get(0);
|
||||
public static int createHardwareInfo(FlatBufferBuilder fbb, Device device) {
|
||||
IMUTracker tracker = device.sensors.get(0);
|
||||
|
||||
HardwareInfo.startHardwareInfo(fbb);
|
||||
// BRUH MOMENT
|
||||
//TODO need support: HardwareInfo.addFirmwareVersion(fbb, firmwareVersionOffset);
|
||||
//TODO need support: HardwareInfo.addHardwareRevision(fbb, hardwareRevisionOffset);
|
||||
//TODO need support: HardwareInfo.addManufacturer(fbb, device.m);
|
||||
//TODO need support: HardwareInfo.addDisplayName(fbb, de);
|
||||
//TODO need support: HardwareInfo.addHardwareAddress(fbb, tracker.);
|
||||
//TODO need support: HardwareInfo.addMcuId(device);
|
||||
return HardwareInfo.endHardwareInfo(fbb);
|
||||
}
|
||||
HardwareInfo.startHardwareInfo(fbb);
|
||||
// BRUH MOMENT
|
||||
//TODO need support: HardwareInfo.addFirmwareVersion(fbb, firmwareVersionOffset);
|
||||
//TODO need support: HardwareInfo.addHardwareRevision(fbb, hardwareRevisionOffset);
|
||||
//TODO need support: HardwareInfo.addManufacturer(fbb, device.m);
|
||||
//TODO need support: HardwareInfo.addDisplayName(fbb, de);
|
||||
//TODO need support: HardwareInfo.addHardwareAddress(fbb, tracker.);
|
||||
//TODO need support: HardwareInfo.addMcuId(device);
|
||||
return HardwareInfo.endHardwareInfo(fbb);
|
||||
}
|
||||
|
||||
public static int createTrackerId(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
TrackerId.startTrackerId(fbb);
|
||||
public static int createTrackerId(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
TrackerId.startTrackerId(fbb);
|
||||
|
||||
TrackerId.addTrackerNum(fbb, tracker.getTrackerNum());
|
||||
if (tracker.getDevice() != null)
|
||||
TrackerId.addDeviceId(fbb, DeviceId.createDeviceId(fbb, tracker.getDevice().getId()));
|
||||
TrackerId.addTrackerNum(fbb, tracker.getTrackerNum());
|
||||
if (tracker.getDevice() != null)
|
||||
TrackerId.addDeviceId(fbb, DeviceId.createDeviceId(fbb, tracker.getDevice().getId()));
|
||||
|
||||
return TrackerId.endTrackerId(fbb);
|
||||
}
|
||||
return TrackerId.endTrackerId(fbb);
|
||||
}
|
||||
|
||||
public static int createTrackerInfos(FlatBufferBuilder fbb, boolean infoMask, Tracker tracker) {
|
||||
public static int createTrackerInfos(FlatBufferBuilder fbb, boolean infoMask, Tracker tracker) {
|
||||
|
||||
if (!infoMask) return -1;
|
||||
if (!infoMask) return -1;
|
||||
|
||||
TrackerInfo.startTrackerInfo(fbb);
|
||||
if (tracker.getBodyPosition() != null)
|
||||
TrackerInfo.addBodyPart(fbb, tracker.getBodyPosition().id);
|
||||
TrackerInfo.addEditable(fbb, tracker.userEditable());
|
||||
TrackerInfo.addComputed(fbb, tracker.isComputed());
|
||||
//TODO need support: TrackerInfo.addImuType(fbb, tracker.im);
|
||||
//TODO need support: TrackerInfo.addPollRate(fbb, tracker.);
|
||||
TrackerInfo.startTrackerInfo(fbb);
|
||||
if (tracker.getBodyPosition() != null)
|
||||
TrackerInfo.addBodyPart(fbb, tracker.getBodyPosition().id);
|
||||
TrackerInfo.addEditable(fbb, tracker.userEditable());
|
||||
TrackerInfo.addComputed(fbb, tracker.isComputed());
|
||||
//TODO need support: TrackerInfo.addImuType(fbb, tracker.im);
|
||||
//TODO need support: TrackerInfo.addPollRate(fbb, tracker.);
|
||||
|
||||
if (tracker instanceof IMUTracker) {
|
||||
IMUTracker imuTracker = (IMUTracker) tracker;
|
||||
if (imuTracker.getMountingRotation() != null) {
|
||||
Quaternion quaternion = imuTracker.getMountingRotation();
|
||||
TrackerInfo.addMountingOrientation(fbb,
|
||||
Quat.createQuat(fbb,
|
||||
quaternion.getX(),
|
||||
quaternion.getY(),
|
||||
quaternion.getZ(),
|
||||
quaternion.getW()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return TrackerInfo.endTrackerInfo(fbb);
|
||||
}
|
||||
if (tracker instanceof IMUTracker) {
|
||||
IMUTracker imuTracker = (IMUTracker) tracker;
|
||||
if (imuTracker.getMountingRotation() != null) {
|
||||
Quaternion quaternion = imuTracker.getMountingRotation();
|
||||
TrackerInfo.addMountingOrientation(fbb,
|
||||
Quat.createQuat(fbb,
|
||||
quaternion.getX(),
|
||||
quaternion.getY(),
|
||||
quaternion.getZ(),
|
||||
quaternion.getW()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return TrackerInfo.endTrackerInfo(fbb);
|
||||
}
|
||||
|
||||
public static int createTrackerPosition(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
Vector3f pos = new Vector3f();
|
||||
tracker.getPosition(pos);
|
||||
public static int createTrackerPosition(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
Vector3f pos = new Vector3f();
|
||||
tracker.getPosition(pos);
|
||||
|
||||
return Vec3f.createVec3f(fbb, pos.x, pos.y, pos.z);
|
||||
}
|
||||
return Vec3f.createVec3f(fbb, pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
public static int createTrackerRotation(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
Quaternion quaternion = new Quaternion();
|
||||
tracker.getRotation(quaternion);
|
||||
public static int createTrackerRotation(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
Quaternion quaternion = new Quaternion();
|
||||
tracker.getRotation(quaternion);
|
||||
|
||||
return Quat.createQuat(fbb,
|
||||
quaternion.getX(),
|
||||
quaternion.getY(),
|
||||
quaternion.getZ(),
|
||||
quaternion.getW()
|
||||
);
|
||||
}
|
||||
return Quat.createQuat(fbb,
|
||||
quaternion.getX(),
|
||||
quaternion.getY(),
|
||||
quaternion.getZ(),
|
||||
quaternion.getW()
|
||||
);
|
||||
}
|
||||
|
||||
public static int createTrackerTemperature(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
if (!(tracker instanceof IMUTracker))
|
||||
return -1;
|
||||
IMUTracker imuTracker = (IMUTracker) tracker;
|
||||
return Temperature.createTemperature(fbb, imuTracker.temperature);
|
||||
}
|
||||
public static int createTrackerTemperature(FlatBufferBuilder fbb, Tracker tracker) {
|
||||
if (!(tracker instanceof IMUTracker))
|
||||
return -1;
|
||||
IMUTracker imuTracker = (IMUTracker) tracker;
|
||||
return Temperature.createTemperature(fbb, imuTracker.temperature);
|
||||
}
|
||||
|
||||
public static int createTrackerData(FlatBufferBuilder fbb, TrackerDataMaskT mask, Tracker tracker) {
|
||||
int trackerInfosOffset = DataFeedBuilder.createTrackerInfos(fbb, mask.getInfo(), tracker);
|
||||
int trackerIdOffset = DataFeedBuilder.createTrackerId(fbb, tracker);
|
||||
public static int createTrackerData(FlatBufferBuilder fbb, TrackerDataMaskT mask, Tracker tracker) {
|
||||
int trackerInfosOffset = DataFeedBuilder.createTrackerInfos(fbb, mask.getInfo(), tracker);
|
||||
int trackerIdOffset = DataFeedBuilder.createTrackerId(fbb, tracker);
|
||||
|
||||
TrackerData.startTrackerData(fbb);
|
||||
TrackerData.startTrackerData(fbb);
|
||||
|
||||
TrackerData.addTrackerId(fbb, trackerIdOffset);
|
||||
TrackerData.addTrackerId(fbb, trackerIdOffset);
|
||||
|
||||
if (trackerInfosOffset != -1)
|
||||
TrackerData.addInfo(fbb, trackerInfosOffset);
|
||||
if (mask.getStatus())
|
||||
TrackerData.addStatus(fbb, tracker.getStatus().id + 1);
|
||||
if (mask.getPosition())
|
||||
TrackerData.addRotation(fbb, DataFeedBuilder.createTrackerPosition(fbb, tracker));
|
||||
if (mask.getRotation())
|
||||
TrackerData.addRotation(fbb, DataFeedBuilder.createTrackerRotation(fbb, tracker));
|
||||
if (mask.getTemp()) {
|
||||
int trackerTemperatureOffset = DataFeedBuilder.createTrackerTemperature(fbb, tracker);
|
||||
if (trackerTemperatureOffset != -1)
|
||||
TrackerData.addTemp(fbb, trackerTemperatureOffset);
|
||||
}
|
||||
if (trackerInfosOffset != -1)
|
||||
TrackerData.addInfo(fbb, trackerInfosOffset);
|
||||
if (mask.getStatus())
|
||||
TrackerData.addStatus(fbb, tracker.getStatus().id + 1);
|
||||
if (mask.getPosition())
|
||||
TrackerData.addRotation(fbb, DataFeedBuilder.createTrackerPosition(fbb, tracker));
|
||||
if (mask.getRotation())
|
||||
TrackerData.addRotation(fbb, DataFeedBuilder.createTrackerRotation(fbb, tracker));
|
||||
if (mask.getTemp()) {
|
||||
int trackerTemperatureOffset = DataFeedBuilder.createTrackerTemperature(fbb, tracker);
|
||||
if (trackerTemperatureOffset != -1)
|
||||
TrackerData.addTemp(fbb, trackerTemperatureOffset);
|
||||
}
|
||||
|
||||
return TrackerData.endTrackerData(fbb);
|
||||
}
|
||||
return TrackerData.endTrackerData(fbb);
|
||||
}
|
||||
|
||||
public static int createTrackersData(FlatBufferBuilder fbb, DeviceDataMaskT mask, Device device) {
|
||||
if (mask.getTrackerData() == null) return -1;
|
||||
public static int createTrackersData(FlatBufferBuilder fbb, DeviceDataMaskT mask, Device device) {
|
||||
if (mask.getTrackerData() == null) return -1;
|
||||
|
||||
int[] trackersOffset = new int[device.sensors.size()];
|
||||
int[] trackersOffset = new int[device.sensors.size()];
|
||||
|
||||
device.sensors.forEach((key, value) -> {
|
||||
trackersOffset[key] = DataFeedBuilder.createTrackerData(fbb, mask.getTrackerData(), value);
|
||||
});
|
||||
device.sensors.forEach((key, value) -> {
|
||||
trackersOffset[key] = DataFeedBuilder.createTrackerData(fbb, mask.getTrackerData(), value);
|
||||
});
|
||||
|
||||
return DeviceData.createTrackersVector(fbb, trackersOffset);
|
||||
}
|
||||
return DeviceData.createTrackersVector(fbb, trackersOffset);
|
||||
}
|
||||
|
||||
public static int createDeviceData(FlatBufferBuilder fbb, int id, DeviceDataMaskT mask, Device device) {
|
||||
if (!mask.getDeviceData()) return -1;
|
||||
public static int createDeviceData(FlatBufferBuilder fbb, int id, DeviceDataMaskT mask, Device device) {
|
||||
if (!mask.getDeviceData()) return -1;
|
||||
|
||||
IMUTracker tracker = device.sensors.get(0);
|
||||
IMUTracker tracker = device.sensors.get(0);
|
||||
|
||||
if (tracker == null) return -1;
|
||||
if (tracker == null) return -1;
|
||||
|
||||
int hardwareDataOffset = HardwareStatus.createHardwareStatus(
|
||||
fbb,
|
||||
tracker.getStatus().id,
|
||||
(int) tracker.getTPS(),
|
||||
tracker.ping,
|
||||
(short) tracker.signalStrength,
|
||||
tracker.temperature,
|
||||
tracker.getBatteryVoltage(),
|
||||
(int) tracker.getBatteryLevel(),
|
||||
-1
|
||||
);
|
||||
int hardwareInfoOffset = DataFeedBuilder.createHardwareInfo(fbb, device);
|
||||
int trackersOffset = DataFeedBuilder.createTrackersData(fbb, mask, device);
|
||||
int hardwareDataOffset = HardwareStatus.createHardwareStatus(
|
||||
fbb,
|
||||
tracker.getStatus().id,
|
||||
(int) tracker.getTPS(),
|
||||
tracker.ping,
|
||||
(short) tracker.signalStrength,
|
||||
tracker.temperature,
|
||||
tracker.getBatteryVoltage(),
|
||||
(int) tracker.getBatteryLevel(),
|
||||
-1
|
||||
);
|
||||
int hardwareInfoOffset = DataFeedBuilder.createHardwareInfo(fbb, device);
|
||||
int trackersOffset = DataFeedBuilder.createTrackersData(fbb, mask, device);
|
||||
|
||||
DeviceData.startDeviceData(fbb);
|
||||
//TODO need support: DeviceData.addCustomName(fbb, nameOffset);
|
||||
DeviceData.addId(fbb, DeviceId.createDeviceId(fbb, id));
|
||||
DeviceData.addHardwareStatus(fbb, hardwareDataOffset);
|
||||
DeviceData.addHardwareInfo(fbb, hardwareInfoOffset);
|
||||
DeviceData.addTrackers(fbb, trackersOffset);
|
||||
DeviceData.startDeviceData(fbb);
|
||||
//TODO need support: DeviceData.addCustomName(fbb, nameOffset);
|
||||
DeviceData.addId(fbb, DeviceId.createDeviceId(fbb, id));
|
||||
DeviceData.addHardwareStatus(fbb, hardwareDataOffset);
|
||||
DeviceData.addHardwareInfo(fbb, hardwareInfoOffset);
|
||||
DeviceData.addTrackers(fbb, trackersOffset);
|
||||
|
||||
return DeviceData.endDeviceData(fbb);
|
||||
}
|
||||
return DeviceData.endDeviceData(fbb);
|
||||
}
|
||||
|
||||
public static int createSyntheticTrackersData(FlatBufferBuilder fbb, TrackerDataMaskT trackerDataMaskT, List<Tracker> trackers) {
|
||||
if (trackerDataMaskT == null) return -1;
|
||||
public static int createSyntheticTrackersData(FlatBufferBuilder fbb, TrackerDataMaskT trackerDataMaskT, List<Tracker> trackers) {
|
||||
if (trackerDataMaskT == null) return -1;
|
||||
|
||||
List<Integer> trackerOffsets = new ArrayList<>();
|
||||
List<Integer> trackerOffsets = new ArrayList<>();
|
||||
|
||||
trackers.stream().filter(Tracker::isComputed).forEach((tracker) -> {
|
||||
trackerOffsets.add(DataFeedBuilder.createTrackerData(fbb, trackerDataMaskT, tracker));
|
||||
});
|
||||
trackers.stream().filter(Tracker::isComputed).forEach((tracker) -> {
|
||||
trackerOffsets.add(DataFeedBuilder.createTrackerData(fbb, trackerDataMaskT, tracker));
|
||||
});
|
||||
|
||||
DataFeedUpdate.startSyntheticTrackersVector(fbb, trackerOffsets.size());
|
||||
trackerOffsets.forEach((tracker -> {
|
||||
DataFeedUpdate.addSyntheticTrackers(fbb, tracker);
|
||||
}));
|
||||
return fbb.endVector();
|
||||
}
|
||||
DataFeedUpdate.startSyntheticTrackersVector(fbb, trackerOffsets.size());
|
||||
trackerOffsets.forEach((tracker -> {
|
||||
DataFeedUpdate.addSyntheticTrackers(fbb, tracker);
|
||||
}));
|
||||
return fbb.endVector();
|
||||
}
|
||||
|
||||
public static int createDevicesData(FlatBufferBuilder fbb, DeviceDataMaskT deviceDataMaskT, List<Device> devices) {
|
||||
if (deviceDataMaskT == null) return -1;
|
||||
public static int createDevicesData(FlatBufferBuilder fbb, DeviceDataMaskT deviceDataMaskT, List<Device> devices) {
|
||||
if (deviceDataMaskT == null) return -1;
|
||||
|
||||
int[] devicesDataOffsets = new int[devices.size()];
|
||||
for (int i = 0; i < devices.size(); i++) {
|
||||
Device device = devices.get(i);
|
||||
devicesDataOffsets[i] = DataFeedBuilder.createDeviceData(fbb, i, deviceDataMaskT, device);
|
||||
}
|
||||
int[] devicesDataOffsets = new int[devices.size()];
|
||||
for (int i = 0; i < devices.size(); i++) {
|
||||
Device device = devices.get(i);
|
||||
devicesDataOffsets[i] = DataFeedBuilder.createDeviceData(fbb, i, deviceDataMaskT, device);
|
||||
}
|
||||
|
||||
return DataFeedUpdate.createDevicesVector(fbb, devicesDataOffsets);
|
||||
}
|
||||
return DataFeedUpdate.createDevicesVector(fbb, devicesDataOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,113 +9,113 @@ import java.util.function.BiConsumer;
|
||||
|
||||
public class DataFeedHandler extends ProtocolHandler<DataFeedMessageHeader> {
|
||||
|
||||
private final ProtocolAPI api;
|
||||
private final ProtocolAPI api;
|
||||
|
||||
public DataFeedHandler(ProtocolAPI api) {
|
||||
this.api = api;
|
||||
public DataFeedHandler(ProtocolAPI api) {
|
||||
this.api = api;
|
||||
|
||||
registerPacketListener(DataFeedMessage.StartDataFeed, this::onStartDataFeed);
|
||||
registerPacketListener(DataFeedMessage.PollDataFeed, this::onPollDataFeedRequest);
|
||||
registerPacketListener(DataFeedMessage.StartDataFeed, this::onStartDataFeed);
|
||||
registerPacketListener(DataFeedMessage.PollDataFeed, this::onPollDataFeedRequest);
|
||||
|
||||
this.api.server.addOnTick(this::sendDataFeedUpdate);
|
||||
}
|
||||
this.api.server.addOnTick(this::sendDataFeedUpdate);
|
||||
}
|
||||
|
||||
private void onStartDataFeed(GenericConnection conn, DataFeedMessageHeader header) {
|
||||
StartDataFeed req = (StartDataFeed) header.message(new StartDataFeed());
|
||||
if (req == null) return;
|
||||
int dataFeeds = req.dataFeedsLength();
|
||||
private void onStartDataFeed(GenericConnection conn, DataFeedMessageHeader header) {
|
||||
StartDataFeed req = (StartDataFeed) header.message(new StartDataFeed());
|
||||
if (req == null) return;
|
||||
int dataFeeds = req.dataFeedsLength();
|
||||
|
||||
conn.getContext().getDataFeedConfigList().clear();
|
||||
for (int i = 0; i < dataFeeds; i++) {
|
||||
// Using the object api here because we need to copy from the buffer anyway so let's do it from here and send the reference to an arraylist
|
||||
DataFeedConfigT config = req.dataFeeds(i).unpack();
|
||||
conn.getContext().getDataFeedConfigList().add(config);
|
||||
conn.getContext().getDataFeedTimers().add(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
conn.getContext().getDataFeedConfigList().clear();
|
||||
for (int i = 0; i < dataFeeds; i++) {
|
||||
// Using the object api here because we need to copy from the buffer anyway so let's do it from here and send the reference to an arraylist
|
||||
DataFeedConfigT config = req.dataFeeds(i).unpack();
|
||||
conn.getContext().getDataFeedConfigList().add(config);
|
||||
conn.getContext().getDataFeedTimers().add(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
private void onPollDataFeedRequest(GenericConnection conn, DataFeedMessageHeader messageHeader) {
|
||||
private void onPollDataFeedRequest(GenericConnection conn, DataFeedMessageHeader messageHeader) {
|
||||
|
||||
PollDataFeed req = (PollDataFeed) messageHeader.message(new PollDataFeed());
|
||||
if (req == null) return;
|
||||
PollDataFeed req = (PollDataFeed) messageHeader.message(new PollDataFeed());
|
||||
if (req == null) return;
|
||||
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
|
||||
int messageOffset = this.buildDatafeed(fbb, req.config().unpack());
|
||||
int messageOffset = this.buildDatafeed(fbb, req.config().unpack());
|
||||
|
||||
DataFeedMessageHeader.startDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.addMessage(fbb, messageOffset);
|
||||
DataFeedMessageHeader.addMessageType(fbb, DataFeedMessage.DataFeedUpdate);
|
||||
int headerOffset = DataFeedMessageHeader.endDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.startDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.addMessage(fbb, messageOffset);
|
||||
DataFeedMessageHeader.addMessageType(fbb, DataFeedMessage.DataFeedUpdate);
|
||||
int headerOffset = DataFeedMessageHeader.endDataFeedMessageHeader(fbb);
|
||||
|
||||
MessageBundle.startDataFeedMsgsVector(fbb, 1);
|
||||
MessageBundle.addDataFeedMsgs(fbb, headerOffset);
|
||||
int datafeedMessagesOffset = fbb.endVector();
|
||||
MessageBundle.startDataFeedMsgsVector(fbb, 1);
|
||||
MessageBundle.addDataFeedMsgs(fbb, headerOffset);
|
||||
int datafeedMessagesOffset = fbb.endVector();
|
||||
|
||||
int packet = createMessage(fbb, datafeedMessagesOffset, -1);
|
||||
fbb.finish(packet);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
int packet = createMessage(fbb, datafeedMessagesOffset, -1);
|
||||
fbb.finish(packet);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public int buildDatafeed(FlatBufferBuilder fbb, DataFeedConfigT config) {
|
||||
int devicesOffset = DataFeedBuilder.createDevicesData(fbb, config.getDataMask(), this.api.server.getTrackersServer().getConnections());
|
||||
int trackersOffset = DataFeedBuilder.createSyntheticTrackersData(fbb, config.getSyntheticTrackersMask(), this.api.server.getAllTrackers());
|
||||
public int buildDatafeed(FlatBufferBuilder fbb, DataFeedConfigT config) {
|
||||
int devicesOffset = DataFeedBuilder.createDevicesData(fbb, config.getDataMask(), this.api.server.getTrackersServer().getConnections());
|
||||
int trackersOffset = DataFeedBuilder.createSyntheticTrackersData(fbb, config.getSyntheticTrackersMask(), this.api.server.getAllTrackers());
|
||||
|
||||
return DataFeedUpdate.createDataFeedUpdate(fbb, devicesOffset, trackersOffset);
|
||||
}
|
||||
return DataFeedUpdate.createDataFeedUpdate(fbb, devicesOffset, trackersOffset);
|
||||
}
|
||||
|
||||
public void sendDataFeedUpdate() {
|
||||
long currTime = System.currentTimeMillis();
|
||||
public void sendDataFeedUpdate() {
|
||||
long currTime = System.currentTimeMillis();
|
||||
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections().values().forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = null;
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections().values().forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = null;
|
||||
|
||||
int configsCount = conn.getContext().getDataFeedConfigList().size();
|
||||
int configsCount = conn.getContext().getDataFeedConfigList().size();
|
||||
|
||||
int[] data = new int[configsCount];
|
||||
int[] data = new int[configsCount];
|
||||
|
||||
for (int index = 0; index < configsCount; index++) {
|
||||
Long lastTimeSent = conn.getContext().getDataFeedTimers().get(index);
|
||||
DataFeedConfigT configT = conn.getContext().getDataFeedConfigList().get(index);
|
||||
if (currTime - lastTimeSent > configT.getMinimumTimeSinceLast()) {
|
||||
if (fbb == null) {
|
||||
// That way we create a buffer only when needed
|
||||
fbb = new FlatBufferBuilder(300);
|
||||
}
|
||||
for (int index = 0; index < configsCount; index++) {
|
||||
Long lastTimeSent = conn.getContext().getDataFeedTimers().get(index);
|
||||
DataFeedConfigT configT = conn.getContext().getDataFeedConfigList().get(index);
|
||||
if (currTime - lastTimeSent > configT.getMinimumTimeSinceLast()) {
|
||||
if (fbb == null) {
|
||||
// That way we create a buffer only when needed
|
||||
fbb = new FlatBufferBuilder(300);
|
||||
}
|
||||
|
||||
int messageOffset = this.buildDatafeed(fbb, configT);
|
||||
int messageOffset = this.buildDatafeed(fbb, configT);
|
||||
|
||||
DataFeedMessageHeader.startDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.addMessage(fbb, messageOffset);
|
||||
DataFeedMessageHeader.addMessageType(fbb, DataFeedMessage.DataFeedUpdate);
|
||||
data[index] = DataFeedMessageHeader.endDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.startDataFeedMessageHeader(fbb);
|
||||
DataFeedMessageHeader.addMessage(fbb, messageOffset);
|
||||
DataFeedMessageHeader.addMessageType(fbb, DataFeedMessage.DataFeedUpdate);
|
||||
data[index] = DataFeedMessageHeader.endDataFeedMessageHeader(fbb);
|
||||
|
||||
conn.getContext().getDataFeedTimers().set(index, currTime);
|
||||
}
|
||||
}
|
||||
conn.getContext().getDataFeedTimers().set(index, currTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (fbb != null) {
|
||||
int messages = MessageBundle.createRpcMsgsVector(fbb, data);
|
||||
int packet = createMessage(fbb, messages, -1);
|
||||
fbb.finish(packet);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (fbb != null) {
|
||||
int messages = MessageBundle.createRpcMsgsVector(fbb, data);
|
||||
int packet = createMessage(fbb, messages, -1);
|
||||
fbb.finish(packet);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(GenericConnection conn, DataFeedMessageHeader message) {
|
||||
BiConsumer<GenericConnection, DataFeedMessageHeader> consumer = this.handlers[message.messageType()];
|
||||
if (consumer != null)
|
||||
consumer.accept(conn, message);
|
||||
else
|
||||
LogManager.log.info("[ProtocolAPI] Unhandled Datafeed packet received id: " + message.messageType());
|
||||
}
|
||||
@Override
|
||||
public void onMessage(GenericConnection conn, DataFeedMessageHeader message) {
|
||||
BiConsumer<GenericConnection, DataFeedMessageHeader> consumer = this.handlers[message.messageType()];
|
||||
if (consumer != null)
|
||||
consumer.accept(conn, message);
|
||||
else
|
||||
LogManager.log.info("[ProtocolAPI] Unhandled Datafeed packet received id: " + message.messageType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int messagesCount() {
|
||||
return DataFeedMessage.names.length;
|
||||
}
|
||||
@Override
|
||||
public int messagesCount() {
|
||||
return DataFeedMessage.names.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import java.util.UUID;
|
||||
|
||||
public interface GenericConnection {
|
||||
|
||||
UUID getConnectionId();
|
||||
UUID getConnectionId();
|
||||
|
||||
ConnectionContext getContext();
|
||||
ConnectionContext getContext();
|
||||
|
||||
void send(ByteBuffer bytes);
|
||||
void send(ByteBuffer bytes);
|
||||
}
|
||||
|
||||
@@ -11,41 +11,41 @@ import java.util.List;
|
||||
|
||||
public class ProtocolAPI {
|
||||
|
||||
public final VRServer server;
|
||||
public final RPCHandler rpcHandler;
|
||||
public final DataFeedHandler dataFeedHandler;
|
||||
public final VRServer server;
|
||||
public final RPCHandler rpcHandler;
|
||||
public final DataFeedHandler dataFeedHandler;
|
||||
|
||||
private final List<ProtocolAPIServer> servers = new ArrayList<>();
|
||||
private final List<ProtocolAPIServer> servers = new ArrayList<>();
|
||||
|
||||
public ProtocolAPI(VRServer server) {
|
||||
this.server = server;
|
||||
this.rpcHandler = new RPCHandler(this);
|
||||
this.dataFeedHandler = new DataFeedHandler(this);
|
||||
}
|
||||
public ProtocolAPI(VRServer server) {
|
||||
this.server = server;
|
||||
this.rpcHandler = new RPCHandler(this);
|
||||
this.dataFeedHandler = new DataFeedHandler(this);
|
||||
}
|
||||
|
||||
public void onMessage(GenericConnection conn, ByteBuffer message) {
|
||||
MessageBundle messageBundle = MessageBundle.getRootAsMessageBundle(message);
|
||||
public void onMessage(GenericConnection conn, ByteBuffer message) {
|
||||
MessageBundle messageBundle = MessageBundle.getRootAsMessageBundle(message);
|
||||
|
||||
for (int index = 0; index < messageBundle.dataFeedMsgsLength(); index++) {
|
||||
DataFeedMessageHeader header = messageBundle.dataFeedMsgsVector().get(index);
|
||||
this.dataFeedHandler.onMessage(conn, header);
|
||||
}
|
||||
for (int index = 0; index < messageBundle.dataFeedMsgsLength(); index++) {
|
||||
DataFeedMessageHeader header = messageBundle.dataFeedMsgsVector().get(index);
|
||||
this.dataFeedHandler.onMessage(conn, header);
|
||||
}
|
||||
|
||||
for (int index = 0; index < messageBundle.rpcMsgsLength(); index++) {
|
||||
RpcMessageHeader header = messageBundle.rpcMsgsVector().get(index);
|
||||
this.rpcHandler.onMessage(conn, header);
|
||||
}
|
||||
}
|
||||
for (int index = 0; index < messageBundle.rpcMsgsLength(); index++) {
|
||||
RpcMessageHeader header = messageBundle.rpcMsgsVector().get(index);
|
||||
this.rpcHandler.onMessage(conn, header);
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProtocolAPIServer> getAPIServers() {
|
||||
return servers;
|
||||
}
|
||||
public List<ProtocolAPIServer> getAPIServers() {
|
||||
return servers;
|
||||
}
|
||||
|
||||
public void registerAPIServer(ProtocolAPIServer server) {
|
||||
this.servers.add(server);
|
||||
}
|
||||
public void registerAPIServer(ProtocolAPIServer server) {
|
||||
this.servers.add(server);
|
||||
}
|
||||
|
||||
public void removeAPIServer(ProtocolAPIServer server) {
|
||||
this.servers.remove(server);
|
||||
}
|
||||
public void removeAPIServer(ProtocolAPIServer server) {
|
||||
this.servers.remove(server);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ import java.util.Map;
|
||||
|
||||
public interface ProtocolAPIServer {
|
||||
|
||||
Map<Integer, GenericConnection> getAPIConnections();
|
||||
Map<Integer, GenericConnection> getAPIConnections();
|
||||
}
|
||||
|
||||
@@ -7,29 +7,29 @@ import java.util.function.BiConsumer;
|
||||
|
||||
public abstract class ProtocolHandler<H> {
|
||||
|
||||
public final BiConsumer<GenericConnection, H>[] handlers;
|
||||
public final BiConsumer<GenericConnection, H>[] handlers;
|
||||
|
||||
public ProtocolHandler() {
|
||||
this.handlers = new BiConsumer[this.messagesCount()];
|
||||
}
|
||||
public ProtocolHandler() {
|
||||
this.handlers = new BiConsumer[this.messagesCount()];
|
||||
}
|
||||
|
||||
public abstract void onMessage(GenericConnection conn, H message);
|
||||
public abstract void onMessage(GenericConnection conn, H message);
|
||||
|
||||
public abstract int messagesCount();
|
||||
public abstract int messagesCount();
|
||||
|
||||
public void registerPacketListener(byte packetType, BiConsumer<GenericConnection, H> consumer) {
|
||||
if (this.handlers[packetType] != null)
|
||||
this.handlers[packetType] = this.handlers[packetType].andThen(consumer);
|
||||
else
|
||||
this.handlers[packetType] = consumer;
|
||||
}
|
||||
public void registerPacketListener(byte packetType, BiConsumer<GenericConnection, H> consumer) {
|
||||
if (this.handlers[packetType] != null)
|
||||
this.handlers[packetType] = this.handlers[packetType].andThen(consumer);
|
||||
else
|
||||
this.handlers[packetType] = consumer;
|
||||
}
|
||||
|
||||
public int createMessage(FlatBufferBuilder fbb, int datafeedMessagesOffset, int rpcMsgsOffset) {
|
||||
MessageBundle.startMessageBundle(fbb);
|
||||
if (datafeedMessagesOffset > -1)
|
||||
MessageBundle.addDataFeedMsgs(fbb, datafeedMessagesOffset);
|
||||
if (rpcMsgsOffset > -1)
|
||||
MessageBundle.addRpcMsgs(fbb, rpcMsgsOffset);
|
||||
return MessageBundle.endMessageBundle(fbb);
|
||||
}
|
||||
public int createMessage(FlatBufferBuilder fbb, int datafeedMessagesOffset, int rpcMsgsOffset) {
|
||||
MessageBundle.startMessageBundle(fbb);
|
||||
if (datafeedMessagesOffset > -1)
|
||||
MessageBundle.addDataFeedMsgs(fbb, datafeedMessagesOffset);
|
||||
if (rpcMsgsOffset > -1)
|
||||
MessageBundle.addRpcMsgs(fbb, rpcMsgsOffset);
|
||||
return MessageBundle.endMessageBundle(fbb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,16 @@ import solarxr_protocol.rpc.SkeletonPart;
|
||||
|
||||
public class RPCBuilder {
|
||||
|
||||
public static int createSkeletonConfig(FlatBufferBuilder fbb, HumanPoseProcessor humanPoseProcessor) {
|
||||
int[] partsOffsets = new int[SkeletonConfigValue.values().length];
|
||||
public static int createSkeletonConfig(FlatBufferBuilder fbb, HumanPoseProcessor humanPoseProcessor) {
|
||||
int[] partsOffsets = new int[SkeletonConfigValue.values().length];
|
||||
|
||||
for (int index = 0; index < SkeletonConfigValue.values().length; index++) {
|
||||
SkeletonConfigValue val = SkeletonConfigValue.values[index];
|
||||
int part = SkeletonPart.createSkeletonPart(fbb, val.id, humanPoseProcessor.getSkeletonConfig(val));
|
||||
partsOffsets[index] = part;
|
||||
}
|
||||
for (int index = 0; index < SkeletonConfigValue.values().length; index++) {
|
||||
SkeletonConfigValue val = SkeletonConfigValue.values[index];
|
||||
int part = SkeletonPart.createSkeletonPart(fbb, val.id, humanPoseProcessor.getSkeletonConfig(val));
|
||||
partsOffsets[index] = part;
|
||||
}
|
||||
|
||||
int parts = SkeletonConfigResponse.createSkeletonPartsVector(fbb, partsOffsets);
|
||||
return SkeletonConfigResponse.createSkeletonConfigResponse(fbb, parts);
|
||||
}
|
||||
int parts = SkeletonConfigResponse.createSkeletonPartsVector(fbb, partsOffsets);
|
||||
return SkeletonConfigResponse.createSkeletonConfigResponse(fbb, parts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,308 +16,308 @@ import java.util.function.BiConsumer;
|
||||
|
||||
public class RPCHandler extends ProtocolHandler<RpcMessageHeader> implements SerialListener {
|
||||
|
||||
private final ProtocolAPI api;
|
||||
private final ProtocolAPI api;
|
||||
|
||||
private long currTransactionId = 0;
|
||||
private long currTransactionId = 0;
|
||||
|
||||
public RPCHandler(ProtocolAPI api) {
|
||||
super();
|
||||
this.api = api;
|
||||
public RPCHandler(ProtocolAPI api) {
|
||||
super();
|
||||
this.api = api;
|
||||
|
||||
registerPacketListener(RpcMessage.ResetRequest, this::onResetRequest);
|
||||
registerPacketListener(RpcMessage.AssignTrackerRequest, this::onAssignTrackerRequest);
|
||||
registerPacketListener(RpcMessage.SettingsRequest, this::onSettingsRequest);
|
||||
registerPacketListener(RpcMessage.ChangeSettingsRequest, this::onChangeSettingsRequest);
|
||||
registerPacketListener(RpcMessage.ResetRequest, this::onResetRequest);
|
||||
registerPacketListener(RpcMessage.AssignTrackerRequest, this::onAssignTrackerRequest);
|
||||
registerPacketListener(RpcMessage.SettingsRequest, this::onSettingsRequest);
|
||||
registerPacketListener(RpcMessage.ChangeSettingsRequest, this::onChangeSettingsRequest);
|
||||
|
||||
registerPacketListener(RpcMessage.RecordBVHRequest, this::onRecordBVHRequest);
|
||||
registerPacketListener(RpcMessage.RecordBVHRequest, this::onRecordBVHRequest);
|
||||
|
||||
registerPacketListener(RpcMessage.SkeletonResetAllRequest, this::onSkeletonResetAllRequest);
|
||||
registerPacketListener(RpcMessage.SkeletonConfigRequest, this::onSkeletonConfigRequest);
|
||||
registerPacketListener(RpcMessage.ChangeSkeletonConfigRequest, this::onChangeSkeletonConfigRequest);
|
||||
registerPacketListener(RpcMessage.SkeletonResetAllRequest, this::onSkeletonResetAllRequest);
|
||||
registerPacketListener(RpcMessage.SkeletonConfigRequest, this::onSkeletonConfigRequest);
|
||||
registerPacketListener(RpcMessage.ChangeSkeletonConfigRequest, this::onChangeSkeletonConfigRequest);
|
||||
|
||||
registerPacketListener(RpcMessage.SetWifiRequest, this::onSetWifiRequest);
|
||||
registerPacketListener(RpcMessage.OpenSerialRequest, this::onOpenSerialRequest);
|
||||
registerPacketListener(RpcMessage.CloseSerialRequest, this::onCloseSerialRequest);
|
||||
registerPacketListener(RpcMessage.SetWifiRequest, this::onSetWifiRequest);
|
||||
registerPacketListener(RpcMessage.OpenSerialRequest, this::onOpenSerialRequest);
|
||||
registerPacketListener(RpcMessage.CloseSerialRequest, this::onCloseSerialRequest);
|
||||
|
||||
this.api.server.getSerialHandler().addListener(this);
|
||||
}
|
||||
this.api.server.getSerialHandler().addListener(this);
|
||||
}
|
||||
|
||||
public void onSetWifiRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SetWifiRequest req = (SetWifiRequest) messageHeader.message(new SetWifiRequest());
|
||||
if (req == null) return;
|
||||
public void onSetWifiRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SetWifiRequest req = (SetWifiRequest) messageHeader.message(new SetWifiRequest());
|
||||
if (req == null) return;
|
||||
|
||||
if (req.password() == null || req.ssid() == null || !this.api.server.getSerialHandler().isConnected())
|
||||
return;
|
||||
this.api.server.getSerialHandler().setWifi(req.ssid(), req.password());
|
||||
}
|
||||
if (req.password() == null || req.ssid() == null || !this.api.server.getSerialHandler().isConnected())
|
||||
return;
|
||||
this.api.server.getSerialHandler().setWifi(req.ssid(), req.password());
|
||||
}
|
||||
|
||||
public void onOpenSerialRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
OpenSerialRequest req = (OpenSerialRequest) messageHeader.message(new OpenSerialRequest());
|
||||
if (req == null) return;
|
||||
public void onOpenSerialRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
OpenSerialRequest req = (OpenSerialRequest) messageHeader.message(new OpenSerialRequest());
|
||||
if (req == null) return;
|
||||
|
||||
conn.getContext().setUseSerial(true);
|
||||
conn.getContext().setUseSerial(true);
|
||||
|
||||
this.api.server.getSerialHandler().openSerial();
|
||||
this.api.server.getSerialHandler().openSerial();
|
||||
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, !this.api.server.getSerialHandler().isConnected());
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, !this.api.server.getSerialHandler().isConnected());
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onCloseSerialRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
CloseSerialRequest req = (CloseSerialRequest) messageHeader.message(new CloseSerialRequest());
|
||||
if (req == null) return;
|
||||
public void onCloseSerialRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
CloseSerialRequest req = (CloseSerialRequest) messageHeader.message(new CloseSerialRequest());
|
||||
if (req == null) return;
|
||||
|
||||
conn.getContext().setUseSerial(false);
|
||||
conn.getContext().setUseSerial(false);
|
||||
|
||||
this.api.server.getSerialHandler().closeSerial();
|
||||
this.api.server.getSerialHandler().closeSerial();
|
||||
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, !this.api.server.getSerialHandler().isConnected());
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, !this.api.server.getSerialHandler().isConnected());
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onSkeletonResetAllRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SkeletonResetAllRequest req = (SkeletonResetAllRequest) messageHeader.message(new SkeletonResetAllRequest());
|
||||
if (req == null) return;
|
||||
public void onSkeletonResetAllRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SkeletonResetAllRequest req = (SkeletonResetAllRequest) messageHeader.message(new SkeletonResetAllRequest());
|
||||
if (req == null) return;
|
||||
|
||||
this.api.server.humanPoseProcessor.getSkeletonConfig().resetConfigs();
|
||||
this.api.server.saveConfig();
|
||||
this.api.server.humanPoseProcessor.getSkeletonConfig().resetConfigs();
|
||||
this.api.server.saveConfig();
|
||||
|
||||
// might not be a good idea maybe let the client ask again
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
int config = RPCBuilder.createSkeletonConfig(fbb, this.api.server.humanPoseProcessor);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SkeletonConfigResponse, config);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
// might not be a good idea maybe let the client ask again
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
int config = RPCBuilder.createSkeletonConfig(fbb, this.api.server.humanPoseProcessor);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SkeletonConfigResponse, config);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onSkeletonConfigRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SkeletonConfigRequest req = (SkeletonConfigRequest) messageHeader.message(new SkeletonConfigRequest());
|
||||
if (req == null) return;
|
||||
public void onSkeletonConfigRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
SkeletonConfigRequest req = (SkeletonConfigRequest) messageHeader.message(new SkeletonConfigRequest());
|
||||
if (req == null) return;
|
||||
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
int config = RPCBuilder.createSkeletonConfig(fbb, this.api.server.humanPoseProcessor);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SkeletonConfigResponse, config);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(300);
|
||||
int config = RPCBuilder.createSkeletonConfig(fbb, this.api.server.humanPoseProcessor);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SkeletonConfigResponse, config);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onChangeSkeletonConfigRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
ChangeSkeletonConfigRequest req = (ChangeSkeletonConfigRequest) messageHeader.message(new ChangeSkeletonConfigRequest());
|
||||
if (req == null) return;
|
||||
public void onChangeSkeletonConfigRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
ChangeSkeletonConfigRequest req = (ChangeSkeletonConfigRequest) messageHeader.message(new ChangeSkeletonConfigRequest());
|
||||
if (req == null) return;
|
||||
|
||||
SkeletonConfigValue joint = SkeletonConfigValue.getById(req.bone());
|
||||
SkeletonConfigValue joint = SkeletonConfigValue.getById(req.bone());
|
||||
|
||||
this.api.server.humanPoseProcessor.setSkeletonConfig(joint, req.value());
|
||||
this.api.server.humanPoseProcessor.getSkeletonConfig().saveToConfig(this.api.server.config);
|
||||
this.api.server.saveConfig();
|
||||
}
|
||||
this.api.server.humanPoseProcessor.setSkeletonConfig(joint, req.value());
|
||||
this.api.server.humanPoseProcessor.getSkeletonConfig().saveToConfig(this.api.server.config);
|
||||
this.api.server.saveConfig();
|
||||
}
|
||||
|
||||
public void onRecordBVHRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
RecordBVHRequest req = (RecordBVHRequest) messageHeader.message(new RecordBVHRequest());
|
||||
if (req == null) return;
|
||||
public void onRecordBVHRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
RecordBVHRequest req = (RecordBVHRequest) messageHeader.message(new RecordBVHRequest());
|
||||
if (req == null) return;
|
||||
|
||||
if (req.stop()) {
|
||||
if (this.api.server.getBvhRecorder().isRecording())
|
||||
this.api.server.getBvhRecorder().endRecording();
|
||||
} else {
|
||||
if (!this.api.server.getBvhRecorder().isRecording())
|
||||
this.api.server.getBvhRecorder().startRecording();
|
||||
}
|
||||
if (req.stop()) {
|
||||
if (this.api.server.getBvhRecorder().isRecording())
|
||||
this.api.server.getBvhRecorder().endRecording();
|
||||
} else {
|
||||
if (!this.api.server.getBvhRecorder().isRecording())
|
||||
this.api.server.getBvhRecorder().startRecording();
|
||||
}
|
||||
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(40);
|
||||
int status = RecordBVHStatus.createRecordBVHStatus(fbb, this.api.server.getBvhRecorder().isRecording());
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.RecordBVHStatus, status);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(40);
|
||||
int status = RecordBVHStatus.createRecordBVHStatus(fbb, this.api.server.getBvhRecorder().isRecording());
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.RecordBVHStatus, status);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onResetRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
ResetRequest req = (ResetRequest) messageHeader.message(new ResetRequest());
|
||||
if (req == null) return;
|
||||
public void onResetRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
ResetRequest req = (ResetRequest) messageHeader.message(new ResetRequest());
|
||||
if (req == null) return;
|
||||
|
||||
if (req.resetType() == ResetType.Quick)
|
||||
this.api.server.resetTrackersYaw();
|
||||
if (req.resetType() == ResetType.Full)
|
||||
this.api.server.resetTrackers();
|
||||
LogManager.log.severe("[WebSocketAPI] Reset performed");
|
||||
}
|
||||
if (req.resetType() == ResetType.Quick)
|
||||
this.api.server.resetTrackersYaw();
|
||||
if (req.resetType() == ResetType.Full)
|
||||
this.api.server.resetTrackers();
|
||||
LogManager.log.severe("[WebSocketAPI] Reset performed");
|
||||
}
|
||||
|
||||
public void onAssignTrackerRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
AssignTrackerRequest req = (AssignTrackerRequest) messageHeader.message(new AssignTrackerRequest());
|
||||
if (req == null) return;
|
||||
public void onAssignTrackerRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
AssignTrackerRequest req = (AssignTrackerRequest) messageHeader.message(new AssignTrackerRequest());
|
||||
if (req == null) return;
|
||||
|
||||
Tracker tracker = this.api.server.getTrackerById(req.trackerId().unpack());
|
||||
if (tracker == null)
|
||||
return;
|
||||
Tracker tracker = this.api.server.getTrackerById(req.trackerId().unpack());
|
||||
if (tracker == null)
|
||||
return;
|
||||
|
||||
tracker.setBodyPosition(TrackerPosition.getById(req.bodyPosition()));
|
||||
tracker.setBodyPosition(TrackerPosition.getById(req.bodyPosition()));
|
||||
|
||||
if (tracker instanceof ReferenceAdjustedTracker) {
|
||||
ReferenceAdjustedTracker refTracker = (ReferenceAdjustedTracker) tracker;
|
||||
if (refTracker.getTracker() instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) refTracker.getTracker();
|
||||
imu.setMountingRotation(new Quaternion(
|
||||
req.mountingRotation().x(),
|
||||
req.mountingRotation().y(),
|
||||
req.mountingRotation().z(),
|
||||
req.mountingRotation().w()
|
||||
));
|
||||
}
|
||||
}
|
||||
this.api.server.trackerUpdated(tracker);
|
||||
}
|
||||
if (tracker instanceof ReferenceAdjustedTracker) {
|
||||
ReferenceAdjustedTracker refTracker = (ReferenceAdjustedTracker) tracker;
|
||||
if (refTracker.getTracker() instanceof IMUTracker) {
|
||||
IMUTracker imu = (IMUTracker) refTracker.getTracker();
|
||||
imu.setMountingRotation(new Quaternion(
|
||||
req.mountingRotation().x(),
|
||||
req.mountingRotation().y(),
|
||||
req.mountingRotation().z(),
|
||||
req.mountingRotation().w()
|
||||
));
|
||||
}
|
||||
}
|
||||
this.api.server.trackerUpdated(tracker);
|
||||
}
|
||||
|
||||
public void onSettingsRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
public void onSettingsRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
|
||||
WindowsNamedPipeBridge bridge = this.api.server.getVRBridge(WindowsNamedPipeBridge.class);
|
||||
WindowsNamedPipeBridge bridge = this.api.server.getVRBridge(WindowsNamedPipeBridge.class);
|
||||
|
||||
int steamvrTrackerSettings = SteamVRTrackersSetting.createSteamVRTrackersSetting(fbb,
|
||||
bridge.getShareSetting(TrackerRole.WAIST),
|
||||
bridge.getShareSetting(TrackerRole.CHEST),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_FOOT) && bridge.getShareSetting(TrackerRole.RIGHT_FOOT),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_KNEE) && bridge.getShareSetting(TrackerRole.RIGHT_KNEE),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_ELBOW) && bridge.getShareSetting(TrackerRole.RIGHT_ELBOW)
|
||||
);
|
||||
int steamvrTrackerSettings = SteamVRTrackersSetting.createSteamVRTrackersSetting(fbb,
|
||||
bridge.getShareSetting(TrackerRole.WAIST),
|
||||
bridge.getShareSetting(TrackerRole.CHEST),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_FOOT) && bridge.getShareSetting(TrackerRole.RIGHT_FOOT),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_KNEE) && bridge.getShareSetting(TrackerRole.RIGHT_KNEE),
|
||||
bridge.getShareSetting(TrackerRole.LEFT_ELBOW) && bridge.getShareSetting(TrackerRole.RIGHT_ELBOW)
|
||||
);
|
||||
|
||||
int filterSettings = FilteringSettings.createFilteringSettings(
|
||||
fbb,
|
||||
TrackerFilters.valueOf(this.api.server.config.getString("filters.type", "NONE")).id,
|
||||
(int) (this.api.server.config.getFloat("filters.amount", 0.3f) * 100),
|
||||
this.api.server.config.getInt("filters.tickCount", 1)
|
||||
);
|
||||
int filterSettings = FilteringSettings.createFilteringSettings(
|
||||
fbb,
|
||||
TrackerFilters.valueOf(this.api.server.config.getString("filters.type", "NONE")).id,
|
||||
(int) (this.api.server.config.getFloat("filters.amount", 0.3f) * 100),
|
||||
this.api.server.config.getInt("filters.tickCount", 1)
|
||||
);
|
||||
|
||||
int settings = SettingsResponse.createSettingsResponse(fbb, steamvrTrackerSettings, filterSettings);
|
||||
int outbound = createRPCMessage(fbb, RpcMessage.SettingsResponse, settings);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
int settings = SettingsResponse.createSettingsResponse(fbb, steamvrTrackerSettings, filterSettings);
|
||||
int outbound = createRPCMessage(fbb, RpcMessage.SettingsResponse, settings);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
}
|
||||
|
||||
public void onChangeSettingsRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
public void onChangeSettingsRequest(GenericConnection conn, RpcMessageHeader messageHeader) {
|
||||
|
||||
ChangeSettingsRequest req = (ChangeSettingsRequest) messageHeader.message(new ChangeSettingsRequest());
|
||||
if (req == null) return;
|
||||
ChangeSettingsRequest req = (ChangeSettingsRequest) messageHeader.message(new ChangeSettingsRequest());
|
||||
if (req == null) return;
|
||||
|
||||
if (req.steamVrTrackers() != null) {
|
||||
WindowsNamedPipeBridge bridge = this.api.server.getVRBridge(WindowsNamedPipeBridge.class);
|
||||
bridge.changeShareSettings(TrackerRole.WAIST, req.steamVrTrackers().waist());
|
||||
bridge.changeShareSettings(TrackerRole.CHEST, req.steamVrTrackers().chest());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_FOOT, req.steamVrTrackers().legs());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_FOOT, req.steamVrTrackers().legs());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_KNEE, req.steamVrTrackers().knees());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_KNEE, req.steamVrTrackers().knees());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_ELBOW, req.steamVrTrackers().elbows());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_ELBOW, req.steamVrTrackers().elbows());
|
||||
}
|
||||
if (req.steamVrTrackers() != null) {
|
||||
WindowsNamedPipeBridge bridge = this.api.server.getVRBridge(WindowsNamedPipeBridge.class);
|
||||
bridge.changeShareSettings(TrackerRole.WAIST, req.steamVrTrackers().waist());
|
||||
bridge.changeShareSettings(TrackerRole.CHEST, req.steamVrTrackers().chest());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_FOOT, req.steamVrTrackers().legs());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_FOOT, req.steamVrTrackers().legs());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_KNEE, req.steamVrTrackers().knees());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_KNEE, req.steamVrTrackers().knees());
|
||||
bridge.changeShareSettings(TrackerRole.LEFT_ELBOW, req.steamVrTrackers().elbows());
|
||||
bridge.changeShareSettings(TrackerRole.RIGHT_ELBOW, req.steamVrTrackers().elbows());
|
||||
}
|
||||
|
||||
if (req.filtering() != null) {
|
||||
TrackerFilters type = TrackerFilters.fromId(req.filtering().type());
|
||||
if (type != null) {
|
||||
this.api.server.updateTrackersFilters(type, (float) req.filtering().intensity() / 100.0f, req.filtering().ticks());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (req.filtering() != null) {
|
||||
TrackerFilters type = TrackerFilters.fromId(req.filtering().type());
|
||||
if (type != null) {
|
||||
this.api.server.updateTrackersFilters(type, (float) req.filtering().intensity() / 100.0f, req.filtering().ticks());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(GenericConnection conn, RpcMessageHeader message) {
|
||||
BiConsumer<GenericConnection, RpcMessageHeader> consumer = this.handlers[message.messageType()];
|
||||
if (consumer != null)
|
||||
consumer.accept(conn, message);
|
||||
else
|
||||
LogManager.log.info("[ProtocolAPI] Unhandled RPC packet received id: " + message.messageType());
|
||||
}
|
||||
@Override
|
||||
public void onMessage(GenericConnection conn, RpcMessageHeader message) {
|
||||
BiConsumer<GenericConnection, RpcMessageHeader> consumer = this.handlers[message.messageType()];
|
||||
if (consumer != null)
|
||||
consumer.accept(conn, message);
|
||||
else
|
||||
LogManager.log.info("[ProtocolAPI] Unhandled RPC packet received id: " + message.messageType());
|
||||
}
|
||||
|
||||
public int createRPCMessage(FlatBufferBuilder fbb, byte messageType, int messageOffset) {
|
||||
int[] data = new int[1];
|
||||
public int createRPCMessage(FlatBufferBuilder fbb, byte messageType, int messageOffset) {
|
||||
int[] data = new int[1];
|
||||
|
||||
RpcMessageHeader.startRpcMessageHeader(fbb);
|
||||
RpcMessageHeader.addMessage(fbb, messageOffset);
|
||||
RpcMessageHeader.addMessageType(fbb, messageType);
|
||||
RpcMessageHeader.addTxId(fbb, TransactionId.createTransactionId(fbb, currTransactionId++));
|
||||
data[0] = RpcMessageHeader.endRpcMessageHeader(fbb);
|
||||
RpcMessageHeader.startRpcMessageHeader(fbb);
|
||||
RpcMessageHeader.addMessage(fbb, messageOffset);
|
||||
RpcMessageHeader.addMessageType(fbb, messageType);
|
||||
RpcMessageHeader.addTxId(fbb, TransactionId.createTransactionId(fbb, currTransactionId++));
|
||||
data[0] = RpcMessageHeader.endRpcMessageHeader(fbb);
|
||||
|
||||
int messages = MessageBundle.createRpcMsgsVector(fbb, data);
|
||||
return createMessage(fbb, -1, messages);
|
||||
}
|
||||
int messages = MessageBundle.createRpcMsgsVector(fbb, data);
|
||||
return createMessage(fbb, -1, messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int messagesCount() {
|
||||
return RpcMessage.names.length;
|
||||
}
|
||||
@Override
|
||||
public int messagesCount() {
|
||||
return RpcMessage.names.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSerialConnected(SerialPort port) {
|
||||
@Override
|
||||
public void onSerialConnected(SerialPort port) {
|
||||
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, false);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, false);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
|
||||
conn.send(fbb.dataBuffer());
|
||||
});
|
||||
});
|
||||
}
|
||||
conn.send(fbb.dataBuffer());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSerialDisconnected() {
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
@Override
|
||||
public void onSerialDisconnected() {
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, true);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
conn.getContext().setUseSerial(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addClosed(fbb, true);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
conn.send(fbb.dataBuffer());
|
||||
conn.getContext().setUseSerial(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSerialLog(String str) {
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
@Override
|
||||
public void onSerialLog(String str) {
|
||||
this.api.getAPIServers().forEach((server) -> {
|
||||
server.getAPIConnections()
|
||||
.values()
|
||||
.stream()
|
||||
.filter(conn -> conn.getContext().useSerial())
|
||||
.forEach((conn) -> {
|
||||
FlatBufferBuilder fbb = new FlatBufferBuilder(32);
|
||||
|
||||
int logOffset = fbb.createString(str);
|
||||
int logOffset = fbb.createString(str);
|
||||
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addLog(fbb, logOffset);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
SerialUpdateResponse.startSerialUpdateResponse(fbb);
|
||||
SerialUpdateResponse.addLog(fbb, logOffset);
|
||||
int update = SerialUpdateResponse.endSerialUpdateResponse(fbb);
|
||||
int outbound = this.createRPCMessage(fbb, RpcMessage.SerialUpdateResponse, update);
|
||||
fbb.finish(outbound);
|
||||
|
||||
conn.send(fbb.dataBuffer());
|
||||
});
|
||||
});
|
||||
}
|
||||
conn.send(fbb.dataBuffer());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,97 +14,97 @@ import java.util.List;
|
||||
|
||||
public class SerialHandler implements SerialPortMessageListener {
|
||||
|
||||
private final List<SerialListener> listeners = new ArrayList<>();
|
||||
private SerialPort trackerPort = null;
|
||||
private final List<SerialListener> listeners = new ArrayList<>();
|
||||
private SerialPort trackerPort = null;
|
||||
|
||||
public void addListener(SerialListener channel) {
|
||||
this.listeners.add(channel);
|
||||
}
|
||||
public void addListener(SerialListener channel) {
|
||||
this.listeners.add(channel);
|
||||
}
|
||||
|
||||
public void removeListener(SerialListener l) {
|
||||
listeners.removeIf(listener -> l == listener);
|
||||
}
|
||||
public void removeListener(SerialListener l) {
|
||||
listeners.removeIf(listener -> l == listener);
|
||||
}
|
||||
|
||||
public boolean openSerial() {
|
||||
if (this.isConnected()) {
|
||||
return true;
|
||||
}
|
||||
public boolean openSerial() {
|
||||
if (this.isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SerialPort[] ports = SerialPort.getCommPorts();
|
||||
for (SerialPort port : ports) {
|
||||
if (port.getDescriptivePortName().toLowerCase().contains("ch340") || port.getDescriptivePortName().toLowerCase().contains("cp21") || port.getDescriptivePortName().toLowerCase().contains("ch910")) {
|
||||
trackerPort = port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trackerPort == null) {
|
||||
return false;
|
||||
}
|
||||
SerialPort[] ports = SerialPort.getCommPorts();
|
||||
for (SerialPort port : ports) {
|
||||
if (port.getDescriptivePortName().toLowerCase().contains("ch340") || port.getDescriptivePortName().toLowerCase().contains("cp21") || port.getDescriptivePortName().toLowerCase().contains("ch910")) {
|
||||
trackerPort = port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trackerPort == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!trackerPort.openPort()) {
|
||||
return false;
|
||||
}
|
||||
if (!trackerPort.openPort()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
trackerPort.setBaudRate(115200);
|
||||
trackerPort.addDataListener(this);
|
||||
this.listeners.forEach((listener) -> listener.onSerialConnected(trackerPort));
|
||||
return true;
|
||||
}
|
||||
trackerPort.setBaudRate(115200);
|
||||
trackerPort.addDataListener(this);
|
||||
this.listeners.forEach((listener) -> listener.onSerialConnected(trackerPort));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void closeSerial() {
|
||||
if (trackerPort != null)
|
||||
trackerPort.closePort();
|
||||
this.listeners.forEach(SerialListener::onSerialDisconnected);
|
||||
System.out.println("Port closed okay");
|
||||
trackerPort = null;
|
||||
}
|
||||
public void closeSerial() {
|
||||
if (trackerPort != null)
|
||||
trackerPort.closePort();
|
||||
this.listeners.forEach(SerialListener::onSerialDisconnected);
|
||||
System.out.println("Port closed okay");
|
||||
trackerPort = null;
|
||||
}
|
||||
|
||||
public void setWifi(String ssid, String passwd) {
|
||||
if (trackerPort == null)
|
||||
return;
|
||||
OutputStream os = trackerPort.getOutputStream();
|
||||
OutputStreamWriter writer = new OutputStreamWriter(os);
|
||||
try {
|
||||
writer.append("SET WIFI \"" + ssid + "\" \"" + passwd + "\"\n");
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
addLog(e + "\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void setWifi(String ssid, String passwd) {
|
||||
if (trackerPort == null)
|
||||
return;
|
||||
OutputStream os = trackerPort.getOutputStream();
|
||||
OutputStreamWriter writer = new OutputStreamWriter(os);
|
||||
try {
|
||||
writer.append("SET WIFI \"" + ssid + "\" \"" + passwd + "\"\n");
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
addLog(e + "\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void addLog(String str) {
|
||||
this.listeners.forEach(listener -> listener.onSerialLog(str));
|
||||
}
|
||||
public void addLog(String str) {
|
||||
this.listeners.forEach(listener -> listener.onSerialLog(str));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getListeningEvents() {
|
||||
return SerialPort.LISTENING_EVENT_PORT_DISCONNECTED | SerialPort.LISTENING_EVENT_DATA_RECEIVED;
|
||||
}
|
||||
@Override
|
||||
public int getListeningEvents() {
|
||||
return SerialPort.LISTENING_EVENT_PORT_DISCONNECTED | SerialPort.LISTENING_EVENT_DATA_RECEIVED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialEvent(SerialPortEvent event) {
|
||||
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_RECEIVED) {
|
||||
byte[] newData = event.getReceivedData();
|
||||
String s = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(newData)).toString();
|
||||
this.addLog(s);
|
||||
} else if (event.getEventType() == SerialPort.LISTENING_EVENT_PORT_DISCONNECTED) {
|
||||
this.closeSerial();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void serialEvent(SerialPortEvent event) {
|
||||
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_RECEIVED) {
|
||||
byte[] newData = event.getReceivedData();
|
||||
String s = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(newData)).toString();
|
||||
this.addLog(s);
|
||||
} else if (event.getEventType() == SerialPort.LISTENING_EVENT_PORT_DISCONNECTED) {
|
||||
this.closeSerial();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return this.trackerPort != null && this.trackerPort.isOpen();
|
||||
}
|
||||
public boolean isConnected() {
|
||||
return this.trackerPort != null && this.trackerPort.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getMessageDelimiter() {
|
||||
return new byte[]{(byte) 0x0A};
|
||||
}
|
||||
@Override
|
||||
public byte[] getMessageDelimiter() {
|
||||
return new byte[]{(byte) 0x0A};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delimiterIndicatesEndOfMessage() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean delimiterIndicatesEndOfMessage() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import com.fazecast.jSerialComm.SerialPort;
|
||||
|
||||
public interface SerialListener {
|
||||
|
||||
void onSerialConnected(SerialPort port);
|
||||
void onSerialConnected(SerialPort port);
|
||||
|
||||
void onSerialDisconnected();
|
||||
void onSerialDisconnected();
|
||||
|
||||
void onSerialLog(String str);
|
||||
void onSerialLog(String str);
|
||||
}
|
||||
|
||||
@@ -9,33 +9,33 @@ import io.eiren.util.BufferedTimer;
|
||||
|
||||
public class ComputedHumanPoseTracker extends ComputedTracker implements TrackerWithTPS, ShareableTracker {
|
||||
|
||||
public final ComputedHumanPoseTrackerPosition skeletonPosition;
|
||||
protected final TrackerRole trackerRole;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
public final ComputedHumanPoseTrackerPosition skeletonPosition;
|
||||
protected final TrackerRole trackerRole;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public ComputedHumanPoseTracker(int trackerId, ComputedHumanPoseTrackerPosition skeletonPosition, TrackerRole role) {
|
||||
super(trackerId, "human://" + skeletonPosition.name(), true, true);
|
||||
this.skeletonPosition = skeletonPosition;
|
||||
this.trackerRole = role;
|
||||
}
|
||||
public ComputedHumanPoseTracker(int trackerId, ComputedHumanPoseTrackerPosition skeletonPosition, TrackerRole role) {
|
||||
super(trackerId, "human://" + skeletonPosition.name(), true, true);
|
||||
this.skeletonPosition = skeletonPosition;
|
||||
this.trackerRole = role;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerRole getTrackerRole() {
|
||||
return trackerRole;
|
||||
}
|
||||
@Override
|
||||
public TrackerRole getTrackerRole() {
|
||||
return trackerRole;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ package dev.slimevr.vr.processor;
|
||||
|
||||
public enum ComputedHumanPoseTrackerPosition {
|
||||
|
||||
WAIST,
|
||||
CHEST,
|
||||
LEFT_FOOT,
|
||||
RIGHT_FOOT,
|
||||
LEFT_KNEE,
|
||||
RIGHT_KNEE,
|
||||
LEFT_ELBOW,
|
||||
RIGHT_ELBOW,
|
||||
LEFT_HAND,
|
||||
RIGHT_HAND
|
||||
WAIST,
|
||||
CHEST,
|
||||
LEFT_FOOT,
|
||||
RIGHT_FOOT,
|
||||
LEFT_KNEE,
|
||||
RIGHT_KNEE,
|
||||
LEFT_ELBOW,
|
||||
RIGHT_ELBOW,
|
||||
LEFT_HAND,
|
||||
RIGHT_HAND
|
||||
}
|
||||
|
||||
@@ -15,112 +15,112 @@ import java.util.function.Consumer;
|
||||
|
||||
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 VRServer server;
|
||||
private final List<ComputedHumanPoseTracker> computedTrackers = new FastList<>();
|
||||
private final List<Consumer<HumanSkeleton>> onSkeletonUpdated = new FastList<>();
|
||||
private HumanSkeleton skeleton;
|
||||
|
||||
public HumanPoseProcessor(VRServer server, HMDTracker hmd) {
|
||||
this.server = server;
|
||||
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));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_ELBOW, TrackerRole.LEFT_ELBOW));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_ELBOW, TrackerRole.RIGHT_ELBOW));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_HAND, TrackerRole.LEFT_HAND));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_HAND, TrackerRole.RIGHT_HAND));
|
||||
}
|
||||
public HumanPoseProcessor(VRServer server, HMDTracker hmd) {
|
||||
this.server = server;
|
||||
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));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_ELBOW, TrackerRole.LEFT_ELBOW));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_ELBOW, TrackerRole.RIGHT_ELBOW));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.LEFT_HAND, TrackerRole.LEFT_HAND));
|
||||
computedTrackers.add(new ComputedHumanPoseTracker(Tracker.getNextLocalTrackerId(), ComputedHumanPoseTrackerPosition.RIGHT_HAND, TrackerRole.RIGHT_HAND));
|
||||
}
|
||||
|
||||
public HumanSkeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
public HumanSkeleton getSkeleton() {
|
||||
return skeleton;
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
onSkeletonUpdated.add(consumer);
|
||||
if (skeleton != null)
|
||||
consumer.accept(skeleton);
|
||||
}
|
||||
@VRServerThread
|
||||
public void addSkeletonUpdatedCallback(Consumer<HumanSkeleton> consumer) {
|
||||
onSkeletonUpdated.add(consumer);
|
||||
if (skeleton != null)
|
||||
consumer.accept(skeleton);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void setSkeletonConfig(SkeletonConfigValue key, float newLength) {
|
||||
if (skeleton != null)
|
||||
skeleton.getSkeletonConfig().setConfig(key, newLength);
|
||||
}
|
||||
@ThreadSafe
|
||||
public void setSkeletonConfig(SkeletonConfigValue key, float newLength) {
|
||||
if (skeleton != null)
|
||||
skeleton.getSkeletonConfig().setConfig(key, newLength);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void resetSkeletonConfig(SkeletonConfigValue key) {
|
||||
if (skeleton != null)
|
||||
skeleton.resetSkeletonConfig(key);
|
||||
}
|
||||
@ThreadSafe
|
||||
public void resetSkeletonConfig(SkeletonConfigValue key) {
|
||||
if (skeleton != null)
|
||||
skeleton.resetSkeletonConfig(key);
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public void resetAllSkeletonConfigs() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetAllSkeletonConfigs();
|
||||
}
|
||||
@ThreadSafe
|
||||
public void resetAllSkeletonConfigs() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetAllSkeletonConfigs();
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public SkeletonConfig getSkeletonConfig() {
|
||||
return skeleton.getSkeletonConfig();
|
||||
}
|
||||
@ThreadSafe
|
||||
public SkeletonConfig getSkeletonConfig() {
|
||||
return skeleton.getSkeletonConfig();
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public float getSkeletonConfig(SkeletonConfigValue key) {
|
||||
if (skeleton != null) {
|
||||
return skeleton.getSkeletonConfig().getConfig(key);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@ThreadSafe
|
||||
public float getSkeletonConfig(SkeletonConfigValue key) {
|
||||
if (skeleton != null) {
|
||||
return skeleton.getSkeletonConfig().getConfig(key);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@ThreadSafe
|
||||
public List<? extends ShareableTracker> getComputedTrackers() {
|
||||
return computedTrackers;
|
||||
}
|
||||
@ThreadSafe
|
||||
public List<? extends ShareableTracker> getComputedTrackers() {
|
||||
return computedTrackers;
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void trackerAdded(Tracker tracker) {
|
||||
updateSekeltonModel();
|
||||
}
|
||||
@VRServerThread
|
||||
public void trackerAdded(Tracker tracker) {
|
||||
updateSekeltonModel();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void trackerUpdated(Tracker tracker) {
|
||||
updateSekeltonModel();
|
||||
}
|
||||
@VRServerThread
|
||||
public void trackerUpdated(Tracker tracker) {
|
||||
updateSekeltonModel();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
private void updateSekeltonModel() {
|
||||
disconnectAllTrackers();
|
||||
skeleton = new SimpleSkeleton(server, computedTrackers);
|
||||
for (int i = 0; i < onSkeletonUpdated.size(); ++i)
|
||||
onSkeletonUpdated.get(i).accept(skeleton);
|
||||
}
|
||||
@VRServerThread
|
||||
private void updateSekeltonModel() {
|
||||
disconnectAllTrackers();
|
||||
skeleton = new SimpleSkeleton(server, computedTrackers);
|
||||
for (int i = 0; i < onSkeletonUpdated.size(); ++i)
|
||||
onSkeletonUpdated.get(i).accept(skeleton);
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
private void disconnectAllTrackers() {
|
||||
for (int i = 0; i < computedTrackers.size(); ++i) {
|
||||
computedTrackers.get(i).setStatus(TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
@VRServerThread
|
||||
private void disconnectAllTrackers() {
|
||||
for (int i = 0; i < computedTrackers.size(); ++i) {
|
||||
computedTrackers.get(i).setStatus(TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void update() {
|
||||
if (skeleton != null)
|
||||
skeleton.updatePose();
|
||||
}
|
||||
@VRServerThread
|
||||
public void update() {
|
||||
if (skeleton != null)
|
||||
skeleton.updatePose();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void resetTrackers() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetTrackersFull();
|
||||
}
|
||||
@VRServerThread
|
||||
public void resetTrackers() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetTrackersFull();
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public void resetTrackersYaw() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetTrackersYaw();
|
||||
}
|
||||
@VRServerThread
|
||||
public void resetTrackersYaw() {
|
||||
if (skeleton != null)
|
||||
skeleton.resetTrackersYaw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,68 +8,68 @@ import java.util.function.Consumer;
|
||||
|
||||
public class TransformNode {
|
||||
|
||||
public final Transform localTransform = new Transform();
|
||||
public final Transform worldTransform = new Transform();
|
||||
public final List<TransformNode> children = new FastList<>();
|
||||
public boolean localRotation = false;
|
||||
protected TransformNode parent;
|
||||
protected String name;
|
||||
public final Transform localTransform = new Transform();
|
||||
public final Transform worldTransform = new Transform();
|
||||
public final List<TransformNode> children = new FastList<>();
|
||||
public boolean localRotation = false;
|
||||
protected TransformNode parent;
|
||||
protected String name;
|
||||
|
||||
public TransformNode(String name, boolean localRotation) {
|
||||
this.name = name;
|
||||
this.localRotation = localRotation;
|
||||
}
|
||||
public TransformNode(String name, boolean localRotation) {
|
||||
this.name = name;
|
||||
this.localRotation = localRotation;
|
||||
}
|
||||
|
||||
public TransformNode(String name) {
|
||||
this(name, true);
|
||||
}
|
||||
public TransformNode(String name) {
|
||||
this(name, true);
|
||||
}
|
||||
|
||||
public void attachChild(TransformNode node) {
|
||||
if (node.parent != null) {
|
||||
throw new IllegalArgumentException("The child node must not already have a parent");
|
||||
}
|
||||
public void attachChild(TransformNode node) {
|
||||
if (node.parent != null) {
|
||||
throw new IllegalArgumentException("The child node must not already have a parent");
|
||||
}
|
||||
|
||||
this.children.add(node);
|
||||
node.parent = this;
|
||||
}
|
||||
this.children.add(node);
|
||||
node.parent = this;
|
||||
}
|
||||
|
||||
public TransformNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
public TransformNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
updateWorldTransforms(); // Call update on each frame because we have relatively few nodes
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
children.get(i).update();
|
||||
}
|
||||
public void update() {
|
||||
updateWorldTransforms(); // Call update on each frame because we have relatively few nodes
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
children.get(i).update();
|
||||
}
|
||||
|
||||
protected synchronized void updateWorldTransforms() {
|
||||
if (parent == null) {
|
||||
worldTransform.set(localTransform);
|
||||
} else {
|
||||
worldTransform.set(localTransform);
|
||||
if (localRotation)
|
||||
worldTransform.combineWithParent(parent.worldTransform);
|
||||
else
|
||||
combineWithParentGlobalRotation(parent.worldTransform);
|
||||
}
|
||||
}
|
||||
protected synchronized void updateWorldTransforms() {
|
||||
if (parent == null) {
|
||||
worldTransform.set(localTransform);
|
||||
} else {
|
||||
worldTransform.set(localTransform);
|
||||
if (localRotation)
|
||||
worldTransform.combineWithParent(parent.worldTransform);
|
||||
else
|
||||
combineWithParentGlobalRotation(parent.worldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
public void depthFirstTraversal(Consumer<TransformNode> visitor) {
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children.get(i).depthFirstTraversal(visitor);
|
||||
}
|
||||
visitor.accept(this);
|
||||
}
|
||||
public void depthFirstTraversal(Consumer<TransformNode> visitor) {
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children.get(i).depthFirstTraversal(visitor);
|
||||
}
|
||||
visitor.accept(this);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void combineWithParentGlobalRotation(Transform parent) {
|
||||
worldTransform.getScale().multLocal(parent.getScale());
|
||||
worldTransform.getTranslation().multLocal(parent.getScale());
|
||||
public void combineWithParentGlobalRotation(Transform parent) {
|
||||
worldTransform.getScale().multLocal(parent.getScale());
|
||||
worldTransform.getTranslation().multLocal(parent.getScale());
|
||||
|
||||
parent.getRotation().multLocal(worldTransform.getTranslation()).addLocal(parent.getTranslation());
|
||||
}
|
||||
parent.getRotation().multLocal(worldTransform.getTranslation()).addLocal(parent.getTranslation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,31 +6,31 @@ import io.eiren.util.ann.ThreadSafe;
|
||||
|
||||
public abstract class HumanSkeleton {
|
||||
|
||||
@VRServerThread
|
||||
public abstract void updatePose();
|
||||
@VRServerThread
|
||||
public abstract void updatePose();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract TransformNode getRootNode();
|
||||
@ThreadSafe
|
||||
public abstract TransformNode getRootNode();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract TransformNode[] getAllNodes();
|
||||
@ThreadSafe
|
||||
public abstract TransformNode[] getAllNodes();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract SkeletonConfig getSkeletonConfig();
|
||||
@ThreadSafe
|
||||
public abstract SkeletonConfig getSkeletonConfig();
|
||||
|
||||
@ThreadSafe
|
||||
public abstract void resetSkeletonConfig(SkeletonConfigValue config);
|
||||
@ThreadSafe
|
||||
public abstract void resetSkeletonConfig(SkeletonConfigValue config);
|
||||
|
||||
@ThreadSafe
|
||||
public void resetAllSkeletonConfigs() {
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
resetSkeletonConfig(config);
|
||||
}
|
||||
}
|
||||
@ThreadSafe
|
||||
public void resetAllSkeletonConfigs() {
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
resetSkeletonConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersFull();
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersFull();
|
||||
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersYaw();
|
||||
@VRServerThread
|
||||
public abstract void resetTrackersYaw();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,391 +9,391 @@ import java.util.Map;
|
||||
|
||||
public class SkeletonConfig {
|
||||
|
||||
protected final EnumMap<SkeletonConfigValue, Float> configs = new EnumMap<SkeletonConfigValue, Float>(SkeletonConfigValue.class);
|
||||
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<SkeletonConfigValue, Float> configs = new EnumMap<SkeletonConfigValue, Float>(SkeletonConfigValue.class);
|
||||
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 boolean autoUpdateOffsets;
|
||||
protected final SkeletonConfigCallback callback;
|
||||
protected final boolean autoUpdateOffsets;
|
||||
protected final SkeletonConfigCallback callback;
|
||||
|
||||
public SkeletonConfig(boolean autoUpdateOffsets) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = null;
|
||||
public SkeletonConfig(boolean autoUpdateOffsets) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = null;
|
||||
|
||||
callCallbackOnAll(true);
|
||||
callCallbackOnAll(true);
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public SkeletonConfig(boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
public SkeletonConfig(boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
|
||||
callCallbackOnAll(true);
|
||||
callCallbackOnAll(true);
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public SkeletonConfig(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles, boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
setConfigs(configs, toggles);
|
||||
public SkeletonConfig(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles, boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
setConfigs(configs, toggles);
|
||||
|
||||
callCallbackOnAll(true);
|
||||
}
|
||||
callCallbackOnAll(true);
|
||||
}
|
||||
|
||||
public SkeletonConfig(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles, boolean autoUpdateOffsets) {
|
||||
this(configs, toggles, autoUpdateOffsets, null);
|
||||
}
|
||||
public SkeletonConfig(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles, boolean autoUpdateOffsets) {
|
||||
this(configs, toggles, autoUpdateOffsets, null);
|
||||
}
|
||||
|
||||
public SkeletonConfig(SkeletonConfig skeletonConfig, boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
setConfigs(skeletonConfig);
|
||||
public SkeletonConfig(SkeletonConfig skeletonConfig, boolean autoUpdateOffsets, SkeletonConfigCallback callback) {
|
||||
this.autoUpdateOffsets = autoUpdateOffsets;
|
||||
this.callback = callback;
|
||||
setConfigs(skeletonConfig);
|
||||
|
||||
callCallbackOnAll(true);
|
||||
}
|
||||
callCallbackOnAll(true);
|
||||
}
|
||||
|
||||
public SkeletonConfig(SkeletonConfig skeletonConfig, boolean autoUpdateOffsets) {
|
||||
this(skeletonConfig, autoUpdateOffsets, null);
|
||||
}
|
||||
public SkeletonConfig(SkeletonConfig skeletonConfig, boolean autoUpdateOffsets) {
|
||||
this(skeletonConfig, autoUpdateOffsets, null);
|
||||
}
|
||||
|
||||
//#region Cast utilities for config reading
|
||||
private static Float castFloat(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Float) {
|
||||
return (Float) o;
|
||||
} else if (o instanceof Double) {
|
||||
return ((Double) o).floatValue();
|
||||
} else if (o instanceof Byte) {
|
||||
return (float) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (float) (Integer) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (float) (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
//#region Cast utilities for config reading
|
||||
private static Float castFloat(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Float) {
|
||||
return (Float) o;
|
||||
} else if (o instanceof Double) {
|
||||
return ((Double) o).floatValue();
|
||||
} else if (o instanceof Byte) {
|
||||
return (float) (Byte) o;
|
||||
} else if (o instanceof Integer) {
|
||||
return (float) (Integer) o;
|
||||
} else if (o instanceof Long) {
|
||||
return (float) (Long) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean castBoolean(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Boolean) {
|
||||
return (Boolean) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static Boolean castBoolean(Object o) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
} else if (o instanceof Boolean) {
|
||||
return (Boolean) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void callCallbackOnAll(boolean defaultOnly) {
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
private void callCallbackOnAll(boolean defaultOnly) {
|
||||
if (callback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
try {
|
||||
Float val = configs.get(config);
|
||||
if (!defaultOnly || val == null) {
|
||||
callback.updateConfigState(config, val == null ? config.defaultValue : val);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
for (SkeletonConfigValue config : SkeletonConfigValue.values) {
|
||||
try {
|
||||
Float val = configs.get(config);
|
||||
if (!defaultOnly || val == null) {
|
||||
callback.updateConfigState(config, val == null ? config.defaultValue : val);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
for (SkeletonConfigToggle config : SkeletonConfigToggle.values) {
|
||||
try {
|
||||
Boolean val = toggles.get(config);
|
||||
if (!defaultOnly || val == null) {
|
||||
callback.updateToggleState(config, val == null ? config.defaultValue : val);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SkeletonConfigToggle config : SkeletonConfigToggle.values) {
|
||||
try {
|
||||
Boolean val = toggles.get(config);
|
||||
if (!defaultOnly || val == null) {
|
||||
callback.updateToggleState(config, val == null ? config.defaultValue : val);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Float setConfig(SkeletonConfigValue config, Float newValue, boolean computeOffsets) {
|
||||
Float origVal = newValue != null ? configs.put(config, newValue) : configs.remove(config);
|
||||
public Float setConfig(SkeletonConfigValue config, Float newValue, boolean computeOffsets) {
|
||||
Float origVal = newValue != null ? configs.put(config, newValue) : configs.remove(config);
|
||||
|
||||
// Re-compute the affected offsets
|
||||
if (computeOffsets && autoUpdateOffsets && config.affectedOffsets != null) {
|
||||
for (SkeletonNodeOffset offset : config.affectedOffsets) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
// Re-compute the affected offsets
|
||||
if (computeOffsets && autoUpdateOffsets && config.affectedOffsets != null) {
|
||||
for (SkeletonNodeOffset offset : config.affectedOffsets) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateConfigState(config, newValue != null ? newValue : config.defaultValue);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateConfigState(config, newValue != null ? newValue : config.defaultValue);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
return origVal;
|
||||
}
|
||||
return origVal;
|
||||
}
|
||||
|
||||
public Float setConfig(SkeletonConfigValue config, Float newValue) {
|
||||
return setConfig(config, newValue, true);
|
||||
}
|
||||
public Float setConfig(SkeletonConfigValue config, Float newValue) {
|
||||
return setConfig(config, newValue, true);
|
||||
}
|
||||
|
||||
public Float setConfig(String config, Float newValue) {
|
||||
return setConfig(SkeletonConfigValue.getByStringValue(config), newValue);
|
||||
}
|
||||
public Float setConfig(String config, Float newValue) {
|
||||
return setConfig(SkeletonConfigValue.getByStringValue(config), newValue);
|
||||
}
|
||||
|
||||
public float getConfig(SkeletonConfigValue config) {
|
||||
if (config == null) {
|
||||
return 0f;
|
||||
}
|
||||
public float getConfig(SkeletonConfigValue config) {
|
||||
if (config == null) {
|
||||
return 0f;
|
||||
}
|
||||
|
||||
// IMPORTANT!! This null check is necessary, getOrDefault seems to randomly decide to return null at times, so this is a secondary check
|
||||
Float val = configs.getOrDefault(config, config.defaultValue);
|
||||
return val != null ? val : config.defaultValue;
|
||||
}
|
||||
// IMPORTANT!! This null check is necessary, getOrDefault seems to randomly decide to return null at times, so this is a secondary check
|
||||
Float val = configs.getOrDefault(config, config.defaultValue);
|
||||
return val != null ? val : config.defaultValue;
|
||||
}
|
||||
|
||||
public float getConfig(String config) {
|
||||
if (config == null) {
|
||||
return 0f;
|
||||
}
|
||||
return getConfig(SkeletonConfigValue.getByStringValue(config));
|
||||
}
|
||||
public float getConfig(String config) {
|
||||
if (config == null) {
|
||||
return 0f;
|
||||
}
|
||||
return getConfig(SkeletonConfigValue.getByStringValue(config));
|
||||
}
|
||||
|
||||
public Boolean setToggle(SkeletonConfigToggle config, Boolean newValue) {
|
||||
Boolean origVal = newValue != null ? toggles.put(config, newValue) : toggles.remove(config);
|
||||
public Boolean setToggle(SkeletonConfigToggle config, Boolean newValue) {
|
||||
Boolean origVal = newValue != null ? toggles.put(config, newValue) : toggles.remove(config);
|
||||
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateToggleState(config, newValue != null ? newValue : config.defaultValue);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateToggleState(config, newValue != null ? newValue : config.defaultValue);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
|
||||
return origVal;
|
||||
}
|
||||
return origVal;
|
||||
}
|
||||
|
||||
public Boolean setToggle(String config, Boolean newValue) {
|
||||
return setToggle(SkeletonConfigToggle.getByStringValue(config), newValue);
|
||||
}
|
||||
public Boolean setToggle(String config, Boolean newValue) {
|
||||
return setToggle(SkeletonConfigToggle.getByStringValue(config), newValue);
|
||||
}
|
||||
|
||||
public boolean getToggle(SkeletonConfigToggle config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
public boolean getToggle(SkeletonConfigToggle config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// IMPORTANT!! This null check is necessary, getOrDefault seems to randomly decide to return null at times, so this is a secondary check
|
||||
Boolean val = toggles.getOrDefault(config, config.defaultValue);
|
||||
return val != null ? val : config.defaultValue;
|
||||
}
|
||||
// IMPORTANT!! This null check is necessary, getOrDefault seems to randomly decide to return null at times, so this is a secondary check
|
||||
Boolean val = toggles.getOrDefault(config, config.defaultValue);
|
||||
return val != null ? val : config.defaultValue;
|
||||
}
|
||||
|
||||
public boolean getToggle(String config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
public boolean getToggle(String config) {
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getToggle(SkeletonConfigToggle.getByStringValue(config));
|
||||
}
|
||||
return getToggle(SkeletonConfigToggle.getByStringValue(config));
|
||||
}
|
||||
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, float x, float y, float z) {
|
||||
Vector3f offset = nodeOffsets.get(nodeOffset);
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, float x, float y, float z) {
|
||||
Vector3f offset = nodeOffsets.get(nodeOffset);
|
||||
|
||||
if (offset == null) {
|
||||
offset = new Vector3f(x, y, z);
|
||||
nodeOffsets.put(nodeOffset, offset);
|
||||
} else {
|
||||
offset.set(x, y, z);
|
||||
}
|
||||
if (offset == null) {
|
||||
offset = new Vector3f(x, y, z);
|
||||
nodeOffsets.put(nodeOffset, offset);
|
||||
} else {
|
||||
offset.set(x, y, z);
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateNodeOffset(nodeOffset, offset);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.updateNodeOffset(nodeOffset, offset);
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[SkeletonConfig] Exception while calling callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset) {
|
||||
if (offset == null) {
|
||||
setNodeOffset(nodeOffset, 0f, 0f, 0f);
|
||||
return;
|
||||
}
|
||||
protected void setNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset) {
|
||||
if (offset == null) {
|
||||
setNodeOffset(nodeOffset, 0f, 0f, 0f);
|
||||
return;
|
||||
}
|
||||
|
||||
setNodeOffset(nodeOffset, offset.x, offset.y, offset.z);
|
||||
}
|
||||
setNodeOffset(nodeOffset, offset.x, offset.y, offset.z);
|
||||
}
|
||||
|
||||
public Vector3f getNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
return nodeOffsets.getOrDefault(nodeOffset, Vector3f.ZERO);
|
||||
}
|
||||
public Vector3f getNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
return nodeOffsets.getOrDefault(nodeOffset, Vector3f.ZERO);
|
||||
}
|
||||
|
||||
public void computeNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
switch (nodeOffset) {
|
||||
case HEAD:
|
||||
setNodeOffset(nodeOffset, 0, 0, getConfig(SkeletonConfigValue.HEAD));
|
||||
break;
|
||||
case NECK:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.NECK), 0);
|
||||
break;
|
||||
case CHEST:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.CHEST), 0);
|
||||
break;
|
||||
case CHEST_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case WAIST:
|
||||
setNodeOffset(nodeOffset, 0, (getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.TORSO) + getConfig(SkeletonConfigValue.WAIST)), 0);
|
||||
break;
|
||||
case HIP:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.WAIST), 0);
|
||||
break;
|
||||
case HIP_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.HIP_OFFSET), -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
public void computeNodeOffset(SkeletonNodeOffset nodeOffset) {
|
||||
switch (nodeOffset) {
|
||||
case HEAD:
|
||||
setNodeOffset(nodeOffset, 0, 0, getConfig(SkeletonConfigValue.HEAD));
|
||||
break;
|
||||
case NECK:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.NECK), 0);
|
||||
break;
|
||||
case CHEST:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.CHEST), 0);
|
||||
break;
|
||||
case CHEST_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case WAIST:
|
||||
setNodeOffset(nodeOffset, 0, (getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.TORSO) + getConfig(SkeletonConfigValue.WAIST)), 0);
|
||||
break;
|
||||
case HIP:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.WAIST), 0);
|
||||
break;
|
||||
case HIP_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.HIP_OFFSET), -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
|
||||
case LEFT_HIP:
|
||||
setNodeOffset(nodeOffset, -getConfig(SkeletonConfigValue.HIPS_WIDTH) / 2f, 0, 0);
|
||||
break;
|
||||
case RIGHT_HIP:
|
||||
setNodeOffset(nodeOffset, getConfig(SkeletonConfigValue.HIPS_WIDTH) / 2f, 0, 0);
|
||||
break;
|
||||
case LEFT_HIP:
|
||||
setNodeOffset(nodeOffset, -getConfig(SkeletonConfigValue.HIPS_WIDTH) / 2f, 0, 0);
|
||||
break;
|
||||
case RIGHT_HIP:
|
||||
setNodeOffset(nodeOffset, getConfig(SkeletonConfigValue.HIPS_WIDTH) / 2f, 0, 0);
|
||||
break;
|
||||
|
||||
case KNEE:
|
||||
setNodeOffset(nodeOffset, 0, -(getConfig(SkeletonConfigValue.LEGS_LENGTH) - getConfig(SkeletonConfigValue.KNEE_HEIGHT)), 0);
|
||||
break;
|
||||
case KNEE_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case ANKLE:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.KNEE_HEIGHT), -getConfig(SkeletonConfigValue.FOOT_OFFSET));
|
||||
break;
|
||||
case FOOT:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.FOOT_LENGTH));
|
||||
break;
|
||||
case FOOT_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case KNEE:
|
||||
setNodeOffset(nodeOffset, 0, -(getConfig(SkeletonConfigValue.LEGS_LENGTH) - getConfig(SkeletonConfigValue.KNEE_HEIGHT)), 0);
|
||||
break;
|
||||
case KNEE_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
case ANKLE:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.KNEE_HEIGHT), -getConfig(SkeletonConfigValue.FOOT_OFFSET));
|
||||
break;
|
||||
case FOOT:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.FOOT_LENGTH));
|
||||
break;
|
||||
case FOOT_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, 0, -getConfig(SkeletonConfigValue.SKELETON_OFFSET));
|
||||
break;
|
||||
|
||||
case CONTROLLER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Y), getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Z));
|
||||
break;
|
||||
case HAND:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Y), -getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Z));
|
||||
break;
|
||||
case FOREARM_CONTRL:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case FOREARM_HMD:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case ELBOW_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.ELBOW_OFFSET), 0);
|
||||
break;
|
||||
case UPPER_ARM:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.UPPER_ARM_LENGTH), 0);
|
||||
break;
|
||||
case LEFT_SHOULDER:
|
||||
setNodeOffset(nodeOffset, -getConfig(SkeletonConfigValue.SHOULDERS_WIDTH) / 2f, getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.SHOULDERS_DISTANCE), 0);
|
||||
break;
|
||||
case RIGHT_SHOULDER:
|
||||
setNodeOffset(nodeOffset, getConfig(SkeletonConfigValue.SHOULDERS_WIDTH) / 2f, getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.SHOULDERS_DISTANCE), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case CONTROLLER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Y), getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Z));
|
||||
break;
|
||||
case HAND:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Y), -getConfig(SkeletonConfigValue.CONTROLLER_DISTANCE_Z));
|
||||
break;
|
||||
case FOREARM_CONTRL:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case FOREARM_HMD:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.FOREARM_LENGTH), 0);
|
||||
break;
|
||||
case ELBOW_TRACKER:
|
||||
setNodeOffset(nodeOffset, 0, getConfig(SkeletonConfigValue.ELBOW_OFFSET), 0);
|
||||
break;
|
||||
case UPPER_ARM:
|
||||
setNodeOffset(nodeOffset, 0, -getConfig(SkeletonConfigValue.UPPER_ARM_LENGTH), 0);
|
||||
break;
|
||||
case LEFT_SHOULDER:
|
||||
setNodeOffset(nodeOffset, -getConfig(SkeletonConfigValue.SHOULDERS_WIDTH) / 2f, getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.SHOULDERS_DISTANCE), 0);
|
||||
break;
|
||||
case RIGHT_SHOULDER:
|
||||
setNodeOffset(nodeOffset, getConfig(SkeletonConfigValue.SHOULDERS_WIDTH) / 2f, getConfig(SkeletonConfigValue.CHEST) - getConfig(SkeletonConfigValue.SHOULDERS_DISTANCE), 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void computeAllNodeOffsets() {
|
||||
for (SkeletonNodeOffset offset : SkeletonNodeOffset.values) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
public void computeAllNodeOffsets() {
|
||||
for (SkeletonNodeOffset offset : SkeletonNodeOffset.values) {
|
||||
computeNodeOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
public void setConfigs(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles) {
|
||||
if (configs != null) {
|
||||
configs.forEach((key, value) -> {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(key, value, false);
|
||||
});
|
||||
}
|
||||
public void setConfigs(Map<SkeletonConfigValue, Float> configs, Map<SkeletonConfigToggle, Boolean> toggles) {
|
||||
if (configs != null) {
|
||||
configs.forEach((key, value) -> {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(key, value, false);
|
||||
});
|
||||
}
|
||||
|
||||
if (toggles != null) {
|
||||
toggles.forEach(this::setToggle);
|
||||
}
|
||||
if (toggles != null) {
|
||||
toggles.forEach(this::setToggle);
|
||||
}
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStringConfigs(Map<String, Float> configs, Map<String, Boolean> toggles) {
|
||||
if (configs != null) {
|
||||
configs.forEach((key, value) -> {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(SkeletonConfigValue.getByStringValue(key), value, false);
|
||||
});
|
||||
}
|
||||
public void setStringConfigs(Map<String, Float> configs, Map<String, Boolean> toggles) {
|
||||
if (configs != null) {
|
||||
configs.forEach((key, value) -> {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(SkeletonConfigValue.getByStringValue(key), value, false);
|
||||
});
|
||||
}
|
||||
|
||||
if (toggles != null) {
|
||||
toggles.forEach((key, value) -> {
|
||||
setToggle(SkeletonConfigToggle.getByStringValue(key), value);
|
||||
});
|
||||
}
|
||||
if (toggles != null) {
|
||||
toggles.forEach((key, value) -> {
|
||||
setToggle(SkeletonConfigToggle.getByStringValue(key), value);
|
||||
});
|
||||
}
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public void setConfigs(SkeletonConfig skeletonConfig) {
|
||||
setConfigs(skeletonConfig.configs, skeletonConfig.toggles);
|
||||
}
|
||||
//#endregion
|
||||
public void setConfigs(SkeletonConfig skeletonConfig) {
|
||||
setConfigs(skeletonConfig.configs, skeletonConfig.toggles);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
public void loadFromConfig(YamlFile config) {
|
||||
for (SkeletonConfigValue configValue : SkeletonConfigValue.values) {
|
||||
Float val = castFloat(config.getProperty(configValue.configKey));
|
||||
if (val != null) {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(configValue, val, false);
|
||||
}
|
||||
}
|
||||
public void loadFromConfig(YamlFile config) {
|
||||
for (SkeletonConfigValue configValue : SkeletonConfigValue.values) {
|
||||
Float val = castFloat(config.getProperty(configValue.configKey));
|
||||
if (val != null) {
|
||||
// Do not recalculate the offsets, these are done in bulk at the end
|
||||
setConfig(configValue, val, false);
|
||||
}
|
||||
}
|
||||
|
||||
for (SkeletonConfigToggle configValue : SkeletonConfigToggle.values) {
|
||||
Boolean val = castBoolean(config.getProperty(configValue.configKey));
|
||||
if (val != null) {
|
||||
setToggle(configValue, val);
|
||||
}
|
||||
}
|
||||
for (SkeletonConfigToggle configValue : SkeletonConfigToggle.values) {
|
||||
Boolean val = castBoolean(config.getProperty(configValue.configKey));
|
||||
if (val != null) {
|
||||
setToggle(configValue, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveToConfig(YamlFile config) {
|
||||
// Write all possible values, this keeps configs consistent even if defaults were changed
|
||||
for (SkeletonConfigValue value : SkeletonConfigValue.values) {
|
||||
config.setProperty(value.configKey, getConfig(value));
|
||||
}
|
||||
public void saveToConfig(YamlFile config) {
|
||||
// Write all possible values, this keeps configs consistent even if defaults were changed
|
||||
for (SkeletonConfigValue value : SkeletonConfigValue.values) {
|
||||
config.setProperty(value.configKey, getConfig(value));
|
||||
}
|
||||
|
||||
for (SkeletonConfigToggle value : SkeletonConfigToggle.values) {
|
||||
config.setProperty(value.configKey, getToggle(value));
|
||||
}
|
||||
}
|
||||
for (SkeletonConfigToggle value : SkeletonConfigToggle.values) {
|
||||
config.setProperty(value.configKey, getToggle(value));
|
||||
}
|
||||
}
|
||||
|
||||
public void resetConfigs() {
|
||||
configs.clear();
|
||||
toggles.clear();
|
||||
public void resetConfigs() {
|
||||
configs.clear();
|
||||
toggles.clear();
|
||||
|
||||
callCallbackOnAll(false);
|
||||
callCallbackOnAll(false);
|
||||
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
if (autoUpdateOffsets) {
|
||||
computeAllNodeOffsets();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import com.jme3.math.Vector3f;
|
||||
|
||||
public interface SkeletonConfigCallback {
|
||||
|
||||
void updateConfigState(SkeletonConfigValue config, float newValue);
|
||||
void updateConfigState(SkeletonConfigValue config, float newValue);
|
||||
|
||||
void updateToggleState(SkeletonConfigToggle configToggle, boolean newValue);
|
||||
void updateToggleState(SkeletonConfigToggle configToggle, boolean newValue);
|
||||
|
||||
void updateNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset);
|
||||
void updateNodeOffset(SkeletonNodeOffset nodeOffset, Vector3f offset);
|
||||
}
|
||||
|
||||
@@ -5,32 +5,32 @@ import java.util.Map;
|
||||
|
||||
public enum SkeletonConfigToggle {
|
||||
|
||||
EXTENDED_PELVIS_MODEL("Extended pelvis model", "extendedPelvis", true),
|
||||
EXTENDED_KNEE_MODEL("Extended knee model", "extendedKnee", false),
|
||||
;
|
||||
EXTENDED_PELVIS_MODEL("Extended pelvis model", "extendedPelvis", true),
|
||||
EXTENDED_KNEE_MODEL("Extended knee model", "extendedKnee", false),
|
||||
;
|
||||
|
||||
public static final SkeletonConfigToggle[] values = values();
|
||||
private static final String CONFIG_PREFIX = "body.model.";
|
||||
private static final Map<String, SkeletonConfigToggle> byStringVal = new HashMap<>();
|
||||
public static final SkeletonConfigToggle[] values = values();
|
||||
private static final String CONFIG_PREFIX = "body.model.";
|
||||
private static final Map<String, SkeletonConfigToggle> byStringVal = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (SkeletonConfigToggle configVal : values()) {
|
||||
byStringVal.put(configVal.stringVal.toLowerCase(), configVal);
|
||||
}
|
||||
}
|
||||
static {
|
||||
for (SkeletonConfigToggle configVal : values()) {
|
||||
byStringVal.put(configVal.stringVal.toLowerCase(), configVal);
|
||||
}
|
||||
}
|
||||
|
||||
public final String stringVal;
|
||||
public final String configKey;
|
||||
public final boolean defaultValue;
|
||||
public final String stringVal;
|
||||
public final String configKey;
|
||||
public final boolean defaultValue;
|
||||
|
||||
SkeletonConfigToggle(String stringVal, String configKey, boolean defaultValue) {
|
||||
this.stringVal = stringVal;
|
||||
this.configKey = CONFIG_PREFIX + configKey;
|
||||
SkeletonConfigToggle(String stringVal, String configKey, boolean defaultValue) {
|
||||
this.stringVal = stringVal;
|
||||
this.configKey = CONFIG_PREFIX + configKey;
|
||||
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public static SkeletonConfigToggle getByStringValue(String stringVal) {
|
||||
return stringVal == null ? null : byStringVal.get(stringVal.toLowerCase());
|
||||
}
|
||||
public static SkeletonConfigToggle getByStringValue(String stringVal) {
|
||||
return stringVal == null ? null : byStringVal.get(stringVal.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,62 +4,62 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum SkeletonConfigValue {
|
||||
HEAD(1, "Head", "headShift", "Head shift", 0.1f, new SkeletonNodeOffset[]{SkeletonNodeOffset.HEAD}),
|
||||
NECK(2, "Neck", "neckLength", "Neck length", 0.1f, new SkeletonNodeOffset[]{SkeletonNodeOffset.NECK}),
|
||||
TORSO(3, "Torso", "torsoLength", "Torso length", 0.56f, new SkeletonNodeOffset[]{SkeletonNodeOffset.WAIST}),
|
||||
CHEST(4, "Chest", "chestDistance", "Chest distance", 0.32f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CHEST, SkeletonNodeOffset.WAIST, SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
WAIST(5, "Waist", "waistDistance", "Waist distance", 0.04f, new SkeletonNodeOffset[]{SkeletonNodeOffset.WAIST, SkeletonNodeOffset.HIP}),
|
||||
HIP_OFFSET(6, "Hip offset", "hipOffset", "Hip offset", 0.0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.HIP_TRACKER}),
|
||||
HIPS_WIDTH(7, "Hips width", "hipsWidth", "Hips width", 0.26f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_HIP, SkeletonNodeOffset.RIGHT_HIP}),
|
||||
LEGS_LENGTH(8, "Legs length", "legsLength", "Legs length", 0.92f, new SkeletonNodeOffset[]{SkeletonNodeOffset.KNEE}),
|
||||
KNEE_HEIGHT(9, "Knee height", "kneeHeight", "Knee height", 0.50f, new SkeletonNodeOffset[]{SkeletonNodeOffset.KNEE, SkeletonNodeOffset.ANKLE}),
|
||||
FOOT_LENGTH(10, "Foot length", "footLength", "Foot length", 0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.FOOT}),
|
||||
FOOT_OFFSET(11, "Foot offset", "footOffset", "Foot offset", -0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.ANKLE}),
|
||||
SKELETON_OFFSET(12, "Skeleton offset", "skeletonOffset", "Skeleton offset", 0.0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CHEST_TRACKER, SkeletonNodeOffset.HIP_TRACKER, SkeletonNodeOffset.KNEE_TRACKER, SkeletonNodeOffset.FOOT_TRACKER}),
|
||||
CONTROLLER_DISTANCE_Z(13, "Controller distance z", "controllerDistanceZ", "Controller distance z", 0.15f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND}),
|
||||
CONTROLLER_DISTANCE_Y(14, "Controller distance y", "controllerDistanceY", "Controller distance y", 0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND}),
|
||||
FOREARM_LENGTH(15, "Forearm length", "forearmLength", "Forearm length", 0.25f, new SkeletonNodeOffset[]{SkeletonNodeOffset.FOREARM_CONTRL, SkeletonNodeOffset.FOREARM_HMD}),
|
||||
SHOULDERS_DISTANCE(16, "Shoulders distance", "shoulersDistance", "Shoulders distance", 0.08f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
SHOULDERS_WIDTH(17, "Shoulders width", "shoulersWidth", "Shoulders width", 0.36f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
UPPER_ARM_LENGTH(18, "Upper arm length", "upperArmLength", "Upper arm length", 0.25f, new SkeletonNodeOffset[]{SkeletonNodeOffset.UPPER_ARM}),
|
||||
ELBOW_OFFSET(19, "Elbow offset", "elbowOffset", "Elbow offset", 0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.ELBOW_TRACKER}),
|
||||
;
|
||||
HEAD(1, "Head", "headShift", "Head shift", 0.1f, new SkeletonNodeOffset[]{SkeletonNodeOffset.HEAD}),
|
||||
NECK(2, "Neck", "neckLength", "Neck length", 0.1f, new SkeletonNodeOffset[]{SkeletonNodeOffset.NECK}),
|
||||
TORSO(3, "Torso", "torsoLength", "Torso length", 0.56f, new SkeletonNodeOffset[]{SkeletonNodeOffset.WAIST}),
|
||||
CHEST(4, "Chest", "chestDistance", "Chest distance", 0.32f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CHEST, SkeletonNodeOffset.WAIST, SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
WAIST(5, "Waist", "waistDistance", "Waist distance", 0.04f, new SkeletonNodeOffset[]{SkeletonNodeOffset.WAIST, SkeletonNodeOffset.HIP}),
|
||||
HIP_OFFSET(6, "Hip offset", "hipOffset", "Hip offset", 0.0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.HIP_TRACKER}),
|
||||
HIPS_WIDTH(7, "Hips width", "hipsWidth", "Hips width", 0.26f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_HIP, SkeletonNodeOffset.RIGHT_HIP}),
|
||||
LEGS_LENGTH(8, "Legs length", "legsLength", "Legs length", 0.92f, new SkeletonNodeOffset[]{SkeletonNodeOffset.KNEE}),
|
||||
KNEE_HEIGHT(9, "Knee height", "kneeHeight", "Knee height", 0.50f, new SkeletonNodeOffset[]{SkeletonNodeOffset.KNEE, SkeletonNodeOffset.ANKLE}),
|
||||
FOOT_LENGTH(10, "Foot length", "footLength", "Foot length", 0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.FOOT}),
|
||||
FOOT_OFFSET(11, "Foot offset", "footOffset", "Foot offset", -0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.ANKLE}),
|
||||
SKELETON_OFFSET(12, "Skeleton offset", "skeletonOffset", "Skeleton offset", 0.0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CHEST_TRACKER, SkeletonNodeOffset.HIP_TRACKER, SkeletonNodeOffset.KNEE_TRACKER, SkeletonNodeOffset.FOOT_TRACKER}),
|
||||
CONTROLLER_DISTANCE_Z(13, "Controller distance z", "controllerDistanceZ", "Controller distance z", 0.15f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND}),
|
||||
CONTROLLER_DISTANCE_Y(14, "Controller distance y", "controllerDistanceY", "Controller distance y", 0.05f, new SkeletonNodeOffset[]{SkeletonNodeOffset.CONTROLLER, SkeletonNodeOffset.HAND}),
|
||||
FOREARM_LENGTH(15, "Forearm length", "forearmLength", "Forearm length", 0.25f, new SkeletonNodeOffset[]{SkeletonNodeOffset.FOREARM_CONTRL, SkeletonNodeOffset.FOREARM_HMD}),
|
||||
SHOULDERS_DISTANCE(16, "Shoulders distance", "shoulersDistance", "Shoulders distance", 0.08f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
SHOULDERS_WIDTH(17, "Shoulders width", "shoulersWidth", "Shoulders width", 0.36f, new SkeletonNodeOffset[]{SkeletonNodeOffset.LEFT_SHOULDER, SkeletonNodeOffset.RIGHT_SHOULDER}),
|
||||
UPPER_ARM_LENGTH(18, "Upper arm length", "upperArmLength", "Upper arm length", 0.25f, new SkeletonNodeOffset[]{SkeletonNodeOffset.UPPER_ARM}),
|
||||
ELBOW_OFFSET(19, "Elbow offset", "elbowOffset", "Elbow offset", 0f, new SkeletonNodeOffset[]{SkeletonNodeOffset.ELBOW_TRACKER}),
|
||||
;
|
||||
|
||||
public static final SkeletonConfigValue[] values = values();
|
||||
private static final String CONFIG_PREFIX = "body.";
|
||||
private static final Map<String, SkeletonConfigValue> byStringVal = new HashMap<>();
|
||||
private static final Map<Number, SkeletonConfigValue> byIdVal = new HashMap<>();
|
||||
public static final SkeletonConfigValue[] values = values();
|
||||
private static final String CONFIG_PREFIX = "body.";
|
||||
private static final Map<String, SkeletonConfigValue> byStringVal = new HashMap<>();
|
||||
private static final Map<Number, SkeletonConfigValue> byIdVal = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (SkeletonConfigValue configVal : values()) {
|
||||
byIdVal.put(configVal.id, configVal);
|
||||
byStringVal.put(configVal.stringVal.toLowerCase(), configVal);
|
||||
}
|
||||
}
|
||||
static {
|
||||
for (SkeletonConfigValue configVal : values()) {
|
||||
byIdVal.put(configVal.id, configVal);
|
||||
byStringVal.put(configVal.stringVal.toLowerCase(), configVal);
|
||||
}
|
||||
}
|
||||
|
||||
public final int id;
|
||||
public final String stringVal;
|
||||
public final String configKey;
|
||||
public final String label;
|
||||
public final float defaultValue;
|
||||
public final SkeletonNodeOffset[] affectedOffsets;
|
||||
public final int id;
|
||||
public final String stringVal;
|
||||
public final String configKey;
|
||||
public final String label;
|
||||
public final float defaultValue;
|
||||
public final SkeletonNodeOffset[] affectedOffsets;
|
||||
|
||||
SkeletonConfigValue(int id, String stringVal, String configKey, String label, float defaultValue, SkeletonNodeOffset[] affectedOffsets) {
|
||||
this.id = id;
|
||||
this.stringVal = stringVal;
|
||||
this.configKey = CONFIG_PREFIX + configKey;
|
||||
this.label = label;
|
||||
SkeletonConfigValue(int id, String stringVal, String configKey, String label, float defaultValue, SkeletonNodeOffset[] affectedOffsets) {
|
||||
this.id = id;
|
||||
this.stringVal = stringVal;
|
||||
this.configKey = CONFIG_PREFIX + configKey;
|
||||
this.label = label;
|
||||
|
||||
this.defaultValue = defaultValue;
|
||||
this.defaultValue = defaultValue;
|
||||
|
||||
this.affectedOffsets = affectedOffsets == null ? new SkeletonNodeOffset[0] : affectedOffsets;
|
||||
}
|
||||
this.affectedOffsets = affectedOffsets == null ? new SkeletonNodeOffset[0] : affectedOffsets;
|
||||
}
|
||||
|
||||
public static SkeletonConfigValue getByStringValue(String stringVal) {
|
||||
return stringVal == null ? null : byStringVal.get(stringVal.toLowerCase());
|
||||
}
|
||||
public static SkeletonConfigValue getByStringValue(String stringVal) {
|
||||
return stringVal == null ? null : byStringVal.get(stringVal.toLowerCase());
|
||||
}
|
||||
|
||||
public static SkeletonConfigValue getById(int id) {
|
||||
return byIdVal.get(id);
|
||||
}
|
||||
public static SkeletonConfigValue getById(int id) {
|
||||
return byIdVal.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,29 +2,29 @@ package dev.slimevr.vr.processor.skeleton;
|
||||
|
||||
public enum SkeletonNodeOffset {
|
||||
|
||||
HEAD,
|
||||
NECK,
|
||||
CHEST,
|
||||
CHEST_TRACKER,
|
||||
WAIST,
|
||||
HIP,
|
||||
HIP_TRACKER,
|
||||
LEFT_HIP,
|
||||
RIGHT_HIP,
|
||||
KNEE,
|
||||
KNEE_TRACKER,
|
||||
ANKLE,
|
||||
FOOT,
|
||||
FOOT_TRACKER,
|
||||
CONTROLLER,
|
||||
FOREARM_CONTRL,
|
||||
FOREARM_HMD,
|
||||
ELBOW_TRACKER,
|
||||
UPPER_ARM,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
HAND,
|
||||
HAND_TRACKER;
|
||||
HEAD,
|
||||
NECK,
|
||||
CHEST,
|
||||
CHEST_TRACKER,
|
||||
WAIST,
|
||||
HIP,
|
||||
HIP_TRACKER,
|
||||
LEFT_HIP,
|
||||
RIGHT_HIP,
|
||||
KNEE,
|
||||
KNEE_TRACKER,
|
||||
ANKLE,
|
||||
FOOT,
|
||||
FOOT_TRACKER,
|
||||
CONTROLLER,
|
||||
FOREARM_CONTRL,
|
||||
FOREARM_HMD,
|
||||
ELBOW_TRACKER,
|
||||
UPPER_ARM,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
HAND,
|
||||
HAND_TRACKER;
|
||||
|
||||
public static final SkeletonNodeOffset[] values = values();
|
||||
public static final SkeletonNodeOffset[] values = values();
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import java.util.function.Consumer;
|
||||
|
||||
public interface CalibratingTracker {
|
||||
|
||||
void startCalibration(Consumer<String> calibrationDataConsumer);
|
||||
void startCalibration(Consumer<String> calibrationDataConsumer);
|
||||
|
||||
void requestCalibrationData(Consumer<String> calibrationDataConsumer);
|
||||
void requestCalibrationData(Consumer<String> calibrationDataConsumer);
|
||||
|
||||
void uploadNewClibrationData();
|
||||
void uploadNewClibrationData();
|
||||
}
|
||||
|
||||
@@ -14,90 +14,90 @@ import java.util.*;
|
||||
*/
|
||||
|
||||
public class CircularArrayList<E>
|
||||
extends AbstractList<E> implements RandomAccess {
|
||||
extends AbstractList<E> implements RandomAccess {
|
||||
|
||||
private final int n; // buffer length
|
||||
private final List<E> buf; // a List implementing RandomAccess
|
||||
private int head = 0;
|
||||
private int tail = 0;
|
||||
private final int n; // buffer length
|
||||
private final List<E> buf; // a List implementing RandomAccess
|
||||
private int head = 0;
|
||||
private int tail = 0;
|
||||
|
||||
public CircularArrayList(int capacity) {
|
||||
n = capacity + 1;
|
||||
buf = new ArrayList<E>(Collections.nCopies(n, null));
|
||||
}
|
||||
public CircularArrayList(int capacity) {
|
||||
n = capacity + 1;
|
||||
buf = new ArrayList<E>(Collections.nCopies(n, null));
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
return n - 1;
|
||||
}
|
||||
public int capacity() {
|
||||
return n - 1;
|
||||
}
|
||||
|
||||
private int wrapIndex(int i) {
|
||||
int m = i % n;
|
||||
if (m < 0) { // java modulus can be negative
|
||||
m += n;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
private int wrapIndex(int i) {
|
||||
int m = i % n;
|
||||
if (m < 0) { // java modulus can be negative
|
||||
m += n;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// This method is O(n) but will never be called if the
|
||||
// CircularArrayList is used in its typical/intended role.
|
||||
private void shiftBlock(int startIndex, int endIndex) {
|
||||
assert (endIndex > startIndex);
|
||||
for (int i = endIndex - 1; i >= startIndex; i--) {
|
||||
set(i + 1, get(i));
|
||||
}
|
||||
}
|
||||
// This method is O(n) but will never be called if the
|
||||
// CircularArrayList is used in its typical/intended role.
|
||||
private void shiftBlock(int startIndex, int endIndex) {
|
||||
assert (endIndex > startIndex);
|
||||
for (int i = endIndex - 1; i >= startIndex; i--) {
|
||||
set(i + 1, get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return tail - head + (tail < head ? n : 0);
|
||||
}
|
||||
@Override
|
||||
public int size() {
|
||||
return tail - head + (tail < head ? n : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int i) {
|
||||
if (i < 0 || i >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return buf.get(wrapIndex(head + i));
|
||||
}
|
||||
@Override
|
||||
public E get(int i) {
|
||||
if (i < 0 || i >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return buf.get(wrapIndex(head + i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public E set(int i, E e) {
|
||||
if (i < 0 || i >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return buf.set(wrapIndex(head + i), e);
|
||||
}
|
||||
@Override
|
||||
public E set(int i, E e) {
|
||||
if (i < 0 || i >= size()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return buf.set(wrapIndex(head + i), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int i, E e) {
|
||||
int s = size();
|
||||
if (s == n - 1) {
|
||||
throw new IllegalStateException(
|
||||
"CircularArrayList is filled to capacity. "
|
||||
+ "(You may want to remove from front"
|
||||
+ " before adding more to back.)");
|
||||
}
|
||||
if (i < 0 || i > s) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
tail = wrapIndex(tail + 1);
|
||||
if (i < s) {
|
||||
shiftBlock(i, s);
|
||||
}
|
||||
set(i, e);
|
||||
}
|
||||
@Override
|
||||
public void add(int i, E e) {
|
||||
int s = size();
|
||||
if (s == n - 1) {
|
||||
throw new IllegalStateException(
|
||||
"CircularArrayList is filled to capacity. "
|
||||
+ "(You may want to remove from front"
|
||||
+ " before adding more to back.)");
|
||||
}
|
||||
if (i < 0 || i > s) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
tail = wrapIndex(tail + 1);
|
||||
if (i < s) {
|
||||
shiftBlock(i, s);
|
||||
}
|
||||
set(i, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int i) {
|
||||
int s = size();
|
||||
if (i < 0 || i >= s) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
E e = get(i);
|
||||
if (i > 0) {
|
||||
shiftBlock(0, i);
|
||||
}
|
||||
head = wrapIndex(head + 1);
|
||||
return e;
|
||||
}
|
||||
@Override
|
||||
public E remove(int i) {
|
||||
int s = size();
|
||||
if (i < 0 || i >= s) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
E e = get(i);
|
||||
if (i > 0) {
|
||||
shiftBlock(0, i);
|
||||
}
|
||||
head = wrapIndex(head + 1);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,140 +6,140 @@ import dev.slimevr.vr.trackers.udp.Device;
|
||||
|
||||
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 final boolean hasRotation;
|
||||
protected final boolean hasPosition;
|
||||
protected final int trackerId;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
protected TrackerStatus status = TrackerStatus.DISCONNECTED;
|
||||
public final Vector3f position = new Vector3f();
|
||||
public final Quaternion rotation = new Quaternion();
|
||||
protected final String name;
|
||||
protected final String serial;
|
||||
protected final boolean hasRotation;
|
||||
protected final boolean hasPosition;
|
||||
protected final int trackerId;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
protected TrackerStatus status = TrackerStatus.DISCONNECTED;
|
||||
|
||||
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 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);
|
||||
}
|
||||
public ComputedTracker(int trackerId, String name, boolean hasRotation, boolean hasPosition) {
|
||||
this(trackerId, name, name, hasRotation, hasPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
config.setDesignation(bodyPosition == null ? null : bodyPosition.designation);
|
||||
}
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
config.setDesignation(bodyPosition == null ? null : bodyPosition.designation);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 = TrackerPosition.getByDesignation(config.designation);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
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 = TrackerPosition.getByDesignation(config.designation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.serial;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.serial;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.name;
|
||||
}
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
store.set(position);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
store.set(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
store.set(rotation);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
store.set(rotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(TrackerStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
public void setStatus(TrackerStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1.0f;
|
||||
}
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
}
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
}
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
}
|
||||
@Override
|
||||
public void dataTick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return hasRotation;
|
||||
}
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return hasRotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return hasPosition;
|
||||
}
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return hasPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package dev.slimevr.vr.trackers;
|
||||
|
||||
public enum DeviceType {
|
||||
HMD,
|
||||
CONTROLLER,
|
||||
TRACKER,
|
||||
TRACKING_REFERENCE,
|
||||
HMD,
|
||||
CONTROLLER,
|
||||
TRACKER,
|
||||
TRACKING_REFERENCE,
|
||||
}
|
||||
|
||||
@@ -4,25 +4,25 @@ import io.eiren.util.BufferedTimer;
|
||||
|
||||
public class HMDTracker extends ComputedTracker implements TrackerWithTPS {
|
||||
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public HMDTracker(String name) {
|
||||
super(0, name, true, true);
|
||||
setBodyPosition(TrackerPosition.HMD);
|
||||
}
|
||||
public HMDTracker(String name) {
|
||||
super(0, name, true, true);
|
||||
setBodyPosition(TrackerPosition.HMD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,310 +10,310 @@ import io.eiren.util.BufferedTimer;
|
||||
|
||||
public class IMUTracker implements Tracker, TrackerWithTPS, TrackerWithBattery {
|
||||
|
||||
public static final float MAX_MAG_CORRECTION_ACCURACY = 5 * FastMath.RAD_TO_DEG;
|
||||
public static final float MAX_MAG_CORRECTION_ACCURACY = 5 * FastMath.RAD_TO_DEG;
|
||||
|
||||
//public final Vector3f gyroVector = new Vector3f();
|
||||
//public final Vector3f accelVector = new Vector3f();
|
||||
public final Vector3f magVector = new Vector3f();
|
||||
public final Quaternion rotQuaternion = new Quaternion();
|
||||
public final Quaternion rotMagQuaternion = new Quaternion();
|
||||
public final Quaternion rotAdjust = new Quaternion();
|
||||
public final Device device;
|
||||
public final int trackerNum;
|
||||
protected final Quaternion correction = new Quaternion();
|
||||
protected final int trackerId;
|
||||
protected final String name;
|
||||
protected final String descriptiveName;
|
||||
protected final TrackersUDPServer server;
|
||||
protected final VRServer vrserver;
|
||||
private final Quaternion buffQuat = new Quaternion();
|
||||
public int movementFilterTickCount = 0;
|
||||
public float movementFilterAmount = 1f;
|
||||
public int calibrationStatus = 0;
|
||||
public int magCalibrationStatus = 0;
|
||||
public float magnetometerAccuracy = 0;
|
||||
public boolean hasNewCorrectionData = false;
|
||||
public int ping = -1;
|
||||
public int signalStrength = -1;
|
||||
public float temperature = 0;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
protected CircularArrayList<Quaternion> previousRots;
|
||||
protected Quaternion mounting = null;
|
||||
protected TrackerStatus status = TrackerStatus.OK;
|
||||
protected float confidence = 0;
|
||||
protected float batteryVoltage = 0;
|
||||
protected float batteryLevel = 0;
|
||||
protected boolean magentometerCalibrated = false;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
//public final Vector3f gyroVector = new Vector3f();
|
||||
//public final Vector3f accelVector = new Vector3f();
|
||||
public final Vector3f magVector = new Vector3f();
|
||||
public final Quaternion rotQuaternion = new Quaternion();
|
||||
public final Quaternion rotMagQuaternion = new Quaternion();
|
||||
public final Quaternion rotAdjust = new Quaternion();
|
||||
public final Device device;
|
||||
public final int trackerNum;
|
||||
protected final Quaternion correction = new Quaternion();
|
||||
protected final int trackerId;
|
||||
protected final String name;
|
||||
protected final String descriptiveName;
|
||||
protected final TrackersUDPServer server;
|
||||
protected final VRServer vrserver;
|
||||
private final Quaternion buffQuat = new Quaternion();
|
||||
public int movementFilterTickCount = 0;
|
||||
public float movementFilterAmount = 1f;
|
||||
public int calibrationStatus = 0;
|
||||
public int magCalibrationStatus = 0;
|
||||
public float magnetometerAccuracy = 0;
|
||||
public boolean hasNewCorrectionData = false;
|
||||
public int ping = -1;
|
||||
public int signalStrength = -1;
|
||||
public float temperature = 0;
|
||||
public TrackerPosition bodyPosition = null;
|
||||
protected CircularArrayList<Quaternion> previousRots;
|
||||
protected Quaternion mounting = null;
|
||||
protected TrackerStatus status = TrackerStatus.OK;
|
||||
protected float confidence = 0;
|
||||
protected float batteryVoltage = 0;
|
||||
protected float batteryLevel = 0;
|
||||
protected boolean magentometerCalibrated = false;
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public IMUTracker(Device device, int trackerId, int trackerNum, String name, String descriptiveName, TrackersUDPServer server, VRServer vrserver) {
|
||||
this.device = device;
|
||||
this.trackerNum = trackerNum;
|
||||
this.name = name;
|
||||
this.server = server;
|
||||
this.trackerId = trackerId;
|
||||
this.descriptiveName = descriptiveName;
|
||||
this.vrserver = vrserver;
|
||||
}
|
||||
public IMUTracker(Device device, int trackerId, int trackerNum, String name, String descriptiveName, TrackersUDPServer server, VRServer vrserver) {
|
||||
this.device = device;
|
||||
this.trackerNum = trackerNum;
|
||||
this.name = name;
|
||||
this.server = server;
|
||||
this.trackerId = trackerId;
|
||||
this.descriptiveName = descriptiveName;
|
||||
this.vrserver = vrserver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
config.setDesignation(bodyPosition == null ? null : bodyPosition.designation);
|
||||
config.mountingRotation = mounting != null ? mounting : null;
|
||||
}
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
config.setDesignation(bodyPosition == null ? null : bodyPosition.designation);
|
||||
config.mountingRotation = mounting != null ? mounting : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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()) {
|
||||
if (config.mountingRotation != null) {
|
||||
mounting = config.mountingRotation;
|
||||
rotAdjust.set(config.mountingRotation);
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
setFilter(vrserver.config.getString("filters.type"), vrserver.config.getFloat("filters.amount", 0.3f), vrserver.config.getInt("filters.tickCount", 1));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
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()) {
|
||||
if (config.mountingRotation != null) {
|
||||
mounting = config.mountingRotation;
|
||||
rotAdjust.set(config.mountingRotation);
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
bodyPosition = TrackerPosition.getByDesignation(config.designation);
|
||||
setFilter(vrserver.config.getString("filters.type"), vrserver.config.getFloat("filters.amount", 0.3f), vrserver.config.getInt("filters.tickCount", 1));
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilter(String type, float amount, int ticks) {
|
||||
amount = FastMath.clamp(amount, 0, 1f);
|
||||
ticks = (int) FastMath.clamp(ticks, 0, 50);
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
case "INTERPOLATION":
|
||||
movementFilterAmount = 1f - (amount / 1.6f);
|
||||
movementFilterTickCount = ticks;
|
||||
break;
|
||||
case "EXTRAPOLATION":
|
||||
movementFilterAmount = 1f + (amount * 1.1f);
|
||||
movementFilterTickCount = ticks;
|
||||
break;
|
||||
case "NONE":
|
||||
default:
|
||||
movementFilterAmount = 1f;
|
||||
movementFilterTickCount = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
movementFilterAmount = 1f;
|
||||
movementFilterTickCount = 0;
|
||||
}
|
||||
previousRots = new CircularArrayList<Quaternion>(movementFilterTickCount + 1);
|
||||
}
|
||||
public void setFilter(String type, float amount, int ticks) {
|
||||
amount = FastMath.clamp(amount, 0, 1f);
|
||||
ticks = (int) FastMath.clamp(ticks, 0, 50);
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
case "INTERPOLATION":
|
||||
movementFilterAmount = 1f - (amount / 1.6f);
|
||||
movementFilterTickCount = ticks;
|
||||
break;
|
||||
case "EXTRAPOLATION":
|
||||
movementFilterAmount = 1f + (amount * 1.1f);
|
||||
movementFilterTickCount = ticks;
|
||||
break;
|
||||
case "NONE":
|
||||
default:
|
||||
movementFilterAmount = 1f;
|
||||
movementFilterTickCount = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
movementFilterAmount = 1f;
|
||||
movementFilterTickCount = 0;
|
||||
}
|
||||
previousRots = new CircularArrayList<Quaternion>(movementFilterTickCount + 1);
|
||||
}
|
||||
|
||||
public Quaternion getMountingRotation() {
|
||||
return mounting;
|
||||
}
|
||||
public Quaternion getMountingRotation() {
|
||||
return mounting;
|
||||
}
|
||||
|
||||
public void setMountingRotation(Quaternion mr) {
|
||||
mounting = mr;
|
||||
if (mounting != null) {
|
||||
rotAdjust.set(mounting);
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
}
|
||||
public void setMountingRotation(Quaternion mr) {
|
||||
mounting = mr;
|
||||
if (mounting != null) {
|
||||
rotAdjust.set(mounting);
|
||||
} else {
|
||||
rotAdjust.loadIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (magentometerCalibrated && hasNewCorrectionData) {
|
||||
hasNewCorrectionData = false;
|
||||
if (magnetometerAccuracy <= MAX_MAG_CORRECTION_ACCURACY) {
|
||||
// Adjust gyro rotation to match magnetometer rotation only if magnetometer
|
||||
// accuracy is within the parameters
|
||||
calculateLiveMagnetometerCorrection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
if (magentometerCalibrated && hasNewCorrectionData) {
|
||||
hasNewCorrectionData = false;
|
||||
if (magnetometerAccuracy <= MAX_MAG_CORRECTION_ACCURACY) {
|
||||
// Adjust gyro rotation to match magnetometer rotation only if magnetometer
|
||||
// accuracy is within the parameters
|
||||
calculateLiveMagnetometerCorrection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
store.set(0, 0, 0);
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
store.set(0, 0, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
if (movementFilterTickCount > 0 && movementFilterAmount != 1 && previousRots.size() > 0) {
|
||||
buffQuat.set(previousRots.get(0));
|
||||
buffQuat.slerp(rotQuaternion, movementFilterAmount);
|
||||
store.set(buffQuat);
|
||||
} else {
|
||||
store.set(rotQuaternion);
|
||||
}
|
||||
//correction.mult(store, store); // Correction is not used now to prevent accidental errors while debugging other things
|
||||
store.multLocal(rotAdjust);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
if (movementFilterTickCount > 0 && movementFilterAmount != 1 && previousRots.size() > 0) {
|
||||
buffQuat.set(previousRots.get(0));
|
||||
buffQuat.slerp(rotQuaternion, movementFilterAmount);
|
||||
store.set(buffQuat);
|
||||
} else {
|
||||
store.set(rotQuaternion);
|
||||
}
|
||||
//correction.mult(store, store); // Correction is not used now to prevent accidental errors while debugging other things
|
||||
store.multLocal(rotAdjust);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void getCorrection(Quaternion store) {
|
||||
store.set(correction);
|
||||
}
|
||||
public void getCorrection(Quaternion store) {
|
||||
store.set(correction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(TrackerStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
public void setStatus(TrackerStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
|
||||
if (movementFilterTickCount != 0) {
|
||||
previousRots.add(rotQuaternion.clone());
|
||||
if (previousRots.size() > movementFilterTickCount) {
|
||||
previousRots.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (movementFilterTickCount != 0) {
|
||||
previousRots.add(rotQuaternion.clone());
|
||||
if (previousRots.size() > movementFilterTickCount) {
|
||||
previousRots.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return confidence;
|
||||
}
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return confidence;
|
||||
}
|
||||
|
||||
public void setConfidence(float newConf) {
|
||||
this.confidence = newConf;
|
||||
}
|
||||
public void setConfidence(float newConf) {
|
||||
this.confidence = newConf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBatteryLevel() {
|
||||
return batteryLevel;
|
||||
}
|
||||
@Override
|
||||
public float getBatteryLevel() {
|
||||
return batteryLevel;
|
||||
}
|
||||
|
||||
public void setBatteryLevel(float level) {
|
||||
this.batteryLevel = level;
|
||||
}
|
||||
public void setBatteryLevel(float level) {
|
||||
this.batteryLevel = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBatteryVoltage() {
|
||||
return batteryVoltage;
|
||||
}
|
||||
@Override
|
||||
public float getBatteryVoltage() {
|
||||
return batteryVoltage;
|
||||
}
|
||||
|
||||
public void setBatteryVoltage(float voltage) {
|
||||
this.batteryVoltage = voltage;
|
||||
}
|
||||
public void setBatteryVoltage(float voltage) {
|
||||
this.batteryVoltage = voltage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
resetYaw(reference);
|
||||
}
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
resetYaw(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not perform actual gyro reset to reference, that's the task of
|
||||
* reference adjusted tracker. Only aligns gyro with magnetometer if
|
||||
* it's reliable
|
||||
*/
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
if (magCalibrationStatus >= CalibrationAccuracy.HIGH.status) {
|
||||
magentometerCalibrated = true;
|
||||
// During calibration set correction to match magnetometer readings exactly
|
||||
// TODO : Correct only yaw
|
||||
correction.set(rotQuaternion).inverseLocal().multLocal(rotMagQuaternion);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Does not perform actual gyro reset to reference, that's the task of
|
||||
* reference adjusted tracker. Only aligns gyro with magnetometer if
|
||||
* it's reliable
|
||||
*/
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
if (magCalibrationStatus >= CalibrationAccuracy.HIGH.status) {
|
||||
magentometerCalibrated = true;
|
||||
// During calibration set correction to match magnetometer readings exactly
|
||||
// TODO : Correct only yaw
|
||||
correction.set(rotQuaternion).inverseLocal().multLocal(rotMagQuaternion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate correction between normal and magnetometer
|
||||
* readings up to accuracy threshold
|
||||
*/
|
||||
protected void calculateLiveMagnetometerCorrection() {
|
||||
// TODO Magic, correct only yaw
|
||||
// TODO Print "jump" length when correcting if it's more than 1 degree
|
||||
}
|
||||
/**
|
||||
* Calculate correction between normal and magnetometer
|
||||
* readings up to accuracy threshold
|
||||
*/
|
||||
protected void calculateLiveMagnetometerCorrection() {
|
||||
// TODO Magic, correct only yaw
|
||||
// TODO Print "jump" length when correcting if it's more than 1 degree
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return bodyPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
this.bodyPosition = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return this.trackerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return this.trackerNum;
|
||||
}
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return this.trackerNum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return this.device;
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return this.device;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.descriptiveName;
|
||||
}
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return this.descriptiveName;
|
||||
}
|
||||
|
||||
public enum CalibrationAccuracy {
|
||||
public enum CalibrationAccuracy {
|
||||
|
||||
UNRELIABLE(0),
|
||||
LOW(1),
|
||||
MEDIUM(2),
|
||||
HIGH(3),
|
||||
;
|
||||
UNRELIABLE(0),
|
||||
LOW(1),
|
||||
MEDIUM(2),
|
||||
HIGH(3),
|
||||
;
|
||||
|
||||
private static final CalibrationAccuracy[] byStatus = new CalibrationAccuracy[4];
|
||||
private static final CalibrationAccuracy[] byStatus = new CalibrationAccuracy[4];
|
||||
|
||||
static {
|
||||
for (CalibrationAccuracy ca : values())
|
||||
byStatus[ca.status] = ca;
|
||||
}
|
||||
static {
|
||||
for (CalibrationAccuracy ca : values())
|
||||
byStatus[ca.status] = ca;
|
||||
}
|
||||
|
||||
public final int status;
|
||||
public final int status;
|
||||
|
||||
CalibrationAccuracy(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
CalibrationAccuracy(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public static CalibrationAccuracy getByStatus(int status) {
|
||||
if (status < 0 || status > 3)
|
||||
return null;
|
||||
return byStatus[status];
|
||||
}
|
||||
}
|
||||
public static CalibrationAccuracy getByStatus(int status) {
|
||||
if (status < 0 || status > 3)
|
||||
return null;
|
||||
return byStatus[status];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,109 +8,109 @@ import java.nio.ByteBuffer;
|
||||
|
||||
public class MPUTracker extends IMUTracker {
|
||||
|
||||
public ConfigurationData newCalibrationData;
|
||||
public ConfigurationData newCalibrationData;
|
||||
|
||||
public MPUTracker(Device device, int trackerId, int trackerNum, String name, String descriptiveName, TrackersUDPServer server, VRServer vrserver) {
|
||||
super(device, trackerId, trackerNum, name, descriptiveName, server, vrserver);
|
||||
}
|
||||
public MPUTracker(Device device, int trackerId, int trackerNum, String name, String descriptiveName, TrackersUDPServer server, VRServer vrserver) {
|
||||
super(device, trackerId, trackerNum, name, descriptiveName, server, vrserver);
|
||||
}
|
||||
|
||||
public static class ConfigurationData {
|
||||
public static class ConfigurationData {
|
||||
|
||||
//accel offsets and correction matrix
|
||||
float[] A_B = new float[3];
|
||||
float[][] A_Ainv = new float[3][3];
|
||||
// mag offsets and correction matrix
|
||||
float[] M_B = new float[3];
|
||||
float[][] M_Ainv = new float[3][3];
|
||||
//raw offsets, determined for gyro at rest
|
||||
float[] G_off = new float[3];
|
||||
int deviceId = -1;
|
||||
int deviceMode = -1;
|
||||
//accel offsets and correction matrix
|
||||
float[] A_B = new float[3];
|
||||
float[][] A_Ainv = new float[3][3];
|
||||
// mag offsets and correction matrix
|
||||
float[] M_B = new float[3];
|
||||
float[][] M_Ainv = new float[3][3];
|
||||
//raw offsets, determined for gyro at rest
|
||||
float[] G_off = new float[3];
|
||||
int deviceId = -1;
|
||||
int deviceMode = -1;
|
||||
|
||||
public ConfigurationData(double[] accelBasis, double[] accelAInv, double[] magBasis, double[] magAInv, double[] gyroOffset) {
|
||||
A_B[0] = (float) accelBasis[0];
|
||||
A_B[1] = (float) accelBasis[1];
|
||||
A_B[2] = (float) accelBasis[2];
|
||||
public ConfigurationData(double[] accelBasis, double[] accelAInv, double[] magBasis, double[] magAInv, double[] gyroOffset) {
|
||||
A_B[0] = (float) accelBasis[0];
|
||||
A_B[1] = (float) accelBasis[1];
|
||||
A_B[2] = (float) accelBasis[2];
|
||||
|
||||
A_Ainv[0][0] = (float) accelAInv[0];
|
||||
A_Ainv[0][1] = (float) accelAInv[1];
|
||||
A_Ainv[0][2] = (float) accelAInv[2];
|
||||
A_Ainv[1][0] = (float) accelAInv[3];
|
||||
A_Ainv[1][1] = (float) accelAInv[4];
|
||||
A_Ainv[1][2] = (float) accelAInv[5];
|
||||
A_Ainv[2][0] = (float) accelAInv[6];
|
||||
A_Ainv[2][1] = (float) accelAInv[7];
|
||||
A_Ainv[2][2] = (float) accelAInv[8];
|
||||
A_Ainv[0][0] = (float) accelAInv[0];
|
||||
A_Ainv[0][1] = (float) accelAInv[1];
|
||||
A_Ainv[0][2] = (float) accelAInv[2];
|
||||
A_Ainv[1][0] = (float) accelAInv[3];
|
||||
A_Ainv[1][1] = (float) accelAInv[4];
|
||||
A_Ainv[1][2] = (float) accelAInv[5];
|
||||
A_Ainv[2][0] = (float) accelAInv[6];
|
||||
A_Ainv[2][1] = (float) accelAInv[7];
|
||||
A_Ainv[2][2] = (float) accelAInv[8];
|
||||
|
||||
M_B[0] = (float) magBasis[0];
|
||||
M_B[1] = (float) magBasis[1];
|
||||
M_B[2] = (float) magBasis[2];
|
||||
M_B[0] = (float) magBasis[0];
|
||||
M_B[1] = (float) magBasis[1];
|
||||
M_B[2] = (float) magBasis[2];
|
||||
|
||||
M_Ainv[0][0] = (float) magAInv[0];
|
||||
M_Ainv[0][1] = (float) magAInv[1];
|
||||
M_Ainv[0][2] = (float) magAInv[2];
|
||||
M_Ainv[1][0] = (float) magAInv[3];
|
||||
M_Ainv[1][1] = (float) magAInv[4];
|
||||
M_Ainv[1][2] = (float) magAInv[5];
|
||||
M_Ainv[2][0] = (float) magAInv[6];
|
||||
M_Ainv[2][1] = (float) magAInv[7];
|
||||
M_Ainv[2][2] = (float) magAInv[8];
|
||||
M_Ainv[0][0] = (float) magAInv[0];
|
||||
M_Ainv[0][1] = (float) magAInv[1];
|
||||
M_Ainv[0][2] = (float) magAInv[2];
|
||||
M_Ainv[1][0] = (float) magAInv[3];
|
||||
M_Ainv[1][1] = (float) magAInv[4];
|
||||
M_Ainv[1][2] = (float) magAInv[5];
|
||||
M_Ainv[2][0] = (float) magAInv[6];
|
||||
M_Ainv[2][1] = (float) magAInv[7];
|
||||
M_Ainv[2][2] = (float) magAInv[8];
|
||||
|
||||
G_off[0] = (float) gyroOffset[0];
|
||||
G_off[1] = (float) gyroOffset[1];
|
||||
G_off[2] = (float) gyroOffset[2];
|
||||
}
|
||||
G_off[0] = (float) gyroOffset[0];
|
||||
G_off[1] = (float) gyroOffset[1];
|
||||
G_off[2] = (float) gyroOffset[2];
|
||||
}
|
||||
|
||||
public ConfigurationData(ByteBuffer buffer) {
|
||||
deviceMode = buffer.getInt();
|
||||
deviceId = buffer.getInt();
|
||||
// Data is read in reverse, because it was reversed when sending
|
||||
G_off[2] = buffer.getFloat();
|
||||
G_off[1] = buffer.getFloat();
|
||||
G_off[0] = buffer.getFloat();
|
||||
public ConfigurationData(ByteBuffer buffer) {
|
||||
deviceMode = buffer.getInt();
|
||||
deviceId = buffer.getInt();
|
||||
// Data is read in reverse, because it was reversed when sending
|
||||
G_off[2] = buffer.getFloat();
|
||||
G_off[1] = buffer.getFloat();
|
||||
G_off[0] = buffer.getFloat();
|
||||
|
||||
M_Ainv[2][2] = buffer.getFloat();
|
||||
M_Ainv[2][1] = buffer.getFloat();
|
||||
M_Ainv[2][0] = buffer.getFloat();
|
||||
M_Ainv[1][2] = buffer.getFloat();
|
||||
M_Ainv[1][1] = buffer.getFloat();
|
||||
M_Ainv[1][0] = buffer.getFloat();
|
||||
M_Ainv[0][2] = buffer.getFloat();
|
||||
M_Ainv[0][1] = buffer.getFloat();
|
||||
M_Ainv[0][0] = buffer.getFloat();
|
||||
M_Ainv[2][2] = buffer.getFloat();
|
||||
M_Ainv[2][1] = buffer.getFloat();
|
||||
M_Ainv[2][0] = buffer.getFloat();
|
||||
M_Ainv[1][2] = buffer.getFloat();
|
||||
M_Ainv[1][1] = buffer.getFloat();
|
||||
M_Ainv[1][0] = buffer.getFloat();
|
||||
M_Ainv[0][2] = buffer.getFloat();
|
||||
M_Ainv[0][1] = buffer.getFloat();
|
||||
M_Ainv[0][0] = buffer.getFloat();
|
||||
|
||||
M_B[2] = buffer.getFloat();
|
||||
M_B[1] = buffer.getFloat();
|
||||
M_B[0] = buffer.getFloat();
|
||||
M_B[2] = buffer.getFloat();
|
||||
M_B[1] = buffer.getFloat();
|
||||
M_B[0] = buffer.getFloat();
|
||||
|
||||
A_Ainv[2][2] = buffer.getFloat();
|
||||
A_Ainv[2][1] = buffer.getFloat();
|
||||
A_Ainv[2][0] = buffer.getFloat();
|
||||
A_Ainv[1][2] = buffer.getFloat();
|
||||
A_Ainv[1][1] = buffer.getFloat();
|
||||
A_Ainv[1][0] = buffer.getFloat();
|
||||
A_Ainv[0][2] = buffer.getFloat();
|
||||
A_Ainv[0][1] = buffer.getFloat();
|
||||
A_Ainv[0][0] = buffer.getFloat();
|
||||
A_Ainv[2][2] = buffer.getFloat();
|
||||
A_Ainv[2][1] = buffer.getFloat();
|
||||
A_Ainv[2][0] = buffer.getFloat();
|
||||
A_Ainv[1][2] = buffer.getFloat();
|
||||
A_Ainv[1][1] = buffer.getFloat();
|
||||
A_Ainv[1][0] = buffer.getFloat();
|
||||
A_Ainv[0][2] = buffer.getFloat();
|
||||
A_Ainv[0][1] = buffer.getFloat();
|
||||
A_Ainv[0][0] = buffer.getFloat();
|
||||
|
||||
A_B[2] = buffer.getFloat();
|
||||
A_B[1] = buffer.getFloat();
|
||||
A_B[0] = buffer.getFloat();
|
||||
}
|
||||
A_B[2] = buffer.getFloat();
|
||||
A_B[1] = buffer.getFloat();
|
||||
A_B[0] = buffer.getFloat();
|
||||
}
|
||||
|
||||
public String toTextMatrix() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("{%8.2f,%8.2f,%8.2f},\n", A_B[0], A_B[1], A_B[2]));
|
||||
sb.append(String.format("{{%9.5f,%9.5f,%9.5f},\n", A_Ainv[0][0], A_Ainv[0][1], A_Ainv[0][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f},\n", A_Ainv[1][0], A_Ainv[1][1], A_Ainv[1][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f}},\n", A_Ainv[2][0], A_Ainv[2][1], A_Ainv[2][2]));
|
||||
sb.append(String.format("{%8.2f,%8.2f,%8.2f},\n", M_B[0], M_B[1], M_B[2]));
|
||||
sb.append(String.format("{{%9.5f,%9.5f,%9.5f},\n", M_Ainv[0][0], M_Ainv[0][1], M_Ainv[0][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f},\n", M_Ainv[1][0], M_Ainv[1][1], M_Ainv[1][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f}},\n", M_Ainv[2][0], M_Ainv[2][1], M_Ainv[2][2]));
|
||||
sb.append(String.format("{%8.2f, %8.2f, %8.2f}};\n", G_off[0], G_off[1], G_off[2]));
|
||||
public String toTextMatrix() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(String.format("{%8.2f,%8.2f,%8.2f},\n", A_B[0], A_B[1], A_B[2]));
|
||||
sb.append(String.format("{{%9.5f,%9.5f,%9.5f},\n", A_Ainv[0][0], A_Ainv[0][1], A_Ainv[0][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f},\n", A_Ainv[1][0], A_Ainv[1][1], A_Ainv[1][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f}},\n", A_Ainv[2][0], A_Ainv[2][1], A_Ainv[2][2]));
|
||||
sb.append(String.format("{%8.2f,%8.2f,%8.2f},\n", M_B[0], M_B[1], M_B[2]));
|
||||
sb.append(String.format("{{%9.5f,%9.5f,%9.5f},\n", M_Ainv[0][0], M_Ainv[0][1], M_Ainv[0][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f},\n", M_Ainv[1][0], M_Ainv[1][1], M_Ainv[1][2]));
|
||||
sb.append(String.format(" {%9.5f,%9.5f,%9.5f}},\n", M_Ainv[2][0], M_Ainv[2][1], M_Ainv[2][2]));
|
||||
sb.append(String.format("{%8.2f, %8.2f, %8.2f}};\n", G_off[0], G_off[1], G_off[2]));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,178 +6,178 @@ import dev.slimevr.vr.trackers.udp.Device;
|
||||
|
||||
public class ReferenceAdjustedTracker<E extends Tracker> implements Tracker {
|
||||
|
||||
public final E tracker;
|
||||
public final Quaternion yawFix = new Quaternion();
|
||||
public final Quaternion gyroFix = new Quaternion();
|
||||
public final Quaternion attachmentFix = new Quaternion();
|
||||
protected float confidenceMultiplier = 1.0f;
|
||||
public final E tracker;
|
||||
public final Quaternion yawFix = new Quaternion();
|
||||
public final Quaternion gyroFix = new Quaternion();
|
||||
public final Quaternion attachmentFix = new Quaternion();
|
||||
protected float confidenceMultiplier = 1.0f;
|
||||
|
||||
public ReferenceAdjustedTracker(E tracker) {
|
||||
this.tracker = tracker;
|
||||
}
|
||||
public ReferenceAdjustedTracker(E tracker) {
|
||||
this.tracker = tracker;
|
||||
}
|
||||
|
||||
public E getTracker() {
|
||||
return this.tracker;
|
||||
}
|
||||
public E getTracker() {
|
||||
return this.tracker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return this.tracker.userEditable();
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return this.tracker.userEditable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
this.tracker.loadConfig(config);
|
||||
}
|
||||
@Override
|
||||
public void loadConfig(TrackerConfig config) {
|
||||
this.tracker.loadConfig(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
this.tracker.saveConfig(config);
|
||||
}
|
||||
@Override
|
||||
public void saveConfig(TrackerConfig config) {
|
||||
this.tracker.saveConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the tracker so that it's current rotation
|
||||
* is counted as (0, <HMD Yaw>, 0). This allows tracker
|
||||
* to be strapped to body at any pitch and roll.
|
||||
* <p>Performs {@link #resetYaw(Quaternion)} for yaw
|
||||
* drift correction.
|
||||
*/
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
tracker.resetFull(reference);
|
||||
fixGyroscope();
|
||||
/**
|
||||
* Reset the tracker so that it's current rotation
|
||||
* is counted as (0, <HMD Yaw>, 0). This allows tracker
|
||||
* to be strapped to body at any pitch and roll.
|
||||
* <p>Performs {@link #resetYaw(Quaternion)} for yaw
|
||||
* drift correction.
|
||||
*/
|
||||
@Override
|
||||
public void resetFull(Quaternion reference) {
|
||||
tracker.resetFull(reference);
|
||||
fixGyroscope();
|
||||
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
gyroFix.mult(sensorRotation, sensorRotation);
|
||||
attachmentFix.set(sensorRotation).inverseLocal();
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
gyroFix.mult(sensorRotation, sensorRotation);
|
||||
attachmentFix.set(sensorRotation).inverseLocal();
|
||||
|
||||
fixYaw(reference);
|
||||
}
|
||||
fixYaw(reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the tracker so that it's current yaw rotation
|
||||
* is counted as <HMD Yaw>. This allows the tracker
|
||||
* to have yaw independent of the HMD. Tracker should
|
||||
* still report yaw as if it was mounted facing HMD,
|
||||
* mounting position should be corrected in the source.
|
||||
*/
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
tracker.resetYaw(reference);
|
||||
fixYaw(reference);
|
||||
}
|
||||
/**
|
||||
* Reset the tracker so that it's current yaw rotation
|
||||
* is counted as <HMD Yaw>. This allows the tracker
|
||||
* to have yaw independent of the HMD. Tracker should
|
||||
* still report yaw as if it was mounted facing HMD,
|
||||
* mounting position should be corrected in the source.
|
||||
*/
|
||||
@Override
|
||||
public void resetYaw(Quaternion reference) {
|
||||
tracker.resetYaw(reference);
|
||||
fixYaw(reference);
|
||||
}
|
||||
|
||||
private void fixYaw(Quaternion reference) {
|
||||
// Use only yaw HMD rotation
|
||||
Quaternion targetTrackerRotation = new Quaternion(reference);
|
||||
float[] angles = new float[3];
|
||||
targetTrackerRotation.toAngles(angles);
|
||||
targetTrackerRotation.fromAngles(0, angles[1], 0);
|
||||
private void fixYaw(Quaternion reference) {
|
||||
// Use only yaw HMD rotation
|
||||
Quaternion targetTrackerRotation = new Quaternion(reference);
|
||||
float[] angles = new float[3];
|
||||
targetTrackerRotation.toAngles(angles);
|
||||
targetTrackerRotation.fromAngles(0, angles[1], 0);
|
||||
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
gyroFix.mult(sensorRotation, sensorRotation);
|
||||
sensorRotation.multLocal(attachmentFix);
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
gyroFix.mult(sensorRotation, sensorRotation);
|
||||
sensorRotation.multLocal(attachmentFix);
|
||||
|
||||
sensorRotation.toAngles(angles);
|
||||
sensorRotation.fromAngles(0, angles[1], 0);
|
||||
sensorRotation.toAngles(angles);
|
||||
sensorRotation.fromAngles(0, angles[1], 0);
|
||||
|
||||
yawFix.set(sensorRotation).inverseLocal().multLocal(targetTrackerRotation);
|
||||
}
|
||||
yawFix.set(sensorRotation).inverseLocal().multLocal(targetTrackerRotation);
|
||||
}
|
||||
|
||||
private void fixGyroscope() {
|
||||
float[] angles = new float[3];
|
||||
private void fixGyroscope() {
|
||||
float[] angles = new float[3];
|
||||
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
Quaternion sensorRotation = new Quaternion();
|
||||
tracker.getRotation(sensorRotation);
|
||||
|
||||
sensorRotation.toAngles(angles);
|
||||
sensorRotation.fromAngles(0, angles[1], 0);
|
||||
sensorRotation.toAngles(angles);
|
||||
sensorRotation.fromAngles(0, angles[1], 0);
|
||||
|
||||
gyroFix.set(sensorRotation).inverseLocal();
|
||||
}
|
||||
gyroFix.set(sensorRotation).inverseLocal();
|
||||
}
|
||||
|
||||
protected void adjustInternal(Quaternion store) {
|
||||
gyroFix.mult(store, store);
|
||||
store.multLocal(attachmentFix);
|
||||
yawFix.mult(store, store);
|
||||
}
|
||||
protected void adjustInternal(Quaternion store) {
|
||||
gyroFix.mult(store, store);
|
||||
store.multLocal(attachmentFix);
|
||||
yawFix.mult(store, store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
tracker.getRotation(store);
|
||||
adjustInternal(store);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean getRotation(Quaternion store) {
|
||||
tracker.getRotation(store);
|
||||
adjustInternal(store);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
return tracker.getPosition(store);
|
||||
}
|
||||
@Override
|
||||
public boolean getPosition(Vector3f store) {
|
||||
return tracker.getPosition(store);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return tracker.getName() + "/adj";
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return tracker.getName() + "/adj";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return tracker.getStatus();
|
||||
}
|
||||
@Override
|
||||
public TrackerStatus getStatus() {
|
||||
return tracker.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return tracker.getConfidenceLevel() * confidenceMultiplier;
|
||||
}
|
||||
@Override
|
||||
public float getConfidenceLevel() {
|
||||
return tracker.getConfidenceLevel() * confidenceMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return tracker.getBodyPosition();
|
||||
}
|
||||
@Override
|
||||
public TrackerPosition getBodyPosition() {
|
||||
return tracker.getBodyPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
tracker.setBodyPosition(position);
|
||||
}
|
||||
@Override
|
||||
public void setBodyPosition(TrackerPosition position) {
|
||||
tracker.setBodyPosition(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
tracker.tick();
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
tracker.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return tracker.hasRotation();
|
||||
}
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return tracker.hasRotation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return tracker.hasPosition();
|
||||
}
|
||||
@Override
|
||||
public boolean hasPosition() {
|
||||
return tracker.hasPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return tracker.isComputed();
|
||||
}
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return tracker.isComputed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return tracker.getTrackerId();
|
||||
}
|
||||
@Override
|
||||
public int getTrackerId() {
|
||||
return tracker.getTrackerId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return tracker.getTrackerNum();
|
||||
}
|
||||
@Override
|
||||
public int getTrackerNum() {
|
||||
return tracker.getTrackerNum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return tracker.getDescriptiveName();
|
||||
}
|
||||
@Override
|
||||
public String getDescriptiveName() {
|
||||
return tracker.getDescriptiveName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return tracker.getDevice();
|
||||
}
|
||||
@Override
|
||||
public Device getDevice() {
|
||||
return tracker.getDevice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
public class SensorTap {
|
||||
|
||||
public final boolean doubleTap;
|
||||
public final boolean doubleTap;
|
||||
|
||||
public SensorTap(int tapBits) {
|
||||
doubleTap = (tapBits & 0x40) > 0;
|
||||
}
|
||||
public SensorTap(int tapBits) {
|
||||
doubleTap = (tapBits & 0x40) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tap{" + (doubleTap ? "double" : "") + "}";
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tap{" + (doubleTap ? "double" : "") + "}";
|
||||
}
|
||||
|
||||
public enum TapAxis {
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
public enum TapAxis {
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
public interface ShareableTracker extends Tracker {
|
||||
|
||||
TrackerRole getTrackerRole();
|
||||
TrackerRole getTrackerRole();
|
||||
}
|
||||
|
||||
@@ -8,51 +8,51 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public interface Tracker {
|
||||
|
||||
AtomicInteger nextLocalTrackerId = new AtomicInteger();
|
||||
AtomicInteger nextLocalTrackerId = new AtomicInteger();
|
||||
|
||||
static int getNextLocalTrackerId() {
|
||||
return nextLocalTrackerId.incrementAndGet();
|
||||
}
|
||||
static int getNextLocalTrackerId() {
|
||||
return nextLocalTrackerId.incrementAndGet();
|
||||
}
|
||||
|
||||
boolean getPosition(Vector3f store);
|
||||
boolean getPosition(Vector3f store);
|
||||
|
||||
boolean getRotation(Quaternion store);
|
||||
boolean getRotation(Quaternion store);
|
||||
|
||||
String getName();
|
||||
String getName();
|
||||
|
||||
TrackerStatus getStatus();
|
||||
TrackerStatus getStatus();
|
||||
|
||||
void loadConfig(TrackerConfig config);
|
||||
void loadConfig(TrackerConfig config);
|
||||
|
||||
void saveConfig(TrackerConfig config);
|
||||
void saveConfig(TrackerConfig config);
|
||||
|
||||
float getConfidenceLevel();
|
||||
float getConfidenceLevel();
|
||||
|
||||
void resetFull(Quaternion reference);
|
||||
void resetFull(Quaternion reference);
|
||||
|
||||
void resetYaw(Quaternion reference);
|
||||
void resetYaw(Quaternion reference);
|
||||
|
||||
void tick();
|
||||
void tick();
|
||||
|
||||
TrackerPosition getBodyPosition();
|
||||
TrackerPosition getBodyPosition();
|
||||
|
||||
void setBodyPosition(TrackerPosition position);
|
||||
void setBodyPosition(TrackerPosition position);
|
||||
|
||||
boolean userEditable();
|
||||
boolean userEditable();
|
||||
|
||||
boolean hasRotation();
|
||||
boolean hasRotation();
|
||||
|
||||
boolean hasPosition();
|
||||
boolean hasPosition();
|
||||
|
||||
boolean isComputed();
|
||||
boolean isComputed();
|
||||
|
||||
int getTrackerId();
|
||||
int getTrackerId();
|
||||
|
||||
int getTrackerNum();
|
||||
int getTrackerNum();
|
||||
|
||||
Device getDevice();
|
||||
Device getDevice();
|
||||
|
||||
default String getDescriptiveName() {
|
||||
return getName();
|
||||
}
|
||||
default String getDescriptiveName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,90 +5,90 @@ import io.eiren.yaml.YamlNode;
|
||||
|
||||
public class TrackerConfig {
|
||||
|
||||
public final String trackerName;
|
||||
public String designation;
|
||||
public String description;
|
||||
public boolean hide;
|
||||
public Quaternion adjustment;
|
||||
public String oldMountingRotation;
|
||||
public Quaternion mountingRotation;
|
||||
public final String trackerName;
|
||||
public String designation;
|
||||
public String description;
|
||||
public boolean hide;
|
||||
public Quaternion adjustment;
|
||||
public String oldMountingRotation;
|
||||
public Quaternion mountingRotation;
|
||||
|
||||
public TrackerConfig(Tracker tracker) {
|
||||
this.trackerName = tracker.getName();
|
||||
this.description = tracker.getDescriptiveName();
|
||||
this.designation = tracker.getBodyPosition() != null ? tracker.getBodyPosition().designation : null;
|
||||
}
|
||||
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.oldMountingRotation = node.getString("rotation");
|
||||
YamlNode mountingRotationNode = node.getNode("mountingRotation");
|
||||
if (mountingRotationNode != null) {
|
||||
mountingRotation = new Quaternion(
|
||||
mountingRotationNode.getFloat("x", 0),
|
||||
mountingRotationNode.getFloat("y", 0),
|
||||
mountingRotationNode.getFloat("z", 0),
|
||||
mountingRotationNode.getFloat("w", 1)
|
||||
);
|
||||
}
|
||||
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.oldMountingRotation = node.getString("rotation");
|
||||
YamlNode mountingRotationNode = node.getNode("mountingRotation");
|
||||
if (mountingRotationNode != null) {
|
||||
mountingRotation = new Quaternion(
|
||||
mountingRotationNode.getFloat("x", 0),
|
||||
mountingRotationNode.getFloat("y", 0),
|
||||
mountingRotationNode.getFloat("z", 0),
|
||||
mountingRotationNode.getFloat("w", 1)
|
||||
);
|
||||
}
|
||||
|
||||
if (oldMountingRotation != null) {
|
||||
mountingRotation = TrackerMountingRotation.valueOf(oldMountingRotation).quaternion;
|
||||
}
|
||||
if (oldMountingRotation != null) {
|
||||
mountingRotation = TrackerMountingRotation.valueOf(oldMountingRotation).quaternion;
|
||||
}
|
||||
|
||||
YamlNode adjNode = node.getNode("adjustment");
|
||||
if (adjNode != null) {
|
||||
adjustment = new Quaternion(
|
||||
adjNode.getFloat("x", 0),
|
||||
adjNode.getFloat("y", 0),
|
||||
adjNode.getFloat("z", 0),
|
||||
adjNode.getFloat("w", 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
YamlNode adjNode = node.getNode("adjustment");
|
||||
if (adjNode != null) {
|
||||
adjustment = new Quaternion(
|
||||
adjNode.getFloat("x", 0),
|
||||
adjNode.getFloat("y", 0),
|
||||
adjNode.getFloat("z", 0),
|
||||
adjNode.getFloat("w", 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDesignation(String newDesignation) {
|
||||
this.designation = newDesignation;
|
||||
}
|
||||
public void setDesignation(String newDesignation) {
|
||||
this.designation = newDesignation;
|
||||
}
|
||||
|
||||
public void saveConfig(YamlNode configNode) {
|
||||
configNode.setProperty("name", trackerName);
|
||||
if (designation != null)
|
||||
configNode.setProperty("designation", designation);
|
||||
else
|
||||
configNode.removeProperty("designation");
|
||||
if (hide)
|
||||
configNode.setProperty("hide", hide);
|
||||
else
|
||||
configNode.removeProperty("hide");
|
||||
if (adjustment != null) {
|
||||
configNode.setProperty("adj.x", adjustment.getX());
|
||||
configNode.setProperty("adj.y", adjustment.getY());
|
||||
configNode.setProperty("adj.z", adjustment.getZ());
|
||||
configNode.setProperty("adj.w", adjustment.getW());
|
||||
} else {
|
||||
configNode.removeProperty("adj");
|
||||
}
|
||||
if (oldMountingRotation != null) {
|
||||
configNode.removeProperty("rotation");
|
||||
}
|
||||
public void saveConfig(YamlNode configNode) {
|
||||
configNode.setProperty("name", trackerName);
|
||||
if (designation != null)
|
||||
configNode.setProperty("designation", designation);
|
||||
else
|
||||
configNode.removeProperty("designation");
|
||||
if (hide)
|
||||
configNode.setProperty("hide", hide);
|
||||
else
|
||||
configNode.removeProperty("hide");
|
||||
if (adjustment != null) {
|
||||
configNode.setProperty("adj.x", adjustment.getX());
|
||||
configNode.setProperty("adj.y", adjustment.getY());
|
||||
configNode.setProperty("adj.z", adjustment.getZ());
|
||||
configNode.setProperty("adj.w", adjustment.getW());
|
||||
} else {
|
||||
configNode.removeProperty("adj");
|
||||
}
|
||||
if (oldMountingRotation != null) {
|
||||
configNode.removeProperty("rotation");
|
||||
}
|
||||
|
||||
if (mountingRotation != null) {
|
||||
configNode.setProperty("mountingRotation.x", mountingRotation.getX());
|
||||
configNode.setProperty("mountingRotation.y", mountingRotation.getY());
|
||||
configNode.setProperty("mountingRotation.z", mountingRotation.getZ());
|
||||
configNode.setProperty("mountingRotation.w", mountingRotation.getW());
|
||||
} else {
|
||||
configNode.removeProperty("mountingRotation");
|
||||
}
|
||||
if (mountingRotation != null) {
|
||||
configNode.setProperty("mountingRotation.x", mountingRotation.getX());
|
||||
configNode.setProperty("mountingRotation.y", mountingRotation.getY());
|
||||
configNode.setProperty("mountingRotation.z", mountingRotation.getZ());
|
||||
configNode.setProperty("mountingRotation.w", mountingRotation.getW());
|
||||
} else {
|
||||
configNode.removeProperty("mountingRotation");
|
||||
}
|
||||
|
||||
if (description != null) {
|
||||
configNode.setProperty("description", description);
|
||||
} else {
|
||||
configNode.removeProperty("description");
|
||||
}
|
||||
}
|
||||
if (description != null) {
|
||||
configNode.setProperty("description", description);
|
||||
} else {
|
||||
configNode.removeProperty("description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
package dev.slimevr.vr.trackers;
|
||||
|
||||
public enum TrackerFilters {
|
||||
NONE(0),
|
||||
INTERPOLATION(1),
|
||||
EXTRAPOLATION(2);
|
||||
NONE(0),
|
||||
INTERPOLATION(1),
|
||||
EXTRAPOLATION(2);
|
||||
|
||||
public final int id;
|
||||
public final int id;
|
||||
|
||||
TrackerFilters(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
TrackerFilters(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static TrackerFilters fromId(int id) {
|
||||
for (TrackerFilters filter : values()) {
|
||||
if (filter.id == id)
|
||||
return filter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static TrackerFilters fromId(int id) {
|
||||
for (TrackerFilters filter : values()) {
|
||||
if (filter.id == id)
|
||||
return filter;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,23 +5,23 @@ import com.jme3.math.Quaternion;
|
||||
|
||||
public enum TrackerMountingRotation {
|
||||
|
||||
FRONT(180),
|
||||
LEFT(90),
|
||||
BACK(0),
|
||||
RIGHT(-90);
|
||||
FRONT(180),
|
||||
LEFT(90),
|
||||
BACK(0),
|
||||
RIGHT(-90);
|
||||
|
||||
public static final TrackerMountingRotation[] values = values();
|
||||
public final Quaternion quaternion;
|
||||
public static final TrackerMountingRotation[] values = values();
|
||||
public final Quaternion quaternion;
|
||||
|
||||
TrackerMountingRotation(float angle) {
|
||||
this.quaternion = new Quaternion().fromAngles(0, angle * FastMath.DEG_TO_RAD, 0);
|
||||
}
|
||||
TrackerMountingRotation(float angle) {
|
||||
this.quaternion = new Quaternion().fromAngles(0, angle * FastMath.DEG_TO_RAD, 0);
|
||||
}
|
||||
|
||||
public static TrackerMountingRotation fromQuaternion(Quaternion q) {
|
||||
for (TrackerMountingRotation r : values()) {
|
||||
if (r.quaternion.equals(q))
|
||||
return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static TrackerMountingRotation fromQuaternion(Quaternion q) {
|
||||
for (TrackerMountingRotation r : values()) {
|
||||
if (r.quaternion.equals(q))
|
||||
return r;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,73 +6,73 @@ import java.util.Map;
|
||||
|
||||
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),
|
||||
;
|
||||
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),
|
||||
;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 int id;
|
||||
public final String designation;
|
||||
public final TrackerRole trackerRole;
|
||||
public final int id;
|
||||
public final String designation;
|
||||
public final TrackerRole trackerRole;
|
||||
|
||||
TrackerPosition(int id, String designation, TrackerRole trackerRole) {
|
||||
this.id = id;
|
||||
this.designation = designation;
|
||||
this.trackerRole = trackerRole;
|
||||
}
|
||||
TrackerPosition(int id, String designation, TrackerRole trackerRole) {
|
||||
this.id = id;
|
||||
this.designation = designation;
|
||||
this.trackerRole = trackerRole;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
return designation == null ? null : byDesignation.get(designation.toLowerCase());
|
||||
}
|
||||
return designation == null ? null : byDesignation.get(designation.toLowerCase());
|
||||
}
|
||||
|
||||
public static TrackerPosition getByRole(TrackerRole role) {
|
||||
return byRole.get(role);
|
||||
}
|
||||
public static TrackerPosition getByRole(TrackerRole role) {
|
||||
return byRole.get(role);
|
||||
}
|
||||
|
||||
public static TrackerPosition getById(int id) {
|
||||
return byId.get(id);
|
||||
}
|
||||
public static TrackerPosition getById(int id) {
|
||||
return byId.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,54 +2,54 @@ package dev.slimevr.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),
|
||||
;
|
||||
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 static final TrackerRole[] values = values();
|
||||
private static final TrackerRole[] byId = new TrackerRole[22];
|
||||
public static final TrackerRole[] values = values();
|
||||
private static final TrackerRole[] byId = new TrackerRole[22];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public final int id;
|
||||
public final String roleHint;
|
||||
public final String viveRole;
|
||||
public final DeviceType deviceType;
|
||||
public final int id;
|
||||
public final String roleHint;
|
||||
public final String viveRole;
|
||||
public final DeviceType deviceType;
|
||||
|
||||
TrackerRole(int id, String roleHint, String viveRole, DeviceType deviceType) {
|
||||
this.id = id;
|
||||
this.roleHint = roleHint;
|
||||
this.viveRole = viveRole;
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
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];
|
||||
}
|
||||
public static TrackerRole getById(int id) {
|
||||
return id < 0 || id >= byId.length ? null : byId[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,31 +2,31 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
public enum TrackerStatus {
|
||||
|
||||
DISCONNECTED(0, false),
|
||||
OK(1, true),
|
||||
BUSY(2, true),
|
||||
ERROR(3, false),
|
||||
OCCLUDED(4, false),
|
||||
;
|
||||
DISCONNECTED(0, false),
|
||||
OK(1, true),
|
||||
BUSY(2, true),
|
||||
ERROR(3, false),
|
||||
OCCLUDED(4, false),
|
||||
;
|
||||
|
||||
private static final TrackerStatus[] byId = new TrackerStatus[5];
|
||||
private static final TrackerStatus[] byId = new TrackerStatus[5];
|
||||
|
||||
static {
|
||||
for (TrackerStatus st : values())
|
||||
byId[st.id] = st;
|
||||
}
|
||||
static {
|
||||
for (TrackerStatus st : values())
|
||||
byId[st.id] = st;
|
||||
}
|
||||
|
||||
public final int id;
|
||||
public final boolean sendData;
|
||||
public final int id;
|
||||
public final boolean sendData;
|
||||
|
||||
TrackerStatus(int id, boolean sendData) {
|
||||
this.sendData = sendData;
|
||||
this.id = id;
|
||||
}
|
||||
TrackerStatus(int id, boolean sendData) {
|
||||
this.sendData = sendData;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static TrackerStatus getById(int id) {
|
||||
if (id < 0 || id >= byId.length)
|
||||
return null;
|
||||
return byId[id];
|
||||
}
|
||||
public static TrackerStatus getById(int id) {
|
||||
if (id < 0 || id >= byId.length)
|
||||
return null;
|
||||
return byId[id];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,68 +4,68 @@ import java.util.List;
|
||||
|
||||
public class TrackerUtils {
|
||||
|
||||
private TrackerUtils() {
|
||||
}
|
||||
private TrackerUtils() {
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerPosition position) {
|
||||
if (position == null)
|
||||
return null;
|
||||
for (int i = 0; i < allTrackers.length; ++i) {
|
||||
T t = allTrackers[i];
|
||||
if (t != null && t.getBodyPosition() == position)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerPosition position) {
|
||||
if (position == null)
|
||||
return null;
|
||||
for (int i = 0; i < allTrackers.length; ++i) {
|
||||
T t = allTrackers[i];
|
||||
if (t != null && t.getBodyPosition() == position)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerPosition position) {
|
||||
if (position == null)
|
||||
return null;
|
||||
for (int i = 0; i < allTrackers.size(); ++i) {
|
||||
T t = allTrackers.get(i);
|
||||
if (t != null && t.getBodyPosition() == position)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(List<T> allTrackers, TrackerPosition position) {
|
||||
if (position == null)
|
||||
return null;
|
||||
for (int i = 0; i < allTrackers.size(); ++i) {
|
||||
T t = allTrackers.get(i);
|
||||
if (t != null && t.getBodyPosition() == position)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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(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, TrackerPosition position, TrackerPosition altPosition, TrackerPosition secondAltPosition) {
|
||||
T t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
return findTrackerForBodyPosition(allTrackers, secondAltPosition);
|
||||
}
|
||||
public static <T extends Tracker> T findTrackerForBodyPosition(T[] allTrackers, TrackerPosition position, TrackerPosition altPosition, TrackerPosition secondAltPosition) {
|
||||
T t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
return findTrackerForBodyPosition(allTrackers, secondAltPosition);
|
||||
}
|
||||
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(List<? extends Tracker> allTrackers, TrackerPosition position, TrackerPosition altPosition, TrackerPosition secondAltPosition) {
|
||||
Tracker t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, secondAltPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
return new ComputedTracker(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
public static Tracker findTrackerForBodyPositionOrEmpty(List<? extends Tracker> allTrackers, TrackerPosition position, TrackerPosition altPosition, TrackerPosition secondAltPosition) {
|
||||
Tracker t = findTrackerForBodyPosition(allTrackers, position);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, altPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
t = findTrackerForBodyPosition(allTrackers, secondAltPosition);
|
||||
if (t != null)
|
||||
return t;
|
||||
return new ComputedTracker(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
|
||||
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(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
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(Tracker.getNextLocalTrackerId(), "Empty tracker", false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
public interface TrackerWithBattery {
|
||||
|
||||
float getBatteryLevel();
|
||||
float getBatteryLevel();
|
||||
|
||||
float getBatteryVoltage();
|
||||
float getBatteryVoltage();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package dev.slimevr.vr.trackers;
|
||||
|
||||
public interface TrackerWithTPS {
|
||||
|
||||
float getTPS();
|
||||
float getTPS();
|
||||
|
||||
void dataTick();
|
||||
void dataTick();
|
||||
}
|
||||
|
||||
@@ -4,33 +4,33 @@ import io.eiren.util.BufferedTimer;
|
||||
|
||||
public class VRTracker extends ComputedTracker {
|
||||
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
protected BufferedTimer timer = new BufferedTimer(1f);
|
||||
|
||||
public VRTracker(int id, String serial, String name, boolean hasRotation, boolean hasPosition) {
|
||||
super(id, serial, name, hasRotation, hasPosition);
|
||||
}
|
||||
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);
|
||||
}
|
||||
public VRTracker(int id, String name, boolean hasRotation, boolean hasPosition) {
|
||||
super(id, name, name, hasRotation, hasPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
@Override
|
||||
public float getTPS() {
|
||||
return timer.getAverageFPS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
@Override
|
||||
public void dataTick() {
|
||||
timer.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean userEditable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean isComputed() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,42 +11,42 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Device {
|
||||
|
||||
public static final AtomicInteger nextLocalDeviceId = new AtomicInteger();
|
||||
public final int id;
|
||||
public Map<Integer, IMUTracker> sensors = new HashMap<>();
|
||||
public SocketAddress address;
|
||||
public InetAddress ipAddress;
|
||||
public long lastPacket = System.currentTimeMillis();
|
||||
public int lastPingPacketId = -1;
|
||||
public long lastPingPacketTime = 0;
|
||||
public String name;
|
||||
public String descriptiveName;
|
||||
public StringBuilder serialBuffer = new StringBuilder();
|
||||
public long lastSerialUpdate = 0;
|
||||
public long lastPacketNumber = -1;
|
||||
public NetworkProtocol protocol = null;
|
||||
public int firmwareBuild = 0;
|
||||
public boolean timedOut = false;
|
||||
public static final AtomicInteger nextLocalDeviceId = new AtomicInteger();
|
||||
public final int id;
|
||||
public Map<Integer, IMUTracker> sensors = new HashMap<>();
|
||||
public SocketAddress address;
|
||||
public InetAddress ipAddress;
|
||||
public long lastPacket = System.currentTimeMillis();
|
||||
public int lastPingPacketId = -1;
|
||||
public long lastPingPacketTime = 0;
|
||||
public String name;
|
||||
public String descriptiveName;
|
||||
public StringBuilder serialBuffer = new StringBuilder();
|
||||
public long lastSerialUpdate = 0;
|
||||
public long lastPacketNumber = -1;
|
||||
public NetworkProtocol protocol = null;
|
||||
public int firmwareBuild = 0;
|
||||
public boolean timedOut = false;
|
||||
|
||||
public Device(SocketAddress address, InetAddress ipAddress) {
|
||||
this.address = address;
|
||||
this.ipAddress = ipAddress;
|
||||
this.id = Device.nextLocalDeviceId.incrementAndGet();
|
||||
}
|
||||
public Device(SocketAddress address, InetAddress ipAddress) {
|
||||
this.address = address;
|
||||
this.ipAddress = ipAddress;
|
||||
this.id = Device.nextLocalDeviceId.incrementAndGet();
|
||||
}
|
||||
|
||||
public boolean isNextPacket(long packetId) {
|
||||
if (packetId != 0 && packetId <= lastPacketNumber)
|
||||
return false;
|
||||
lastPacketNumber = packetId;
|
||||
return true;
|
||||
}
|
||||
public boolean isNextPacket(long packetId) {
|
||||
if (packetId != 0 && packetId <= lastPacketNumber)
|
||||
return false;
|
||||
lastPacketNumber = packetId;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "udp:/" + ipAddress;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "udp:/" + ipAddress;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@ package dev.slimevr.vr.trackers.udp;
|
||||
|
||||
public interface SensorSpecificPacket {
|
||||
|
||||
/**
|
||||
* Sensor with id 255 is "global" representing a whole device
|
||||
*
|
||||
* @param sensorId
|
||||
* @return
|
||||
*/
|
||||
static boolean isGlobal(int sensorId) {
|
||||
return sensorId == 255;
|
||||
}
|
||||
/**
|
||||
* Sensor with id 255 is "global" representing a whole device
|
||||
*
|
||||
* @param sensorId
|
||||
* @return
|
||||
*/
|
||||
static boolean isGlobal(int sensorId) {
|
||||
return sensorId == 255;
|
||||
}
|
||||
|
||||
int getSensorId();
|
||||
int getSensorId();
|
||||
}
|
||||
|
||||
@@ -26,397 +26,397 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class TrackersUDPServer extends Thread {
|
||||
|
||||
/**
|
||||
* Change between IMU axes and OpenGL/SteamVR axes
|
||||
*/
|
||||
private static final Quaternion offset = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);
|
||||
/**
|
||||
* Change between IMU axes and OpenGL/SteamVR axes
|
||||
*/
|
||||
private static final Quaternion offset = new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X);
|
||||
|
||||
private final Quaternion buf = new Quaternion();
|
||||
private final Random random = new Random();
|
||||
private final List<Device> connections = new FastList<>();
|
||||
private final Map<InetAddress, Device> connectionsByAddress = new HashMap<>();
|
||||
private final Map<String, Device> connectionsByMAC = new HashMap<>();
|
||||
private final Consumer<Tracker> trackersConsumer;
|
||||
private final int port;
|
||||
private final ArrayList<SocketAddress> broadcastAddresses = new ArrayList<>();
|
||||
private final UDPProtocolParser parser = new UDPProtocolParser();
|
||||
private final byte[] rcvBuffer = new byte[512];
|
||||
private final ByteBuffer bb = ByteBuffer.wrap(rcvBuffer).order(ByteOrder.BIG_ENDIAN);
|
||||
private final Quaternion buf = new Quaternion();
|
||||
private final Random random = new Random();
|
||||
private final List<Device> connections = new FastList<>();
|
||||
private final Map<InetAddress, Device> connectionsByAddress = new HashMap<>();
|
||||
private final Map<String, Device> connectionsByMAC = new HashMap<>();
|
||||
private final Consumer<Tracker> trackersConsumer;
|
||||
private final int port;
|
||||
private final ArrayList<SocketAddress> broadcastAddresses = new ArrayList<>();
|
||||
private final UDPProtocolParser parser = new UDPProtocolParser();
|
||||
private final byte[] rcvBuffer = new byte[512];
|
||||
private final ByteBuffer bb = ByteBuffer.wrap(rcvBuffer).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
protected DatagramSocket socket = null;
|
||||
protected long lastKeepup = System.currentTimeMillis();
|
||||
protected DatagramSocket socket = null;
|
||||
protected long lastKeepup = System.currentTimeMillis();
|
||||
|
||||
public TrackersUDPServer(int port, String name, Consumer<Tracker> trackersConsumer) {
|
||||
super(name);
|
||||
this.port = port;
|
||||
this.trackersConsumer = trackersConsumer;
|
||||
try {
|
||||
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (ifaces.hasMoreElements()) {
|
||||
NetworkInterface iface = ifaces.nextElement();
|
||||
// Ignore loopback, PPP, virtual and disabled devices
|
||||
if (iface.isLoopback() || !iface.isUp() || iface.isPointToPoint() || iface.isVirtual()) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<InetAddress> iaddrs = iface.getInetAddresses();
|
||||
while (iaddrs.hasMoreElements()) {
|
||||
InetAddress iaddr = iaddrs.nextElement();
|
||||
// Ignore IPv6 addresses
|
||||
if (iaddr instanceof Inet6Address) {
|
||||
continue;
|
||||
}
|
||||
String[] iaddrParts = iaddr.getHostAddress().split("\\.");
|
||||
broadcastAddresses.add(new InetSocketAddress(String.format("%s.%s.%s.255", iaddrParts[0], iaddrParts[1], iaddrParts[2]), port));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[TrackerServer] Can't enumerate network interfaces", e);
|
||||
}
|
||||
}
|
||||
public TrackersUDPServer(int port, String name, Consumer<Tracker> trackersConsumer) {
|
||||
super(name);
|
||||
this.port = port;
|
||||
this.trackersConsumer = trackersConsumer;
|
||||
try {
|
||||
Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (ifaces.hasMoreElements()) {
|
||||
NetworkInterface iface = ifaces.nextElement();
|
||||
// Ignore loopback, PPP, virtual and disabled devices
|
||||
if (iface.isLoopback() || !iface.isUp() || iface.isPointToPoint() || iface.isVirtual()) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<InetAddress> iaddrs = iface.getInetAddresses();
|
||||
while (iaddrs.hasMoreElements()) {
|
||||
InetAddress iaddr = iaddrs.nextElement();
|
||||
// Ignore IPv6 addresses
|
||||
if (iaddr instanceof Inet6Address) {
|
||||
continue;
|
||||
}
|
||||
String[] iaddrParts = iaddr.getHostAddress().split("\\.");
|
||||
broadcastAddresses.add(new InetSocketAddress(String.format("%s.%s.%s.255", iaddrParts[0], iaddrParts[1], iaddrParts[2]), port));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogManager.log.severe("[TrackerServer] Can't enumerate network interfaces", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String packetToString(DatagramPacket packet) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DatagramPacket{");
|
||||
sb.append(packet.getAddress().toString());
|
||||
sb.append(packet.getPort());
|
||||
sb.append(',');
|
||||
sb.append(packet.getLength());
|
||||
sb.append(',');
|
||||
sb.append(ArrayUtils.toString(packet.getData()));
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
private static String packetToString(DatagramPacket packet) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DatagramPacket{");
|
||||
sb.append(packet.getAddress().toString());
|
||||
sb.append(packet.getPort());
|
||||
sb.append(',');
|
||||
sb.append(packet.getLength());
|
||||
sb.append(',');
|
||||
sb.append(ArrayUtils.toString(packet.getData()));
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void setUpNewConnection(DatagramPacket handshakePacket, UDPPacket3Handshake handshake) throws IOException {
|
||||
LogManager.log.info("[TrackerServer] Handshake received from " + handshakePacket.getAddress() + ":" + handshakePacket.getPort());
|
||||
InetAddress addr = handshakePacket.getAddress();
|
||||
Device connection;
|
||||
synchronized (connections) {
|
||||
connection = connectionsByAddress.get(addr);
|
||||
}
|
||||
if (connection == null) {
|
||||
connection = new Device(handshakePacket.getSocketAddress(), addr);
|
||||
connection.firmwareBuild = handshake.firmwareBuild;
|
||||
if (handshake.firmware == null || handshake.firmware.length() == 0) {
|
||||
// Only old owoTrack doesn't report firmware and have different packet IDs with SlimeVR
|
||||
connection.protocol = NetworkProtocol.OWO_LEGACY;
|
||||
} else {
|
||||
connection.protocol = NetworkProtocol.SLIMEVR_RAW;
|
||||
}
|
||||
connection.name = handshake.macString != null ? "udp://" + handshake.macString : "udp:/" + handshakePacket.getAddress().toString();
|
||||
connection.descriptiveName = "udp:/" + handshakePacket.getAddress().toString();
|
||||
int i = 0;
|
||||
synchronized (connections) {
|
||||
if (handshake.macString != null && connectionsByMAC.containsKey(handshake.macString)) {
|
||||
Device previousConnection = connectionsByMAC.get(handshake.macString);
|
||||
i = connections.indexOf(previousConnection);
|
||||
connectionsByAddress.remove(previousConnection.ipAddress);
|
||||
previousConnection.lastPacketNumber = 0;
|
||||
previousConnection.ipAddress = addr;
|
||||
previousConnection.address = handshakePacket.getSocketAddress();
|
||||
previousConnection.name = connection.name;
|
||||
previousConnection.descriptiveName = connection.descriptiveName;
|
||||
connectionsByAddress.put(addr, previousConnection);
|
||||
LogManager.log.info("[TrackerServer] Tracker " + i + " handed over to address " + handshakePacket.getSocketAddress() + ". Board type: " + handshake.boardType + ", imu type: " + handshake.imuType + ", firmware: " + handshake.firmware + " (" + connection.firmwareBuild + "), mac: " + handshake.macString + ", name: " + previousConnection.name);
|
||||
} else {
|
||||
i = connections.size();
|
||||
connections.add(connection);
|
||||
connectionsByAddress.put(addr, connection);
|
||||
if (handshake.macString != null) {
|
||||
connectionsByMAC.put(handshake.macString, connection);
|
||||
}
|
||||
LogManager.log.info("[TrackerServer] Tracker " + i + " added with address " + handshakePacket.getSocketAddress() + ". Board type: " + handshake.boardType + ", imu type: " + handshake.imuType + ", firmware: " + handshake.firmware + " (" + connection.firmwareBuild + "), mac: " + handshake.macString + ", name: " + connection.name);
|
||||
}
|
||||
}
|
||||
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) {
|
||||
// Set up new sensor for older firmware
|
||||
// Firmware after 7 should send sensor status packet and sensor will be created when it's received
|
||||
setUpSensor(connection, 0, handshake.imuType, 1);
|
||||
}
|
||||
}
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.writeHandshakeResponse(bb, connection);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), connection.address));
|
||||
}
|
||||
private void setUpNewConnection(DatagramPacket handshakePacket, UDPPacket3Handshake handshake) throws IOException {
|
||||
LogManager.log.info("[TrackerServer] Handshake received from " + handshakePacket.getAddress() + ":" + handshakePacket.getPort());
|
||||
InetAddress addr = handshakePacket.getAddress();
|
||||
Device connection;
|
||||
synchronized (connections) {
|
||||
connection = connectionsByAddress.get(addr);
|
||||
}
|
||||
if (connection == null) {
|
||||
connection = new Device(handshakePacket.getSocketAddress(), addr);
|
||||
connection.firmwareBuild = handshake.firmwareBuild;
|
||||
if (handshake.firmware == null || handshake.firmware.length() == 0) {
|
||||
// Only old owoTrack doesn't report firmware and have different packet IDs with SlimeVR
|
||||
connection.protocol = NetworkProtocol.OWO_LEGACY;
|
||||
} else {
|
||||
connection.protocol = NetworkProtocol.SLIMEVR_RAW;
|
||||
}
|
||||
connection.name = handshake.macString != null ? "udp://" + handshake.macString : "udp:/" + handshakePacket.getAddress().toString();
|
||||
connection.descriptiveName = "udp:/" + handshakePacket.getAddress().toString();
|
||||
int i = 0;
|
||||
synchronized (connections) {
|
||||
if (handshake.macString != null && connectionsByMAC.containsKey(handshake.macString)) {
|
||||
Device previousConnection = connectionsByMAC.get(handshake.macString);
|
||||
i = connections.indexOf(previousConnection);
|
||||
connectionsByAddress.remove(previousConnection.ipAddress);
|
||||
previousConnection.lastPacketNumber = 0;
|
||||
previousConnection.ipAddress = addr;
|
||||
previousConnection.address = handshakePacket.getSocketAddress();
|
||||
previousConnection.name = connection.name;
|
||||
previousConnection.descriptiveName = connection.descriptiveName;
|
||||
connectionsByAddress.put(addr, previousConnection);
|
||||
LogManager.log.info("[TrackerServer] Tracker " + i + " handed over to address " + handshakePacket.getSocketAddress() + ". Board type: " + handshake.boardType + ", imu type: " + handshake.imuType + ", firmware: " + handshake.firmware + " (" + connection.firmwareBuild + "), mac: " + handshake.macString + ", name: " + previousConnection.name);
|
||||
} else {
|
||||
i = connections.size();
|
||||
connections.add(connection);
|
||||
connectionsByAddress.put(addr, connection);
|
||||
if (handshake.macString != null) {
|
||||
connectionsByMAC.put(handshake.macString, connection);
|
||||
}
|
||||
LogManager.log.info("[TrackerServer] Tracker " + i + " added with address " + handshakePacket.getSocketAddress() + ". Board type: " + handshake.boardType + ", imu type: " + handshake.imuType + ", firmware: " + handshake.firmware + " (" + connection.firmwareBuild + "), mac: " + handshake.macString + ", name: " + connection.name);
|
||||
}
|
||||
}
|
||||
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) {
|
||||
// Set up new sensor for older firmware
|
||||
// Firmware after 7 should send sensor status packet and sensor will be created when it's received
|
||||
setUpSensor(connection, 0, handshake.imuType, 1);
|
||||
}
|
||||
}
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.writeHandshakeResponse(bb, connection);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), connection.address));
|
||||
}
|
||||
|
||||
private void setUpSensor(Device connection, int trackerId, int sensorType, int sensorStatus) throws IOException {
|
||||
LogManager.log.info("[TrackerServer] Sensor " + trackerId + " for " + connection.name + " status: " + sensorStatus);
|
||||
IMUTracker imu = connection.sensors.get(trackerId);
|
||||
if (imu == null) {
|
||||
imu = new IMUTracker(connection, Tracker.getNextLocalTrackerId(), trackerId, connection.name + "/" + trackerId, connection.descriptiveName + "/" + trackerId, this, Main.vrServer);
|
||||
connection.sensors.put(trackerId, imu);
|
||||
ReferenceAdjustedTracker<IMUTracker> adjustedTracker = new ReferenceAdjustedTracker<>(imu);
|
||||
trackersConsumer.accept(adjustedTracker);
|
||||
LogManager.log.info("[TrackerServer] Added sensor " + trackerId + " for " + connection.name + ", type " + sensorType);
|
||||
}
|
||||
TrackerStatus status = UDPPacket15SensorInfo.getStatus(sensorStatus);
|
||||
if (status != null)
|
||||
imu.setStatus(status);
|
||||
}
|
||||
private void setUpSensor(Device connection, int trackerId, int sensorType, int sensorStatus) throws IOException {
|
||||
LogManager.log.info("[TrackerServer] Sensor " + trackerId + " for " + connection.name + " status: " + sensorStatus);
|
||||
IMUTracker imu = connection.sensors.get(trackerId);
|
||||
if (imu == null) {
|
||||
imu = new IMUTracker(connection, Tracker.getNextLocalTrackerId(), trackerId, connection.name + "/" + trackerId, connection.descriptiveName + "/" + trackerId, this, Main.vrServer);
|
||||
connection.sensors.put(trackerId, imu);
|
||||
ReferenceAdjustedTracker<IMUTracker> adjustedTracker = new ReferenceAdjustedTracker<>(imu);
|
||||
trackersConsumer.accept(adjustedTracker);
|
||||
LogManager.log.info("[TrackerServer] Added sensor " + trackerId + " for " + connection.name + ", type " + sensorType);
|
||||
}
|
||||
TrackerStatus status = UDPPacket15SensorInfo.getStatus(sensorStatus);
|
||||
if (status != null)
|
||||
imu.setStatus(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
StringBuilder serialBuffer2 = new StringBuilder();
|
||||
try {
|
||||
socket = new DatagramSocket(port);
|
||||
@Override
|
||||
public void run() {
|
||||
StringBuilder serialBuffer2 = new StringBuilder();
|
||||
try {
|
||||
socket = new DatagramSocket(port);
|
||||
|
||||
long prevPacketTime = System.currentTimeMillis();
|
||||
socket.setSoTimeout(250);
|
||||
while (true) {
|
||||
DatagramPacket received = null;
|
||||
try {
|
||||
boolean hasActiveTrackers = false;
|
||||
for (Device tracker : connections) {
|
||||
if (tracker.sensors.size() > 0) {
|
||||
hasActiveTrackers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasActiveTrackers) {
|
||||
long discoveryPacketTime = System.currentTimeMillis();
|
||||
if ((discoveryPacketTime - prevPacketTime) >= 2000) {
|
||||
for (SocketAddress addr : broadcastAddresses) {
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.write(bb, null, new UDPPacket0Heartbeat());
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), addr));
|
||||
}
|
||||
prevPacketTime = discoveryPacketTime;
|
||||
}
|
||||
}
|
||||
long prevPacketTime = System.currentTimeMillis();
|
||||
socket.setSoTimeout(250);
|
||||
while (true) {
|
||||
DatagramPacket received = null;
|
||||
try {
|
||||
boolean hasActiveTrackers = false;
|
||||
for (Device tracker : connections) {
|
||||
if (tracker.sensors.size() > 0) {
|
||||
hasActiveTrackers = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasActiveTrackers) {
|
||||
long discoveryPacketTime = System.currentTimeMillis();
|
||||
if ((discoveryPacketTime - prevPacketTime) >= 2000) {
|
||||
for (SocketAddress addr : broadcastAddresses) {
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.write(bb, null, new UDPPacket0Heartbeat());
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), addr));
|
||||
}
|
||||
prevPacketTime = discoveryPacketTime;
|
||||
}
|
||||
}
|
||||
|
||||
received = new DatagramPacket(rcvBuffer, rcvBuffer.length);
|
||||
socket.receive(received);
|
||||
bb.limit(received.getLength());
|
||||
bb.rewind();
|
||||
received = new DatagramPacket(rcvBuffer, rcvBuffer.length);
|
||||
socket.receive(received);
|
||||
bb.limit(received.getLength());
|
||||
bb.rewind();
|
||||
|
||||
Device connection;
|
||||
Device connection;
|
||||
|
||||
synchronized (connections) {
|
||||
connection = connectionsByAddress.get(received.getAddress());
|
||||
}
|
||||
UDPPacket packet = parser.parse(bb, connection);
|
||||
if (packet != null) {
|
||||
processPacket(received, packet, connection);
|
||||
}
|
||||
} catch (SocketTimeoutException e) {
|
||||
} catch (Exception e) {
|
||||
LogManager.log.warning("[TrackerServer] Error parsing packet " + packetToString(received), e);
|
||||
}
|
||||
if (lastKeepup + 500 < System.currentTimeMillis()) {
|
||||
lastKeepup = System.currentTimeMillis();
|
||||
synchronized (connections) {
|
||||
for (int i = 0; i < connections.size(); ++i) {
|
||||
Device conn = connections.get(i);
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.write(bb, conn, new UDPPacket1Heartbeat());
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), conn.address));
|
||||
if (conn.lastPacket + 1000 < System.currentTimeMillis()) {
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tracker = iterator.next();
|
||||
if (tracker.getStatus() == TrackerStatus.OK)
|
||||
tracker.setStatus(TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
if (!conn.timedOut) {
|
||||
conn.timedOut = true;
|
||||
LogManager.log.info("[TrackerServer] Tracker timed out: " + conn);
|
||||
}
|
||||
} else {
|
||||
conn.timedOut = false;
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tracker = iterator.next();
|
||||
if (tracker.getStatus() == TrackerStatus.DISCONNECTED)
|
||||
tracker.setStatus(TrackerStatus.OK);
|
||||
}
|
||||
}
|
||||
if (conn.serialBuffer.length() > 0) {
|
||||
if (conn.lastSerialUpdate + 500L < System.currentTimeMillis()) {
|
||||
serialBuffer2.append('[').append(conn.name).append("] ").append(conn.serialBuffer);
|
||||
System.out.println(serialBuffer2);
|
||||
serialBuffer2.setLength(0);
|
||||
conn.serialBuffer.setLength(0);
|
||||
}
|
||||
}
|
||||
if (conn.lastPingPacketTime + 500 < System.currentTimeMillis()) {
|
||||
conn.lastPingPacketId = random.nextInt();
|
||||
conn.lastPingPacketTime = System.currentTimeMillis();
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
bb.putInt(10);
|
||||
bb.putLong(0);
|
||||
bb.putInt(conn.lastPingPacketId);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), conn.address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
Util.close(socket);
|
||||
}
|
||||
}
|
||||
synchronized (connections) {
|
||||
connection = connectionsByAddress.get(received.getAddress());
|
||||
}
|
||||
UDPPacket packet = parser.parse(bb, connection);
|
||||
if (packet != null) {
|
||||
processPacket(received, packet, connection);
|
||||
}
|
||||
} catch (SocketTimeoutException e) {
|
||||
} catch (Exception e) {
|
||||
LogManager.log.warning("[TrackerServer] Error parsing packet " + packetToString(received), e);
|
||||
}
|
||||
if (lastKeepup + 500 < System.currentTimeMillis()) {
|
||||
lastKeepup = System.currentTimeMillis();
|
||||
synchronized (connections) {
|
||||
for (int i = 0; i < connections.size(); ++i) {
|
||||
Device conn = connections.get(i);
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.write(bb, conn, new UDPPacket1Heartbeat());
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), conn.address));
|
||||
if (conn.lastPacket + 1000 < System.currentTimeMillis()) {
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tracker = iterator.next();
|
||||
if (tracker.getStatus() == TrackerStatus.OK)
|
||||
tracker.setStatus(TrackerStatus.DISCONNECTED);
|
||||
}
|
||||
if (!conn.timedOut) {
|
||||
conn.timedOut = true;
|
||||
LogManager.log.info("[TrackerServer] Tracker timed out: " + conn);
|
||||
}
|
||||
} else {
|
||||
conn.timedOut = false;
|
||||
Iterator<IMUTracker> iterator = conn.sensors.values().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tracker = iterator.next();
|
||||
if (tracker.getStatus() == TrackerStatus.DISCONNECTED)
|
||||
tracker.setStatus(TrackerStatus.OK);
|
||||
}
|
||||
}
|
||||
if (conn.serialBuffer.length() > 0) {
|
||||
if (conn.lastSerialUpdate + 500L < System.currentTimeMillis()) {
|
||||
serialBuffer2.append('[').append(conn.name).append("] ").append(conn.serialBuffer);
|
||||
System.out.println(serialBuffer2);
|
||||
serialBuffer2.setLength(0);
|
||||
conn.serialBuffer.setLength(0);
|
||||
}
|
||||
}
|
||||
if (conn.lastPingPacketTime + 500 < System.currentTimeMillis()) {
|
||||
conn.lastPingPacketId = random.nextInt();
|
||||
conn.lastPingPacketTime = System.currentTimeMillis();
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
bb.putInt(10);
|
||||
bb.putLong(0);
|
||||
bb.putInt(conn.lastPingPacketId);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), conn.address));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
Util.close(socket);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processPacket(DatagramPacket received, UDPPacket packet, Device connection) throws IOException {
|
||||
IMUTracker tracker = null;
|
||||
switch (packet.getPacketId()) {
|
||||
case UDPProtocolParser.PACKET_HEARTBEAT:
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_HANDSHAKE:
|
||||
setUpNewConnection(received, (UDPPacket3Handshake) packet);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ROTATION:
|
||||
case UDPProtocolParser.PACKET_ROTATION_2:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket1Rotation rotationPacket = (UDPPacket1Rotation) packet;
|
||||
buf.set(rotationPacket.rotation);
|
||||
offset.mult(buf, buf);
|
||||
tracker = connection.sensors.get(rotationPacket.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.rotQuaternion.set(buf);
|
||||
tracker.dataTick();
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ROTATION_DATA:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket17RotationData rotationData = (UDPPacket17RotationData) packet;
|
||||
tracker = connection.sensors.get(rotationData.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
buf.set(rotationData.rotation);
|
||||
offset.mult(buf, buf);
|
||||
protected void processPacket(DatagramPacket received, UDPPacket packet, Device connection) throws IOException {
|
||||
IMUTracker tracker = null;
|
||||
switch (packet.getPacketId()) {
|
||||
case UDPProtocolParser.PACKET_HEARTBEAT:
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_HANDSHAKE:
|
||||
setUpNewConnection(received, (UDPPacket3Handshake) packet);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ROTATION:
|
||||
case UDPProtocolParser.PACKET_ROTATION_2:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket1Rotation rotationPacket = (UDPPacket1Rotation) packet;
|
||||
buf.set(rotationPacket.rotation);
|
||||
offset.mult(buf, buf);
|
||||
tracker = connection.sensors.get(rotationPacket.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.rotQuaternion.set(buf);
|
||||
tracker.dataTick();
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ROTATION_DATA:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket17RotationData rotationData = (UDPPacket17RotationData) packet;
|
||||
tracker = connection.sensors.get(rotationData.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
buf.set(rotationData.rotation);
|
||||
offset.mult(buf, buf);
|
||||
|
||||
switch (rotationData.dataType) {
|
||||
case UDPPacket17RotationData.DATA_TYPE_NORMAL:
|
||||
tracker.rotQuaternion.set(buf);
|
||||
tracker.calibrationStatus = rotationData.calibrationInfo;
|
||||
tracker.dataTick();
|
||||
break;
|
||||
case UDPPacket17RotationData.DATA_TYPE_CORRECTION:
|
||||
tracker.rotMagQuaternion.set(buf);
|
||||
tracker.magCalibrationStatus = rotationData.calibrationInfo;
|
||||
tracker.hasNewCorrectionData = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_MAGNETOMETER_ACCURACY:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket18MagnetometerAccuracy magAccuracy = (UDPPacket18MagnetometerAccuracy) packet;
|
||||
tracker = connection.sensors.get(magAccuracy.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.magnetometerAccuracy = magAccuracy.accuracyInfo;
|
||||
break;
|
||||
case 2: // PACKET_GYRO
|
||||
case 4: // PACKET_ACCEL
|
||||
case 5: // PACKET_MAG
|
||||
case 9: // PACKET_RAW_MAGENTOMETER
|
||||
break; // None of these packets are used by SlimeVR trackers and are deprecated, use more generic PACKET_ROTATION_DATA
|
||||
case 8: // PACKET_CONFIG
|
||||
if (connection == null)
|
||||
break;
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_PING_PONG: // PACKET_PING_PONG:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket10PingPong ping = (UDPPacket10PingPong) packet;
|
||||
if (connection.lastPingPacketId == ping.pingId) {
|
||||
for (IMUTracker imuTracker : connection.sensors.values()) {
|
||||
imuTracker.ping = (int) (System.currentTimeMillis() - connection.lastPingPacketTime) / 2;
|
||||
imuTracker.dataTick();
|
||||
}
|
||||
} else {
|
||||
LogManager.log.debug("[TrackerServer] Wrong ping id " + ping.pingId + " != " + connection.lastPingPacketId);
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SERIAL:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket11Serial serial = (UDPPacket11Serial) packet;
|
||||
System.out.println("[" + connection.name + "] " + serial.serial);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_BATTERY_LEVEL:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket12BatteryLevel battery = (UDPPacket12BatteryLevel) packet;
|
||||
if (connection.sensors.size() > 0) {
|
||||
Collection<IMUTracker> trackers = connection.sensors.values();
|
||||
Iterator<IMUTracker> iterator = trackers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tr = iterator.next();
|
||||
tr.setBatteryVoltage(battery.voltage);
|
||||
tr.setBatteryLevel(battery.level * 100);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_TAP:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket13Tap tap = (UDPPacket13Tap) packet;
|
||||
tracker = connection.sensors.get(tap.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
LogManager.log.info("[TrackerServer] Tap packet received from " + tracker.getName() + ": " + tap.tap);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ERROR:
|
||||
UDPPacket14Error error = (UDPPacket14Error) packet;
|
||||
LogManager.log.severe("[TrackerServer] Error received from " + received.getSocketAddress() + ": " + error.errorNumber);
|
||||
if (connection == null)
|
||||
break;
|
||||
tracker = connection.sensors.get(error.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.setStatus(TrackerStatus.ERROR);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SENSOR_INFO:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket15SensorInfo info = (UDPPacket15SensorInfo) packet;
|
||||
setUpSensor(connection, info.getSensorId(), info.sensorType, info.sensorStatus);
|
||||
// Send ack
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.writeSensorInfoResponse(bb, connection, info);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), connection.address));
|
||||
LogManager.log.info("[TrackerServer] Sensor info for " + connection.descriptiveName + "/" + info.getSensorId() + ": " + info.sensorStatus);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SIGNAL_STRENGTH:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket19SignalStrength signalStrength = (UDPPacket19SignalStrength) packet;
|
||||
if (connection.sensors.size() > 0) {
|
||||
Collection<IMUTracker> trackers = connection.sensors.values();
|
||||
Iterator<IMUTracker> iterator = trackers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tr = iterator.next();
|
||||
tr.signalStrength = signalStrength.signalStrength;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_TEMPERATURE:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket20Temperature temp = (UDPPacket20Temperature) packet;
|
||||
tracker = connection.sensors.get(temp.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.temperature = temp.temperature;
|
||||
break;
|
||||
default:
|
||||
LogManager.log.warning("[TrackerServer] Skipped packet " + packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (rotationData.dataType) {
|
||||
case UDPPacket17RotationData.DATA_TYPE_NORMAL:
|
||||
tracker.rotQuaternion.set(buf);
|
||||
tracker.calibrationStatus = rotationData.calibrationInfo;
|
||||
tracker.dataTick();
|
||||
break;
|
||||
case UDPPacket17RotationData.DATA_TYPE_CORRECTION:
|
||||
tracker.rotMagQuaternion.set(buf);
|
||||
tracker.magCalibrationStatus = rotationData.calibrationInfo;
|
||||
tracker.hasNewCorrectionData = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_MAGNETOMETER_ACCURACY:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket18MagnetometerAccuracy magAccuracy = (UDPPacket18MagnetometerAccuracy) packet;
|
||||
tracker = connection.sensors.get(magAccuracy.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.magnetometerAccuracy = magAccuracy.accuracyInfo;
|
||||
break;
|
||||
case 2: // PACKET_GYRO
|
||||
case 4: // PACKET_ACCEL
|
||||
case 5: // PACKET_MAG
|
||||
case 9: // PACKET_RAW_MAGENTOMETER
|
||||
break; // None of these packets are used by SlimeVR trackers and are deprecated, use more generic PACKET_ROTATION_DATA
|
||||
case 8: // PACKET_CONFIG
|
||||
if (connection == null)
|
||||
break;
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_PING_PONG: // PACKET_PING_PONG:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket10PingPong ping = (UDPPacket10PingPong) packet;
|
||||
if (connection.lastPingPacketId == ping.pingId) {
|
||||
for (IMUTracker imuTracker : connection.sensors.values()) {
|
||||
imuTracker.ping = (int) (System.currentTimeMillis() - connection.lastPingPacketTime) / 2;
|
||||
imuTracker.dataTick();
|
||||
}
|
||||
} else {
|
||||
LogManager.log.debug("[TrackerServer] Wrong ping id " + ping.pingId + " != " + connection.lastPingPacketId);
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SERIAL:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket11Serial serial = (UDPPacket11Serial) packet;
|
||||
System.out.println("[" + connection.name + "] " + serial.serial);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_BATTERY_LEVEL:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket12BatteryLevel battery = (UDPPacket12BatteryLevel) packet;
|
||||
if (connection.sensors.size() > 0) {
|
||||
Collection<IMUTracker> trackers = connection.sensors.values();
|
||||
Iterator<IMUTracker> iterator = trackers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tr = iterator.next();
|
||||
tr.setBatteryVoltage(battery.voltage);
|
||||
tr.setBatteryLevel(battery.level * 100);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_TAP:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket13Tap tap = (UDPPacket13Tap) packet;
|
||||
tracker = connection.sensors.get(tap.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
LogManager.log.info("[TrackerServer] Tap packet received from " + tracker.getName() + ": " + tap.tap);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_ERROR:
|
||||
UDPPacket14Error error = (UDPPacket14Error) packet;
|
||||
LogManager.log.severe("[TrackerServer] Error received from " + received.getSocketAddress() + ": " + error.errorNumber);
|
||||
if (connection == null)
|
||||
break;
|
||||
tracker = connection.sensors.get(error.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.setStatus(TrackerStatus.ERROR);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SENSOR_INFO:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket15SensorInfo info = (UDPPacket15SensorInfo) packet;
|
||||
setUpSensor(connection, info.getSensorId(), info.sensorType, info.sensorStatus);
|
||||
// Send ack
|
||||
bb.limit(bb.capacity());
|
||||
bb.rewind();
|
||||
parser.writeSensorInfoResponse(bb, connection, info);
|
||||
socket.send(new DatagramPacket(rcvBuffer, bb.position(), connection.address));
|
||||
LogManager.log.info("[TrackerServer] Sensor info for " + connection.descriptiveName + "/" + info.getSensorId() + ": " + info.sensorStatus);
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_SIGNAL_STRENGTH:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket19SignalStrength signalStrength = (UDPPacket19SignalStrength) packet;
|
||||
if (connection.sensors.size() > 0) {
|
||||
Collection<IMUTracker> trackers = connection.sensors.values();
|
||||
Iterator<IMUTracker> iterator = trackers.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IMUTracker tr = iterator.next();
|
||||
tr.signalStrength = signalStrength.signalStrength;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UDPProtocolParser.PACKET_TEMPERATURE:
|
||||
if (connection == null)
|
||||
break;
|
||||
UDPPacket20Temperature temp = (UDPPacket20Temperature) packet;
|
||||
tracker = connection.sensors.get(temp.getSensorId());
|
||||
if (tracker == null)
|
||||
break;
|
||||
tracker.temperature = temp.temperature;
|
||||
break;
|
||||
default:
|
||||
LogManager.log.warning("[TrackerServer] Skipped packet " + packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Device> getConnections() {
|
||||
return connections;
|
||||
}
|
||||
public List<Device> getConnections() {
|
||||
return connections;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,67 +5,67 @@ import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class UDPPacket {
|
||||
|
||||
/**
|
||||
* Naively read null-terminated ASCII string from the byte buffer
|
||||
*
|
||||
* @param buf
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readASCIIString(ByteBuffer buf) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true) {
|
||||
char c = (char) (buf.get() & 0xFF);
|
||||
if (c == 0)
|
||||
break;
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
/**
|
||||
* Naively read null-terminated ASCII string from the byte buffer
|
||||
*
|
||||
* @param buf
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String readASCIIString(ByteBuffer buf) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (true) {
|
||||
char c = (char) (buf.get() & 0xFF);
|
||||
if (c == 0)
|
||||
break;
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String readASCIIString(ByteBuffer buf, int length) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (length-- > 0) {
|
||||
char c = (char) (buf.get() & 0xFF);
|
||||
if (c == 0)
|
||||
break;
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
public static String readASCIIString(ByteBuffer buf, int length) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (length-- > 0) {
|
||||
char c = (char) (buf.get() & 0xFF);
|
||||
if (c == 0)
|
||||
break;
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Naively write null-terminated ASCII string to byte buffer
|
||||
*
|
||||
* @param str
|
||||
* @param buf
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeASCIIString(String str, ByteBuffer buf) throws IOException {
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
char c = str.charAt(i);
|
||||
buf.put((byte) (c & 0xFF));
|
||||
}
|
||||
buf.put((byte) 0);
|
||||
}
|
||||
/**
|
||||
* Naively write null-terminated ASCII string to byte buffer
|
||||
*
|
||||
* @param str
|
||||
* @param buf
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void writeASCIIString(String str, ByteBuffer buf) throws IOException {
|
||||
for (int i = 0; i < str.length(); ++i) {
|
||||
char c = str.charAt(i);
|
||||
buf.put((byte) (c & 0xFF));
|
||||
}
|
||||
buf.put((byte) 0);
|
||||
}
|
||||
|
||||
public abstract int getPacketId();
|
||||
public abstract int getPacketId();
|
||||
|
||||
public abstract void readData(ByteBuffer buf) throws IOException;
|
||||
public abstract void readData(ByteBuffer buf) throws IOException;
|
||||
|
||||
public abstract void writeData(ByteBuffer buf) throws IOException;
|
||||
public abstract void writeData(ByteBuffer buf) throws IOException;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append('{');
|
||||
sb.append(getPacketId());
|
||||
if (this instanceof SensorSpecificPacket) {
|
||||
sb.append(",sensor:");
|
||||
sb.append(((SensorSpecificPacket) this).getSensorId());
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append('{');
|
||||
sb.append(getPacketId());
|
||||
if (this instanceof SensorSpecificPacket) {
|
||||
sb.append(",sensor:");
|
||||
sb.append(((SensorSpecificPacket) this).getSensorId());
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,21 @@ import java.nio.ByteBuffer;
|
||||
|
||||
public class UDPPacket0Heartbeat extends UDPPacket {
|
||||
|
||||
public UDPPacket0Heartbeat() {
|
||||
}
|
||||
public UDPPacket0Heartbeat() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
// Empty packet
|
||||
}
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
// Empty packet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
// Empty packet
|
||||
}
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
// Empty packet
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,27 +5,27 @@ import java.nio.ByteBuffer;
|
||||
|
||||
public class UDPPacket10PingPong extends UDPPacket {
|
||||
|
||||
public int pingId;
|
||||
public int pingId;
|
||||
|
||||
public UDPPacket10PingPong() {
|
||||
}
|
||||
public UDPPacket10PingPong() {
|
||||
}
|
||||
|
||||
public UDPPacket10PingPong(int pingId) {
|
||||
this.pingId = pingId;
|
||||
}
|
||||
public UDPPacket10PingPong(int pingId) {
|
||||
this.pingId = pingId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 10;
|
||||
}
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
pingId = buf.getInt();
|
||||
}
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
pingId = buf.getInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
buf.putInt(pingId);
|
||||
}
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
buf.putInt(pingId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,29 +5,29 @@ import java.nio.ByteBuffer;
|
||||
|
||||
public class UDPPacket11Serial extends UDPPacket {
|
||||
|
||||
public String serial;
|
||||
public String serial;
|
||||
|
||||
public UDPPacket11Serial() {
|
||||
}
|
||||
public UDPPacket11Serial() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 11;
|
||||
}
|
||||
@Override
|
||||
public int getPacketId() {
|
||||
return 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
int length = buf.getInt();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char ch = (char) buf.get();
|
||||
sb.append(ch);
|
||||
}
|
||||
serial = sb.toString();
|
||||
}
|
||||
@Override
|
||||
public void readData(ByteBuffer buf) throws IOException {
|
||||
int length = buf.getInt();
|
||||
StringBuilder sb = new StringBuilder(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char ch = (char) buf.get();
|
||||
sb.append(ch);
|
||||
}
|
||||
serial = sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
// Never sent back in current protocol
|
||||
}
|
||||
@Override
|
||||
public void writeData(ByteBuffer buf) throws IOException {
|
||||
// Never sent back in current protocol
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user