472 lines
11 KiB
C++
472 lines
11 KiB
C++
#include "externals.hh"
|
|
#include "sync.hh"
|
|
|
|
|
|
/*= T_SyncTime ===============================================================*/
|
|
|
|
void T_SyncTime::setDuration(
|
|
__rd__ const float uDuration ,
|
|
__rd__ const uint32_t iDuration )
|
|
{
|
|
this->uDuration = std::max( 1e-3f , uDuration );
|
|
this->iDuration = std::max( 1u , iDuration );
|
|
time = std::min( time , duration( ) );
|
|
}
|
|
|
|
/*= T_SyncCurves =============================================================*/
|
|
|
|
void T_SyncCurves::clear( )
|
|
{
|
|
curves.clear( );
|
|
positions.clear( );
|
|
}
|
|
|
|
bool T_SyncCurves::addCurve( __rd__ T_SyncCurve curve )
|
|
{
|
|
const auto p( positions.find( curve.name ) );
|
|
if ( p == positions.end( ) ) {
|
|
positions.emplace( curve.name , curves.size( ) );
|
|
curves.emplace_back( std::move( curve ) );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int32_t T_SyncCurves::indexOf( __rd__ std::string const& name )
|
|
{
|
|
const auto p( positions.find( name ) );
|
|
return p == positions.end( ) ? -1 : p->second;
|
|
}
|
|
|
|
|
|
/*= T_SyncCurveCache =========================================================*/
|
|
|
|
T_SyncCurveCache::T_SyncCurveCache(
|
|
__rd__ T_SyncTime const& time ,
|
|
__rd__ T_SyncCurves const& curves ,
|
|
__rd__ const uint32_t curve ) noexcept
|
|
: curve( curve ) , curPos( 0 )
|
|
{
|
|
auto const& c( curves.curves[ curve ] );
|
|
const auto ns( c.segments.size( ) );
|
|
assert( ns > 0 );
|
|
|
|
uint32_t s = 0;
|
|
for ( auto i = 0u ; i < ns ; i ++ ) {
|
|
auto const& v( c.segments[ 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 ++ ) {
|
|
const auto sStart( s * time.uDuration );
|
|
if ( time.time >= sStart ) {
|
|
curPos = segStarts.size( );
|
|
}
|
|
segStarts.push_back( sStart );
|
|
segRefs.push_back( std::make_pair( i , j ) );
|
|
s += v.durations[ j ];
|
|
segEnds.push_back( std::min( s , time.iDuration ) * time.uDuration );
|
|
if ( s > time.iDuration ) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
uint32_t T_SyncCurveCache::findSegment(
|
|
__rd__ const float time ) const noexcept
|
|
{
|
|
const auto ns( segStarts.size( ) );
|
|
for ( auto i = 0u ; i < ns ; i ++ ) {
|
|
if ( segStarts[ i ] <= time && segEnds[ i ] > time ) {
|
|
return i;
|
|
}
|
|
}
|
|
return ns;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
float T_SyncCurveCache::valueAt(
|
|
__rd__ T_SyncTime const& time ,
|
|
__rd__ T_SyncCurves const& curves ,
|
|
__rd__ const float position ) const noexcept
|
|
{
|
|
return segmentValue( time.time , findSegment( position ) ,
|
|
curves.curves[ curve ].segments );
|
|
}
|
|
|
|
float T_SyncCurveCache::value(
|
|
__rd__ T_SyncTime const& time ,
|
|
__rd__ T_SyncCurves const& curves ) noexcept
|
|
{
|
|
const auto t( time.time );
|
|
|
|
// Check / update curPos
|
|
const float ss0( curPos == segStarts.size( )
|
|
? time.duration( )
|
|
: segStarts[ curPos ] );
|
|
if ( ss0 > t ) {
|
|
curPos = findSegment( t );
|
|
} else {
|
|
while ( curPos < segStarts.size( ) && t >= segEnds[ curPos ] ) {
|
|
curPos ++;
|
|
}
|
|
}
|
|
|
|
// We got the actual index in curPos, now compute the value.
|
|
return segmentValue( t , curPos , curves.curves[ curve ].segments );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
float T_SyncCurveCache::segmentValue(
|
|
__rd__ float time ,
|
|
__rd__ uint32_t segIndex ,
|
|
__rd__ std::vector< T_SyncSegment > const& segments ) const noexcept
|
|
{
|
|
const auto sss( segStarts.size( ) );
|
|
if ( segIndex >= sss ) {
|
|
assert( sss != 0 );
|
|
segIndex = sss - 1;
|
|
time = segEnds[ segIndex ];
|
|
}
|
|
|
|
auto const& idxp( segRefs[ segIndex ] );
|
|
auto const& seg( segments[ idxp.second ] );
|
|
|
|
// Interpolation factor
|
|
const float st( segStarts[ segIndex ] );
|
|
const float et( segEnds[ segIndex ] );
|
|
const float v0 = ( time - st ) / ( et - st );
|
|
float v = v0;
|
|
if ( seg.type != T_SyncSegment::LINEAR ) {
|
|
v *= v0;
|
|
if ( seg.type == T_SyncSegment::SMOOTH ) {
|
|
v *= 3 - 2 * v0;
|
|
}
|
|
}
|
|
|
|
const auto pid( idxp.second );
|
|
const float sv( seg.values[ pid ] );
|
|
const float ev( seg.values[ pid + 1 ] );
|
|
return v * ( ev - sv ) + sv;
|
|
}
|
|
|
|
|
|
/*= T_SyncValues =============================================================*/
|
|
|
|
T_SyncValues::T_SyncValues( )
|
|
{
|
|
values.push_back( 0 );
|
|
}
|
|
|
|
// ---------------------------------------------------------------------
|
|
|
|
void T_SyncValues::clear( )
|
|
{
|
|
identifiers.clear( );
|
|
values.clear( );
|
|
overriden.clear( );
|
|
positions.clear( );
|
|
values.push_back( 0 );
|
|
}
|
|
|
|
bool T_SyncValues::addValue(
|
|
__rd__ std::string const& name ,
|
|
__rd__ const float initial )
|
|
{
|
|
const auto np( positions.find( name ) );
|
|
if ( np != positions.end( ) ) {
|
|
return false;
|
|
}
|
|
const auto li( values.size( ) - 1 );
|
|
positions.emplace( name , li );
|
|
identifiers.push_back( name );
|
|
values.push_back( initial );
|
|
std::swap( values[ li ] , values[ li + 1 ] );
|
|
overriden.push_back( false );
|
|
return true;
|
|
}
|
|
|
|
uint32_t T_SyncValues::indexOf(
|
|
__rd__ std::string const& name ) const
|
|
{
|
|
const auto np( positions.find( name ) );
|
|
if ( np == positions.end( ) ) {
|
|
return values.size( ) - 1;
|
|
} else {
|
|
return np->second;
|
|
}
|
|
}
|
|
|
|
|
|
/*= T_SyncManager ============================================================*/
|
|
|
|
void T_SyncManager::setDuration(
|
|
__rd__ const float uDuration ,
|
|
__rd__ const uint32_t iDuration )
|
|
{
|
|
time_.setDuration( uDuration , iDuration );
|
|
updateCurveCaches( );
|
|
}
|
|
|
|
void T_SyncManager::setTime(
|
|
__rd__ const float time )
|
|
{
|
|
time_.setTime( time );
|
|
updateValues( );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
void T_SyncManager::updateCurveCaches( )
|
|
{
|
|
curveCaches_.clear( );
|
|
const uint32_t nv( values_.identifiers.size( ) );
|
|
for ( auto i = 0u ; i < nv ; i ++ ) {
|
|
auto const& id( values_.identifiers[ i ] );
|
|
const auto cp( curves_.indexOf( id ) );
|
|
if ( cp < 0 ) {
|
|
curveCaches_.emplace_back( );
|
|
} else {
|
|
curveCaches_.emplace_back( new T_SyncCurveCache(
|
|
time_ , curves_ , cp
|
|
) );
|
|
}
|
|
}
|
|
updateValues( );
|
|
}
|
|
|
|
void T_SyncManager::updateValues( )
|
|
{
|
|
const auto nv( values_.identifiers.size( ) );
|
|
assert( nv == curveCaches_.size( ) );
|
|
for ( auto i = 0u ; i < nv ; i ++ ) {
|
|
auto const& cc( curveCaches_[ i ] );
|
|
if ( !cc || values_.overriden[ i ] ) {
|
|
continue;
|
|
}
|
|
values_.values[ i ] = cc->value( time_ , curves_ );
|
|
}
|
|
}
|
|
|
|
/*============================================================================*/
|
|
|
|
#if 0
|
|
void T_SyncManager::makeUI( )
|
|
{
|
|
auto const& dspSize( ImGui::GetIO( ).DisplaySize );
|
|
|
|
if ( wOverrides ) {
|
|
ImGui::SetNextWindowSize( ImVec2( 300 , dspSize.y - 300 ) ,
|
|
ImGuiSetCond_Once );
|
|
ImGui::SetNextWindowPos( ImVec2( 0 , 150 ) ,
|
|
ImGuiSetCond_Once );
|
|
ImGui::Begin( "Input overrides" );
|
|
displayOvSections( uiRoot , true );
|
|
ImGui::End( );
|
|
}
|
|
if ( wCurves ) {
|
|
ImGui::SetNextWindowSize( ImVec2( dspSize.x , 150 ) ,
|
|
ImGuiSetCond_Once );
|
|
ImGui::SetNextWindowPos( ImVec2( 0 , dspSize.y - 150 ) ,
|
|
ImGuiSetCond_Once );
|
|
ImGui::Begin( "Curve editor" );
|
|
// XXX contents
|
|
ImGui::End( );
|
|
}
|
|
}
|
|
|
|
void T_SyncManager::displayOvSections(
|
|
__rw__ T_SyncUISections& sections ,
|
|
__rd__ const bool topLevel )
|
|
{
|
|
for ( auto& s : sections ) {
|
|
const bool display( topLevel
|
|
? ImGui::CollapsingHeader( s->title.c_str( ) )
|
|
: ImGui::TreeNode( s->title.c_str( ) ) );
|
|
if ( !display ) {
|
|
continue;
|
|
}
|
|
displayOvSections( s->subsections );
|
|
if ( s->subsections.size( ) && s->overrides.size( ) ) {
|
|
ImGui::Separator( );
|
|
}
|
|
displayOvControls( s->overrides );
|
|
if ( !topLevel ) {
|
|
ImGui::TreePop( );
|
|
}
|
|
}
|
|
}
|
|
|
|
void T_SyncManager::displayOvControls(
|
|
__rw__ T_SyncUIOverrides& overrides )
|
|
{
|
|
for ( auto& o : overrides ) {
|
|
// XXX enable override checkbox should be selected and disabled
|
|
// if there is no curve
|
|
const bool changed( ImGui::Checkbox( "" , &o->enabled ) );
|
|
if ( changed ) {
|
|
// XXX mark the inputs as coming from the UI / the curves
|
|
}
|
|
ImGui::SameLine( );
|
|
|
|
switch ( o->type ) {
|
|
case T_SyncUIOverride::FLOAT:
|
|
case T_SyncUIOverride::VEC2:
|
|
case T_SyncUIOverride::VEC3:
|
|
case T_SyncUIOverride::VEC4:
|
|
case T_SyncUIOverride::INT:
|
|
case T_SyncUIOverride::COLOR:
|
|
case T_SyncUIOverride::COLOR_GRADING:
|
|
case T_SyncUIOverride::CAMERA:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*============================================================================*/
|
|
|
|
const T_SyncVariable T_SyncData::MissingVariable_{ };
|
|
|
|
T_SyncData::T_SyncData( )
|
|
: T_SyncData( 60 * 60 , 1. / 60 )
|
|
{ }
|
|
|
|
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 ,
|
|
__rd__ const uint32_t position ) noexcept
|
|
: variable( std::move( v ) ) , position( position )
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
float T_SyncData::T_VarHelper_::valueAt(
|
|
__rd__ const float position ,
|
|
__rd__ const float units ) const noexcept
|
|
{
|
|
// Find segment
|
|
const auto tu( uint32_t( floor( position / units ) ) );
|
|
uint32_t s( 0 );
|
|
for ( auto ss : segStarts ) {
|
|
if ( ss > tu ) {
|
|
break;
|
|
}
|
|
s ++;
|
|
}
|
|
assert( s > 0 );
|
|
s --;
|
|
const auto sid( segRefs[ s ].first );
|
|
auto const& seg( variable[ sid ] );
|
|
const auto pid( segRefs[ s ].second );
|
|
|
|
// Interpolation factor
|
|
const float st( segStarts[ s ] * units );
|
|
const float et( ( segStarts[ s ] + seg.durations[ pid ] ) * units );
|
|
const float v0 = ( position - st ) / ( et - st );
|
|
float v = v0;
|
|
if ( seg.type != T_SyncSegment::LINEAR ) {
|
|
v *= v0;
|
|
if ( seg.type == T_SyncSegment::SMOOTH ) {
|
|
v *= 3 - 2 * v0;
|
|
}
|
|
}
|
|
|
|
const float sv( seg.values[ pid ] );
|
|
const float ev( seg.values[ pid + 1 ] );
|
|
return v * ( ev - sv ) + sv;
|
|
}
|
|
|
|
|
|
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_ ,
|
|
uint32_t( variables_.size( ) )
|
|
} );
|
|
}
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
uint32_t T_SyncData::offsetOf(
|
|
__rd__ std::string const& name ) const noexcept
|
|
{
|
|
auto pos( variables_.find( name ) );
|
|
if ( pos == variables_.end( ) ) {
|
|
return 0xffffffff;
|
|
}
|
|
return pos->second.position;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
return pos->second.valueAt( std::min( duration_ * units_ , time ) , units_ );
|
|
}
|
|
|
|
|
|
void T_SyncData::computeValues(
|
|
__rd__ const float time ,
|
|
__wr__ std::vector< float >& values ) const noexcept
|
|
{
|
|
assert( time >= 0 );
|
|
values.resize( variables_.size( ) );
|
|
auto vit( values.begin( ) );
|
|
const float t( std::min( duration_ * units_ , time ) );
|
|
for ( auto const& var : variables_ ) {
|
|
*vit = var.second.valueAt( t , units_ );
|
|
vit ++;
|
|
}
|
|
}
|