#include "stdafx.h" #include "Configuration.h" #include #include #include #include #include #include static picojson::array FloatArray(const float *buf, int numFloats) { picojson::array arr; for (int i = 0; i < numFloats; i++) arr.push_back(picojson::value(double(buf[i]))); return arr; } static void LoadFloatArray(const picojson::value &obj, float *buf, int numFloats) { if (!obj.is()) throw std::runtime_error("expected array, got " + obj.to_str()); auto &arr = obj.get(); if (arr.size() != numFloats) throw std::runtime_error("wrong buffer size"); for (int i = 0; i < numFloats; i++) buf[i] = (float) arr[i].get(); } static void ParseProfile(CalibrationContext &ctx, std::istream &stream) { picojson::value v; std::string err = picojson::parse(v, stream); if (!err.empty()) throw std::runtime_error(err); auto arr = v.get(); if (arr.size() < 1) throw std::runtime_error("no profiles in file"); auto obj = arr[0].get(); ctx.referenceTrackingSystem = obj["reference_tracking_system"].get(); ctx.targetTrackingSystem = obj["target_tracking_system"].get(); ctx.calibratedRotation(0) = obj["roll"].get(); ctx.calibratedRotation(1) = obj["yaw"].get(); ctx.calibratedRotation(2) = obj["pitch"].get(); ctx.calibratedTranslation(0) = obj["x"].get(); ctx.calibratedTranslation(1) = obj["y"].get(); ctx.calibratedTranslation(2) = obj["z"].get(); if (obj["calibration_speed"].is()) ctx.calibrationSpeed = (CalibrationContext::Speed)(int) obj["calibration_speed"].get(); if (obj["chaperone"].is()) { auto chaperone = obj["chaperone"].get(); ctx.chaperone.autoApply = chaperone["auto_apply"].get(); LoadFloatArray(chaperone["play_space_size"], ctx.chaperone.playSpaceSize.v, 2); LoadFloatArray( chaperone["standing_center"], (float *) ctx.chaperone.standingCenter.m, sizeof(ctx.chaperone.standingCenter.m) / sizeof(float) ); if (!chaperone["geometry"].is()) throw std::runtime_error("chaperone geometry is not an array"); auto &geometry = chaperone["geometry"].get(); if (geometry.size() > 0) { ctx.chaperone.geometry.resize(geometry.size() * sizeof(float) / sizeof(ctx.chaperone.geometry[0])); LoadFloatArray(chaperone["geometry"], (float *) ctx.chaperone.geometry.data(), geometry.size()); ctx.chaperone.valid = true; } } ctx.validProfile = true; } static void WriteProfile(CalibrationContext &ctx, std::ostream &out) { if (!ctx.validProfile) return; picojson::object profile; profile["reference_tracking_system"].set(ctx.referenceTrackingSystem); profile["target_tracking_system"].set(ctx.targetTrackingSystem); profile["roll"].set(ctx.calibratedRotation(0)); profile["yaw"].set(ctx.calibratedRotation(1)); profile["pitch"].set(ctx.calibratedRotation(2)); profile["x"].set(ctx.calibratedTranslation(0)); profile["y"].set(ctx.calibratedTranslation(1)); profile["z"].set(ctx.calibratedTranslation(2)); double speed = (int) ctx.calibrationSpeed; profile["calibration_speed"].set(speed); if (ctx.chaperone.valid) { picojson::object chaperone; chaperone["auto_apply"].set(ctx.chaperone.autoApply); chaperone["play_space_size"].set(FloatArray(ctx.chaperone.playSpaceSize.v, 2)); chaperone["standing_center"].set(FloatArray( (float *) ctx.chaperone.standingCenter.m, sizeof(ctx.chaperone.standingCenter.m) / sizeof(float) )); chaperone["geometry"].set(FloatArray( (float *) ctx.chaperone.geometry.data(), sizeof(ctx.chaperone.geometry[0]) / sizeof(float) * ctx.chaperone.geometry.size() )); profile["chaperone"].set(chaperone); } picojson::value profileV; profileV.set(profile); picojson::array profiles; profiles.push_back(profileV); picojson::value profilesV; profilesV.set(profiles); out << profilesV.serialize(true); } static void LogRegistryResult(LSTATUS result) { char *message; FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, result, LANG_USER_DEFAULT, (LPSTR)&message, 0, NULL); std::cerr << "Opening registry key: " << message << std::endl; } static const char *RegistryKey = "Software\\OpenVR-SpaceCalibrator"; static std::string ReadRegistryKey() { DWORD size = 0; auto result = RegGetValueA(HKEY_CURRENT_USER_LOCAL_SETTINGS, RegistryKey, "Config", RRF_RT_REG_SZ, 0, 0, &size); if (result != ERROR_SUCCESS) { LogRegistryResult(result); return ""; } std::string str; str.resize(size); result = RegGetValueA(HKEY_CURRENT_USER_LOCAL_SETTINGS, RegistryKey, "Config", RRF_RT_REG_SZ, 0, &str[0], &size); if (result != ERROR_SUCCESS) { LogRegistryResult(result); return ""; } str.resize(size - 1); return str; } static void WriteRegistryKey(std::string str) { HKEY hkey; auto result = RegCreateKeyExA(HKEY_CURRENT_USER_LOCAL_SETTINGS, RegistryKey, 0, REG_NONE, 0, KEY_ALL_ACCESS, 0, &hkey, 0); if (result != ERROR_SUCCESS) { LogRegistryResult(result); return; } DWORD size = str.size() + 1; result = RegSetValueExA(hkey, "Config", 0, REG_SZ, reinterpret_cast(str.c_str()), size); if (result != ERROR_SUCCESS) LogRegistryResult(result); RegCloseKey(hkey); } void LoadProfile(CalibrationContext &ctx) { ctx.validProfile = false; auto str = ReadRegistryKey(); if (str == "") { std::cout << "Profile is empty" << std::endl; return; } try { std::stringstream io(str); ParseProfile(ctx, io); std::cout << "Loaded profile" << std::endl; } catch (const std::runtime_error &e) { std::cerr << "Error loading profile: " << e.what() << std::endl; } } void SaveProfile(CalibrationContext &ctx) { std::cout << "Saving profile to registry" << std::endl; std::stringstream io; WriteProfile(ctx, io); WriteRegistryKey(io.str()); }