Sync - load curves from JSON file

This commit is contained in:
Emmanuel BENOîT 2017-10-31 14:21:42 +01:00
parent 699e409e64
commit ffe0fd8337
8 changed files with 297 additions and 69 deletions

23
curves.json Normal file
View file

@ -0,0 +1,23 @@
{
"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 ]
}
]
}

30
demo.cc
View file

@ -24,40 +24,12 @@ bool T_Demo::initialise( )
combine->output( ) );
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 );
// XXX test curve
{
T_SyncCurve curve;
curve.name = "dof:sharp-distance";
{
T_SyncSegment seg;
seg.nPoints = 4;
seg.type = T_SyncSegment::SMOOTH;
seg.durations.push_back( 300 );
seg.durations.push_back( 300 );
seg.durations.push_back( 300 );
seg.values.push_back( 15 );
seg.values.push_back( 30 );
seg.values.push_back( 15 );
seg.values.push_back( 15 );
curve.segments.emplace_back( std::move( seg ) );
}
{
T_SyncSegment seg;
seg.nPoints = 2;
seg.type = T_SyncSegment::LINEAR;
seg.durations.push_back( 600 );
seg.values.push_back( 100 );
seg.values.push_back( 20 );
curve.segments.emplace_back( std::move( seg ) );
}
Globals::Sync( ).setCurve( std::move( curve ) );
}
Globals::Sync( ).updateCurveCaches( );
return true;

View file

@ -52,4 +52,4 @@ struct T_WatchedFiles
bool triggered;
std::vector< int > identifiers;
};
using P_WatchedFiles = std::unique_ptr< T_WatchedFiles >;

View file

@ -71,6 +71,7 @@ void T_Main::mainLoop( )
Globals::Watcher( ).check( );
Globals::Shaders( ).update( );
Globals::Sync( ).checkCurveFile( );
glFinish( );
p.startFrame( );

198
sync.cc
View file

@ -1,5 +1,18 @@
#include "externals.hh"
#include "sync.hh"
#include "globals.hh"
namespace {
const std::map< std::string , T_SyncSegment::E_SegmentType > SegmentTypes_( ([] {
std::map< std::string , T_SyncSegment::E_SegmentType > t;
t.emplace( "linear" , T_SyncSegment::LINEAR );
t.emplace( "ramp" , T_SyncSegment::RAMP );
t.emplace( "smooth" , T_SyncSegment::SMOOTH );
return t;
})());
}
/*= T_SyncTime ===============================================================*/
@ -228,6 +241,23 @@ void T_SyncManager::setTime(
/*----------------------------------------------------------------------------*/
void T_SyncManager::checkCurveFile( )
{
if ( watcher_ ) {
return;
}
printf( "CURVE INIT\n" );
bool missing;
if ( loadCurves_( missing ) || !missing ) {
watcher_ = std::make_unique< T_WatchedFiles >(
Globals::Watcher( ) ,
[this] { curvesChanged_( ); } );
watcher_->watch( "curves.json" );
}
printf( "INIT MISSING IS %c\n" , missing ? 'Y' : 'N' );
}
void T_SyncManager::clearCurves( )
{
curves_.clear( );
@ -241,6 +271,174 @@ void T_SyncManager::setCurve(
updateCurveCaches( );
}
void T_SyncManager::curvesChanged_( )
{
bool missing;
if ( !loadCurves_( missing ) && missing ) {
watcher_.reset( );
} else {
// XXX temp bullshit to work around the deletion problem
watcher_->clear( );
watcher_->watch( "curves.json" );
}
}
bool T_SyncManager::loadCurves_(
__wr__ bool& missing )
{
using T_STI_ = std::istream_iterator< char >;
std::ifstream file( "curves.json" );
picojson::value root;
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( ) );
missing = false;
return false;
}
T_SyncCurves nCurves;
if ( !loadCurvesData_( nCurves , root ) ) {
return false;
}
curves_ = std::move( nCurves );
updateCurveCaches( );
return true;
}
bool T_SyncManager::loadCurvesData_(
__wr__ T_SyncCurves& curves ,
__rd__ 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 ) != -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;
nsc.name = item.first;
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 , nsc.name ,
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.emplace_back( std::move( segment ) );
}
ok = ok && segsOk;
if ( nsc.segments.empty( ) && 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_(
__wr__ T_SyncSegment& segment ,
__rd__ std::string const& curve ,
__rd__ 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.c_str( ) , 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.c_str( ) );
return false;
}
if ( vList.size( ) != dList.size( ) + 1 ) {
printf( "Curves data: curve '%s': segment values / durations count mismatch\n" ,
curve.c_str( ) );
return false;
}
for ( auto const& vv : vList ) {
if ( !vv.is< double >( ) ) {
printf( "Curves data: curve '%s': non-numeric entry in segment values\n" ,
curve.c_str( ) );
return false;
}
segment.values.push_back( float( 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.c_str( ) );
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.c_str( ) , dvn );
return false;
}
segment.durations.push_back( uint32_t( dvn ) );
}
segment.nPoints = segment.values.size( );
return true;
}
/*----------------------------------------------------------------------------*/
void T_SyncManager::updateCurveCaches( )

