#include "externals.hh" #include "control.hh" #include "sync.hh" using namespace cops; /*= Command execution ========================================================*/ void cops::Execute( __rd__ T_Operations const& operations , __rw__ T_Context& context ) { for ( auto const& op : operations ) { op->execute( context ); } } /*= X_OpFailure ==============================================================*/ X_OpFailure::X_OpFailure( __rd__ std::string const& source , __rd__ uint32_t line , __rd__ std::string const& error ) noexcept : std::exception( ) , source_( source ) , line_( line ) , error_( error ) { std::ostringstream oss; oss << "Program error (" << source << ", l. " << line << "): " << error; fullMessage_ = oss.str( ); } char const* X_OpFailure::what( ) const noexcept { return fullMessage_.c_str( ); } /*= T_Op =====================================================================*/ T_Op::T_Op( __rd__ const E_Op op ) : op_( op ) { } T_Op::~T_Op( ) { } X_OpFailure T_Op::error( __rd__ std::string const& message ) const noexcept { return X_OpFailure( source , line , message ); } /*= OPLoadConstant ===========================================================*/ OPLoadConstant::OPLoadConstant( __rd__ const float constant ) : T_Op( OP_LOAD_CONSTANT ) , constant( constant ) { } void OPLoadConstant::execute( __rw__ T_Context& ctx ) const { ctx.opStack.push_back( constant ); } /*= OPLoadVariable ===========================================================*/ OPLoadVariable::OPLoadVariable( __rd__ std::string const& variable ) : T_Op( OP_LOAD_VARIABLE ) , variable( variable ) { } void OPLoadVariable::execute( __rw__ T_Context& ctx ) const { const auto vPos( ctx.varPos.find( variable ) ); if ( vPos == ctx.varPos.end( ) ) { throw error( "variable '" + variable + "' not found" ); } ctx.opStack.push_back( ctx.varValues[ vPos->second ] ); } /*= OPLoadInput ==============================================================*/ OPLoadInput::OPLoadInput( __rd__ std::string const& input ) : T_Op( OP_LOAD_VARIABLE ) , input( input ) { } void OPLoadInput::execute( __rw__ T_Context& ctx ) const { ctx.opStack.push_back( ctx.sync->valueOf( input , *( ctx.time ) ) ); } /*= OPStoreVariable ==========================================================*/ OPStoreVariable::OPStoreVariable( __rd__ std::string const& variable ) : T_Op( OP_LOAD_VARIABLE ) , variable( variable ) { } void OPStoreVariable::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.empty( ) ) { throw error( "stack is empty" ); } const auto vPos( ctx.varPos.find( variable ) ); uint32_t pos; if ( vPos == ctx.varPos.end( ) ) { pos = ctx.varValues.size( ); ctx.varPos.emplace( variable , pos ); } else { pos = vPos->second; } ctx.varValues[ pos ] = ctx.opStack.back( ); ctx.opStack.pop_back( ); } /*= Arithmetic operators =====================================================*/ void OPAdd::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) < 2 ) { throw error( "missing operands in stack" ); } const float v( ctx.opStack.back( ) ); ctx.opStack.pop_back( ); ctx.opStack.back( ) += v; } void OPMul::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) < 2 ) { throw error( "missing operands in stack" ); } const float v( ctx.opStack.back( ) ); ctx.opStack.pop_back( ); ctx.opStack.back( ) *= v; } void OPNeg::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.empty( ) ) { throw error( "missing operand in stack" ); } ctx.opStack.back( ) = -ctx.opStack.back( ); } void OPInv::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.empty( ) || ctx.opStack.back( ) == 0 ) { throw error( "missing operand in stack" ); } ctx.opStack.back( ) = 1.0f / ctx.opStack.back( ); } /*= Stack operations =========================================================*/ OPDup::OPDup( __rd__ const uint32_t stackIndex ) : T_Op( OP_DUP ) , stackIndex( stackIndex ) { } void OPDup::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) <= stackIndex ) { std::string err( "stack does not have " ); err += stackIndex + 1; err += " items"; throw error( err ); } ctx.opStack.push_back( *( ctx.opStack.end( ) - stackIndex - 1 ) ); } /*----------------------------------------------------------------------------*/ OPXchg::OPXchg( __rd__ const uint32_t stackIndex ) : T_Op( OP_XCHG ) , stackIndex( stackIndex ) { } void OPXchg::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) <= stackIndex ) { std::string err( "stack does not have " ); err += stackIndex + 1; err += " items"; throw error( err ); } if ( stackIndex ) { std::swap( *( ctx.opStack.end( ) - 1 ) , *( ctx.opStack.end( ) - stackIndex - 1 ) ); } } /*= OPSetUniform =============================================================*/ // GENERAL FIXME // program identifier should be an entry in a table // or, you know, a program name OPSetUniform::OPSetUniform( __rd__ const uint32_t program , __rd__ const uint32_t uniform , __rd__ const uint32_t count , __rd__ const bool integer ) : T_Op( OP_SET_UNIFORM ) , program( program ) , uniform( uniform ) , count( count ) , integer( integer ) { } void OPSetUniform::execute( __rw__ T_Context& ctx ) const { if ( count == 0 || ctx.opStack.size( ) < count ) { std::string err( "stack does not have " ); err += count; err += " items"; throw error( err ); } void* funcs[] = { &glProgramUniform1fv , &glProgramUniform2fv , &glProgramUniform3fv , &glProgramUniform4fv , &glProgramUniform1iv , &glProgramUniform2iv , &glProgramUniform3iv , &glProgramUniform4iv , }; void (*func)( int , int , int , void* ) = (void (*)( int , int , int , void* )) funcs[ count + ( integer ? 4 : 0 ) ]; if ( integer ) { int values[ count ]; auto i = count; while ( i != 0 ) { values[ count - i ] = int( ctx.opStack.back( ) ); ctx.opStack.pop_back( ); i --; } func( program , uniform , 1 , values ); } else { float values[ count ]; auto i = count; while ( i != 0 ) { values[ count - i ] = ctx.opStack.back( ); ctx.opStack.pop_back( ); i --; } func( program , uniform , 1 , values ); } } /*= OPUsePipeline ============================================================*/ // GENERAL FIXME // pipeline identifier should be an entry in a table // or, you know, a program name OPUsePipeline::OPUsePipeline( __rd__ const uint32_t index ) : T_Op( OP_USE_PIPELINE ) , pipeline( index ) { } void OPUsePipeline::execute( __rw__ T_Context& ) const { glBindProgramPipeline( pipeline ); } /*= OPUseTexture =============================================================*/ // GENERAL FIXME // texture & sampler identifiers should be entries in a table OPUseTexture::OPUseTexture( __rd__ const uint32_t binding , __rd__ const uint32_t texture , __rd__ const uint32_t sampler ) : T_Op( OP_USE_TEXTURE ) , binding( binding ) , texture( texture ) , sampler( sampler ) { } void OPUseTexture::execute( __rw__ T_Context& ) const { glBindTextureUnit( binding , texture ); glBindSampler( binding , sampler ); } /*= OPUseFramebuffer =========================================================*/ // GENERAL FIXME // framebuffer identifier should be an entry in a table OPUseFramebuffer::OPUseFramebuffer( __rd__ const uint32_t framebuffer ) : T_Op( OP_USE_FRAMEBUFFER ) , framebuffer( framebuffer ) { } void OPUseFramebuffer::execute( __rw__ T_Context& ) const { glBindFramebuffer( GL_FRAMEBUFFER , framebuffer ); } /*= OPSetViewport ============================================================*/ void OPSetViewport::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) < 4 ) { throw error( "stack does not have 4 items" ); } glViewport( *( ctx.opStack.end( ) - 1 ) , *( ctx.opStack.end( ) - 2 ) , *( ctx.opStack.end( ) - 3 ) , *( ctx.opStack.end( ) - 4 ) ); ctx.opStack.resize( ctx.opStack.size( ) - 4 ); } /*= Draw commands ============================================================*/ void OPClear::execute( __rw__ T_Context& ctx ) const { if ( ctx.opStack.size( ) < 4 ) { throw error( "stack does not have 4 items" ); } glClearColor( *( ctx.opStack.end( ) - 1 ) , *( ctx.opStack.end( ) - 2 ) , *( ctx.opStack.end( ) - 3 ) , *( ctx.opStack.end( ) - 4 ) ); ctx.opStack.resize( ctx.opStack.size( ) - 4 ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); } void OPFullscreen::execute( __rw__ T_Context& ) const { glBindVertexArray( 0 ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); }