1 //-*****************************************************************************
2 //
3 // Copyright (c) 2009-2013,
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 #include "AttributesWriter.h"
38 #include "MayaUtility.h"
39 
40 namespace Abc = Alembic::Abc;
41 namespace AbcGeom = Alembic::AbcGeom;
42 namespace AbcA = Alembic::AbcCoreAbstract;
43 
44 namespace {
45 
46 static const char * cAttrScope = "_AbcGeomScope";
47 static const char * cAttrType  = "_AbcType";
48 
scopeToString(AbcGeom::GeometryScope input)49 std::string scopeToString( AbcGeom::GeometryScope input )
50 {
51     switch(input)
52     {
53         case AbcGeom::kConstantScope: return "kConstantScope";
54         case AbcGeom::kFacevaryingScope:return "kFacevaryingScope";
55         case AbcGeom::kUniformScope: return "kUniformScope";
56         case AbcGeom::kUnknownScope: return "kUnknownScope";
57         case AbcGeom::kVaryingScope: return "kVaryingScope";
58         case AbcGeom::kVertexScope: return "kVertexScope";
59     }
60     return "kUnknownScope";
61 }
62 
63 // returns true if a plug is of a simple numeric data type
isDataAttr(const MPlug & iParent)64 bool isDataAttr(const MPlug & iParent)
65 {
66     MObject obj = iParent.asMObject();
67     switch (obj.apiType())
68     {
69         case MFn::kData2Double:
70         case MFn::kData3Double:
71         case MFn::kData4Double:
72         case MFn::kData2Float:
73         case MFn::kData3Float:
74         case MFn::kData2Int:
75         case MFn::kData3Int:
76         case MFn::kData2Short:
77         case MFn::kData3Short:
78         case MFn::kStringData:
79         case MFn::kStringArrayData:
80         case MFn::kFloatVectorArrayData:
81         case MFn::kVectorArrayData:
82         case MFn::kFloatArrayData:
83         case MFn::kDoubleArrayData:
84         case MFn::kIntArrayData:
85         case MFn::kPointArrayData:
86         case MFn::kUInt64ArrayData:
87             return true;
88 
89         default:
90             return false;
91     }
92     return false;
93 }
94 
strToScope(MString iStr)95 AbcGeom::GeometryScope strToScope(MString iStr)
96 {
97     iStr.toLowerCase();
98     if (iStr == "vtx")
99     {
100         return AbcGeom::kVertexScope;
101     }
102     else if (iStr == "fvr")
103     {
104         return AbcGeom::kFacevaryingScope;
105     }
106     else if (iStr == "uni")
107     {
108         return AbcGeom::kUniformScope;
109     }
110     else if (iStr == "var")
111     {
112         return AbcGeom::kVaryingScope;
113     }
114 
115     return AbcGeom::kConstantScope;
116 }
117 
118 // returns true if the string ends with _AbcGeomScope or _AbcType
endsWithArbAttr(const std::string & iStr)119 bool endsWithArbAttr(const std::string & iStr)
120 {
121     size_t len = iStr.size();
122 
123     return (len >= 13 && iStr.compare(len - 13, 13, cAttrScope) == 0) ||
124         (len >= 8 && iStr.compare(len - 8, 8, cAttrType) == 0);
125 }
126 
createUserPropertyFromNumeric(MFnNumericData::Type iType,const MObject & iAttr,const MPlug & iPlug,Abc::OCompoundProperty & iParent,Alembic::Util::uint32_t iTimeIndex,AbcGeom::GeometryScope iScope,std::vector<PlugAndObjScalar> & oScalars,std::vector<PlugAndObjArray> & oArrays)127 void createUserPropertyFromNumeric(MFnNumericData::Type iType,
128                                    const MObject& iAttr,
129                                    const MPlug& iPlug,
130                                    Abc::OCompoundProperty & iParent,
131                                    Alembic::Util::uint32_t iTimeIndex,
132                                    AbcGeom::GeometryScope iScope,
133                                    std::vector < PlugAndObjScalar > & oScalars,
134                                    std::vector < PlugAndObjArray > & oArrays)
135 {
136     std::string plugName = iPlug.partialName(0, 0, 0, 0, 0, 1).asChar();
137     switch (iType)
138     {
139         case MFnNumericData::kBoolean:
140         {
141             PlugAndObjScalar p;
142             p.plug = iPlug;
143             p.obj = iAttr;
144             Abc::OBoolProperty up(iParent, plugName, iTimeIndex);
145             p.prop = up;
146             oScalars.push_back(p);
147         }
148         break;
149 
150         case MFnNumericData::kByte:
151         case MFnNumericData::kChar:
152         {
153             PlugAndObjScalar p;
154             p.plug = iPlug;
155             p.obj = iAttr;
156             Abc::OCharProperty up(iParent, plugName, iTimeIndex);
157             p.prop = up;
158             oScalars.push_back(p);
159         }
160         break;
161 
162         case MFnNumericData::kShort:
163         {
164             PlugAndObjScalar p;
165             p.plug = iPlug;
166             p.obj = iAttr;
167             Abc::OInt16Property up(iParent, plugName, iTimeIndex);
168             p.prop = up;
169             oScalars.push_back(p);
170         }
171         break;
172 
173         case MFnNumericData::kInt:
174         {
175             PlugAndObjScalar p;
176             p.plug = iPlug;
177             p.obj = iAttr;
178             Abc::OInt32Property up(iParent, plugName, iTimeIndex);
179             p.prop = up;
180             oScalars.push_back(p);
181         }
182         break;
183 
184         case MFnNumericData::kFloat:
185         {
186             PlugAndObjScalar p;
187             p.plug = iPlug;
188             p.obj = iAttr;
189             Abc::OFloatProperty up(iParent, plugName, iTimeIndex);
190             p.prop = up;
191             oScalars.push_back(p);
192         }
193         break;
194 
195         case MFnNumericData::kDouble:
196         {
197             PlugAndObjScalar p;
198             p.plug = iPlug;
199             p.obj = iAttr;
200             Abc::ODoubleProperty up(iParent, plugName, iTimeIndex);
201             p.prop = up;
202             oScalars.push_back(p);
203         }
204         break;
205 
206         case MFnNumericData::k2Short:
207         {
208             PlugAndObjScalar p;
209             p.plug = iPlug;
210             p.obj = iAttr;
211             Abc::OV2sProperty up(iParent, plugName, iTimeIndex);
212             p.prop = up;
213             oScalars.push_back(p);
214         }
215         break;
216 
217         case MFnNumericData::k3Short:
218         {
219             PlugAndObjScalar p;
220             p.plug = iPlug;
221             p.obj = iAttr;
222             Abc::OV3sProperty up(iParent, plugName, iTimeIndex);
223             p.prop = up;
224             oScalars.push_back(p);
225         }
226         break;
227 
228         case MFnNumericData::k2Int:
229         {
230             PlugAndObjScalar p;
231             p.plug = iPlug;
232             p.obj = iAttr;
233             Abc::OV2iProperty up(iParent, plugName, iTimeIndex);
234             p.prop = up;
235             oScalars.push_back(p);
236         }
237         break;
238 
239         case MFnNumericData::k3Int:
240         {
241             PlugAndObjScalar p;
242             p.plug = iPlug;
243             p.obj = iAttr;
244             Abc::OV3iProperty up(iParent, plugName, iTimeIndex);
245             p.prop = up;
246             oScalars.push_back(p);
247         }
248         break;
249 
250         case MFnNumericData::k2Float:
251         {
252             PlugAndObjScalar p;
253             p.plug = iPlug;
254             p.obj = iAttr;
255             Abc::OV2fProperty up(iParent, plugName, iTimeIndex);
256             p.prop = up;
257             oScalars.push_back(p);
258         }
259         break;
260 
261         case MFnNumericData::k3Float:
262         {
263             PlugAndObjScalar p;
264             p.plug = iPlug;
265             p.obj = iAttr;
266             Abc::OV3fProperty up(iParent, plugName, iTimeIndex);
267             p.prop = up;
268             oScalars.push_back(p);
269         }
270         break;
271 
272         case MFnNumericData::k2Double:
273         {
274             PlugAndObjScalar p;
275             p.plug = iPlug;
276             p.obj = iAttr;
277             Abc::OV2dProperty up(iParent, plugName, iTimeIndex);
278             p.prop = up;
279             oScalars.push_back(p);
280         }
281         break;
282 
283         case MFnNumericData::k3Double:
284         {
285             PlugAndObjScalar p;
286             p.plug = iPlug;
287             p.obj = iAttr;
288             Abc::OV3dProperty up(iParent, plugName, iTimeIndex);
289             p.prop = up;
290             oScalars.push_back(p);
291         }
292         break;
293 
294         case MFnNumericData::k4Double:
295         {
296             PlugAndObjArray p;
297             p.plug = iPlug;
298             p.obj = iAttr;
299             AbcA::DataType dtype(Alembic::Util::kFloat64POD, 4);
300             Abc::OArrayProperty up(iParent, plugName, dtype, iTimeIndex);
301             p.prop = up;
302             oArrays.push_back(p);
303         }
304         break;
305 
306         default:
307         break;
308     }
309 }
310 
createGeomPropertyFromNumeric(MFnNumericData::Type iType,const MObject & iAttr,const MPlug & iPlug,Abc::OCompoundProperty & iParent,Alembic::Util::uint32_t iTimeIndex,AbcGeom::GeometryScope iScope,std::vector<PlugAndObjArray> & oArrayVec)311 void createGeomPropertyFromNumeric(MFnNumericData::Type iType, const MObject& iAttr,
312                                const MPlug& iPlug, Abc::OCompoundProperty & iParent,
313                                Alembic::Util::uint32_t iTimeIndex,
314                                AbcGeom::GeometryScope iScope,
315                                std::vector < PlugAndObjArray > & oArrayVec)
316 {
317     std::string plugName = iPlug.partialName(0, 0, 0, 0, 0, 1).asChar();
318     switch (iType)
319     {
320         case MFnNumericData::kBoolean:
321         {
322             PlugAndObjArray p;
323             p.plug = iPlug;
324             p.obj = iAttr;
325             AbcGeom::OBoolGeomParam gp(iParent, plugName, false, iScope, 1,
326                 iTimeIndex);
327             p.prop = gp.getValueProperty();
328             oArrayVec.push_back(p);
329         }
330         break;
331 
332         case MFnNumericData::kByte:
333         case MFnNumericData::kChar:
334         {
335             PlugAndObjArray p;
336             p.plug = iPlug;
337             p.obj = iAttr;
338             AbcGeom::OCharGeomParam gp(iParent, plugName, false, iScope, 1,
339                 iTimeIndex);
340             p.prop = gp.getValueProperty();
341             oArrayVec.push_back(p);
342         }
343         break;
344 
345         case MFnNumericData::kShort:
346         {
347             PlugAndObjArray p;
348             p.plug = iPlug;
349             p.obj = iAttr;
350             AbcGeom::OInt16GeomParam gp(iParent, plugName, false, iScope, 1,
351                 iTimeIndex);
352             p.prop = gp.getValueProperty();
353             oArrayVec.push_back(p);
354         }
355         break;
356 
357         case MFnNumericData::kInt:
358         {
359             PlugAndObjArray p;
360             p.plug = iPlug;
361             p.obj = iAttr;
362             AbcGeom::OInt32GeomParam gp(iParent, plugName, false, iScope, 1,
363                 iTimeIndex);
364             p.prop = gp.getValueProperty();
365             oArrayVec.push_back(p);
366         }
367         break;
368 
369         case MFnNumericData::kFloat:
370         {
371             PlugAndObjArray p;
372             p.plug = iPlug;
373             p.obj = iAttr;
374             AbcGeom::OFloatGeomParam gp(iParent, plugName, false, iScope, 1,
375                 iTimeIndex);
376             p.prop = gp.getValueProperty();
377             oArrayVec.push_back(p);
378         }
379         break;
380 
381         case MFnNumericData::kDouble:
382         {
383             PlugAndObjArray p;
384             p.plug = iPlug;
385             p.obj = iAttr;
386             AbcGeom::ODoubleGeomParam gp(iParent, plugName, false, iScope, 1,
387                 iTimeIndex);
388             p.prop = gp.getValueProperty();
389             oArrayVec.push_back(p);
390         }
391         break;
392 
393         case MFnNumericData::k2Short:
394         {
395             PlugAndObjArray p;
396             p.plug = iPlug;
397             p.obj = iAttr;
398             AbcGeom::OV2sGeomParam gp(iParent, plugName, false, iScope, 1,
399                 iTimeIndex);
400             p.prop = gp.getValueProperty();
401             oArrayVec.push_back(p);
402         }
403         break;
404 
405         case MFnNumericData::k3Short:
406         {
407             PlugAndObjArray p;
408             p.plug = iPlug;
409             p.obj = iAttr;
410             AbcGeom::OV3sGeomParam gp(iParent, plugName, false, iScope, 1,
411                 iTimeIndex);
412             p.prop = gp.getValueProperty();
413             oArrayVec.push_back(p);
414         }
415         break;
416 
417         case MFnNumericData::k2Int:
418         {
419             PlugAndObjArray p;
420             p.plug = iPlug;
421             p.obj = iAttr;
422             AbcGeom::OV2iGeomParam gp(iParent, plugName, false, iScope, 1,
423                 iTimeIndex);
424             p.prop = gp.getValueProperty();
425             oArrayVec.push_back(p);
426         }
427         break;
428 
429         case MFnNumericData::k3Int:
430         {
431             PlugAndObjArray p;
432             p.plug = iPlug;
433             p.obj = iAttr;
434             AbcGeom::OV3iGeomParam gp(iParent, plugName, false, iScope, 1,
435                 iTimeIndex);
436             p.prop = gp.getValueProperty();
437             oArrayVec.push_back(p);
438         }
439         break;
440 
441         case MFnNumericData::k2Float:
442         {
443             PlugAndObjArray p;
444             p.plug = iPlug;
445             p.obj = iAttr;
446             AbcGeom::OV2fGeomParam gp(iParent, plugName, false, iScope, 1,
447                 iTimeIndex);
448             p.prop = gp.getValueProperty();
449             oArrayVec.push_back(p);
450         }
451         break;
452 
453         case MFnNumericData::k3Float:
454         {
455             PlugAndObjArray p;
456             p.plug = iPlug;
457             p.obj = iAttr;
458 
459             MFnAttribute mfnAttr(iAttr);
460             if (mfnAttr.isUsedAsColor())
461             {
462                 AbcGeom::OC3fGeomParam gp(iParent, plugName, false, iScope, 1,
463                     iTimeIndex);
464                 p.prop = gp.getValueProperty();
465             }
466             else
467             {
468                 AbcGeom::OV3fGeomParam gp(iParent, plugName, false, iScope, 1,
469                     iTimeIndex);
470                 p.prop = gp.getValueProperty();
471             }
472 
473             oArrayVec.push_back(p);
474         }
475         break;
476 
477         case MFnNumericData::k2Double:
478         {
479             PlugAndObjArray p;
480             p.plug = iPlug;
481             p.obj = iAttr;
482             AbcGeom::OV2dGeomParam gp(iParent, plugName, false, iScope, 1,
483                 iTimeIndex);
484             p.prop = gp.getValueProperty();
485             oArrayVec.push_back(p);
486         }
487         break;
488 
489         case MFnNumericData::k3Double:
490         {
491             PlugAndObjArray p;
492             p.plug = iPlug;
493             p.obj = iAttr;
494             AbcGeom::OV3dGeomParam gp(iParent, plugName, false, iScope, 1,
495                 iTimeIndex);
496             p.prop = gp.getValueProperty();
497             oArrayVec.push_back(p);
498         }
499         break;
500 
501         case MFnNumericData::k4Double:
502         {
503             PlugAndObjArray p;
504             p.plug = iPlug;
505             p.obj = iAttr;
506             AbcA::DataType dtype(Alembic::Util::kFloat64POD, 4);
507             p.prop = Abc::OArrayProperty(iParent, plugName, dtype, iTimeIndex);
508             oArrayVec.push_back(p);
509         }
510         break;
511 
512         default:
513         break;
514     }
515 }
516 
MFnNumericDataToSample(MFnNumericData::Type iType,const MPlug & iPlug,Abc::OScalarProperty & oProp)517 bool MFnNumericDataToSample(MFnNumericData::Type iType,
518                             const MPlug& iPlug,
519                             Abc::OScalarProperty & oProp)
520 {
521     int    ival;
522     float  fval;
523     double dval;
524     bool   bval;
525     Alembic::Util::int16_t sval;
526     Alembic::Util::int8_t  cval;
527 
528     Alembic::Util::int16_t v2sVal[2];
529     Alembic::Util::int16_t v3sVal[3];
530 
531     Alembic::Util::int32_t v2iVal[2];
532     Alembic::Util::int32_t v3iVal[3];
533 
534     float v2fVal[2];
535     float v3fVal[3];
536 
537     double v2dVal[2];
538     double v3dVal[3];
539 
540     switch (iType)
541     {
542         case MFnNumericData::kBoolean:
543         {
544             bval = iPlug.asBool();
545             oProp.set(&bval);
546         }
547         break;
548 
549         case MFnNumericData::kByte:
550         case MFnNumericData::kChar:
551         {
552             cval = iPlug.asChar();
553             oProp.set(&cval);
554         }
555         break;
556 
557         case MFnNumericData::kShort:
558         {
559             sval = iPlug.asShort();
560             oProp.set(&sval);
561         }
562         break;
563 
564         case MFnNumericData::kInt:
565         {
566             ival = iPlug.asInt();
567             oProp.set(&ival);
568         }
569         break;
570 
571         case MFnNumericData::kFloat:
572         {
573             fval = iPlug.asFloat();
574             oProp.set(&fval);
575         }
576         break;
577 
578         case MFnNumericData::kDouble:
579         {
580             dval = iPlug.asDouble();
581             oProp.set(&dval);
582         }
583         break;
584 
585         case MFnNumericData::k2Short:
586         {
587             MFnNumericData numdFn(iPlug.asMObject());
588             numdFn.getData2Short(v2sVal[0], v2sVal[1]);
589 
590             oProp.set(&v2sVal[0]);
591         }
592         break;
593 
594         case MFnNumericData::k3Short:
595         {
596             MFnNumericData numdFn(iPlug.asMObject());
597             numdFn.getData3Short(v3sVal[0], v3sVal[1], v3sVal[2]);
598 
599             oProp.set(&v3sVal[0]);
600         }
601         break;
602 
603         case MFnNumericData::k2Int:
604         {
605             int val0, val1;
606             MFnNumericData numdFn(iPlug.asMObject());
607             numdFn.getData2Int(val0, val1);
608             v2iVal[0] = Alembic::Util::int32_t(val0);
609             v2iVal[1] = Alembic::Util::int32_t(val1);
610 
611             oProp.set(&v2iVal[0]);
612         }
613         break;
614 
615         case MFnNumericData::k3Int:
616         {
617             int val0, val1, val2;
618             MFnNumericData numdFn(iPlug.asMObject());
619             numdFn.getData3Int(val0, val1, val2);
620             v3iVal[0] = Alembic::Util::int32_t(val0);
621             v3iVal[1] = Alembic::Util::int32_t(val1);
622             v3iVal[2] = Alembic::Util::int32_t(val2);
623 
624             oProp.set(&v3iVal[0]);
625         }
626         break;
627 
628         case MFnNumericData::k2Float:
629         {
630             MFnNumericData numdFn(iPlug.asMObject());
631             numdFn.getData2Float(v2fVal[0], v2fVal[1]);
632 
633             oProp.set(&v2fVal[0]);
634         }
635         break;
636 
637         case MFnNumericData::k3Float:
638         {
639             MFnNumericData numdFn(iPlug.asMObject());
640             numdFn.getData3Float(v3fVal[0], v3fVal[1], v3fVal[2]);
641 
642             oProp.set(&v3fVal[0]);
643         }
644         break;
645 
646         case MFnNumericData::k2Double:
647         {
648             MFnNumericData numdFn(iPlug.asMObject());
649             numdFn.getData2Double(v2dVal[0], v3dVal[1]);
650 
651             oProp.set(&v2dVal[0]);
652         }
653         break;
654 
655         case MFnNumericData::k3Double:
656         {
657             MFnNumericData numdFn(iPlug.asMObject());
658             numdFn.getData3Double(v3dVal[0], v3dVal[1], v3dVal[2]);
659 
660             oProp.set(&v3dVal[0]);
661         }
662         break;
663 
664         default:
665             return false;
666         break;
667     }
668 
669     return true;
670 }
671 
MFnNumericDataToSample(MFnNumericData::Type iType,const MPlug & iPlug,Abc::OArrayProperty & oProp)672 bool MFnNumericDataToSample(MFnNumericData::Type iType,
673                             const MPlug& iPlug,
674                             Abc::OArrayProperty & oProp)
675 {
676     unsigned int numElements =  iPlug.numElements();
677     bool isArray = iPlug.isArray();
678 
679     unsigned int dimSize = numElements;
680     if (!isArray)
681         dimSize = 1;
682 
683     switch (iType)
684     {
685         case MFnNumericData::kBoolean:
686         {
687             std::vector< Alembic::Util::bool_t > val(dimSize);
688             if (!isArray)
689             {
690                 val[0] = iPlug.asBool();
691             }
692             else
693             {
694                 for (unsigned int i = 0; i < numElements; ++i)
695                 {
696                     val[i] = iPlug[i].asBool();
697                 }
698             }
699             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
700                 Alembic::Util::Dimensions(dimSize));
701             oProp.set(samp);
702         }
703         break;
704 
705         case MFnNumericData::kByte:
706         case MFnNumericData::kChar:
707         {
708             std::vector< Alembic::Util::int8_t > val(dimSize);
709             if (!isArray)
710             {
711                 val[0] = iPlug.asChar();
712             }
713             else
714             {
715                 for (unsigned int i = 0; i < numElements; ++i)
716                 {
717                     val[i] = iPlug[i].asChar();
718                 }
719             }
720             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
721                 Alembic::Util::Dimensions(dimSize));
722             oProp.set(samp);
723         }
724         break;
725 
726         case MFnNumericData::kShort:
727         {
728             std::vector< Alembic::Util::int16_t > val(dimSize);
729             if (!isArray)
730             {
731                 val[0] = iPlug.asShort();
732             }
733             else
734             {
735                 for (unsigned int i = 0; i < numElements; ++i)
736                 {
737                     val[i] = iPlug[i].asShort();
738                 }
739             }
740             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
741                 Alembic::Util::Dimensions(dimSize));
742             oProp.set(samp);
743         }
744         break;
745 
746         case MFnNumericData::kInt:
747         {
748             std::vector< Alembic::Util::int32_t > val(dimSize);
749             if (!isArray)
750             {
751                 val[0] = iPlug.asInt();
752             }
753             else
754             {
755                 for (unsigned int i = 0; i < numElements; ++i)
756                 {
757                     val[i] = iPlug[i].asInt();
758                 }
759             }
760             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
761                 Alembic::Util::Dimensions(dimSize));
762             oProp.set(samp);
763         }
764         break;
765 
766         case MFnNumericData::kFloat:
767         {
768             std::vector<float> val(dimSize);
769             if (!isArray)
770             {
771                 val[0] = iPlug.asFloat();
772             }
773             else
774             {
775                 for (unsigned int i = 0; i < numElements; ++i)
776                 {
777                     val[i] = iPlug[i].asFloat();
778                 }
779             }
780             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
781                 Alembic::Util::Dimensions(dimSize));
782             oProp.set(samp);
783         }
784         break;
785 
786         case MFnNumericData::kDouble:
787         {
788             std::vector<double> val(dimSize);
789             if (!isArray)
790             {
791                 val[0] = iPlug.asDouble();
792             }
793             else
794             {
795                 for (unsigned int i = 0; i < numElements; ++i)
796                 {
797                     val[i] = iPlug[i].asDouble();
798                 }
799             }
800             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
801                 Alembic::Util::Dimensions(dimSize));
802             oProp.set(samp);
803         }
804         break;
805 
806         case MFnNumericData::k2Short:
807         {
808             std::vector< Alembic::Util::int16_t > val(dimSize*2);
809             if (!isArray)
810             {
811                 MFnNumericData numdFn(iPlug.asMObject());
812                 numdFn.getData2Short(val[0], val[1]);
813             }
814             else
815             {
816                 for (unsigned int i = 0; i < numElements; ++i)
817                 {
818                     MFnNumericData numdFn(iPlug[i].asMObject());
819                     numdFn.getData2Short(val[2*i], val[2*i+1]);
820                 }
821             }
822             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
823                 Alembic::Util::Dimensions(dimSize));
824             oProp.set(samp);
825         }
826         break;
827 
828         case MFnNumericData::k3Short:
829         {
830             std::vector< Alembic::Util::int16_t > val(dimSize*3);
831             if (!isArray)
832             {
833                 MFnNumericData numdFn(iPlug.asMObject());
834                 numdFn.getData3Short(val[0], val[1], val[2]);
835             }
836             else
837             {
838                 for (unsigned int i = 0; i < numElements; ++i)
839                 {
840                     MFnNumericData numdFn(iPlug[i].asMObject());
841                     numdFn.getData3Short(val[3*i], val[3*i+1], val[3*i+2]);
842                 }
843             }
844             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
845                 Alembic::Util::Dimensions(dimSize));
846             oProp.set(samp);
847         }
848         break;
849 
850         case MFnNumericData::k2Int:
851         {
852             std::vector< Alembic::Util::int32_t > val(dimSize*2);
853             if (!isArray)
854             {
855                 int val0, val1;
856                 MFnNumericData numdFn(iPlug.asMObject());
857                 numdFn.getData2Int(val0, val1);
858                 val[0] = Alembic::Util::int32_t(val0);
859                 val[1] = Alembic::Util::int32_t(val1);
860             }
861             else
862             {
863                 for (unsigned int i = 0; i < numElements; ++i)
864                 {
865                     int val0, val1;
866                     MFnNumericData numdFn(iPlug[i].asMObject());
867                     numdFn.getData2Int(val0, val1);
868                     val[2*i] = Alembic::Util::int32_t(val0);
869                     val[2*i+1] = Alembic::Util::int32_t(val1);
870                 }
871             }
872             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
873                 Alembic::Util::Dimensions(dimSize));
874             oProp.set(samp);
875         }
876         break;
877 
878         case MFnNumericData::k3Int:
879         {
880             std::vector< Alembic::Util::int32_t > val(dimSize*3);
881             if (!isArray)
882             {
883                 int val0, val1, val2;
884                 MFnNumericData numdFn(iPlug.asMObject());
885                 numdFn.getData3Int(val0, val1, val2);
886                 val[0] = Alembic::Util::int32_t(val0);
887                 val[1] = Alembic::Util::int32_t(val1);
888                 val[2] = Alembic::Util::int32_t(val2);
889             }
890             else
891             {
892                 for (unsigned int i = 0; i < numElements; ++i)
893                 {
894                     int val0, val1, val2;
895                     MFnNumericData numdFn(iPlug[i].asMObject());
896                     numdFn.getData3Int(val0, val1, val2);
897                     val[3*i] = Alembic::Util::int32_t(val0);
898                     val[3*i+1] = Alembic::Util::int32_t(val1);
899                     val[3*i+2] = Alembic::Util::int32_t(val2);
900                 }
901             }
902             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
903                 Alembic::Util::Dimensions(dimSize));
904             oProp.set(samp);
905         }
906         break;
907 
908         case MFnNumericData::k2Float:
909         {
910             std::vector<float> val(dimSize*2);
911             if (!isArray)
912             {
913                 MFnNumericData numdFn(iPlug.asMObject());
914                 numdFn.getData2Float(val[0], val[1]);
915             }
916             else
917             {
918                 for (unsigned int i = 0; i < numElements; ++i)
919                 {
920                     MFnNumericData numdFn(iPlug[i].asMObject());
921                     numdFn.getData2Float(val[2*i], val[2*i+1]);
922                 }
923             }
924             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
925                 Alembic::Util::Dimensions(dimSize));
926             oProp.set(samp);
927         }
928         break;
929 
930         case MFnNumericData::k3Float:
931         {
932             std::vector<float> val(dimSize*3);
933             if (!isArray)
934             {
935                 MFnNumericData numdFn(iPlug.asMObject());
936                 numdFn.getData3Float(val[0], val[1], val[2]);
937             }
938             else
939             {
940                 for (unsigned int i = 0; i < numElements; ++i)
941                 {
942                     MFnNumericData numdFn(iPlug[i].asMObject());
943                     numdFn.getData3Float(val[3*i], val[3*i+1], val[3*i+2]);
944                 }
945             }
946             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
947                 Alembic::Util::Dimensions(dimSize));
948             oProp.set(samp);
949         }
950         break;
951 
952         case MFnNumericData::k2Double:
953         {
954             std::vector<double> val(dimSize*2);
955             if (!isArray)
956             {
957                 MFnNumericData numdFn(iPlug.asMObject());
958                 numdFn.getData2Double(val[0], val[1]);
959             }
960             else
961             {
962                 for (unsigned int i = 0; i < numElements; ++i)
963                 {
964                     MFnNumericData numdFn(iPlug[i].asMObject());
965                     numdFn.getData2Double(val[2*i], val[2*i+1]);
966                 }
967             }
968             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
969                 Alembic::Util::Dimensions(dimSize));
970             oProp.set(samp);
971         }
972         break;
973 
974         case MFnNumericData::k3Double:
975         {
976             std::vector<double> val(dimSize*3);
977             if (!isArray)
978             {
979                 MFnNumericData numdFn(iPlug.asMObject());
980                 numdFn.getData3Double(val[0], val[1], val[2]);
981             }
982             else
983             {
984                 for (unsigned int i = 0; i < numElements; ++i)
985                 {
986                     MFnNumericData numdFn(iPlug[i].asMObject());
987                     numdFn.getData3Double(val[3*i], val[3*i+1], val[3*i+2]);
988                 }
989             }
990             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
991                 Alembic::Util::Dimensions(dimSize));
992             oProp.set(samp);
993         }
994         break;
995 
996         case MFnNumericData::k4Double:
997         {
998             std::vector<double> val(dimSize*4);
999             if (!isArray)
1000             {
1001                 MFnNumericData numdFn(iPlug.asMObject());
1002                 numdFn.getData4Double(val[0], val[1], val[2], val[3]);
1003             }
1004             else
1005             {
1006                 for (unsigned int i = 0; i < numElements; ++i)
1007                 {
1008                     MFnNumericData numdFn(iPlug[i].asMObject());
1009                     numdFn.getData4Double(val[4*i], val[4*i+1], val[4*i+2],
1010                         val[4*i+3]);
1011                 }
1012             }
1013             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1014                 Alembic::Util::Dimensions(dimSize));
1015             oProp.set(samp);
1016         }
1017         break;
1018 
1019         default:
1020             return false;
1021         break;
1022     }
1023 
1024     return true;
1025 }
1026 
MFnTypedDataToSample(MFnData::Type iType,const MPlug & iPlug,Abc::OScalarProperty & oProp)1027 bool MFnTypedDataToSample(MFnData::Type iType,
1028                           const MPlug& iPlug,
1029                           Abc::OScalarProperty & oProp)
1030 {
1031     switch (iType)
1032     {
1033         case MFnData::kNumeric:
1034         {
1035             MFnNumericData numObj(iPlug.asMObject());
1036             return MFnNumericDataToSample(numObj.numericType(), iPlug,
1037                 oProp);
1038         }
1039         break;
1040 
1041         case MFnData::kString:
1042         {
1043             Abc::OStringProperty strProp( oProp.getPtr(), Abc::kWrapExisting );
1044             std::string val = iPlug.asString().asChar();
1045             strProp.set(val);
1046         }
1047         break;
1048 
1049         case MFnData::kMatrix:
1050         {
1051             MFnMatrixData arr(iPlug.asMObject());
1052             MMatrix mat = arr.matrix();
1053             double val[16];
1054 
1055             unsigned int i = 0;
1056             for (unsigned int r = 0; r < 4; r++)
1057             {
1058                 for (unsigned int c = 0; c < 4; c++, i++)
1059                 {
1060                     val[i] = mat[r][c];
1061                 }
1062             }
1063 
1064             oProp.set(&val);
1065         }
1066         break;
1067 
1068         default:
1069             return false;
1070         break;
1071     }
1072 
1073     return true;
1074 }
1075 
MFnTypedDataToSample(MFnData::Type iType,const MPlug & iPlug,Abc::OArrayProperty & oProp)1076 bool MFnTypedDataToSample(MFnData::Type iType,
1077                           const MPlug& iPlug,
1078                           Abc::OArrayProperty & oProp)
1079 {
1080     switch (iType)
1081     {
1082         case MFnData::kNumeric:
1083         {
1084             MFnNumericData numObj(iPlug.asMObject());
1085             return MFnNumericDataToSample(numObj.numericType(), iPlug,
1086                 oProp);
1087         }
1088         break;
1089 
1090         case MFnData::kString:
1091         {
1092             std::vector< std::string > val(1);
1093             val[0] = iPlug.asString().asChar();
1094             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1095                 Alembic::Util::Dimensions(1));
1096             oProp.set(samp);
1097         }
1098         break;
1099 
1100         case MFnData::kStringArray:
1101         {
1102             MFnStringArrayData arr(iPlug.asMObject());
1103 
1104             unsigned int length = arr.length();
1105             std::vector< std::string > val(length);
1106             for (unsigned int i = 0; i < length; i++)
1107             {
1108                 val[i] = arr[i].asChar();
1109             }
1110             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1111                 Alembic::Util::Dimensions(length));
1112             oProp.set(samp);
1113         }
1114         break;
1115 
1116         case MFnData::kDoubleArray:
1117         {
1118             MFnDoubleArrayData arr(iPlug.asMObject());
1119 
1120             unsigned int length = arr.length();
1121             std::vector< double > val(length);
1122             for (unsigned int i = 0; i < length; i++)
1123             {
1124                 val[i] = arr[i];
1125             }
1126             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1127                 Alembic::Util::Dimensions(length));
1128             oProp.set(samp);
1129         }
1130         break;
1131 
1132         case MFnData::kFloatArray:
1133         {
1134             MFnFloatArrayData arr(iPlug.asMObject());
1135 
1136             unsigned int length = arr.length();
1137             std::vector< float > val(length);
1138             for (unsigned int i = 0; i < length; i++)
1139             {
1140                 val[i] = arr[i];
1141             }
1142             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1143                 Alembic::Util::Dimensions(length));
1144             oProp.set(samp);
1145         }
1146         break;
1147 
1148         case MFnData::kIntArray:
1149         {
1150             MFnIntArrayData arr(iPlug.asMObject());
1151 
1152             unsigned int length = arr.length();
1153             std::vector< Alembic::Util::int32_t > val(length);
1154             for (unsigned int i = 0; i < length; i++)
1155             {
1156                 val[i] = arr[i];
1157             }
1158             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1159                 Alembic::Util::Dimensions(length));
1160             oProp.set(samp);
1161         }
1162         break;
1163 
1164         case MFnData::kPointArray:
1165         {
1166             MFnPointArrayData arr(iPlug.asMObject());
1167 
1168             unsigned int length = arr.length();
1169             unsigned int extent = oProp.getDataType().getExtent();
1170             std::vector< double > val(length*extent);
1171             for (unsigned int i = 0; i < length; i++)
1172             {
1173                 MPoint pt(arr[i]);
1174                 val[extent*i] = pt.x;
1175                 val[extent*i+1] = pt.y;
1176 
1177                 if (extent > 2)
1178                     val[extent*i+2] = pt.z;
1179 
1180                 if (extent > 3)
1181                     val[extent*i+3] = pt.w;
1182             }
1183             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1184                 Alembic::Util::Dimensions(length));
1185             oProp.set(samp);
1186         }
1187         break;
1188 
1189         case MFnData::kVectorArray:
1190         {
1191             MFnVectorArrayData arr(iPlug.asMObject());
1192 
1193             unsigned int length = arr.length();
1194             unsigned int extent = oProp.getDataType().getExtent();
1195             std::vector< double > val(length*extent);
1196             for (unsigned int i = 0; i < length; i++)
1197             {
1198                 MVector v(arr[i]);
1199                 val[extent*i] = v.x;
1200                 val[extent*i+1] = v.y;
1201 
1202                 if (extent > 2)
1203                    val[extent*i+2] = v.z;
1204             }
1205             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1206                 Alembic::Util::Dimensions(length));
1207             oProp.set(samp);
1208         }
1209         break;
1210 
1211         case MFnData::kMatrix:
1212         {
1213             MFnMatrixData arr(iPlug.asMObject());
1214             MMatrix mat = arr.matrix();
1215             std::vector<double> val(16);
1216 
1217             unsigned int i = 0;
1218             for (unsigned int r = 0; r < 4; r++)
1219             {
1220                 for (unsigned int c = 0; c < 4; c++, i++)
1221                 {
1222                     val[i] = mat[r][c];
1223                 }
1224             }
1225             AbcA::ArraySample samp(&(val.front()), oProp.getDataType(),
1226                 Alembic::Util::Dimensions(1));
1227             oProp.set(samp);
1228         }
1229         break;
1230 
1231         default:
1232             return false;
1233         break;
1234     }
1235 
1236     return true;
1237 }
1238 
attributeToScalarPropertyPair(const MObject & iAttr,const MPlug & iPlug,Abc::OScalarProperty & oProp)1239 bool attributeToScalarPropertyPair(const MObject& iAttr,
1240                                    const MPlug& iPlug,
1241                                    Abc::OScalarProperty & oProp)
1242 {
1243     if (iAttr.hasFn(MFn::kTypedAttribute))
1244     {
1245         MFnTypedAttribute typedAttr(iAttr);
1246         return MFnTypedDataToSample(typedAttr.attrType(), iPlug, oProp);
1247     }
1248     else if (iAttr.hasFn(MFn::kNumericAttribute))
1249     {
1250         MFnNumericAttribute numAttr(iAttr);
1251         return MFnNumericDataToSample(numAttr.unitType(), iPlug, oProp);
1252     }
1253     else if (iAttr.hasFn(MFn::kUnitAttribute))
1254     {
1255         double dval = iPlug.asDouble();
1256         oProp.set(&dval);
1257         return true;
1258     }
1259     else if (iAttr.hasFn(MFn::kEnumAttribute))
1260     {
1261         Alembic::Util::int16_t val = iPlug.asShort();
1262         oProp.set(&val);
1263         return true;
1264     }
1265 
1266     return false;
1267 }
1268 
1269 
attributeToArrayPropertyPair(const MObject & iAttr,const MPlug & iPlug,Abc::OArrayProperty & oProp)1270 bool attributeToArrayPropertyPair(const MObject& iAttr,
1271                                   const MPlug& iPlug,
1272                                   Abc::OArrayProperty & oProp)
1273 {
1274     if (iAttr.hasFn(MFn::kTypedAttribute))
1275     {
1276         MFnTypedAttribute typedAttr(iAttr);
1277         return MFnTypedDataToSample(typedAttr.attrType(), iPlug,
1278             oProp);
1279     }
1280     else if (iAttr.hasFn(MFn::kNumericAttribute))
1281     {
1282         MFnNumericAttribute numAttr(iAttr);
1283         return MFnNumericDataToSample(numAttr.unitType(), iPlug,
1284             oProp);
1285     }
1286     else if (iAttr.hasFn(MFn::kUnitAttribute))
1287     {
1288         double val = iPlug.asDouble();
1289         AbcA::ArraySample samp(&val, oProp.getDataType(),
1290             Alembic::Util::Dimensions(1));
1291         oProp.set(samp);
1292         return true;
1293     }
1294     else if (iAttr.hasFn(MFn::kEnumAttribute))
1295     {
1296         Alembic::Util::int16_t val = iPlug.asShort();
1297         AbcA::ArraySample samp(&val, oProp.getDataType(),
1298             Alembic::Util::Dimensions(1));
1299         oProp.set(samp);
1300         return true;
1301     }
1302 
1303     return false;
1304 }
1305 
createUserPropertyFromMFnAttr(const MObject & iAttr,const MPlug & iPlug,Abc::OCompoundProperty & iParent,Alembic::Util::uint32_t iTimeIndex,AbcGeom::GeometryScope iScope,const MString & iTypeStr,std::vector<PlugAndObjScalar> & oScalars,std::vector<PlugAndObjArray> & oArrays)1306 void createUserPropertyFromMFnAttr(const MObject& iAttr,
1307                                    const MPlug& iPlug,
1308                                    Abc::OCompoundProperty & iParent,
1309                                    Alembic::Util::uint32_t iTimeIndex,
1310                                    AbcGeom::GeometryScope iScope,
1311                                    const MString & iTypeStr,
1312                                    std::vector < PlugAndObjScalar > & oScalars,
1313                                    std::vector < PlugAndObjArray > & oArrays)
1314 {
1315     MStatus stat;
1316     std::string plugName = iPlug.partialName(0, 0, 0, 0, 0, 1).asChar();
1317 
1318     if (iAttr.hasFn(MFn::kNumericAttribute))
1319     {
1320         MFnNumericAttribute numFn(iAttr, &stat);
1321 
1322         if (!stat)
1323         {
1324             MString err = "Couldn't instantiate MFnNumericAttribute\n\tType: ";
1325             err += iAttr.apiTypeStr();
1326             MGlobal::displayError(err);
1327 
1328             return;
1329         }
1330 
1331         createUserPropertyFromNumeric(numFn.unitType(), iAttr, iPlug,
1332                                       iParent, iTimeIndex, iScope,
1333                                       oScalars, oArrays);
1334     }
1335     else if (iAttr.hasFn(MFn::kTypedAttribute))
1336     {
1337         MFnTypedAttribute typeFn(iAttr, &stat);
1338 
1339         if (!stat)
1340         {
1341             MString err = "Couldn't instantiate MFnTypedAttribute\n\tType: ";
1342             err += iAttr.apiTypeStr();
1343 
1344             MGlobal::displayError(err);
1345 
1346             return;
1347         }
1348 
1349         switch (typeFn.attrType())
1350         {
1351             case MFnData::kString:
1352             {
1353                 PlugAndObjScalar p;
1354                 p.plug = iPlug;
1355                 p.obj = iAttr;
1356                 p.prop = Abc::OStringProperty(iParent, plugName, iTimeIndex);
1357                 oScalars.push_back(p);
1358             }
1359             break;
1360 
1361             case MFnData::kStringArray:
1362             {
1363                 PlugAndObjArray p;
1364                 p.plug = iPlug;
1365                 p.obj = iAttr;
1366                 p.prop = Abc::OStringArrayProperty(iParent, plugName, iTimeIndex);
1367                 oArrays.push_back(p);
1368             }
1369             break;
1370 
1371             case MFnData::kDoubleArray:
1372             {
1373                 PlugAndObjArray p;
1374                 p.plug = iPlug;
1375                 p.obj = iAttr;
1376                 p.prop = Abc::ODoubleArrayProperty(iParent, plugName, iTimeIndex);
1377                 oArrays.push_back(p);
1378             }
1379             break;
1380 
1381             case MFnData::kFloatArray:
1382             {
1383                 PlugAndObjArray p;
1384                 p.plug = iPlug;
1385                 p.obj = iAttr;
1386                 p.prop = Abc::OFloatArrayProperty(iParent, plugName, iTimeIndex);
1387                 oArrays.push_back(p);
1388             }
1389             break;
1390 
1391             case MFnData::kIntArray:
1392             {
1393                 PlugAndObjArray p;
1394                 p.plug = iPlug;
1395                 p.obj = iAttr;
1396                 p.prop = Abc::OInt32ArrayProperty(iParent, plugName, iTimeIndex);
1397                 oArrays.push_back(p);
1398             }
1399             break;
1400 
1401             case MFnData::kPointArray:
1402             {
1403                 PlugAndObjArray p;
1404                 p.plug = iPlug;
1405                 p.obj = iAttr;
1406                 if (iTypeStr  == "point2")
1407                     p.prop = Abc::OP2dArrayProperty(iParent, plugName, iTimeIndex);
1408                 else
1409                     p.prop = Abc::OP3dArrayProperty(iParent, plugName, iTimeIndex);
1410 
1411                 oArrays.push_back(p);
1412             }
1413             break;
1414 
1415             case MFnData::kVectorArray:
1416             {
1417                 PlugAndObjArray p;
1418                 p.plug = iPlug;
1419                 p.obj = iAttr;
1420                 if (iTypeStr == "vector2")
1421                     p.prop = Abc::OV2dArrayProperty(iParent, plugName, iTimeIndex);
1422                 else if (iTypeStr == "normal2")
1423                     p.prop = Abc::ON2dArrayProperty(iParent, plugName, iTimeIndex);
1424                 else if (iTypeStr == "normal3")
1425                     p.prop = Abc::ON3dArrayProperty(iParent, plugName, iTimeIndex);
1426                 else
1427                     p.prop = Abc::OV3dArrayProperty(iParent, plugName, iTimeIndex);
1428 
1429                 oArrays.push_back(p);
1430             }
1431             break;
1432 
1433             case MFnData::kMatrix:
1434             {
1435                 PlugAndObjScalar p;
1436                 p.plug = iPlug;
1437                 p.obj = iAttr;
1438                 p.prop = Abc::OM44dProperty(iParent, plugName, iTimeIndex);
1439                 oScalars.push_back(p);
1440             }
1441             break;
1442 
1443             case MFnData::kNumeric:
1444             {
1445                 MFnNumericAttribute numAttr(iPlug.asMObject());
1446                 createUserPropertyFromNumeric(numAttr.unitType(), iAttr,
1447                     iPlug, iParent, iTimeIndex, iScope, oScalars, oArrays);
1448             }
1449             break;
1450 
1451             default:
1452             {
1453                 // get the full property name for the warning
1454                 MString msg = "WARNING: Couldn't convert ";
1455                 msg += iPlug.partialName(1, 0, 0, 0, 1, 1);
1456                 msg += " to a property, so skipping.";
1457                 MGlobal::displayWarning(msg);
1458             }
1459             break;
1460         }
1461     }
1462     else if (iAttr.hasFn(MFn::kUnitAttribute))
1463     {
1464         PlugAndObjScalar p;
1465         p.plug = iPlug;
1466         p.obj = iAttr;
1467         p.prop = Abc::ODoubleProperty(iParent, plugName, iTimeIndex);
1468         oScalars.push_back(p);
1469     }
1470     else if (iAttr.hasFn(MFn::kEnumAttribute))
1471     {
1472         PlugAndObjScalar p;
1473         p.plug = iPlug;
1474         p.obj = iAttr;
1475         p.prop = Abc::OInt16Property(iParent, plugName, iTimeIndex);
1476         oScalars.push_back(p);
1477     }
1478 }
1479 
createGeomPropertyFromMFnAttr(const MObject & iAttr,const MPlug & iPlug,Abc::OCompoundProperty & iParent,Alembic::Util::uint32_t iTimeIndex,AbcGeom::GeometryScope iScope,const MString & iTypeStr,std::vector<PlugAndObjArray> & oArrayVec)1480 void createGeomPropertyFromMFnAttr(const MObject& iAttr,
1481                                    const MPlug& iPlug,
1482                                    Abc::OCompoundProperty & iParent,
1483                                    Alembic::Util::uint32_t iTimeIndex,
1484                                    AbcGeom::GeometryScope iScope,
1485                                    const MString & iTypeStr,
1486                                    std::vector < PlugAndObjArray > & oArrayVec)
1487 {
1488     // for some reason we have just 1 of the elements of an array, bail
1489     if (iPlug.isElement())
1490         return;
1491 
1492     MStatus stat;
1493 
1494     std::string plugName = iPlug.partialName(0, 0, 0, 0, 0, 1).asChar();
1495 
1496     if (iAttr.hasFn(MFn::kNumericAttribute))
1497     {
1498         MFnNumericAttribute numFn(iAttr, &stat);
1499 
1500         if (!stat)
1501         {
1502             MString err = "Couldn't instantiate MFnNumericAttribute\n\tType: ";
1503             err += iAttr.apiTypeStr();
1504             MGlobal::displayError(err);
1505 
1506             return;
1507         }
1508 
1509         createGeomPropertyFromNumeric(numFn.unitType(), iAttr, iPlug, iParent,
1510             iTimeIndex, iScope, oArrayVec);
1511     }
1512     else if (iAttr.hasFn(MFn::kTypedAttribute))
1513     {
1514         MFnTypedAttribute typeFn(iAttr, &stat);
1515         if (!stat)
1516         {
1517             MString err = "Couldn't instantiate MFnTypedAttribute\n\tType: ";
1518             err += iAttr.apiTypeStr();
1519 
1520             MGlobal::displayError(err);
1521 
1522             return;
1523         }
1524 
1525         Alembic::AbcCoreAbstract::MetaData md;
1526         md.set("isArray", "1");
1527 
1528         switch (typeFn.attrType())
1529         {
1530             case MFnData::kString:
1531             {
1532                 PlugAndObjArray p;
1533                 p.plug = iPlug;
1534                 p.obj = iAttr;
1535                 AbcGeom::OStringGeomParam gp(iParent, plugName, false, iScope,
1536                     1, iTimeIndex);
1537                 p.prop = gp.getValueProperty();
1538                 oArrayVec.push_back(p);
1539             }
1540             break;
1541 
1542             case MFnData::kStringArray:
1543             {
1544                 PlugAndObjArray p;
1545                 p.plug = iPlug;
1546                 p.obj = iAttr;
1547                 AbcGeom::OStringGeomParam gp(iParent, plugName, false, iScope,
1548                     1, iTimeIndex, md);
1549                 p.prop = gp.getValueProperty();
1550                 oArrayVec.push_back(p);
1551             }
1552             break;
1553 
1554             case MFnData::kDoubleArray:
1555             {
1556                 PlugAndObjArray p;
1557                 p.plug = iPlug;
1558                 p.obj = iAttr;
1559                 AbcGeom::ODoubleGeomParam gp(iParent, plugName, false, iScope,
1560                     1, iTimeIndex, md);
1561                 p.prop = gp.getValueProperty();
1562                 oArrayVec.push_back(p);
1563             }
1564             break;
1565 
1566             case MFnData::kFloatArray:
1567             {
1568                 PlugAndObjArray p;
1569                 p.plug = iPlug;
1570                 p.obj = iAttr;
1571                 AbcGeom::OFloatGeomParam gp(iParent, plugName, false, iScope,
1572                     1, iTimeIndex, md);
1573                 p.prop = gp.getValueProperty();
1574                 oArrayVec.push_back(p);
1575             }
1576             break;
1577 
1578             case MFnData::kIntArray:
1579             {
1580                 PlugAndObjArray p;
1581                 p.plug = iPlug;
1582                 p.obj = iAttr;
1583                 AbcGeom::OInt32GeomParam gp(iParent, plugName, false, iScope,
1584                     1, iTimeIndex, md);
1585                 p.prop = gp.getValueProperty();
1586                 oArrayVec.push_back(p);
1587             }
1588             break;
1589 
1590             case MFnData::kPointArray:
1591             {
1592                 PlugAndObjArray p;
1593                 p.plug = iPlug;
1594                 p.obj = iAttr;
1595                 if (iTypeStr  == "point2")
1596                 {
1597                     AbcGeom::OP2dGeomParam gp(iParent, plugName, false, iScope,
1598                         1, iTimeIndex, md);
1599                     p.prop = gp.getValueProperty();
1600                 }
1601                 else
1602                 {
1603                     AbcGeom::OP3dGeomParam gp(iParent, plugName, false, iScope,
1604                         1, iTimeIndex);
1605                     p.prop = gp.getValueProperty();
1606                 }
1607                 oArrayVec.push_back(p);
1608             }
1609             break;
1610 
1611             case MFnData::kVectorArray:
1612             {
1613                 PlugAndObjArray p;
1614                 p.plug = iPlug;
1615                 p.obj = iAttr;
1616                 if (iTypeStr == "vector2")
1617                 {
1618                     AbcGeom::OV2dGeomParam gp(iParent, plugName, false, iScope,
1619                         1, iTimeIndex, md);
1620                     p.prop = gp.getValueProperty();
1621                 }
1622                 else if (iTypeStr == "normal2")
1623                 {
1624                     AbcGeom::ON2dGeomParam gp(iParent, plugName, false, iScope,
1625                         1, iTimeIndex, md);
1626                     p.prop = gp.getValueProperty();
1627                 }
1628                 else if (iTypeStr == "normal3")
1629                 {
1630                     AbcGeom::ON3dGeomParam gp(iParent, plugName, false, iScope,
1631                         1, iTimeIndex, md);
1632                     p.prop = gp.getValueProperty();
1633                 }
1634                 else
1635                 {
1636                     AbcGeom::OV3dGeomParam gp(iParent, plugName, false, iScope,
1637                         1, iTimeIndex, md);
1638                     p.prop = gp.getValueProperty();
1639                 }
1640                 oArrayVec.push_back(p);
1641             }
1642             break;
1643 
1644             case MFnData::kMatrix:
1645             {
1646                 PlugAndObjArray p;
1647                 p.plug = iPlug;
1648                 p.obj = iAttr;
1649                 AbcGeom::OM44dGeomParam gp(iParent, plugName, false, iScope, 1,
1650                     iTimeIndex);
1651                 p.prop = gp.getValueProperty();
1652                 oArrayVec.push_back(p);
1653             }
1654             break;
1655 
1656             case MFnData::kNumeric:
1657             {
1658                 MFnNumericAttribute numAttr(iPlug.asMObject());
1659                 createGeomPropertyFromNumeric(numAttr.unitType(), iAttr,
1660                     iPlug, iParent, iTimeIndex, iScope, oArrayVec);
1661             }
1662             break;
1663 
1664             default:
1665             {
1666                 // get the full property name for the warning
1667                 MString msg = "WARNING: Couldn't convert ";
1668                 msg += iPlug.partialName(1, 0, 0, 0, 1, 1);
1669                 msg += " to a property, so skipping.";
1670                 MGlobal::displayWarning(msg);
1671             }
1672             break;
1673         }
1674     }
1675     else if (iAttr.hasFn(MFn::kUnitAttribute))
1676     {
1677         PlugAndObjArray p;
1678         p.plug = iPlug;
1679         p.obj = iAttr;
1680         AbcGeom::ODoubleGeomParam gp(iParent, plugName, false, iScope, 1,
1681             iTimeIndex);
1682         p.prop = gp.getValueProperty();
1683         oArrayVec.push_back(p);
1684     }
1685     else if (iAttr.hasFn(MFn::kEnumAttribute))
1686     {
1687         PlugAndObjArray p;
1688         p.plug = iPlug;
1689         p.obj = iAttr;
1690         AbcGeom::OInt16GeomParam gp(iParent, plugName, false, iScope, 1,
1691             iTimeIndex);
1692         p.prop = gp.getValueProperty();
1693         oArrayVec.push_back(p);
1694     }
1695 }
1696 
1697 
isPerParticleAttributes(const MFnDependencyNode & iNode,MObject attrObj)1698 bool isPerParticleAttributes( const MFnDependencyNode &iNode, MObject attrObj )
1699 {
1700     MStatus status(MS::kSuccess);
1701 
1702     if ( !iNode.object().hasFn(MFn::kParticle))
1703     {
1704         return false;
1705     }
1706 
1707     if ( !attrObj.hasFn(MFn::kTypedAttribute))
1708     {
1709         return false;
1710     }
1711 
1712     MFnTypedAttribute attr( attrObj );
1713     MString attrName = attr.name();
1714 
1715     if (attrName == "radiusPP")
1716     {
1717         // radiusPP was handled as IPointGeom Width
1718         return false;
1719     }
1720 
1721     if ( attr.isHidden() ||
1722          !attr.isReadable() ||
1723          attr.isArray() ||
1724          attr.internal() )
1725     {
1726         return false;
1727     }
1728     if ( attr.attrType() != MFnData::kDoubleArray && attr.attrType() != MFnData::kVectorArray )
1729     {
1730         return false;
1731     }
1732 
1733     // Perform a few name filtering to avoid useless attribute
1734     // we only filter non user created attribute
1735     if ( !attr.isDynamic() )
1736     {
1737         // manualy filter a few attributes
1738         if (     attrName.substring(0, 7) == "internal" ||
1739                 attrName.toLowerCase().substring(attrName.length() - 5, attrName.length()) == "cache" ||
1740                 attrName.substring( attrName.length() - 1, attrName.length()) == "0" )
1741         {
1742             return false;
1743         }
1744 
1745     }
1746 
1747     MFnParticleSystem particle( iNode.object() );
1748 
1749     if ( particle.isPerParticleDoubleAttribute(attrName, &status) ||
1750          particle.isPerParticleVectorAttribute(attrName, &status)
1751     )
1752     {
1753         return true;
1754     }
1755 
1756 
1757     return false;
1758 }
1759 
1760 } // namespace
1761 
AttributesWriter(Alembic::Abc::OCompoundProperty & iArbGeom,Alembic::Abc::OCompoundProperty & iUserProps,Alembic::Abc::OObject & iParentObj,const MFnDependencyNode & iNode,Alembic::Util::uint32_t iTimeIndex,const JobArgs & iArgs,bool isShape)1762 AttributesWriter::AttributesWriter(
1763     Alembic::Abc::OCompoundProperty & iArbGeom,
1764     Alembic::Abc::OCompoundProperty & iUserProps,
1765     Alembic::Abc::OObject & iParentObj,
1766     const MFnDependencyNode & iNode,
1767     Alembic::Util::uint32_t iTimeIndex,
1768     const JobArgs & iArgs,
1769     bool isShape)
1770 {
1771     PlugAndObjScalar visPlug;
1772 
1773     unsigned int attrCount = iNode.attributeCount();
1774     unsigned int i;
1775 
1776     std::vector< PlugAndObjArray > staticPlugObjArrayVec;
1777     std::vector< PlugAndObjScalar > staticPlugObjScalarVec;
1778 
1779     for (i = 0; i < attrCount; i++)
1780     {
1781         MObject attr = iNode.attribute(i);
1782 
1783         MFnAttribute mfnAttr(attr);
1784         MPlug plug = iNode.findPlug(attr, true);
1785 
1786         // if it is not readable, then bail without any more checking
1787         if (!mfnAttr.isReadable() || plug.isNull())
1788         {
1789             continue;
1790         }
1791 
1792         MString propName = plug.partialName(0, 0, 0, 0, 0, 1);
1793 
1794         std::string propStr = propName.asChar();
1795 
1796         // we handle visibility in a special way
1797         if (propStr == "visibility")
1798         {
1799             if (iArgs.writeVisibility)
1800             {
1801                 visPlug.plug = plug;
1802                 visPlug.obj = attr;
1803             }
1804             continue;
1805         }
1806 
1807         bool userAttr = false;
1808         bool userPerParticleAttr = false;
1809 
1810         bool isPerParticle = isPerParticleAttributes(iNode, attr);
1811 
1812         if (!matchFilterOrAttribs(plug, iArgs, userAttr) && !isPerParticle)
1813             continue;
1814 
1815         // When someone set user attribute on a particleShape, we want to write it to arbGeom
1816         // This enable the attribute to be correctly considered as point cloud data
1817         if (userAttr && isPerParticle)
1818         {
1819             // The code will continue with the current attribute,  but will write it to arbGeom
1820             userAttr = false;
1821             userPerParticleAttr = true;
1822         }
1823 
1824         if (userAttr && !iUserProps.valid())
1825             continue;
1826         if (!userAttr && !iArbGeom.valid())
1827             continue;
1828 
1829         int sampType = util::getSampledType(plug) || isPerParticle; // Per particle is always animated
1830 
1831 
1832         MPlug scopePlug = iNode.findPlug(propName + cAttrScope, true);
1833         AbcGeom::GeometryScope scope = AbcGeom::kUnknownScope;
1834 
1835 
1836         if (isPerParticle) // PerParticle is always kVaryingScope
1837         {
1838             scope = AbcGeom::kVaryingScope;
1839         }
1840         else if (!scopePlug.isNull())
1841         {
1842             scope = strToScope(scopePlug.asString());
1843         }
1844         else if (userPerParticleAttr)
1845         {
1846             // We need to find the scope we will write
1847             // The attribute was not found to be a perParticle attribute, so it cannot be kVarying
1848             if (sampType == 0)
1849                 scope = AbcGeom::kConstantScope;
1850             else if (sampType == 1)
1851                 scope = AbcGeom::kUniformScope;
1852         }
1853 
1854         MString typeStr;
1855         MPlug typePlug = iNode.findPlug(propName + cAttrType, true);
1856         if (!typePlug.isNull())
1857         {
1858             typeStr= typePlug.asString();
1859         }
1860 
1861         if (userAttr)
1862         {
1863             switch (sampType)
1864             {
1865                 // static
1866                 case 0:
1867                 {
1868                     //
1869                     // Fills in the static plug to OScalarProperty OR
1870                     // OArrayProperty correspondence, used for the writing
1871                     // below.
1872                     //
1873                     createUserPropertyFromMFnAttr(attr, plug, iUserProps, 0,
1874                         scope, typeStr, staticPlugObjScalarVec,
1875                         staticPlugObjArrayVec);
1876                 }
1877                 break;
1878 
1879                 // sampled
1880                 case 1:
1881                 // curve treat like sampled
1882                 case 2:
1883                 {
1884                     //
1885                     // Fill in the mPlugUserPropertyVec, used for the writing
1886                     // below as well as in the write() method for animated
1887                     // values.
1888                     //
1889                     createUserPropertyFromMFnAttr(attr, plug, iUserProps,
1890                         iTimeIndex, scope, typeStr, mPlugObjScalarVec,
1891                         mPlugObjArrayVec);
1892                 }
1893                 break;
1894             }
1895         }
1896         else
1897         {
1898             switch (sampType)
1899             {
1900                 // static
1901                 case 0:
1902                 {
1903                     //
1904                     // Fills in the plug to OArrayProperty correspondence,
1905                     // used for the writing below.
1906                     //
1907                     createGeomPropertyFromMFnAttr(attr, plug, iArbGeom, 0,
1908                         scope, typeStr, staticPlugObjArrayVec);
1909                 }
1910                 break;
1911 
1912                 // sampled
1913                 case 1:
1914                 // curve treat like sampled
1915                 case 2:
1916                 {
1917                     //
1918                     // mPlugObjArrayVec
1919                     //
1920                     // member variable used by isAnimated and when sampling
1921                     // the animated data.
1922                     //
1923                     createGeomPropertyFromMFnAttr(attr, plug, iArbGeom,
1924                         iTimeIndex, scope, typeStr, mPlugObjArrayVec);
1925                 }
1926                 break;
1927             }
1928         }
1929     }
1930 
1931     // handle visibility
1932     if (!visPlug.plug.isNull())
1933     {
1934         int retVis = util::getVisibilityType(visPlug.plug);
1935 
1936         // visible will go on the top most compound
1937         Abc::OCompoundProperty parent = iParentObj.getProperties();
1938 
1939         switch (retVis)
1940         {
1941             // static visibility 0 case
1942             case 1:
1943             {
1944                 Alembic::Util::int8_t visVal =
1945                     Alembic::AbcGeom::kVisibilityHidden;
1946 
1947                 Abc::OCharProperty bp =
1948                     Alembic::AbcGeom::CreateVisibilityProperty(
1949                         iParentObj, 0);
1950                 bp.set(visVal);
1951             }
1952             break;
1953 
1954             // animated visibility 0 case
1955             case 2:
1956             {
1957                 Alembic::Util::int8_t visVal =
1958                     Alembic::AbcGeom::kVisibilityHidden;
1959 
1960                 Abc::OCharProperty bp =
1961                     Alembic::AbcGeom::CreateVisibilityProperty(
1962                         iParentObj, iTimeIndex);
1963 
1964                 bp.set(visVal);
1965                 visPlug.prop = bp;
1966                 mAnimVisibility = visPlug;
1967             }
1968             break;
1969 
1970             // animated visibility 1 case
1971             case 3:
1972             {
1973                 // dont add if we are forcing static (no frame range specified)
1974                 if (iTimeIndex == 0)
1975                 {
1976                     break;
1977                 }
1978 
1979                 mAnimVisibility = visPlug;
1980 
1981                 Alembic::Util::int8_t visVal =
1982                     Alembic::AbcGeom::kVisibilityDeferred;
1983 
1984                 Abc::OCharProperty bp =
1985                     Alembic::AbcGeom::CreateVisibilityProperty(
1986                         iParentObj, iTimeIndex);
1987 
1988                 bp.set(visVal);
1989                 visPlug.prop = bp;
1990                 mAnimVisibility = visPlug;
1991 
1992             }
1993             break;
1994 
1995             // dont write any visibility
1996             default:
1997             break;
1998         }
1999     }
2000 
2001     // write the static scalar props
2002     std::vector< PlugAndObjScalar >::iterator k =
2003         staticPlugObjScalarVec.begin();
2004     std::vector< PlugAndObjScalar >::iterator kend =
2005         staticPlugObjScalarVec.end();
2006 
2007     for (; k != kend; k++)
2008     {
2009         MString propName = k->plug.partialName(0, 0, 0, 0, 0, 1);
2010 
2011         //
2012         // attributeTo[Scalar|Array]PropertyPair does the writing.
2013         bool filledProp = attributeToScalarPropertyPair(k->obj, k->plug,
2014             k->prop);
2015 
2016         if (!filledProp)
2017         {
2018             MString msg = "WARNING: Couldn't get static scalar property ";
2019             msg += k->plug.partialName(1, 0, 0, 0, 1, 1);
2020             msg += ", so skipping.";
2021             MGlobal::displayWarning(msg);
2022             continue;
2023         }
2024     }
2025 
2026     // write the static array props
2027     std::vector< PlugAndObjArray >::iterator j =
2028         staticPlugObjArrayVec.begin();
2029     std::vector< PlugAndObjArray >::iterator jend =
2030         staticPlugObjArrayVec.end();
2031 
2032     for (; j != jend; j++)
2033     {
2034         MString propName = j->plug.partialName(0, 0, 0, 0, 0, 1);
2035         bool filledProp = attributeToArrayPropertyPair(j->obj, j->plug,
2036             j->prop);
2037 
2038         if (!filledProp)
2039         {
2040             MString msg = "WARNING: Couldn't get static array property ";
2041             msg += j->plug.partialName(1, 0, 0, 0, 1, 1);
2042             msg += ", so skipping.";
2043             MGlobal::displayWarning(msg);
2044             continue;
2045         }
2046     }
2047 
2048     // we shouldn't set the animated channels so bail
2049     if (isShape && !iArgs.setFirstAnimShape)
2050     {
2051         return;
2052     }
2053 
2054     // write the animated userProperties
2055     k = mPlugObjScalarVec.begin();
2056     kend = mPlugObjScalarVec.end();
2057 
2058     for (; k != kend; ++k)
2059     {
2060         MString propName = k->plug.partialName(0, 0, 0, 0, 0, 1);
2061 
2062         bool filledProp = attributeToScalarPropertyPair(k->obj, k->plug,
2063             k->prop);
2064 
2065         if (!filledProp)
2066         {
2067             MString msg = "WARNING: Couldn't get scalar property ";
2068             msg += k->plug.partialName(1, 0, 0, 0, 1, 1);
2069             msg += ", so skipping.";
2070             MGlobal::displayWarning(msg);
2071             continue;
2072         }
2073     }
2074 
2075     // write the animated arbGeomProps if appropriate
2076     j = mPlugObjArrayVec.begin();
2077     jend = mPlugObjArrayVec.end();
2078 
2079     for (; j != jend; j++)
2080     {
2081         MString propName = j->plug.partialName(0, 0, 0, 0, 0, 1);
2082         bool filledProp = attributeToArrayPropertyPair(j->obj, j->plug,j->prop);
2083 
2084         if (!filledProp)
2085         {
2086             MString msg = "WARNING: Couldn't get array property ";
2087             msg += j->plug.partialName(1, 0, 0, 0, 1, 1);
2088             msg += ", so skipping.";
2089             MGlobal::displayWarning(msg);
2090             continue;
2091         }
2092     }
2093 
2094 }
2095 
2096 //
2097 // Returns true if the attribute is:
2098 //
2099 // * Included by name via a -a or -u argument
2100 // * Matches by name via a -atp or -uatp argument
2101 //
2102 // If it's matched via -u or -uatp, userAttrOut is set to true.
2103 // These are intended to go in the .userProperties bucket on the
2104 // object.
2105 //
matchFilterOrAttribs(const MPlug & iPlug,const JobArgs & iArgs,bool & userAttrOut)2106 bool AttributesWriter::matchFilterOrAttribs(const MPlug & iPlug,
2107                                             const JobArgs & iArgs,
2108                                             bool& userAttrOut)
2109 {
2110 
2111     MString propName = iPlug.partialName(0, 0, 0, 0, 0, 1);
2112     std::string name = propName.asChar();
2113 
2114     if (name.find("[") != std::string::npos)
2115     {
2116         return false;
2117     }
2118 
2119     // For .arbGeomParam bucket
2120     std::vector<std::string>::const_iterator f;
2121     std::vector<std::string>::const_iterator fEnd =
2122         iArgs.prefixFilters.end();
2123     for (f = iArgs.prefixFilters.begin(); f != fEnd; ++f)
2124     {
2125         // check the prefilter and ignore those that match but end with
2126         // arb attr
2127         if (f->length() > 0 &&
2128             name.compare(0, f->length(), *f) == 0 &&
2129             !endsWithArbAttr(name) &&
2130             ( !iPlug.isChild() || !isDataAttr(iPlug.parent()) ))
2131         {
2132             userAttrOut = false;
2133             return true;
2134         }
2135     }
2136 
2137     //
2138     // For .userProperties bucket
2139     std::vector<std::string>::const_iterator it;
2140     std::vector<std::string>::const_iterator itEnd =
2141         iArgs.userPrefixFilters.end();
2142     for (it = iArgs.userPrefixFilters.begin(); it != itEnd; ++it)
2143     {
2144         // check the userprefilter and ignore those that match but end with
2145         // arb attr
2146         if (it->length() > 0 &&
2147             name.compare(0, it->length(), *it) == 0 &&
2148             !endsWithArbAttr(name) &&
2149             ( !iPlug.isChild() || !isDataAttr(iPlug.parent()) ))
2150         {
2151             userAttrOut = true;
2152             return true;
2153         }
2154     }
2155 
2156     // check our specific list of attributes
2157     if (iArgs.attribs.find(name) != iArgs.attribs.end())
2158     {
2159         userAttrOut = false;
2160         return true;
2161     }
2162 
2163     if (iArgs.userAttribs.find(name) != iArgs.userAttribs.end())
2164     {
2165         userAttrOut = true;
2166         return true;
2167     }
2168 
2169     return false;
2170 }
2171 
hasAnyAttr(const MFnDependencyNode & iNode,const JobArgs & iArgs)2172 bool AttributesWriter::hasAnyAttr(const MFnDependencyNode & iNode,
2173                                   const JobArgs & iArgs)
2174 {
2175     unsigned int attrCount = iNode.attributeCount();
2176     unsigned int i;
2177 
2178     std::vector< PlugAndObjArray > staticPlugObjArrayVec;
2179 
2180     if (iNode.object().hasFn(MFn::kParticle))
2181     {
2182         // Particles always have extra attributes
2183         return true;
2184     }
2185 
2186     bool userAttr;
2187     for (i = 0; i < attrCount; i++)
2188     {
2189         MObject attr = iNode.attribute(i);
2190         MFnAttribute mfnAttr(attr);
2191         MPlug plug = iNode.findPlug(attr, true);
2192 
2193         // if it is not readable, then bail without any more checking
2194         if (!mfnAttr.isReadable() || plug.isNull())
2195         {
2196             continue;
2197         }
2198 
2199         if (matchFilterOrAttribs(plug, iArgs, userAttr))
2200         {
2201             return true;
2202         }
2203     }
2204 
2205     return false;
2206 }
2207 
~AttributesWriter()2208 AttributesWriter::~AttributesWriter()
2209 {
2210 }
2211 
isAnimated()2212 bool AttributesWriter::isAnimated()
2213 {
2214     return !mPlugObjArrayVec.empty() || !mAnimVisibility.plug.isNull() ||
2215            !mPlugObjScalarVec.empty();
2216 }
2217 
write()2218 void AttributesWriter::write()
2219 {
2220 
2221     std::vector< PlugAndObjArray >::iterator j =
2222         mPlugObjArrayVec.begin();
2223     std::vector< PlugAndObjArray >::iterator jend =
2224         mPlugObjArrayVec.end();
2225 
2226     for (; j != jend; j++)
2227     {
2228         MString propName = j->plug.partialName(0, 0, 0, 0, 0, 1);
2229         bool filledProp = attributeToArrayPropertyPair(j->obj, j->plug, j->prop);
2230 
2231         if (!filledProp)
2232         {
2233             MString msg = "WARNING: Couldn't get sampled array property ";
2234             msg += j->plug.partialName(1, 0, 0, 0, 1, 1);
2235             msg += ", so skipping.";
2236             MGlobal::displayWarning(msg);
2237             continue;
2238         }
2239     }
2240 
2241     std::vector< PlugAndObjScalar >::iterator k =
2242         mPlugObjScalarVec.begin();
2243     std::vector< PlugAndObjScalar >::iterator kend =
2244         mPlugObjScalarVec.end();
2245 
2246     for (; k != kend; ++k)
2247     {
2248         MString propName = k->plug.partialName(0, 0, 0, 0, 0, 1);
2249 
2250         bool filledProp = attributeToScalarPropertyPair(k->obj, k->plug,
2251             k->prop);
2252 
2253         if (!filledProp)
2254         {
2255             MString msg = "WARNING: Couldn't get sampled scalar property ";
2256             msg += k->plug.partialName(1, 0, 0, 0, 1, 1);
2257             msg += ", so skipping.";
2258             MGlobal::displayWarning(msg);
2259             continue;
2260         }
2261     }
2262 
2263     if (!mAnimVisibility.plug.isNull())
2264     {
2265         Alembic::Util::int8_t visVal = -1;
2266         if (!mAnimVisibility.plug.asBool())
2267         {
2268             visVal = 0;
2269         }
2270 
2271         mAnimVisibility.prop.set(&visVal);
2272     }
2273 
2274 }
2275 
2276 
2277