23
sync.hh
View file

@ -1,8 +1,6 @@
#pragma once
#ifndef REAL_BUILD
# include "externals.hh"
#endif
#include "filewatcher.hh"
#include "utilities.hh"
// Duration and current playing time
struct T_SyncTime
@ -174,15 +172,30 @@ struct T_SyncManager
// ---------------------------------------------------------------------
// Curves
void checkCurveFile( );
void clearCurves( );
void setCurve( __rd__ T_SyncCurve curve );
// ---------------------------------------------------------------------
private:
void curvesChanged_( );
bool loadCurves_( __wr__ bool& missing );
bool loadCurvesData_(
__wr__ T_SyncCurves& curves ,
__rd__ picojson::value const& root );
bool loadSegmentData_(
__wr__ T_SyncSegment& segment ,
__rd__ std::string const& curve ,
__rd__ T_JSONObject const& sd );
// ---------------------------------------------------------------------
// Update
public:
void updateCurveCaches( );
void updateValues( );
private:
P_WatchedFiles watcher_;
T_SyncTime time_;
T_SyncValues values_;
T_SyncCurves curves_;

View file

@ -44,25 +44,25 @@ void anglesToMatrix(
/*= JSON =====================================================================*/
template void jsonAdd< double >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ double const& v );
template void jsonAdd< picojson::value::object >(
__rw__ picojson::value::object& object ,
template void jsonAdd< T_JSONObject >(
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value::object const& v );
template void jsonAdd< picojson::value::array >(
__rw__ picojson::value::object& object ,
__rd__ T_JSONObject const& v );
template void jsonAdd< T_JSONArray >(
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value::array const& v );
__rd__ T_JSONArray const& v );
template void jsonAdd< std::string >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ std::string const& v );
template< >
void jsonAdd< picojson::value >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value const& v )
{
@ -72,7 +72,7 @@ void jsonAdd< picojson::value >(
template< >
void jsonAdd< int >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ int const& v )
{
@ -82,7 +82,7 @@ void jsonAdd< int >(
template< >
void jsonAdd< unsigned >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ unsigned const& v )
{
@ -107,7 +107,7 @@ picojson::value jsonVector( float const* vector , const int nComponents )
void jsonGetVectorOpt(
__wr__ float* vector ,
__rd__ const size_t size ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* key )
{
using namespace picojson;

View file

@ -62,6 +62,9 @@ inline auto find(
/*= JSON utilities ===========================================================*/
using T_JSONObject = picojson::value::object;
using T_JSONArray = picojson::value::array;
// Convert a vector to a JSON array
picojson::value jsonVector(
__rd__ float const* vector ,
@ -77,7 +80,7 @@ inline picojson::value jsonVector(
// Add an entry to a JSON object
template< typename T >
inline void jsonAdd(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ T const& v )
{
@ -86,35 +89,35 @@ inline void jsonAdd(
}
extern template void jsonAdd< double >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ double const& v );
extern template void jsonAdd< picojson::value::object >(
__rw__ picojson::value::object& object ,
extern template void jsonAdd< T_JSONObject >(
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value::object const& v );
extern template void jsonAdd< picojson::value::array >(
__rw__ picojson::value::object& object ,
__rd__ T_JSONObject const& v );
extern template void jsonAdd< T_JSONArray >(
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value::array const& v );
__rd__ T_JSONArray const& v );
extern template void jsonAdd< std::string >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ std::string const& v );
template< >
void jsonAdd< picojson::value >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ picojson::value const& v );
template< >
void jsonAdd< int >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ int const& v );
template< >
void jsonAdd< unsigned >(
__rw__ picojson::value::object& object ,
__rw__ T_JSONObject& object ,
__rd__ std::string const& key ,
__rd__ unsigned const& v );
@ -123,11 +126,30 @@ void jsonAdd< unsigned >(
// JSON read type error
class X_JsonGetFailed : public std::exception { };
// Get a JSON object field; throws X_JsonGetFailed if the type is incorrect or
// if the field is missing.
template< typename T >
inline T const& jsonGet(
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
const std::string k( key );
if ( object.find( k ) == object.end( ) ) {
throw X_JsonGetFailed( );
}
picojson::value const& v( object.at( k ) );
if ( !v.is< T >( ) ) {
throw X_JsonGetFailed( );
}
return v.get< T >( );
}
// Get a pointer to a JSON object field, or nullptr if the field doesn't exist.
// Throws X_JsonGetFailed if the type is incorrect.
template< typename T >
inline T const* jsonGetOpt(
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
const std::string k( key );
@ -147,7 +169,7 @@ inline T const* jsonGetOpt(
template< typename T >
inline bool jsonSetFromOpt(
__wr__ T& out ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
T const* ptr( jsonGetOpt< T >( object , key ) );
@ -161,7 +183,7 @@ inline bool jsonSetFromOpt(
template< >
inline bool jsonSetFromOpt< int >(
__wr__ int& out ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
double const* ptr( jsonGetOpt< double >( object , key ) );
@ -175,7 +197,7 @@ inline bool jsonSetFromOpt< int >(
template< >
inline bool jsonSetFromOpt< unsigned >(
__wr__ unsigned& out ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
double const* ptr( jsonGetOpt< double >( object , key ) );
@ -189,7 +211,7 @@ inline bool jsonSetFromOpt< unsigned >(
template< >
inline bool jsonSetFromOpt< float >(
__wr__ float& out ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* const key )
{
double const* ptr( jsonGetOpt< double >( object , key ) );
@ -203,13 +225,13 @@ inline bool jsonSetFromOpt< float >(
void jsonGetVectorOpt(
__wr__ float* vector ,
__rd__ const size_t size ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* key );
// Read a GLM vec3 from a JSON array of numbers
inline void jsonGetVectorOpt(
__wr__ glm::vec3& vector ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* key )
{
jsonGetVectorOpt( &vector.x , 3 , object , key );
@ -219,12 +241,11 @@ inline void jsonGetVectorOpt(
template< typename T >
inline bool jsonLoadOpt(
__rw__ T& out ,
__rd__ picojson::value::object const& object ,
__rd__ T_JSONObject const& object ,
__rd__ char const* key )
{
using T_Obj = picojson::value::object;
try {
auto const* sub( jsonGetOpt< T_Obj >( object , key ) );
auto const* sub( jsonGetOpt< T_JSONObject >( object , key ) );
if ( sub ) {
return out.load( *sub );
}