Files
video-shader-toys/apps/LoopThroughWithOpenGLCompositing/RuntimeHost.h
2026-05-02 16:40:21 +10:00

174 lines
5.5 KiB
C++

#pragma once
#include "RuntimeJson.h"
#include <chrono>
#include <filesystem>
#include <map>
#include <mutex>
#include <string>
#include <vector>
enum class ShaderParameterType
{
Float,
Vec2,
Color,
Boolean,
Enum
};
struct ShaderParameterOption
{
std::string value;
std::string label;
};
struct ShaderParameterDefinition
{
std::string id;
std::string label;
ShaderParameterType type = ShaderParameterType::Float;
std::vector<double> defaultNumbers;
std::vector<double> minNumbers;
std::vector<double> maxNumbers;
std::vector<double> stepNumbers;
bool defaultBoolean = false;
std::string defaultEnumValue;
std::vector<ShaderParameterOption> enumOptions;
};
struct ShaderParameterValue
{
std::vector<double> numberValues;
bool booleanValue = false;
std::string enumValue;
};
struct ShaderPackage
{
std::string id;
std::string displayName;
std::string description;
std::string category;
std::string entryPoint;
std::filesystem::path directoryPath;
std::filesystem::path shaderPath;
std::filesystem::path manifestPath;
std::vector<ShaderParameterDefinition> parameters;
std::filesystem::file_time_type shaderWriteTime;
std::filesystem::file_time_type manifestWriteTime;
};
struct RuntimeRenderState
{
std::string activeShaderId;
std::vector<ShaderParameterDefinition> parameterDefinitions;
std::map<std::string, ShaderParameterValue> parameterValues;
double timeSeconds = 0.0;
double frameCount = 0.0;
double mixAmount = 1.0;
double bypass = 0.0;
unsigned inputWidth = 0;
unsigned inputHeight = 0;
unsigned outputWidth = 0;
unsigned outputHeight = 0;
};
class RuntimeHost
{
public:
RuntimeHost();
bool Initialize(std::string& error);
bool PollFileChanges(bool& registryChanged, bool& reloadRequested, std::string& error);
bool ManualReloadRequested();
void ClearReloadRequest();
bool SelectShader(const std::string& shaderId, std::string& error);
bool UpdateParameter(const std::string& shaderId, const std::string& parameterId, const JsonValue& newValue, std::string& error);
bool SetBypass(bool bypassEnabled, std::string& error);
bool SetMixAmount(double mixAmount, std::string& error);
void SetCompileStatus(bool succeeded, const std::string& message);
void SetSignalStatus(bool hasSignal, unsigned width, unsigned height, const std::string& modeName);
void AdvanceFrame();
bool BuildActiveFragmentShaderSource(std::string& fragmentShaderSource, std::string& error);
RuntimeRenderState GetRenderState(unsigned outputWidth, unsigned outputHeight) const;
std::string BuildStateJson() const;
const std::filesystem::path& GetRepoRoot() const { return mRepoRoot; }
const std::filesystem::path& GetUiRoot() const { return mUiRoot; }
const std::filesystem::path& GetRuntimeRoot() const { return mRuntimeRoot; }
unsigned short GetServerPort() const { return mServerPort; }
void SetServerPort(unsigned short port);
bool AutoReloadEnabled() const { return mAutoReloadEnabled; }
private:
struct AppConfig
{
std::string shaderLibrary = "shaders";
unsigned short serverPort = 8080;
bool autoReload = true;
};
struct PersistentState
{
std::string activeShaderId;
double mixAmount = 1.0;
bool bypass = false;
std::map<std::string, std::map<std::string, ShaderParameterValue>> parameterValuesByShader;
};
bool LoadConfig(std::string& error);
bool LoadPersistentState(std::string& error);
bool SavePersistentState(std::string& error) const;
bool ScanShaderPackages(std::string& error);
bool ParseShaderManifest(const std::filesystem::path& manifestPath, ShaderPackage& shaderPackage, std::string& error) const;
bool NormalizeAndValidateValue(const ShaderParameterDefinition& definition, const JsonValue& value, ShaderParameterValue& normalizedValue, std::string& error) const;
ShaderParameterValue DefaultValueForDefinition(const ShaderParameterDefinition& definition) const;
void EnsureParameterDefaultsLocked(ShaderPackage& shaderPackage);
std::string BuildWrapperSlangSource(const ShaderPackage& shaderPackage) const;
bool FindSlangCompiler(std::filesystem::path& compilerPath, std::string& error) const;
bool RunSlangCompiler(const std::filesystem::path& wrapperPath, const std::filesystem::path& outputPath, std::string& error) const;
bool PatchGeneratedGlsl(std::string& shaderText, std::string& error) const;
std::string ReadTextFile(const std::filesystem::path& path, std::string& error) const;
bool WriteTextFile(const std::filesystem::path& path, const std::string& contents, std::string& error) const;
bool ResolvePaths(std::string& error);
JsonValue BuildStateValue() const;
JsonValue SerializeParameterValue(const ShaderParameterDefinition& definition, const ShaderParameterValue& value) const;
private:
mutable std::mutex mMutex;
AppConfig mConfig;
PersistentState mPersistentState;
std::filesystem::path mRepoRoot;
std::filesystem::path mUiRoot;
std::filesystem::path mShaderRoot;
std::filesystem::path mRuntimeRoot;
std::filesystem::path mRuntimeStatePath;
std::filesystem::path mConfigPath;
std::filesystem::path mWrapperPath;
std::filesystem::path mGeneratedGlslPath;
std::filesystem::path mPatchedGlslPath;
std::map<std::string, ShaderPackage> mPackagesById;
std::vector<std::string> mPackageOrder;
std::string mActiveShaderId;
bool mReloadRequested;
bool mCompileSucceeded;
std::string mCompileMessage;
bool mHasSignal;
unsigned mSignalWidth;
unsigned mSignalHeight;
std::string mSignalModeName;
unsigned short mServerPort;
bool mAutoReloadEnabled;
double mMixAmount;
bool mBypass;
std::chrono::steady_clock::time_point mStartTime;
std::chrono::steady_clock::time_point mLastScanTime;
uint64_t mFrameCounter;
};