diff --git a/curves.json b/curves.json deleted file mode 100644 index 7aab9df..0000000 --- a/curves.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "dof:sharp-distance" : [ - { - "type" : "smooth" , - "values" : [ 35 , 100 , 35 ] , - "durations" : [ 300 , 300 ] - } - ] , - "dof:sharp-range" : [ - { - "type" : "smooth" , - "values" : [ 20 , 2 ] , - "durations" : [ 900 ] - } - ] , - "dof:falloff" : [ - { - "type" : "linear" , - "values" : [ 2 , 2 ] , - "durations" : [ 1 ] - } - ] -} diff --git a/curves.srd b/curves.srd new file mode 100644 index 0000000..981c663 --- /dev/null +++ b/curves.srd @@ -0,0 +1,20 @@ +(dof-sharp-distance + (segment smooth + (values 35 100 35) + (durations 300 300) + ) +) + +(dof-sharp-range + (segment smooth + (values 20 2) + (durations 900) + ) +) + +(dof-falloff + (segment linear + (values 2 2) + (durations 1) + ) +) diff --git a/demo.cc b/demo.cc index 1ab049d..c4290aa 100644 --- a/demo.cc +++ b/demo.cc @@ -25,11 +25,11 @@ bool T_Demo::initialise( ) Globals::Sync( ).clearInputs( ); // XXX should come from program - Globals::Sync( ).addInput( "dof:sharp-distance" , 15 ); - Globals::Sync( ).addInput( "dof:sharp-range" , 5 ); - Globals::Sync( ).addInput( "dof:falloff" , 10 ); - Globals::Sync( ).addInput( "dof:max-blur" , 16 ); - Globals::Sync( ).addInput( "dof:samples" , 16 ); + Globals::Sync( ).addInput( "dof-sharp-distance" , 15 ); + Globals::Sync( ).addInput( "dof-sharp-range" , 5 ); + Globals::Sync( ).addInput( "dof-falloff" , 10 ); + Globals::Sync( ).addInput( "dof-max-blur" , 16 ); + Globals::Sync( ).addInput( "dof-samples" , 16 ); Globals::Sync( ).updateCurveCaches( ); return true; diff --git a/dof.cc b/dof.cc index 123e5ac..f11075f 100644 --- a/dof.cc +++ b/dof.cc @@ -63,13 +63,13 @@ void T_DoFPass::render( ) << OPLoadVariable( "width" ) << OPLoadConstant( U_RES_TIME ) << OPDup( 8 ) - << OPLoadInput( "dof:samples" ) + << OPLoadInput( "dof-samples" ) << OPLoadConstant( U_SAMPLES ) << OPDup( 11 ) - << OPLoadInput( "dof:max-blur" ) - << OPLoadInput( "dof:falloff" ) - << OPLoadInput( "dof:sharp-range" ) - << OPLoadInput( "dof:sharp-distance" ) + << OPLoadInput( "dof-max-blur" ) + << OPLoadInput( "dof-falloff" ) + << OPLoadInput( "dof-sharp-range" ) + << OPLoadInput( "dof-sharp-distance" ) << OPLoadConstant( U_PARAMS ) << OPDup( 17 ) << OPLoadConstant( 1 ) diff --git a/ebcl b/ebcl index 1b1be9e..073fcb3 160000 --- a/ebcl +++ b/ebcl @@ -1 +1 @@ -Subproject commit 1b1be9e6b2149867c5de67a3dc62ed997f803334 +Subproject commit 073fcb3d5e9366de941ebce73a42cbf3c7686b4d diff --git a/sync.cc b/sync.cc index 6df752a..9f5b45f 100644 --- a/sync.cc +++ b/sync.cc @@ -2,6 +2,11 @@ #include "sync.hh" #include "globals.hh" +#include +#include +#include +using ebcl::T_SRDParserConfig; + namespace { const std::map< std::string , T_SyncSegment::E_SegmentType > SegmentTypes_( ([] { @@ -15,6 +20,135 @@ const std::map< std::string , T_SyncSegment::E_SegmentType > SegmentTypes_( ([] } +/*= SRD parser for the curves ================================================*/ + +namespace { + +using namespace ebcl; + +bool CPEnterCurve_( T_SRDParserData const& data ) +{ + *( data.targetData ) = T_SyncCurve{ (*data.input)[ 0 ].stringValue( ) }; + return true; +} + +bool CPExitCurve_( T_SRDParserData const& data ) +{ + T_SyncCurve& curve( data.currentData->value< T_SyncCurve >( ) ); + T_SyncCurves& curves( *( data.targetData->value< T_SharedPtr< T_SyncCurves > >( ) ) ); + + if ( curve.segments.empty( ) ) { + T_StringBuilder sb; + sb << "curve '" << curve.name << "' is empty"; + data.errors.add( std::move( sb ) , (*data.input)[ 0 ] ); + } + + if ( curves.curves.contains( curve.name ) ) { + T_StringBuilder sb; + sb << "duplicate curve '" << curve.name << "'"; + data.errors.add( std::move( sb ) , (*data.input)[ 0 ] ); + } else { + curves.setCurve( std::move( curve ) ); + } + + return true; +} + +void CPHandleSegment_( + const T_SyncSegment::E_SegmentType type , + T_SRDList const& lValues , + T_SRDList const& lDurations , + T_SRDErrors& errors , + T_SyncCurve& curve ) +{ + bool failed = false; + if ( lDurations.size( ) != lValues.size( ) - 1 ) { + errors.add( "values / durations count mismatch" , lValues[ 0 ] ); + failed = true; + } + + // Check durations + const auto nd( lDurations.size( ) ); + for ( auto i = 1u ; i < nd ; i ++ ) { + auto const& tok( lDurations[ i ] ); + const uint64_t v( tok.longValue( ) ); + if ( v < 1 || v > UINT32_MAX ) { + errors.add( "invalid duration" , tok ); + failed = true; + } + } + + if ( !failed ) { + T_SyncSegment& segment( curve.segments.addNew( ) ); + segment.type = type; + segment.durations.ensureCapacity( nd - 1 ); + for ( auto i = 1u ; i < nd ; i ++ ) { + auto const& tok( lDurations[ i ] ); + segment.durations.add( uint32_t( tok.longValue( ) ) ); + } + + segment.values.ensureCapacity( nd ); + for ( auto i = 1u ; i <= nd ; i ++ ) { + auto const& tok( lValues[ i ] ); + segment.values.add( tok.floatValue( ) ); + } + } +} + +bool CPSegmentVD_( T_SRDParserData const& data ) +{ + auto const& input( *data.input ); + const auto ev( data.config.enumValue( "segment-type" , input[ 1 ].stringValue( ) ) ); + assert( ev.present( ) ); + CPHandleSegment_( (T_SyncSegment::E_SegmentType) *ev.target( ) , + input[ 2 ].list( ) , input[ 3 ].list( ) , + data.errors , data.targetData->value< T_SyncCurve >( ) ); + return true; +} + +bool CPSegmentDV_( T_SRDParserData const& data ) +{ + auto const& input( *data.input ); + const auto ev( data.config.enumValue( "segment-type" , input[ 1 ].stringValue( ) ) ); + assert( ev.present( ) ); + CPHandleSegment_( (T_SyncSegment::E_SegmentType) *ev.target( ) , + input[ 3 ].list( ) , input[ 2 ].list( ) , + data.errors , data.targetData->value< T_SyncCurve >( ) ); + return true; +} + +T_SRDParserConfig MakeCurvesParser_( ) +{ + using namespace ebcl::SRD; + + T_SRDParserDefs defs( "default" ); + defs << OnStart( []( T_SRDParserData const& data ) -> bool { + *( data.currentData ) = NewShared< T_SyncCurves >( ); + return true; + } ); + + defs.enumeration( "segment-type" ) + << "linear" << "ramp" << "smooth"; + + defs.context( "default" ) + << ( Rule( ) << Text( ) << EnterContext( "segments" ) + << OnEnter( CPEnterCurve_ ) << OnExit( CPExitCurve_ ) ); + defs.context( "segments" ) + << ( Rule( ) << "segment" << Enum( "segment-type" ) + << ( List( ) << "values" << ( AtLeast( 2 ) << Numeric( ) ) ) + << ( List( ) << "durations" << ( AtLeast( 1 ) << Integer( ) ) ) + << CPSegmentVD_ ) + << ( Rule( ) << "segment" << Enum( "segment-type" ) + << ( List( ) << "durations" << ( AtLeast( 1 ) << Integer( ) ) ) + << ( List( ) << "values" << ( AtLeast( 2 ) << Numeric( ) ) ) + << CPSegmentDV_ ); + + return defs; +} + +} + + /*= T_SyncTime ===============================================================*/ void T_SyncTime::setDuration( @@ -63,10 +197,9 @@ T_SyncCurveCache::T_SyncCurveCache( 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 ); + assert( v.durations.size( ) == v.values.size( ) - 1 ); - const auto nd( v.nPoints - 1 ); + const auto nd( v.durations.size( ) ); for ( auto j = 0u ; j < nd ; j ++ ) { const auto sStart( s * time.uDuration ); if ( time.time >= sStart ) { @@ -227,6 +360,12 @@ uint32_t T_SyncValues::indexOf( /*= T_SyncManager ============================================================*/ +T_SyncManager::T_SyncManager( ) + : pConfig_( MakeCurvesParser_( ) ) +{ } + +/*----------------------------------------------------------------------------*/ + void T_SyncManager::setDuration( const float uDuration , const uint32_t iDuration ) @@ -250,15 +389,12 @@ void T_SyncManager::checkCurveFile( ) return; } - printf( "CURVE INIT\n" ); + watcher_ = NewOwned< T_WatchedFiles >( + Globals::Watcher( ) , + [this] { curvesChanged_( ); } ); + watcher_->watch( "curves.srd" ); bool missing; - if ( loadCurves_( missing ) || !missing ) { - watcher_ = NewOwned< T_WatchedFiles >( - Globals::Watcher( ) , - [this] { curvesChanged_( ); } ); - watcher_->watch( "curves.json" ); - } - printf( "INIT MISSING IS %c\n" , missing ? 'Y' : 'N' ); + loadCurves_( missing ); } void T_SyncManager::clearCurves( ) @@ -277,166 +413,48 @@ void T_SyncManager::setCurve( void T_SyncManager::curvesChanged_( ) { bool missing; - if ( !loadCurves_( missing ) && missing ) { - watcher_.clear( ); - } + loadCurves_( missing ); } bool T_SyncManager::loadCurves_( bool& missing ) { - using T_STI_ = std::istream_iterator< char >; - std::ifstream file( "curves.json" ); - picojson::value root; + printf( "Loading curves data\n" ); + missing = true; try { - missing = !file.is_open( ); - if ( missing ) { - return false; - } - - std::string errors; - picojson::parse( root , T_STI_( file ) , T_STI_( ) , &errors ); - if ( !errors.empty( ) ) { - printf( "Failed to parse 'curves.json':\n%s\n" , errors.c_str( ) ); - return false; - } - } catch ( std::ios_base::failure const& e ) { - printf( "I/O error while reading 'curves.json'\n%s\n" , e.what( ) ); + using namespace ebcl; + const T_SRDParserConfig cfg( MakeCurvesParser_( ) ); + T_File file( "curves.srd" , E_FileMode::READ_ONLY ); + file.open( ); missing = false; - return false; - } - T_SyncCurves nCurves; - if ( !loadCurvesData_( nCurves , root ) ) { + T_FileInputStream fis( file ); + T_SRDParser parser( cfg ); + T_SRDTextReader reader( parser ); + reader.read( "curves.srd" , fis ); + + curves_ = std::move( *parser.getData< T_SharedPtr< T_SyncCurves > >( ) ); + } catch ( ebcl::X_StreamError const& e ) { + printf( "... ERR %s\n" , e.what( ) ); + return false; + + } catch ( ebcl::X_SRDErrors const& e ) { + T_StringBuilder sb; + auto const ne( e.errors.size( ) ); + for ( auto i = 0u ; i < ne ; i ++ ) { + auto const& err( e.errors[ i ] ); + sb << "... ERR " << err.location( ) << ": " << err.error( ) << '\n'; + } + sb << '\0'; + printf( "%s" , sb.data( ) ); return false; } - curves_ = std::move( nCurves ); + printf( "... success\n" ); + updateCurveCaches( ); return true; } -bool T_SyncManager::loadCurvesData_( - T_SyncCurves& curves , - picojson::value const& root ) -{ - if ( !root.is< T_JSONObject >( ) ) { - printf( "Curves data: root is not a JSON object\n" ); - return false; - } - - auto const& r( root.get< T_JSONObject >( ) ); - bool ok( true ); - for ( auto const& item : r ) { - if ( curves.indexOf( item.first.c_str( ) ) != -1 ) { - printf( "Curves data: duplicate curve '%s'\n" , - item.first.c_str( ) ); - ok = false; - continue; - } - if ( !item.second.is< T_JSONArray >( ) ) { - printf( "Curves data: entry for curve '%s' is not an array\n" , - item.first.c_str( ) ); - ok = false; - continue; - } - - T_SyncCurve nsc{ item.first.c_str( ) }; - - bool segsOk( true ); - for ( auto const& v : item.second.get< T_JSONArray >( ) ) { - if ( !v.is< T_JSONObject >( ) ) { - printf( "Curves data: curve '%s': invalid segment\n" , - item.first.c_str( ) ); - segsOk = false; - continue; - } - - T_SyncSegment segment; - try { - if ( !loadSegmentData_( segment , (char*) nsc.name.toOSString( ).data( ) , - v.get< T_JSONObject >( ) ) ) { - segsOk = false; - continue; - } - } catch ( X_JsonGetFailed const& ) { - printf( "Curves data: curve '%s': could not parse segment data\n" , - item.first.c_str( ) ); - segsOk = false; - continue; - } - nsc.segments.add( std::move( segment ) ); - } - - ok = ok && segsOk; - if ( nsc.segments.size( ) == 0 && segsOk ) { - printf( "Curves data: curve '%s': no segments\n" , - item.first.c_str( ) ); - ok = false; - } - curves.setCurve( std::move( nsc ) ); - } - - return ok; -} - -bool T_SyncManager::loadSegmentData_( - T_SyncSegment& segment , - T_String const& curve , - T_JSONObject const& sd ) -{ - auto const& sType( jsonGet< std::string >( sd , "type" ) ); - - const auto p( SegmentTypes_.find( sType ) ); - if ( p == SegmentTypes_.end( ) ) { - printf( "Curves data: curve '%s': invalid segment type '%s'\n" , - curve.toOSString( ).data( ) , sType.c_str( ) ); - return false; - } - segment.type = p->second; - - auto const& vList( jsonGet< T_JSONArray >( sd , "values" ) ); - auto const& dList( jsonGet< T_JSONArray >( sd , "durations" ) ); - - if ( vList.size( ) < 2 ) { - printf( "Curves data: curve '%s': segment doesn't have enough values\n" , - curve.toOSString( ).data( ) ); - return false; - } - if ( vList.size( ) != dList.size( ) + 1 ) { - printf( "Curves data: curve '%s': segment values / durations count mismatch\n" , - curve.toOSString( ).data( ) ); - return false; - } - - for ( auto const& vv : vList ) { - if ( !vv.is< double >( ) ) { - printf( "Curves data: curve '%s': non-numeric entry in segment values\n" , - curve.toOSString( ).data( ) ); - return false; - } - segment.values.add( vv.get< double >( ) ); - } - - for ( auto const& dv : dList ) { - if ( !dv.is< double >( ) ) { - printf( "Curves data: curve '%s': non-numeric entry in segment durations\n" , - curve.toOSString( ).data( ) ); - return false; - } - - const double dvn( dv.get< double >( ) ); - if ( fmod( dvn , 1.0 ) != 0.0 || dvn <= 0 ) { - printf( "Curves data: curve '%s': invalid segment duration %f\n" , - curve.toOSString( ).data( ) , dvn ); - return false; - } - segment.durations.add( dvn ); - } - - segment.nPoints = segment.values.size( ); - return true; -} - /*----------------------------------------------------------------------------*/ void T_SyncManager::updateCurveCaches( ) diff --git a/sync.hh b/sync.hh index cf7b16d..e9b4157 100644 --- a/sync.hh +++ b/sync.hh @@ -2,6 +2,9 @@ #include "filewatcher.hh" #include "utilities.hh" +#include + + // Duration and current playing time struct T_SyncTime { @@ -33,10 +36,9 @@ struct T_SyncSegment //HERMITE }; - uint32_t nPoints; E_SegmentType type; - T_Array< float > values; // nPoints items - T_Array< uint32_t > durations; // nPoints - 1 items + T_Array< float > values; + T_Array< uint32_t > durations; // n(values) - 1 items }; // An input curve @@ -70,8 +72,6 @@ struct T_SyncCurves { } void clear( ); - - // Returns true on success, false on duplicate void setCurve( T_SyncCurve curve ); // Returns -1 on lookup failure @@ -161,6 +161,8 @@ struct T_SyncValues // work together. struct T_SyncManager { + T_SyncManager( ); + // --------------------------------------------------------------------- // Duration & time controls @@ -203,13 +205,6 @@ struct T_SyncManager private: void curvesChanged_( ); bool loadCurves_( bool& missing ); - bool loadCurvesData_( - T_SyncCurves& curves , - picojson::value const& root ); - bool loadSegmentData_( - T_SyncSegment& segment , - T_String const& curve , - T_JSONObject const& sd ); // --------------------------------------------------------------------- // Update @@ -219,6 +214,7 @@ struct T_SyncManager void updateValues( ); private: + ebcl::T_SRDParserConfig pConfig_; P_WatchedFiles watcher_; T_SyncTime time_; T_SyncValues values_;