<commit_before>#include "stdafx.h"
#include "Alembic.h"
#include "AlembicArchiveStorage.h"
#include "AlembicMeshUtilities.h"
#include "AlembicSplineUtilities.h"
#include "AlembicXformUtilities.h"
#include "AlembicXformController.h"
#include "AlembicCameraUtilities.h"
#include "AlembicParticles.h"
#include "SceneEnumProc.h"
#include "AlembicDefinitions.h"
#include "AlembicWriteJob.h"
#include "AlembicRecursiveImporter.h"
#include "Utility.h"

#include "AlembicRecursiveImporter.h"



int createAlembicObject(AbcG::IObject& iObj, INode **pMaxNode, alembic_importoptions &options, std::string& file)
{
	int ret = alembic_success;
	//if(AbcG::IXform::matches(iObj.getMetaData())) //Transform
	//{
	//	ESS_LOG_INFO( "AlembicImport_XForm: " << objects[j].getFullName() );
	//	int ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); 
	//} 	
	if (AbcG::IPolyMesh::matches(iObj.getMetaData()) || 
		AbcG::ISubD::matches(iObj.getMetaData()) ) // PolyMesh / SubD
	{
		ESS_LOG_INFO( "AlembicImport_PolyMesh: " << iObj.getFullName() );
		ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); 
	}
	else if (AbcG::ICamera::matches(iObj.getMetaData())) // Camera
	{
		ESS_LOG_INFO( "AlembicImport_Camera: " << iObj.getFullName() );
		ret = AlembicImport_Camera(file, iObj, options, pMaxNode);
	}
	else if (AbcG::IPoints::matches(iObj.getMetaData())) // Points
	{
		ESS_LOG_INFO( "AlembicImport_Points: " << iObj.getFullName() );
		ret = AlembicImport_Points(file, iObj, options, pMaxNode);
	}
	else if (AbcG::ICurves::matches(iObj.getMetaData())) // Curves
	{
		ESS_LOG_INFO( "AlembicImport_Shape: " << iObj.getFullName() );
		ret = AlembicImport_Shape(file, iObj, options, pMaxNode);
	}
   else // NURBS
	{
		if( options.failOnUnsupported ) {
			ESS_LOG_ERROR( "Alembic data type not supported: " << iObj.getFullName() );
			return alembic_failure;
		}
		else {
			ESS_LOG_WARNING( "Alembic data type not supported: " << iObj.getFullName() );
		}
	}
	return ret;
}

struct stackElement
{
   AbcObjectCache *pObjectCache;
   INode *pParentMaxNode;

   stackElement(AbcObjectCache *pMyObjectCache):pObjectCache(pMyObjectCache), pParentMaxNode(NULL)
   {}
   stackElement(AbcObjectCache *pMyObjectCache, INode* parent):pObjectCache(pMyObjectCache), pParentMaxNode(parent)
   {}


};

