Change the formating to tabs

This commit is contained in:
lucas lelievre
2022-04-28 03:44:24 +02:00
parent 93c353bbc6
commit 3a80ad0632
118 changed files with 16690 additions and 16689 deletions

View File

@@ -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

View File

@@ -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();
}
}
}
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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() {
}
}
}

View File

@@ -1,7 +1,7 @@
package dev.slimevr.bridge;
public enum PipeState {
CREATED,
OPEN,
ERROR
CREATED,
OPEN,
ERROR
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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) {
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
});
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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());
}
});
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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);
}
});
}
}
}

View File

@@ -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(""), 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(""), 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");
}
}
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -4,7 +4,7 @@ import java.awt.*;
public class EJBag extends EJPanel {
public EJBag() {
super(new GridBagLayout());
}
public EJBag() {
super(new GridBagLayout());
}
}

View File

@@ -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;
}
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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) {
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -4,5 +4,5 @@ import java.util.Map;
public interface ProtocolAPIServer {
Map<Integer, GenericConnection> getAPIConnections();
Map<Integer, GenericConnection> getAPIConnections();
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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());
});
});
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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
}

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -1,8 +1,8 @@
package dev.slimevr.vr.trackers;
public enum DeviceType {
HMD,
CONTROLLER,
TRACKER,
TRACKING_REFERENCE,
HMD,
CONTROLLER,
TRACKER,
TRACKING_REFERENCE,
}

View File

@@ -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;
}
}

View File

@@ -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];
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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
}
}

View File

@@ -2,5 +2,5 @@ package dev.slimevr.vr.trackers;
public interface ShareableTracker extends Tracker {
TrackerRole getTrackerRole();
TrackerRole getTrackerRole();
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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];
}
}

View File

@@ -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];
}
}

View File

@@ -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);
}
}

View File

@@ -2,7 +2,7 @@ package dev.slimevr.vr.trackers;
public interface TrackerWithBattery {
float getBatteryLevel();
float getBatteryLevel();
float getBatteryVoltage();
float getBatteryVoltage();
}

View File

@@ -2,7 +2,7 @@ package dev.slimevr.vr.trackers;
public interface TrackerWithTPS {
float getTPS();
float getTPS();
void dataTick();
void dataTick();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}

View File

@@ -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