diff --git a/Makefile b/Makefile index 3a01709..75f2d9d 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ DEMO = \ profiling.cc \ shaders.cc \ odbg.cc \ + sync.cc \ \ demo.cc \ \ diff --git a/externals.hh b/externals.hh index aab13f9..9358efe 100644 --- a/externals.hh +++ b/externals.hh @@ -22,6 +22,7 @@ #include #include #include +#include // ImGui #include diff --git a/sync.cc b/sync.cc new file mode 100644 index 0000000..779dbf2 --- /dev/null +++ b/sync.cc @@ -0,0 +1,105 @@ +#include "externals.hh" +#include "sync.hh" + + +const T_SyncVariable T_SyncData::MissingVariable_{ }; + + +T_SyncData::T_SyncData( + __rd__ const uint32_t duration , + __rd__ const float units ) noexcept + : duration_( duration ) , units_( units ) +{ } + + +T_SyncData::T_VarHelper_::T_VarHelper_( + __rw__ T_SyncVariable&& v , + __rd__ const uint32_t duration ) noexcept + : variable( std::move( v ) ) +{ + const auto n( variable.size( ) ); + uint32_t s = 0; + for ( auto i = 0u ; i < n ; i ++ ) { + auto const& v( variable[ i ] ); + assert( v.nPoints >= 2 ); + assert( v.durations.size( ) == v.nPoints - 1 ); + + const auto nd( v.nPoints - 1 ); + for ( auto j = 0u ; j < nd ; j ++ ) { + segStarts.push_back( s ); + segRefs.push_back( std::make_pair( i , j ) ); + s += v.durations[ j ]; + if ( s > duration ) { + return; + } + } + } +} + + +void T_SyncData::setSyncVariable( + __rd__ std::string const& name , + __rw__ T_SyncVariable&& variable ) noexcept +{ + variables_.erase( name ); + if ( !variable.empty( ) ) { + variables_.emplace( name , T_VarHelper_{ std::move( variable ) , duration_ } ); + } +} + + +T_SyncVariable const& T_SyncData::variable( + __rd__ std::string const& name ) const noexcept +{ + auto pos( variables_.find( name ) ); + if ( pos == variables_.end( ) ) { + return MissingVariable_; + } + return pos->second.variable; +} + + +float T_SyncData::valueOf( + __rd__ std::string const& name , + __rd__ const float time ) const noexcept +{ + assert( time >= 0 ); + + auto pos( variables_.find( name ) ); + if ( pos == variables_.end( ) ) { + return 0; + } + + // Find segment + auto const& var( pos->second ); + const uint32_t tu( std::min( duration_ , + uint32_t( floor( time / units_ ) ) ) ); + uint32_t s( 0 ); + for ( auto ss : var.segStarts ) { + if ( ss > tu ) { + break; + } + s ++; + } + assert( s > 0 ); + s --; + const auto sid( var.segRefs[ s ].first ); + auto const& seg( var.variable[ sid ] ); + const auto pid( var.segRefs[ s ].second ); + + // Interpolation factor + const float st( var.segStarts[ s ] * units_ ); + const float et( ( var.segStarts[ s ] + seg.durations[ pid ] ) * units_ ); + const float v0 = ( time - st ) / ( et - st ); + float v = v0; + if ( seg.type != E_SyncSegment::LINEAR ) { + v *= v0; + if ( seg.type == E_SyncSegment::SMOOTH ) { + v *= 3 - 2 * v0; + } + } + + const float sv( seg.values[ pid ] ); + const float ev( seg.values[ pid + 1 ] ); + return v * ( ev - sv ) + sv; +} diff --git a/sync.hh b/sync.hh new file mode 100644 index 0000000..7286efc --- /dev/null +++ b/sync.hh @@ -0,0 +1,63 @@ +#pragma once +#ifndef REAL_BUILD +# include "externals.hh" +#endif + + +enum class E_SyncSegment +{ + LINEAR , + RAMP , + SMOOTH , + //HERMITE +}; + +struct T_SyncSegment +{ + uint32_t nPoints; + E_SyncSegment type; + std::vector< float > values; // nPoints items + std::vector< uint32_t > durations; // nPoints - 1 items +}; + +using T_SyncVariable = std::vector< T_SyncSegment >; + + +struct T_SyncData +{ + T_SyncData( ) = delete; + T_SyncData( + __rd__ const uint32_t duration , + __rd__ const float units ) noexcept; + + void setSyncVariable( + __rd__ std::string const& name , + __rw__ T_SyncVariable&& variable ) noexcept; + + T_SyncVariable const& variable( + __rd__ std::string const& name ) const noexcept; + + float valueOf( + __rd__ std::string const& variable , + __rd__ const float time ) const noexcept; + + private: + static const T_SyncVariable MissingVariable_; + + // Caching structure used to access segments + using T_SegRef_ = std::pair< uint32_t , uint32_t >; + struct T_VarHelper_ + { + T_SyncVariable variable; + std::vector< T_SegRef_ > segRefs; + std::vector< float > segStarts; + + T_VarHelper_( + __rw__ T_SyncVariable&& variable , + __rd__ const uint32_t duration ) noexcept; + }; + + uint32_t duration_; + float units_; + std::unordered_map< std::string , T_VarHelper_ > variables_; +};