Pass 3
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
#include "RuntimeConfigStore.h"
|
||||
|
||||
#include "RuntimeJson.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
double Clamp01(double value)
|
||||
{
|
||||
return (std::max)(0.0, (std::min)(1.0, value));
|
||||
}
|
||||
|
||||
bool LooksLikePackagedRuntimeRoot(const std::filesystem::path& candidate)
|
||||
{
|
||||
return std::filesystem::exists(candidate / "config" / "runtime-host.json") &&
|
||||
std::filesystem::exists(candidate / "runtime" / "templates" / "shader_wrapper.slang.in") &&
|
||||
std::filesystem::exists(candidate / "shaders");
|
||||
}
|
||||
|
||||
bool LooksLikeRepoRoot(const std::filesystem::path& candidate)
|
||||
{
|
||||
return std::filesystem::exists(candidate / "CMakeLists.txt") &&
|
||||
std::filesystem::exists(candidate / "apps" / "LoopThroughWithOpenGLCompositing");
|
||||
}
|
||||
|
||||
std::filesystem::path FindRepoRootCandidate()
|
||||
{
|
||||
std::vector<std::filesystem::path> rootsToTry;
|
||||
|
||||
char currentDirectory[MAX_PATH] = {};
|
||||
if (GetCurrentDirectoryA(MAX_PATH, currentDirectory) > 0)
|
||||
rootsToTry.push_back(std::filesystem::path(currentDirectory));
|
||||
|
||||
char modulePath[MAX_PATH] = {};
|
||||
DWORD moduleLength = GetModuleFileNameA(NULL, modulePath, MAX_PATH);
|
||||
if (moduleLength > 0 && moduleLength < MAX_PATH)
|
||||
rootsToTry.push_back(std::filesystem::path(modulePath).parent_path());
|
||||
|
||||
for (const std::filesystem::path& startPath : rootsToTry)
|
||||
{
|
||||
std::filesystem::path candidate = startPath;
|
||||
for (int depth = 0; depth < 10 && !candidate.empty(); ++depth)
|
||||
{
|
||||
if (LooksLikePackagedRuntimeRoot(candidate) || LooksLikeRepoRoot(candidate))
|
||||
return candidate;
|
||||
|
||||
candidate = candidate.parent_path();
|
||||
}
|
||||
}
|
||||
|
||||
return std::filesystem::path();
|
||||
}
|
||||
}
|
||||
|
||||
bool RuntimeConfigStore::Initialize(std::string& error)
|
||||
{
|
||||
if (!ResolvePaths(error))
|
||||
return false;
|
||||
if (!LoadConfig(error))
|
||||
return false;
|
||||
RefreshConfigDependentPaths();
|
||||
return true;
|
||||
}
|
||||
|
||||
const RuntimeConfigStore::AppConfig& RuntimeConfigStore::GetConfig() const
|
||||
{
|
||||
return mConfig;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetRepoRoot() const
|
||||
{
|
||||
return mRepoRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetUiRoot() const
|
||||
{
|
||||
return mUiRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetDocsRoot() const
|
||||
{
|
||||
return mDocsRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetShaderRoot() const
|
||||
{
|
||||
return mShaderRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetRuntimeRoot() const
|
||||
{
|
||||
return mRuntimeRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetPresetRoot() const
|
||||
{
|
||||
return mPresetRoot;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetRuntimeStatePath() const
|
||||
{
|
||||
return mRuntimeStatePath;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetWrapperPath() const
|
||||
{
|
||||
return mWrapperPath;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetGeneratedGlslPath() const
|
||||
{
|
||||
return mGeneratedGlslPath;
|
||||
}
|
||||
|
||||
const std::filesystem::path& RuntimeConfigStore::GetPatchedGlslPath() const
|
||||
{
|
||||
return mPatchedGlslPath;
|
||||
}
|
||||
|
||||
void RuntimeConfigStore::SetBoundControlServerPort(unsigned short port)
|
||||
{
|
||||
mConfig.serverPort = port;
|
||||
}
|
||||
|
||||
bool RuntimeConfigStore::ResolvePaths(std::string& error)
|
||||
{
|
||||
mRepoRoot = FindRepoRootCandidate();
|
||||
if (mRepoRoot.empty())
|
||||
{
|
||||
error = "Could not locate the repository root from the current runtime path.";
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::filesystem::path builtUiRoot = mRepoRoot / "ui" / "dist";
|
||||
mUiRoot = std::filesystem::exists(builtUiRoot) ? builtUiRoot : (mRepoRoot / "ui");
|
||||
mDocsRoot = mRepoRoot / "docs";
|
||||
mConfigPath = mRepoRoot / "config" / "runtime-host.json";
|
||||
mRuntimeRoot = mRepoRoot / "runtime";
|
||||
mPresetRoot = mRuntimeRoot / "stack_presets";
|
||||
mRuntimeStatePath = mRuntimeRoot / "runtime_state.json";
|
||||
RefreshConfigDependentPaths();
|
||||
|
||||
std::error_code fsError;
|
||||
std::filesystem::create_directories(mRuntimeRoot / "shader_cache", fsError);
|
||||
std::filesystem::create_directories(mPresetRoot, fsError);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RuntimeConfigStore::LoadConfig(std::string& error)
|
||||
{
|
||||
if (!std::filesystem::exists(mConfigPath))
|
||||
return true;
|
||||
|
||||
std::string configText = ReadTextFile(mConfigPath, error);
|
||||
if (configText.empty())
|
||||
return false;
|
||||
|
||||
JsonValue configJson;
|
||||
if (!ParseJson(configText, configJson, error))
|
||||
return false;
|
||||
|
||||
if (const JsonValue* shaderLibraryValue = configJson.find("shaderLibrary"))
|
||||
mConfig.shaderLibrary = shaderLibraryValue->asString();
|
||||
if (const JsonValue* serverPortValue = configJson.find("serverPort"))
|
||||
mConfig.serverPort = static_cast<unsigned short>(serverPortValue->asNumber(mConfig.serverPort));
|
||||
if (const JsonValue* oscPortValue = configJson.find("oscPort"))
|
||||
mConfig.oscPort = static_cast<unsigned short>(oscPortValue->asNumber(mConfig.oscPort));
|
||||
if (const JsonValue* oscBindAddressValue = configJson.find("oscBindAddress"))
|
||||
mConfig.oscBindAddress = oscBindAddressValue->asString();
|
||||
if (const JsonValue* oscSmoothingValue = configJson.find("oscSmoothing"))
|
||||
mConfig.oscSmoothing = Clamp01(oscSmoothingValue->asNumber(mConfig.oscSmoothing));
|
||||
if (const JsonValue* autoReloadValue = configJson.find("autoReload"))
|
||||
mConfig.autoReload = autoReloadValue->asBoolean(mConfig.autoReload);
|
||||
if (const JsonValue* maxTemporalHistoryFramesValue = configJson.find("maxTemporalHistoryFrames"))
|
||||
{
|
||||
const double configuredValue = maxTemporalHistoryFramesValue->asNumber(static_cast<double>(mConfig.maxTemporalHistoryFrames));
|
||||
mConfig.maxTemporalHistoryFrames = configuredValue <= 0.0 ? 0u : static_cast<unsigned>(configuredValue);
|
||||
}
|
||||
if (const JsonValue* previewFpsValue = configJson.find("previewFps"))
|
||||
{
|
||||
const double configuredValue = previewFpsValue->asNumber(static_cast<double>(mConfig.previewFps));
|
||||
mConfig.previewFps = configuredValue <= 0.0 ? 0u : static_cast<unsigned>(configuredValue);
|
||||
}
|
||||
if (const JsonValue* enableExternalKeyingValue = configJson.find("enableExternalKeying"))
|
||||
mConfig.enableExternalKeying = enableExternalKeyingValue->asBoolean(mConfig.enableExternalKeying);
|
||||
if (const JsonValue* videoFormatValue = configJson.find("videoFormat"))
|
||||
{
|
||||
if (videoFormatValue->isString() && !videoFormatValue->asString().empty())
|
||||
{
|
||||
mConfig.inputVideoFormat = videoFormatValue->asString();
|
||||
mConfig.outputVideoFormat = videoFormatValue->asString();
|
||||
}
|
||||
}
|
||||
if (const JsonValue* frameRateValue = configJson.find("frameRate"))
|
||||
{
|
||||
if (frameRateValue->isString() && !frameRateValue->asString().empty())
|
||||
{
|
||||
mConfig.inputFrameRate = frameRateValue->asString();
|
||||
mConfig.outputFrameRate = frameRateValue->asString();
|
||||
}
|
||||
else if (frameRateValue->isNumber())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << frameRateValue->asNumber();
|
||||
mConfig.inputFrameRate = stream.str();
|
||||
mConfig.outputFrameRate = stream.str();
|
||||
}
|
||||
}
|
||||
if (const JsonValue* inputVideoFormatValue = configJson.find("inputVideoFormat"))
|
||||
{
|
||||
if (inputVideoFormatValue->isString() && !inputVideoFormatValue->asString().empty())
|
||||
mConfig.inputVideoFormat = inputVideoFormatValue->asString();
|
||||
}
|
||||
if (const JsonValue* inputFrameRateValue = configJson.find("inputFrameRate"))
|
||||
{
|
||||
if (inputFrameRateValue->isString() && !inputFrameRateValue->asString().empty())
|
||||
mConfig.inputFrameRate = inputFrameRateValue->asString();
|
||||
else if (inputFrameRateValue->isNumber())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << inputFrameRateValue->asNumber();
|
||||
mConfig.inputFrameRate = stream.str();
|
||||
}
|
||||
}
|
||||
if (const JsonValue* outputVideoFormatValue = configJson.find("outputVideoFormat"))
|
||||
{
|
||||
if (outputVideoFormatValue->isString() && !outputVideoFormatValue->asString().empty())
|
||||
mConfig.outputVideoFormat = outputVideoFormatValue->asString();
|
||||
}
|
||||
if (const JsonValue* outputFrameRateValue = configJson.find("outputFrameRate"))
|
||||
{
|
||||
if (outputFrameRateValue->isString() && !outputFrameRateValue->asString().empty())
|
||||
mConfig.outputFrameRate = outputFrameRateValue->asString();
|
||||
else if (outputFrameRateValue->isNumber())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << outputFrameRateValue->asNumber();
|
||||
mConfig.outputFrameRate = stream.str();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string RuntimeConfigStore::ReadTextFile(const std::filesystem::path& path, std::string& error) const
|
||||
{
|
||||
std::ifstream input(path, std::ios::binary);
|
||||
if (!input)
|
||||
{
|
||||
error = "Could not open file: " + path.string();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::ostringstream buffer;
|
||||
buffer << input.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
void RuntimeConfigStore::RefreshConfigDependentPaths()
|
||||
{
|
||||
mShaderRoot = mRepoRoot / mConfig.shaderLibrary;
|
||||
mWrapperPath = mRuntimeRoot / "shader_cache" / "active_shader_wrapper.slang";
|
||||
mGeneratedGlslPath = mRuntimeRoot / "shader_cache" / "active_shader.raw.frag";
|
||||
mPatchedGlslPath = mRuntimeRoot / "shader_cache" / "active_shader.frag";
|
||||
}
|
||||
Reference in New Issue
Block a user