runtime udates
This commit is contained in:
@@ -825,182 +825,6 @@ void RuntimeHost::ClearReloadRequest()
|
|||||||
mReloadRequested = false;
|
mReloadRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeHost::AddLayer(const std::string& shaderId, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
auto shaderIt = mPackagesById.find(shaderId);
|
|
||||||
if (shaderIt == mPackagesById.end())
|
|
||||||
{
|
|
||||||
error = "Unknown shader id: " + shaderId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerPersistentState layer;
|
|
||||||
layer.id = GenerateLayerId();
|
|
||||||
layer.shaderId = shaderId;
|
|
||||||
layer.bypass = false;
|
|
||||||
EnsureLayerDefaultsLocked(layer, shaderIt->second);
|
|
||||||
mPersistentState.layers.push_back(layer);
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::RemoveLayer(const std::string& layerId, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
auto it = std::find_if(mPersistentState.layers.begin(), mPersistentState.layers.end(),
|
|
||||||
[&layerId](const LayerPersistentState& layer) { return layer.id == layerId; });
|
|
||||||
if (it == mPersistentState.layers.end())
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPersistentState.layers.erase(it);
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::MoveLayer(const std::string& layerId, int direction, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
auto it = std::find_if(mPersistentState.layers.begin(), mPersistentState.layers.end(),
|
|
||||||
[&layerId](const LayerPersistentState& layer) { return layer.id == layerId; });
|
|
||||||
if (it == mPersistentState.layers.end())
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::ptrdiff_t index = std::distance(mPersistentState.layers.begin(), it);
|
|
||||||
const std::ptrdiff_t newIndex = index + direction;
|
|
||||||
if (newIndex < 0 || newIndex >= static_cast<std::ptrdiff_t>(mPersistentState.layers.size()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
std::swap(mPersistentState.layers[index], mPersistentState.layers[newIndex]);
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
auto it = std::find_if(mPersistentState.layers.begin(), mPersistentState.layers.end(),
|
|
||||||
[&layerId](const LayerPersistentState& layer) { return layer.id == layerId; });
|
|
||||||
if (it == mPersistentState.layers.end())
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPersistentState.layers.empty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (targetIndex >= mPersistentState.layers.size())
|
|
||||||
targetIndex = mPersistentState.layers.size() - 1;
|
|
||||||
|
|
||||||
const std::size_t sourceIndex = static_cast<std::size_t>(std::distance(mPersistentState.layers.begin(), it));
|
|
||||||
if (sourceIndex == targetIndex)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
LayerPersistentState movedLayer = *it;
|
|
||||||
mPersistentState.layers.erase(mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(sourceIndex));
|
|
||||||
mPersistentState.layers.insert(mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(targetIndex), movedLayer);
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
LayerPersistentState* layer = FindLayerById(layerId);
|
|
||||||
if (!layer)
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer->bypass = bypassed;
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkParameterStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
LayerPersistentState* layer = FindLayerById(layerId);
|
|
||||||
if (!layer)
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto shaderIt = mPackagesById.find(shaderId);
|
|
||||||
if (shaderIt == mPackagesById.end())
|
|
||||||
{
|
|
||||||
error = "Unknown shader id: " + shaderId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer->shaderId = shaderId;
|
|
||||||
layer->parameterValues.clear();
|
|
||||||
EnsureLayerDefaultsLocked(*layer, shaderIt->second);
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
|
|
||||||
LayerPersistentState* layer = FindLayerById(layerId);
|
|
||||||
if (!layer)
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto shaderIt = mPackagesById.find(layer->shaderId);
|
|
||||||
if (shaderIt == mPackagesById.end())
|
|
||||||
{
|
|
||||||
error = "Unknown shader id: " + layer->shaderId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShaderPackage& shaderPackage = shaderIt->second;
|
|
||||||
auto parameterIt = std::find_if(shaderPackage.parameters.begin(), shaderPackage.parameters.end(),
|
|
||||||
[¶meterId](const ShaderParameterDefinition& definition) { return definition.id == parameterId; });
|
|
||||||
if (parameterIt == shaderPackage.parameters.end())
|
|
||||||
{
|
|
||||||
error = "Unknown parameter id: " + parameterId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parameterIt->type == ShaderParameterType::Trigger)
|
|
||||||
{
|
|
||||||
ShaderParameterValue& value = layer->parameterValues[parameterId];
|
|
||||||
const double previousCount = value.numberValues.empty() ? 0.0 : value.numberValues[0];
|
|
||||||
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mStartTime).count();
|
|
||||||
value.numberValues = { previousCount + 1.0, triggerTime };
|
|
||||||
MarkParameterStateDirtyLocked();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderParameterValue normalized;
|
|
||||||
if (!NormalizeAndValidateValue(*parameterIt, newValue, normalized, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
layer->parameterValues[parameterId] = normalized;
|
|
||||||
MarkParameterStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
bool RuntimeHost::UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
||||||
{
|
{
|
||||||
return UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, true, error);
|
return UpdateLayerParameterByControlKey(layerKey, parameterKey, newValue, true, error);
|
||||||
@@ -1196,90 +1020,6 @@ bool RuntimeHost::ApplyOscTargetByControlKey(const std::string& layerKey, const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeHost::ResetLayerParameters(const std::string& layerId, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
|
|
||||||
LayerPersistentState* layer = FindLayerById(layerId);
|
|
||||||
if (!layer)
|
|
||||||
{
|
|
||||||
error = "Unknown layer id: " + layerId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto shaderIt = mPackagesById.find(layer->shaderId);
|
|
||||||
if (shaderIt == mPackagesById.end())
|
|
||||||
{
|
|
||||||
error = "Unknown shader id: " + layer->shaderId;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
layer->parameterValues.clear();
|
|
||||||
EnsureLayerDefaultsLocked(*layer, shaderIt->second);
|
|
||||||
MarkParameterStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::SaveStackPreset(const std::string& presetName, std::string& error) const
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
const std::string safeStem = MakeSafePresetFileStem(presetName);
|
|
||||||
if (safeStem.empty())
|
|
||||||
{
|
|
||||||
error = "Preset name must include at least one letter or number.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonValue root = JsonValue::MakeObject();
|
|
||||||
root.set("version", JsonValue(1.0));
|
|
||||||
root.set("name", JsonValue(Trim(presetName)));
|
|
||||||
root.set("layers", SerializeLayerStackLocked());
|
|
||||||
|
|
||||||
return WriteTextFile(mPresetRoot / (safeStem + ".json"), SerializeJson(root, true), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RuntimeHost::LoadStackPreset(const std::string& presetName, std::string& error)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
|
||||||
const std::string safeStem = MakeSafePresetFileStem(presetName);
|
|
||||||
if (safeStem.empty())
|
|
||||||
{
|
|
||||||
error = "Preset name must include at least one letter or number.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::filesystem::path presetPath = mPresetRoot / (safeStem + ".json");
|
|
||||||
std::string presetText = ReadTextFile(presetPath, error);
|
|
||||||
if (presetText.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JsonValue root;
|
|
||||||
if (!ParseJson(presetText, root, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const JsonValue* layersValue = root.find("layers");
|
|
||||||
if (!layersValue || !layersValue->isArray())
|
|
||||||
{
|
|
||||||
error = "Preset file is missing a valid 'layers' array.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<LayerPersistentState> nextLayers;
|
|
||||||
if (!DeserializeLayerStackLocked(*layersValue, nextLayers, error))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (nextLayers.empty())
|
|
||||||
{
|
|
||||||
error = "Preset does not contain any valid layers.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPersistentState.layers = nextLayers;
|
|
||||||
mReloadRequested = true;
|
|
||||||
MarkRenderStateDirtyLocked();
|
|
||||||
return SavePersistentState(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RuntimeHost::SetCompileStatus(bool succeeded, const std::string& message)
|
void RuntimeHost::SetCompileStatus(bool succeeded, const std::string& message)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|||||||
@@ -25,19 +25,9 @@ public:
|
|||||||
bool ManualReloadRequested();
|
bool ManualReloadRequested();
|
||||||
void ClearReloadRequest();
|
void ClearReloadRequest();
|
||||||
|
|
||||||
bool AddLayer(const std::string& shaderId, std::string& error);
|
|
||||||
bool RemoveLayer(const std::string& layerId, std::string& error);
|
|
||||||
bool MoveLayer(const std::string& layerId, int direction, std::string& error);
|
|
||||||
bool MoveLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error);
|
|
||||||
bool SetLayerBypass(const std::string& layerId, bool bypassed, std::string& error);
|
|
||||||
bool SetLayerShader(const std::string& layerId, const std::string& shaderId, std::string& error);
|
|
||||||
bool UpdateLayerParameter(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error);
|
|
||||||
bool UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error);
|
bool UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error);
|
||||||
bool UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error);
|
bool UpdateLayerParameterByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, bool persistState, std::string& error);
|
||||||
bool ApplyOscTargetByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& targetValue, double smoothingAmount, bool& keepApplying, std::string& resolvedLayerId, std::string& resolvedParameterId, ShaderParameterValue& appliedValue, std::string& error);
|
bool ApplyOscTargetByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& targetValue, double smoothingAmount, bool& keepApplying, std::string& resolvedLayerId, std::string& resolvedParameterId, ShaderParameterValue& appliedValue, std::string& error);
|
||||||
bool ResetLayerParameters(const std::string& layerId, std::string& error);
|
|
||||||
bool SaveStackPreset(const std::string& presetName, std::string& error) const;
|
|
||||||
bool LoadStackPreset(const std::string& presetName, std::string& error);
|
|
||||||
|
|
||||||
void SetCompileStatus(bool succeeded, const std::string& message);
|
void SetCompileStatus(bool succeeded, const std::string& message);
|
||||||
void SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
void SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
#include "RuntimeStore.h"
|
#include "RuntimeStore.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string TrimCopy(const std::string& text)
|
||||||
|
{
|
||||||
|
std::size_t start = 0;
|
||||||
|
while (start < text.size() && std::isspace(static_cast<unsigned char>(text[start])))
|
||||||
|
++start;
|
||||||
|
|
||||||
|
std::size_t end = text.size();
|
||||||
|
while (end > start && std::isspace(static_cast<unsigned char>(text[end - 1])))
|
||||||
|
--end;
|
||||||
|
|
||||||
|
return text.substr(start, end - start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
|
RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
|
||||||
mRuntimeHost(runtimeHost)
|
mRuntimeHost(runtimeHost)
|
||||||
{
|
{
|
||||||
@@ -64,37 +80,178 @@ std::string RuntimeStore::BuildPersistentStateJson() const
|
|||||||
|
|
||||||
bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error)
|
bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.AddLayer(shaderId, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
auto shaderIt = mRuntimeHost.mPackagesById.find(shaderId);
|
||||||
|
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState layer;
|
||||||
|
layer.id = mRuntimeHost.GenerateLayerId();
|
||||||
|
layer.shaderId = shaderId;
|
||||||
|
layer.bypass = false;
|
||||||
|
mRuntimeHost.EnsureLayerDefaultsLocked(layer, shaderIt->second);
|
||||||
|
mRuntimeHost.mPersistentState.layers.push_back(layer);
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
|
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.RemoveLayer(layerId, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
|
||||||
|
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
|
||||||
|
if (it == mRuntimeHost.mPersistentState.layers.end())
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRuntimeHost.mPersistentState.layers.erase(it);
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
|
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.MoveLayer(layerId, direction, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
|
||||||
|
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
|
||||||
|
if (it == mRuntimeHost.mPersistentState.layers.end())
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::ptrdiff_t index = std::distance(mRuntimeHost.mPersistentState.layers.begin(), it);
|
||||||
|
const std::ptrdiff_t newIndex = index + direction;
|
||||||
|
if (newIndex < 0 || newIndex >= static_cast<std::ptrdiff_t>(mRuntimeHost.mPersistentState.layers.size()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::swap(mRuntimeHost.mPersistentState.layers[index], mRuntimeHost.mPersistentState.layers[newIndex]);
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.MoveLayerToIndex(layerId, targetIndex, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
|
||||||
|
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
|
||||||
|
if (it == mRuntimeHost.mPersistentState.layers.end())
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRuntimeHost.mPersistentState.layers.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (targetIndex >= mRuntimeHost.mPersistentState.layers.size())
|
||||||
|
targetIndex = mRuntimeHost.mPersistentState.layers.size() - 1;
|
||||||
|
|
||||||
|
const std::size_t sourceIndex = static_cast<std::size_t>(std::distance(mRuntimeHost.mPersistentState.layers.begin(), it));
|
||||||
|
if (sourceIndex == targetIndex)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState movedLayer = *it;
|
||||||
|
mRuntimeHost.mPersistentState.layers.erase(mRuntimeHost.mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(sourceIndex));
|
||||||
|
mRuntimeHost.mPersistentState.layers.insert(mRuntimeHost.mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(targetIndex), movedLayer);
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
|
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.SetLayerBypass(layerId, bypassed, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->bypass = bypassed;
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkParameterStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
|
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.SetLayerShader(layerId, shaderId, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shaderIt = mRuntimeHost.mPackagesById.find(shaderId);
|
||||||
|
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->shaderId = shaderId;
|
||||||
|
layer->parameterValues.clear();
|
||||||
|
mRuntimeHost.EnsureLayerDefaultsLocked(*layer, shaderIt->second);
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
|
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.UpdateLayerParameter(layerId, parameterId, newValue, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shaderIt = mRuntimeHost.mPackagesById.find(layer->shaderId);
|
||||||
|
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + layer->shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShaderPackage& shaderPackage = shaderIt->second;
|
||||||
|
auto parameterIt = std::find_if(shaderPackage.parameters.begin(), shaderPackage.parameters.end(),
|
||||||
|
[¶meterId](const ShaderParameterDefinition& definition) { return definition.id == parameterId; });
|
||||||
|
if (parameterIt == shaderPackage.parameters.end())
|
||||||
|
{
|
||||||
|
error = "Unknown parameter id: " + parameterId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameterIt->type == ShaderParameterType::Trigger)
|
||||||
|
{
|
||||||
|
ShaderParameterValue& value = layer->parameterValues[parameterId];
|
||||||
|
const double previousCount = value.numberValues.empty() ? 0.0 : value.numberValues[0];
|
||||||
|
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mRuntimeHost.mStartTime).count();
|
||||||
|
value.numberValues = { previousCount + 1.0, triggerTime };
|
||||||
|
mRuntimeHost.MarkParameterStateDirtyLocked();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderParameterValue normalized;
|
||||||
|
if (!mRuntimeHost.NormalizeAndValidateValue(*parameterIt, newValue, normalized, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
layer->parameterValues[parameterId] = normalized;
|
||||||
|
mRuntimeHost.MarkParameterStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
|
||||||
@@ -109,17 +266,86 @@ bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerK
|
|||||||
|
|
||||||
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
|
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.ResetLayerParameters(layerId, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
|
||||||
|
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
error = "Unknown layer id: " + layerId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto shaderIt = mRuntimeHost.mPackagesById.find(layer->shaderId);
|
||||||
|
if (shaderIt == mRuntimeHost.mPackagesById.end())
|
||||||
|
{
|
||||||
|
error = "Unknown shader id: " + layer->shaderId;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->parameterValues.clear();
|
||||||
|
mRuntimeHost.EnsureLayerDefaultsLocked(*layer, shaderIt->second);
|
||||||
|
mRuntimeHost.MarkParameterStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
|
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
|
||||||
{
|
{
|
||||||
return mRuntimeHost.SaveStackPreset(presetName, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
const std::string safeStem = mRuntimeHost.MakeSafePresetFileStem(presetName);
|
||||||
|
if (safeStem.empty())
|
||||||
|
{
|
||||||
|
error = "Preset name must include at least one letter or number.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonValue root = JsonValue::MakeObject();
|
||||||
|
root.set("version", JsonValue(1.0));
|
||||||
|
root.set("name", JsonValue(TrimCopy(presetName)));
|
||||||
|
root.set("layers", mRuntimeHost.SerializeLayerStackLocked());
|
||||||
|
|
||||||
|
return mRuntimeHost.WriteTextFile(mRuntimeHost.mPresetRoot / (safeStem + ".json"), SerializeJson(root, true), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::string& error)
|
bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::string& error)
|
||||||
{
|
{
|
||||||
return mRuntimeHost.LoadStackPreset(presetName, error);
|
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
|
||||||
|
const std::string safeStem = mRuntimeHost.MakeSafePresetFileStem(presetName);
|
||||||
|
if (safeStem.empty())
|
||||||
|
{
|
||||||
|
error = "Preset name must include at least one letter or number.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path presetPath = mRuntimeHost.mPresetRoot / (safeStem + ".json");
|
||||||
|
std::string presetText = mRuntimeHost.ReadTextFile(presetPath, error);
|
||||||
|
if (presetText.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JsonValue root;
|
||||||
|
if (!ParseJson(presetText, root, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const JsonValue* layersValue = root.find("layers");
|
||||||
|
if (!layersValue || !layersValue->isArray())
|
||||||
|
{
|
||||||
|
error = "Preset file is missing a valid 'layers' array.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<RuntimeHost::LayerPersistentState> nextLayers;
|
||||||
|
if (!mRuntimeHost.DeserializeLayerStackLocked(*layersValue, nextLayers, error))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (nextLayers.empty())
|
||||||
|
{
|
||||||
|
error = "Preset does not contain any valid layers.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRuntimeHost.mPersistentState.layers = nextLayers;
|
||||||
|
mRuntimeHost.mReloadRequested = true;
|
||||||
|
mRuntimeHost.MarkRenderStateDirtyLocked();
|
||||||
|
return mRuntimeHost.SavePersistentState(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::filesystem::path& RuntimeStore::GetRuntimeRepositoryRoot() const
|
const std::filesystem::path& RuntimeStore::GetRuntimeRepositoryRoot() const
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ These are still compatibility seams, not a completed subsystem extraction. Most
|
|||||||
- store-facing UI/runtime control calls in `OpenGLCompositeRuntimeControls.cpp` now route through `RuntimeStore`
|
- store-facing UI/runtime control calls in `OpenGLCompositeRuntimeControls.cpp` now route through `RuntimeStore`
|
||||||
- runtime startup for path resolution, config load, persistent state load, and shader package scan now initializes through `RuntimeStore`
|
- runtime startup for path resolution, config load, persistent state load, and shader package scan now initializes through `RuntimeStore`
|
||||||
- runtime/UI state JSON composition now lives in `RuntimeStore` instead of `RuntimeHost`
|
- runtime/UI state JSON composition now lives in `RuntimeStore` instead of `RuntimeHost`
|
||||||
|
- regular stored layer mutations and stack preset save/load now live in `RuntimeStore` instead of `RuntimeHost` public APIs
|
||||||
- mutation and reload policy now routes through `RuntimeCoordinator`
|
- mutation and reload policy now routes through `RuntimeCoordinator`
|
||||||
- render-state and shader-build reads in `OpenGLComposite.cpp`, `OpenGLShaderPrograms.cpp`, and `ShaderBuildQueue.cpp` now route through `RuntimeSnapshotProvider`
|
- render-state and shader-build reads in `OpenGLComposite.cpp`, `OpenGLShaderPrograms.cpp`, and `ShaderBuildQueue.cpp` now route through `RuntimeSnapshotProvider`
|
||||||
- render-state assembly, cached parameter refresh, and frame-context application now live in `RuntimeSnapshotProvider` instead of `RuntimeHost` public APIs
|
- render-state assembly, cached parameter refresh, and frame-context application now live in `RuntimeSnapshotProvider` instead of `RuntimeHost` public APIs
|
||||||
|
|||||||
Reference in New Issue
Block a user