mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-07 19:00:20 +02:00
222 lines
6.0 KiB
C++
222 lines
6.0 KiB
C++
#include "stdafx.h"
|
|
#include "Configuration.h"
|
|
|
|
#include <picojson.h>
|
|
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <limits>
|
|
|
|
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<picojson::array>())
|
|
throw std::runtime_error("expected array, got " + obj.to_str());
|
|
|
|
auto &arr = obj.get<picojson::array>();
|
|
if (arr.size() != numFloats)
|
|
throw std::runtime_error("wrong buffer size");
|
|
|
|
for (int i = 0; i < numFloats; i++)
|
|
buf[i] = (float) arr[i].get<double>();
|
|
}
|
|
|
|
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<picojson::array>();
|
|
if (arr.size() < 1)
|
|
throw std::runtime_error("no profiles in file");
|
|
|
|
auto obj = arr[0].get<picojson::object>();
|
|
|
|
ctx.referenceTrackingSystem = obj["reference_tracking_system"].get<std::string>();
|
|
ctx.targetTrackingSystem = obj["target_tracking_system"].get<std::string>();
|
|
ctx.calibratedRotation(0) = obj["roll"].get<double>();
|
|
ctx.calibratedRotation(1) = obj["yaw"].get<double>();
|
|
ctx.calibratedRotation(2) = obj["pitch"].get<double>();
|
|
ctx.calibratedTranslation(0) = obj["x"].get<double>();
|
|
ctx.calibratedTranslation(1) = obj["y"].get<double>();
|
|
ctx.calibratedTranslation(2) = obj["z"].get<double>();
|
|
|
|
if (obj["calibration_speed"].is<double>())
|
|
ctx.calibrationSpeed = (CalibrationContext::Speed)(int) obj["calibration_speed"].get<double>();
|
|
|
|
if (obj["chaperone"].is<picojson::object>())
|
|
{
|
|
auto chaperone = obj["chaperone"].get<picojson::object>();
|
|
ctx.chaperone.autoApply = chaperone["auto_apply"].get<bool>();
|
|
|
|
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<picojson::array>())
|
|
throw std::runtime_error("chaperone geometry is not an array");
|
|
|
|
auto &geometry = chaperone["geometry"].get<picojson::array>();
|
|
|
|
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<std::string>(ctx.referenceTrackingSystem);
|
|
profile["target_tracking_system"].set<std::string>(ctx.targetTrackingSystem);
|
|
profile["roll"].set<double>(ctx.calibratedRotation(0));
|
|
profile["yaw"].set<double>(ctx.calibratedRotation(1));
|
|
profile["pitch"].set<double>(ctx.calibratedRotation(2));
|
|
profile["x"].set<double>(ctx.calibratedTranslation(0));
|
|
profile["y"].set<double>(ctx.calibratedTranslation(1));
|
|
profile["z"].set<double>(ctx.calibratedTranslation(2));
|
|
|
|
double speed = (int) ctx.calibrationSpeed;
|
|
profile["calibration_speed"].set<double>(speed);
|
|
|
|
if (ctx.chaperone.valid)
|
|
{
|
|
picojson::object chaperone;
|
|
chaperone["auto_apply"].set<bool>(ctx.chaperone.autoApply);
|
|
chaperone["play_space_size"].set<picojson::array>(FloatArray(ctx.chaperone.playSpaceSize.v, 2));
|
|
|
|
chaperone["standing_center"].set<picojson::array>(FloatArray(
|
|
(float *) ctx.chaperone.standingCenter.m,
|
|
sizeof(ctx.chaperone.standingCenter.m) / sizeof(float)
|
|
));
|
|
|
|
chaperone["geometry"].set<picojson::array>(FloatArray(
|
|
(float *) ctx.chaperone.geometry.data(),
|
|
sizeof(ctx.chaperone.geometry[0]) / sizeof(float) * ctx.chaperone.geometry.size()
|
|
));
|
|
|
|
profile["chaperone"].set<picojson::object>(chaperone);
|
|
}
|
|
|
|
picojson::value profileV;
|
|
profileV.set<picojson::object>(profile);
|
|
|
|
picojson::array profiles;
|
|
profiles.push_back(profileV);
|
|
|
|
picojson::value profilesV;
|
|
profilesV.set<picojson::array>(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<const BYTE*>(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());
|
|
}
|