void readEmptyCompoundProperties(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 2, "Wrong number of children (expected 2)"); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names for (int ii=0; ii<numChildren; ii++) { IObject child( archiveTop, archiveTop.getChildHeader(ii).getName() ); std::cout << " " << child.getName(); std::cout << " has " << child.getNumChildren() << " children" << std::endl; // Properties ICompoundProperty props = child.getProperties(); int numProperties = props.getNumProperties(); std::cout << " ..and " << numProperties << " properties" << std::endl; std::vector<std::string> propNames; for (int pp=0; pp<numProperties; pp++) propNames.push_back( props.getPropertyHeader(pp).getName() ); for (int jj=0; jj<numProperties; jj++) { std::cout << " ..named " << propNames[jj] << std::endl; std::cout << " ..with type: "; PropertyType pType = props.getPropertyHeader(jj).getPropertyType(); if (pType == kCompoundProperty) { std::cout << "compound" << std::endl; } else if (pType == kScalarProperty) { std::cout << "scalar" << std::endl; } else if (pType == kArrayProperty) { std::cout << "array" << std::endl; } } } // Done - the archive closes itself }
void readDeepHierarchy(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const unsigned int numChildren = archiveTop.getNumChildren(); std::cout << "The archive has " << numChildren << " children:" << std::endl; ABCA_ASSERT( numChildren == 2, "Expected 2 children, found " << numChildren ); // Iterate through them, print out their names for (unsigned int ii=0; ii<numChildren; ii++) { IObject child( archiveTop, archiveTop.getChildHeader(ii).getName() ); std::cout << " " << child.getName(); recursivelyReadChildren( child ); } // do it again to make sure we clean up after ourselves properly IArchive archive2 = factory.getArchive(archiveName, coreType); IObject archiveTop2 = archive2.getTop(); // Done - the archive closes itself }
//-***************************************************************************** void simpleTestIn( const std::string &iArchiveName ) { AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(iArchiveName, coreType); IObject archiveTop = archive.getTop(); TESTING_ASSERT( archiveTop.getNumChildren() == ( size_t )NUM_TOP_CHILDREN ); for ( int i = 0 ; i < NUM_TOP_CHILDREN ; i++ ) { std::ostringstream strm; strm << i; std::string cname = strm.str(); IObject obj( archiveTop, cname ); readDeepHierarchy( obj, 0, obj ); } TESTING_ASSERT( PATHS.size() == ( size_t ) NUM_TOP_CHILDREN ); }
void readFlatHierarchy(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 10, "Expected 10 children, found " << numChildren ); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names for (int ii=0; ii<numChildren; ii++) { IObject child( archiveTop, archiveTop.getChildHeader(ii).getName() ); std::cout << " " << child.getName(); const unsigned int children = child.getNumChildren(); std::cout << " has " << children << " children" << std::endl; ABCA_ASSERT( children == 0, "Expected no children, found " << children ); } // Done - the archive closes itself }
void readSimpleProperties(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const int numChildren = archiveTop.getNumChildren(); TESTING_ASSERT( numChildren == 4 ); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names for (int ii=0; ii<numChildren; ii++) { IObject child( archiveTop, archiveTop.getChildHeader( ii ).getName() ); std::cout << " " << child.getName(); std::cout << " has " << child.getNumChildren() << " children" << std::endl; // Properties ICompoundProperty props = child.getProperties(); int numProperties = props.getNumProperties(); std::cout << " ..and " << numProperties << " simple properties" << std::endl; std::vector<std::string> propNames; for (int pp=0; pp<numProperties; pp++) propNames.push_back( props.getPropertyHeader(pp).getName() ); for (int jj=0; jj<numProperties; jj++) { std::cout << " ..named " << propNames[jj] << std::endl; std::cout << " ..with type: "; PropertyType pType = props.getPropertyHeader(jj).getPropertyType(); if (pType == kCompoundProperty) { std::cout << "compound" << std::endl; } else if (pType == kScalarProperty) { std::cout << "scalar" << std::endl; } else if (pType == kArrayProperty) { std::cout << "array" << std::endl; } DataType dType = props.getPropertyHeader(jj).getDataType(); std::cout << " ..with POD-type: "; switch (dType.getPod()) { case kBooleanPOD: std::cout << "boolean" << std::endl; break; // Char/UChar case kUint8POD: std::cout << "unsigned char" << std::endl; break; case kInt8POD: std::cout << "char" << std::endl; break; // Short/UShort case kUint16POD: std::cout << "short unsigned int" << std::endl; break; case kInt16POD: std::cout << "short int" << std::endl; break; // Int/UInt case kUint32POD: std::cout << "unsigned int" << std::endl; break; case kInt32POD: std::cout << "int" << std::endl; break; // Long/ULong case kUint64POD: std::cout << "unsigned long int" << std::endl; break; case kInt64POD: std::cout << "long int" << std::endl; break; // Half/Float/Double case kFloat16POD: std::cout << "half" << std::endl; break; case kFloat32POD: std::cout << "float" << std::endl; break; case kFloat64POD: std::cout << "double" << std::endl; break; case kStringPOD: std::cout << "string" << std::endl; break; case kUnknownPOD: default: std::cout << " Unknown! (this is bad)" << std::endl; }; TimeSamplingPtr ts = GetCompoundPropertyReaderPtr(props)-> getScalarProperty( propNames[jj] )->getTimeSampling(); int numSamples = ts->getNumStoredTimes(); std::cout << " ..and " << ts->getTimeSamplingType() << std::endl << " ..and " << numSamples << " samples at times: "; if (numSamples > 0) { std::cout << " ( "; for (int ss=0; ss<numSamples; ss++) std::cout << ts->getSampleTime(ss) << " "; std::cout << ")"; } std::cout << std::endl; std::cout << " ..and values: "; if (numSamples > 0) { for (int ss=0; ss<numSamples; ss++) { ISampleSelector iss( (index_t) ss); switch (dType.getPod()) { // Boolean case kBooleanPOD: { IBoolProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Char/UChar case kUint8POD: { IUcharProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt8POD: { ICharProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Short/UShort case kUint16POD: { IUInt16Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt16POD: { IInt16Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Int/UInt case kUint32POD: { IUInt32Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt32POD: { IInt32Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Long/ULong case kUint64POD: { IUInt64Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kInt64POD: { IInt64Property prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } // Half/Float/Double case kFloat16POD: // iostream doesn't understand float_16's //printSampleValue( IHalfProperty( props, propNames[jj] ), // iss ); break; case kFloat32POD: { IFloatProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kFloat64POD: { IDoubleProperty prop( props, propNames[jj] ); printSampleValue( prop, iss ); break; } case kUnknownPOD: default: std::cout << " Unknown! (this is bad)" << std::endl; }; } } std::cout << std::endl; std::cout << std::endl; // done parsing property } } // Done - the archive closes itself }
void errorHandlerTest(bool useOgawa) { { OArchive archive; if (useOgawa) { archive = OArchive( Alembic::AbcCoreOgawa::WriteArchive(), "throwTest.abc", ErrorHandler::kThrowPolicy ); } else { archive = OArchive( Alembic::AbcCoreHDF5::WriteArchive(), "throwTest.abc", ErrorHandler::kThrowPolicy ); } OObject archiveTop = archive.getTop(); ABCA_ASSERT( archiveTop.getErrorHandler().getPolicy() == ErrorHandler::kThrowPolicy, "Error: Not kThrowPolicy" ); OObject childQuiet(archiveTop, "childQuiet", ErrorHandler::kQuietNoopPolicy ); OObject childNoisy(archiveTop, "childNoisy", ErrorHandler::kNoisyNoopPolicy ); OObject grandchildQuiet(childQuiet, "grandchildQuiet" ); OObject grandchildNoisy(childNoisy, "grandchildNoisy" ); ABCA_ASSERT( childQuiet.getErrorHandler().getPolicy() == ErrorHandler::kQuietNoopPolicy, "Error: Not kQuietNoopPolicy" ); ABCA_ASSERT( childNoisy.getErrorHandler().getPolicy() == ErrorHandler::kNoisyNoopPolicy, "Error: Not kNoisyNoopPolicy" ); ABCA_ASSERT( grandchildQuiet.getErrorHandler().getPolicy() == ErrorHandler::kQuietNoopPolicy, "Error: Not kQuietNoopPolicy" ); ABCA_ASSERT( grandchildNoisy.getErrorHandler().getPolicy() == ErrorHandler::kNoisyNoopPolicy, "Error: Not kNoisyNoopPolicy" ); } { AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive("throwTest.abc", coreType); IObject archiveTop = archive.getTop(); ABCA_ASSERT( archiveTop.getErrorHandler().getPolicy() == ErrorHandler::kThrowPolicy, "Error: Not kThrowPolicy" ); IObject childQuiet(archiveTop, "childQuiet", ErrorHandler::kQuietNoopPolicy ); IObject childNoisy(archiveTop, "childNoisy", ErrorHandler::kNoisyNoopPolicy ); IObject grandchildQuiet(childQuiet, "grandchildQuiet" ); IObject grandchildNoisy(childNoisy, "grandchildNoisy" ); ABCA_ASSERT( childQuiet.getErrorHandler().getPolicy() == ErrorHandler::kQuietNoopPolicy, "Error: Not kQuietNoopPolicy" ); ABCA_ASSERT( childNoisy.getErrorHandler().getPolicy() == ErrorHandler::kNoisyNoopPolicy, "Error: Not kNoisyNoopPolicy" ); ABCA_ASSERT( grandchildQuiet.getErrorHandler().getPolicy() == ErrorHandler::kQuietNoopPolicy, "Error: Not kQuietNoopPolicy" ); ABCA_ASSERT( grandchildNoisy.getErrorHandler().getPolicy() == ErrorHandler::kNoisyNoopPolicy, "Error: Not kNoisyNoopPolicy" ); } }
//-***************************************************************************** //-***************************************************************************** // DO IT. //-***************************************************************************** //-***************************************************************************** int main( int argc, char *argv[] ) { if (argc < 4) { std::cerr << "USAGE: " << argv[0] << " outFile.abc inFile1.abc" << " inFile2.abc (inFile3.abc ...)" << std::endl; return -1; } { size_t numInputs = argc - 2; std::vector< chrono_t > minVec; minVec.reserve(numInputs); std::vector< IArchive > iArchives; iArchives.reserve(numInputs); std::map< chrono_t, size_t > minIndexMap; size_t rootChildren = 0; Alembic::AbcCoreFactory::IFactory factory; factory.setPolicy(ErrorHandler::kThrowPolicy); Alembic::AbcCoreFactory::IFactory::CoreType coreType; for (int i = 2; i < argc; ++i) { IArchive archive = factory.getArchive(argv[i], coreType); if (!archive.valid() || archive.getTop().getNumChildren() < 1) { std::cerr << "ERROR: " << argv[i] << " not a valid Alembic file" << std::endl; return 1; } IObject iRoot = archive.getTop(); size_t numChildren = iRoot.getNumChildren(); if (i == 2) { rootChildren = numChildren; } else if (rootChildren != numChildren) { std::cerr << "ERROR: " << argv[i] << " doesn't have the same number of children as: " << argv[i-1] << std::endl; } // reorder the input files according to their mins chrono_t min = DBL_MAX; Alembic::Util::uint32_t numSamplings = archive.getNumTimeSamplings(); if (numSamplings > 1) { // timesampling index 0 is special, so it will be skipped // // make sure all the other timesampling objects start at // the same time or throw here // min = archive.getTimeSampling(1)->getSampleTime(0); for (Alembic::Util::uint32_t s = 2; s < numSamplings; ++s) { chrono_t thisMin = archive.getTimeSampling(s)->getSampleTime(0); if (fabs(thisMin - min) > 1e-5) { std::cerr << "ERROR: " << argv[i] << " has non-default TimeSampling objects" << " that don't start at the same time." << std::endl; return 1; } } minVec.push_back(min); if (minIndexMap.count(min) == 0) { minIndexMap.insert(std::make_pair(min, i-2)); } else if (argv[2] != argv[i]) { std::cerr << "ERROR: overlapping frame range between " << argv[2] << " and " << argv[i] << std::endl; return 1; } } else { std::cerr << "ERROR: " << archive.getName() << " only has default (static) TimeSampling." << std::endl; return 1; } iArchives.push_back(archive); } // now reorder the input nodes so they are in increasing order of their // min values in the frame range std::sort(minVec.begin(), minVec.end()); std::vector< IArchive > iOrderedArchives; iOrderedArchives.reserve(numInputs); for (size_t f = 0; f < numInputs; ++f) { size_t index = minIndexMap.find(minVec[f])->second; iOrderedArchives.push_back(iArchives[index]); } std::string appWriter = "AbcStitcher"; std::string fileName = argv[1]; std::string userStr; // Create an archive with the default writer OArchive oArchive; if (coreType == Alembic::AbcCoreFactory::IFactory::kHDF5) { oArchive = CreateArchiveWithInfo( Alembic::AbcCoreHDF5::WriteArchive(), fileName, appWriter, userStr, ErrorHandler::kThrowPolicy); } else if (coreType == Alembic::AbcCoreFactory::IFactory::kOgawa) { oArchive = CreateArchiveWithInfo( Alembic::AbcCoreOgawa::WriteArchive(), fileName, appWriter, userStr, ErrorHandler::kThrowPolicy); } OObject oRoot = oArchive.getTop(); if (!oRoot.valid()) return -1; std::vector<IObject> iRoots; iRoots.resize(numInputs); for (size_t f = 0; f < rootChildren; ++f) { for (size_t g = 0; g < numInputs; ++g) { iRoots[g] = iOrderedArchives[g].getTop().getChild(f); } visitObjects(iRoots, oRoot); } // collect the top level compound property ICompoundPropertyVec iCompoundProps; iCompoundProps.reserve(numInputs); for (size_t f = 0; f < numInputs; ++f) { iCompoundProps.push_back(iRoots[f].getParent().getProperties()); } OCompoundProperty oCompoundProperty = oRoot.getProperties(); stitchCompoundProp(iCompoundProps, oCompoundProperty); } return 0; }
//-***************************************************************************** int main( int argc, char *argv[] ) { //float opt_fps = 24.0; bool opt_all = false; // show all option bool opt_long = false; // long listing option bool opt_meta = false; // metadata option bool opt_recursive = false; // recursive option bool opt_size = false; // array sample size option bool opt_time = false; // time info option bool opt_values = false; // show all 0th values int index = -1; // sample number, at tail of path std::string desc( "abcls [OPTION] FILE[/NAME] \n" " -a include property listings\n" " -f show time sampling as 24 fps\n" " -h, --help show this help message\n" " -l long listing format\n" " -m show archive metadata\n" " -r list entries recursively\n" " -s show the size of a data property sample\n" " -t show time sampling information\n" " -v show 0th value for all properties\n" ); /* sigaction if available */ #if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 199506L) // seg fault handler struct sigaction act; sigemptyset(&act.sa_mask); act.sa_handler = segfault_sigaction; act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); /* signal if available */ #elif defined(_POSIX_VERSION) || defined(_MSC_VER) signal(SIGSEGV, segfault_sigaction); #else #error No signal interface available #endif //_POSIX_VERSION // check for min args if ( argc < 2 ) { std::cout << desc << std::endl; return 0; }; // parse args std::vector<std::string> arguments(argv, argv + argc); std::vector<std::string> options; std::vector<std::string> files; // separate file args from option args for ( std::size_t i = 1; i < arguments.size(); i++ ) { if ( arguments[ i ].substr( 0, 1 ) == "-" ) options.push_back( arguments[ i ] ); else files.push_back( arguments[ i ] ); } // help if ( argc < 2 || optionExists( options, "h" ) || optionExists( options, "help" ) ) { std::cout << desc << std::endl; return 0; }; // set some flags double fps = 1.0; opt_all = optionExists( options, "a" ); opt_long = optionExists( options, "l" ); opt_meta = optionExists( options, "m" ); opt_recursive = optionExists( options, "r" ); opt_size = optionExists( options, "s" ); opt_time = optionExists( options, "t" ); opt_values = optionExists( options, "v" ); if ( optionExists( options, "f" ) ) { fps = 24.0; opt_time = true; } // open each file for ( std::size_t i = 0; i < files.size(); i++ ) { if ( files.size() > 1 ) std::cout << BOLD << files[i] << ':' << RESETCOLOR << std::endl; std::stringstream ss( files[i] ); std::stringstream fp; std::string segment; std::vector<std::string> seglist; /* * separate file and object paths, e.g. * * ../dir1/foo.abc/bar/baz/index * \_____________/\______/\____/ * file obj sample */ int j = 0; while ( std::getline( ss, segment, '/' ) ) { if ( !isFile ( fp.str() ) ) { if ( j != 0 ) fp << "/"; fp << segment; } else { seglist.push_back( segment ); } ++j; } bool lastIsIndex = false; if (!seglist.empty() && is_digit( seglist.back() ) ) { index = atoi( seglist.back().c_str() ); lastIsIndex = true; } // open the iarchive Abc::IArchive archive; AbcF::IFactory factory; factory.setPolicy(Abc::ErrorHandler::kQuietNoopPolicy); AbcF::IFactory::CoreType coreType; archive = factory.getArchive(std::string( fp.str() ), coreType); // display file metadata if ( opt_meta && seglist.size() == 0 ) { std::cout << "Using " << Alembic::AbcCoreAbstract::GetLibraryVersion() << std::endl;; std::string appName; std::string libraryVersionString; Alembic::Util::uint32_t libraryVersion; std::string whenWritten; std::string userDescription; std::string coreName; GetArchiveInfo (archive, appName, libraryVersionString, libraryVersion, whenWritten, userDescription); if ( coreType == AbcF::IFactory::kOgawa ) { coreName = "Ogawa"; } else if ( coreType == AbcF::IFactory::kHDF5 ) { coreName = "HDF5"; } else { coreName = "Unknown"; }; if ( appName != "" ) { std::cout << " file written by: " << appName << std::endl; std::cout << " using Alembic : " << libraryVersionString << std::endl; std::cout << " written on : " << whenWritten << std::endl; std::cout << " user description : " << userDescription << std::endl; } else { std::cout << " (file doesn't have any ArchiveInfo)" << std::endl; } std::cout << " core type : " << coreName << std::endl; }; if ( opt_time && seglist.size() == 0 ) { uint32_t numTimes = archive.getNumTimeSamplings(); std::cout << std::endl << "Time Samplings: " << std::endl; for ( uint32_t k = 0; k < numTimes; ++k ) { AbcA::TimeSamplingPtr ts = archive.getTimeSampling( k ); index_t maxSample = archive.getMaxNumSamplesForTimeSamplingIndex( k ); std::cout << k << " "; printTimeSampling( ts, maxSample, fps ); } std::cout << std::endl; } // walk object hierarchy and find valid objects AbcG::IObject test = archive.getTop(); AbcG::IObject iObj = test; while ( test.valid() && seglist.size() > 0 ) { test = test.getChild( seglist.front() ); if ( test.valid() ) { iObj = test; seglist.erase( seglist.begin() ); } } // walk property hierarchy for most recent object Abc::ICompoundProperty props = iObj.getProperties(); const Abc::PropertyHeader* header; bool found = false; bool shouldPrintValue = false; for ( std::size_t i = 0; i < seglist.size(); ++i ) { header = props.getPropertyHeader( seglist[i] ); if ( header && header->isCompound() ) { Abc::ICompoundProperty ptest( props, header->getName() ); if ( ptest.valid() ) { props = ptest; found = true; } } else if ( header && header->isSimple() ) { found = true; // if the last value happens to be an index, and we are a // property then dont bother checking the last item in seglist if (lastIsIndex && i == seglist.size() - 2) { shouldPrintValue = true; break; } } else { std::cout << seglist[i] << ": Invalid object or property" << std::endl; return 1; } } // do stuff if ( shouldPrintValue ) { printValue( props, *header, index, opt_size, opt_time, fps ); } else { if ( found && header->isCompound() ) visit( props, opt_all, opt_long, opt_meta, opt_recursive, true, opt_values ); else if ( found && header->isSimple() ) printChild( props, *header, opt_all, opt_long, opt_values ); else visit( iObj, opt_all, opt_long, opt_meta, opt_recursive, true, opt_values ); std::cout << RESETCOLOR; if ( !opt_long ) std::cout << std::endl; } } return 0; }
//-***************************************************************************** void simpleTestIn( const std::string& iArchiveName ) { AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive( iArchiveName, coreType ); /* x1 / | \ x2 x3 x2a (x2a is an instance targeting x2) | | x4 x5 (x5 is an instance targeting x4) / | g1 g2 | g5 */ // an archive has a single top object which contains all its children IObject topObject = archive.getTop(); IObject x1( topObject, "x1" ); TESTING_ASSERT( x1 != 0 ); // // Verify the target path IObject x2( x1, "x2" ); TESTING_ASSERT( x2.valid() ); TESTING_ASSERT( !x2.isInstanceDescendant() ); IObject x4( x2, "x4" ); TESTING_ASSERT( x4.valid() ); TESTING_ASSERT( !x4.isInstanceDescendant() ); int numChildren = x4.getNumChildren(); TESTING_ASSERT( numChildren == 2 ); TESTING_ASSERT( x4.getParent().getFullName() == x2.getFullName() ); IObject g1( x4.getChild(0) ); TESTING_ASSERT( g1 != 0 ); TESTING_ASSERT( g1.getName() == "g1" ); TESTING_ASSERT( !g1.isInstanceDescendant() ); TESTING_ASSERT( g1.getParent() != 0 ); TESTING_ASSERT( g1.getParent().getFullName() == x4.getFullName() ); IObject g2( x4.getChild(1) ); TESTING_ASSERT( g2 != 0 ); TESTING_ASSERT( g2.getName() == "g2" ); TESTING_ASSERT( !g2.isInstanceDescendant() ); TESTING_ASSERT( g2.getParent() != 0 ); TESTING_ASSERT( g2.getParent().getFullName() == x4.getFullName() ); IObject g5( g2.getChild(0) ); TESTING_ASSERT( g5 != 0 ); TESTING_ASSERT( g5.getName() == "g5" ); TESTING_ASSERT( !g5.isInstanceDescendant() ); TESTING_ASSERT( g5.getParent() != 0 ); TESTING_ASSERT( g5.getParent().getFullName() == g2.getFullName() ); // // Verify the instance path IObject x3( x1, "x3" ); TESTING_ASSERT( x3 != 0 ); IObject x5( x3, "x5" ); TESTING_ASSERT( x5 != 0 ); TESTING_ASSERT( x5.isInstanceDescendant() ); TESTING_ASSERT( x5.isInstanceRoot() ); TESTING_ASSERT( x5.instanceSourcePath() == x4.getFullName() ); numChildren = x5.getNumChildren(); TESTING_ASSERT( numChildren == 2 ); TESTING_ASSERT( x5.getParent().getFullName() == x3.getFullName() ); IObject g1p( x5.getChild(0) ); TESTING_ASSERT( g1p != 0 ); TESTING_ASSERT( g1p.getName() == "g1" ); TESTING_ASSERT( g1p.isInstanceDescendant() ); TESTING_ASSERT( !g1p.isInstanceRoot() ); TESTING_ASSERT( g1p.getParent() != 0 ); TESTING_ASSERT( g1p.getParent().getFullName() == x5.getFullName() ); IObject g2p( x5.getChild(1) ); TESTING_ASSERT( g2p != 0 ); TESTING_ASSERT( g2p.getName() == "g2" ); TESTING_ASSERT( g2p.isInstanceDescendant() ); TESTING_ASSERT( !g2p.isInstanceRoot() ); TESTING_ASSERT( g2p.getParent() != 0 ); TESTING_ASSERT( g2p.getParent().getFullName() == x5.getFullName() ); IObject g5p( g2p.getChild(0) ); TESTING_ASSERT( g5p != 0 ); TESTING_ASSERT( g5p.getName() == "g5" ); TESTING_ASSERT( g5p.isInstanceDescendant() ); TESTING_ASSERT( !g5p.isInstanceRoot() ); TESTING_ASSERT( g5p.getParent() != 0 ); TESTING_ASSERT( g5p.getParent().getFullName() == g2p.getFullName() ); // test x2a IObject x2a( x1, "x2a" ); TESTING_ASSERT( x2a.valid() ); TESTING_ASSERT( x2a.isInstanceDescendant() ); TESTING_ASSERT( x2a.isInstanceRoot() ); TESTING_ASSERT( x2a.instanceSourcePath() == x2.getFullName() ); TESTING_ASSERT( x2a.getNumChildren() == 1 ); IObject x2aParent = x2a.getParent(); TESTING_ASSERT( x2aParent.getFullName() == "/x1" ); TESTING_ASSERT( !x2aParent.isInstanceDescendant() ); }
//-***************************************************************************** void simpleTestIn( const std::string &iArchiveName, bool useOgawa) { AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(iArchiveName, coreType); TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5) ); IObject archiveTop = archive.getTop(); IObject ac0( archiveTop, "ac0" ); IObject acc0( ac0, "acc0" ); IObject ac1( archiveTop, "ac1" ); IInt32ArrayProperty ac1iap0( ac1.getProperties(), "iap0" ); const AbcA::PropertyHeader * iap0Header = ac1.getProperties().getPropertyHeader( "iap0" ); TESTING_ASSERT( IInt32ArrayProperty::matches( *iap0Header ) ); TESTING_ASSERT( OInt32ArrayProperty::matches( *iap0Header ) ); TESTING_ASSERT( ! IFloatArrayProperty::matches( *iap0Header ) ); TESTING_ASSERT( ! IV3fArrayProperty::matches( *iap0Header ) ); ISampleSelector ac1iap0iss; AbcA::index_t sampIdx = ac1iap0iss.getIndex( ac1iap0.getTimeSampling(), ac1iap0.getNumSamples() ); std::cout << "sampIdx: " << sampIdx << std::endl; // an object contains a single compound property that contains all // sub-properties; all property access is through that. ICompoundProperty ac0Props = ac0.getProperties(); ICompoundProperty acc0Props = acc0.getProperties(); TESTING_ASSERT( ac0.getNumChildren() == 1 ); TESTING_ASSERT( ac0Props.getNumProperties() == 4 ); TESTING_ASSERT( acc0.getNumChildren() == 0 ); TESTING_ASSERT( acc0Props.getNumProperties() == 6 ); std::cout << "ac0 has " << ac0.getNumChildren() << " children and " << ac0Props.getNumProperties() << " properties." << std::endl; std::cout << "acc0 has " << acc0.getNumChildren() << " children and " << acc0Props.getNumProperties() << " properties." << std::endl; for ( size_t i = 0 ; i < acc0Props.getNumProperties() ; ++i ) { std::cout << "acc0.getPropertyHeader( " << i << " ).getName(): " << acc0Props.getPropertyHeader( i ).getName() << std::endl; } ICompoundProperty acc0CProp0( acc0Props, "acc0CProp0" ); IInt32Property acc0cp0ip0( acc0CProp0, "acc0cp0ip0" ); IInt32Property acc0cp0ip1( acc0CProp0, "acc0cp0ip1" ); int acc0cp0ip0val = acc0cp0ip0.getValue(); int acc0cp0ip1val = acc0cp0ip1.getValue(); TESTING_ASSERT( acc0cp0ip0val == 0 ); TESTING_ASSERT( acc0cp0ip1val == 1 ); std::cout << "acc0cp0ip0 is " << acc0cp0ip0val << std::endl; std::cout << "acc0cp0ip1 is " << acc0cp0ip1val << std::endl; IV3fProperty ac0V3fp0( ac0Props, "ac0V3fp0", kStrictMatching ); IN3fProperty ac0N3fp0( ac0Props, "ac0N3fp0", kStrictMatching ); IP3fProperty ac0P3fp0( ac0Props, "ac0P3fp0", kStrictMatching ); // we expect this to throw when doing strict matching TESTING_ASSERT_THROW ( IP3fProperty( ac0Props, "ac0N3fp0", kStrictMatching ), Alembic::Util::Exception ); IInt32Property acc0ip0( acc0Props, "acc0ip0" ); IBoolProperty acc0bp0( acc0Props, "acc0bp0" ); TESTING_ASSERT( ! acc0bp0.getValue() ); std::cout << "bool scalar property acc0bp0 is false! Huzzah!" << std::endl; TESTING_ASSERT( acc0ip0.getValue() == 99 ); TESTING_ASSERT( ac0V3fp0.getValue() == scalarV3fval ); TESTING_ASSERT( ac0N3fp0.getValue() == scalarV3fval ); TESTING_ASSERT( ac0P3fp0.getValue() == scalarV3fval ); std::cout << "acc0ip0 is " << acc0ip0.getValue() << std::endl; std::cout << "ac0V3fp0 is " << ac0V3fp0.getValue() << std::endl; IV3fArrayProperty acc0V3fap0( acc0Props, "acc0V3fap0", kStrictMatching ); const AbcA::PropertyHeader * acc0V3fap0Header = acc0Props.getPropertyHeader( "acc0V3fap0" ); TESTING_ASSERT( OV3fArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( IV3fArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( ! OFloatArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( ! IFloatArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( ! IInt32ArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( ! IP3fArrayProperty::matches( *acc0V3fap0Header ) ); TESTING_ASSERT( ! IV3fProperty::matches( *acc0V3fap0Header ) ); V3fArraySamplePtr acc0V3fap0SampPtr; IP3fArrayProperty acc0P3fap0( acc0Props, "acc0P3fap0", kStrictMatching ); const AbcA::PropertyHeader * acc0P3fap0Header = acc0Props.getPropertyHeader( "acc0P3fap0" ); TESTING_ASSERT( OP3fArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( IP3fArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( ! OFloatArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( ! IFloatArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( ! IInt32ArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( ! IV3fArrayProperty::matches( *acc0P3fap0Header ) ); TESTING_ASSERT( ! IP3fProperty::matches( *acc0P3fap0Header ) ); P3fArraySamplePtr acc0P3fap0SampPtr; IN3fArrayProperty acc0N3fap0( acc0Props, "acc0N3fap0", kStrictMatching ); const AbcA::PropertyHeader * acc0N3fap0Header = acc0Props.getPropertyHeader( "acc0N3fap0" ); TESTING_ASSERT( ON3fArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( IN3fArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( ! OFloatArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( ! IFloatArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( ! IInt32ArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( ! IV3fArrayProperty::matches( *acc0N3fap0Header ) ); TESTING_ASSERT( ! IP3fProperty::matches( *acc0N3fap0Header ) ); N3fArraySamplePtr acc0N3fap0SampPtr; TESTING_ASSERT_THROW ( IP3fProperty( ac0Props, "acc0V3fap0", kStrictMatching ), Alembic::Util::Exception ); IInt32ArrayProperty ac0iap0( ac0Props, "ac0iap0" ); Int32ArraySamplePtr ac0iap0SampPtr; const size_t numReadV3fSamps = acc0V3fap0.getNumSamples(); const size_t numReadN3fSamps = acc0N3fap0.getNumSamples(); const size_t numReadP3fSamps = acc0P3fap0.getNumSamples(); const size_t numReadIntSamps = ac0iap0.getNumSamples(); TESTING_ASSERT( numReadIntSamps == numIntSamps ); TESTING_ASSERT( numReadV3fSamps == numV3fSamps ); TESTING_ASSERT( numReadN3fSamps == numV3fSamps ); TESTING_ASSERT( numReadP3fSamps == numV3fSamps ); std::cout << "acc0V3fap0 has " << numReadV3fSamps << " samples." << std::endl; std::cout << "ac0iap0 has " << numReadIntSamps << " samples." << std::endl; // first the V3f array property for ( size_t i = 0 ; i < numV3fSamps ; ++i ) { acc0V3fap0.get( acc0V3fap0SampPtr, i ); acc0N3fap0.get( acc0N3fap0SampPtr, i ); acc0P3fap0.get( acc0P3fap0SampPtr, i ); size_t numPoints = acc0V3fap0SampPtr->size(); chrono_t time = acc0V3fap0.getTimeSampling()->getSampleTime( i ); chrono_t compTime = v3fStartTime + ( i * dt ); TESTING_ASSERT( numPoints == numV3fPoints ); TESTING_ASSERT( numPoints == acc0N3fap0SampPtr->size() ); TESTING_ASSERT( numPoints == acc0P3fap0SampPtr->size() ); TESTING_ASSERT( Imath::equalWithAbsError( time, compTime, CHRONO_EPSILON ) ); float32_t elementVal = i + time; TESTING_ASSERT( (*acc0V3fap0SampPtr)[0][0] == elementVal ); TESTING_ASSERT( (*acc0N3fap0SampPtr)[0][0] == elementVal ); TESTING_ASSERT( (*acc0P3fap0SampPtr)[0][0] == elementVal ); std::cout << "acc0V3fap0 at sample " << i << " is at time " << time << " and has " << numPoints << " points " << " with the values:" << std::endl; for ( size_t j = 0 ; j < numPoints ; ++j ) { std::cout << (*acc0V3fap0SampPtr)[j] << ", "; } std::cout << std::endl << std::endl; } // now the int array property for ( size_t i = 0 ; i < numIntSamps ; ++i ) { ac0iap0.get( ac0iap0SampPtr, i ); size_t numPoints = ac0iap0SampPtr->size(); chrono_t time = ac0iap0.getTimeSampling()->getSampleTime( i ); chrono_t compTime = intStartTime + ( i * dt ); TESTING_ASSERT( Imath::equalWithAbsError( time, compTime, CHRONO_EPSILON ) ); TESTING_ASSERT( numPoints == numIntPoints ); std::cout << "ac0iap0 at sample " << i << " is at time " << time << " and has " << numPoints << " points" << " with the values:" << std::endl; for ( size_t j = 0 ; j < numPoints ; ++j ) { Alembic::Util::int32_t val = (*ac0iap0SampPtr)[j]; TESTING_ASSERT( val == ( Alembic::Util::int32_t ) ( i + j ) ); std::cout << val << ", "; } std::cout << std::endl << std::endl; } }
void readProperty(const std::string &archiveName) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. std::cout << "Reading " << archiveName << std::endl; AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const unsigned int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 3)"); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names IObject child( archiveTop, archiveTop.getChildHeader(0).getName() ); std::cout << " " << child.getName(); // Properties ICompoundProperty props = child.getProperties(); size_t numProperties = props.getNumProperties(); // only top-level props ABCA_ASSERT( numProperties == 1, "Expected 1 property, found " << numProperties); std::cout << " has a simple property"; std::vector<std::string> propNames(1); propNames[0] = props.getPropertyHeader(0).getName(); std::cout << " named " << propNames[0] << std::endl; PropertyType pType = props.getPropertyHeader(0).getPropertyType(); ABCA_ASSERT( pType == kScalarProperty, "Expected a scalar property, but didn't find one" ); DataType dType = props.getPropertyHeader(0).getDataType(); ABCA_ASSERT( dType.getPod() == kFloat64POD, "Expected a double (kFloat64POD) property, but didn't" " find one" ); // We know this is a scalar property (I'm eliding the if/else // statements required to recognize this) IDoubleProperty mass( props, propNames[0] ); size_t numSamples = mass.getNumSamples(); std::cout << ".. it has " << numSamples << " samples" << std::endl; ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples ); std::cout << "..with values: "; for (unsigned int ss=0; ss<numSamples; ss++) { ISampleSelector iss( (index_t) ss); printSampleValue( mass, iss ); double massDiff = mass.getValue( iss ) - (33.0 + 0.1*ss); ABCA_ASSERT( fabs(massDiff) < 1e-12, "Incorrect sample value read" ); } std::cout << std::endl; // Done - the archive closes itself }
void emptyAndValueTest(const std::string &archiveName, bool useOgawa) { std::vector<std::string> strVec; strVec.push_back( "potato" ); std::vector<C3f> colorVec; colorVec.push_back( C3f( 0.0, 0.5, 0.75 ) ); std::vector<Alembic::Util::int32_t> intVec; intVec.push_back(42); StringArraySample strSamp( strVec ); C3fArraySample colorSamp( colorVec ); Int32ArraySample intSamp( intVec ); StringArraySample emptyStrSamp = StringArraySample::emptySample(); C3fArraySample emptyColorSamp = C3fArraySample::emptySample(); Int32ArraySample emptyIntSamp = Int32ArraySample::emptySample(); { OArchive archive; if (useOgawa) { archive = OArchive( Alembic::AbcCoreOgawa::WriteArchive(), archiveName ); } else { archive = OArchive( Alembic::AbcCoreHDF5::WriteArchive(), archiveName ); } OCompoundProperty root = archive.getTop().getProperties(); OC3fArrayProperty colorProp( root, "colors" ); OInt32ArrayProperty numProp( root, "numbers" ); AbcA::MetaData md; SetReference( md ); OStringArrayProperty strProp( root, "strings", md ); TESTING_ASSERT( isReference( strProp.getHeader() ) ); colorProp.set( emptyColorSamp ); colorProp.set( colorSamp ); colorProp.set( emptyColorSamp ); colorProp.set( colorSamp ); numProp.set( emptyIntSamp ); numProp.set( intSamp ); numProp.set( emptyIntSamp ); numProp.set( intSamp ); strProp.set( emptyStrSamp ); strProp.set( strSamp ); strProp.set( emptyStrSamp ); strProp.set( strSamp ); } { StringArraySamplePtr strSampPtr; C3fArraySamplePtr colorSampPtr; Int32ArraySamplePtr intSampPtr; AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5) ); ICompoundProperty root = archive.getTop().getProperties(); IC3fArrayProperty colorProp( root, "colors" ); IInt32ArrayProperty numProp( root, "numbers" ); IStringArrayProperty strProp( root, "strings" ); TESTING_ASSERT( isReference( strProp.getHeader() ) ); TESTING_ASSERT( colorProp.getNumSamples() == 4 ); TESTING_ASSERT( strProp.getNumSamples() == 4 ); TESTING_ASSERT( numProp.getNumSamples() == 4 ); colorProp.get( colorSampPtr, 0 ); strProp.get( strSampPtr, 0 ); numProp.get( intSampPtr, 0 ); TESTING_ASSERT( colorSampPtr->size() == 0 ); TESTING_ASSERT( strSampPtr->size() == 0 ); TESTING_ASSERT( intSampPtr->size() == 0 ); colorProp.get( colorSampPtr, 2 ); strProp.get( strSampPtr, 2 ); numProp.get( intSampPtr, 2 ); TESTING_ASSERT( colorSampPtr->size() == 0 ); TESTING_ASSERT( strSampPtr->size() == 0 ); TESTING_ASSERT( intSampPtr->size() == 0 ); colorProp.get( colorSampPtr, 1 ); strProp.get( strSampPtr, 1 ); numProp.get( intSampPtr, 1 ); TESTING_ASSERT( colorSampPtr->size() == 1 && colorSamp[0] == ( *colorSampPtr )[0] ); TESTING_ASSERT( strSampPtr->size() == 1 && strSamp[0] == ( *strSampPtr )[0] ); TESTING_ASSERT( intSampPtr->size() == 1 && intSamp[0] == ( *intSampPtr )[0] ); colorProp.get( colorSampPtr, 3 ); strProp.get( strSampPtr, 3 ); numProp.get( intSampPtr, 3 ); TESTING_ASSERT( colorSampPtr->size() == 1 && colorSamp[0] == ( *colorSampPtr )[0] ); TESTING_ASSERT( strSampPtr->size() == 1 && strSamp[0] == ( *strSampPtr )[0] ); TESTING_ASSERT( intSampPtr->size() == 1 && intSamp[0] == ( *intSampPtr )[0] ); } }
void readWriteColorArrayProperty(const std::string &archiveName, bool useOgawa) { { OArchive archive; if (useOgawa) { archive = OArchive( Alembic::AbcCoreOgawa::WriteArchive(), archiveName, ErrorHandler::kThrowPolicy ); } else { archive = OArchive( Alembic::AbcCoreHDF5::WriteArchive(), archiveName, ErrorHandler::kThrowPolicy ); } OObject archiveTop = archive.getTop(); OObject child( archiveTop, "test" ); OCompoundProperty childProps = child.getProperties(); OC3fArrayProperty shades( childProps, "shades", 0 ); std::vector < C3f > grays(8); grays[0].x = 0.0; grays[0].y = 0.0; grays[0].z = 0.0; grays[1].x = 0.125; grays[1].y = 0.125; grays[1].z = 0.125; grays[2].x = 0.25; grays[2].y = 0.25; grays[2].z = 0.25; grays[3].x = 0.375; grays[3].y = 0.375; grays[3].z = 0.375; grays[4].x = 0.5; grays[4].y = 0.5; grays[4].z = 0.5; grays[5].x = 0.625; grays[5].y = 0.625; grays[5].z = 0.625; grays[6].x = 0.75; grays[6].y = 0.75; grays[6].z = 0.75; grays[7].x = 0.875; grays[7].y = 0.875; grays[7].z = 0.875; // let's write 4 different color3f[2] Dimensions d; d.setRank(2); d[0] = 2; d[1] = 4; C3fArraySample cas(&(grays.front()), d); shades.set(cas); } { // now read it AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5) ); IObject archiveTop = archive.getTop(); IObject child( archiveTop, archiveTop.getChildHeader(0).getName() ); ICompoundProperty props = child.getProperties(); IC3fArrayProperty shades( props, "shades" ); C3fArraySamplePtr samplePtr; shades.get( samplePtr ); ABCA_ASSERT( samplePtr->getDimensions().rank() == 2, "Incorrect rank on the sample." ); ABCA_ASSERT( samplePtr->getDimensions().numPoints() == 8, "Incorrect number of total points." ); ABCA_ASSERT( samplePtr->getDimensions()[0] == 2, "Incorrect size on dimension 0." ); ABCA_ASSERT( samplePtr->getDimensions()[1] == 4, "Incorrect size on dimension 1." ); Alembic::Util::Dimensions dims; shades.getDimensions( dims ); ABCA_ASSERT( dims.rank() == 2, "Incorrect rank on the sample." ); ABCA_ASSERT( dims.numPoints() == 8, "Incorrect number of total points." ); ABCA_ASSERT( dims[0] == 2, "Incorrect size on dimension 0." ); ABCA_ASSERT( dims[1] == 4, "Incorrect size on dimension 1." ); for (size_t i = 0; i < 8; ++i) { ABCA_ASSERT( (*samplePtr)[i].x == i/8.0 && (*samplePtr)[i].x == (*samplePtr)[i].y && (*samplePtr)[i].x == (*samplePtr)[i].z, "Color [" << i << "] is incorrect."); } double start, end; GetArchiveStartAndEndTime( archive, start, end ); TESTING_ASSERT( almostEqual(start, 0.0) ); TESTING_ASSERT( almostEqual(end, 0.0) ); } }
void readV3fArrayProperty(const std::string &archiveName, bool useOgawa) { // Open an existing archive for reading. Indicate that we want // Alembic to throw exceptions on errors. std::cout << "Reading " << archiveName << std::endl; AbcF::IFactory factory; factory.setPolicy( ErrorHandler::kThrowPolicy ); AbcF::IFactory::CoreType coreType; IArchive archive = factory.getArchive(archiveName, coreType); TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) || (!useOgawa && coreType == AbcF::IFactory::kHDF5) ); IObject archiveTop = archive.getTop(); // Determine the number of (top level) children the archive has const unsigned int numChildren = archiveTop.getNumChildren(); ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 1)"); std::cout << "The archive has " << numChildren << " children:" << std::endl; // Iterate through them, print out their names IObject child( archiveTop, archiveTop.getChildHeader(0).getName() ); std::cout << " named '" << child.getName() << "'"; // Properties ICompoundProperty props = child.getProperties(); size_t numProperties = props.getNumProperties(); // only top-level props ABCA_ASSERT( numProperties == 1, "Expected 1 property, found " << numProperties); std::cout << " with one property"; std::vector<std::string> propNames(1); propNames[0] = props.getPropertyHeader(0).getName(); std::cout << " named '" << propNames[0] << "'" << std::endl; PropertyType pType = props.getPropertyHeader(0).getPropertyType(); ABCA_ASSERT( pType == kArrayProperty, "Expected an array property, but didn't find one" ); std::cout << " which is an array property"; DataType dType = props.getPropertyHeader(0).getDataType(); ABCA_ASSERT( dType.getPod() == kFloat32POD, "Expected an v3f property, but didn't find one" ); // We know this is an array property (I'm eliding the if/else // statements required to recognize and handle this properly) IV3fArrayProperty positions( props, propNames[0] ); size_t numSamples = positions.getNumSamples(); std::cout << ".. it has " << numSamples << " samples" << std::endl; ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples ); TimeSamplingPtr ts = positions.getTimeSampling(); std::cout << "..with time/value pairs: " << std::endl;; for (unsigned int ss=0; ss<numSamples; ss++) { std::cout << " "; ISampleSelector iss( (index_t) ss); std::cout << ts->getSampleTime( (index_t) ss ) << " / "; V3fArraySamplePtr samplePtr; positions.get( samplePtr, iss ); std::cout << "[ "; size_t numPoints = samplePtr->size(); for ( size_t jj=0 ; jj<numPoints ; jj++ ) std::cout << (*samplePtr)[jj] << " "; std::cout << "]" << std::endl; if (ss == 2) // no entries in sample #2 { ABCA_ASSERT( numPoints == 0, "Expected an empty sample, but found " << numPoints << " entries." ); } else { for ( size_t jj=0 ; jj<numPoints ; jj++ ) ABCA_ASSERT( (*samplePtr)[jj] == g_vectors[jj], "Incorrect value read from archive." ); } } ABCA_ASSERT( archive.getMaxNumSamplesForTimeSamplingIndex(1) == (index_t) numSamples, "Incorrect number of max samples in readV3fArrayProperty." ); std::cout << std::endl; // Done - the archive closes itself double start, end; GetArchiveStartAndEndTime( archive, start, end ); TESTING_ASSERT( almostEqual(start, 123.0) ); TESTING_ASSERT( almostEqual(end, 123.0 + 4.0 / 24.0) ); }
MStatus AlembicNode::compute(const MPlug & plug, MDataBlock & dataBlock) { MStatus status; // update the frame number to be imported MDataHandle speedHandle = dataBlock.inputValue(mSpeedAttr, &status); double speed = speedHandle.asDouble(); MDataHandle offsetHandle = dataBlock.inputValue(mOffsetAttr, &status); double offset = offsetHandle.asDouble(); MDataHandle timeHandle = dataBlock.inputValue(mTimeAttr, &status); MTime t = timeHandle.asTime(); double inputTime = t.as(MTime::kSeconds); double fps = getFPS(); // scale and offset inputTime. inputTime = computeAdjustedTime(inputTime, speed, offset/fps); // this should be done only once per file if (mFileInitialized == false) { mFileInitialized = true; //Get list of input filenames MFnDependencyNode depNode(thisMObject()); MPlug layerFilesPlug = depNode.findPlug("abc_layerFiles"); MFnStringArrayData fnSAD( layerFilesPlug.asMObject() ); MStringArray storedFilenames = fnSAD.array(); //Legacy support for single-filename input if( storedFilenames.length() == 0 ) { MFileObject fileObject; MDataHandle dataHandle = dataBlock.inputValue(mAbcFileNameAttr); fileObject.setRawFullName(dataHandle.asString()); MString fileName = fileObject.resolvedFullName(); storedFilenames.append( fileName ); } std::vector<std::string> abcFilenames; for(unsigned int i = 0; i < storedFilenames.length(); i++) abcFilenames.push_back( storedFilenames[i].asChar() ); Alembic::Abc::IArchive archive; Alembic::AbcCoreFactory::IFactory factory; factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy); archive = factory.getArchive( abcFilenames ); if (!archive.valid()) { MString theError = "Error opening these alembic files: "; const unsigned int numFilenames = storedFilenames.length(); for( unsigned int i = 0; i < numFilenames; i++ ) { theError += storedFilenames[ i ]; if( i != (numFilenames - 1) ) theError += ", "; } printError(theError); } // initialize some flags for plug update mSubDInitialized = false; mPolyInitialized = false; // When an alembic cache will be imported at the first time using // AbcImport, we need to set mIncludeFilterAttr (filterHandle) to be // mIncludeFilterString for later use. When we save a maya scene(.ma) // mIncludeFilterAttr will be saved. Then when we load the saved // .ma file, mIncludeFilterString will be set to be mIncludeFilterAttr. MDataHandle includeFilterHandle = dataBlock.inputValue(mIncludeFilterAttr, &status); MString& includeFilterString = includeFilterHandle.asString(); if (mIncludeFilterString.length() > 0) { includeFilterHandle.set(mIncludeFilterString); dataBlock.setClean(mIncludeFilterAttr); } else if (includeFilterString.length() > 0) { mIncludeFilterString = includeFilterString; } MDataHandle excludeFilterHandle = dataBlock.inputValue(mExcludeFilterAttr, &status); MString& excludeFilterString = excludeFilterHandle.asString(); if (mExcludeFilterString.length() > 0) { excludeFilterHandle.set(mExcludeFilterString); dataBlock.setClean(mExcludeFilterAttr); } else if (excludeFilterString.length() > 0) { mExcludeFilterString = excludeFilterString; } MFnDependencyNode dep(thisMObject()); MPlug allSetsPlug = dep.findPlug("allColorSets"); CreateSceneVisitor visitor(inputTime, !allSetsPlug.isNull(), MObject::kNullObj, CreateSceneVisitor::NONE, "", mIncludeFilterString, mExcludeFilterString); visitor.walk(archive); if (visitor.hasSampledData()) { // information retrieved from the hierarchy traversal // and given to AlembicNode to provide update visitor.getData(mData); mData.getFrameRange(mSequenceStartTime, mSequenceEndTime); MDataHandle startFrameHandle = dataBlock.inputValue(mStartFrameAttr, &status); startFrameHandle.set(mSequenceStartTime*fps); MDataHandle endFrameHandle = dataBlock.inputValue(mEndFrameAttr, &status); endFrameHandle.set(mSequenceEndTime*fps); } } // Retime MDataHandle cycleHandle = dataBlock.inputValue(mCycleTypeAttr, &status); short playType = cycleHandle.asShort(); inputTime = computeRetime(inputTime, mSequenceStartTime, mSequenceEndTime, playType); clamp<double>(mSequenceStartTime, mSequenceEndTime, inputTime); // update only when the time lapse is big enough if (fabs(inputTime - mCurTime) > 0.00001) { mOutRead = std::vector<bool>(mOutRead.size(), false); mCurTime = inputTime; } if (plug == mOutPropArrayAttr) { if (mOutRead[0]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[0] = true; unsigned int propSize = static_cast<unsigned int>(mData.mPropList.size()); if (propSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutPropArrayAttr, &status); unsigned int outHandleIndex = 0; MDataHandle outHandle; // for all of the nodes with sampled attributes for (unsigned int i = 0; i < propSize; i++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(); } else { continue; } if (mData.mPropList[i].mArray.valid()) { readProp(mCurTime, mData.mPropList[i].mArray, outHandle); } else if (mData.mPropList[i].mScalar.valid()) { // for visibility only if (mData.mPropList[i].mScalar.getName() == Alembic::AbcGeom::kVisibilityPropertyName) { Alembic::Util::int8_t visVal = 1; mData.mPropList[i].mScalar.get(&visVal, Alembic::Abc::ISampleSelector(mCurTime, Alembic::Abc::ISampleSelector::kNearIndex )); outHandle.setGenericBool(visVal != 0, false); } else { // for all scalar props readProp(mCurTime, mData.mPropList[i].mScalar, outHandle); } } outArrayHandle.next(); } outArrayHandle.setAllClean(); } } else if (plug == mOutTransOpArrayAttr ) { if (mOutRead[1]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[1] = true; unsigned int xformSize = static_cast<unsigned int>(mData.mXformList.size()); if (xformSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutTransOpArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutTransOpArrayAttr); MDataHandle outHandle; unsigned int outHandleIndex = 0; for (unsigned int i = 0; i < xformSize; i++) { std::vector<double> sampleList; if (mData.mIsComplexXform[i]) { readComplex(mCurTime, mData.mXformList[i], sampleList); } else { Alembic::AbcGeom::XformSample samp; read(mCurTime, mData.mXformList[i], sampleList, samp); } unsigned int sampleSize = (unsigned int)sampleList.size(); for (unsigned int j = 0; j < sampleSize; j++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(&status); } else continue; outArrayHandle.next(); outHandle.set(sampleList[j]); } } outArrayHandle.setAllClean(); } } else if (plug == mOutLocatorPosScaleArrayAttr ) { if (mOutRead[8]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[8] = true; unsigned int locSize = static_cast<unsigned int>(mData.mLocList.size()); if (locSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutLocatorPosScaleArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutLocatorPosScaleArrayAttr); MDataHandle outHandle; unsigned int outHandleIndex = 0; for (unsigned int i = 0; i < locSize; i++) { std::vector< double > sampleList; read(mCurTime, mData.mLocList[i], sampleList); unsigned int sampleSize = (unsigned int)sampleList.size(); for (unsigned int j = 0; j < sampleSize; j++) { // only use the handle if it matches the index. // The index wont line up in the sparse case so we // can just skip that element. if (outArrayHandle.elementIndex() == outHandleIndex++) { outHandle = outArrayHandle.outputValue(&status); } else continue; outArrayHandle.next(); outHandle.set(sampleList[j]); } } outArrayHandle.setAllClean(); } } else if (plug == mOutSubDArrayAttr) { if (mOutRead[2]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutSubDArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[2] = true; unsigned int subDSize = static_cast<unsigned int>(mData.mSubDList.size()); if (subDSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutSubDArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < subDSize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFnMesh fnMesh(obj); readSubD(mCurTime, fnMesh, obj, mData.mSubDList[j], mSubDInitialized); outHandle.set(obj); } } mSubDInitialized = true; outArrayHandle.setAllClean(); } // for the case where we don't have any nodes, we want to make sure // to push out empty meshes on our connections, this can happen if // the input file was offlined, currently we only need to do this for // meshes as Nurbs, curves, and the other channels don't crash Maya else { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutSubDArrayAttr, &status); if (outArrayHandle.elementCount() > 0) { do { MDataHandle outHandle = outArrayHandle.outputValue(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFloatPointArray emptyVerts; MIntArray emptyCounts; MIntArray emptyConnects; MFnMesh emptyMesh; emptyMesh.create(0, 0, emptyVerts, emptyCounts, emptyConnects, obj); outHandle.set(obj); } } while (outArrayHandle.next() == MS::kSuccess); } mSubDInitialized = true; outArrayHandle.setAllClean(); } } else if (plug == mOutPolyArrayAttr) { if (mOutRead[3]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutPolyArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[3] = true; unsigned int polySize = static_cast<unsigned int>(mData.mPolyMeshList.size()); if (polySize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutPolyArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < polySize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFnMesh fnMesh(obj); readPoly(mCurTime, fnMesh, obj, mData.mPolyMeshList[j], mPolyInitialized); outHandle.set(obj); } } mPolyInitialized = true; outArrayHandle.setAllClean(); } // for the case where we don't have any nodes, we want to make sure // to push out empty meshes on our connections, this can happen if // the input file was offlined, currently we only need to do this for // meshes as Nurbs, curves, and the other channels don't crash Maya else { MArrayDataHandle outArrayHandle = dataBlock.outputValue( mOutPolyArrayAttr, &status); if (outArrayHandle.elementCount() > 0) { do { MDataHandle outHandle = outArrayHandle.outputValue(&status); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kMesh)) { MFloatPointArray emptyVerts; MIntArray emptyCounts; MIntArray emptyConnects; MFnMesh emptyMesh; emptyMesh.create(0, 0, emptyVerts, emptyCounts, emptyConnects, obj); outHandle.set(obj); } } while (outArrayHandle.next() == MS::kSuccess); } mPolyInitialized = true; outArrayHandle.setAllClean(); } } else if (plug == mOutCameraArrayAttr) { if (mOutRead[4]) { dataBlock.setClean(plug); return MS::kSuccess; } mOutRead[4] = true; unsigned int cameraSize = static_cast<unsigned int>(mData.mCameraList.size()); if (cameraSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutCameraArrayAttr, &status); MPlug arrayPlug(thisMObject(), mOutCameraArrayAttr); double angleConversion = 1.0; switch (MAngle::uiUnit()) { case MAngle::kRadians: angleConversion = 0.017453292519943295; break; case MAngle::kAngMinutes: angleConversion = 60.0; break; case MAngle::kAngSeconds: angleConversion = 3600.0; break; default: break; } MDataHandle outHandle; unsigned int index = 0; for (unsigned int cameraIndex = 0; cameraIndex < cameraSize; cameraIndex++) { Alembic::AbcGeom::ICamera & cam = mData.mCameraList[cameraIndex]; std::vector<double> array; read(mCurTime, cam, array); for (unsigned int dataIndex = 0; dataIndex < array.size(); dataIndex++, index++) { // skip over sparse elements if (index != outArrayHandle.elementIndex()) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); // not shutter angle index, so not an angle if (dataIndex != 11) { outHandle.set(array[dataIndex]); } else { outHandle.set(array[dataIndex] * angleConversion); } } // for the per camera data handles } // for each camera outArrayHandle.setAllClean(); } } else if (plug == mOutNurbsSurfaceArrayAttr) { if (mOutRead[5]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsSurfaceArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[5] = true; unsigned int nSurfaceSize = static_cast<unsigned int>(mData.mNurbsList.size()); if (nSurfaceSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsSurfaceArrayAttr, &status); MDataHandle outHandle; for (unsigned int j = 0; j < nSurfaceSize; j++) { // these elements can be sparse if they have been deleted if (outArrayHandle.elementIndex() != j) continue; outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); MObject obj = outHandle.data(); if (obj.hasFn(MFn::kNurbsSurface)) { readNurbs(mCurTime, mData.mNurbsList[j], obj); outHandle.set(obj); } } outArrayHandle.setAllClean(); } } else if (plug == mOutNurbsCurveGrpArrayAttr) { if (mOutRead[6]) { // Reference the output to let EM know we are the writer // of the data. EM sets the output to holder and causes // race condition when evaluating fan-out destinations. MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsCurveGrpArrayAttr, &status); const unsigned int elementCount = outArrayHandle.elementCount(); for (unsigned int j = 0; j < elementCount; j++) { outArrayHandle.outputValue().data(); outArrayHandle.next(); } outArrayHandle.setAllClean(); return MS::kSuccess; } mOutRead[6] = true; unsigned int nCurveGrpSize = static_cast<unsigned int>(mData.mCurvesList.size()); if (nCurveGrpSize > 0) { MArrayDataHandle outArrayHandle = dataBlock.outputValue(mOutNurbsCurveGrpArrayAttr, &status); MDataHandle outHandle; std::vector<MObject> curvesObj; for (unsigned int i = 0; i < nCurveGrpSize; ++i) { readCurves(mCurTime, mData.mCurvesList[i], mData.mNumCurves[i], curvesObj); } std::size_t numChild = curvesObj.size(); // not the best way to do this // only reading bunches of curves based on the connections would be // more efficient when there is a bunch of broken connections for (unsigned int i = 0; i < numChild; i++) { if (outArrayHandle.elementIndex() != i) { continue; } outHandle = outArrayHandle.outputValue(&status); outArrayHandle.next(); status = outHandle.set(curvesObj[i]); } outArrayHandle.setAllClean(); } } else { return MS::kUnknownParameter; } dataBlock.setClean(plug); return status; }
//-***************************************************************************** int main( int argc, char *argv[] ) { bool opt_all = false; bool opt_meta = false; std::string desc( "abctree [OPTION] FILE[/NAME]\n" " -a include properties listings\n" " -h, --help prints this help message\n" " -m print metadata\n" ); // check for min args if ( argc < 2 ) { std::cout << desc << std::endl; return 0; }; // parse args std::vector<std::string> arguments(argv, argv + argc); std::vector<std::string> options; std::vector<std::string> files; // separate file args from option args for ( std::size_t i = 1; i < arguments.size(); i++ ) { if ( arguments[ i ].substr( 0, 1 ) == "-" ) options.push_back( arguments[ i ] ); else files.push_back( arguments[ i ] ); } // help if ( argc < 2 || optionExists( options, "h" ) || optionExists( options, "help" ) ) { std::cout << desc << std::endl; return 0; }; // set some flags opt_all = optionExists( options, "a"); opt_meta = optionExists( options, "m"); // open each file size_t count = 0; for ( std::size_t i = 0; i < files.size(); i++ ) { if ( files.size() > 1 ) std::cout << BOLD << files[i] << ':' << RESETCOLOR << std::endl; std::stringstream ss( files[i] ); std::stringstream fp; std::string segment; std::vector<std::string> seglist; /* * separate file and object paths, e.g. * * ../dir1/foo.abc/bar/baz * \_____________/\______/ * file obj */ int j = 0; while ( std::getline( ss, segment, '/' ) ) { if ( !isFile ( fp.str() ) ) { if ( j != 0 ) fp << "/"; fp << segment; } else { seglist.push_back( segment ); } ++j; } // open the iarchive Abc::IArchive archive; AbcF::IFactory factory; factory.setPolicy(Abc::ErrorHandler::kQuietNoopPolicy); AbcF::IFactory::CoreType coreType; archive = factory.getArchive(std::string( fp.str() ), coreType); // display file metadata if ( opt_meta ) { std::cout << "Using " << Alembic::AbcCoreAbstract::GetLibraryVersion () << std::endl;; std::string appName; std::string libraryVersionString; Alembic::Util::uint32_t libraryVersion; std::string whenWritten; std::string userDescription; std::string coreName; GetArchiveInfo (archive, appName, libraryVersionString, libraryVersion, whenWritten, userDescription); if ( coreType == AbcF::IFactory::kOgawa ) { coreName = "Ogawa"; } else if ( coreType == AbcF::IFactory::kHDF5 ) { coreName = "HDF5"; } else { coreName = "Unknown"; }; if ( appName != "" ) { std::cout << " file written by: " << appName << std::endl; std::cout << " using Alembic : " << libraryVersionString << std::endl; std::cout << " written on : " << whenWritten << std::endl; std::cout << " user description : " << userDescription << std::endl; } else { std::cout << " (file doesn't have any ArchiveInfo)" << std::endl; } std::cout << " core type : " << coreName << std::endl; }; // walk object hierarchy and find valid objects AbcG::IObject test = archive.getTop(); AbcG::IObject iObj = test; while ( test.valid() && seglist.size() > 0 ) { test = test.getChild( seglist.front() ); if ( test.valid() ) { iObj = test; seglist.erase( seglist.begin() ); } } // walk property hierarchy for most recent valid object Abc::ICompoundProperty props = iObj.getProperties(); const Abc::PropertyHeader* header; bool found = false; for ( std::size_t i = 0; i < seglist.size(); ++i ) { header = props.getPropertyHeader( seglist[i] ); if ( header && header->isCompound() ) { Abc::ICompoundProperty ptest( props, header->getName() ); if ( ptest.valid() ) { props = ptest; found = true; } } else if ( header && header->isSimple() ) { found = true; } else { std::cout << seglist[i] << ": Invalid object or property" << std::endl; return 1; } } // walk the archive tree if ( found ) if ( header->isCompound() ) tree( props ); else tree( Abc::IScalarProperty( props, header->getName() ) ); else tree( iObj, opt_all ); ++count; } return 0; }