3535#include " IECoreNuke/LiveScene.h"
3636
3737#include " DDImage/Scene.h"
38+ #include " DDImage/Execute.h"
3839
3940#include " IECoreNuke/Convert.h"
4041#include " IECoreNuke/MeshFromNuke.h"
5455#include " boost/format.hpp"
5556#include " boost/tokenizer.hpp"
5657
58+ #include " tbb/recursive_mutex.h"
59+
5760using namespace IECore ;
5861using namespace IECoreScene ;
5962using namespace IECoreNuke ;
@@ -74,6 +77,14 @@ IECore::TransformationMatrixd convertTransformMatrix( DD::Image::Matrix4& from )
7477 return to;
7578}
7679
80+ tbb::recursive_mutex g_mutex;
81+
82+ LiveScene::LiveSceneGeometryCache &cachedGeometryListMap ()
83+ {
84+ static LiveScene::LiveSceneGeometryCache *cache = new LiveScene::LiveSceneGeometryCache ();
85+ return *cache;
86+ }
87+
7788}
7889
7990const std::string& LiveScene::nameAttribute ( " ieName" );
@@ -124,9 +135,13 @@ std::string LiveScene::geoInfoPath( const int& index ) const
124135 }
125136 else
126137 {
127- auto info = geometryList ().object ( index );
138+ auto info = object ( index );
139+ if ( !info )
140+ {
141+ return " /undefined" + std::to_string ( index );
142+ }
128143 std::string nameValue;
129- if ( auto nameAttrib = info. get_group_attribute ( GroupType::Group_Object, nameAttribute.data () ) )
144+ if ( auto nameAttrib = info-> get_group_attribute ( GroupType::Group_Object, nameAttribute.data () ) )
130145 {
131146 nameValue = nameAttrib->stdstring ();
132147 }
@@ -141,26 +156,164 @@ std::string LiveScene::geoInfoPath( const int& index ) const
141156 }
142157}
143158
144- GeometryList LiveScene::geometryList ( const double * time ) const
159+ void LiveScene::cacheGeometryList ( const double & frame ) const
145160{
146- auto oc = OutputContext ();
161+ DD::Image::Hash h;
162+ if ( auto parent = m_op->parent () )
163+ {
164+ h = static_cast <Op*>( parent )->hash ();
165+ }
166+ else
167+ {
168+ h = static_cast <Op*>( m_op )->hash ();
169+ }
170+ auto it = cachedGeometryListMap ().find ( this );
171+ if ( it == cachedGeometryListMap ().end () )
172+ {
173+ auto geomList = geometryList ( frame );
174+ cachedGeometryListMap ()[this ][h][frame] = geomList;
175+ }
176+ else
177+ {
178+ auto jit = cachedGeometryListMap ()[this ].find ( h );
179+ if ( jit == cachedGeometryListMap ()[this ].end () )
180+ {
181+ auto geomList = geometryList ( frame );
182+ cachedGeometryListMap ()[this ][h][frame] = geomList;
183+ }
184+ else
185+ {
186+ auto kit = cachedGeometryListMap ()[this ][h].find ( frame );
187+ if ( kit == cachedGeometryListMap ()[this ][h].end () )
188+ {
189+ auto geomList = geometryList ( frame );
190+ cachedGeometryListMap ()[this ][h][frame] = geomList;
191+ }
192+ }
193+ }
194+ }
195+
196+ unsigned LiveScene::objects ( const double * time) const
197+ {
198+ double frame;
147199 if ( time )
148200 {
149- oc. setFrame ( timeToFrame ( *time ) );
201+ frame = timeToFrame ( *time );
150202 }
151203 else
152204 {
153- oc. setFrame ( m_op->outputContext ().frame () );
205+ frame = m_op->outputContext ().frame ();
154206 }
207+
208+ cacheGeometryList ( frame );
155209
156- auto nodeInputOp = m_op->node_input ( 0 , Op::EXECUTABLE_INPUT, &oc );
157- auto geoOp = dynamic_cast <DD::Image::GeoOp*>( nodeInputOp );
210+ DD::Image::Hash h;
211+ if ( auto parent = m_op->parent () )
212+ {
213+ h = static_cast <Op*>( parent )->hash ();
214+ }
215+ else
216+ {
217+ h = static_cast <Op*>( m_op )->hash ();
218+ }
158219
159- geoOp->validate (true );
220+ auto cit = cachedGeometryListMap ().find ( this );
221+ if ( cit != cachedGeometryListMap ().end () )
222+ {
223+ auto jit = cachedGeometryListMap ()[this ].find ( h );
224+ if ( jit != cachedGeometryListMap ()[this ].end () )
225+ {
226+
227+ auto kit = cachedGeometryListMap ()[this ][h].find ( frame );
228+ if ( kit != cachedGeometryListMap ()[this ][h].end () )
229+ {
230+ return cachedGeometryListMap ()[this ][h][frame].objects ();
231+ }
232+ }
233+ }
234+
235+ return 0 ;
236+ }
237+
238+ DD::Image::GeoInfo* LiveScene::object ( const unsigned & index, const double * time ) const
239+ {
240+ double frame;
241+ if ( time )
242+ {
243+ frame = timeToFrame ( *time );
244+ }
245+ else
246+ {
247+ frame = m_op->outputContext ().frame ();
248+ }
249+
250+ cacheGeometryList ( frame );
251+
252+ DD::Image::Hash h;
253+ if ( auto parent = m_op->parent () )
254+ {
255+ h = static_cast <Op*>( parent )->hash ();
256+ }
257+ else
258+ {
259+ h = static_cast <Op*>( m_op )->hash ();
260+ }
261+
262+ auto cit = cachedGeometryListMap ().find ( this );
263+ if ( cit != cachedGeometryListMap ().end () )
264+ {
265+ auto jit = cachedGeometryListMap ()[this ].find ( h );
266+ if ( jit != cachedGeometryListMap ()[this ].end () )
267+ {
268+
269+ auto kit = cachedGeometryListMap ()[this ][h].find ( frame );
270+ if ( kit != cachedGeometryListMap ()[this ][h].end () )
271+ {
272+ return &kit->second .object ( index );
273+ }
274+ }
275+ }
276+ return nullptr ;
277+ }
278+
279+ DD::Image::GeometryList LiveScene::geometryList ( DD::Image::Op* op, const double & frame ) const
280+ {
160281 boost::shared_ptr<DD::Image::Scene> scene ( new DD::Image::Scene () );
161- geoOp->build_scene ( *scene );
282+ boost::shared_ptr<DD::Image::GeometryList> geo ( new DD::Image::GeometryList () );
283+
284+ auto executioner = Execute ();
285+ auto executableOp = executioner.generateOp ( op, 0 , frame );
286+ if ( !executableOp )
287+ {
288+ return *geo;
289+ }
162290
163- return *scene->object_list ();
291+ DD::Image::GeoOp* geoOp = executableOp->geoOp ();
292+ if ( !geoOp )
293+ {
294+ return *geo;
295+ }
296+
297+ geoOp->validate (true );
298+
299+ geoOp->get_geometry ( *scene, *geo );
300+
301+ return *geo;
302+ }
303+
304+ DD::Image::GeometryList LiveScene::geometryList ( const double & frame ) const
305+ {
306+ // Nuke Geometry API is not thread safe so we need to use a mutex here to avoid crashes.
307+ tbb::recursive_mutex::scoped_lock l ( g_mutex );
308+ auto result = geometryList ( m_op, frame );
309+
310+ if ( !result.objects () && m_op->input ( 0 ) )
311+ {
312+ auto particleToGeo = Op::create ( " ParticleToGeo" , m_op );
313+ result = geometryList ( particleToGeo, frame );
314+ }
315+
316+ return result;
164317}
165318
166319std::string LiveScene::fileName () const
@@ -190,7 +343,7 @@ Imath::Box3d LiveScene::readBound( double time ) const
190343{
191344 Imath::Box3d bound;
192345 IECoreScene::SceneInterface::Path rootPath, currentPath;
193- for ( unsigned i=0 ; i < geometryList ( &time ). objects ( ); ++i )
346+ for ( unsigned i=0 ; i < objects ( &time ); ++i )
194347 {
195348 auto nameValue = geoInfoPath ( i );
196349 auto result = m_pathMatcher.match ( nameValue );
@@ -201,16 +354,21 @@ Imath::Box3d LiveScene::readBound( double time ) const
201354 IECoreScene::SceneInterface::stringToPath ( m_rootPath, rootPath );
202355 IECoreScene::SceneInterface::stringToPath ( nameValue, currentPath );
203356
204- GeoInfo info = geometryList ( &time ).object ( i );
357+ auto info = object ( i, &time );
358+ if ( !info )
359+ {
360+ return bound;
361+ }
362+
205363 Box3 objectBound;
206364 if ( ( currentPath.size () > 1 ) && ( ( currentPath.size () == rootPath.size () + 1 ) || ( nameValue == m_rootPath ) ) )
207365 {
208366 // object space bound
209- objectBound = info. bbox ();
367+ objectBound = info-> bbox ();
210368 }
211369 else
212370 {
213- objectBound = info. getTransformedBBox ();
371+ objectBound = info-> getTransformedBBox ();
214372 }
215373 Imath::Box3d b = IECore::convert<Imath::Box3d, Box3>( objectBound );
216374
@@ -231,14 +389,18 @@ void LiveScene::writeBound( const Imath::Box3d &bound, double time )
231389ConstDataPtr LiveScene::readTransform ( double time ) const
232390{
233391
234- for ( unsigned i=0 ; i < geometryList (). objects (); ++i )
392+ for ( unsigned i=0 ; i < objects ( &time ); ++i )
235393 {
236394 auto nameValue = geoInfoPath ( i );
237395 auto result = m_pathMatcher.match ( nameValue );
238396 if ( result == IECore::PathMatcher::ExactMatch )
239397 {
240- auto geoInfo = geometryList ( &time ).object ( i );
241- auto from = geoInfo.matrix ;
398+ auto geoInfo = object ( i, &time );
399+ if ( !geoInfo )
400+ {
401+ return new TransformationMatrixdData ( IECore::TransformationMatrixd () );
402+ }
403+ auto from = geoInfo->matrix ;
242404 return new TransformationMatrixdData ( convertTransformMatrix ( from ) );
243405 }
244406 }
@@ -310,7 +472,7 @@ void LiveScene::hashSet( const Name& setName, IECore::MurmurHash &h ) const
310472
311473bool LiveScene::hasObject () const
312474{
313- for ( unsigned i=0 ; i < geometryList (). objects (); ++i )
475+ for ( unsigned i=0 ; i < objects (); ++i )
314476 {
315477 auto nameValue = geoInfoPath ( i );
316478 auto result = m_pathMatcher.match ( nameValue );
@@ -352,10 +514,11 @@ void LiveScene::writeObject( const Object *object, double time )
352514
353515void LiveScene::childNames ( NameList &childNames ) const
354516{
517+
355518 childNames.clear ();
356519 std::vector<std::string> allPaths;
357520
358- for ( unsigned i=0 ; i < geometryList (). objects (); ++i )
521+ for ( unsigned i=0 ; i < objects (); ++i )
359522 {
360523 auto nameValue = geoInfoPath ( i );
361524 auto result = m_pathMatcher.match ( nameValue );
0 commit comments