#ifndef OPENMW_MWRENDER_POSTPROCESSOR_H #define OPENMW_MWRENDER_POSTPROCESSOR_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pingpongcanvas.hpp" #include "transparentpass.hpp" #include namespace osgViewer { class Viewer; } namespace Stereo { class MultiviewFramebuffer; } namespace VFS { class Manager; } namespace Shader { class ShaderManager; } namespace MWRender { class RenderingManager; class PingPongCull; class PingPongCanvas; class TransparentDepthBinCallback; class PostProcessor : public osg::Group { public: using FBOArray = std::array, 5>; using TextureArray = std::array, 5>; using TechniqueList = std::vector>; enum TextureIndex { Tex_Scene, Tex_Scene_LDR, Tex_Depth, Tex_OpaqueDepth, Tex_Normal }; enum FBOIndex { FBO_Primary, FBO_Multisample, FBO_FirstPerson, FBO_OpaqueDepth, FBO_Intercept }; enum TextureUnits { Unit_LastShader = 0, Unit_LastPass, Unit_Depth, Unit_EyeAdaptation, Unit_Normals, Unit_NextFree }; enum Status { Status_Error, Status_Toggled, Status_Unchanged }; PostProcessor(RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode, const VFS::Manager* vfs); ~PostProcessor(); void traverse(osg::NodeVisitor& nv) override; osg::ref_ptr getFbo(FBOIndex index, unsigned int frameId) { return mFbos[frameId][index]; } osg::ref_ptr getTexture(TextureIndex index, unsigned int frameId) { return mTextures[frameId][index]; } osg::ref_ptr getPrimaryFbo(unsigned int frameId) { return mFbos[frameId][FBO_Multisample] ? mFbos[frameId][FBO_Multisample] : mFbos[frameId][FBO_Primary]; } osg::ref_ptr getStateUpdater() { return mStateUpdater; } const TechniqueList& getTechniques() { return mTechniques; } const TechniqueList& getTemplates() const { return mTemplates; } osg::ref_ptr getCanvas() { return mPingPongCanvas; } const auto& getTechniqueMap() const { return mTechniqueFileMap; } void resize(); Status enableTechnique(std::shared_ptr technique, std::optional location = std::nullopt); Status disableTechnique(std::shared_ptr technique, bool dirty = true); bool getSupportsNormalsRT() const { return mNormalsSupported; } template void setUniform(std::shared_ptr technique, const std::string& name, const T& value) { if (!isEnabled()) return; auto it = technique->findUniform(name); if (it == technique->getUniformMap().end()) return; if ((*it)->mStatic) { Log(Debug::Warning) << "Attempting to set a configration variable [" << name << "] as a uniform"; return; } (*it)->setValue(value); } std::optional getUniformSize(std::shared_ptr technique, const std::string& name) { auto it = technique->findUniform(name); if (it == technique->getUniformMap().end()) return std::nullopt; return (*it)->getNumElements(); } bool isTechniqueEnabled(const std::shared_ptr& technique) const; void setExteriorFlag(bool exterior) { mExteriorFlag = exterior; } void setUnderwaterFlag(bool underwater) { mUnderwater = underwater; } void toggleMode(); std::shared_ptr loadTechnique(const std::string& name, bool loadNextFrame=false); bool isEnabled() const { return mUsePostProcessing && mEnabled; } bool softParticlesEnabled() const {return mSoftParticles; } bool getHDR() const { return mHDR; } void disable(); void enable(bool usePostProcessing = true); void setRenderTargetSize(int width, int height) { mWidth = width; mHeight = height; } void disableDynamicShaders(); int renderWidth() const; int renderHeight() const; void triggerShaderReload(); bool mEnableLiveReload; void loadChain(); void saveChain(); private: void populateTechniqueFiles(); size_t frame() const { return mViewer->getFrameStamp()->getFrameNumber(); } void createObjectsForFrame(size_t frameId); void createTexturesAndCamera(size_t frameId); void reloadMainPass(fx::Technique& technique); void dirtyTechniques(); void update(size_t frameId); void reloadIfRequired(); void updateLiveReload(); void cull(size_t frameId, osgUtil::CullVisitor* cv); osg::ref_ptr mRootNode; osg::ref_ptr mHUDCamera; std::array mTextures; std::array mFbos; TechniqueList mTechniques; TechniqueList mTemplates; TechniqueList mQueuedTemplates; std::unordered_map mTechniqueFileMap; int mSamples; bool mDirty; size_t mDirtyFrameId; RenderingManager& mRendering; osgViewer::Viewer* mViewer; const VFS::Manager* mVFS; bool mTriggerShaderReload; bool mReload; bool mEnabled; bool mUsePostProcessing; bool mSoftParticles; bool mDisableDepthPasses; size_t mLastFrameNumber; float mLastSimulationTime; bool mExteriorFlag; bool mUnderwater; bool mHDR; bool mNormals; bool mPrevNormals; bool mNormalsSupported; bool mPassLights; bool mPrevPassLights; bool mUBO; int mGLSLVersion; osg::ref_ptr mStateUpdater; osg::ref_ptr mPingPongCull; osg::ref_ptr mPingPongCanvas; osg::ref_ptr mTransparentDepthPostPass; int mWidth; int mHeight; fx::DispatchArray mTemplateData; }; } #endif