#pragma once #include "filewatcher.hh" #include "utilities.hh" /*= INPUT FILES ==============================================================*/ // Type of input chunk enum class E_ShaderInputChunk { CODE , INCLUDE , UNIFORMS }; // Input chunk data struct T_ShaderInputChunk { E_ShaderInputChunk type; T_String text; uint32_t lines; T_ShaderInputChunk( ) = default; T_ShaderInputChunk( const E_ShaderInputChunk type , T_String text , const uint32_t lines ) : type( type ) , text( std::move( text ) ) , lines( lines ) { } }; // Input file type enum class E_ShaderInput { CHUNK , // Chunk that may be repeated LIBRARY , // Library (will only be loaded once) // "Main" shader source files VERTEX , FRAGMENT , GEOMETRY , COMPUTE }; // Preprocessing errors struct T_ShaderInputError { uint32_t line; T_String error; T_ShaderInputError( const uint32_t line , T_String error ) : line( line ) , error( std::move( error ) ) { } }; // Uniform types enum class E_UniformType { F1 , F2 , F3 , F4 , I1 , I2 , I3 , I4 , SAMPLER2D }; // Uniform declarations struct T_ShaderUniform { T_String name; bool global; E_UniformType type; }; // Source file struct T_ShaderInput { E_ShaderInput type = E_ShaderInput::CHUNK; T_Array< T_ShaderInputChunk > chunks; T_Array< T_ShaderInputError > errors; T_ObjectTable< T_String , T_ShaderUniform > uniforms{ []( T_ShaderUniform const& su ) -> T_String { return su.name; } }; bool load( T_String const& path ); }; using P_ShaderInput = T_OwnPtr< T_ShaderInput >; // Type of shader enum class E_ShaderType { VERTEX , FRAGMENT , GEOMETRY , COMPUTE , __COUNT__ }; // Errors in shader code - the errors it represents may come from either // the input loader, the shader loader or the driver. struct T_ShaderError { T_String source; uint32_t line; T_String error; T_ShaderError( ) = default; T_ShaderError( T_String source , const uint32_t line , T_String error ) : source( std::move( source ) ) , line( line ) , error( std::move( error ) ) { } T_ShaderError( T_String source , const uint32_t line , T_StringBuilder& error ) : source( std::move( source ) ) , line( line ) , error( std::move( error ) ) { } }; 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_String 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_String , 8 > sources; // Chunk source files T_StringBuilder code; T_Array< T_ShaderError > errors; T_KeyValueTable< T_String , bool > files; }; T_ShaderManager( ) noexcept; T_ShaderProgram program( T_String const& name ); T_ShaderPipeline pipeline( std::initializer_list< T_String > shaders ); void update( ); void makeUI( ); bool& uiEnabled( ) { return uiEnabled_; } private: struct T_Pipeline_ { T_String idString; uint32_t references = 0; GLuint id = 0; T_Array< T_String > programs{ 8 }; T_Pipeline_( T_String const& id , std::initializer_list< T_String > shaders ) : idString{ id } , programs{ shaders } {} }; struct T_Program_ { T_String 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_String , T_Pipeline_ > pipelines_; T_Array< T_Program_ > programs_; T_KeyValueTable< T_String , uint32_t > programIndex_; T_KeyValueTable< T_String , P_ShaderInput > inputs_; T_KeyValueTable< T_String , T_Array< T_String > > missing_; T_Array< T_String > updates_; // Load/use existing program for use with pipelines void loadProgram( T_String const& pipeline , T_String const& name ); bool useExistingProgram( T_String const& pipeline , T_String const& name ); // Load/use existing program for standalone use void loadProgram( T_String const& name ); bool useExistingProgram( T_String const& name ); // Program management T_Program_& initProgramRecord( // Init management data T_String const& record ); uint32_t newProgramRecord( ); // Allocate entry in index T_ShaderInput const* getInput( T_String 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 parseGLSLError( T_ShaderCode& code , char const* errorLine ); void programUpdated( T_String const& name ); void resetProgram( T_Program_& program ); };