#pragma once #include "c-renderdefs.hh" #include struct T_SyncOverrideSection; namespace opast { /*= BASE CLASS FOR AST NODES ===================================================*/ class T_RootNode; class A_Node { public: enum E_Type { ROOT , // Root node ILIST , // Instruction list // DECL_INIT , // Initialisation block DECL_FRAME , // Frame block DECL_FN , // Function // OP_CALL , // Function call OP_CLEAR , // Clear buffer OP_COMPUTE , // Compute shader dispatch OP_COND , // Conditional instruction OP_FRAMEBUFFER ,// Define framebuffer OP_FULLSCREEN , // Draw a fullscreen quad OP_IMAGE , // Image unit binding OP_INPUT , // Input declaration OP_LOCALS , // Declare local variables OP_MAINOUT , // Select the output buffer OP_ODBG , // Output debugging OP_OVERRIDES , // Register input overrides OP_PIPELINE , // Shader pipeline declaration OP_PROFILE , // Profiling block OP_PROGRAM , // Shader program declaration OP_SAMPLER , // Define sampler OP_SET , // Set instruction OP_TEXTURE , // Define texture OP_UNIFORMS , // Set uniforms OP_VIEWPORT , // Set viewport // "Use-" instructions OP_USE_FRAMEBUFFER , OP_USE_PIPELINE , OP_USE_PROGRAM , OP_USE_TEXTURE , // Unary operators EXPR_NEG , EXPR_INV , EXPR_NOT , EXPR_SIN , EXPR_COS , EXPR_TAN , EXPR_SQRT , EXPR_EXP , EXPR_LN , // Binary operators EXPR_ADD , EXPR_SUB , EXPR_MUL , EXPR_DIV , EXPR_POW , // Binary operators - comparisons EXPR_CMP_EQ , EXPR_CMP_NE , EXPR_CMP_GT , EXPR_CMP_GE , EXPR_CMP_LT , EXPR_CMP_LE , // EXPR_ID , // Variable access EXPR_INPUT , // Input value access EXPR_CONST , // Numeric constant // Technical nodes TN_CONDITION , // Expression for a conditional instruction TN_CASE , // Valued case for a conditional instruction TN_DEFAULT , // Default case for a conditional instruction TN_FBATT , // Framebuffer attachment TN_ARG , // Call argument }; private: const E_Type type_; A_Node* parent_; ebcl::T_SRDLocation location_; protected: T_AutoArray< T_OwnPtr< A_Node > , 8 > children_; explicit A_Node( const E_Type type , A_Node* const parent ) noexcept; public: virtual ~A_Node( ) = 0; E_Type type( ) const noexcept { return type_; } ebcl::T_SRDLocation& location( ) noexcept { return location_; } ebcl::T_SRDLocation const& location( ) const noexcept { return location_; } A_Node& parent( ) const noexcept { assert( parent_ ); return *parent_; } T_RootNode& root( ) const noexcept; uint32_t size( ) const noexcept { return children_.size( ); } T_OwnPtr< A_Node > const& child( const uint32_t index ) const noexcept { return children_[ index ]; } T_OwnPtr< A_Node >& child( const uint32_t index ) noexcept { return children_[ index ]; } bool replace( A_Node const& node , T_OwnPtr< A_Node >& replacement ) noexcept; void setParent( A_Node& newParent ) noexcept { parent_ = &newParent; } }; // Browser function to be used with T_Visitor extern A_Node* ASTVisitorBrowser( A_Node& node , const uint32_t child ) noexcept; // Data types enum class E_DataType { UNKNOWN , BUILTIN , VARIABLE , FRAMEBUFFER , INPUT , PIPELINE , PROGRAM , SAMPLER , TEXTURE , }; M_LSHIFT_OP( T_StringBuilder , E_DataType ); /*= BASE STRUCTURES FOR INSTRUCTIONS =========================================*/ // Some instructions are restricted to either the initialisation code or the // frame code. enum class E_InstrRestriction { INIT , FRAME }; using T_InstrRestriction = T_Flags< E_InstrRestriction >; // Base class for instruction nodes class A_InstructionNode : public A_Node { private: const T_InstrRestriction restriction_; protected: A_InstructionNode( const E_Type type , A_Node& parent , T_InstrRestriction restriction = {} ) noexcept : A_Node( type , &parent ) , restriction_( restriction ) { assert( !restriction_.isSet({ E_InstrRestriction::INIT , E_InstrRestriction::FRAME }) ); } public: T_InstrRestriction restriction( ) const noexcept { return restriction_; } }; // Nodes that store lists of instructions class T_InstrListNode : public A_Node { public: T_InstrListNode( A_Node& parent ) noexcept : A_Node( ILIST , &parent ) { } template< typename IType , typename... ArgTypes > IType& add( ArgTypes&&... args ); A_InstructionNode& node( const uint32_t index ) const noexcept { return dynamic_cast< A_InstructionNode& >( *children_[ index ] ); } void replaceMultiple( A_InstructionNode& instruction , T_InstrListNode* replacement ) noexcept; }; template< typename IType , typename... ArgTypes > inline IType& T_InstrListNode::add( ArgTypes&&... args ) { children_.add( NewOwned< IType >( *this , std::forward< ArgTypes >( args ) ... ) ); return (IType&) *children_.last( ); } /*------------------------------------------------------------------------------*/ // Base class for expressions class A_ExpressionNode : public A_Node { protected: A_ExpressionNode( E_Type type , A_Node& parent ) noexcept : A_Node( type , &parent ) { } }; using P_ExpressionNode = T_OwnPtr< A_ExpressionNode >; // Technical node used for the arguments of various instructions class T_ArgumentNode : public A_Node { public: T_ArgumentNode( A_Node& parent , P_ExpressionNode expr ) noexcept : A_Node( TN_ARG , &parent ) { if ( expr ) { location( ) = expr->location( ); children_.add( std::move( expr ) ); } } A_ExpressionNode& expression( ) const noexcept { return (A_ExpressionNode&) *child( 0 ); } bool isIdentifier( ) const noexcept { return expression( ).type( ) == EXPR_ID; } void expression( P_ExpressionNode expr ) noexcept { assert( expr ); child( 0 ) = std::move( expr ); } }; using P_ArgumentNode = T_OwnPtr< T_ArgumentNode >; /*= FUNCTIONS AND ROOT NODES =================================================*/ // Function-like nodes class A_FuncNode : public A_Node { private: T_String name_; T_InstrListNode* instructions_{ nullptr }; protected: struct T_Local_ { T_String name; ebcl::T_SRDLocation location; bool argument; E_DataType type{ E_DataType::UNKNOWN }; T_Local_( T_String const& name , ebcl::T_SRDLocation const& location , const bool argument ) noexcept : name{ name } , location{ location } , argument{ argument } { } }; T_ObjectTable< T_String , T_Local_ > locals_{ []( T_Local_ const& l ) -> T_String { return l.name; } }; protected: // For init or frame entry points. // isInit = true => init entry point // isInit = false => frame entry point explicit A_FuncNode( bool isInit , T_RootNode* const parent ) noexcept; // For normal functions explicit A_FuncNode( T_String const& name , T_RootNode* const parent ) noexcept; public: T_String const& name( ) const noexcept { return name_; } T_InstrListNode& instructions( ) noexcept { if ( !instructions_ ) { auto p{ NewOwned< T_InstrListNode >( *this ) }; instructions_ = p.get( ); children_.add( std::move( p ) ); } return *instructions_; } // --------------------------------------------------------------------- T_Optional< ebcl::T_SRDLocation > addLocalVariable( T_String const& name , ebcl::T_SRDLocation const& location ) noexcept; uint32_t locals( ) const noexcept { return locals_.size( ); } bool hasLocal( T_String const& id ) const noexcept { return locals_.contains( id ); } bool isArgument( T_String const& id ) const noexcept { auto const* const ptr( locals_.get( id ) ); return ptr && ptr->argument; } uint32_t getLocalIndex( T_String const& name ) const noexcept { return locals_.indexOf( name ); } T_String const& getLocalName( const uint32_t index ) const noexcept { return locals_[ index ].name; } ebcl::T_SRDLocation const& getLocalLocation( const uint32_t index ) const noexcept { return locals_[ index ].location; } E_DataType getLocalType( T_String const& name ) const noexcept { return locals_.get( name )->type; } E_DataType getLocalType( const uint32_t index ) const noexcept { return locals_[ index ].type; } void setLocalType( const uint32_t index , const E_DataType type ) noexcept { locals_[ index ].type = type; } void removeLocal( T_String const& name ) noexcept { locals_.remove( name ); } }; using P_InstrListNode = T_OwnPtr< T_InstrListNode >; /*----------------------------------------------------------------------------*/ // Root node, keeps track of the whole tree and related data (function table, // assets...) class T_RootNode : public A_Node { private: T_KeyValueTable< T_String , uint32_t > functions_; public: T_RootNode( ) noexcept; // --------------------------------------------------------------------- // Return type for addFunction. We'll always return a reference to a // function node (which may or may not be the same as the initial one, // if there were duplicates), and we'll return the location of the // initial function in the case of a duplicate. struct T_AddFunctionResult { A_FuncNode& function; T_Optional< ebcl::T_SRDLocation > dupLocation; T_AddFunctionResult( A_FuncNode& function ) noexcept : function{ function } , dupLocation{} {} T_AddFunctionResult( A_FuncNode& function , ebcl::T_SRDLocation const& dupLocation ) noexcept : function{ function } , dupLocation{ dupLocation } {} }; // Attempts to add a function. If the function is already present in // the table, the result will be set up with the previous declaration's // location, and the specified function will not be modified (a duplicate // entry will be added to the table instead). T_AddFunctionResult addFunction( T_OwnPtr< A_FuncNode >& function ) noexcept; // --------------------------------------------------------------------- bool hasFunction( T_String const& name ) noexcept { return functions_.contains( name ); } bool hasInit( ) noexcept { return hasFunction( "*init*" ); } bool hasFrame( ) noexcept { return hasFunction( "*frame*" ); } uint32_t nFunctions( ) const noexcept { return functions_.size( ); } int32_t functionIndex( T_String const& name ) const noexcept { auto const* const ip{ functions_.get( name ) }; return ip ? *ip : -1; } A_FuncNode& function( const uint32_t index ) const noexcept { return dynamic_cast< A_FuncNode& >( *child( index ) ); } void removeFunction( T_String const& name ) noexcept { auto const* const ip{ functions_.get( name ) }; if ( !ip ) { return; } const auto i{ *ip }; functions_.remove( name ); children_.removeSwap( i ); if ( i < children_.size( ) ) { functions_.update( function( i ).name( ) , i ); } } }; /*----------------------------------------------------------------------------*/ // Init & frame functions class T_SpecialFuncNode : public A_FuncNode { public: T_SpecialFuncNode( bool isInit , T_RootNode& parent ) noexcept : A_FuncNode( isInit , &parent ) { } }; // Normal functions class T_FuncNode : public A_FuncNode { public: T_FuncNode( T_String const& name , T_RootNode& parent ) noexcept : A_FuncNode( name , &parent ) { } // Add an argument. If the argument is a duplicate, return the location // of the initial argument. T_Optional< ebcl::T_SRDLocation > addArgument( ebcl::T_SRDToken const& token ) noexcept; uint32_t arguments( ) const noexcept; }; /*= GENERAL / FLOW CONTROL INSTRUCTIONS ========================================*/ // Function call class T_CallInstrNode : public A_InstructionNode { private: T_String id_; ebcl::T_SRDLocation idLocation_; public: T_CallInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& idToken ) noexcept : A_InstructionNode( OP_CALL , parent ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } void addArgument( P_ExpressionNode expr ) noexcept { if ( expr ) { children_.add( NewOwned< T_ArgumentNode >( *this , std::move( expr ) ) ); } } T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } T_ArgumentNode& argument( const uint32_t index ) const noexcept { return (T_ArgumentNode&) *child( index ); } }; // Conditional instruction class T_CondInstrNode : public A_InstructionNode { public: class T_Expression : public A_Node { public: T_Expression( T_CondInstrNode& parent , P_ExpressionNode expr ) : A_Node( TN_CONDITION , &parent ) { children_.add( std::move( expr ) ); } A_ExpressionNode& expression( ) const noexcept { return (A_ExpressionNode&) *child( 0 ); } void expression( P_ExpressionNode expr ) noexcept { assert( expr ); child( 0 ) = std::move( expr ); } }; class T_ValuedCase : public A_Node { private: int64_t value_; public: T_ValuedCase( T_CondInstrNode& parent , const int64_t value , P_InstrListNode il ) : A_Node( TN_CASE , &parent ) , value_( value ) { children_.add( std::move( il ) ); } int64_t value( ) const noexcept { return value_; } T_InstrListNode& instructions( ) const noexcept { return (T_InstrListNode&) *child( 0 ); } }; class T_DefaultCase : public A_Node { public: T_DefaultCase( T_CondInstrNode& parent , P_InstrListNode il ) : A_Node( TN_DEFAULT , &parent ) { children_.add( std::move( il ) ); } T_InstrListNode& instructions( ) const noexcept { return (T_InstrListNode&) *child( 0 ); } }; private: T_Optional< uint32_t > expression_; T_KeyValueTable< int64_t , uint32_t > cases_; T_Optional< uint32_t > defaultCase_; void handleRemoval( uint32_t idx ) noexcept; public: explicit T_CondInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_COND , parent ) { } void setExpression( P_ExpressionNode expression ) noexcept; bool hasExpression( ) const noexcept { return bool( expression_ ); } T_Expression& expression( ) const noexcept { return (T_Expression&) *child( *expression_ ); } void setCase( const int64_t value , P_InstrListNode instrList ) noexcept; void rmCase( const int64_t value ) noexcept { cases_.remove( value ); } uint32_t nCases( ) const noexcept { return cases_.size( ); } T_Array< int64_t > const& cases( ) const noexcept { return cases_.keys( ); } bool hasCase( const int64_t value ) const noexcept { return cases_.contains( value ); } T_ValuedCase& getCase( const int64_t value ) const noexcept { return (T_ValuedCase&) *child( *cases_.get( value ) ); } T_ValuedCase& getCaseByIndex( const uint32_t index ) const noexcept { return (T_ValuedCase&) *child( cases_[ index ] ); } void setDefaultCase( P_InstrListNode defaultCase ) noexcept; bool hasDefaultCase( ) const noexcept { return bool( defaultCase_ ); } T_DefaultCase& defaultCase( ) const noexcept { return (T_DefaultCase&) *child( *defaultCase_ ); } }; // Local variable declarations class T_LocalsInstrNode : public A_InstructionNode { private: T_AutoArray< T_String , 8 > vars_; T_AutoArray< ebcl::T_SRDLocation , 8 > varLocs_; public: T_LocalsInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_LOCALS , parent ) { } T_Optional< ebcl::T_SRDLocation > addVariable( ebcl::T_SRDToken const& token ) noexcept; uint32_t variables( ) const noexcept { return vars_.size( ); } T_String const& varName( const uint32_t index ) const noexcept { return vars_[ index ]; } ebcl::T_SRDLocation const& varLocation( const uint32_t index ) const noexcept { return varLocs_[ index ]; } }; // Setting a global variable class T_SetInstrNode : public A_InstructionNode { private: T_String id_; ebcl::T_SRDLocation idLocation_; public: T_SetInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& idToken ) noexcept : A_InstructionNode( OP_SET , parent ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } void id( T_String const& nid ) noexcept { id_ = nid; } void setExpression( P_ExpressionNode expression ) noexcept { if ( children_.size( ) ) { child( 0 ) = std::move( expression ); } else { children_.add( std::move( expression ) ); } } bool hasExpression( ) const noexcept { return children_.size( ) && child( 0 ); } A_ExpressionNode& expression( ) const noexcept { return (A_ExpressionNode&) *child( 0 ); } }; /*= RESOURCE DEFINITION INSTRUCTIONS =========================================*/ // Base class class A_ResourceDefInstrNode : public A_InstructionNode { private: T_String id_; ebcl::T_SRDLocation idLocation_; E_DataType dataType_; protected: A_ResourceDefInstrNode( const E_Type type , T_InstrListNode& parent , ebcl::T_SRDToken const& identifier , const E_DataType dataType ) noexcept : A_InstructionNode( type , parent , E_InstrRestriction::FRAME ) , id_( identifier.stringValue( ) ) , idLocation_( identifier.location( ) ) , dataType_( dataType ) { } public: T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } E_DataType dataType( ) const noexcept { return dataType_; } }; /*------------------------------------------------------------------------------*/ // Framebuffer definition instruction class T_FramebufferInstrNode : public A_ResourceDefInstrNode { public: class T_Attachment : public A_Node { private: bool depth_; T_String id_; public: T_Attachment( T_FramebufferInstrNode& parent , const bool depth , ebcl::T_SRDToken const& texId , P_ExpressionNode lod = { } ) noexcept : A_Node( TN_FBATT , &parent ) , depth_( depth ) , id_( texId.stringValue( ) ) { location() = texId.location( ); if ( lod ) { children_.add( NewOwned< T_ArgumentNode >( *this , std::move( lod ) ) ); } } bool isDepth( ) const noexcept { return depth_; } T_String const& id( ) const noexcept { return id_; } T_ArgumentNode* lod( ) const noexcept { return (T_ArgumentNode*) ( children_.size( ) ? child( 0 ).get( ) : nullptr ); } void id( T_String const& nid , ebcl::T_SRDLocation const& loc ) noexcept { id_ = nid; location( ) = loc; } }; private: T_AutoArray< uint32_t , 16 > colorAttachments_; T_Optional< uint32_t > depthAttachment_; bool hasAttachment( T_String const& name ) const noexcept; public: T_FramebufferInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& identifier ) noexcept : A_ResourceDefInstrNode( OP_FRAMEBUFFER , parent , identifier , E_DataType::FRAMEBUFFER ) { } // --------------------------------------------------------------------- bool addColorAttachment( ebcl::T_SRDToken const& id , P_ExpressionNode lod = {} ) noexcept; uint32_t colorAttachments( ) const noexcept { return colorAttachments_.size( ); } T_Attachment& colorAttachment( const uint32_t index ) const noexcept { return (T_Attachment&) *child( colorAttachments_[ index ] ); } // --------------------------------------------------------------------- bool setDepthAttachment( ebcl::T_SRDToken const& token , P_ExpressionNode lod = {} ) noexcept; T_Attachment* depthAttachment( ) const noexcept { return depthAttachment_ ? ((T_Attachment*) child( *depthAttachment_ ).get( ) ) : nullptr; } }; // Input declaration class T_InputInstrNode : public A_ResourceDefInstrNode { private: float defValue_; ebcl::T_SRDLocation dvLocation_; public: T_InputInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& tName ) noexcept : A_ResourceDefInstrNode( OP_INPUT , parent , tName , E_DataType::INPUT ) {} T_InputInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& tName , ebcl::T_SRDToken const& tDefault ) noexcept : A_ResourceDefInstrNode( OP_INPUT , parent , tName , E_DataType::INPUT ) , defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) ) {} float defValue( ) const noexcept { return defValue_; } ebcl::T_SRDLocation const& defValueLocation( ) const noexcept { return dvLocation_; } }; // Pipeline declaration instruction class T_PipelineInstrNode : public A_ResourceDefInstrNode { private: T_StaticArray< T_String , 6 > pids_; T_StaticArray< ebcl::T_SRDLocation , 6 > pidLocations_; public: T_PipelineInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& idToken ) noexcept : A_ResourceDefInstrNode( OP_PIPELINE , parent , idToken , E_DataType::PIPELINE ) { } // Add a program identifier. The token is assumed to be a valid word, // and the list of programs is assumed not to be full. If the identifer // is already in the pipeline's list, the location of the first // occurrence will be returned. T_Optional< ebcl::T_SRDLocation > addProgram( ebcl::T_SRDToken const& pidToken ) noexcept; uint32_t size( ) const noexcept { return pids_.size( ); } T_String const& program( const uint32_t index ) const noexcept { return pids_[ index ]; } ebcl::T_SRDLocation const& pLocation( const uint32_t index ) const noexcept { return pidLocations_[ index ]; } void program( const uint32_t index , T_String const& id , ebcl::T_SRDLocation const& location ) noexcept { pids_[ index ] = id; pidLocations_[ index ] = location; } }; // Program loader instruction class T_ProgramInstrNode : public A_ResourceDefInstrNode { private: T_FSPath path_; ebcl::T_SRDLocation pathLocation_; public: T_ProgramInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& idToken , ebcl::T_FSPath path , ebcl::T_SRDLocation const& pathLoc ) noexcept : A_ResourceDefInstrNode( OP_PROGRAM , parent , idToken , E_DataType::PROGRAM ) , path_( std::move( path ) ) , pathLocation_( pathLoc ) { } T_FSPath const& path( ) const noexcept { return path_; } ebcl::T_SRDLocation const& pathLocation( ) const noexcept { return pathLocation_; } }; // Sampler definition class T_SamplerInstrNode : public A_ResourceDefInstrNode { private: struct T_Sampling_ { ebcl::T_SRDLocation location; E_TexSampling mode; }; struct T_Mipmaps_ { ebcl::T_SRDLocation location; T_Optional< E_TexSampling > mode; }; struct T_Wrapping_ { ebcl::T_SRDLocation location; E_TexWrap mode; }; struct T_LOD_ { ebcl::T_SRDLocation location; T_Optional< uint32_t > min; T_Optional< uint32_t > max; }; T_Optional< T_Sampling_ > sampling_; T_Optional< T_Mipmaps_ > mipmaps_; T_Optional< T_Wrapping_ > wrapping_; T_Optional< T_LOD_ > lod_; public: T_SamplerInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& id ) noexcept : A_ResourceDefInstrNode( OP_SAMPLER , parent , id , E_DataType::SAMPLER ) { } // Attempt to set sampling mode, mipmap mode, wrapping mode or // LOD minimal/maximal, returning the location of the previous // definition if there was one. T_Optional< ebcl::T_SRDLocation > setSampling( E_TexSampling mode , ebcl::T_SRDLocation const& location ) noexcept; T_Optional< ebcl::T_SRDLocation > setMipmapSampling( E_TexSampling mode , ebcl::T_SRDLocation const& location ) noexcept; T_Optional< ebcl::T_SRDLocation > setNoMipmap( ebcl::T_SRDLocation const& location ) noexcept; T_Optional< ebcl::T_SRDLocation > setWrapping( E_TexWrap mode , ebcl::T_SRDLocation const& location ) noexcept; T_Optional< ebcl::T_SRDLocation > setLOD( ebcl::T_SRDLocation const& location , P_ExpressionNode min , P_ExpressionNode max ) noexcept; // Get either the defined values or the defaults E_TexSampling sampling( ) const noexcept { return sampling_ ? sampling_->mode : E_TexSampling::NEAREST; } T_Optional< E_TexSampling > mipmap( ) const noexcept { return mipmaps_ ? mipmaps_->mode : T_Optional< E_TexSampling >{}; } E_TexWrap wrapping( ) const noexcept { return wrapping_ ? wrapping_->mode : E_TexWrap::REPEAT; } T_ArgumentNode* minLod( ) const noexcept { return ( T_ArgumentNode*) ( ( lod_ && lod_->min ) ? child( *( lod_->min ) ).get( ) : nullptr ); } T_ArgumentNode* maxLod( ) const noexcept { return ( T_ArgumentNode*) ( ( lod_ && lod_->max ) ? child( *( lod_->max ) ).get( ) : nullptr ); } }; // Texture definition class T_TextureInstrNode : public A_ResourceDefInstrNode { private: E_TexType type_; public: T_TextureInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& id , E_TexType type ) noexcept : A_ResourceDefInstrNode( OP_TEXTURE , parent , id , E_DataType::TEXTURE ) , type_( type ) { children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); } E_TexType texType( ) const noexcept { return type_; } void setWidth( P_ExpressionNode width ) noexcept { if ( width ) { child( 0 ) = NewOwned< T_ArgumentNode >( *this , std::move( width ) ); } } void setHeight( P_ExpressionNode height ) noexcept { if ( height ) { child( 1 ) = NewOwned< T_ArgumentNode >( *this , std::move( height ) ); } } void setLODs( P_ExpressionNode lods ) noexcept { if ( lods ) { child( 2 ) = NewOwned< T_ArgumentNode >( *this , std::move( lods ) ); } } bool hasWidth( ) const noexcept { return bool( child( 0 ) ); } T_ArgumentNode& width( ) const noexcept { return (T_ArgumentNode&) *child( 0 ); } bool hasHeight( ) const noexcept { return bool( child( 1 ) ); } T_ArgumentNode& height( ) const noexcept { return (T_ArgumentNode&) *child( 1 ); } T_ArgumentNode* lods( ) const noexcept { return (T_ArgumentNode*) child( 2 ).get( ); } }; /*= TOOL CONTROL INSTRUCTIONS ==================================================*/ // Output debugging class T_OutputDebugInstrNode : public A_InstructionNode { private: T_String idTexture_; ebcl::T_SRDLocation locTexture_; E_ODbgMode mode_; ebcl::T_SRDLocation locMode_; T_String description_; ebcl::T_SRDLocation locDescription_; public: T_OutputDebugInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& texture , const E_ODbgMode mode , ebcl::T_SRDLocation const& modeLocation , ebcl::T_SRDToken const& description ) noexcept; T_String const& texture( ) const noexcept { return idTexture_; } ebcl::T_SRDLocation const& textureLocation( ) const noexcept { return locTexture_; } E_ODbgMode mode( ) const noexcept { return mode_; } ebcl::T_SRDLocation const& modeLocation( ) const noexcept { return locMode_; } T_String const& description( ) const noexcept { return description_; } ebcl::T_SRDLocation const& descriptionLocation( ) const noexcept { return locDescription_; } }; // User interface overrides for inputs class T_OverridesInstrNode : public A_InstructionNode { private: T_OwnPtr< T_SyncOverrideSection > overrides_; public: T_OverridesInstrNode( T_InstrListNode& parent , T_OwnPtr< T_SyncOverrideSection > overrides ) noexcept : A_InstructionNode( OP_OVERRIDES , parent , E_InstrRestriction::FRAME ) , overrides_( std::move( overrides ) ) { } T_SyncOverrideSection& root( ) const noexcept { return *overrides_; } T_OwnPtr< T_SyncOverrideSection > extractRoot( ) noexcept { return std::move( overrides_ ); } }; // Profiling instruction class T_ProfileInstrNode : public A_InstructionNode { private: T_String text_; public: T_ProfileInstrNode( T_InstrListNode& parent , T_String const& text ) noexcept : A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) , text_( text ) { children_.add( NewOwned< T_InstrListNode >( *this ) ); } T_String const& text( ) const { return text_; } T_InstrListNode& instructions( ) const noexcept { return (T_InstrListNode&) *child( 0 ); } }; /*= RENDERING INSTRUCTIONS =====================================================*/ // Clear instruction class T_ClearInstrNode : public A_InstructionNode { public: T_ClearInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_CLEAR , parent , E_InstrRestriction::INIT ) { } void addComponent( P_ExpressionNode expr ) noexcept { if ( expr ) { children_.add( NewOwned< T_ArgumentNode >( *this , std::move( expr ) ) ); } } T_ArgumentNode& component( const uint32_t index ) const noexcept { return (T_ArgumentNode&) *child( index ); } }; // Fullscreen quad instruction class T_FullscreenInstrNode : public A_InstructionNode { public: T_FullscreenInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_FULLSCREEN , parent , E_InstrRestriction::INIT ) { } }; // Dispatch a compute job class T_ComputeInstrNode : public A_InstructionNode { public: T_ComputeInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_COMPUTE , parent ) { } void addComponent( P_ExpressionNode expr ) noexcept { if ( expr ) { children_.add( NewOwned< T_ArgumentNode >( *this , std::move( expr ) ) ); } } T_ArgumentNode& component( const uint32_t index ) const noexcept { return (T_ArgumentNode&) *child( index ); } }; /*= RENDERING STATE INSTRUCTIONS ===============================================*/ // Main output selection class T_MainOutputInstrNode : public A_InstructionNode { public: T_MainOutputInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_MAINOUT , parent , E_InstrRestriction::INIT ) { } }; // Uniform setting instruction class T_UniformsInstrNode : public A_InstructionNode { private: bool integers_; T_String progId_; ebcl::T_SRDLocation progIdLocation_; uint32_t uloc_; ebcl::T_SRDLocation ulocLocation_; public: T_UniformsInstrNode( T_InstrListNode& parent , const bool integers , ebcl::T_SRDToken const& prog , ebcl::T_SRDToken const& loc ) noexcept : A_InstructionNode{ OP_UNIFORMS , parent } , integers_{ integers } , progId_{ prog.stringValue( ) } , progIdLocation_{ prog.location( ) } , uloc_{ (uint32_t)loc.longValue( ) } , ulocLocation_{ loc.location( ) } { } bool integers( ) const noexcept { return integers_; } T_String const& progId( ) const noexcept { return progId_; } ebcl::T_SRDLocation const& progIdLocation( ) const noexcept { return progIdLocation_; } void progId( T_String const& id , ebcl::T_SRDLocation const& location ) noexcept { progId_ = id; progIdLocation_ = location; } uint32_t uloc( ) const noexcept { return uloc_; } ebcl::T_SRDLocation const& ulocLocation( ) const noexcept { return ulocLocation_; } void addValue( P_ExpressionNode value ) noexcept { if ( value ) { children_.add( NewOwned< T_ArgumentNode >( *this , std::move( value ) ) ); } } T_ArgumentNode& value( const uint32_t index ) const noexcept { return (T_ArgumentNode&) *child( index ); } }; // Use-* instructions (framebuffers, programs, pipelines) // Also serves as the base for use-texture class T_UseInstrNode : public A_InstructionNode { public: enum E_Type { FRAMEBUFFER , PIPELINE , PROGRAM , TEXTURE }; private: T_String id_; ebcl::T_SRDLocation idLocation_; public: T_UseInstrNode( T_InstrListNode& parent , const E_Type type , ebcl::T_SRDToken const& identifier ) noexcept : A_InstructionNode( ([type]() { switch ( type ) { case FRAMEBUFFER: return OP_USE_FRAMEBUFFER; case PIPELINE: return OP_USE_PIPELINE; case PROGRAM: return OP_USE_PROGRAM; case TEXTURE: return OP_USE_TEXTURE; } std::abort( ); } )( ) , parent ) , id_( identifier.stringValue( ) ) , idLocation_( identifier.location( ) ) { } T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } void id( T_String const& nid , ebcl::T_SRDLocation const& location ) noexcept { id_ = nid; idLocation_ = location; } }; // Texture/sampler use instructions class T_UseTextureInstrNode : public T_UseInstrNode { private: uint32_t bank_; ebcl::T_SRDLocation bankLocation_; T_String samplerId_; ebcl::T_SRDLocation samplerIdLocation_; public: T_UseTextureInstrNode( T_InstrListNode& parent , ebcl::T_SRDToken const& bank , ebcl::T_SRDToken const& identifier , ebcl::T_SRDToken const& sampler ) noexcept : T_UseInstrNode( parent , TEXTURE , identifier ) , bank_( bank.longValue( ) ) , bankLocation_( bank.location( ) ) , samplerId_( sampler.stringValue( ) ) , samplerIdLocation_( sampler.location( ) ) { } uint32_t bank( ) const noexcept { return bank_; } ebcl::T_SRDLocation const& bankLocation( ) const noexcept { return bankLocation_; } T_String const& samplerId( ) const noexcept { return samplerId_; } ebcl::T_SRDLocation const& samplerIdLocation( ) const noexcept { return samplerIdLocation_; } void samplerId( T_String const& id , ebcl::T_SRDLocation const& location ) noexcept { samplerId_ = id; samplerIdLocation_ = location; } }; // Viewport instruction class T_ViewportInstrNode : public A_InstructionNode { public: enum E_Parameter { PX , PY , PWIDTH , PHEIGHT }; public: T_ViewportInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_VIEWPORT , parent , E_InstrRestriction::INIT ) { children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); } void setParameter( const E_Parameter p , P_ExpressionNode value ) noexcept { if ( value ) { children_[ int( p ) ] = NewOwned< T_ArgumentNode >( *this , std::move( value ) ); } } bool hasParameter( const E_Parameter p ) const noexcept { return bool( children_[ int( p ) ] ); } T_ArgumentNode& parameter( const E_Parameter p ) const noexcept { return (T_ArgumentNode&) *children_[ int( p ) ]; } }; // Image unit binding class T_ImageInstrNode : public A_InstructionNode { public: enum class E_AccessMode { READ , WRITE }; using T_AccessMode = T_Flags< E_AccessMode >; enum E_Parameter { P_UNIT , P_LEVEL , P_LAYER }; private: T_AccessMode accessMode_ = { }; T_String id_; ebcl::T_SRDLocation idLocation_; public: T_ImageInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_IMAGE , parent ) { children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); children_.add( P_ArgumentNode{} ); } //---------------------------------------------------------------------- T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } void id( T_String const& nid , ebcl::T_SRDLocation const& location ) noexcept { id_ = nid; idLocation_ = location; } //---------------------------------------------------------------------- T_AccessMode accessMode( ) const noexcept { return accessMode_; } void accessMode( T_AccessMode mode ) noexcept { assert( mode ); accessMode_ = mode; } //---------------------------------------------------------------------- void setParameter( const E_Parameter p , P_ExpressionNode value ) noexcept { if ( value ) { children_[ int( p ) ] = NewOwned< T_ArgumentNode >( *this , std::move( value ) ); } } bool hasParameter( const E_Parameter p ) const noexcept { return bool( children_[ int( p ) ] ); } T_ArgumentNode& parameter( const E_Parameter p ) const noexcept { return (T_ArgumentNode&) *children_[ int( p ) ]; } }; /*= EXPRESSIONS ==============================================================*/ // A constant value class T_ConstantExprNode : public A_ExpressionNode { private: bool wasFloat_; double vFloat_; int64_t vInt_; public: T_ConstantExprNode( A_Node& parent , ebcl::T_SRDToken const& token ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( token.type( ) == ebcl::E_SRDTokenType::FLOAT ) , vFloat_( token.floatValue( ) ) , vInt_( token.longValue( ) ) { location( ) = token.location( ); } T_ConstantExprNode( A_Node& parent , int64_t value ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) , vFloat_( value ) , vInt_( value ) { } T_ConstantExprNode( A_Node& parent , double value ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( true ) , vFloat_( value ) , vInt_( (int64_t) value ) { } bool wasFloat( ) const noexcept { return wasFloat_; } double floatValue( ) const noexcept { return vFloat_; } int64_t intValue( ) const noexcept { return vInt_; } }; // An identifier used in an expression class T_IdentifierExprNode : public A_ExpressionNode { private: T_String id_; public: T_IdentifierExprNode( A_Node& parent , ebcl::T_SRDToken const& token ) noexcept : T_IdentifierExprNode( parent , token.stringValue( ) ) { location( ) = token.location( ); } T_IdentifierExprNode( A_Node& parent , T_String const& id ) noexcept : A_ExpressionNode( EXPR_ID , parent ) , id_( id ) { } T_String const& id( ) const noexcept { return id_; } }; // Access to an input value class T_InputExprNode : public A_ExpressionNode { private: T_String id_; ebcl::T_SRDLocation idLocation_; public: T_InputExprNode( A_Node& parent , ebcl::T_SRDToken const& token ) noexcept : A_ExpressionNode( EXPR_INPUT , parent ) , id_( token.stringValue( ) ) , idLocation_( token.location( ) ) { } T_String const& id( ) const noexcept { return id_; } ebcl::T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } }; // A unary operator class T_UnaryOperatorNode : public A_ExpressionNode { public: enum E_Operator { NEG , INV , NOT , SIN , COS , TAN , SQRT , EXP , LN }; private: E_Operator op_; public: T_UnaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setArgument( P_ExpressionNode argument ) noexcept { child( 0 ) = std::move( argument ); } bool hasArgument( ) const noexcept { return bool( child( 0 ) ); } A_ExpressionNode& argument( ) const noexcept { return (A_ExpressionNode&) *child( 0 ); } }; // A binary operator class T_BinaryOperatorNode : public A_ExpressionNode { public: enum E_Operator { ADD , SUB , MUL , DIV , POW , CMP_EQ , CMP_NE , CMP_GT , CMP_GE , CMP_LT , CMP_LE , }; private: E_Operator op_; public: T_BinaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setLeft( P_ExpressionNode left ) noexcept { child( 0 ) = std::move( left ); } void setRight( P_ExpressionNode right ) noexcept { child( 1 ) = std::move( right ); } bool hasLeft( ) const noexcept { return bool( child( 0 ) ); } bool hasRight( ) const noexcept { return bool( child( 1 ) ); } A_ExpressionNode& left( ) const noexcept { return (A_ExpressionNode&) *child( 0 ); } A_ExpressionNode& right( ) const noexcept { return (A_ExpressionNode&) *child( 1 ); } }; } // namespace opast