int importAlembicScene(AbcArchiveCache *pArchiveCache, AbcObjectCache *pRootObjectCache, alembic_importoptions &options, std::string& file, progressUpdate& progress, std::map<std::string, bool>& nodeFullPaths)
{
   std::vector<stackElement> sceneStack;
   sceneStack.reserve(200);
	for(size_t j=0; j<pRootObjectCache->childIdentifiers.size(); j++)
	{
      sceneStack.push_back(stackElement( &( pArchiveCache->find( pRootObjectCache->childIdentifiers[j] )->second ) ));
	} 

   while( !sceneStack.empty() )
   {
      stackElement sElement = sceneStack.back();
      sceneStack.pop_back();
      Abc::IObject& iObj = sElement.pObjectCache->obj;
      INode *pParentMaxNode = sElement.pParentMaxNode;

	   if(!iObj.valid()){
		   return alembic_failure;
	   }

	   const std::string fullname = iObj.getFullName();
	   const std::string pname = (pParentMaxNode) ? EC_MCHAR_to_UTF8( pParentMaxNode->GetName() ) : std::string("");
	   const std::string name = iObj.getName();

      ESS_LOG_INFO("Importing "<<fullname);

      bool bCreateDummyNode = false;
      int mergedGeomNodeIndex = -1;
      AbcObjectCache *pMergedObjectCache = NULL;
      getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateDummyNode, mergedGeomNodeIndex, &pMergedObjectCache);

      INode* pMaxNode = NULL;// the newly create node, which may be a merged node
      INode* pExistingNode = NULL;
      int keepTM = 1;//I don't remember why this needed to be set in some cases.

      bool bCreateNode = true;

      if(!nodeFullPaths.empty()){
         if(mergedGeomNodeIndex != -1){
        	AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
          bCreateNode = nodeFullPaths.find(mergedGeomChild.getFullName()) != nodeFullPaths.end(); 
         }
         else{
            bCreateNode = nodeFullPaths.find(fullname) != nodeFullPaths.end(); 
         }
      }

      if(bCreateNode){

	      if(bCreateDummyNode){

		      std::string importName = removeXfoSuffix(iObj.getName());

		      pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
		      if(options.attachToExisting && pExistingNode){
			      pMaxNode = pExistingNode;

			      //see if a controller already exists, and then delete it
   				
			      int ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options);
			      if(ret != 0) return ret;
		      }//only create node if either attachToExisting is false or it is true and the object does not already exist
		      else{
			      int ret = AlembicImport_DummyNode(iObj, options, &pMaxNode, importName);
			      if(ret != 0) return ret;

			      ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options);
			      if(ret != 0) return ret;
		      }
	      }
	      else{
		      if(mergedGeomNodeIndex != -1){//we are merging, so look at the child geometry node
             	AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
          std::string importName = removeXfoSuffix(iObj.getName());
			      pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
			      if(options.attachToExisting && pExistingNode){
				      pMaxNode = pExistingNode;
			      }//only create node if either attachToExisting is false or it is true and the object does not already exist
   				
			      int ret = createAlembicObject(mergedGeomChild, &pMaxNode, options, file);
			      if(ret != 0) return ret;
				  if( pMaxNode != NULL ) {
					ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, &mergedGeomChild, file, options);
					if(ret != 0) return ret;
				  }
   				
		      }
		      else{ //geometry node(s) under a dummy node (in pParentMaxNode)
			      pExistingNode = GetChildNodeFromName(iObj.getName(), pParentMaxNode);
			      if(options.attachToExisting && pExistingNode){
				      pMaxNode = pExistingNode;
			      }//only create node if either attachToExisting is false or it is true and the object does not already exist
   				
			      int ret = createAlembicObject(iObj, &pMaxNode, options, file);
			      if(ret != 0) return ret;

			      //since the transform is the identity, should position relative to parent
			      keepTM = 0;

			      //import identity matrix, since more than goemetry node share the same transform
			      //Should we just list MAX put a default position/scale/rotation controller on?

			      //	int ret = AlembicImport_XForm(pMaxNode, *piParentObj, file, options);
   				
		      }

			  if(options.failOnUnsupported ) {
				  if(!pMaxNode){
					  return alembic_failure;
				  }
			  }
         }

	   }

	   if(pMaxNode && pParentMaxNode && !pExistingNode){
		   pParentMaxNode->AttachChild(pMaxNode, keepTM);
	   }

	   progress.increment();
	   progress.update();

      if(pMaxNode){
	      for(size_t j=0; j<sElement.pObjectCache->childIdentifiers.size(); j++)
	      {
          AbcObjectCache *pChildObjectCache = &( pArchiveCache->find( sElement.pObjectCache->childIdentifiers[j] )->second );
		      if( NodeCategory::get( pChildObjectCache->obj ) == 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 it 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( mergedGeomNodeIndex != j ){
              sceneStack.push_back( stackElement( pChildObjectCache, pMaxNode) );
            }
	      } 
      }
   }

	return alembic_success;
}<commit_msg>issue #335 - fix for parenting to cameras, submitting early so that I can merge<commit_after>#include "stdafx.h"
#include "Alembic.h"
#include "AlembicArchiveStorage.h"
#include "AlembicMeshUtilities.h"
#include "AlembicSplineUtilities.h"
#include "AlembicXformUtilities.h"
#include "AlembicXformController.h"
#include "AlembicCameraUtilities.h"
#include "AlembicParticles.h"
#include "SceneEnumProc.h"
#include "AlembicDefinitions.h"
#include "AlembicWriteJob.h"
#include "AlembicRecursiveImporter.h"
#include "Utility.h"

#include "AlembicRecursiveImporter.h"



