diff --git a/depthrush/depthrush.vcxproj b/depthrush/depthrush.vcxproj
index af97827..9348b74 100644
--- a/depthrush/depthrush.vcxproj
+++ b/depthrush/depthrush.vcxproj
@@ -171,6 +171,7 @@
+
diff --git a/depthrush/depthrush.vcxproj.filters b/depthrush/depthrush.vcxproj.filters
index e55c07d..6324a0e 100644
--- a/depthrush/depthrush.vcxproj.filters
+++ b/depthrush/depthrush.vcxproj.filters
@@ -103,6 +103,9 @@
Header Files
+
+ Header Files
+
diff --git a/depthrush/includes.h b/depthrush/includes.h
index 94fb7b9..63d8c55 100644
--- a/depthrush/includes.h
+++ b/depthrush/includes.h
@@ -9,6 +9,7 @@
#include "kiero/minhook/include/MinHook.h"
#include "kiero/injector/injector.hpp"
#include "d3d9.h"
+#include "ini.h"
#include "drs.h"
typedef LRESULT(CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
diff --git a/depthrush/ini.h b/depthrush/ini.h
new file mode 100644
index 0000000..cb0b801
--- /dev/null
+++ b/depthrush/ini.h
@@ -0,0 +1,789 @@
+/*
+ * The MIT License (MIT)
+ * Copyright (c) 2018 Danijel Durakovic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // /mINI/ v0.9.14
+ // An INI file reader and writer for the modern age.
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // A tiny utility library for manipulating INI files with a straightforward
+ // API and a minimal footprint. It conforms to the (somewhat) standard INI
+ // format - sections and keys are case insensitive and all leading and
+ // trailing whitespace is ignored. Comments are lines that begin with a
+ // semicolon. Trailing comments are allowed on section lines.
+ //
+ // Files are read on demand, upon which data is kept in memory and the file
+ // is closed. This utility supports lazy writing, which only writes changes
+ // and updates to a file and preserves custom formatting and comments. A lazy
+ // write invoked by a write() call will read the output file, find what
+ // changes have been made and update the file accordingly. If you only need to
+ // generate files, use generate() instead. Section and key order is preserved
+ // on read, write and insert.
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // /* BASIC USAGE EXAMPLE: */
+ //
+ // /* read from file */
+ // mINI::INIFile file("myfile.ini");
+ // mINI::INIStructure ini;
+ // file.read(ini);
+ //
+ // /* read value; gets a reference to actual value in the structure.
+ // if key or section don't exist, a new empty value will be created */
+ // std::string& value = ini["section"]["key"];
+ //
+ // /* read value safely; gets a copy of value in the structure.
+ // does not alter the structure */
+ // std::string value = ini.get("section").get("key");
+ //
+ // /* set or update values */
+ // ini["section"]["key"] = "value";
+ //
+ // /* set multiple values */
+ // ini["section2"].set({
+ // {"key1", "value1"},
+ // {"key2", "value2"}
+ // });
+ //
+ // /* write updates back to file, preserving comments and formatting */
+ // file.write(ini);
+ //
+ // /* or generate a file (overwrites the original) */
+ // file.generate(ini);
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // Long live the INI file!!!
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MINI_INI_H_
+#define MINI_INI_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace mINI
+{
+ namespace INIStringUtil
+ {
+ const char* const whitespaceDelimiters = " \t\n\r\f\v";
+ inline void trim(std::string& str)
+ {
+ str.erase(str.find_last_not_of(whitespaceDelimiters) + 1);
+ str.erase(0, str.find_first_not_of(whitespaceDelimiters));
+ }
+#ifndef MINI_CASE_SENSITIVE
+ inline void toLower(std::string& str)
+ {
+ std::transform(str.begin(), str.end(), str.begin(), [](const char c) {
+ return static_cast(std::tolower(c));
+ });
+ }
+#endif
+ inline void replace(std::string& str, std::string const& a, std::string const& b)
+ {
+ if (!a.empty())
+ {
+ std::size_t pos = 0;
+ while ((pos = str.find(a, pos)) != std::string::npos)
+ {
+ str.replace(pos, a.size(), b);
+ pos += b.size();
+ }
+ }
+ }
+#ifdef _WIN32
+ const char* const endl = "\r\n";
+#else
+ const char* const endl = "\n";
+#endif
+ }
+
+ template
+ class INIMap
+ {
+ private:
+ using T_DataIndexMap = std::unordered_map;
+ using T_DataItem = std::pair;
+ using T_DataContainer = std::vector;
+ using T_MultiArgs = typename std::vector>;
+
+ T_DataIndexMap dataIndexMap;
+ T_DataContainer data;
+
+ inline std::size_t setEmpty(std::string& key)
+ {
+ std::size_t index = data.size();
+ dataIndexMap[key] = index;
+ data.emplace_back(key, T());
+ return index;
+ }
+
+ public:
+ using const_iterator = typename T_DataContainer::const_iterator;
+
+ INIMap() { }
+
+ INIMap(INIMap const& other)
+ {
+ std::size_t data_size = other.data.size();
+ for (std::size_t i = 0; i < data_size; ++i)
+ {
+ auto const& key = other.data[i].first;
+ auto const& obj = other.data[i].second;
+ data.emplace_back(key, obj);
+ }
+ dataIndexMap = T_DataIndexMap(other.dataIndexMap);
+ }
+
+ T& operator[](std::string key)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ bool hasIt = (it != dataIndexMap.end());
+ std::size_t index = (hasIt) ? it->second : setEmpty(key);
+ return data[index].second;
+ }
+ T get(std::string key) const
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it == dataIndexMap.end())
+ {
+ return T();
+ }
+ return T(data[it->second].second);
+ }
+ bool has(std::string key) const
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ return (dataIndexMap.count(key) == 1);
+ }
+ void set(std::string key, T obj)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it != dataIndexMap.end())
+ {
+ data[it->second].second = obj;
+ }
+ else
+ {
+ dataIndexMap[key] = data.size();
+ data.emplace_back(key, obj);
+ }
+ }
+ void set(T_MultiArgs const& multiArgs)
+ {
+ for (auto const& it : multiArgs)
+ {
+ auto const& key = it.first;
+ auto const& obj = it.second;
+ set(key, obj);
+ }
+ }
+ bool remove(std::string key)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it != dataIndexMap.end())
+ {
+ std::size_t index = it->second;
+ data.erase(data.begin() + index);
+ dataIndexMap.erase(it);
+ for (auto& it2 : dataIndexMap)
+ {
+ auto& vi = it2.second;
+ if (vi > index)
+ {
+ vi--;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ void clear()
+ {
+ data.clear();
+ dataIndexMap.clear();
+ }
+ std::size_t size() const
+ {
+ return data.size();
+ }
+ const_iterator begin() const { return data.begin(); }
+ const_iterator end() const { return data.end(); }
+ };
+
+ using INIStructure = INIMap>;
+
+ namespace INIParser
+ {
+ using T_ParseValues = std::pair;
+
+ enum class PDataType : char
+ {
+ PDATA_NONE,
+ PDATA_COMMENT,
+ PDATA_SECTION,
+ PDATA_KEYVALUE,
+ PDATA_UNKNOWN
+ };
+
+ inline PDataType parseLine(std::string line, T_ParseValues& parseData)
+ {
+ parseData.first.clear();
+ parseData.second.clear();
+ INIStringUtil::trim(line);
+ if (line.empty())
+ {
+ return PDataType::PDATA_NONE;
+ }
+ char firstCharacter = line[0];
+ if (firstCharacter == ';')
+ {
+ return PDataType::PDATA_COMMENT;
+ }
+ if (firstCharacter == '[')
+ {
+ auto commentAt = line.find_first_of(';');
+ if (commentAt != std::string::npos)
+ {
+ line = line.substr(0, commentAt);
+ }
+ auto closingBracketAt = line.find_last_of(']');
+ if (closingBracketAt != std::string::npos)
+ {
+ auto section = line.substr(1, closingBracketAt - 1);
+ INIStringUtil::trim(section);
+ parseData.first = section;
+ return PDataType::PDATA_SECTION;
+ }
+ }
+ auto lineNorm = line;
+ INIStringUtil::replace(lineNorm, "\\=", " ");
+ auto equalsAt = lineNorm.find_first_of('=');
+ if (equalsAt != std::string::npos)
+ {
+ auto key = line.substr(0, equalsAt);
+ INIStringUtil::trim(key);
+ INIStringUtil::replace(key, "\\=", "=");
+ auto value = line.substr(equalsAt + 1);
+ INIStringUtil::trim(value);
+ parseData.first = key;
+ parseData.second = value;
+ return PDataType::PDATA_KEYVALUE;
+ }
+ return PDataType::PDATA_UNKNOWN;
+ }
+ }
+
+ class INIReader
+ {
+ public:
+ using T_LineData = std::vector;
+ using T_LineDataPtr = std::shared_ptr;
+
+ bool isBOM = false;
+
+ private:
+ std::ifstream fileReadStream;
+ T_LineDataPtr lineData;
+
+ T_LineData readFile()
+ {
+ fileReadStream.seekg(0, std::ios::end);
+ const std::size_t fileSize = static_cast(fileReadStream.tellg());
+ fileReadStream.seekg(0, std::ios::beg);
+ if (fileSize >= 3) {
+ const char header[3] = {
+ static_cast(fileReadStream.get()),
+ static_cast(fileReadStream.get()),
+ static_cast(fileReadStream.get())
+ };
+ isBOM = (
+ header[0] == static_cast(0xEF) &&
+ header[1] == static_cast(0xBB) &&
+ header[2] == static_cast(0xBF)
+ );
+ }
+ else {
+ isBOM = false;
+ }
+ std::string fileContents;
+ fileContents.resize(fileSize);
+ fileReadStream.seekg(isBOM ? 3 : 0, std::ios::beg);
+ fileReadStream.read(&fileContents[0], fileSize);
+ fileReadStream.close();
+ T_LineData output;
+ if (fileSize == 0)
+ {
+ return output;
+ }
+ std::string buffer;
+ buffer.reserve(50);
+ for (std::size_t i = 0; i < fileSize; ++i)
+ {
+ char& c = fileContents[i];
+ if (c == '\n')
+ {
+ output.emplace_back(buffer);
+ buffer.clear();
+ continue;
+ }
+ if (c != '\0' && c != '\r')
+ {
+ buffer += c;
+ }
+ }
+ output.emplace_back(buffer);
+ return output;
+ }
+
+ public:
+ INIReader(std::string const& filename, bool keepLineData = false)
+ {
+ fileReadStream.open(filename, std::ios::in | std::ios::binary);
+ if (keepLineData)
+ {
+ lineData = std::make_shared();
+ }
+ }
+ ~INIReader() { }
+
+ bool operator>>(INIStructure& data)
+ {
+ if (!fileReadStream.is_open())
+ {
+ return false;
+ }
+ T_LineData fileLines = readFile();
+ std::string section;
+ bool inSection = false;
+ INIParser::T_ParseValues parseData;
+ for (auto const& line : fileLines)
+ {
+ auto parseResult = INIParser::parseLine(line, parseData);
+ if (parseResult == INIParser::PDataType::PDATA_SECTION)
+ {
+ inSection = true;
+ data[section = parseData.first];
+ }
+ else if (inSection && parseResult == INIParser::PDataType::PDATA_KEYVALUE)
+ {
+ auto const& key = parseData.first;
+ auto const& value = parseData.second;
+ data[section][key] = value;
+ }
+ if (lineData && parseResult != INIParser::PDataType::PDATA_UNKNOWN)
+ {
+ if (parseResult == INIParser::PDataType::PDATA_KEYVALUE && !inSection)
+ {
+ continue;
+ }
+ lineData->emplace_back(line);
+ }
+ }
+ return true;
+ }
+ T_LineDataPtr getLines()
+ {
+ return lineData;
+ }
+ };
+
+ class INIGenerator
+ {
+ private:
+ std::ofstream fileWriteStream;
+
+ public:
+ bool prettyPrint = false;
+
+ INIGenerator(std::string const& filename)
+ {
+ fileWriteStream.open(filename, std::ios::out | std::ios::binary);
+ }
+ ~INIGenerator() { }
+
+ bool operator<<(INIStructure const& data)
+ {
+ if (!fileWriteStream.is_open())
+ {
+ return false;
+ }
+ if (!data.size())
+ {
+ return true;
+ }
+ auto it = data.begin();
+ for (;;)
+ {
+ auto const& section = it->first;
+ auto const& collection = it->second;
+ fileWriteStream
+ << "["
+ << section
+ << "]";
+ if (collection.size())
+ {
+ fileWriteStream << INIStringUtil::endl;
+ auto it2 = collection.begin();
+ for (;;)
+ {
+ auto key = it2->first;
+ INIStringUtil::replace(key, "=", "\\=");
+ auto value = it2->second;
+ INIStringUtil::trim(value);
+ fileWriteStream
+ << key
+ << ((prettyPrint) ? " = " : "=")
+ << value;
+ if (++it2 == collection.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ if (++it == data.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ if (prettyPrint)
+ {
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ return true;
+ }
+ };
+
+ class INIWriter
+ {
+ private:
+ using T_LineData = std::vector;
+ using T_LineDataPtr = std::shared_ptr;
+
+ std::string filename;
+
+ T_LineData getLazyOutput(T_LineDataPtr const& lineData, INIStructure& data, INIStructure& original)
+ {
+ T_LineData output;
+ INIParser::T_ParseValues parseData;
+ std::string sectionCurrent;
+ bool parsingSection = false;
+ bool continueToNextSection = false;
+ bool discardNextEmpty = false;
+ bool writeNewKeys = false;
+ std::size_t lastKeyLine = 0;
+ for (auto line = lineData->begin(); line != lineData->end(); ++line)
+ {
+ if (!writeNewKeys)
+ {
+ auto parseResult = INIParser::parseLine(*line, parseData);
+ if (parseResult == INIParser::PDataType::PDATA_SECTION)
+ {
+ if (parsingSection)
+ {
+ writeNewKeys = true;
+ parsingSection = false;
+ --line;
+ continue;
+ }
+ sectionCurrent = parseData.first;
+ if (data.has(sectionCurrent))
+ {
+ parsingSection = true;
+ continueToNextSection = false;
+ discardNextEmpty = false;
+ output.emplace_back(*line);
+ lastKeyLine = output.size();
+ }
+ else
+ {
+ continueToNextSection = true;
+ discardNextEmpty = true;
+ continue;
+ }
+ }
+ else if (parseResult == INIParser::PDataType::PDATA_KEYVALUE)
+ {
+ if (continueToNextSection)
+ {
+ continue;
+ }
+ if (data.has(sectionCurrent))
+ {
+ auto& collection = data[sectionCurrent];
+ auto const& key = parseData.first;
+ auto const& value = parseData.second;
+ if (collection.has(key))
+ {
+ auto outputValue = collection[key];
+ if (value == outputValue)
+ {
+ output.emplace_back(*line);
+ }
+ else
+ {
+ INIStringUtil::trim(outputValue);
+ auto lineNorm = *line;
+ INIStringUtil::replace(lineNorm, "\\=", " ");
+ auto equalsAt = lineNorm.find_first_of('=');
+ auto valueAt = lineNorm.find_first_not_of(
+ INIStringUtil::whitespaceDelimiters,
+ equalsAt + 1
+ );
+ std::string outputLine = line->substr(0, valueAt);
+ if (prettyPrint && equalsAt + 1 == valueAt)
+ {
+ outputLine += " ";
+ }
+ outputLine += outputValue;
+ output.emplace_back(outputLine);
+ }
+ lastKeyLine = output.size();
+ }
+ }
+ }
+ else
+ {
+ if (discardNextEmpty && line->empty())
+ {
+ discardNextEmpty = false;
+ }
+ else if (parseResult != INIParser::PDataType::PDATA_UNKNOWN)
+ {
+ output.emplace_back(*line);
+ }
+ }
+ }
+ if (writeNewKeys || std::next(line) == lineData->end())
+ {
+ T_LineData linesToAdd;
+ if (data.has(sectionCurrent) && original.has(sectionCurrent))
+ {
+ auto const& collection = data[sectionCurrent];
+ auto const& collectionOriginal = original[sectionCurrent];
+ for (auto const& it : collection)
+ {
+ auto key = it.first;
+ if (collectionOriginal.has(key))
+ {
+ continue;
+ }
+ auto value = it.second;
+ INIStringUtil::replace(key, "=", "\\=");
+ INIStringUtil::trim(value);
+ linesToAdd.emplace_back(
+ key + ((prettyPrint) ? " = " : "=") + value
+ );
+ }
+ }
+ if (!linesToAdd.empty())
+ {
+ output.insert(
+ output.begin() + lastKeyLine,
+ linesToAdd.begin(),
+ linesToAdd.end()
+ );
+ }
+ if (writeNewKeys)
+ {
+ writeNewKeys = false;
+ --line;
+ }
+ }
+ }
+ for (auto const& it : data)
+ {
+ auto const& section = it.first;
+ if (original.has(section))
+ {
+ continue;
+ }
+ if (prettyPrint && output.size() > 0 && !output.back().empty())
+ {
+ output.emplace_back();
+ }
+ output.emplace_back("[" + section + "]");
+ auto const& collection = it.second;
+ for (auto const& it2 : collection)
+ {
+ auto key = it2.first;
+ auto value = it2.second;
+ INIStringUtil::replace(key, "=", "\\=");
+ INIStringUtil::trim(value);
+ output.emplace_back(
+ key + ((prettyPrint) ? " = " : "=") + value
+ );
+ }
+ }
+ return output;
+ }
+
+ public:
+ bool prettyPrint = false;
+
+ INIWriter(std::string const& filename)
+ : filename(filename)
+ {
+ }
+ ~INIWriter() { }
+
+ bool operator<<(INIStructure& data)
+ {
+ struct stat buf;
+ bool fileExists = (stat(filename.c_str(), &buf) == 0);
+ if (!fileExists)
+ {
+ INIGenerator generator(filename);
+ generator.prettyPrint = prettyPrint;
+ return generator << data;
+ }
+ INIStructure originalData;
+ T_LineDataPtr lineData;
+ bool readSuccess = false;
+ bool fileIsBOM = false;
+ {
+ INIReader reader(filename, true);
+ if ((readSuccess = reader >> originalData))
+ {
+ lineData = reader.getLines();
+ fileIsBOM = reader.isBOM;
+ }
+ }
+ if (!readSuccess)
+ {
+ return false;
+ }
+ T_LineData output = getLazyOutput(lineData, data, originalData);
+ std::ofstream fileWriteStream(filename, std::ios::out | std::ios::binary);
+ if (fileWriteStream.is_open())
+ {
+ if (fileIsBOM) {
+ const char utf8_BOM[3] = {
+ static_cast(0xEF),
+ static_cast(0xBB),
+ static_cast(0xBF)
+ };
+ fileWriteStream.write(utf8_BOM, 3);
+ }
+ if (output.size())
+ {
+ auto line = output.begin();
+ for (;;)
+ {
+ fileWriteStream << *line;
+ if (++line == output.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ class INIFile
+ {
+ private:
+ std::string filename;
+
+ public:
+ INIFile(std::string const& filename)
+ : filename(filename)
+ { }
+
+ ~INIFile() { }
+
+ bool read(INIStructure& data) const
+ {
+ if (data.size())
+ {
+ data.clear();
+ }
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIReader reader(filename);
+ return reader >> data;
+ }
+ bool generate(INIStructure const& data, bool pretty = false) const
+ {
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIGenerator generator(filename);
+ generator.prettyPrint = pretty;
+ return generator << data;
+ }
+ bool write(INIStructure& data, bool pretty = false) const
+ {
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIWriter writer(filename);
+ writer.prettyPrint = pretty;
+ return writer << data;
+ }
+ };
+}
+
+#endif // MINI_INI_H_
\ No newline at end of file
diff --git a/depthrushConfig/calibration.cpp b/depthrushConfig/calibration.cpp
index c2fa0ef..7caaa47 100644
--- a/depthrushConfig/calibration.cpp
+++ b/depthrushConfig/calibration.cpp
@@ -60,12 +60,26 @@ int calibration() {
// Clean up and proceed to kinect test
kinectScanning = false;
+ std::cout << "Saving the following values to depthrush.ini...\n";
std::cout << std::to_string(xGrad) << " ";
std::cout << std::to_string(xOffset) << " ";
std::cout << std::to_string(yGrad) << " ";
std::cout << std::to_string(yOffset) << " ";
std::cout << std::to_string(zGrad) << " ";
std::cout << std::to_string(zOffset) << "\n";
+
+ // Save values
+ mINI::INIFile file("depthrush.ini");
+ mINI::INIStructure ini;
+ ini["calibration"]["xGrad"] = std::to_string(xGrad);
+ ini["calibration"]["xOffset"] = std::to_string(xOffset);
+ ini["calibration"]["yGrad"] = std::to_string(yGrad);
+ ini["calibration"]["yOffset"] = std::to_string(yOffset);
+ ini["calibration"]["zGrad"] = std::to_string(zGrad);
+ ini["calibration"]["zOffset"] = std::to_string(zOffset);
+ file.generate(ini);
+ std::cout << "Save complete.\n";
+
std::cout << "Proceeding to Kinect Preview..\n";
kinectTest(xGrad, xOffset, yGrad, yOffset, zGrad, zOffset);
});
diff --git a/depthrushConfig/depthrushConfig.cpp b/depthrushConfig/depthrushConfig.cpp
index 917944f..15b9474 100644
--- a/depthrushConfig/depthrushConfig.cpp
+++ b/depthrushConfig/depthrushConfig.cpp
@@ -2,6 +2,23 @@
int main()
{
+ // load config from ini
+ mINI::INIFile file("depthrush.ini");
+ mINI::INIStructure ini;
+ file.read(ini);
+ std::string& readValue = ini["calibration"]["xGrad"];
+ float xGrad = std::stof(readValue);
+ readValue = ini["calibration"]["xOffset"];
+ float xOffset = std::stof(readValue);
+ readValue = ini["calibration"]["yGrad"];
+ float yGrad = std::stof(readValue);
+ readValue = ini["calibration"]["yOffset"];
+ float yOffset = std::stof(readValue);
+ readValue = ini["calibration"]["zGrad"];
+ float zGrad = std::stof(readValue);
+ readValue = ini["calibration"]["zOffset"];
+ float zOffset = std::stof(readValue);
+
int choice = 0;
std::cout << "Depthrush test application\n";
std::cout << "1. Calibrate Kinect\n";
@@ -13,7 +30,7 @@ int main()
return 0;
}
else if (choice == 2) {
- kinectTest(1, 1, 1, 1, 1, 1);
+ kinectTest(xGrad, xOffset, yGrad, yOffset, zGrad, zOffset);
return 0;
}
else {
diff --git a/depthrushConfig/depthrushConfig.vcxproj b/depthrushConfig/depthrushConfig.vcxproj
index ecb007a..0116fe4 100644
--- a/depthrushConfig/depthrushConfig.vcxproj
+++ b/depthrushConfig/depthrushConfig.vcxproj
@@ -139,6 +139,7 @@
+
diff --git a/depthrushConfig/depthrushConfig.vcxproj.filters b/depthrushConfig/depthrushConfig.vcxproj.filters
index 917980d..350adad 100644
--- a/depthrushConfig/depthrushConfig.vcxproj.filters
+++ b/depthrushConfig/depthrushConfig.vcxproj.filters
@@ -35,5 +35,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/depthrushConfig/includes.h b/depthrushConfig/includes.h
index a699c4d..554b0d2 100644
--- a/depthrushConfig/includes.h
+++ b/depthrushConfig/includes.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include "ini.h"
#include "calibration.h"
#include "kinectTest.h"
diff --git a/depthrushConfig/ini.h b/depthrushConfig/ini.h
new file mode 100644
index 0000000..cb0b801
--- /dev/null
+++ b/depthrushConfig/ini.h
@@ -0,0 +1,789 @@
+/*
+ * The MIT License (MIT)
+ * Copyright (c) 2018 Danijel Durakovic
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // /mINI/ v0.9.14
+ // An INI file reader and writer for the modern age.
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // A tiny utility library for manipulating INI files with a straightforward
+ // API and a minimal footprint. It conforms to the (somewhat) standard INI
+ // format - sections and keys are case insensitive and all leading and
+ // trailing whitespace is ignored. Comments are lines that begin with a
+ // semicolon. Trailing comments are allowed on section lines.
+ //
+ // Files are read on demand, upon which data is kept in memory and the file
+ // is closed. This utility supports lazy writing, which only writes changes
+ // and updates to a file and preserves custom formatting and comments. A lazy
+ // write invoked by a write() call will read the output file, find what
+ // changes have been made and update the file accordingly. If you only need to
+ // generate files, use generate() instead. Section and key order is preserved
+ // on read, write and insert.
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // /* BASIC USAGE EXAMPLE: */
+ //
+ // /* read from file */
+ // mINI::INIFile file("myfile.ini");
+ // mINI::INIStructure ini;
+ // file.read(ini);
+ //
+ // /* read value; gets a reference to actual value in the structure.
+ // if key or section don't exist, a new empty value will be created */
+ // std::string& value = ini["section"]["key"];
+ //
+ // /* read value safely; gets a copy of value in the structure.
+ // does not alter the structure */
+ // std::string value = ini.get("section").get("key");
+ //
+ // /* set or update values */
+ // ini["section"]["key"] = "value";
+ //
+ // /* set multiple values */
+ // ini["section2"].set({
+ // {"key1", "value1"},
+ // {"key2", "value2"}
+ // });
+ //
+ // /* write updates back to file, preserving comments and formatting */
+ // file.write(ini);
+ //
+ // /* or generate a file (overwrites the original) */
+ // file.generate(ini);
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+ //
+ // Long live the INI file!!!
+ //
+ ///////////////////////////////////////////////////////////////////////////////
+
+#ifndef MINI_INI_H_
+#define MINI_INI_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace mINI
+{
+ namespace INIStringUtil
+ {
+ const char* const whitespaceDelimiters = " \t\n\r\f\v";
+ inline void trim(std::string& str)
+ {
+ str.erase(str.find_last_not_of(whitespaceDelimiters) + 1);
+ str.erase(0, str.find_first_not_of(whitespaceDelimiters));
+ }
+#ifndef MINI_CASE_SENSITIVE
+ inline void toLower(std::string& str)
+ {
+ std::transform(str.begin(), str.end(), str.begin(), [](const char c) {
+ return static_cast(std::tolower(c));
+ });
+ }
+#endif
+ inline void replace(std::string& str, std::string const& a, std::string const& b)
+ {
+ if (!a.empty())
+ {
+ std::size_t pos = 0;
+ while ((pos = str.find(a, pos)) != std::string::npos)
+ {
+ str.replace(pos, a.size(), b);
+ pos += b.size();
+ }
+ }
+ }
+#ifdef _WIN32
+ const char* const endl = "\r\n";
+#else
+ const char* const endl = "\n";
+#endif
+ }
+
+ template
+ class INIMap
+ {
+ private:
+ using T_DataIndexMap = std::unordered_map;
+ using T_DataItem = std::pair;
+ using T_DataContainer = std::vector;
+ using T_MultiArgs = typename std::vector>;
+
+ T_DataIndexMap dataIndexMap;
+ T_DataContainer data;
+
+ inline std::size_t setEmpty(std::string& key)
+ {
+ std::size_t index = data.size();
+ dataIndexMap[key] = index;
+ data.emplace_back(key, T());
+ return index;
+ }
+
+ public:
+ using const_iterator = typename T_DataContainer::const_iterator;
+
+ INIMap() { }
+
+ INIMap(INIMap const& other)
+ {
+ std::size_t data_size = other.data.size();
+ for (std::size_t i = 0; i < data_size; ++i)
+ {
+ auto const& key = other.data[i].first;
+ auto const& obj = other.data[i].second;
+ data.emplace_back(key, obj);
+ }
+ dataIndexMap = T_DataIndexMap(other.dataIndexMap);
+ }
+
+ T& operator[](std::string key)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ bool hasIt = (it != dataIndexMap.end());
+ std::size_t index = (hasIt) ? it->second : setEmpty(key);
+ return data[index].second;
+ }
+ T get(std::string key) const
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it == dataIndexMap.end())
+ {
+ return T();
+ }
+ return T(data[it->second].second);
+ }
+ bool has(std::string key) const
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ return (dataIndexMap.count(key) == 1);
+ }
+ void set(std::string key, T obj)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it != dataIndexMap.end())
+ {
+ data[it->second].second = obj;
+ }
+ else
+ {
+ dataIndexMap[key] = data.size();
+ data.emplace_back(key, obj);
+ }
+ }
+ void set(T_MultiArgs const& multiArgs)
+ {
+ for (auto const& it : multiArgs)
+ {
+ auto const& key = it.first;
+ auto const& obj = it.second;
+ set(key, obj);
+ }
+ }
+ bool remove(std::string key)
+ {
+ INIStringUtil::trim(key);
+#ifndef MINI_CASE_SENSITIVE
+ INIStringUtil::toLower(key);
+#endif
+ auto it = dataIndexMap.find(key);
+ if (it != dataIndexMap.end())
+ {
+ std::size_t index = it->second;
+ data.erase(data.begin() + index);
+ dataIndexMap.erase(it);
+ for (auto& it2 : dataIndexMap)
+ {
+ auto& vi = it2.second;
+ if (vi > index)
+ {
+ vi--;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ void clear()
+ {
+ data.clear();
+ dataIndexMap.clear();
+ }
+ std::size_t size() const
+ {
+ return data.size();
+ }
+ const_iterator begin() const { return data.begin(); }
+ const_iterator end() const { return data.end(); }
+ };
+
+ using INIStructure = INIMap>;
+
+ namespace INIParser
+ {
+ using T_ParseValues = std::pair;
+
+ enum class PDataType : char
+ {
+ PDATA_NONE,
+ PDATA_COMMENT,
+ PDATA_SECTION,
+ PDATA_KEYVALUE,
+ PDATA_UNKNOWN
+ };
+
+ inline PDataType parseLine(std::string line, T_ParseValues& parseData)
+ {
+ parseData.first.clear();
+ parseData.second.clear();
+ INIStringUtil::trim(line);
+ if (line.empty())
+ {
+ return PDataType::PDATA_NONE;
+ }
+ char firstCharacter = line[0];
+ if (firstCharacter == ';')
+ {
+ return PDataType::PDATA_COMMENT;
+ }
+ if (firstCharacter == '[')
+ {
+ auto commentAt = line.find_first_of(';');
+ if (commentAt != std::string::npos)
+ {
+ line = line.substr(0, commentAt);
+ }
+ auto closingBracketAt = line.find_last_of(']');
+ if (closingBracketAt != std::string::npos)
+ {
+ auto section = line.substr(1, closingBracketAt - 1);
+ INIStringUtil::trim(section);
+ parseData.first = section;
+ return PDataType::PDATA_SECTION;
+ }
+ }
+ auto lineNorm = line;
+ INIStringUtil::replace(lineNorm, "\\=", " ");
+ auto equalsAt = lineNorm.find_first_of('=');
+ if (equalsAt != std::string::npos)
+ {
+ auto key = line.substr(0, equalsAt);
+ INIStringUtil::trim(key);
+ INIStringUtil::replace(key, "\\=", "=");
+ auto value = line.substr(equalsAt + 1);
+ INIStringUtil::trim(value);
+ parseData.first = key;
+ parseData.second = value;
+ return PDataType::PDATA_KEYVALUE;
+ }
+ return PDataType::PDATA_UNKNOWN;
+ }
+ }
+
+ class INIReader
+ {
+ public:
+ using T_LineData = std::vector;
+ using T_LineDataPtr = std::shared_ptr;
+
+ bool isBOM = false;
+
+ private:
+ std::ifstream fileReadStream;
+ T_LineDataPtr lineData;
+
+ T_LineData readFile()
+ {
+ fileReadStream.seekg(0, std::ios::end);
+ const std::size_t fileSize = static_cast(fileReadStream.tellg());
+ fileReadStream.seekg(0, std::ios::beg);
+ if (fileSize >= 3) {
+ const char header[3] = {
+ static_cast(fileReadStream.get()),
+ static_cast(fileReadStream.get()),
+ static_cast(fileReadStream.get())
+ };
+ isBOM = (
+ header[0] == static_cast(0xEF) &&
+ header[1] == static_cast(0xBB) &&
+ header[2] == static_cast(0xBF)
+ );
+ }
+ else {
+ isBOM = false;
+ }
+ std::string fileContents;
+ fileContents.resize(fileSize);
+ fileReadStream.seekg(isBOM ? 3 : 0, std::ios::beg);
+ fileReadStream.read(&fileContents[0], fileSize);
+ fileReadStream.close();
+ T_LineData output;
+ if (fileSize == 0)
+ {
+ return output;
+ }
+ std::string buffer;
+ buffer.reserve(50);
+ for (std::size_t i = 0; i < fileSize; ++i)
+ {
+ char& c = fileContents[i];
+ if (c == '\n')
+ {
+ output.emplace_back(buffer);
+ buffer.clear();
+ continue;
+ }
+ if (c != '\0' && c != '\r')
+ {
+ buffer += c;
+ }
+ }
+ output.emplace_back(buffer);
+ return output;
+ }
+
+ public:
+ INIReader(std::string const& filename, bool keepLineData = false)
+ {
+ fileReadStream.open(filename, std::ios::in | std::ios::binary);
+ if (keepLineData)
+ {
+ lineData = std::make_shared();
+ }
+ }
+ ~INIReader() { }
+
+ bool operator>>(INIStructure& data)
+ {
+ if (!fileReadStream.is_open())
+ {
+ return false;
+ }
+ T_LineData fileLines = readFile();
+ std::string section;
+ bool inSection = false;
+ INIParser::T_ParseValues parseData;
+ for (auto const& line : fileLines)
+ {
+ auto parseResult = INIParser::parseLine(line, parseData);
+ if (parseResult == INIParser::PDataType::PDATA_SECTION)
+ {
+ inSection = true;
+ data[section = parseData.first];
+ }
+ else if (inSection && parseResult == INIParser::PDataType::PDATA_KEYVALUE)
+ {
+ auto const& key = parseData.first;
+ auto const& value = parseData.second;
+ data[section][key] = value;
+ }
+ if (lineData && parseResult != INIParser::PDataType::PDATA_UNKNOWN)
+ {
+ if (parseResult == INIParser::PDataType::PDATA_KEYVALUE && !inSection)
+ {
+ continue;
+ }
+ lineData->emplace_back(line);
+ }
+ }
+ return true;
+ }
+ T_LineDataPtr getLines()
+ {
+ return lineData;
+ }
+ };
+
+ class INIGenerator
+ {
+ private:
+ std::ofstream fileWriteStream;
+
+ public:
+ bool prettyPrint = false;
+
+ INIGenerator(std::string const& filename)
+ {
+ fileWriteStream.open(filename, std::ios::out | std::ios::binary);
+ }
+ ~INIGenerator() { }
+
+ bool operator<<(INIStructure const& data)
+ {
+ if (!fileWriteStream.is_open())
+ {
+ return false;
+ }
+ if (!data.size())
+ {
+ return true;
+ }
+ auto it = data.begin();
+ for (;;)
+ {
+ auto const& section = it->first;
+ auto const& collection = it->second;
+ fileWriteStream
+ << "["
+ << section
+ << "]";
+ if (collection.size())
+ {
+ fileWriteStream << INIStringUtil::endl;
+ auto it2 = collection.begin();
+ for (;;)
+ {
+ auto key = it2->first;
+ INIStringUtil::replace(key, "=", "\\=");
+ auto value = it2->second;
+ INIStringUtil::trim(value);
+ fileWriteStream
+ << key
+ << ((prettyPrint) ? " = " : "=")
+ << value;
+ if (++it2 == collection.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ if (++it == data.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ if (prettyPrint)
+ {
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ return true;
+ }
+ };
+
+ class INIWriter
+ {
+ private:
+ using T_LineData = std::vector;
+ using T_LineDataPtr = std::shared_ptr;
+
+ std::string filename;
+
+ T_LineData getLazyOutput(T_LineDataPtr const& lineData, INIStructure& data, INIStructure& original)
+ {
+ T_LineData output;
+ INIParser::T_ParseValues parseData;
+ std::string sectionCurrent;
+ bool parsingSection = false;
+ bool continueToNextSection = false;
+ bool discardNextEmpty = false;
+ bool writeNewKeys = false;
+ std::size_t lastKeyLine = 0;
+ for (auto line = lineData->begin(); line != lineData->end(); ++line)
+ {
+ if (!writeNewKeys)
+ {
+ auto parseResult = INIParser::parseLine(*line, parseData);
+ if (parseResult == INIParser::PDataType::PDATA_SECTION)
+ {
+ if (parsingSection)
+ {
+ writeNewKeys = true;
+ parsingSection = false;
+ --line;
+ continue;
+ }
+ sectionCurrent = parseData.first;
+ if (data.has(sectionCurrent))
+ {
+ parsingSection = true;
+ continueToNextSection = false;
+ discardNextEmpty = false;
+ output.emplace_back(*line);
+ lastKeyLine = output.size();
+ }
+ else
+ {
+ continueToNextSection = true;
+ discardNextEmpty = true;
+ continue;
+ }
+ }
+ else if (parseResult == INIParser::PDataType::PDATA_KEYVALUE)
+ {
+ if (continueToNextSection)
+ {
+ continue;
+ }
+ if (data.has(sectionCurrent))
+ {
+ auto& collection = data[sectionCurrent];
+ auto const& key = parseData.first;
+ auto const& value = parseData.second;
+ if (collection.has(key))
+ {
+ auto outputValue = collection[key];
+ if (value == outputValue)
+ {
+ output.emplace_back(*line);
+ }
+ else
+ {
+ INIStringUtil::trim(outputValue);
+ auto lineNorm = *line;
+ INIStringUtil::replace(lineNorm, "\\=", " ");
+ auto equalsAt = lineNorm.find_first_of('=');
+ auto valueAt = lineNorm.find_first_not_of(
+ INIStringUtil::whitespaceDelimiters,
+ equalsAt + 1
+ );
+ std::string outputLine = line->substr(0, valueAt);
+ if (prettyPrint && equalsAt + 1 == valueAt)
+ {
+ outputLine += " ";
+ }
+ outputLine += outputValue;
+ output.emplace_back(outputLine);
+ }
+ lastKeyLine = output.size();
+ }
+ }
+ }
+ else
+ {
+ if (discardNextEmpty && line->empty())
+ {
+ discardNextEmpty = false;
+ }
+ else if (parseResult != INIParser::PDataType::PDATA_UNKNOWN)
+ {
+ output.emplace_back(*line);
+ }
+ }
+ }
+ if (writeNewKeys || std::next(line) == lineData->end())
+ {
+ T_LineData linesToAdd;
+ if (data.has(sectionCurrent) && original.has(sectionCurrent))
+ {
+ auto const& collection = data[sectionCurrent];
+ auto const& collectionOriginal = original[sectionCurrent];
+ for (auto const& it : collection)
+ {
+ auto key = it.first;
+ if (collectionOriginal.has(key))
+ {
+ continue;
+ }
+ auto value = it.second;
+ INIStringUtil::replace(key, "=", "\\=");
+ INIStringUtil::trim(value);
+ linesToAdd.emplace_back(
+ key + ((prettyPrint) ? " = " : "=") + value
+ );
+ }
+ }
+ if (!linesToAdd.empty())
+ {
+ output.insert(
+ output.begin() + lastKeyLine,
+ linesToAdd.begin(),
+ linesToAdd.end()
+ );
+ }
+ if (writeNewKeys)
+ {
+ writeNewKeys = false;
+ --line;
+ }
+ }
+ }
+ for (auto const& it : data)
+ {
+ auto const& section = it.first;
+ if (original.has(section))
+ {
+ continue;
+ }
+ if (prettyPrint && output.size() > 0 && !output.back().empty())
+ {
+ output.emplace_back();
+ }
+ output.emplace_back("[" + section + "]");
+ auto const& collection = it.second;
+ for (auto const& it2 : collection)
+ {
+ auto key = it2.first;
+ auto value = it2.second;
+ INIStringUtil::replace(key, "=", "\\=");
+ INIStringUtil::trim(value);
+ output.emplace_back(
+ key + ((prettyPrint) ? " = " : "=") + value
+ );
+ }
+ }
+ return output;
+ }
+
+ public:
+ bool prettyPrint = false;
+
+ INIWriter(std::string const& filename)
+ : filename(filename)
+ {
+ }
+ ~INIWriter() { }
+
+ bool operator<<(INIStructure& data)
+ {
+ struct stat buf;
+ bool fileExists = (stat(filename.c_str(), &buf) == 0);
+ if (!fileExists)
+ {
+ INIGenerator generator(filename);
+ generator.prettyPrint = prettyPrint;
+ return generator << data;
+ }
+ INIStructure originalData;
+ T_LineDataPtr lineData;
+ bool readSuccess = false;
+ bool fileIsBOM = false;
+ {
+ INIReader reader(filename, true);
+ if ((readSuccess = reader >> originalData))
+ {
+ lineData = reader.getLines();
+ fileIsBOM = reader.isBOM;
+ }
+ }
+ if (!readSuccess)
+ {
+ return false;
+ }
+ T_LineData output = getLazyOutput(lineData, data, originalData);
+ std::ofstream fileWriteStream(filename, std::ios::out | std::ios::binary);
+ if (fileWriteStream.is_open())
+ {
+ if (fileIsBOM) {
+ const char utf8_BOM[3] = {
+ static_cast(0xEF),
+ static_cast(0xBB),
+ static_cast(0xBF)
+ };
+ fileWriteStream.write(utf8_BOM, 3);
+ }
+ if (output.size())
+ {
+ auto line = output.begin();
+ for (;;)
+ {
+ fileWriteStream << *line;
+ if (++line == output.end())
+ {
+ break;
+ }
+ fileWriteStream << INIStringUtil::endl;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ class INIFile
+ {
+ private:
+ std::string filename;
+
+ public:
+ INIFile(std::string const& filename)
+ : filename(filename)
+ { }
+
+ ~INIFile() { }
+
+ bool read(INIStructure& data) const
+ {
+ if (data.size())
+ {
+ data.clear();
+ }
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIReader reader(filename);
+ return reader >> data;
+ }
+ bool generate(INIStructure const& data, bool pretty = false) const
+ {
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIGenerator generator(filename);
+ generator.prettyPrint = pretty;
+ return generator << data;
+ }
+ bool write(INIStructure& data, bool pretty = false) const
+ {
+ if (filename.empty())
+ {
+ return false;
+ }
+ INIWriter writer(filename);
+ writer.prettyPrint = pretty;
+ return writer << data;
+ }
+ };
+}
+
+#endif // MINI_INI_H_
\ No newline at end of file