#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