int createAlembicObject(AbcG::IObject& iObj, INode **pMaxNode, alembic_importoptions &options, std::string& file)
{
	int ret = alembic_success;
	//if(AbcG::IXform::matches(iObj.getMetaData())) //Transform
	//{
	//	ESS_LOG_INFO( "AlembicImport_XForm: " << objects[j].getFullName() );
	//	int ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); 
	//} 	
	if (AbcG::IPolyMesh::matches(iObj.getMetaData()) || 
		AbcG::ISubD::matches(iObj.getMetaData()) ) // PolyMesh / SubD
	{
		ESS_LOG_INFO( "AlembicImport_PolyMesh: " << iObj.getFullName() );
		ret = AlembicImport_PolyMesh(file, iObj, options, pMaxNode); 
	}
	else if (AbcG::ICamera::matches(iObj.getMetaData())) // Camera
	{
		ESS_LOG_INFO( "AlembicImport_Camera: " << iObj.getFullName() );
		ret = AlembicImport_Camera(file, iObj, options, pMaxNode);
	}
	else if (AbcG::IPoints::matches(iObj.getMetaData())) // Points
	{
		ESS_LOG_INFO( "AlembicImport_Points: " << iObj.getFullName() );
		ret = AlembicImport_Points(file, iObj, options, pMaxNode);
	}
	else if (AbcG::ICurves::matches(iObj.getMetaData())) // Curves
	{
		ESS_LOG_INFO( "AlembicImport_Shape: " << iObj.getFullName() );
		ret = AlembicImport_Shape(file, iObj, options, pMaxNode);
	}
   else // NURBS
	{
		if( options.failOnUnsupported ) {
			ESS_LOG_ERROR( "Alembic data type not supported: " << iObj.getFullName() );
			return alembic_failure;
		}
		else {
			ESS_LOG_WARNING( "Alembic data type not supported: " << iObj.getFullName() );
		}
	}
	return ret;
}

struct stackElement
{
   AbcObjectCache *pObjectCache;
   INode *pParentMaxNode;

   stackElement(AbcObjectCache *pMyObjectCache):pObjectCache(pMyObjectCache), pParentMaxNode(NULL)
   {}
   stackElement(AbcObjectCache *pMyObjectCache, INode* parent):pObjectCache(pMyObjectCache), pParentMaxNode(parent)
   {}


};

