3636
3737#include " GEO/GEO_AttributeHandle.h"
3838#include " GU/GU_Detail.h"
39- #include " OBJ/OBJ_Node.h"
39+ #include " OBJ/OBJ_Node.h"
40+ #include " OP/OP_Bundle.h"
4041#include " OP/OP_Director.h"
4142#include " PRM/PRM_Include.h"
43+ #include " PRM/PRM_Parm.h"
4244#include " PRM/PRM_SpareData.h"
4345#include " ROP/ROP_Error.h"
46+ #include " UT/UT_StringMMPattern.h"
4447
4548#include " IECore/LinkedScene.h"
4649
@@ -54,12 +57,13 @@ using namespace IECoreHoudini;
5457const char *ROP_SceneCacheWriter::typeName = " ieSceneCacheWriter" ;
5558
5659ROP_SceneCacheWriter::ROP_SceneCacheWriter ( OP_Network *net, const char *name, OP_Operator *op )
57- : ROP_Node( net, name, op ), m_liveScene( 0 ), m_outScene( 0 )
60+ : ROP_Node( net, name, op ), m_liveScene( 0 ), m_outScene( 0 ), m_forceFilter( 0 )
5861{
5962}
6063
6164ROP_SceneCacheWriter::~ROP_SceneCacheWriter ()
6265{
66+ delete m_forceFilter;
6367}
6468
6569OP_Node *ROP_SceneCacheWriter::create ( OP_Network *net, const char *name, OP_Operator *op )
@@ -69,16 +73,18 @@ OP_Node *ROP_SceneCacheWriter::create( OP_Network *net, const char *name, OP_Ope
6973
7074PRM_Name ROP_SceneCacheWriter::pFile ( " file" , " File" );
7175PRM_Name ROP_SceneCacheWriter::pRootObject ( " rootObject" , " Root Object" );
76+ PRM_Name ROP_SceneCacheWriter::pForceObjects ( " forceObjects" , " Force Objects" );
7277
7378PRM_Default ROP_SceneCacheWriter::fileDefault ( 0 , " $HIP/output.scc" );
7479PRM_Default ROP_SceneCacheWriter::rootObjectDefault ( 0 , " /obj" );
80+ PRM_SpareData ROP_SceneCacheWriter::forceObjectsSpareData;
7581
7682OP_TemplatePair *ROP_SceneCacheWriter::buildParameters ()
7783{
7884 static PRM_Template *thisTemplate = 0 ;
7985 if ( !thisTemplate )
8086 {
81- thisTemplate = new PRM_Template[3 ];
87+ thisTemplate = new PRM_Template[4 ];
8288
8389 thisTemplate[0 ] = PRM_Template (
8490 PRM_FILE, 1 , &pFile, &fileDefault, 0 , 0 , 0 , 0 , 0 ,
@@ -89,6 +95,15 @@ OP_TemplatePair *ROP_SceneCacheWriter::buildParameters()
8995 PRM_STRING, PRM_TYPE_DYNAMIC_PATH, 1 , &pRootObject, &rootObjectDefault, 0 , 0 , 0 ,
9096 &PRM_SpareData::objPath, 0 , " The node to use as the root of the SceneCache"
9197 );
98+
99+ forceObjectsSpareData.copyFrom ( PRM_SpareData::objPath );
100+ forceObjectsSpareData.setOpRelative ( " /obj" );
101+
102+ thisTemplate[2 ] = PRM_Template (
103+ PRM_STRING, PRM_TYPE_DYNAMIC_PATH_LIST, 1 , &pForceObjects, 0 , 0 , 0 , 0 ,
104+ &forceObjectsSpareData, 0 , " Optional list of nodes to force as expanded objects. "
105+ " If this list is used, then links will be stored for any node not listed."
106+ );
92107 }
93108
94109 static OP_TemplatePair *templatePair = 0 ;
@@ -116,7 +131,7 @@ int ROP_SceneCacheWriter::startRender( int nframes, fpreal s, fpreal e )
116131 m_liveScene = new IECoreHoudini::HoudiniScene ( nodePath, emptyPath, emptyPath );
117132
118133 // wrapping with a LinkedScene to ensure full expansion when writing the non-linked file
119- if ( boost::filesystem::path ( file ). extension (). string () != " .lscc " )
134+ if ( ! linked ( file ) )
120135 {
121136 m_liveScene = new LinkedScene ( m_liveScene );
122137 }
@@ -137,6 +152,39 @@ int ROP_SceneCacheWriter::startRender( int nframes, fpreal s, fpreal e )
137152 return false ;
138153 }
139154
155+ UT_String forceObjects;
156+ evalString ( forceObjects, pForceObjects.getToken (), 0 , 0 );
157+
158+ m_forceFilter = 0 ;
159+ if ( linked ( file ) && !forceObjects.equal ( " " ) )
160+ {
161+ // get the list of nodes matching the filter
162+ const PRM_SpareData *data = getParm ( pForceObjects.getToken () ).getSparePtr ();
163+ OBJ_Node *baseNode = OPgetDirector ()->findNode ( data->getOpRelative () )->castToOBJNode ();
164+ OP_Bundle *bundle = getParmBundle ( pForceObjects.getToken (), 0 , forceObjects, baseNode, data->getOpFilter () );
165+
166+ // add all of the parent nodes
167+ UT_PtrArray<OP_Node *> nodes;
168+ bundle->getMembers ( nodes );
169+ size_t numNodes = nodes.entries ();
170+ for ( size_t i = 0 ; i < numNodes; ++i )
171+ {
172+ OP_Node *current = nodes[i]->getParent ();
173+ while ( current )
174+ {
175+ bundle->addOp ( current );
176+ current = current->getParent ();
177+ }
178+ }
179+
180+ // build a matchable filter from all these nodes
181+ UT_WorkBuffer buffer;
182+ bundle->buildString ( buffer );
183+ buffer.copyIntoString ( forceObjects );
184+ m_forceFilter = new UT_StringMMPattern ();
185+ m_forceFilter->compile ( forceObjects );
186+ }
187+
140188 return true ;
141189}
142190
@@ -193,20 +241,47 @@ ROP_RENDER_CODE ROP_SceneCacheWriter::doWrite( const SceneInterface *liveScene,
193241 outScene->writeTransform ( liveScene->readTransform ( time ), time );
194242 }
195243
196- bool link = false ;
244+ Mode mode = NaturalExpand;
245+ const HoudiniScene *hScene = IECore::runTimeCast<const HoudiniScene>( liveScene );
246+ if ( hScene && m_forceFilter )
247+ {
248+ UT_String nodePath;
249+ hScene->node ()->getFullPath ( nodePath );
250+ mode = ( nodePath.multiMatch ( *m_forceFilter ) ) ? ForcedExpand : ForcedLink;
251+ }
252+
197253 SceneInterface::NameList attrs;
198254 liveScene->attributeNames ( attrs );
199255 for ( SceneInterface::NameList::iterator it = attrs.begin (); it != attrs.end (); ++it )
200256 {
201- outScene->writeAttribute ( *it, liveScene->readAttribute ( *it, time ), time );
202257 if ( *it == LinkedScene::linkAttribute )
203258 {
204- link = true ;
259+ if ( mode == ForcedExpand )
260+ {
261+ continue ;
262+ }
263+
264+ mode = NaturalLink;
265+ }
266+
267+ outScene->writeAttribute ( *it, liveScene->readAttribute ( *it, time ), time );
268+ }
269+
270+ if ( mode == ForcedLink )
271+ {
272+ const SceneCacheNode<OP_Node> *sceneNode = static_cast < const SceneCacheNode<OP_Node>* >( hScene->node () );
273+ if ( sceneNode )
274+ {
275+ ConstSceneInterfacePtr scene = sceneNode->scene ();
276+ if ( scene )
277+ {
278+ IECore::runTimeCast<LinkedScene>( outScene )->writeLink ( scene );
279+ return ROP_CONTINUE_RENDER;
280+ }
205281 }
206282 }
207283
208- // If this is a link, we exit now, since all other write calls will throw exceptions
209- if ( link )
284+ if ( mode == NaturalLink )
210285 {
211286 return ROP_CONTINUE_RENDER;
212287 }
@@ -243,3 +318,17 @@ ROP_RENDER_CODE ROP_SceneCacheWriter::doWrite( const SceneInterface *liveScene,
243318
244319 return ROP_CONTINUE_RENDER;
245320}
321+
322+ bool ROP_SceneCacheWriter::updateParmsFlags ()
323+ {
324+ UT_String value;
325+ evalString ( value, pFile.getToken (), 0 , 0 );
326+ std::string file = value.toStdString ();
327+ enableParm ( pForceObjects.getToken (), linked ( file ) );
328+ return true ;
329+ }
330+
331+ bool ROP_SceneCacheWriter::linked ( const std::string &file ) const
332+ {
333+ return ( boost::filesystem::path ( file ).extension ().string () == " .lscc" );
334+ }
0 commit comments