void OutputVertices( std::ofstream& in_mfw, CGeometryAccessor& in_ga, X3DObject& xobj)
{
	bar.PutStatusText( L"Vertices..." );
	
	// polygon vertex positions
	CDoubleArray vtxPosArray;
	CStatus st = in_ga.GetVertexPositions(vtxPosArray);
	st.AssertSucceeded( L"GetVertexPositions" );

	MATH::CTransformation localTransformation = xobj.GetKinematics().GetLocal().GetTransform();
	CString string = L"#begin " +  CString(in_ga.GetVertexCount()) + L" vertices\n";
	in_mfw << string.GetAsciiString();
	OutputArrayPositions( in_mfw, vtxPosArray, localTransformation );
	string = L"#end " +  CString(in_ga.GetVertexCount()) + L" vertices\n";
	in_mfw << string.GetAsciiString();
	in_mfw << "\n";

	if(Get3DCoatParam(L"bExpUV").GetValue())
	{
		// uv props: siClusterPropertyUVType
		CRefArray uvProps = in_ga.GetUVs();
		if(uvProps.GetCount() > 0)
		{
			OutputClusterPropertyValues( in_mfw, in_ga, uvProps );
		}
	}
	if(Get3DCoatParam(L"bExpNorm").GetValue())
	{

		// polygon node normals
		CFloatArray nodeArray;
		st = in_ga.GetNodeNormals(nodeArray);
		st.AssertSucceeded( L"GetNodeNormals" );

		//app.LogMessage(L"NormalArray: " + nodeArray.GetAsText());
		string = L"#begin " +  CString(in_ga.GetNodeCount()) + L" normals\n";
		in_mfw << string.GetAsciiString();
		OutputArray( in_mfw, nodeArray, 3,  L"vn " );
		string = L"#end " +  CString(in_ga.GetNodeCount()) + L" normals\n";
		in_mfw << string.GetAsciiString();
		in_mfw << "\n";
	}
}
void OutputPolygonComponents( std::ofstream& in_mfw, CGeometryAccessor& in_ga)
{
	// polygon node indices
	CLongArray polyNodeIdxArray;
	CStatus st = in_ga.GetNodeIndices(polyNodeIdxArray);
	st.AssertSucceeded( L"GetNodeIndices");
	
	//app.LogMessage(L"NodeIdx: " + polyNodeIdxArray.GetAsText());

	CLongArray polySizeArray;
	st = in_ga.GetPolygonVerticesCount(polySizeArray);
	st.AssertSucceeded( L"GetPolygonVerticesCount" );

	//app.LogMessage(L"GetPolygonVerticesCount: " + polySizeArray.GetAsText());

	// polygon vertex indices
	CLongArray polyVtxIdxArray;
	st = in_ga.GetVertexIndices(polyVtxIdxArray);
	st.AssertSucceeded( L"GetVertexIndices" );

	CString string = L"#begin " +  CString(in_ga.GetPolygonCount()) + L" faces\n";
	in_mfw << string.GetAsciiString();

	// get the material objects used by the mesh
	CRefArray materials = in_ga.GetMaterials();
	CRefArray uvProps = in_ga.GetUVs();

	// get the material indices used by each polygon
	CLongArray pmIndices;
	in_ga.GetPolygonMaterialIndices(pmIndices);

	CString prevMat = L"";
	CString curMat = L"";

	bar.PutMinimum(0);
	bar.PutMaximum(polySizeArray.GetCount());
	bar.PutStatusText(L"Faces...");

	bool bUV = (bool)Get3DCoatParam(L"bExpUV").GetValue();
	bool bNrm = (bool)Get3DCoatParam(L"bExpNorm").GetValue();
	bool bMtl = (bool)Get3DCoatParam(L"bExpMat").GetValue();
	bool bUVCnt	= (uvProps.GetCount() > 0)?true:false;
	CString strVertices;

	for (LONG i=0, offset=0; i < polySizeArray.GetCount(); i++)
	{	
		bar.PutValue(i);
		strVertices = "";
		strVertices += CString(polyVtxIdxArray[offset] + 1 + gVprev);// vertices idx[0]
		if(bUV && bUVCnt)
		{
			strVertices += L"/";
			//strVertices += CString(polyNodeIdxArray[offset] + 1 + gVtPrev);// texture nodes idx[0]
			strVertices += CString(g_aNodeIsland[offset] + 1 + gVtPrev);// texture nodes idx[0]
			
			if(bNrm)
			{
				strVertices += L"/";
				strVertices += CString(polyNodeIdxArray[offset] + 1 + gVnPrev);// normal vertices idx[0]
			}
		}
		else if(bNrm)
		{
			strVertices += L"//";
			strVertices += CString(polyNodeIdxArray[offset] + 1 + gVnPrev);// normal vertices idx[0]
		}

		for (LONG j=1; j<polySizeArray[i]; j++)
		{
			strVertices += L" ";
			strVertices += CString(polyVtxIdxArray[offset+j] + 1 + gVprev);// vertices idx[12]
			if(bUV && bUVCnt)
			{
				strVertices += L"/";
				//strVertices += CString(polyNodeIdxArray[offset+j] + 1 + gVtPrev);// texture nodes idx[12]
				strVertices += CString(g_aNodeIsland[offset+j] + 1 + gVtPrev);// texture nodes idx[0]
				
				if(bNrm)
				{
					strVertices += L"/";
					strVertices += CString(polyNodeIdxArray[offset+j] + 1 + gVnPrev);// normal vertices idx[12]
				}
			}
			else if(bNrm)
			{
				strVertices += L"//";
				strVertices += CString(polyNodeIdxArray[offset+j] + 1 + gVnPrev);// normal vertices idx[12]
			}
		}

		if(bMtl)
		{
			Material mat(materials[ pmIndices[i] ]);
			curMat = mat.GetName();
			if(curMat != prevMat)
			{
				in_mfw << "usemtl ";
				in_mfw << curMat.GetAsciiString();
				in_mfw << "\n";
				prevMat = curMat;
			}
		}

		in_mfw << "f ";
		in_mfw << strVertices.GetAsciiString();
		in_mfw << "\n";
		
		offset += polySizeArray[i];

		//bar.Increment();
	}
	string = L"#end " +  CString(in_ga.GetPolygonCount()) + L" faces\n";
	in_mfw << string.GetAsciiString();
	in_mfw << "\n";
}
void OutputClusterPropertyValues( std::ofstream& in_mfw,	CGeometryAccessor& in_ga, CRefArray& in_array)
{	
	LONG nVals = in_array.GetCount();
	double s;

	ClusterProperty cp(in_array[0]);

	CFloatArray valueArray;
	CBitArray flags;		
	cp.GetValues( valueArray, flags );

	LONG nValueSize = cp.GetValueSize();
	
	bar.PutValue(0);
	bar.PutStatusText(L"Optimize UV...");
	// polygon node indices
	CLongArray polyNodeIdxArray;
	CStatus st = in_ga.GetNodeIndices(polyNodeIdxArray);
	st.AssertSucceeded( L"GetNodeIndices");

	//app.LogMessage(L"polyNodeIdxArray: " + polyNodeIdxArray.GetAsText());
	g_aNodeIsland = polyNodeIdxArray;
	std::vector<float> newValueArray;
	newValueArray.clear();

	for ( LONG j=0; j < polyNodeIdxArray.GetCount(); j++)
	{	
		float u = valueArray[polyNodeIdxArray[j]*3];
		float v = valueArray[polyNodeIdxArray[j]*3+1];
		//app.LogMessage(L"u = " + CString(u)+ "; v = "+ CString(v));
		LONG nmb = 0;
		bool bIs = false;
		for ( ULONG k = 0; k < newValueArray.size(); k += 3 )
		{
			if(fabs(newValueArray.at(k) - u) < 0.000002 && fabs(newValueArray.at(k+1) - v) < 0.000002)
			{
				nmb = k/3;
				bIs = true;
				break;
				//app.LogMessage(L"Yarr!: g_aNodeIsland["+ CString(j)+"] = "+ CString(k/3));
			}
		}
		
		if(bIs)
		{
			g_aNodeIsland[j] = nmb;
			//app.LogMessage(L"Yarr!: g_aNodeIsland["+ CString(j)+"] = "+ CString(nmb));
		}
		else
		{
			newValueArray.push_back(u);
			newValueArray.push_back(v);
			newValueArray.push_back(0.0f);
			g_aNodeIsland[j] = (LONG)(newValueArray.size()/3-1);
			//app.LogMessage(L"g_aNodeIsland["+ CString(j)+"] = "+ CString(newValueArray.size()/3-1));
		}
	}

	in_mfw << "#begin ";
	in_mfw << CString((ULONG)newValueArray.size()/nValueSize).GetAsciiString();
	in_mfw << "\n";
	
	bar.PutStatusText(L"Clusters...");
	bar.PutMinimum(0);
	bar.PutMaximum((LONG)newValueArray.size()/nValueSize);
	for ( ULONG j=0; j < newValueArray.size(); j += nValueSize)
	{
		//bar.PutValue(j);
		s = newValueArray.at(j);
		CString strValues = FormatNumber(s);
		
		for ( LONG k=1; k<nValueSize; k++ )
		{
			s = newValueArray.at(j+k);
			strValues += L" " + FormatNumber(s);
		}
		
		in_mfw << "vt ";
		in_mfw << strValues.GetAsciiString();
		in_mfw << "\n";

		gVt++;
		bar.Increment();
	}
	CString string = L"#end " +  CString((ULONG)newValueArray.size()/nValueSize) + L"\n";
	in_mfw << string.GetAsciiString();
	in_mfw << "\n";
}
XSIPLUGINCALLBACK CStatus OutputMaterials( Selection& in_sel )
{
	// prepare the mtl file
	Project prj = app.GetActiveProject();
	Scene scn = prj.GetActiveScene();
	CString tmpLocation = Get3DCoatParam( L"tempLocation" ).GetValue();

	ULONG npos = tmpLocation.ReverseFindString(L".");
	CString substr = tmpLocation.GetSubString(0, npos+1);
	CString strOut = substr + L"mtl";	

	//app.LogMessage(L"strOut:" + strOut);

	std::ofstream matfw;
	matfw.open(strOut.GetAsciiString(), std::ios_base::out | std::ios_base::trunc);
	if (matfw.is_open())
	{
		CRefArray tempMats;

		for(int i=0; i< in_sel.GetCount(); i++)
		{
			X3DObject xobj(in_sel.GetItem(i));

			// Get a geometry accessor from the selected object	
			Primitive prim = xobj.GetActivePrimitive();
			PolygonMesh mesh = prim.GetGeometry();
			if (!mesh.IsValid()) return CStatus::False;

			CGeometryAccessor ga = mesh.GetGeometryAccessor();

			// get the material objects used by the mesh
			CRefArray materials = ga.GetMaterials();

			for (LONG n=0; n < materials.GetCount(); n++)
			{
				bar.PutStatusText( L"materials" );

				Material mat(materials[n]);
				bool inMats = false;
				//app.LogMessage(CString(n) +L" : "+ CString(i)+ L" :" + mat.GetName());

				for(int m = 0; m < tempMats.GetCount(); m++)
				{
					Material tmat(tempMats[m]);
					if(mat.GetName() == tmat.GetName())
					{
						inMats = true;
						break;
					}
				}

				//app.LogMessage(CString(inMats));

				if(!inMats)
				{
					CString string = L"newmtl " + mat.GetName() + L"\n";
					matfw << string.GetAsciiString();

					Parameter surf = mat.GetParameters().GetItem(L"surface");
					Shader lShader(surf.GetSource());
					//app.LogMessage(L"shader: " + lShader.GetFullName());
					//app.LogMessage(L"shader: " + lShader.GetProgID());
					if ( lShader.GetProgID() == L"Softimage.material-phong.1" )
					{
						float r, g, b, a;

						lShader.GetColorParameterValue(L"ambient", r, g, b, a );
						CString ka = L"Ka " + FormatNumber(r) + L" " + FormatNumber(g) + L" " + FormatNumber(b);
						lShader.GetColorParameterValue(L"diffuse", r, g, b, a );
						CString kd = L"Kd " + FormatNumber(r) + L" " + FormatNumber(g) + L" " + FormatNumber(b);
						lShader.GetColorParameterValue(L"specular", r, g, b, a );
						CString ks = L"Ks " + FormatNumber(r) + L" " + FormatNumber(g) + L" " + FormatNumber(b);
						float ns = lShader.GetParameterValue(L"shiny");
						float d = 1.0f;
						CValue illum = 2;

						matfw << ka.GetAsciiString();
						matfw << "\n";
						matfw << kd.GetAsciiString();
						matfw << "\n";
						matfw << ks.GetAsciiString();
						matfw << "\n";
						matfw << "Ns ";
						matfw << FormatNumber(ns).GetAsciiString();
						matfw << "\n";
						matfw << "d ";
						matfw << FormatNumber(d).GetAsciiString();
						matfw << "\n";
						matfw << "illum ";
						matfw << illum.GetAsText().GetAsciiString();
						matfw << "\n";

						Parameter diff = lShader.GetParameters().GetItem(L"diffuse");
						Shader lImageD(diff.GetSource());

						if (lImageD.GetProgID() == L"Softimage.txt2d-image-explicit.1")
						{
							Parameter tex = lImageD.GetParameters().GetItem(L"tex");
							ImageClip2 lTextureD(tex.GetSource());

							//app.LogMessage( L"Found texture shader: " + lTexture.GetFullName() + L", Class: " + lTexture.GetClassIDName() + L", Type: " + lTexture.GetType() );
							app.LogMessage(L"texture GetFileName: " + lTextureD.GetFileName());
							matfw << "map_Kd ";
							matfw << lTextureD.GetFileName().GetAsciiString();
							matfw << "\n";
						}

						Parameter spec = lShader.GetParameters().GetItem(L"specular");
						Shader lImageS(spec.GetSource());

						if (lImageS.GetProgID() == L"Softimage.txt2d-image-explicit.1")
						{
							Parameter tex = lImageD.GetParameters().GetItem(L"tex");
							ImageClip2 lTextureS(tex.GetSource());

							//app.LogMessage( L"Found texture shader: " + lTexture.GetFullName() + L", Class: " + lTexture.GetClassIDName() + L", Type: " + lTexture.GetType() );
							//app.LogMessage(L"texture GetFileName: " + lTexture.GetFileName());
							matfw << "map_Ks ";
							matfw << lTextureS.GetFileName().GetAsciiString();
							matfw << "\n";
						}
					}
					tempMats.Add(mat);
					matfw << "\n";
					matfw << "\n";
				}
			}		
		}
		matfw.close();
	}
	return CStatus::OK;
}
Beispiel #5
0
XSI::CStatus AlembicSubD::Save(double time)
{
   // store the transform
   Primitive prim(GetRef(REF_PRIMITIVE));
   bool globalSpace = GetJob()->GetOption(L"globalSpace");

   // query the global space
   CTransformation globalXfo;
   if(globalSpace)
      globalXfo = KinematicState(GetRef(REF_GLOBAL_TRANS)).GetTransform(time);
   CTransformation globalRotation;
   globalRotation.SetRotation(globalXfo.GetRotation());

   // store the metadata
   SaveMetaData(GetRef(REF_NODE),this);

   // check if the mesh is animated
   if(mNumSamples > 0) {
      if(!isRefAnimated(GetRef(REF_PRIMITIVE), false, globalSpace))
         return CStatus::OK;
   }

   // determine if we are a pure point cache
   bool purePointCache = (bool)GetJob()->GetOption(L"exportPurePointCache");

   // access the mesh
   PolygonMesh mesh = prim.GetGeometry(time);
   CVector3Array pos = mesh.GetVertices().GetPositionArray();
   LONG vertCount = pos.GetCount();

   // prepare the bounding box
   Abc::Box3d bbox;

   // allocate the points and normals
   std::vector<Abc::V3f> posVec(vertCount);
   for(LONG i=0;i<vertCount;i++)
   {
      if(globalSpace)
         pos[i] = MapObjectPositionToWorldSpace(globalXfo,pos[i]);
      posVec[i].x = (float)pos[i].GetX();
      posVec[i].y = (float)pos[i].GetY();
      posVec[i].z = (float)pos[i].GetZ();
      bbox.extendBy(posVec[i]);
   }

   // allocate the sample for the points
   if(posVec.size() == 0)
   {
      bbox.extendBy(Abc::V3f(0,0,0));
      posVec.push_back(Abc::V3f(FLT_MAX,FLT_MAX,FLT_MAX));
   }
   Abc::P3fArraySample posSample(&posVec.front(),posVec.size());

   // store the positions && bbox
   mSubDSample.setPositions(posSample);
   mSubDSample.setSelfBounds(bbox);

   customAttributes.exportCustomAttributes(mesh);

   // abort here if we are just storing points
   if(purePointCache)
   {
      if(mNumSamples == 0)
      {
         // store a dummy empty topology
         mFaceCountVec.push_back(0);
         mFaceIndicesVec.push_back(0);
         Abc::Int32ArraySample faceCountSample(&mFaceCountVec.front(),mFaceCountVec.size());
         Abc::Int32ArraySample faceIndicesSample(&mFaceIndicesVec.front(),mFaceIndicesVec.size());
         mSubDSample.setFaceCounts(faceCountSample);
         mSubDSample.setFaceIndices(faceIndicesSample);
      }

      mSubDSchema.set(mSubDSample);
      mNumSamples++;
      return CStatus::OK;
   }

   // check if we support changing topology
   bool dynamicTopology = (bool)GetJob()->GetOption(L"exportDynamicTopology");

   CPolygonFaceRefArray faces = mesh.GetPolygons();
   LONG faceCount = faces.GetCount();
   LONG sampleCount = mesh.GetSamples().GetCount();

   // create a sample look table
   LONG offset = 0;
   CLongArray sampleLookup(sampleCount);
   for(LONG i=0;i<faces.GetCount();i++)
   {
      PolygonFace face(faces[i]);
      CLongArray samples = face.GetSamples().GetIndexArray();
      for(LONG j=samples.GetCount()-1;j>=0;j--)
         sampleLookup[offset++] = samples[j];
   }

   // check if we should export the velocities
   if(dynamicTopology)
   {
      ICEAttribute velocitiesAttr = mesh.GetICEAttributeFromName(L"PointVelocity");
      if(velocitiesAttr.IsDefined() && velocitiesAttr.IsValid())
      {
         CICEAttributeDataArrayVector3f velocitiesData;
         velocitiesAttr.GetDataArray(velocitiesData);

         mVelocitiesVec.resize(vertCount);
         for(LONG i=0;i<vertCount;i++)
         {
            CVector3 vel;
            vel.PutX(velocitiesData[i].GetX());
            vel.PutY(velocitiesData[i].GetY());
            vel.PutZ(velocitiesData[i].GetZ());
            if(globalSpace)
               vel = MapObjectPositionToWorldSpace(globalRotation,vel);
            mVelocitiesVec[i].x = (float)vel.GetX();
            mVelocitiesVec[i].y = (float)vel.GetY();
            mVelocitiesVec[i].z = (float)vel.GetZ();
         }

         if(mVelocitiesVec.size() == 0)
            mVelocitiesVec.push_back(Abc::V3f(0,0,0));
         Abc::V3fArraySample sample = Abc::V3fArraySample(&mVelocitiesVec.front(),mVelocitiesVec.size());
         mSubDSample.setVelocities(sample);
      }
   }

   // if we are the first frame!
   if(mNumSamples == 0 || dynamicTopology)
   {
      // we also need to store the face counts as well as face indices
      if(mFaceIndicesVec.size() != sampleCount || sampleCount == 0)
      {
         mFaceCountVec.resize(faceCount);
         mFaceIndicesVec.resize(sampleCount);

         offset = 0;
         for(LONG i=0;i<faceCount;i++)
         {
            PolygonFace face(faces[i]);
            CLongArray indices = face.GetVertices().GetIndexArray();
            mFaceCountVec[i] = indices.GetCount();
            for(LONG j=indices.GetCount()-1;j>=0;j--)
               mFaceIndicesVec[offset++] = indices[j];
         }

         if(mFaceIndicesVec.size() == 0)
         {
            mFaceCountVec.push_back(0);
            mFaceIndicesVec.push_back(0);
         }
         Abc::Int32ArraySample faceCountSample(&mFaceCountVec.front(),mFaceCountVec.size());
         Abc::Int32ArraySample faceIndicesSample(&mFaceIndicesVec.front(),mFaceIndicesVec.size());

         mSubDSample.setFaceCounts(faceCountSample);
         mSubDSample.setFaceIndices(faceIndicesSample);
      }

      // set the subd level
      Property geomApproxProp;
      prim.GetParent3DObject().GetPropertyFromName(L"geomapprox",geomApproxProp);
      mSubDSample.setFaceVaryingInterpolateBoundary(geomApproxProp.GetParameterValue(L"gapproxmordrsl"));

      // also check if we need to store UV
      CRefArray clusters = mesh.GetClusters();
      if((bool)GetJob()->GetOption(L"exportUVs"))
      {
         CGeometryAccessor accessor = mesh.GetGeometryAccessor(siConstructionModeSecondaryShape);
         CRefArray uvPropRefs = accessor.GetUVs();

         // if we now finally found a valid uvprop
         if(uvPropRefs.GetCount() > 0)
         {
            // ok, great, we found UVs, let's set them up
            if(mNumSamples == 0)
            {
               mUvVec.resize(uvPropRefs.GetCount());
               if((bool)GetJob()->GetOption(L"indexedUVs"))
                  mUvIndexVec.resize(uvPropRefs.GetCount());

               // query the names of all uv properties
               std::vector<std::string> uvSetNames;
               for(LONG i=0;i< uvPropRefs.GetCount();i++)
                  uvSetNames.push_back(ClusterProperty(uvPropRefs[i]).GetName().GetAsciiString());

               Abc::OStringArrayProperty uvSetNamesProperty = Abc::OStringArrayProperty(
                  mSubDSchema, ".uvSetNames", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs() );
               Abc::StringArraySample uvSetNamesSample(&uvSetNames.front(),uvSetNames.size());
               uvSetNamesProperty.set(uvSetNamesSample);
            }

            // loop over all uvsets
            for(LONG uvI=0;uvI<uvPropRefs.GetCount();uvI++)
            {
               mUvVec[uvI].resize(sampleCount);
               CDoubleArray uvValues = ClusterProperty(uvPropRefs[uvI]).GetElements().GetArray();

               for(LONG i=0;i<sampleCount;i++)
               {
                  mUvVec[uvI][i].x = (float)uvValues[sampleLookup[i] * 3 + 0];
                  mUvVec[uvI][i].y = (float)uvValues[sampleLookup[i] * 3 + 1];
               }

               // now let's sort the normals 
               size_t uvCount = mUvVec[uvI].size();
               size_t uvIndexCount = 0;
               if((bool)GetJob()->GetOption(L"indexedUVs")) {
                  std::map<SortableV2f,size_t> uvMap;
                  std::map<SortableV2f,size_t>::const_iterator it;
                  size_t sortedUVCount = 0;
                  std::vector<Abc::V2f> sortedUVVec;
                  mUvIndexVec[uvI].resize(mUvVec[uvI].size());
                  sortedUVVec.resize(mUvVec[uvI].size());

                  // loop over all uvs
                  for(size_t i=0;i<mUvVec[uvI].size();i++)
                  {
                     it = uvMap.find(mUvVec[uvI][i]);
                     if(it != uvMap.end())
                        mUvIndexVec[uvI][uvIndexCount++] = (Abc::uint32_t)it->second;
                     else
                     {
                        mUvIndexVec[uvI][uvIndexCount++] = (Abc::uint32_t)sortedUVCount;
                        uvMap.insert(std::pair<Abc::V2f,size_t>(mUvVec[uvI][i],(Abc::uint32_t)sortedUVCount));
                        sortedUVVec[sortedUVCount++] = mUvVec[uvI][i];
                     }
                  }

                  // use indexed uvs if they use less space
                  mUvVec[uvI] = sortedUVVec;
                  uvCount = sortedUVCount;

                  sortedUVCount = 0;
                  sortedUVVec.clear();
               }

              AbcG::OV2fGeomParam::Sample uvSample(Abc::V2fArraySample(&mUvVec[uvI].front(),uvCount),AbcG::kFacevaryingScope);
               if(mUvIndexVec.size() > 0 && uvIndexCount > 0)
                  uvSample.setIndices(Abc::UInt32ArraySample(&mUvIndexVec[uvI].front(),uvIndexCount));

               if(uvI == 0)
               {
                  mSubDSample.setUVs(uvSample);
               }
               else
               {
                  // create the uv param if required
                  if(mNumSamples == 0)
                  {
                     CString storedUvSetName = CString(L"uv") + CString(uvI);
                     mUvParams.push_back(AbcG::OV2fGeomParam( mSubDSchema, storedUvSetName.GetAsciiString(), uvIndexCount > 0,
                                        AbcG::kFacevaryingScope, 1, GetJob()->GetAnimatedTs()));
                  }
                  mUvParams[uvI-1].set(uvSample);
               }
            }

            // create the uv options
            if(mUvOptionsVec.size() == 0)
            {
				mUvOptionsProperty = Abc::OFloatArrayProperty(mSubDSchema, ".uvOptions", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs() );

               for(LONG uvI=0;uvI<uvPropRefs.GetCount();uvI++)
               {
				  //ESS_LOG_ERROR( "Cluster Property child name: " << ClusterProperty(uvPropRefs[uvI]).GetFullName().GetAsciiString() );
				  //ESS_LOG_ERROR( "Cluster Property child type: " << ClusterProperty(uvPropRefs[uvI]).GetType().GetAsciiString() );
				  
				  ClusterProperty clusterProperty = (ClusterProperty) uvPropRefs[uvI];
				  bool subdsmooth = false;
				  if( clusterProperty.GetType() == L"uvspace") {
				      subdsmooth = (bool)clusterProperty.GetParameter(L"subdsmooth").GetValue();      
					 // ESS_LOG_ERROR( "subdsmooth: " << subdsmooth );
				  }

                  CRefArray children = clusterProperty.GetNestedObjects();
                  bool uWrap = false;
                  bool vWrap = false;
                  for(LONG i=0; i<children.GetCount(); i++)
                  {
                     ProjectItem child(children.GetItem(i));
                     CString type = child.GetType();
					// ESS_LOG_ERROR( "  Cluster Property child type: " << type.GetAsciiString() );
                     if(type == L"uvprojdef")
                     {
                        uWrap = (bool)child.GetParameter(L"wrap_u").GetValue();
                        vWrap = (bool)child.GetParameter(L"wrap_v").GetValue();
                        break;
                     }
                  }

                  // uv wrapping
                  mUvOptionsVec.push_back(uWrap ? 1.0f : 0.0f);
                  mUvOptionsVec.push_back(vWrap ? 1.0f : 0.0f);
				  mUvOptionsVec.push_back(subdsmooth ? 1.0f : 0.0f);
               }
               mUvOptionsProperty.set(Abc::FloatArraySample(&mUvOptionsVec.front(),mUvOptionsVec.size()));
            }
         }
      }

      // sweet, now let's have a look at face sets
      if(GetJob()->GetOption(L"exportFaceSets") && mNumSamples == 0)
      {
         for(LONG i=0;i<clusters.GetCount();i++)
         {
            Cluster cluster(clusters[i]);
            if(!cluster.GetType().IsEqualNoCase(L"poly"))
               continue;

            CLongArray elements = cluster.GetElements().GetArray();
            if(elements.GetCount() == 0)
               continue;

            std::string name(cluster.GetName().GetAsciiString());

            mFaceSetsVec.push_back(std::vector<Abc::int32_t>());
            std::vector<Abc::int32_t> & faceSetVec = mFaceSetsVec.back();
            for(LONG j=0;j<elements.GetCount();j++)
               faceSetVec.push_back(elements[j]);

            if(faceSetVec.size() > 0)
            {
              AbcG::OFaceSet faceSet = mSubDSchema.createFaceSet(name);
              AbcG::OFaceSetSchema::Sample faceSetSample(Abc::Int32ArraySample(&faceSetVec.front(),faceSetVec.size()));
               faceSet.getSchema().set(faceSetSample);
            }
         }
      }

      // save the sample
      mSubDSchema.set(mSubDSample);

      // check if we need to export the bindpose
      if(GetJob()->GetOption(L"exportBindPose") && prim.GetParent3DObject().GetEnvelopes().GetCount() > 0 && mNumSamples == 0)
      {
         mBindPoseProperty = Abc::OV3fArrayProperty(mSubDSchema, ".bindpose", mSubDSchema.getMetaData(), GetJob()->GetAnimatedTs());

         // store the positions of the modeling stack into here
         PolygonMesh bindPoseGeo = prim.GetGeometry(time, siConstructionModeModeling);
         CVector3Array bindPosePos = bindPoseGeo.GetPoints().GetPositionArray();
         mBindPoseVec.resize((size_t)bindPosePos.GetCount());
         for(LONG i=0;i<bindPosePos.GetCount();i++)
         {
            mBindPoseVec[i].x = (float)bindPosePos[i].GetX();
            mBindPoseVec[i].y = (float)bindPosePos[i].GetY();
            mBindPoseVec[i].z = (float)bindPosePos[i].GetZ();
         }

         Abc::V3fArraySample sample;
         if(mBindPoseVec.size() > 0)
            sample = Abc::V3fArraySample(&mBindPoseVec.front(),mBindPoseVec.size());
         mBindPoseProperty.set(sample);
      }   
   }
   else
   {
      mSubDSchema.set(mSubDSample);
   }

   mNumSamples++;

   return CStatus::OK;
}