int importAlembicScene(AbcArchiveCache *pArchiveCache, AbcObjectCache *pRootObjectCache, alembic_importoptions &options, std::string& file, progressUpdate& progress, std::map<std::string, bool>& nodeFullPaths)
{
   std::vector<stackElement> sceneStack;
   sceneStack.reserve(200);
	for(size_t j=0; j<pRootObjectCache->childIdentifiers.size(); j++)
	{
      sceneStack.push_back(stackElement( &( pArchiveCache->find( pRootObjectCache->childIdentifiers[j] )->second ) ));
	} 

   while( !sceneStack.empty() )
   {
      stackElement sElement = sceneStack.back();
      sceneStack.pop_back();
      Abc::IObject& iObj = sElement.pObjectCache->obj;
      INode *pParentMaxNode = sElement.pParentMaxNode;

	   if(!iObj.valid()){
		   return alembic_failure;
	   }

	   const std::string fullname = iObj.getFullName();
	   const std::string pname = (pParentMaxNode) ? EC_MCHAR_to_UTF8( pParentMaxNode->GetName() ) : std::string("");
	   const std::string name = iObj.getName();

      ESS_LOG_INFO("Importing "<<fullname);

      bool bCreateDummyNode = false;
      int mergedGeomNodeIndex = -1;
      AbcObjectCache *pMergedObjectCache = NULL;
      getMergeInfo(pArchiveCache, sElement.pObjectCache, bCreateDummyNode, mergedGeomNodeIndex, &pMergedObjectCache);

      INode* pMaxNode = NULL;// the newly create node, which may be a merged node
      INode* pExistingNode = NULL;
      int keepTM = 1;//I don't remember why this needed to be set in some cases.

      bool bCreateNode = true;

      if(!nodeFullPaths.empty()){
         if(mergedGeomNodeIndex != -1){
        	AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
          bCreateNode = nodeFullPaths.find(mergedGeomChild.getFullName()) != nodeFullPaths.end(); 
         }
         else{
            bCreateNode = nodeFullPaths.find(fullname) != nodeFullPaths.end(); 
         }
      }

      if(bCreateNode){

          if(sElement.pObjectCache->childIdentifiers.size() > 1 && AbcG::ICamera::matches(iObj.getMetaData())){
             bCreateDummyNode = true;  
          }

	      if(bCreateDummyNode){

		      std::string importName = removeXfoSuffix(iObj.getName());

		      pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
		      if(options.attachToExisting && pExistingNode){
			      pMaxNode = pExistingNode;

			      //see if a controller already exists, and then delete it
   				
			      int ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options);
			      if(ret != 0) return ret;
		      }//only create node if either attachToExisting is false or it is true and the object does not already exist
		      else{
			      int ret = AlembicImport_DummyNode(iObj, options, &pMaxNode, importName);
			      if(ret != 0) return ret;

			      ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, NULL, file, options);
			      if(ret != 0) return ret;
		      }
	      }
	      else{
		      if(mergedGeomNodeIndex != -1){//we are merging, so look at the child geometry node
             	  AbcG::IObject mergedGeomChild = pMergedObjectCache->obj;
                  std::string importName = removeXfoSuffix(iObj.getName());
			      pExistingNode = GetChildNodeFromName(importName, pParentMaxNode);
			      if(options.attachToExisting && pExistingNode){
				      pMaxNode = pExistingNode;
			      }//only create node if either attachToExisting is false or it is true and the object does not already exist
   				
			      int ret = createAlembicObject(mergedGeomChild, &pMaxNode, options, file);
			      if(ret != 0) return ret;
				  if( pMaxNode != NULL ) {
					ret = AlembicImport_XForm(pParentMaxNode, pMaxNode, iObj, &mergedGeomChild, file, options);
					if(ret != 0) return ret;
				  }
   				
		      }
		      else{ //geometry node(s) under a dummy node (in pParentMaxNode)
			      pExistingNode = GetChildNodeFromName(iObj.getName(), pParentMaxNode);
			      if(options.attachToExisting && pExistingNode){
				      pMaxNode = pExistingNode;
			      }//only create node if either attachToExisting is false or it is true and the object does not already exist
   				
			      int ret = createAlembicObject(iObj, &pMaxNode, options, file);
			      if(ret != 0) return ret;

			      //since the transform is the identity, should position relative to parent
			      keepTM = 0;

                  if(pMaxNode == pExistingNode && AbcG::ICamera::matches(iObj.getMetaData()) ){
                      //apply camera adjustment matrix to the identity

                       Matrix3 rotation(TRUE);
                       rotation.RotateX(HALFPI);
                       TimeValue zero(0);
                       
		               if(pParentMaxNode != NULL){
			               pMaxNode->SetNodeTM(zero, rotation * pParentMaxNode->GetObjectTM(zero));
		               }
		               else{
			               pMaxNode->SetNodeTM(zero, rotation);
		               }
                  }

			      //import identity matrix, since more than goemetry node share the same transform
			      //Should we just list MAX put a default position/scale/rotation controller on?

			      //	int ret = AlembicImport_XForm(pMaxNode, *piParentObj, file, options);
   				
		      }

			  if(options.failOnUnsupported ) {
				  if(!pMaxNode){
					  return alembic_failure;
				  }
			  }
         }

	   }

	   if(pMaxNode && pParentMaxNode && !pExistingNode){
		   pParentMaxNode->AttachChild(pMaxNode, keepTM);
	   }

	   progress.increment();
	   progress.update();

      if(pMaxNode){
	      for(size_t j=0; j<sElement.pObjectCache->childIdentifiers.size(); j++)
	      {
          AbcObjectCache *pChildObjectCache = &( pArchiveCache->find( sElement.pObjectCache->childIdentifiers[j] )->second );
		      if( NodeCategory::get( pChildObjectCache->obj ) == 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 it 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( mergedGeomNodeIndex != j ){
              sceneStack.push_back( stackElement( pChildObjectCache, pMaxNode) );
            }
	      } 
      }
   }

	return alembic_success;
}
{'fraction_non_alphanumeric': 0.1125569680978652, 'fraction_numerical': 0.0023986567522187576, 'mean_word_length': 3.1630054917623567, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5803253', 'n_tokens_mistral': 5839, 'n_tokens_neox': 5280, 'n_words': 1197}