//-----------------------------------------------------------------------------
	ProgressManager::ProgressManager(size_t numberOfStages)
		:mNumberOfStages(numberOfStages), mProgress(0)
	{
		XSI::Application app;

		mProgressBar = app.GetUIToolkit().GetProgressBar();
		mProgressBar.PutMaximum(numberOfStages);
		mProgressBar.PutStep(1);
		mProgressBar.PutVisible(true);
		mProgressBar.PutCaption(L"Exporting");
	}
SI_Error SMDEnvelope::Write ( FILE* l_fptr, int rigid, SMDNodeList* in_pNodeList )
{

	CSIBCVector3D*	l_pPosition = NULL;
	CSIBCVector3D*	l_pNormal = NULL;
	CSIBCVector2D*	l_pUV = NULL;
	
	XSI::Primitive l_pPrim = m_pModel.GetActivePrimitive();
	
	if ( !l_pPrim.IsValid() )
		return SI_ERR_ERROR_MSG;

	XSI::Application app;

	XSI::UIToolkit kit = app.GetUIToolkit();
	XSI::ProgressBar	m_pBar = kit.GetProgressBar();
	
	m_pBar.PutMaximum( 100 );
	m_pBar.PutMinimum( 1 );
	m_pBar.PutStep( 1 );
	m_pBar.PutValue( 1 );
	m_pBar.PutCaption( L"Writing vertex data..." );
	m_pBar.PutStatusText( L"" );
	m_pBar.PutVisible( true );

	//
	// Get default texture name
	//

	char l_szDefaultTextureName[MAX_PATH];
	XSI::OGLTexture l_pDefaultTexture = m_pModel.GetMaterial().GetOGLTexture();

	if ( !l_pDefaultTexture.IsValid() )
	{
		XSILogMessage ( "Material on enveloped mesh has no texture!", XSI::siErrorMsg );
		sprintf ( l_szDefaultTextureName, "default.tga" );
	} else {

		W2AHelper2 ( l_szDefaultTextureName, l_pDefaultTexture.GetFullName().GetWideString() );
		
		char l_szTextureFile[MAX_PATH];
		char l_szTextureExt[MAX_PATH];
		
		_splitpath ( l_szDefaultTextureName, NULL, NULL, l_szTextureFile, l_szTextureExt );
		sprintf ( l_szDefaultTextureName, "%s%s",  l_szTextureFile, l_szTextureExt );
	}

	XSI::Geometry l_pGeo = l_pPrim.GetGeometry();
	XSI::CPointRefArray l_pPoints = l_pGeo.GetPoints();
	XSI::PolygonMesh l_pPolyMesh = l_pGeo;

	XSI::CPointRefArray pointRefArray(l_pPolyMesh.GetPoints());
	XSI::MATH::CVector3Array  positionArray(pointRefArray.GetPositionArray());
	XSI::CPolygonNodeRefArray nodeRefArray(l_pPolyMesh.GetNodes());
	XSI::MATH::CVector3Array  normalArray(nodeRefArray.GetNormalArray());

	//Take care of the UV's
	XSI::CRefArray		clusterRefArray;
	l_pPolyMesh.GetClusters().Filter(XSI::siSampledPointCluster,XSI::CStringArray(),L"",clusterRefArray);

	XSI::Cluster			samplePointClusterUV;
	XSI::CRefArray       uvClusterPropertiesRefArray;
	
	int i;
	for(i=0;i < clusterRefArray.GetCount(); i++)
	{
		XSI::Cluster cluster(clusterRefArray[i]);		
		if(cluster.GetProperties().Filter(XSI::siClsUVSpaceTxtType,XSI::CStringArray(), L"",uvClusterPropertiesRefArray) == XSI::CStatus::OK)
		{
			samplePointClusterUV = cluster;			
			break;
		}
	}

	XSI::ClusterProperty uvProp(uvClusterPropertiesRefArray[0]);
	XSI::CClusterPropertyElementArray uvElementArray = uvProp.GetElements();
	XSI::CDoubleArray uvValueArray = uvElementArray.GetArray();
	long lnbUV= (long)(uvValueArray.GetCount() / 3);

	//
	// Make sure that UVs are present
	//

	if ( !samplePointClusterUV.IsValid() )
	{
		XSILogMessage ( "Invalid .SMD: Enveloped mesh doesn't have any UVs.", XSI::siErrorMsg );

		return SI_ERR_ERROR_MSG;
	}

	m_pBar.PutCaption( L"Analyzing clusters..." );
	m_pBar.PutStatusText( L"" );
	m_pBar.PutVisible( true );


	SMDNode* in_pNode = in_pNodeList->GetByName ( m_pModel.GetFullName() );
	CSIBCArray < CSIBCVector3D >	l_pVertexNormals;
	ComputeVertexNormals ( l_pVertexNormals, l_pGeo );

	XSI::CRefArray		allClusters;
	l_pPolyMesh.GetClusters().Filter(L"poly",XSI::CStringArray(),L"",allClusters);

	CSIBCArray<MateriaList>	matList;
	
	for (int c=0;c<allClusters.GetCount();c++)
	{
		XSI::Cluster Thecluster = allClusters[c];
		XSI::Material l_pMat = Thecluster.GetMaterial();
		XSI::OGLTexture l_pTexture = l_pMat.GetOGLTexture();
		matList.Extend(1);

		if ( !l_pTexture.IsValid() )
		{
			char mess[1024];
			sprintf ( mess, "Cluster #%d has no texture! Bypassing.", c);
			XSILogMessage ( mess, XSI::siErrorMsg );
			continue;
		}

		W2AHelper2 ( matList[matList.GetUsed()-1].texture, l_pTexture.GetFullName().GetWideString() );

		char l_szTextureFile[MAX_PATH];
		char l_szTextureExt[MAX_PATH];

		_splitpath ( matList[matList.GetUsed()-1].texture, NULL, NULL, l_szTextureFile, l_szTextureExt );
		sprintf ( matList[matList.GetUsed()-1].texture, "%s%s",  l_szTextureFile, l_szTextureExt );


		XSI::CClusterElementArray clusterElementArray = Thecluster.GetElements();
		XSI::CLongArray values(clusterElementArray.GetArray());
		long countPolyIndices = values.GetCount();
		matList[matList.GetUsed()-1].polyIndices.Extend(countPolyIndices);
		for (int v=0;v<countPolyIndices;v++)
		{
			matList[matList.GetUsed()-1].polyIndices[v] = values[v];
		}
	}

	XSI::CTriangleRefArray tris = l_pPolyMesh.GetTriangles();

	
	m_pBar.PutCaption( L"Processing geometry..." );
	m_pBar.PutStatusText( L"" );
	m_pBar.PutVisible( true );

	long progress_value = 0;
	long last_progress_value = 0;

		int vindex = 0;
		int vii = 0;

		for (int v=0;v<tris.GetCount();v++)
		{
			progress_value = (long)(((float)v / (float)tris.GetCount()) * 100.0f);

			if ( progress_value != last_progress_value )
			{
				last_progress_value = progress_value;
				m_pBar.PutValue ( progress_value );
				
				if ( m_pBar.IsCancelPressed() )
				{
					if ( MessageBox ( NULL, "Cancelling the export will create a corrupted SMD file.\n\n Are you sure?", "Cancel Export", MB_YESNO|MB_ICONWARNING ) == IDYES )
					{
						break;
					} else {

						m_pBar.PutVisible( true );
					}

				}

			}
			
			XSI::Triangle tri = tris[v];

			char* textureName = l_szDefaultTextureName;

			long polyI = tri.GetPolygonIndex();

			for (int p=0;p<matList.GetUsed();p++)
			{
				bool found = false;

				for (int h=0;h<matList[p].polyIndices.GetUsed();h++)
				{
					if ( matList[p].polyIndices[h] == polyI )
					{
						textureName = matList[p].texture;
						found = true;
						break;
					}

				}

				if ( found )
					break;
			}


			for (int i=0;i<3;i++)
			{
				//
				// Build a vertex
				//

				CSIBCVector3D	l_vPosition = CSIBCVector3D( (float)tri.GetPositionArray()[i].GetX(), 
																(float)tri.GetPositionArray()[i].GetY(), 
																(float)tri.GetPositionArray()[i].GetZ() );

				XSI::CTriangleVertexRefArray vRef = tri.GetPoints();
				XSI::TriangleVertex l_vTriangleVertex = vRef[i];
				

				CSIBCVector3D	l_vNormal = CSIBCVector3D ( (float)l_vTriangleVertex.GetNormal().GetX(),
															(float)l_vTriangleVertex.GetNormal().GetY(),
															(float)l_vTriangleVertex.GetNormal().GetZ() );

				//if ( SMDType == 1 )
				//{
				//	l_vNormal	= l_pVertexNormals [ l_pVertexList[vii] ];
				//} 

				if (( SMDType == 0 ) || ( SMDType == 1 ))
				{
					CSIBCMatrix4x4 l_pResult = in_pNode->GetMatrix();

					l_pResult.Multiply ( l_vPosition, l_vPosition );
					l_pResult.Multiply ( l_vNormal, l_vNormal );
					l_vNormal = l_vNormal.Normalize();
					
				}

				XSI::CTriangleVertexRefArray l_TriRef = tri.GetPoints();
				XSI::CUVArray l_vuvArray = l_TriRef.GetUVArray();
				XSI::CUV l_uv = l_vuvArray[i];
				int c = l_vuvArray.GetCount();
				long vertexIndex = tri.GetIndexArray()[i];

				CSIBCVector2D	l_vUV;
				l_vUV.m_fX = (float)l_uv.u;
				l_vUV.m_fY = (float)l_uv.v;

				//
				// Build weight list
				//

				SMDVertex*	l_pWeights = m_pVertexList[vertexIndex];

				// not sure the line above works correclty, if not, uncomment
				// the code below
				//for (int w=0;w<m_pVertexList.GetUsed();w++)
				//{
				//	if ( m_pVertexList[w]->GetIndex() == vertexIndex )
				//	{
				//		l_pWeights = m_pVertexList[w];
				//		break;
				//		
				//	}

				//}

				vii++;
				
				//
				// Now output
				//

			
			//	XSI::OGLTexture l_pTexture = useMat.GetOGLTexture();

				if ( vindex == 0 )
				{
					fprintf ( l_fptr, "%s\n", textureName );
				}

				if ( !rigid )
				{
					CSIBCString l_szWeight;
					l_szWeight.Concat ( l_pWeights->GetNumWeights() );
					l_szWeight.Concat (" ");
					for (int f=0;f<l_pWeights->GetNumWeights();f++)
					{
						l_szWeight.Concat ( l_pWeights->GetWeight(f)->m_iBoneID );
						l_szWeight.Concat (" ");
						l_szWeight.Concat ( l_pWeights->GetWeight(f)->m_fWeight );
						l_szWeight.Concat (" ");
					}

					fprintf ( l_fptr, 
								"0 %f %f %f %f %f %f %f %f %s\n",
								l_vPosition.m_fX,
								l_vPosition.m_fY,
								l_vPosition.m_fZ,
								l_vNormal.m_fX,
								l_vNormal.m_fY,
								l_vNormal.m_fZ,
								l_vUV.m_fX,
								l_vUV.m_fY,
								l_szWeight.GetText());
				} else {

					fprintf ( l_fptr, 
								"%d %f %f %f %f %f %f %f %f \n",
								l_pWeights->GetWeight(0)->m_iBoneID,
								l_vPosition.m_fX,
								l_vPosition.m_fY,
								l_vPosition.m_fZ,
								l_vNormal.m_fX,
								l_vNormal.m_fY,
								l_vNormal.m_fZ,
								l_vUV.m_fX,
								l_vUV.m_fY
								);
				}



				vindex++;

				if ( vindex == 3 )
					vindex = 0;
			}

		}

		
	

	return SI_SUCCESS;
}