#pragma once #include "RuntimeJson.h" #include #include #include #include #include #include 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 defaultNumbers; std::vector minNumbers; std::vector maxNumbers; std::vector stepNumbers; bool defaultBoolean = false; std::string defaultEnumValue; std::vector enumOptions; }; struct ShaderParameterValue { std::vector 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 parameters; std::filesystem::file_time_type shaderWriteTime; std::filesystem::file_time_type manifestWriteTime; }; struct RuntimeRenderState { std::string activeShaderId; std::vector parameterDefinitions; std::map 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 ResetParameters(const std::string& shaderId, 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 SetPerformanceStats(double frameBudgetMilliseconds, double renderMilliseconds); 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> 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 mPackagesById; std::vector mPackageOrder; std::string mActiveShaderId; bool mReloadRequested; bool mCompileSucceeded; std::string mCompileMessage; bool mHasSignal; unsigned mSignalWidth; unsigned mSignalHeight; std::string mSignalModeName; double mFrameBudgetMilliseconds; double mRenderMilliseconds; double mSmoothedRenderMilliseconds; 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; };