EAbcIObjectType GetEIObjectType( Alembic::Abc::IObject& in_object )
{
	AbcA::MetaData l_md = in_object.getMetaData();

	if ( IPolyMesh::matches( l_md ) )
		return EIObject_Polymesh;
	else if ( ISubD::matches( l_md ) )
		return EIObject_Subd;
	else if ( IPoints::matches( l_md ) )
		return EIObject_Points;
	else if ( IMaterial::matches( l_md ) )
		return EIObject_Material;
	else if ( ICamera::matches( l_md ) )
		return EIObject_Camera;
	else if ( IXform::matches( l_md ) )
		return EIObject_Xform;
	else if ( ICurves::matches( l_md ) )
		return EIObject_Curves;
	else if ( INuPatch::matches( l_md ) )
		return EIObject_NuPatch;
	else if ( IFaceSet::matches( l_md ) )
		return EIObject_FaceSet;
	else
		return EIObject_Unknown;
}
bool getBasicSchemaDataFromObject(Alembic::Abc::IObject &object, BasicSchemaData &bsd)
{
	ESS_PROFILE_SCOPE("getBasicSchemaDataFromObject"); 
	const Alembic::Abc::MetaData &md = object.getMetaData();
	if(Alembic::AbcGeom::IXform::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__XFORM, Alembic::AbcGeom::IXform(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::IPolyMesh::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__POLYMESH, Alembic::AbcGeom::IPolyMesh(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::ICurves::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__CURVES, Alembic::AbcGeom::ICurves(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::INuPatch::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__NUPATCH, Alembic::AbcGeom::INuPatch(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::IPoints::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__POINTS, Alembic::AbcGeom::IPoints(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::ISubD::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__SUBDIV, Alembic::AbcGeom::ISubD(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::ICamera::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__CAMERA, Alembic::AbcGeom::ICamera(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	else if(Alembic::AbcGeom::IFaceSet::matches(md))
		return __getBasicSchemaDataFromObject(BasicSchemaData::__FACESET, Alembic::AbcGeom::IFaceSet(object,Alembic::Abc::kWrapExisting).getSchema(), bsd);

	return false;
};
Esempio n. 3
0
void copyObject(Alembic::Abc::IObject & iIn,
    Alembic::Abc::OObject & iOut)
{
    std::size_t numChildren = iIn.getNumChildren();

    Alembic::Abc::ICompoundProperty inProps = iIn.getProperties();
    Alembic::Abc::OCompoundProperty outProps = iOut.getProperties();
    copyProps(inProps, outProps);

    for (std::size_t i = 0; i < numChildren; ++i)
    {
        Alembic::Abc::IObject childIn(iIn.getChild(i));
        Alembic::Abc::OObject childOut(iOut, childIn.getName(),
                                       childIn.getMetaData());
        copyObject(childIn, childOut);
    }
}
void getABCCameras(Alembic::Abc::IObject & iObj,
		std::vector<Alembic::AbcGeom::ICamera> & _objs)
{

	unsigned int numChildren = iObj.getNumChildren();

	for (unsigned i=0; i<numChildren; ++i)
	{
		IObject child( iObj.getChild( i ));
		if ( Alembic::AbcGeom::ICamera::matches(child.getHeader()) ) {
			ICamera cam(child, Alembic::Abc::kWrapExisting);
			_objs.push_back(cam);
		}

		if (child.getNumChildren() > 0) {
			getABCCameras(child, _objs);
		}
	}
}
void getABCGeos(Alembic::Abc::IObject & iObj,
		std::vector<Alembic::AbcGeom::IObject> & _objs)
{

	unsigned int numChildren = iObj.getNumChildren();

	for (unsigned i=0; i<numChildren; ++i)
	{
		IObject child( iObj.getChild( i ));
		if ( Alembic::AbcGeom::IPolyMesh::matches(child.getHeader())
		|| Alembic::AbcGeom::ISubD::matches(child.getHeader())) {
			_objs.push_back(child);
		}

		if (child.getNumChildren() > 0) {
			getABCGeos(child, _objs);
		}
	}
}
void traverse(Abc::IObject object, bool includeSelf)
{
    if (includeSelf)
    {
        std::cout << "---------------------------------" << std::endl;
        std::cout << object.getFullName() << std::endl;
        
        
        
        
        if (Mat::IMaterial::matches(object.getHeader()))
        {
            std::cout << "(is material, local data shown)\n";
            Mat::IMaterial mat(object, Abc::kWrapExisting);
            printMaterialSchema(mat.getSchema());
            TESTING_ASSERT(object.getName() == "materialA" ||
                object.getName() == "materialB");
        }
        else
        {
            Mat::MaterialFlatten mafla(object);

            std::string name = object.getName();
            std::cout << name << " " << mafla.empty() << std::endl;
            TESTING_ASSERT(
                (!mafla.empty() &&
                    (name == "geoA" || name == "geoB" || name == "geoC")) ||
                (mafla.empty() &&
                    (name == "geometry" || name == "materials")));

            if (!mafla.empty())
            {
                std::cout << "(flattened material via has and/or assigned)\n";
                printFlattenedMafla(mafla);
            }
            else
            {
                std::cout << "(neither is, has or is assigned)\n";
            }
        }
        
        
        
        
        
        
        
        
    }
    
    for (size_t i = 0; i < object.getNumChildren(); ++i)
    {
        traverse(object.getChild(i), true);
    }
    
}
Alembic::Abc::TimeSamplingPtr getTimeSamplingFromObject(
    Alembic::Abc::IObject& object)
{
  ESS_PROFILE_SCOPE("getTimeSamplingFromObject");
  const Alembic::Abc::MetaData& md = object.getMetaData();
  if (Alembic::AbcGeom::IXform::matches(md)) {
    return Alembic::AbcGeom::IXform(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
    return Alembic::AbcGeom::IPolyMesh(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::ICurves::matches(md)) {
    return Alembic::AbcGeom::ICurves(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::INuPatch::matches(md)) {
    return Alembic::AbcGeom::INuPatch(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::IPoints::matches(md)) {
    return Alembic::AbcGeom::IPoints(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::ISubD::matches(md)) {
    return Alembic::AbcGeom::ISubD(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::ICamera::matches(md)) {
    return Alembic::AbcGeom::ICamera(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
    return Alembic::AbcGeom::IFaceSet(object, Alembic::Abc::kWrapExisting)
        .getSchema()
        .getTimeSampling();
  }
  return Alembic::Abc::TimeSamplingPtr();
}
bool isObjectConstant(Alembic::Abc::IObject& object)
{
  ESS_PROFILE_SCOPE("isObjectConstant");
  const Alembic::Abc::MetaData& md = object.getMetaData();
  if (Alembic::AbcGeom::IXform::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::IXform(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::IPolyMesh::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::IPolyMesh(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::ICurves::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::ICurves(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::INuPatch::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::INuPatch(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::IPoints::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::IPoints(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::ISubD::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::ISubD(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::ICamera::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::ICamera(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  else if (Alembic::AbcGeom::IFaceSet::matches(md)) {
    return isObjectSchemaConstant(
        Alembic::AbcGeom::IFaceSet(object, Alembic::Abc::kWrapExisting)
            .getSchema());
  }
  return true;
}
AbcObjectCache::AbcObjectCache( Alembic::Abc::IObject & objToCache )
		:	obj( objToCache ), isMeshTopoDynamic(false), isMeshPointCache(false), fullName(objToCache.getFullName())
{
	ESS_PROFILE_SCOPE("AbcObjectCache::AbcObjectCache");

	BasicSchemaData bsd;
	getBasicSchemaDataFromObject(objToCache, bsd);
	isConstant = bsd.isConstant;
	numSamples = bsd.nbSamples;
	bool isMesh = true;
	if ( bsd.type == bsd.__POLYMESH || !( isMesh = (bsd.type != bsd.__SUBDIV) ) )
	{
		bool isTopoDyn = false;
		extractMeshInfo(&objToCache, isMesh, isMeshPointCache, isTopoDyn);
		if (!isConstant)
			isMeshTopoDynamic = isTopoDyn;
	}
}
Esempio n. 10
0
//-*****************************************************************************
bool is_leaf( AbcG::IObject iObj )
{
    if ( !iObj.getParent().valid() ) {
        return true;
    }

    Abc::IObject parent = iObj.getParent();
    int numChildren = parent.getNumChildren();

    Abc::IObject test = parent.getChild(numChildren - 1);
    if ( test.valid() && test.getName() != iObj.getName() ) {
        return false;
    }
    return true;
}
// returns the number of nodes
int prescanAlembicHierarchy(AbcArchiveCache* pArchiveCache,
                            AbcObjectCache* pRootObjectCache,
                            std::vector<std::string>& nodes,
                            std::map<std::string, bool>& map,
                            bool bIncludeChildren)
{
  for (int i = 0; i < nodes.size(); i++) {
    boost::to_upper(nodes[i]);
  }

  std::list<AlembicSelectionStackElement> sceneStack;

  for (size_t j = 0; j < pRootObjectCache->childIdentifiers.size(); j++) {
    AbcObjectCache* pChildObjectCache =
        &(pArchiveCache->find(pRootObjectCache->childIdentifiers[j])->second);
    sceneStack.push_back(
        AlembicSelectionStackElement(pChildObjectCache, false));
  }

  int nNumNodes = 0;
  while (!sceneStack.empty()) {
    AlembicSelectionStackElement sElement = sceneStack.back();
    Alembic::Abc::IObject iObj = sElement.pObjectCache->obj;
    bool bSelected = sElement.bSelected;
    sceneStack.pop_back();

    nNumNodes++;

    bool bCreateNullNode = false;
    int nMergedGeomNodeIndex = -1;
    AbcObjectCache* pMergedChildObjectCache = NULL;
    getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateNullNode,
                 nMergedGeomNodeIndex, &pMergedChildObjectCache);

    std::string name;
    std::string fullname;

    if (nMergedGeomNodeIndex != -1) {  // we are merging
      Alembic::AbcGeom::IObject mergedGeomChild = pMergedChildObjectCache->obj;
      name = mergedGeomChild.getName();
      fullname = mergedGeomChild.getFullName();
    }
    else {  // geometry node(s) under a dummy node (in pParentMaxNode)
      name = iObj.getName();
      fullname = iObj.getFullName();
    }

    bool bSelectChildren = false;

    if (bSelected) {
      map[fullname] = true;
      bSelectChildren = true;
    }
    else {
      boost::to_upper(name);
      for (int i = 0; i < nodes.size(); i++) {
        const char* cstrName = name.c_str();
        const char* cstrNode = nodes[i].c_str();

        if (name.find(nodes[i]) != std::string::npos) {
          if (bIncludeChildren) {
            bSelectChildren = true;
          }

          std::vector<std::string> parts;
          boost::split(parts, fullname, boost::is_any_of("/"));

          std::string nodeName;
          for (int j = 1; j < parts.size(); j++) {
            nodeName += "/";
            nodeName += parts[j];
            map[nodeName] = true;
          }
        }
      }
    }

    // push the children as the last step, since we need to who the parent is
    // first (we may have merged)
    for (size_t j = 0; j < sElement.pObjectCache->childIdentifiers.size();
         j++) {
      AbcObjectCache* pChildObjectCache =
          &(pArchiveCache->find(sElement.pObjectCache->childIdentifiers[j])
                ->second);
      Alembic::AbcGeom::IObject childObj = pChildObjectCache->obj;
      NodeCategory::type childCat = NodeCategory::get(childObj);
      if (childCat == NodeCategory::UNSUPPORTED)
        continue;  // skip over unsupported types

      // I assume that geometry nodes are always leaf nodes. Thus, if we merged
      // a geometry node will its parent transform, we don't
      // need to push that geometry node to the stack.
      // A geometry node can't be combined with its transform node, the
      // transform node has other tranform nodes as children. These
      // nodes must be pushed.
      if (nMergedGeomNodeIndex != j) {
        sceneStack.push_back(
            AlembicSelectionStackElement(pChildObjectCache, bSelectChildren));
      }
    }
  }

  return nNumNodes;
}
Esempio n. 12
0
int main(int argc, char *argv[])
{

    std::string toType;
    std::string inFile;
    std::string outFile;
    std::string forceStr;

    if (argc == 4)
    {
        toType = argv[1];
        inFile = argv[2];
        outFile = argv[3];
    }
    else if (argc == 5)
    {
        forceStr = argv[1];
        toType = argv[2];
        inFile = argv[3];
        outFile = argv[4];
    }

    if ((argc == 4 || argc == 5) && (forceStr.empty() || forceStr == "-force"))
    {
        if (inFile == outFile)
        {
            printf("Error: inFile and outFile must not be the same!\n");
            return 1;
        }

        if (toType != "-toHDF" && toType != "-toOgawa")
        {
            printf("Error: Unknown conversion type specified %s\n",
                   toType.c_str());
            printf("Currently only -toHDF and -toOgawa are supported.\n");
            return 1;
        }

        Alembic::AbcCoreFactory::IFactory factory;
        Alembic::AbcCoreFactory::IFactory::CoreType coreType;
        Alembic::Abc::IArchive archive = factory.getArchive(inFile, coreType);
        if (!archive.valid())
        {
            printf("Error: Invalid Alembic file specified: %s\n",
                   inFile.c_str());
            return 1;
        }
        else if ( forceStr != "-force" && (
            (coreType == Alembic::AbcCoreFactory::IFactory::kHDF5 &&
             toType == "-toHDF") ||
            (coreType == Alembic::AbcCoreFactory::IFactory::kOgawa &&
             toType == "-toOgawa")) )
        {
            printf("Warning: Alembic file specified: %s\n",inFile.c_str());
            printf("is already of the type you want to convert to.\n");
            printf("Please specify -force if you want to do this anyway.\n");
            return 1;
        }

        Alembic::Abc::IObject inTop = archive.getTop();
        Alembic::Abc::OArchive outArchive;
        if (toType == "-toHDF")
        {
            outArchive = Alembic::Abc::OArchive(
                Alembic::AbcCoreHDF5::WriteArchive(),
                outFile, inTop.getMetaData(),
                Alembic::Abc::ErrorHandler::kThrowPolicy);
        }
        else if (toType == "-toOgawa")
        {
            outArchive = Alembic::Abc::OArchive(
                Alembic::AbcCoreOgawa::WriteArchive(),
                outFile, inTop.getMetaData(),
                Alembic::Abc::ErrorHandler::kThrowPolicy);
        }

        // start at 1, we don't need to worry about intrinsic default case
        for (Alembic::Util::uint32_t i = 1; i < archive.getNumTimeSamplings();
             ++i)
        {
            outArchive.addTimeSampling(*archive.getTimeSampling(i));
        }

        Alembic::Abc::OObject outTop = outArchive.getTop();
        copyObject(inTop, outTop);
        return 0;
    }

    printf ("Usage: abcconvert [-force] OPTION inFile outFile\n");
    printf ("Used to convert an Alembic file from one type to another.\n\n");
    printf ("If -force is not provided and inFile happens to be the same\n");
    printf ("type as OPTION no conversion will be done and a message will\n");
    printf ("be printed out.\n");
    printf ("OPTION has to be one of these:\n\n");
    printf ("  -toHDF   Convert to HDF.\n");
    printf ("  -toOgawa Convert to Ogawa.\n");

    return 1;
}
Esempio n. 13
0
AtNode *createInstanceNode(nodeData &nodata, userData * ud, int i)
{
  Alembic::AbcGeom::IPoints typedObject(ud->gIObjects[i].abc, Alembic::Abc::kWrapExisting);

  instanceCloudInfo * info = ud->gIObjects[i].instanceCloud;

  // check that we have the masternode
  size_t id = (size_t)ud->gIObjects[i].ID;
  size_t instanceID = (size_t)ud->gIObjects[i].instanceID;
  if(instanceID >= info->groupInfos.size())
  {
    AiMsgError("[ExocortexAlembicArnold] Instance '%s.%d' has an invalid instanceID  . Aborting.",ud->gIObjects[i].abc.getFullName().c_str(),(int)id);
    return NULL;
  }
  size_t groupID = (size_t)ud->gIObjects[i].instanceGroupID;
  if(groupID >= info->groupInfos[instanceID].identifiers.size())
  {
    AiMsgError("[ExocortexAlembicArnold] Instance '%s.%d' has an invalid instanceGroupID. Aborting.",ud->gIObjects[i].abc.getFullName().c_str(),(int)id);
    return NULL;
  }

  instanceGroupInfo * group = &info->groupInfos[instanceID];

  // get the right centroidTime
  float centroidTime = ud->gCentroidTime;
  if(info->time.size() > 0)
  {
    centroidTime = info->time[0]->get()[id < info->time[0]->size() ? id : info->time[0]->size() - 1];
    if(info->time.size() > 1)
      centroidTime = (1.0f - info->timeAlpha) * centroidTime + info->timeAlpha * info->time[1]->get()[id < info->time[1]->size() ? id : info->time[1]->size() - 1];
    centroidTime = roundCentroid(centroidTime);
  }

  std::map<float,AtNode*>::iterator it = group->nodes[groupID].find(centroidTime);
  if(it == group->nodes[groupID].end())
  {
    AiMsgError("[ExocortexAlembicArnold] Cannot find masterNode '%s' for centroidTime '%f'. Aborting.",group->identifiers[groupID].c_str(),centroidTime);
    return NULL;
  }
  AtNode *usedMasterNode = it->second;

  AtNode *shapeNode = AiNode("ginstance");

  // setup name, id and the master node
  AiNodeSetStr(shapeNode, "name", getNameFromIdentifier(ud->gIObjects[i].abc.getFullName(),ud->gIObjects[i].ID,(long)groupID).c_str());
  AiNodeSetInt(shapeNode, "id", ud->gIObjects[i].instanceID); 
  AiNodeSetPtr(shapeNode, "node", usedMasterNode);

  // declare color on the ginstance
  if(info->color.size() > 0 && AiNodeDeclare(shapeNode, "Color", "constant RGBA"))
  {
    Alembic::Abc::C4f color = info->color[0]->get()[id < info->color[0]->size() ? id : info->color[0]->size() - 1];
    AiNodeSetRGBA(shapeNode, "Color", color.r, color.g, color.b, color.a);
  }

  // now let's take care of the transform
  AtArray * matrices = AiArrayAllocate(1,(AtInt)ud->gMbKeys.size(),AI_TYPE_MATRIX);
  for(size_t j=0;j<ud->gMbKeys.size(); ++j)
  {
    SampleInfo sampleInfo = getSampleInfo(
      ud->gMbKeys[j],
      typedObject.getSchema().getTimeSampling(),
      typedObject.getSchema().getNumSamples()
    );

    Alembic::Abc::M44f matrixAbc;
    matrixAbc.makeIdentity();
    const size_t floorIndex = j << 1;
    const size_t ceilIndex =  floorIndex + 1;

    // apply translation
    if(info->pos[floorIndex]->size() == info->pos[ceilIndex]->size())
    {
      matrixAbc.setTranslation(float(1.0 - sampleInfo.alpha) * info->pos[floorIndex]->get()[id < info->pos[floorIndex]->size() ? id : info->pos[floorIndex]->size() - 1] + 
                               float(sampleInfo.alpha) * info->pos[ceilIndex]->get()[id < info->pos[ceilIndex]->size() ? id : info->pos[ceilIndex]->size() - 1]);
    }
    else
    {
      const float timeAlpha = getTimeOffsetFromObject( typedObject, sampleInfo );

      matrixAbc.setTranslation(info->pos[floorIndex]->get()[id < info->pos[floorIndex]->size() ? id : info->pos[floorIndex]->size() - 1] + 
                               info->vel[floorIndex]->get()[id < info->vel[floorIndex]->size() ? id : info->vel[floorIndex]->size() - 1] * timeAlpha);
    }

    // now take care of rotation
    if(info->rot.size() == ud->gMbKeys.size())
    {
      Alembic::Abc::Quatf rotAbc = info->rot[j]->get()[id < info->rot[j]->size() ? id : info->rot[j]->size() - 1];
      if(info->ang.size() == ud->gMbKeys.size() && sampleInfo.alpha > 0.0)
      {
        Alembic::Abc::Quatf angAbc = info->ang[j]->get()[id < info->ang[j]->size() ? id : info->ang[j]->size() -1] * (float)sampleInfo.alpha;
        if(angAbc.axis().length2() != 0.0f && angAbc.r != 0.0f)
        {
          rotAbc = angAbc * rotAbc;
          rotAbc.normalize();
        }
      }
      Alembic::Abc::M44f matrixAbcRot;
      matrixAbcRot.setAxisAngle(rotAbc.axis(),rotAbc.angle());
      matrixAbc = matrixAbcRot * matrixAbc;
    }

    // and finally scaling
    if(info->scale.size() == ud->gMbKeys.size() * 2)
    {
      const Alembic::Abc::V3f scalingAbc = info->scale[floorIndex]->get()[id < info->scale[floorIndex]->size() ? id : info->scale[floorIndex]->size() - 1] * 
                                           info->width[floorIndex]->get()[id < info->width[floorIndex]->size() ? id : info->width[floorIndex]->size() - 1] * float(1.0 - sampleInfo.alpha) + 
                                           info->scale[ceilIndex]->get()[id < info->scale[ceilIndex]->size() ? id : info->scale[ceilIndex]->size() - 1] * 
                                           info->width[ceilIndex]->get()[id < info->width[ceilIndex]->size() ? id : info->width[ceilIndex]->size() - 1] * float(sampleInfo.alpha);
      matrixAbc.scale(scalingAbc);
    }
    else
    {
      const float width = info->width[floorIndex]->get()[id < info->width[floorIndex]->size() ? id : info->width[floorIndex]->size() - 1] * float(1.0 - sampleInfo.alpha) + 
                          info->width[ceilIndex]->get()[id < info->width[ceilIndex]->size() ? id : info->width[ceilIndex]->size() - 1] * float(sampleInfo.alpha);
      matrixAbc.scale(Alembic::Abc::V3f(width,width,width));
    }

    // if we have offset matrices
    if(group->parents.size() > groupID && group->matrices.size() > groupID)
    {
      if(group->objects[groupID].valid() && group->parents[groupID].valid())
      {
        // we have a matrix map and a parent.
        // now we need to check if we already exported the matrices
        std::map<float,std::vector<Alembic::Abc::M44f> >::iterator it;
        std::vector<Alembic::Abc::M44f> offsets;
        it = group->matrices[groupID].find(centroidTime);
        if(it == group->matrices[groupID].end())
        {
          std::vector<float> samples(ud->gMbKeys.size());
          offsets.resize(ud->gMbKeys.size());
          for(AtInt sampleIndex=0;sampleIndex<(AtInt)ud->gMbKeys.size(); ++sampleIndex)
          {
            offsets[sampleIndex].makeIdentity();
            // centralize the time once more
            samples[sampleIndex] = centroidTime + ud->gMbKeys[sampleIndex] - ud->gCentroidTime;
          }

          // if the transform differs, we need to compute the offset matrices
          // get the parent, which should be a transform
          Alembic::Abc::IObject parent = group->parents[groupID];
          Alembic::Abc::IObject xform = group->objects[groupID].getParent();
          while(Alembic::AbcGeom::IXform::matches(xform.getMetaData()) && xform.getFullName() != parent.getFullName())
          {
            // cast to a xform
            Alembic::AbcGeom::IXform parentXform(xform,Alembic::Abc::kWrapExisting);
            if(parentXform.getSchema().getNumSamples() == 0)
              break;

            // loop over all samples
            for(size_t sampleIndex=0;sampleIndex<ud->gMbKeys.size(); ++sampleIndex)
            {
              SampleInfo sampleInfo = getSampleInfo(
                 samples[sampleIndex],
                 parentXform.getSchema().getTimeSampling(),
                 parentXform.getSchema().getNumSamples()
              );

              // get the data and blend it if necessary
              Alembic::AbcGeom::XformSample sample;
              parentXform.getSchema().get(sample,sampleInfo.floorIndex);
              Alembic::Abc::M44f abcMatrix;
              Alembic::Abc::M44d abcMatrixd = sample.getMatrix();
              for(int x=0;x<4;x++)
                 for(int y=0;y<4;y++)
                    abcMatrix[x][y] = (float)abcMatrixd[x][y];
               
              if(sampleInfo.alpha >= sampleTolerance)
              {
                parentXform.getSchema().get(sample,sampleInfo.ceilIndex);
                Alembic::Abc::M44d ceilAbcMatrixd = sample.getMatrix();
                Alembic::Abc::M44f ceilAbcMatrix;
                for(int x=0;x<4;x++)
                  for(int y=0;y<4;y++)
                     ceilAbcMatrix[x][y] = (float)ceilAbcMatrixd[x][y];
                abcMatrix = float(1.0 - sampleInfo.alpha) * abcMatrix + float(sampleInfo.alpha) * ceilAbcMatrix;
              }

              offsets[sampleIndex] = abcMatrix * offsets[sampleIndex];
            }

            // go upwards
            xform = xform.getParent();
          }
          group->matrices[groupID].insert(std::pair<float,std::vector<Alembic::Abc::M44f> >(centroidTime,offsets));
        }
        else
          offsets = it->second;

        // this means we have the right amount of matrices to blend against
        if(offsets.size() > j)
          matrixAbc = offsets[j] * matrixAbc;
      }
    }

    // store it to the array
    AiArraySetMtx(matrices,(AtULong)j,matrixAbc.x);
  }

  AiNodeSetArray(shapeNode,"matrix",matrices);
  AiNodeSetBool(shapeNode, "inherit_xform", FALSE);

  return shapeNode;
}
int main(int argc, char *argv[])
{
    ConversionOptions options;
    bool doConversion = false;

    if (parseArgs( argc, argv, options, doConversion ) == false)
        return 1;

    if (doConversion)
    {
        for( std::vector<std::string>::const_iterator inFile = options.inFiles.begin(); inFile != options.inFiles.end(); inFile++ )
        {
            if (*inFile == options.outFile)
            {
                printf("Error: inFile and outFile must not be the same!\n");
                return 1;
            }
        }

        if (options.toType != IFactoryNS::kHDF5 && options.toType != IFactoryNS::kOgawa)
        {
            printf("Currently only -toHDF and -toOgawa are supported.\n");
            return 1;
        }

        Alembic::AbcCoreFactory::IFactory factory;
        Alembic::AbcCoreFactory::IFactory::CoreType coreType;

        Alembic::Abc::IArchive archive;
        if(options.inFiles.size() == 1)
        {
            archive = factory.getArchive(*options.inFiles.begin(), coreType);
            if (!archive.valid())
            {
                printf("Error: Invalid Alembic file specified: %s\n",
                       options.inFiles.begin()->c_str());
                return 1;
            }
            else if ( !options.force && (
                (coreType == IFactoryNS::kHDF5 &&
                 options.toType == IFactoryNS::kHDF5) ||
                (coreType == IFactoryNS::kOgawa &&
                 options.toType == IFactoryNS::kOgawa)) )
            {
                printf("Warning: Alembic file specified: %s\n", options.inFiles.begin()->c_str());
                printf("is already of the type you want to convert to.\n");
                printf("Please specify -force if you want to do this anyway.\n");
                return 1;
            }
        }
        else
        {
            archive = factory.getArchive(options.inFiles, coreType);
        }

        Alembic::Abc::IObject inTop = archive.getTop();
        Alembic::Abc::OArchive outArchive;
        if (options.toType == IFactoryNS::kHDF5)
        {
            outArchive = Alembic::Abc::OArchive(
                Alembic::AbcCoreHDF5::WriteArchive(),
                options.outFile, inTop.getMetaData(),
                Alembic::Abc::ErrorHandler::kThrowPolicy);
        }
        else if (options.toType == IFactoryNS::kOgawa)
        {
            outArchive = Alembic::Abc::OArchive(
                Alembic::AbcCoreOgawa::WriteArchive(),
                options.outFile, inTop.getMetaData(),
                Alembic::Abc::ErrorHandler::kThrowPolicy);
        }

        // start at 1, we don't need to worry about intrinsic default case
        for (Alembic::Util::uint32_t i = 1; i < archive.getNumTimeSamplings();
             ++i)
        {
            outArchive.addTimeSampling(*archive.getTimeSampling(i));
        }

        Alembic::Abc::OObject outTop = outArchive.getTop();
        copyObject(inTop, outTop);
    }

    return 0;
}