diff --git a/.gitmodules b/.gitmodules index 1175981..7f387dc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "external/openvr"] path = external/openvr url = https://github.com/ValveSoftware/openvr.git +[submodule "external/json"] + path = external/json + url = git@github.com:nlohmann/json.git diff --git a/external/json b/external/json new file mode 160000 index 0000000..9cca280 --- /dev/null +++ b/external/json @@ -0,0 +1 @@ +Subproject commit 9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03 diff --git a/vrto3d/src/hmd_device_driver.cpp b/vrto3d/src/hmd_device_driver.cpp index 1937154..2ec3ba5 100644 --- a/vrto3d/src/hmd_device_driver.cpp +++ b/vrto3d/src/hmd_device_driver.cpp @@ -16,15 +16,17 @@ */ #include "hmd_device_driver.h" #include "key_mappings.h" - #include "driverlog.h" #include "vrmath.h" +#include "json_manager.h" + #include #include #include #include #include #include +#include // Link the XInput library #pragma comment(lib, "XInput.lib") @@ -699,70 +701,62 @@ void MockControllerDeviceDriver::FocusUpdateThread() //----------------------------------------------------------------------------- -// Purpose: Load Game Specific Settings from Steam\config\steamvr.vrsettings +// Purpose: Load Game Specific Settings from Documents\My games\vrto3d\app_name_config.json //----------------------------------------------------------------------------- void MockControllerDeviceDriver::LoadSettings(const std::string& app_name) { if (app_name != app_name_) { app_name_ = app_name; - auto* vrs = vr::VRSettings(); - - try { - bool profile = vrs->GetBool(stereo_display_settings_section, app_name.c_str()); - if (profile) - { - stereo_display_component_->LoadSettings(app_name, device_index_); - BeepSuccess(); - } - else - { - DriverLog("No settings found for %s profile\n", app_name); - } - } - catch (...) { - DriverLog("No settings found for %s profile\n", app_name); - } + stereo_display_component_->LoadSettings(app_name, device_index_); } } //----------------------------------------------------------------------------- -// Purpose: Save Game Specific Settings to Steam\config\steamvr.vrsettings +// Purpose: Save Game Specific Settings to Documents\My games\vrto3d\app_name_config.json //----------------------------------------------------------------------------- -void MockControllerDeviceDriver::SaveSettings() -{ - auto* vrs = vr::VRSettings(); +void MockControllerDeviceDriver::SaveSettings() { + // Create a JSON object to hold all the configuration data + nlohmann::json jsonConfig; auto config = stereo_display_component_->GetConfig(); - vrs->SetBool(stereo_display_settings_section, app_name_.c_str(), true); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/depth").c_str(), stereo_display_component_->GetDepth()); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/convergence").c_str(), stereo_display_component_->GetConvergence()); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/hmd_height").c_str(), config.hmd_height); - vrs->SetBool(stereo_display_settings_section, (app_name_ + "/pitch_enable").c_str(), config.pitch_enable); - vrs->SetBool(stereo_display_settings_section, (app_name_ + "/yaw_enable").c_str(), config.yaw_enable); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/pose_reset_key").c_str(), config.pose_reset_key); - vrs->SetBool(stereo_display_settings_section, (app_name_ + "/reset_xinput").c_str(), config.reset_xinput); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/ctrl_toggle_key").c_str(), config.ctrl_toggle_key); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/ctrl_toggle_type").c_str(), config.ctrl_type); - vrs->SetBool(stereo_display_settings_section, (app_name_ + "/ctrl_xinput").c_str(), config.ctrl_xinput); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/pitch_radius").c_str(), config.pitch_radius); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/ctrl_deadzone").c_str(), config.ctrl_deadzone); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/ctrl_sensitivity").c_str(), config.ctrl_sensitivity); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/num_user_settings").c_str(), config.num_user_settings); + // Populate the JSON object with settings + jsonConfig["depth"] = stereo_display_component_->GetDepth(); + jsonConfig["convergence"] = stereo_display_component_->GetConvergence(); + jsonConfig["hmd_height"] = config.hmd_height; + jsonConfig["pitch_enable"] = config.pitch_enable; + jsonConfig["yaw_enable"] = config.yaw_enable; + jsonConfig["pose_reset_key"] = config.pose_reset_key; + jsonConfig["reset_xinput"] = config.reset_xinput; + jsonConfig["ctrl_toggle_key"] = config.ctrl_toggle_key; + jsonConfig["ctrl_toggle_type"] = config.ctrl_type; + jsonConfig["ctrl_xinput"] = config.ctrl_xinput; + jsonConfig["pitch_radius"] = config.pitch_radius; + jsonConfig["ctrl_deadzone"] = config.ctrl_deadzone; + jsonConfig["ctrl_sensitivity"] = config.ctrl_sensitivity; + jsonConfig["num_user_settings"] = config.num_user_settings; + + // Store user settings as an array + for (int i = 0; i < config.num_user_settings; i++) { + nlohmann::json userSettings; + userSettings["user_load_key"] = config.user_load_key[i]; + userSettings["user_store_key"] = config.user_store_key[i]; + userSettings["user_key_type"] = config.user_key_type[i]; + userSettings["user_depth"] = config.user_depth[i]; + userSettings["user_convergence"] = config.user_convergence[i]; + userSettings["load_xinput"] = config.load_xinput[i]; + + // Append to JSON array in the main config + jsonConfig["user_settings"].push_back(userSettings); + } - for (int i = 0; i < config.num_user_settings; i++) - { - auto si = std::to_string(i + 1); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/user_load_key" + si).c_str(), config.user_load_key[i]); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/user_store_key" + si).c_str(), config.user_store_key[i]); - vrs->SetInt32(stereo_display_settings_section, (app_name_ + "/user_key_type" + si).c_str(), config.user_key_type[i]); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/user_depth" + si).c_str(), config.user_depth[i]); - vrs->SetFloat(stereo_display_settings_section, (app_name_ + "/user_convergence" + si).c_str(), config.user_convergence[i]); - vrs->SetBool(stereo_display_settings_section, (app_name_ + "/load_xinput" + si).c_str(), config.load_xinput[i]); + // Now write this JSON object to a file + JsonManager json_manager; + if (json_manager.writeJsonToFile(app_name_ + "_config.json", jsonConfig)) { + DriverLog("Settings saved to %s profile\n", app_name_.c_str()); + BeepSuccess(); } - DriverLog("Saved to %s profile\n", app_name_); - BeepSuccess(); } @@ -1196,59 +1190,78 @@ void StereoDisplayComponent::SetReset() //----------------------------------------------------------------------------- -// Purpose: Load Game Specific Settings from Steam\config\steamvr.vrsettings +// Purpose: Load Game Specific Settings from Documents\My games\vrto3d\app_name_config.json //----------------------------------------------------------------------------- -void StereoDisplayComponent::LoadSettings(const std::string& app_name, uint32_t device_index) -{ - auto* vrs = vr::VRSettings(); - std::unique_lock lock(cfg_mutex_); +void StereoDisplayComponent::LoadSettings(const std::string& app_name, uint32_t device_index) { + JsonManager json_manager; + auto config = GetConfig(); - try { - config_.depth = vrs->GetFloat(stereo_display_settings_section, (app_name + "/depth").c_str()); - config_.convergence = vrs->GetFloat(stereo_display_settings_section, (app_name + "/convergence").c_str()); - config_.hmd_height = vrs->GetFloat(stereo_display_settings_section, (app_name + "/hmd_height").c_str()); - config_.pitch_enable = vrs->GetBool(stereo_display_settings_section, (app_name + "/pitch_enable").c_str()); - config_.yaw_enable = vrs->GetBool(stereo_display_settings_section, (app_name + "/yaw_enable").c_str()); - config_.pose_reset_key = vrs->GetInt32(stereo_display_settings_section, (app_name + "/pose_reset_key").c_str()); - config_.reset_xinput = vrs->GetBool(stereo_display_settings_section, (app_name + "/reset_xinput").c_str()); - config_.ctrl_toggle_key = vrs->GetInt32(stereo_display_settings_section, (app_name + "/ctrl_toggle_key").c_str()); - config_.ctrl_type = vrs->GetInt32(stereo_display_settings_section, (app_name + "/ctrl_toggle_type").c_str()); - config_.ctrl_xinput = vrs->GetBool(stereo_display_settings_section, (app_name + "/ctrl_xinput").c_str()); - config_.pitch_radius = vrs->GetFloat(stereo_display_settings_section, (app_name + "/pitch_radius").c_str()); - config_.ctrl_deadzone = vrs->GetFloat(stereo_display_settings_section, (app_name + "/ctrl_deadzone").c_str()); - config_.ctrl_sensitivity = vrs->GetFloat(stereo_display_settings_section, (app_name + "/ctrl_sensitivity").c_str()); - config_.num_user_settings = vrs->GetInt32(stereo_display_settings_section, (app_name + "/num_user_settings").c_str()); - - config_.user_load_key.resize(config_.num_user_settings); - config_.user_store_key.resize(config_.num_user_settings); - config_.user_key_type.resize(config_.num_user_settings); - config_.user_depth.resize(config_.num_user_settings); - config_.user_convergence.resize(config_.num_user_settings); - config_.prev_depth.resize(config_.num_user_settings); - config_.prev_convergence.resize(config_.num_user_settings); - config_.was_held.resize(config_.num_user_settings); - config_.load_xinput.resize(config_.num_user_settings); - config_.sleep_count.resize(config_.num_user_settings); - for (int i = 0; i < config_.num_user_settings; i++) - { - auto si = std::to_string(i + 1); - config_.user_load_key[i] = vrs->GetInt32(stereo_display_settings_section, (app_name + "/user_load_key" + si).c_str()); - config_.user_store_key[i] = vrs->GetInt32(stereo_display_settings_section, (app_name + "/user_store_key" + si).c_str()); - config_.user_key_type[i] = vrs->GetInt32(stereo_display_settings_section, (app_name + "/user_key_type" + si).c_str()); - config_.user_depth[i] = vrs->GetFloat(stereo_display_settings_section, (app_name + "/user_depth" + si).c_str()); - config_.user_convergence[i] = vrs->GetFloat(stereo_display_settings_section, (app_name + "/user_convergence" + si).c_str()); - config_.load_xinput[i] = vrs->GetBool(stereo_display_settings_section, (app_name + "/load_xinput" + si).c_str()); - } + // Attempt to read the JSON settings file + nlohmann::json jsonConfig = json_manager.readJsonFromFile(app_name + "_config.json"); - AdjustDepth(config_.depth, false, device_index); - AdjustConvergence(config_.convergence, false, device_index); - config_.pose_reset = true; + // Check if the JSON file was successfully read + if (jsonConfig.is_null()) { + DriverLog("No profile found for %s\n", app_name.c_str()); + return; + } - DriverLog("Loaded %s profile\n", app_name); + try { + // Attempt to load all settings from the JSON object + config.depth = jsonConfig.at("depth").get(); + config.convergence = jsonConfig.at("convergence").get(); + config.hmd_height = jsonConfig.at("hmd_height").get(); + config.pitch_enable = jsonConfig.at("pitch_enable").get(); + config.yaw_enable = jsonConfig.at("yaw_enable").get(); + config.pose_reset_key = jsonConfig.at("pose_reset_key").get(); + config.reset_xinput = jsonConfig.at("reset_xinput").get(); + config.ctrl_toggle_key = jsonConfig.at("ctrl_toggle_key").get(); + config.ctrl_type = jsonConfig.at("ctrl_toggle_type").get(); + config.ctrl_xinput = jsonConfig.at("ctrl_xinput").get(); + config.pitch_radius = jsonConfig.at("pitch_radius").get(); + config.ctrl_deadzone = jsonConfig.at("ctrl_deadzone").get(); + config.ctrl_sensitivity = jsonConfig.at("ctrl_sensitivity").get(); + config.num_user_settings = jsonConfig.at("num_user_settings").get(); + + // Resize vectors based on the number of user settings + config.user_load_key.resize(config.num_user_settings); + config.user_store_key.resize(config.num_user_settings); + config.user_key_type.resize(config.num_user_settings); + config.user_depth.resize(config.num_user_settings); + config.user_convergence.resize(config.num_user_settings); + config.prev_depth.resize(config.num_user_settings); + config.prev_convergence.resize(config.num_user_settings); + config.was_held.resize(config.num_user_settings); + config.load_xinput.resize(config.num_user_settings); + config.sleep_count.resize(config.num_user_settings); + + // Load the user settings array + const auto& userSettingsArray = jsonConfig.at("user_settings"); + for (int i = 0; i < config.num_user_settings; i++) { + const auto& userSetting = userSettingsArray.at(i); + + config.user_load_key[i] = userSetting.at("user_load_key").get(); + config.user_store_key[i] = userSetting.at("user_store_key").get(); + config.user_key_type[i] = userSetting.at("user_key_type").get(); + config.user_depth[i] = userSetting.at("user_depth").get(); + config.user_convergence[i] = userSetting.at("user_convergence").get(); + config.load_xinput[i] = userSetting.at("load_xinput").get(); + } } - catch (...) { - DriverLog("Failed loading settings for %s profile\n", app_name); + catch (const nlohmann::json::exception& e) { + // Catch any JSON-related exceptions (missing field, wrong type, etc.) + DriverLog("Profile corrupt or missing fields %s: %s\n", app_name.c_str(), e.what()); + return; } + + // Apply loaded settings + AdjustDepth(config.depth, false, device_index); + AdjustConvergence(config.convergence, false, device_index); + config.pose_reset = true; + + std::unique_lock lock(cfg_mutex_); + config_ = config; + DriverLog("Loaded %s profile\n", app_name.c_str()); + BeepSuccess(); } diff --git a/vrto3d/src/json_manager.cpp b/vrto3d/src/json_manager.cpp new file mode 100644 index 0000000..e7bea51 --- /dev/null +++ b/vrto3d/src/json_manager.cpp @@ -0,0 +1,86 @@ +/* + * This file is part of VRto3D. + * + * VRto3D is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VRto3D is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with VRto3D. If not, see . + */ + +#include "json_manager.h" +#include "driverlog.h" + +#include +#include +#include +#include + +// Include the nlohmann/json library +#include + +JsonManager::JsonManager() { + vrto3dFolder = getVrto3DPath(); + createFolderIfNotExist(vrto3dFolder); +} + +std::string JsonManager::getDocumentsFolderPath() { + PWSTR path = NULL; + HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &path); + if (SUCCEEDED(hr)) { + char charPath[MAX_PATH]; + size_t convertedChars = 0; + wcstombs_s(&convertedChars, charPath, MAX_PATH, path, _TRUNCATE); + CoTaskMemFree(path); + return std::string(charPath); + } + else { + DriverLog("Failed to get Documents folder path\n"); + } +} + +std::string JsonManager::getVrto3DPath() { + return getDocumentsFolderPath() + "\\My Games\\vrto3d"; +} + +void JsonManager::createFolderIfNotExist(const std::string& path) { + if (!std::filesystem::exists(path)) { + std::filesystem::create_directories(path); + } +} + +bool JsonManager::writeJsonToFile(const std::string& fileName, const nlohmann::json& jsonData) { + std::string filePath = vrto3dFolder + "\\" + fileName; + std::ofstream file(filePath); + if (file.is_open()) { + file << jsonData.dump(4); // Pretty-print the JSON with an indent of 4 spaces + file.close(); + return true; + } + else { + DriverLog("Failed to save profile: %s\n", fileName); + return false; + } +} + +nlohmann::json JsonManager::readJsonFromFile(const std::string& fileName) { + std::string filePath = vrto3dFolder + "\\" + fileName; + std::ifstream file(filePath); + if (file.is_open()) { + nlohmann::json jsonData; + file >> jsonData; + file.close(); + return jsonData; + } + else { + DriverLog("No profile found: %s\n", fileName); + return {}; + } +} diff --git a/vrto3d/src/json_manager.h b/vrto3d/src/json_manager.h new file mode 100644 index 0000000..732ce1a --- /dev/null +++ b/vrto3d/src/json_manager.h @@ -0,0 +1,34 @@ +/* + * This file is part of VRto3D. + * + * VRto3D is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VRto3D is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with VRto3D. If not, see . + */ +#pragma once + +#include +#include + +class JsonManager { +public: + JsonManager(); + + bool writeJsonToFile(const std::string& fileName, const nlohmann::json& jsonData); + nlohmann::json readJsonFromFile(const std::string& fileName); + +private: + std::string vrto3dFolder; + std::string getDocumentsFolderPath(); + std::string getVrto3DPath(); + void createFolderIfNotExist(const std::string& path); +}; diff --git a/vrto3d/vrto3d.vcxproj b/vrto3d/vrto3d.vcxproj index 62419cf..9cbd0c0 100644 --- a/vrto3d/vrto3d.vcxproj +++ b/vrto3d/vrto3d.vcxproj @@ -98,7 +98,8 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + ..\external\json\include;..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + stdcpp17 Console @@ -121,7 +122,8 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + ..\external\json\include;..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + stdcpp17 Console @@ -144,7 +146,8 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + ..\external\json\include;..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + stdcpp17 Console @@ -167,7 +170,8 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + ..\external\json\include;..\external\openvr\headers;..\utils\driverlog;..\utils\vrmath + stdcpp17 Console @@ -188,10 +192,12 @@ + +