demotool/control.cc

361 lines
8.4 KiB
C++
Raw Normal View History

2017-10-14 12:00:47 +02:00
#include "externals.hh"
#include "control.hh"
#include "sync.hh"
using namespace cops;
2017-10-14 21:10:46 +02:00
/*= Command execution ========================================================*/
void cops::Execute(
__rd__ T_Operations const& operations ,
__rw__ T_Context& context )
{
for ( auto const& op : operations ) {
op->execute( context );
}
}
2017-10-14 12:00:47 +02:00
/*= 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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
ctx.opStack.push_back( constant );
}
/*= OPLoadVariable ===========================================================*/
OPLoadVariable::OPLoadVariable(
__rd__ std::string const& variable )
: T_Op( OP_LOAD_VARIABLE ) , variable( variable )
{ }
void OPLoadVariable::execute(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
if ( ctx.opStack.empty( ) ) {
throw error( "missing operand in stack" );
}
ctx.opStack.back( ) = -ctx.opStack.back( );
}
void OPInv::execute(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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 =============================================================*/
2017-10-14 21:10:46 +02:00
// GENERAL FIXME
// program identifier should be an entry in a table
// or, you know, a program name
2017-10-14 12:00:47 +02:00
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(
2017-10-14 21:10:46 +02:00
__rw__ T_Context& ctx ) const
2017-10-14 12:00:47 +02:00
{
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 );
}
}
2017-10-14 21:10:46 +02:00
/*= 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 );
}