Abc::C4f AlembicPoints::GetColor(IParticleObjectExt *pExt, int particleId,
                                 TimeValue ticks)
{
  Abc::C4f color(0.5, 0.5, 0.5, 1.0);

  // Go into the particle's action list
  INode *particleGroupNode = pExt->GetParticleGroup(particleId);
  Object *particleGroupObj = (particleGroupNode != NULL)
                                 ? particleGroupNode->EvalWorldState(ticks).obj
                                 : NULL;

  if (!particleGroupObj) {
    return color;
  }

  IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);
  INode *particleActionListNode = particleGroup->GetActionList();
  Object *particleActionObj =
      (particleActionListNode != NULL
           ? particleActionListNode->EvalWorldState(ticks).obj
           : NULL);

  if (!particleActionObj) {
    return color;
  }

  PFSimpleOperator *pSimpleOperator = NULL;

  // In the case of multiple shape operators in an action list, the one furthest
  // down the list seems to be the one that applies
  IPFActionList *particleActionList =
      GetPFActionListInterface(particleActionObj);

  for (int p = particleActionList->NumActions() - 1; p >= 0; p -= 1) {
    INode *pActionNode = particleActionList->GetAction(p);
    Object *pActionObj =
        (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

    if (pActionObj == NULL) {
      continue;
    }

    if (pActionObj->ClassID() == PFOperatorDisplay_Class_ID) {
      pSimpleOperator = static_cast<PFSimpleOperator *>(pActionObj);
      break;
    }
  }

  if (pSimpleOperator) {
    IParamBlock2 *pblock = pSimpleOperator->GetParamBlockByID(0);
    Point3 c = pblock->GetPoint3(kDisplay_color);
    color.r = c.x;
    color.g = c.y;
    color.b = c.z;
    color.a = 1.0;
  }

  return color;
}
void AlembicPoints::GetShapeType(IParticleObjectExt *pExt, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime)
{
    // Set up initial values
    type = ShapeType_Point;
    instanceId = 0;
    animationTime = 0.0f;

    // Go into the particle's action list
    INode *particleGroupNode = pExt->GetParticleGroup(particleId);
    Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL;

	if (!particleGroupObj){
        return;
	}

    IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj);
    INode *particleActionListNode = particleGroup->GetActionList();
    Object *particleActionObj = (particleActionListNode != NULL ? particleActionListNode->EvalWorldState(ticks).obj : NULL);

	if (!particleActionObj){
        return;
	}
	
    PFSimpleOperator *pSimpleOperator = NULL;

	//In the case of multiple shape operators in an action list, the one furthest down the list seems to be the one that applies
    IPFActionList *particleActionList = GetPFActionListInterface(particleActionObj);
	
	for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
	{
		INode *pActionNode = particleActionList->GetAction(p);
		Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

		if (pActionObj == NULL){
			continue;
		}

		if (pActionObj->ClassID() == PFOperatorSimpleShape_Class_ID){
			pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj);
			break;
		}else if(pActionObj->ClassID() == PFOperatorShapeLib_Class_ID){
			pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj);
			break;
		}else if(pActionObj->ClassID() == PFOperatorInstanceShape_Class_ID){
			pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj);
			break;
		}else if(pActionObj->ClassID() == PFOperatorMarkShape_Class_ID){
			pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj);
			break;
		}else if(pActionObj->ClassID() == PFOperatorFacingShape_Class_ID){
			pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj);
			break;
		}
	}

	

	for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1)
	{
		INode *pActionNode = particleActionList->GetAction(p);
		Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL);

		if (pActionObj == NULL){
			continue;
		}

		IPFTest* pTestAction = GetPFTestInterface(pActionObj);

		if (pTestAction){
			
			INode* childActionListNode = pTestAction->GetNextActionList(pActionNode, NULL);

			if(childActionListNode){
				AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(childActionListNode);

				//create a cache entry if necessary
				if(actionListIt == mPerActionListShapeMap.end()){
					mPerActionListShapeMap[childActionListNode] = AlembicPoints::shapeInfo();
				}
				AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[childActionListNode];
				
				if(!sInfo.pParentActionList){
					sInfo.pParentActionList = particleActionListNode;
				}
			}
		}
	}

	ReadShapeFromOperator(particleGroup, pSimpleOperator, particleId, ticks, type, instanceId, animationTime);

	if(type != ShapeType_NbElements){//write the shape to the cache

		// create cache entry for the current action list node, and then fill in the shape info
		// we will fill in the parent later

		AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(particleActionListNode);

		//create a cache entry if necessary
		if(actionListIt == mPerActionListShapeMap.end()){
			mPerActionListShapeMap[particleActionListNode] = AlembicPoints::shapeInfo();
		}
		AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[particleActionListNode];
		
		//if(sInfo.type == ShapeType_NbElements){
		//	sInfo.type = type;
		//	sInfo.animationTime = animationTime;
		//	if(sInfo.type == ShapeType_Instance){
		//		sInfo.instanceName = mInstanceNames[instanceId];
		//	}
		//}
	}
	else{ //read the shape from the cache

		AlembicPoints::shapeInfo sInfo;
		INode* currActionNode = particleActionListNode;
		
		//search for shape along path from this node to the root node
		const int MAX_DEPTH = 10; //just in case there is an infinite loop due a bug
		int i = 0;
		while(currActionNode && sInfo.type == ShapeType_NbElements && i<MAX_DEPTH){

			AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(currActionNode);
			if(actionListIt != mPerActionListShapeMap.end()){
				sInfo = actionListIt->second;
			}

			currActionNode = sInfo.pParentActionList;
			i++;
		}

		if(sInfo.type != ShapeType_NbElements){//We have found shape, so add it to the list if necessary

			// Find if the name is alerady registered, otherwise add it to the list
			//instanceId = FindInstanceName(sInfo.instanceName);
			//if (instanceId == USHRT_MAX)
			//{
			//	mInstanceNames.push_back(sInfo.instanceName);
			//	instanceId = (Abc::uint16_t)mInstanceNames.size()-1;
			//}
			//type = sInfo.type;
		}
		else{
			int nBornIndex = pExt->GetParticleBornIndex(particleId);
			ESS_LOG_INFO("Could not determine shape type for particle with born index: "<<nBornIndex<<". Defaulting to point.");
 			type = ShapeType_Point;
		}
	}
}