Curves use SRD file

This commit is contained in:
Emmanuel BENOîT 2017-11-05 21:06:38 +01:00
parent 2ce821c4c0
commit 13d7a544ef
7 changed files with 214 additions and 203 deletions

View file

@ -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 ]
}
]
}

20
curves.srd Normal file
View file

@ -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)
)
)

10
demo.cc
View file

@ -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;

10
dof.cc
View file

@ -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 )

2
ebcl

@ -1 +1 @@
Subproject commit 1b1be9e6b2149867c5de67a3dc62ed997f803334
Subproject commit 073fcb3d5e9366de941ebce73a42cbf3c7686b4d

332
sync.cc
View file

@ -2,6 +2,11 @@
#include "sync.hh"
#include "globals.hh"
#include <ebcl/Files.hh>
#include <ebcl/SRDText.hh>
#include <ebcl/SRDParser.hh>
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( )

20
sync.hh
View file

@ -2,6 +2,9 @@
#include "filewatcher.hh"
#include "utilities.hh"
#include <ebcl/SRDParserConfig.hh>
// 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_;