1 //-*****************************************************************************
2 //
3 // Copyright (c) 2009-2012,
4 //  Sony Pictures Imageworks Inc. and
5 //  Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 // *       Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // *       Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following disclaimer
16 // in the documentation and/or other materials provided with the
17 // distribution.
18 // *       Neither the name of Sony Pictures Imageworks, nor
19 // Industrial Light & Magic, nor the names of their contributors may be used
20 // to endorse or promote products derived from this software without specific
21 // prior written permission.
22 //
23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 //
35 //-*****************************************************************************
36 
37 
38 #include <Alembic/AbcMaterial/IMaterial.h>
39 #include "InternalUtil.h"
40 
41 #include <set>
42 
43 namespace Alembic {
44 namespace AbcMaterial {
45 namespace ALEMBIC_VERSION_NS {
46 
init()47 void IMaterialSchema::init()
48 {
49     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterialSchema::init()" );
50 
51     AbcCoreAbstract::CompoundPropertyReaderPtr _this = this->getPtr();
52 
53     if ( this->getPropertyHeader( ".nodes" ) != NULL )
54     {
55         m_node = Abc::ICompoundProperty( _this, ".nodes" );
56     }
57 
58     if ( this->getPropertyHeader( ".interfaceParams" ) != NULL )
59     {
60         m_interfaceParams = Abc::ICompoundProperty( _this, ".interfaceParams" );
61     }
62 
63     if ( this->getPropertyHeader( ".terminals" ) != NULL )
64     {
65         Abc::IStringArrayProperty termProp( _this, ".terminals" );
66         Abc::StringArraySamplePtr samp;
67         termProp.get( samp );
68 
69         size_t numTerms = samp->size() / 2;
70         for( size_t i = 0; i < numTerms; ++i )
71         {
72             m_terminals[( *samp )[2 * i]] = ( *samp )[2 * i + 1];
73         }
74     }
75 
76     if ( this->getPropertyHeader( ".shaderNames" ) != NULL )
77     {
78         Abc::IStringArrayProperty shaderProp( _this, ".shaderNames" );
79         Abc::StringArraySamplePtr samp;
80         shaderProp.get( samp );
81 
82         size_t numShaders = samp->size() / 2;
83         for( size_t i = 0; i < numShaders; ++i )
84         {
85             m_shaderNames[( *samp )[2 * i]] = ( *samp )[2 * i + 1];
86         }
87     }
88 
89     if ( this->getPropertyHeader( ".interface" ) != NULL )
90     {
91         Abc::IStringArrayProperty interfaceProp( _this, ".interface" );
92         Abc::StringArraySamplePtr samp;
93         interfaceProp.get( samp );
94 
95         size_t numInterface = samp->size() / 2;
96         m_interface.reserve( numInterface );
97         for( size_t i = 0; i < numInterface; ++i )
98         {
99             m_interfaceMap[( *samp )[2 * i]] = ( *samp )[2 * i + 1];
100             m_interface.push_back( ( *samp )[2 * i] );
101         }
102     }
103     ALEMBIC_ABC_SAFE_CALL_END_RESET();
104 }
105 
getTargetNames(std::vector<std::string> & oTargetNames)106 void IMaterialSchema::getTargetNames( std::vector<std::string> & oTargetNames )
107 {
108     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterial::getTargetNames" );
109     std::set<std::string> uniqueNames;
110 
111     std::vector<std::string> tokens;
112 
113     std::map<std::string, std::string>::iterator i;
114     for ( i = m_shaderNames.begin(); i != m_shaderNames.end(); ++i )
115     {
116         Util::split_tokens( i->first, tokens );
117 
118         // target.shaderType
119         if ( tokens.size() == 2 )
120         {
121             uniqueNames.insert( tokens[0] );
122         }
123     }
124 
125     oTargetNames.clear();
126     oTargetNames.reserve( uniqueNames.size() );
127     oTargetNames.insert( oTargetNames.end(), uniqueNames.begin(),
128                          uniqueNames.end() );
129 
130     ALEMBIC_ABC_SAFE_CALL_END_RESET();
131 }
132 
133 
getShaderTypesForTarget(const std::string & iTargetName,std::vector<std::string> & oShaderTypeNames)134 void IMaterialSchema::getShaderTypesForTarget( const std::string & iTargetName,
135     std::vector<std::string> & oShaderTypeNames )
136 {
137     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterialSchema::getShaderTypesForTarget" );
138     std::set<std::string> uniqueNames;
139 
140     std::vector<std::string> tokens;
141 
142     std::map<std::string, std::string>::iterator i;
143     for ( i = m_shaderNames.begin(); i != m_shaderNames.end(); ++i )
144     {
145         Util::split_tokens( i->first, tokens );
146 
147         if ( tokens.size() == 2 )
148         {
149             if ( tokens[0] == iTargetName )
150             {
151                 uniqueNames.insert( tokens[1] );
152             }
153         }
154     }
155 
156     oShaderTypeNames.clear();
157     oShaderTypeNames.reserve( uniqueNames.size() );
158     oShaderTypeNames.insert( oShaderTypeNames.end(),
159             uniqueNames.begin(), uniqueNames.end() );
160     ALEMBIC_ABC_SAFE_CALL_END_RESET();
161 }
162 
getShader(const std::string & iTarget,const std::string & iShaderType,std::string & oResult)163 bool IMaterialSchema::getShader( const std::string & iTarget,
164                                  const std::string & iShaderType,
165                                  std::string & oResult )
166 {
167     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterialSchema::getShader" );
168     std::string propName = Util::buildTargetName( iTarget, iShaderType, "" );
169 
170     std::map<std::string, std::string>::iterator i =
171         m_shaderNames.find( propName );
172 
173     if ( i != m_shaderNames.end() )
174     {
175         oResult = i->second;
176         return true;
177     }
178 
179     ALEMBIC_ABC_SAFE_CALL_END_RESET();
180     return false;
181 }
182 
183 
getShaderParameters(const std::string & iTarget,const std::string & iShaderType)184 Abc::ICompoundProperty IMaterialSchema::getShaderParameters(
185         const std::string & iTarget,
186         const std::string & iShaderType )
187 {
188     Abc::ICompoundProperty result;
189 
190     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterialSchema::getShaderParameters" );
191     std::string propName = Util::buildTargetName( iTarget, iShaderType,
192                                                   "params" );
193 
194     if (const AbcCoreAbstract::PropertyHeader * header =
195         getPropertyHeader( propName ) )
196     {
197         if ( header->isCompound() )
198         {
199             result = Abc::ICompoundProperty( *this, propName );
200         }
201     }
202     ALEMBIC_ABC_SAFE_CALL_END_RESET();
203 
204     return result;
205 }
206 
getNumNetworkNodes()207 size_t IMaterialSchema::getNumNetworkNodes()
208 {
209     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMaterialSchema::getNumNetworkNodes" );
210     if ( m_node.valid() )
211     {
212         return m_node.getNumProperties();
213     }
214     ALEMBIC_ABC_SAFE_CALL_END_RESET();
215 
216     return 0;
217 }
218 
getNetworkNodeNames(std::vector<std::string> & oNames)219 void IMaterialSchema::getNetworkNodeNames( std::vector<std::string> & oNames )
220 {
221     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMateriaSchema::getNetworkNodeNames" );
222     oNames.clear();
223 
224     if ( !m_node.valid() )
225     {
226         return;
227     }
228 
229     oNames.reserve( m_node.getNumProperties() );
230 
231     for ( size_t i = 0, e = m_node.getNumProperties(); i < e; ++i )
232     {
233         const AbcCoreAbstract::PropertyHeader &header =
234             m_node.getPropertyHeader( i );
235 
236         if ( header.isCompound() )
237         {
238             oNames.push_back( header.getName() );
239         }
240     }
241     ALEMBIC_ABC_SAFE_CALL_END_RESET();
242 }
243 
getNetworkNode(size_t iIndex)244 IMaterialSchema::NetworkNode IMaterialSchema::getNetworkNode( size_t iIndex )
245 {
246     ALEMBIC_ABC_SAFE_CALL_BEGIN( "IMateriaSchema::getNetworkNode" );
247     if ( !m_node.valid() || iIndex >= m_node.getNumProperties() )
248     {
249         return NetworkNode();
250     }
251 
252     const AbcCoreAbstract::PropertyHeader &header =
253         m_node.getPropertyHeader( iIndex );
254 
255     if ( !header.isCompound() )
256     {
257         return NetworkNode();
258     }
259 
260     return NetworkNode(
261             Abc::ICompoundProperty( m_node, header.getName() ) );
262     ALEMBIC_ABC_SAFE_CALL_END_RESET();
263 
264     return NetworkNode();
265 }
266 
267 
getNetworkNode(const std::string & iNodeName)268 IMaterialSchema::NetworkNode IMaterialSchema::getNetworkNode(
269     const std::string & iNodeName )
270 {
271     return NetworkNode( m_node, iNodeName );
272 }
273 
274 
getNetworkTerminalTargetNames(std::vector<std::string> & oTargetNames)275 void IMaterialSchema::getNetworkTerminalTargetNames(
276     std::vector<std::string> & oTargetNames )
277 {
278     ALEMBIC_ABC_SAFE_CALL_BEGIN(
279         "IMateriaSchema::getNetworkTerminalTargetNames" );
280     oTargetNames.clear();
281 
282     std::set<std::string> uniqueNames;
283 
284     std::vector<std::string> tokens;
285     std::map<std::string, std::string>::iterator i;
286     for ( i = m_terminals.begin(); i != m_terminals.end(); ++i )
287     {
288         Util::split_tokens( i->first, tokens );
289 
290         // target.shaderType
291         if ( tokens.size() == 2 )
292         {
293             uniqueNames.insert( tokens[0] );
294         }
295     }
296 
297     oTargetNames.reserve( uniqueNames.size() );
298     oTargetNames.insert( oTargetNames.end(),
299             uniqueNames.begin(), uniqueNames.end() );
300     ALEMBIC_ABC_SAFE_CALL_END_RESET();
301 }
302 
getNetworkTerminalShaderTypesForTarget(const std::string & iTargetName,std::vector<std::string> & oShaderTypeNames)303 void IMaterialSchema::getNetworkTerminalShaderTypesForTarget(
304     const std::string & iTargetName,
305     std::vector<std::string> & oShaderTypeNames)
306 {
307     ALEMBIC_ABC_SAFE_CALL_BEGIN(
308         "IMateriaSchema::getNetworkTerminalShaderTypesForTarget" );
309 
310     oShaderTypeNames.clear();
311 
312     std::set<std::string> uniqueNames;
313 
314     std::vector<std::string> tokens;
315     std::map<std::string, std::string>::iterator i;
316     for ( i = m_terminals.begin(); i != m_terminals.end(); ++i )
317     {
318         Util::split_tokens( i->first, tokens );
319 
320         if ( tokens.size() == 2 )
321         {
322             if ( tokens[0] == iTargetName )
323             {
324                 uniqueNames.insert( tokens[1] );
325             }
326         }
327     }
328 
329     oShaderTypeNames.reserve( uniqueNames.size() );
330     oShaderTypeNames.insert( oShaderTypeNames.end(),
331         uniqueNames.begin(), uniqueNames.end() );
332 
333     ALEMBIC_ABC_SAFE_CALL_END_RESET();
334 }
335 
getNetworkTerminal(const std::string & iTarget,const std::string & iShaderType,std::string & oNodeName,std::string & oOutputName)336 bool IMaterialSchema::getNetworkTerminal(
337         const std::string & iTarget,
338         const std::string & iShaderType,
339         std::string & oNodeName,
340         std::string & oOutputName)
341 {
342     ALEMBIC_ABC_SAFE_CALL_BEGIN(
343         "IMateriaSchema::getNetworkTerminal" );
344 
345     std::string propName = iTarget + "." + iShaderType;
346 
347     std::map<std::string, std::string>::iterator i =
348         m_terminals.find( propName );
349 
350     if ( i == m_terminals.end() )
351     {
352         return false;
353     }
354 
355     std::vector<std::string> tokens;
356     Util::split_tokens( i->second, tokens, 1 );
357 
358     oNodeName = tokens[0];
359     oOutputName = tokens.size() > 1 ? tokens[1] : "";
360 
361     return true;
362     ALEMBIC_ABC_SAFE_CALL_END_RESET();
363 
364     return false;
365 }
366 
getNumNetworkInterfaceParameterMappings()367 size_t IMaterialSchema::getNumNetworkInterfaceParameterMappings()
368 {
369     return m_interface.size();
370 }
371 
372 
getNetworkInterfaceParameterMapping(size_t iIndex,std::string & oInterfaceParamName,std::string & oMapToNodeName,std::string & oMapToParamName)373 bool IMaterialSchema::getNetworkInterfaceParameterMapping( size_t iIndex,
374     std::string & oInterfaceParamName, std::string & oMapToNodeName,
375     std::string & oMapToParamName )
376 {
377     ALEMBIC_ABC_SAFE_CALL_BEGIN(
378         "IMateriaSchema::getNetworkInterfaceParameterMapping(size_t,...)" );
379 
380     if ( iIndex >= m_interface.size() )
381     {
382         return false;
383     }
384 
385     oInterfaceParamName = m_interface[iIndex];
386 
387     return getNetworkInterfaceParameterMapping( oInterfaceParamName,
388                                                 oMapToNodeName,
389                                                 oMapToParamName );
390     ALEMBIC_ABC_SAFE_CALL_END_RESET();
391 
392     return false;
393 }
394 
395 
396 
397 
getNetworkInterfaceParameterMappingNames(std::vector<std::string> & oNames)398 void IMaterialSchema::getNetworkInterfaceParameterMappingNames(
399     std::vector<std::string> & oNames )
400 {
401     oNames = m_interface;
402 }
403 
404 
getNetworkInterfaceParameterMapping(const std::string & iInterfaceParamName,std::string & oMapToNodeName,std::string & oMapToParamName)405 bool IMaterialSchema::getNetworkInterfaceParameterMapping(
406     const std::string & iInterfaceParamName,
407     std::string & oMapToNodeName,
408     std::string & oMapToParamName )
409 {
410     ALEMBIC_ABC_SAFE_CALL_BEGIN(
411         "IMateriaSchema::getNetworkInterfaceParameterMapping" );
412 
413     std::map<std::string, std::string>::iterator i =
414         m_interfaceMap.find( iInterfaceParamName );
415 
416     if ( i == m_interfaceMap.end() )
417     {
418         return false;
419     }
420 
421     std::vector<std::string> tokens;
422 
423     Util::split_tokens( i->second, tokens, 1 );
424 
425     oMapToNodeName = tokens[0];
426     oMapToParamName = tokens.size() > 1 ? tokens[1] : "";
427 
428     return true;
429     ALEMBIC_ABC_SAFE_CALL_END_RESET();
430 
431     return false;
432 }
433 
getNetworkInterfaceParameters()434 Abc::ICompoundProperty IMaterialSchema::getNetworkInterfaceParameters()
435 {
436     return m_interfaceParams;
437 }
438 
439 
440 ///////////////////////////////////////////////////////////////////////////////
441 
NetworkNode()442 IMaterialSchema::NetworkNode::NetworkNode()
443 : m_connectionsChecked( false )
444 {
445 }
446 
447 
NetworkNode(Abc::ICompoundProperty iCompound)448 IMaterialSchema::NetworkNode::NetworkNode( Abc::ICompoundProperty iCompound )
449 : m_compound( iCompound )
450 , m_connectionsChecked( false )
451 {
452 }
453 
454 
NetworkNode(Abc::ICompoundProperty iParent,const std::string & iNodeName)455 IMaterialSchema::NetworkNode::NetworkNode( Abc::ICompoundProperty iParent,
456                                            const std::string & iNodeName )
457 : m_connectionsChecked( false )
458 {
459     if ( iParent.valid() )
460     {
461         if ( const AbcCoreAbstract::PropertyHeader * header =
462             iParent.getPropertyHeader( iNodeName ) )
463         {
464             if ( header->isCompound() )
465             {
466                 m_compound =  Abc::ICompoundProperty( iParent, iNodeName );
467             }
468         }
469     }
470 }
471 
valid()472 bool IMaterialSchema::NetworkNode::valid()
473 {
474     return m_compound.valid();
475 }
476 
477 
getName()478 std::string IMaterialSchema::NetworkNode::getName()
479 {
480     if ( valid() )
481     {
482         return m_compound.getName();
483     }
484 
485     return "";
486 }
487 
488 
getTarget(std::string & oResult)489 bool IMaterialSchema::NetworkNode::getTarget( std::string & oResult )
490 {
491     if ( !valid() )
492     {
493         return false;
494     }
495 
496     if ( const AbcCoreAbstract::PropertyHeader * header =
497         m_compound.getPropertyHeader( "target" ) )
498     {
499         if ( header->isScalar() && Abc::IStringProperty::matches( *header) )
500         {
501             Abc::IStringProperty prop( m_compound, header->getName() );
502 
503             oResult = prop.getValue();
504             return true;
505         }
506     }
507 
508     return false;
509 }
510 
getNodeType(std::string & oResult)511 bool IMaterialSchema::NetworkNode::getNodeType( std::string & oResult )
512 {
513     if ( !valid() )
514     {
515         return false;
516     }
517 
518     if ( const AbcCoreAbstract::PropertyHeader * header =
519         m_compound.getPropertyHeader( "type" ) )
520     {
521         if ( header->isScalar() && Abc::IStringProperty::matches( *header ) )
522         {
523             Abc::IStringProperty prop( m_compound, header->getName() );
524 
525             oResult = prop.getValue();
526             return true;
527         }
528     }
529 
530     return false;
531 }
532 
getParameters()533 Abc::ICompoundProperty IMaterialSchema::NetworkNode::getParameters()
534 {
535     Abc::ICompoundProperty result;
536     if ( !valid() )
537     {
538         return result;
539     }
540 
541     if (const AbcCoreAbstract::PropertyHeader * header =
542         m_compound.getPropertyHeader( "params" ) )
543     {
544         if ( header->isCompound() )
545         {
546             result = Abc::ICompoundProperty( m_compound, "params" );
547         }
548     }
549 
550     return result;
551 }
552 
getNumConnections()553 size_t IMaterialSchema::NetworkNode::getNumConnections()
554 {
555     if ( ! m_connectionsChecked )
556     {
557         if ( m_compound.getPropertyHeader( ".connections" ) != NULL )
558         {
559             Abc::IStringArrayProperty connectProp( m_compound, ".connections" );
560             Abc::StringArraySamplePtr samp;
561             connectProp.get( samp );
562 
563             size_t numConnect = samp->size() / 2;
564             m_connections.reserve( numConnect );
565             for( size_t i = 0; i < numConnect; ++i )
566             {
567                 m_connectionsMap[( *samp )[2 * i]] = ( *samp )[2 * i + 1];
568                 m_connections.push_back( ( *samp )[2 * i] );
569             }
570         }
571         m_connectionsChecked = true;
572     }
573 
574     return m_connections.size();
575 
576 }
577 
splitConnectionValue(const std::string & v,std::string & a,std::string & b)578 void IMaterialSchema::NetworkNode::splitConnectionValue( const std::string & v,
579     std::string & a, std::string & b )
580 {
581     std::vector<std::string> tokens;
582 
583     Util::split_tokens(v, tokens, 1);
584 
585     a = tokens[0];
586     b = tokens.size() > 1 ? tokens[1] : "";
587 }
588 
getConnection(size_t iIndex,std::string & oInputName,std::string & oConnectedNodeName,std::string & oConnectedOutputName)589 bool IMaterialSchema::NetworkNode::getConnection(
590     size_t iIndex,
591     std::string & oInputName,
592     std::string & oConnectedNodeName,
593     std::string & oConnectedOutputName )
594 {
595     if ( iIndex >= getNumConnections() )
596     {
597         return false;
598     }
599 
600     oInputName = m_connections[iIndex];
601     return getConnection( oInputName, oConnectedNodeName,
602         oConnectedOutputName );
603 }
604 
getConnection(const std::string & iInputName,std::string & oConnectedNodeName,std::string & oConnectedOutputName)605 bool IMaterialSchema::NetworkNode::getConnection(
606     const std::string & iInputName,
607     std::string & oConnectedNodeName,
608     std::string & oConnectedOutputName )
609 {
610     // loads the connections if it hasn't already
611     getNumConnections();
612 
613     std::map< std::string, std::string >::iterator i =
614         m_connectionsMap.find( iInputName );
615 
616     if ( i == m_connectionsMap.end() )
617     {
618         return false;
619     }
620 
621     std::string value = i->second;
622     splitConnectionValue( value, oConnectedNodeName, oConnectedOutputName );
623 
624     return true;
625 }
626 
627 } // End namespace ALEMBIC_VERSION_NS
628 } // End namespace AbcMaterial
629 } // End namespace Alembic
630 
631