#pragma once #include "c-shaders.hh" #include "c-filewatcher.hh" struct T_ShaderManager; struct T_ShaderProgram { friend struct T_ShaderManager; T_ShaderProgram( ); COPY( T_ShaderProgram ); MOVE( T_ShaderProgram ); ~T_ShaderProgram( ); bool valid( ) const noexcept; void enable( ) const; GLuint id( ) const; T_Optional< E_ShaderType > type( ) const; T_FSPath name( ) const; private: explicit T_ShaderProgram( uint32_t id ) noexcept; uint32_t id_; }; struct T_ShaderPipeline { friend struct T_ShaderManager; T_ShaderPipeline( ); COPY( T_ShaderPipeline ); MOVE( T_ShaderPipeline ); ~T_ShaderPipeline( ); bool valid( ) const noexcept; void enable( ) const; GLuint id( ) const; GLuint program( const E_ShaderType program ) const; private: explicit T_ShaderPipeline( T_String id ) noexcept; T_String id_; }; struct T_ShaderManager { friend struct T_ShaderPipeline; friend struct T_ShaderProgram; struct T_ShaderCode { E_ShaderType type; T_AutoArray< uint32_t , 8 > starts; // Position of chunk in source file T_AutoArray< uint32_t , 8 > counts; // Chunk lengths T_AutoArray< T_FSPath , 8 > sources; // Chunk source files T_StringBuilder code; T_Array< T_ShaderError > errors; T_KeyValueTable< T_FSPath , bool > files; }; T_ShaderManager( ) noexcept; // Build / get a program based on its name T_ShaderProgram program( T_FSPath const& name ); // Build a program from its source code T_ShaderProgram program( T_String const& name , E_ShaderType type , char const* source ); T_ShaderPipeline pipeline( std::initializer_list< T_String > shaders ); T_ShaderPipeline pipeline( T_String const* shaderNames , uint32_t count ); void update( ); void makeUI( ); bool& uiEnabled( ) { return uiEnabled_; } T_ShaderPipeline currentPipeline( ) const noexcept { return T_ShaderPipeline{ cPipeline_ }; } private: struct T_Pipeline_ { T_String idString; uint32_t references = 0; GLuint id = 0; T_Array< T_String > programs{ 6 }; T_Pipeline_( T_String const& id , std::initializer_list< T_String > shaders ) : idString{ id } , programs{ shaders } {} T_Pipeline_( T_String const& id , T_String const* const shaderNames , const uint32_t count ) noexcept : idString{ id } { for ( auto i = 0u ; i < count ; i ++ ) { programs.add( shaderNames[ i ] ); } } }; struct T_Program_ { T_FSPath name; T_Array< T_String > plReferences; uint32_t saReferences{ 0 }; T_ShaderCode code; GLuint id; T_Optional< T_WatchedFiles > watch; }; bool uiEnabled_ = false; T_ObjectTable< T_FSPath , T_Pipeline_ > pipelines_; T_Array< T_Program_ > programs_; T_KeyValueTable< T_FSPath , uint32_t > programIndex_; T_KeyValueTable< T_FSPath , P_ShaderInput > inputs_; T_KeyValueTable< T_FSPath , T_Array< T_FSPath > > missing_; T_Array< T_FSPath > updates_; T_String cPipeline_{ }; // Load/use existing program for use with pipelines void loadProgram( T_String const& pipeline , T_FSPath const& name ); bool useExistingProgram( T_String const& pipeline , T_FSPath const& name ); // Load/use existing program for standalone use void loadProgram( T_FSPath const& name ); void loadBuiltinProgram( T_String const& name , E_ShaderType type , char const* source ); bool useExistingProgram( T_FSPath const& name ); // Program management T_Program_& initProgramRecord( // Init management data T_FSPath const& record , E_ShaderType type = E_ShaderType::__COUNT__ , char const* source = nullptr ); uint32_t newProgramRecord( ); // Allocate entry in index T_ShaderInput const* getInput( T_FSPath const& name ); void dereferencePipeline( T_String const& id ); void dereferenceProgram( const uint32_t index , T_String const& pipeline ); void dereferenceProgram( const uint32_t index ); void initPipeline( T_Pipeline_& pipeline ) const; void initProgram( T_Program_& program ); void initBuiltinProgram( T_Program_& program , E_ShaderType type , char const* source ); void buildProgram( T_Program_& program ); void parseGLSLError( T_ShaderCode& code , char const* errorLine ); void programUpdated( T_FSPath const& name ); void resetProgram( T_Program_& program ); };