示例#1
0
ViewShape::ViewShape(const ShapeObject& other)
	: index(other.GetIndex())
	, type(other.GetType())
	, offset(0)
	, length(other.GetVertexCount())
	, bounds(other.GetBounds())
{
	std::vector<ShapeObject::Part> other_parts = other.GetParts();
	for (auto part : other_parts) {
		parts.push_back(ViewPart(part.type, part.offset, part.length));
	}
}
bool SplineData::UpdateNode(INode *node)
{
	if (mReset)
	{
		mReset = false;
		return AddNode(node);
	}
	else
	{
		TimeValue t  = GetCOREInterface()->GetTime();
		Interval valid;
		Matrix3 tm = node->GetObjectTM(t,&valid);
		ObjectState nos = node->EvalWorldState(t);
		//make sure it is a shape
		if (nos.obj->IsShapeObject()) 
		{
			ShapeObject *pathOb = (ShapeObject*)nos.obj;
			pathOb->MakePolyShape(t, mShapeCache,32,FALSE);
			mShapeCache.Transform(tm);
			int numberOfCurves = pathOb->NumberOfCurves();
			for (int i = 0; i < numberOfCurves; i++)
			{
				//just rebuild our cache info
				mSplineElementData[i]->ResetBoundingBox();
				mSplineElementData[i]->SetLineCache(&mShapeCache.lines[i]);
				mSplineElementData[i]->ComputePlanarUp(mPlanarMapUp);
				if (pathOb->CurveClosed(t,i))
					mSplineElementData[i]->SetClosed(true);
				else mSplineElementData[i]->SetClosed(false);

				mSplineElementData[i]->Select(FALSE);
			}
			//now rebuild our derived cross sections
			RecomputeCrossSections();
			if (mActiveSpline >= numberOfCurves)
				mActiveSpline = 0;
			mSplineElementData[mActiveSpline]->Select(TRUE);
			return true;
		}
	}
	return false;
}
bool Aliens::isHitBy(const ShapeObject& object)
{
    if( ! object.isVisible())
    {
        return false;
    }

    std::vector<Alien>::iterator i = std::find_if(aliens_.begin(), aliens_.end(), Overlap(object.getBoundary()));

    if(i == aliens_.end())
    {
        return false;
    }

    aliens_.erase(i);
    return true;
}
bool SplineData::AddNode(INode *node)
{
	//see if the node is a shape object
	if (node != NULL) 
	{
		TimeValue t  = GetCOREInterface()->GetTime();
		Interval valid;
		Matrix3 tm = node->GetObjectTM(t,&valid);
		ObjectState nos = node->EvalWorldState(t);
		if (nos.obj->IsShapeObject()) 
		{
			ShapeObject *pathOb = (ShapeObject*)nos.obj;
			int numberOfCurves = pathOb->NumberOfCurves();
			//get number of splines
			if (numberOfCurves != 0) 
			{
				pathOb->MakePolyShape(t, mShapeCache,32,FALSE);
				mShapeCache.Transform(tm);
				mSplineElementData.SetCount(numberOfCurves);
				for (int i = 0; i < numberOfCurves; i++)
					mSplineElementData[i] = NULL;

				for (int i = 0; i < numberOfCurves; i++)
				{

					Box3 bounds;
					bounds.Init();

					//sample the shape object
					int numberOfCurves = pathOb->NumberOfPieces(t, i);
					if (numberOfCurves != 0)
					{

						mSplineElementData[i] = new SplineElementData();
						
						mSplineElementData[i]->ResetBoundingBox();
						mSplineElementData[i]->SetLineCache(&mShapeCache.lines[i]);
						mSplineElementData[i]->ComputePlanarUp(mPlanarMapUp);
						mSplineElementData[i]->SetNumCurves(numberOfCurves);
						mSplineElementData[i]->SetNumberOfCrossSections(numberOfCurves+1);
						if (pathOb->CurveClosed(t,i))
							mSplineElementData[i]->SetClosed(true);
						else mSplineElementData[i]->SetClosed(false);
						float curveLength = pathOb->LengthOfCurve(t,i);

						float runningLength = 0.0f;
						Quat q;
						q.Identity();
						mSplineElementData[i]->SetCrossSection(0,Point3(0.0f,0.0f,0.0f),Point2(20.0f,20.0f),q);
						for (int j = 0; j < numberOfCurves; j++)
						{
							float u = runningLength/curveLength;
							mSplineElementData[i]->SetCrossSection(j,Point3(0.0f,0.0f,u),Point2(20.0f,20.0f),q);
							Point3 lastPoint = pathOb->InterpPiece3D(t,i,j,0.0f,PARAM_NORMALIZED);
							bounds += lastPoint;
							float runningU = 0.0f;
							float inc = 1.0f/(float)(mSampleRate-1);
							for (int k = 1; k < mSampleRate; k++)
							{								
								runningU += inc;
								Point3 p = pathOb->InterpPiece3D(t,i,j,runningU,PARAM_NORMALIZED);
								runningLength += Length(p-lastPoint);
								lastPoint = p;
								bounds += lastPoint;
							}


						}

						mSplineElementData[i]->SetCrossSection(numberOfCurves,Point3(0.0f,0.0f,1.0f),Point2(20.0f,20.0f),q);
						mSplineElementData[i]->Select(FALSE);

					}
				}

				if (mActiveSpline >= numberOfCurves)
					mActiveSpline = 0;
				mSplineElementData[mActiveSpline]->Select(TRUE);

				//build our bounding box
				RecomputeCrossSections();

				return true;
			}
		}
	}

	return false;

}
示例#5
0
void SolidifyPW::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node) 
{

	//TODO: Add the code for actually modifying the object
	meshInfo.Free();

	if (os->obj->IsSubClassOf(triObjectClassID)) {
		TriObject *tobj = (TriObject*)os->obj;
		Mesh &mesh = tobj->GetMesh();
		Interval iv = FOREVER;
		float a,oa;
		
		pblock->GetValue(pb_amount,t,a,iv);
		pblock->GetValue(pb_oamount,t,oa,iv);

		if (a == oa)
			oa += 0.00001f;

		BOOL overrideMatID;
		int matid;

		pblock->GetValue(pb_overridematid,t,overrideMatID,iv);
		pblock->GetValue(pb_matid,t,matid,iv);
		matid--;

		if (!overrideMatID) matid = -1;


		BOOL overridesg;
		int sg;
		pblock->GetValue(pb_overridesg,t,overridesg,iv);
		pblock->GetValue(pb_sg,t,sg,iv);
		

		if (!overridesg) sg = -1;

		int edgeMap;
		pblock->GetValue(pb_edgemap,t,edgeMap,iv);

		float tvOffset;
		pblock->GetValue(pb_tvoffset,t,tvOffset,iv);


		BOOL ioverrideMatID;
		int imatid;

		pblock->GetValue(pb_overrideinnermatid,t,ioverrideMatID,iv);
		pblock->GetValue(pb_innermatid,t,imatid,iv);
		imatid--;

		if (!ioverrideMatID) imatid = -1;


		BOOL ooverrideMatID;
		int omatid;

		pblock->GetValue(pb_overrideoutermatid,t,ooverrideMatID,iv);
		pblock->GetValue(pb_outermatid,t,omatid,iv);
		omatid--;

		if (!ooverrideMatID) omatid = -1;


		BOOL selEdges, selInner,selOuter;

		static BOOL selEdgesPrev = FALSE;
		static BOOL selInnerPrev = FALSE;
		static BOOL selOuterPrev = FALSE;
		
		BOOL updateUI = FALSE;
		
		pblock->GetValue(pb_seledges,t,selEdges,iv);
		pblock->GetValue(pb_selinner,t,selInner,iv);
		pblock->GetValue(pb_selouter,t,selOuter,iv);
		
		if (selEdges && (!selEdgesPrev))
			updateUI = TRUE;
		if (selInner && (!selInnerPrev))
			updateUI = TRUE;
		if (selOuter && (!selOuterPrev))
			updateUI = TRUE;
			
		selEdgesPrev = selEdges;
		selInnerPrev = selInner;			
		selOuterPrev = selOuter;			

		if (selEdges || selInner|| selOuter)
			{
			mesh.dispFlags = DISP_SELFACES;
			mesh.selLevel = MESH_FACE;
			}



		int segments = 1;

		pblock->GetValue(pb_segments,t,segments,iv);
		if (segments < 1) segments = 1;


		BOOL fixupCorners;
		pblock->GetValue(pb_fixupcorners,t,fixupCorners,iv);


		BOOL autoSmooth;
		float smoothAngle;
		pblock->GetValue(pb_autosmooth,t,autoSmooth,iv);
		pblock->GetValue(pb_autosmoothangle,t,smoothAngle,iv);

		BOOL bevel;
		INode *node;
		pblock->GetValue(pb_bevel,t,bevel,iv);
		pblock->GetValue(pb_bevelshape,t,node,iv);

		PolyShape shape;
		if ((bevel) && node)
		{
			ObjectState nos = node->EvalWorldState(t);
			if (nos.obj->IsShapeObject()) 
			{
				ShapeObject *pathOb = (ShapeObject*)nos.obj;

				if (!pathOb->NumberOfCurves()) 
				{
					bevel = FALSE;
				}
				else
				{
					pathOb->MakePolyShape(t, shape,PSHAPE_BUILTIN_STEPS,TRUE);
					if (shape.lines[0].IsClosed())
						bevel = FALSE;

;
				}
			
			}
		}


		DWORD selLevel = mesh.selLevel;
		
		mesh.faceSel.ClearAll();

		if (bevel)
			meshInfo.MakeSolid(&mesh,segments, a,oa,matid, sg,edgeMap,tvOffset,imatid,omatid,selEdges,selInner,selOuter,fixupCorners,autoSmooth,smoothAngle,&shape.lines[0]);
		else meshInfo.MakeSolid(&mesh,segments, a,oa,matid, sg,edgeMap,tvOffset,imatid,omatid,selEdges,selInner,selOuter,fixupCorners,autoSmooth,smoothAngle,NULL);

		
		mesh.selLevel = selLevel;

		mesh.InvalidateTopologyCache ();


		for (int i = 0; i < mesh.numFaces; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				int index = mesh.faces[j].v[j];
				if ((index < 0) || (index >= mesh.numVerts))
					DebugPrint(_T("Invalid face %d(%d) %d\n"),i,j,index);
			}
		}
		
		int numMaps = mesh.getNumMaps();


		for (int mp = -NUM_HIDDENMAPS; mp < numMaps; mp++)
		{

			if (!mesh.mapSupport(mp)) continue;
			Point3 *uvw = mesh.mapVerts(mp);
			TVFace *uvwFace = mesh.mapFaces(mp);

			if ((uvw) && (uvwFace))
			{
				int numberTVVerts = mesh.getNumMapVerts(mp);
				for (int i = 0; i < mesh.numFaces; i++)
				{
					for (int j = 0; j < 3; j++)
					{
						int index = uvwFace[i].t[j];
						if ((index < 0) || (index >= numberTVVerts))
							DebugPrint(_T("Invalid Map %d tvface %d(%d) %d\n"),mp,i,j,index);
					}
				}

			}
		}



		os->obj->UpdateValidity(GEOM_CHAN_NUM,iv);
		os->obj->UpdateValidity(TOPO_CHAN_NUM,iv);
		
		MeshNormalSpec *pNormSpec = (MeshNormalSpec *) mesh.GetInterface (MESH_NORMAL_SPEC_INTERFACE);
		if (pNormSpec && pNormSpec->GetNumFaces() > 0)
		{
			pNormSpec->SetParent(&mesh);
			pNormSpec->BuildNormals();
			pNormSpec->ComputeNormals();
		}

		if ((updateUI) && (ip))
		{
			ip->PipeSelLevelChanged();
		}
		}
	EnableUIControls();

}
bool Aliens::hits(const ShapeObject& object)
{
    return std::find_if(bullets_.begin(), bullets_.end(), Overlap(object.getBoundary())) != bullets_.end();
}
 bool operator() (const ShapeObject& object)
 {
     return object.getBoundary().overlapsWith(boundary);
 }
示例#8
0
//=============================================================================================
NL3D::IShape *CExportNel::buildRemanence(INode& node, TimeValue time)
{
	std::auto_ptr<CSegRemanenceShape> srs(new CSegRemanenceShape);
	uint  numSlices = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SLICE_NUMBER, 2);
	float samplingPeriod = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SAMPLING_PERIOD, 0.02f);
	float rollupRatio    = getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_ROLLUP_RATIO, 1.f);

	if (samplingPeriod <= 0.f) samplingPeriod = 0.02f;
	if (numSlices <= 2) numSlices = 2;
	if (rollupRatio <= 0) rollupRatio = 1.f;
	
	srs->setNumSlices((uint32) numSlices);
	srs->setSliceTime(samplingPeriod);
	srs->setRollupRatio(rollupRatio);

	// get material from this node
	std::vector<NL3D::CMaterial> materials;
	CMaxMeshBaseBuild mmbb;
	buildMaterials(materials, mmbb, node, time);
	if (materials.size() != 1)
	{	
		buildRemanenceError(this, node, "The remanent segment %s should have a single material");
		return NULL;
	}
	srs->setMaterial(materials[0]);
	// 
	// get geometry

	ObjectState os = node.EvalWorldState(_Ip->GetTime());		
	Object *obj = node.EvalWorldState(time).obj;	
	if (obj->SuperClassID() != SHAPE_CLASS_ID)
	{
		buildRemanenceError(this, node, "Can't get curves from %s");
		return NULL;
	}
	
	ShapeObject *so = (ShapeObject *) obj;	
	if (so->NumberOfCurves() != 1 || so->NumberOfPieces(time, 0) == 0)
	{
		buildRemanenceError(this, node, "Remanence export : %s should only contain one curve with at least one segment!");		
		return NULL;
	}

	int numPieces = so->NumberOfPieces(time, 0);
	srs->setNumCorners(numPieces + 1);

	// build offset matrix
	Matrix3 invNodeTM = node.GetNodeTM(time);
	invNodeTM.Invert();

	// Get the object matrix
	Matrix3 objectTM = node.GetObjectTM(time);

	// Compute the local to world matrix
	Matrix3 objectToLocal = objectTM*invNodeTM;	


	for(uint k = 0; k <= (uint) numPieces; ++k)
	{
		Point3 pos;		
		pos = (k == 0) ? so->InterpPiece3D(time, 0, 0, 0.f)
					   : so->InterpPiece3D(time, 0, k - 1, 1.f);		
		NLMISC::CVector nelPos;		
		convertVector(nelPos, objectToLocal * pos);
		srs->setCorner(k, nelPos);
	}

	
	srs->setTextureShifting(CExportNel::getScriptAppData (&node, NEL3D_APPDATA_REMANENCE_SHIFTING_TEXTURE, 0) != 0);	


	if (CExportNel::getScriptAppData (&node, NEL3D_APPDATA_EXPORT_ANIMATED_MATERIALS, 0) != 0)
	{
		srs->setAnimatedMaterial(mmbb.MaterialInfo[0].MaterialName);
	}					
	

	// ********************************
	// *** Export default transformation
	// ********************************

	// Get the node matrix
	Matrix3 localTM;
	getLocalMatrix (localTM, node, time);

	// Get the translation, rotation, scale of the node
	CVector pos, scale;
	CQuat rot;
	decompMatrix (scale, rot, pos, localTM);

	// Set the default values
	srs->getDefaultPos()->setDefaultValue(pos);					
	srs->getDefaultScale()->setDefaultValue(scale);					
	srs->getDefaultRotQuat()->setDefaultValue(rot);


	return srs.release();

	/*ObjectState os = node.EvalWorldState(_Ip->GetTime());		
	Object *obj = node.EvalWorldState(time).obj;	
	TriObject *tri = (TriObject *) obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0));	
	bool deleteIt=false;
	if (obj != tri) 
		deleteIt = true;
	Mesh *pMesh = &tri->mesh;
	if (pMesh && pMesh->numVerts > 1) 
	{
	  	Point3 v = pMesh->getVert(0);
		NLMISC::CVector minV, maxV;
		convertVector(minV, v);
		maxV = minV;
		for(uint k = 1; k < (uint) pMesh->numVerts; ++k)
		{
			NLMISC::CVector nv;
			v = pMesh->getVert(k);
			convertVector(nv, v);
			maxV.maxof(maxV, nv);
			minV.minof(minV, nv);
		}
		srs->setSeg(0, minV);
		srs->setSeg(1, maxV);	
	}
	else
	{
		buildRemanenceError(this, node, "Can't get mesh from %s or empty mesh");
	}*/

	//	
}
示例#9
0
bool AlembicCurves::Save(double time, bool bLastFrame)
{
    ESS_PROFILE_FUNC();

    //TimeValue ticks = GET_MAX_INTERFACE()->GetTime();
    TimeValue ticks = GetTimeValueFromFrame(time);
	Object *obj = mMaxNode->EvalWorldState(ticks).obj;
	if(mNumSamples == 0){
		bForever = CheckIfObjIsValidForever(obj, ticks);
	}
	else{
		bool bNewForever = CheckIfObjIsValidForever(obj, ticks);
		if(bForever && bNewForever != bForever){
			ESS_LOG_INFO( "bForever has changed" );
		}
	}

	SaveMetaData(mMaxNode, this);

    // check if the spline is animated
    if(mNumSamples > 0) 
    {
        if(bForever)
        {
            return true;
        }
    }

    AbcG::OCurvesSchema::Sample curvesSample;

	std::vector<AbcA::int32_t> nbVertices;
    std::vector<Point3> vertices;
    std::vector<float> knotVector;
    std::vector<Abc::uint16_t> orders;

    if(obj->ClassID() == EDITABLE_SURF_CLASS_ID){

       NURBSSet nurbsSet;   
       BOOL success = GetNURBSSet(obj, ticks, nurbsSet, TRUE);   

       AbcG::CurvePeriodicity cPeriod = AbcG::kNonPeriodic;
       AbcG::CurveType cType = AbcG::kCubic;
       AbcG::BasisType cBasis = AbcG::kNoBasis;

       int n = nurbsSet.GetNumObjects();
       for(int i=0; i<n; i++){
          NURBSObject* pObject = nurbsSet.GetNURBSObject((int)i);

          //NURBSType type = pObject->GetType();
          if(!pObject){
             continue;
          }

          if( pObject->GetKind() == kNURBSCurve ){
             NURBSCurve* pNurbsCurve = (NURBSCurve*)pObject;

             int degree;
             int numCVs;
             NURBSCVTab cvs;
			 int numKnots;
		     NURBSKnotTab knots;
             pNurbsCurve->GetNURBSData(ticks, degree, numCVs, cvs, numKnots, knots);

             orders.push_back(degree+1);

             const int cvsCount = cvs.Count();
             const int knotCount = knots.Count();

             for(int j=0; j<cvs.Count(); j++){
                NURBSControlVertex cv = cvs[j];
                double x, y, z;
                cv.GetPosition(ticks, x, y, z);
                vertices.push_back( Point3((float)x, (float)y, (float)z) );
             }

             nbVertices.push_back(cvsCount);

             //skip the first and last entry because Maya and XSI use this format
             for(int j=1; j<knots.Count()-1; j++){
                knotVector.push_back((float)knots[j]);
             }

             if(i == 0){
                if(pNurbsCurve->IsClosed()){
                   cPeriod = AbcG::kPeriodic;
                }  
             }
             else{
                if(pNurbsCurve->IsClosed()){
                   if(cPeriod != AbcG::kPeriodic){
                      ESS_LOG_WARNING("Mixed curve wrap types not supported.");
                   }
                }
                else{
                   if(cPeriod != AbcG::kNonPeriodic){
                      ESS_LOG_WARNING("Mixed curve wrap types not supported.");
                   }
                }
             }

          }
          
       }
       

       curvesSample.setType(cType);
       curvesSample.setWrap(cPeriod);
       curvesSample.setBasis(cBasis);
    }
    else
    {
          BezierShape beziershape;
          PolyShape polyShape;
          bool bBezier = false;

          // Get a pointer to the spline shpae
          ShapeObject *pShapeObject = NULL;
          if (obj->IsShapeObject())
          {
              pShapeObject = reinterpret_cast<ShapeObject *>(obj);
          }
          else
          {
              return false;
          }

          // Determine if we are a bezier shape
          if (pShapeObject->CanMakeBezier())
          {
              pShapeObject->MakeBezier(ticks, beziershape);
              bBezier = true;
          }
          else
          {
              pShapeObject->MakePolyShape(ticks, polyShape);
              bBezier = false;
          }

          // Get the control points

          //std::vector<Point3> inTangents;
	      //std::vector<Point3> outTangents;
          if (bBezier)
          {
              int oldVerticesCount = (int)vertices.size();
              for (int i = 0; i < beziershape.SplineCount(); i += 1)
              {
                  Spline3D *pSpline = beziershape.GetSpline(i);
                  int knots = pSpline->KnotCount();
                  for(int ix = 0; ix < knots; ++ix) 
                  {
                      Point3 in = pSpline->GetInVec(ix);
                      Point3 p = pSpline->GetKnotPoint(ix);
                      Point3 out = pSpline->GetOutVec(ix);

                      vertices.push_back( p );
				      //inTangents.push_back( in );
				      //outTangents.push_back( out );
                  }

                  int nNumVerticesAdded = (int)vertices.size() - oldVerticesCount;
                  nbVertices.push_back( nNumVerticesAdded );
                  oldVerticesCount = (int)vertices.size();
              }
          }
          else
          {
              for (int i = 0; i < polyShape.numLines; i += 1)
              {
                  PolyLine &refLine = polyShape.lines[i];
                  nbVertices.push_back(refLine.numPts);
                  for (int j = 0; j < refLine.numPts; j += 1)
                  {
                      Point3 p = refLine.pts[j].p;
                      vertices.push_back(p);
                  }
              }
          }

          // set the type + wrapping
	      curvesSample.setType(bBezier ? AbcG::kCubic : AbcG::kLinear);
          curvesSample.setWrap(pShapeObject->CurveClosed(ticks, 0) ? AbcG::kPeriodic : AbcG::kNonPeriodic);
          curvesSample.setBasis(AbcG::kNoBasis);
    }

    if(nbVertices.size() == 0 || vertices.size() == 0){
       ESS_LOG_WARNING("No curve data to export.");
       return false;
    }
 

    const int vertCount = (int)vertices.size();

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

    // allocate the points and normals
    std::vector<Abc::V3f> posVec(vertCount);
    Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks);

    for(int i=0;i<vertCount;i++)
    {
        posVec[i] = ConvertMaxPointToAlembicPoint(vertices[i] );
        bbox.extendBy(posVec[i]);

        // Set the archive bounding box
        if (mJob)
        {
            Point3 worldMaxPoint = wm * vertices[i];
            Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint);
            mJob->GetArchiveBBox().extendBy(alembicWorldPoint);
        }
    }

    if(knotVector.size() > 0 && orders.size() > 0){
       if(!mKnotVectorProperty.valid()){
          mKnotVectorProperty = Abc::OFloatArrayProperty(mCurvesSchema.getArbGeomParams(), ".knot_vector", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() );
       }
       mKnotVectorProperty.set(Abc::FloatArraySample(knotVector));

       if(!mOrdersProperty.valid()){
          mOrdersProperty = Abc::OUInt16ArrayProperty(mCurvesSchema.getArbGeomParams(), ".orders", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() );
       }
       mOrdersProperty.set(Abc::UInt16ArraySample(orders));
    }

    // store the bbox
    curvesSample.setSelfBounds(bbox);
	mCurvesSchema.getChildBoundsProperty().set(bbox);

 
    Abc::Int32ArraySample nbVerticesSample(&nbVertices.front(),nbVertices.size());
    curvesSample.setCurvesNumVertices(nbVerticesSample);


 
    // allocate for the points and normals
    Abc::P3fArraySample posSample(&posVec.front(),posVec.size());
	curvesSample.setPositions(posSample);


    mCurvesSchema.set(curvesSample);

   mNumSamples++;

   return true;
}
示例#10
0
void BlobMesh::BuildMesh(TimeValue t)
{

	//TODO: Implement the code to build the mesh representation of the object
	//    using its parameter settings at the time passed. The plug-in should 
	//    use the data member mesh to store the built mesh.
	int numberOfNodes = pblock2->Count(pb_nodelist);

	float size, tension, renderCoarseness, viewCoarseness,coarseness;

	// Interval valid;
	pblock2->GetValue(pb_size,t,size,ivalid);
	pblock2->GetValue(pb_tension,t,tension,ivalid);
	if (tension < 0.011f) tension = 0.011f;
	if (tension > 1.0f) tension = 1.0f;

	pblock2->GetValue(pb_render,t,renderCoarseness,ivalid);
	pblock2->GetValue(pb_viewport,t,viewCoarseness,ivalid);

	BOOL autoCoarseness;
	pblock2->GetValue(pb_relativecoarseness,t,autoCoarseness,ivalid);

	BOOL largeDataSetOpt;
	pblock2->GetValue(pb_oldmetaballmethod,t,largeDataSetOpt,ivalid);


	BOOL useSoftSel;
	float minSize;
	pblock2->GetValue(pb_usesoftsel,t,useSoftSel,ivalid);
	pblock2->GetValue(pb_minsize,t,minSize,ivalid);

	if (inRender)
		coarseness = renderCoarseness;
	else coarseness = viewCoarseness;

	if (autoCoarseness)
		coarseness = size/coarseness;

	Tab<INode *> pfList;

	BOOL useAllPFEvents;
	pblock2->GetValue(pb_useallpf,0,useAllPFEvents,FOREVER);



	int pfCt = pblock2->Count(pb_pfeventlist);

	BOOL offInView;
	pblock2->GetValue(pb_offinview,0,offInView,FOREVER);



	for (int i = 0; i < pfCt; i++)
	{
		INode* node = NULL;
		pblock2->GetValue(pb_pfeventlist,0,node,FOREVER,i);
		if (node)
			pfList.Append(1,&node);
	}

	float thres = 0.6f;

	//need to get our tm
	if (selfNode == NULL)
	{
		MyEnumProc dep(true);
		DoEnumDependents(&dep);
		if (dep.Nodes.Count() > 0)
			selfNode = dep.Nodes[0];
	}

	Matrix3 baseTM(1);

	if (selfNode != NULL)
		baseTM = Inverse(selfNode->GetObjectTM(t));
	//loop throght the nodes

	if (!inRender)
	{
		if (offInView)
			numberOfNodes = 0;

	}

	std::vector<SphereData> data;
	data.reserve(500);

	for (int i = 0; i < numberOfNodes; i++)
	{
		INode* node = NULL;
		pblock2->GetValue(pb_nodelist,t,node,ivalid,i);

		if (node)
		{
			//get the nodes tm
			Matrix3 objectTM = node->GetObjectTM(t);
			Matrix3 toLocalSpace = objectTM*baseTM;

			ObjectState tos =  node->EvalWorldState(t,TRUE);

			if (tos.obj->IsParticleSystem())
			{
				SimpleParticle* pobj      = NULL;
				IParticleObjectExt* epobj = NULL;
				pobj = static_cast<SimpleParticle*>( tos.obj->GetInterface(I_SIMPLEPARTICLEOBJ) );
				if (pobj)
				{
					pobj->UpdateParticles(t, node);

					int count = pobj->parts.Count();
					data.reserve(data.size() + count);
					float closest = 999999999.9f;
					SphereData d;
					for (int pid = 0; pid < count; pid++)
					{
						TimeValue age  = pobj->ParticleAge(t,pid);
						TimeValue life = pobj->ParticleLife(t,pid);
						if (age != -1)
						{
							float psize = pobj->ParticleSize(t,pid);
							Point3 curval = pobj->parts.points[pid];
							d.center = curval * baseTM;
							d.radius = psize;
							d.oradius = psize;
							d.rsquare = psize * psize;
							d.tover4 = tension * d.rsquare *d.rsquare ;
							data.push_back(d);
						}
					}
				}
				else
				{
					epobj = (IParticleObjectExt*) tos.obj->GetInterface(PARTICLEOBJECTEXT_INTERFACE);
					if (epobj) 
					{
						
						epobj->UpdateParticles(node, t);

						int count = epobj->NumParticles();
						data.reserve(data.size() + count);
						for (int pid = 0; pid < count; pid++)
						{
							TimeValue age  = epobj->GetParticleAgeByIndex(pid);
							if (age!=-1)
							{
								INode *node = epobj->GetParticleGroup(pid);

								Point3 *curval = epobj->GetParticlePositionByIndex(pid);

								BOOL useParticle = TRUE;

								if (!useAllPFEvents)
								{
									useParticle = FALSE;
									for (int k = 0; k < pfList.Count(); k++)
									{
										if (node == pfList[k])
										{
											useParticle = TRUE;
											k = pfList.Count();
										}
									}
								}

								if ((curval) && (useParticle))
								{
									float scale = epobj->GetParticleScaleByIndex(pid) ;
									float psize = scale;

									SphereData d;
									d.center = *curval*baseTM;
									d.radius = psize;
									d.oradius = psize;
									d.rsquare = psize * psize;
									d.tover4 = tension * d.rsquare *d.rsquare ;
									data.push_back(d);
								}
							}
						}
					}

				}
			}
			else if (tos.obj->IsShapeObject()) 
			{
				PolyShape shape;

				ShapeObject *pathOb = (ShapeObject*)tos.obj;
				pathOb->MakePolyShape(t, shape);
				
				// first find out how many points there are:
				size_t num_points = 0;
				for (int i = 0; i < shape.numLines; i++)
				{
					PolyLine& line = shape.lines[i];
					num_points += line.numPts;
				}
				data.reserve(data.size() + num_points);

				for (int i = 0; i < shape.numLines; i++)
				{
					PolyLine line = shape.lines[i];
					for (int j = 0; j < line.numPts; j++)
					{
						SphereData d;
						float tsize = size;
						d.center = line.pts[j].p*toLocalSpace;
						d.radius = tsize;
						d.oradius = tsize;
						d.rsquare = tsize * tsize;
						d.tover4 = tension * d.rsquare *d.rsquare ;
						data.push_back(d);
					}
				}
			}
			else if (tos.obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
			{
				SphereData d;
				BOOL converted = FALSE;

				TriObject *triObj = NULL;


				if(tos.obj->IsSubClassOf(triObjectClassID)) 
				{
					triObj = (TriObject *)tos.obj;
				}

				// If it can convert to a TriObject, do it
				else if(tos.obj->CanConvertToType(triObjectClassID)) 
				{
					triObj = (TriObject *)tos.obj->ConvertToType(t, triObjectClassID);
					converted = TRUE;
				}

				if (triObj != NULL)
				{
					Mesh* mesh = &triObj->GetMesh();
					if (mesh)
					{
						int vcount = mesh->getNumVerts();
						float *vsw = mesh->getVSelectionWeights ();
						BitArray vsel =  mesh->VertSel();
						data.reserve(data.size() + vcount);
						for (int j = 0; j < vcount; j++)
						{
							float tsize = size;
							if (useSoftSel)
							{
								tsize = 0.0f;
								if (vsw)
								{
									float v = 0.0f;
									if (vsel[j]) 
										v = 1.0f;
									else 
									{
										if (vsw)
											v = vsw[j];
									}
									if (v == 0.0f)
										tsize = 0.0f;
									else
									{
										tsize = minSize + (size -minSize)*v;
									}

								}
								else
								{
									float v = 0.0f;
									if (vsel[j]) 
										v = 1.0f;
									tsize = minSize + (size -minSize)*v;
								}
							}
							if (tsize != 0.0f)
							{
								d.center = mesh->getVert(j)*toLocalSpace;
								d.radius = tsize;
								d.oradius = tsize;
								d.rsquare = tsize * tsize;
								d.tover4 = tension * d.rsquare *d.rsquare ;
								data.push_back(d);
							}
						}
					}

					if (converted) triObj->DeleteThis();
				}
			}
			else
			{
				SphereData d;
				d.center = Point3(0.0f,0.0f,0.0f)*toLocalSpace;
				d.radius = size;
				d.oradius = size;
				d.rsquare = size * size;
				d.tover4 = tension * d.rsquare *d.rsquare ;
				data.push_back(d);
			}
		}
	}


	if ((data.size() == 0) && (numberOfNodes==0))
	{
		data.resize(1);
		data[0].center = Point3(0.0f,0.0f,0.0f);
		data[0].radius = size;
		data[0].oradius = size;
		data[0].rsquare = size * size;
		data[0].tover4 = tension * data[0].rsquare *data[0].rsquare ;

	}

	if (data.size() > 0)
	{
		int iRes = 1;
		if (!largeDataSetOpt)
		{
			MetaParticle oldBlob;
			iRes = oldBlob.CreatePodMetas(&data[0],(int)data.size(),&mesh,thres,coarseness);
		}
		else
		{
			MetaParticleFast blob;
			iRes = blob.CreatePodMetas(&data[0],(int)data.size(),&mesh,thres,coarseness);
		}

		// An out of memory error is the only reason iRes would be zero in either case
		if( (iRes == 0) && GetCOREInterface() )
			GetCOREInterface()->DisplayTempPrompt(GetString(IDS_NOT_ENOUGH_MEM), 5000 );
	}
	else
	{
		mesh.setNumFaces(0);
		mesh.setNumVerts(0);
	}

	mesh.InvalidateTopologyCache();

	ivalid.Set(t,t);
}
示例#11
0
void ExtrudeMod::BuildMeshFromShape(TimeValue t,ModContext &mc, ObjectState * os, Mesh &mesh, BOOL simple) {
	BOOL texturing;
	pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER);
	BOOL genMatIDs;
	pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER);
	BOOL useShapeIDs;
	pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER);
	BOOL smooth;
	pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER);

	ShapeObject *shape = (ShapeObject *)os->obj;

	float amount;
	int levels,capStart,capEnd,capType;

	pblock->GetValue(PB_AMOUNT,t,amount,FOREVER);
	if(simple) {
		levels = 1;
		capStart = capEnd = FALSE;
		}
	else {
		pblock->GetValue(PB_SEGS,t,levels,FOREVER);
		if (levels<1) levels = 1;
		pblock->GetValue(PB_CAPSTART,t,capStart,FOREVER);
		pblock->GetValue(PB_CAPEND,t,capEnd,FOREVER);
		}
	pblock->GetValue(PB_CAPTYPE,t,capType,FOREVER);

	LimitValue(amount, -1000000.0f, 1000000.0f);

	// Get the basic dimension stuff
	float zSize = (float)fabs(amount);
	float baseZ = 0.0f;
	if(amount < 0.0f)
		baseZ = amount;

	// Make the shape convert itself to a PolyShape -- This makes our mesh conversion MUCH easier!
	
	PolyShape pShape;
	shape->MakePolyShape(t, pShape);
	ShapeHierarchy hier;
	pShape.OrganizeCurves(t, &hier);
	// Need to flip the reversed curves in the shape!
	pShape.Reverse(hier.reverse);

	int polys = pShape.numLines;
	int levelVerts = 0, levelFaces = 0, levelTVerts = 0;
	int verts = 0, faces = 0, tVerts = 0;
	int poly, piece;

	BOOL anyClosed = FALSE;
	for(poly = 0; poly < polys; ++poly) {
		PolyLine &line = pShape.lines[poly];
		if(!line.numPts)
			continue;
		if(line.IsClosed()) {
			anyClosed = TRUE;
			levelTVerts++;
			}
		levelVerts += line.numPts;
		levelTVerts += line.numPts;
		levelFaces += (line.Segments() * 2);
		}

	int vertsPerLevel = levelVerts;
	int numLevels = levels;

	verts = levelVerts * (levels + 1);
	tVerts = levelTVerts * (levels + 1);
	faces = levelFaces * levels;

	mesh.setNumVerts(verts);
	mesh.setNumFaces(faces);
	if(texturing) {
		mesh.setNumTVerts(tVerts);
		mesh.setNumTVFaces(faces);
		}

	// Create the vertices!
	int vert = 0;
	int tvertex = 0;
	int level;
	Point3 offset1, offset2;
	for(poly = 0; poly < polys; ++poly) {
		PolyLine &line = pShape.lines[poly];
		if(!line.numPts)
			continue;
		if(texturing) {
//DebugPrint(_T("Texture Verts:\n"));
            BOOL usePhysUVs = GetUsePhysicalScaleUVs();
			int tp;
			int texPts = line.numPts + (line.IsClosed() ? 1 : 0);
			float *texPt = new float [texPts];
			float lastPt = (float)(texPts - 1);
			float cumLen = 0.0f;
			float totLen = line.CurveLength();
			Point3 prevPt = line.pts[0].p;
			for(tp = 0; tp < texPts; ++tp) {
				int ltp = tp % line.numPts;
				if(tp == (texPts - 1))
					texPt[tp] = usePhysUVs ? totLen : 1.0f;
				else {
					Point3 &pt = line.pts[ltp].p;
					cumLen += Length(pt - prevPt);
                    if (usePhysUVs)
                        texPt[tp] = cumLen;
                    else
					texPt[tp] = cumLen / totLen;
					prevPt = pt;
					}
				}
			float flevels = (float)levels;
			for(level = 0; level <= levels; ++level) {
				float tV = (float)level / flevels;
                float vScale = usePhysUVs ? amount : 1.0f;
				for(tp = 0; tp < texPts; ++tp) {
					mesh.setTVert(tvertex++, UVVert(texPt[tp], vScale*tV, 0.0f));
					}
				}
			delete [] texPt;
			}
		int lverts = line.numPts;
		for(level = 0; level <= levels; ++level) {
			Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			if(level == 0)
				offset1 = offset;
			else
			if(level == levels)
				offset2 = offset;
			for(int v = 0; v < lverts; ++v) {
				line.pts[v].aux = vert;			// Gives the capper this vert's location in the mesh!
				mesh.setVert(vert++, line.pts[v].p + offset);
				}
			}
		}
	assert(vert == verts);

	// If capping, do it!
	if(anyClosed && (capStart || capEnd)) {
		MeshCapInfo capInfo;
		pShape.MakeCap(t, capInfo, capType);
		// Build information for capping
		MeshCapper capper(pShape);
		if(capStart) {
			vert = 0;
			for(poly = 0; poly < polys; ++poly) {
				PolyLine &line = pShape.lines[poly];
				if(!line.numPts)
					continue;
				MeshCapPoly &capline = capper[poly];
				int lverts = line.numPts;
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				vert += lverts * levels;
				}
			// Create a work matrix for grid capping
			Matrix3 gridMat = TransMatrix(offset1);
			int oldFaces = mesh.numFaces;
			capper.CapMesh(mesh, capInfo, TRUE, 16, &gridMat, genMatIDs ? -1 : 0);
			// If texturing, create the texture faces and vertices
			if(texturing)
				MakeMeshCapTexture(mesh, Inverse(gridMat), oldFaces, mesh.numFaces, GetUsePhysicalScaleUVs());
			}
		if(capEnd) {
			int baseVert = 0;
			for(poly = 0; poly < polys; ++poly) {
				PolyLine &line = pShape.lines[poly];
				if(!line.numPts)
					continue;
				MeshCapPoly &capline = capper[poly];
				int lverts = line.numPts;
				vert = baseVert + lverts * levels;
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				baseVert += lverts * (levels + 1);
				}
			// Create a work matrix for grid capping
			Matrix3 gridMat = TransMatrix(offset2);
			int oldFaces = mesh.numFaces;
			capper.CapMesh(mesh, capInfo, FALSE, 16, &gridMat, genMatIDs ? -1 : 0);
			// If texturing, create the texture faces and vertices
			if(texturing)
				MakeMeshCapTexture(mesh, Inverse(gridMat), oldFaces, mesh.numFaces, GetUsePhysicalScaleUVs());
			}
		}

	// Create the faces!
	int face = 0;
	int TVface = 0;
	int baseVert = 0;
	int baseTVert = 0;
	for(poly = 0; poly < polys; ++poly) {
		PolyLine &line = pShape.lines[poly];
		if(!line.numPts)
			continue;
		int pieces = line.Segments();
		int closed = line.IsClosed();
		int segVerts = pieces + ((closed) ? 0 : 1);
		int segTVerts = pieces + 1;
		for(level = 0; level < levels; ++level) {
			int sm = 0;		// Initial smoothing group
			BOOL firstSmooth = (line.pts[0].flags & POLYPT_SMOOTH) ? TRUE : FALSE;
			for(piece = 0; piece < pieces; ++piece) {
				int v1 = baseVert + piece;
				int v2 = baseVert + ((piece + 1) % segVerts);
				int v3 = v1 + segVerts;
				int v4 = v2 + segVerts;
				// If the vertex is not smooth, go to the next group!
				BOOL thisSmooth = line.pts[piece].flags & POLYPT_SMOOTH;
				MtlID mtl = useShapeIDs ? line.pts[piece].GetMatID() : 2;
				if(piece > 0 && !thisSmooth) {
					sm++;
					if(sm > 2)
						sm = 1;
					}
				DWORD smoothGroup = 1 << sm;
				// Advance to the next smoothing group right away
				if(sm == 0)
					sm++;
				// Special case for smoothing from first segment
				if(piece == 1 && thisSmooth)
					smoothGroup |= 1;
				// Special case for smoothing from last segment
				if((piece == pieces - 1) && firstSmooth)
					smoothGroup |= 1;
				mesh.faces[face].setEdgeVisFlags(1,1,0);
				mesh.faces[face].setSmGroup(smooth ? smoothGroup : 0);
				mesh.faces[face].setMatID(genMatIDs ? mtl : 0);
				mesh.faces[face++].setVerts(v1, v2, v4);
				mesh.faces[face].setEdgeVisFlags(0,1,1);
				mesh.faces[face].setSmGroup(smooth ? smoothGroup : 0);
				mesh.faces[face].setMatID(genMatIDs ? mtl : 0);
				mesh.faces[face++].setVerts(v1, v4, v3);
//DebugPrint(_T("BV:%d V:%d v1:%d v2:%d v3:%d v4:%d\n"),baseVert, vert, v1, v2, v3, v4);
				if(texturing) {
					int tv1 = baseTVert + piece;
					int tv2 = tv1 + 1;
					int tv3 = tv1 + segTVerts;
					int tv4 = tv2 + segTVerts;
					mesh.tvFace[TVface++].setTVerts(tv1, tv2, tv4);
					mesh.tvFace[TVface++].setTVerts(tv1, tv4, tv3);
					}
				}
			baseVert += segVerts;
			baseTVert += segTVerts;
			}
		baseVert += segVerts;	// Increment to next poly start (skips last verts of this poly)
		baseTVert += segTVerts;
		}
	assert(face == faces);

	mesh.InvalidateGeomCache();
	}
示例#12
0
bool ExtrudeMod::BuildAMSolidFromShape(TimeValue t,ModContext &mc, ObjectState * os, IGeomImp* igeom) 
{
	ShapeObject *shape = (ShapeObject *)os->obj;

	float amount;

	pblock->GetValue(PB_AMOUNT,t,amount,FOREVER);

	BOOL texturing;
	pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER);
	BOOL genMatIDs;
	pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER);
	BOOL useShapeIDs;
	pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER);
	BOOL smooth;
	pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER);

	LimitValue(amount, -1000000.0f, 1000000.0f);
	if(fabs(amount)<MIN_EXT)
		amount = MIN_EXT;

	// Get the basic dimension stuff
	float zSize = (float)fabs(amount);
	float baseZ = 0.0f;
	if(amount < 0.0f)
		baseZ = amount;

	// If the shape can convert itself to a BezierShape, have it do so!
	BezierShape bShape;
	PolyShape pShape;
	shape->MakePolyShape(t, pShape, PSHAPE_BUILTIN_STEPS, true);
	ShapeHierarchy hier;
	pShape.OrganizeCurves(t, &hier);
	// Need to flip the reversed curves in the shape!
	pShape.Reverse(hier.reverse);

	//Now add the extrusion for each polygon
	bool res = false;//assume the best

	//make a solid to hold our work
	Object* solid = (Object*)CreateInstance(GEOMOBJECT_CLASS_ID, GENERIC_AMSOLID_CLASS_ID);
	IGeomImp* workgeom = NULL;
	assert(solid);
	if(solid)
	{
		workgeom = (IGeomImp*)(solid->GetInterface(I_GEOMIMP));
		assert(workgeom);
	}

	for(int i=0;i<pShape.numLines; i++)
	{
		PolyLine poly = pShape.lines[i];
		if(poly.numPts)
			poly.pts[0].aux = poly.flags;
		bool localres  = workgeom->createExtrusion(poly.pts, poly.numPts, amount, smooth, genMatIDs, useShapeIDs);

		if(localres)
		{
			//need to figure out how deeply nested this shape is
			//order is this value with zero meaning not nested
			HierarchyEntry *entry = hier.hier.FindEntry(i);
			assert(entry);
			int order = 0;
			while(entry && (entry->parent != (HierarchyEntry *)-1))
			{
				entry = entry->parent;
				++order;
			}

			if(order%2)
				igeom->operator-=(*workgeom);
			else
				igeom->operator+=(*workgeom);
		}
		res |= localres;
	}

	//do some cleanup
	if(workgeom)
	{
		assert(solid);
		solid->ReleaseInterface(I_GEOMIMP, workgeom);
		solid->DeleteMe();
	}
	return res;
}
示例#13
0
void ExtrudeMod::BuildPatchFromShape(TimeValue t,ModContext &mc, ObjectState * os, PatchMesh &pmesh) {
	ShapeObject *shape = (ShapeObject *)os->obj;

	float amount;
	int levels,capStart,capEnd,capType;

	pblock->GetValue(PB_AMOUNT,t,amount,FOREVER);
	pblock->GetValue(PB_SEGS,t,levels,FOREVER);
	if (levels<1) levels = 1;
	pblock->GetValue(PB_CAPSTART,t,capStart,FOREVER);
	pblock->GetValue(PB_CAPEND,t,capEnd,FOREVER);
	pblock->GetValue(PB_CAPTYPE,t,capType,FOREVER);

	BOOL texturing;
	pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER);
	BOOL genMatIDs;
	pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER);
	BOOL useShapeIDs;
	pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER);
	BOOL smooth;
	pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER);

	LimitValue(amount, -1000000.0f, 1000000.0f);

	// Get the basic dimension stuff
	float zSize = (float)fabs(amount);
	float baseZ = 0.0f;
	if(amount < 0.0f)
		baseZ = amount;

	// If the shape can convert itself to a BezierShape, have it do so!
	BezierShape bShape;
	if(shape->CanMakeBezier())
		shape->MakeBezier(t, bShape);
	else {
		PolyShape pShape;
		shape->MakePolyShape(t, pShape);
		bShape = pShape;	// UGH -- Convert it from a PolyShape -- not good!
		}
	
//DebugPrint(_T("Extrude organizing shape\n"));
	ShapeHierarchy hier;
	bShape.OrganizeCurves(t, &hier);
	// Need to flip the reversed polys...
	bShape.Reverse(hier.reverse);
	// ...and tell the hierarchy they're no longer reversed!
	hier.reverse.ClearAll();

	// Our shapes are now organized for patch-making -- Let's do the sides!
	int polys = bShape.splineCount;
	int poly, knot;
	int levelVerts = 0, levelVecs = 0, levelPatches = 0, nverts = 0, nvecs = 0, npatches = 0;
	int TVlevels = levels + 1, levelTVerts = 0, ntverts = 0, ntpatches = 0;
	BOOL anyClosed = FALSE;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		if(spline->Closed())
			anyClosed = TRUE;
		levelVerts += spline->KnotCount();
		levelTVerts += (spline->Segments() + 1);
		levelVecs += (spline->Segments() * 2);
		levelPatches += spline->Segments();
		}
	nverts = levelVerts * (levels + 1);
	npatches = levelPatches * levels;
	nvecs = (levelVecs * (levels + 1)) + levels * levelVerts * 2 + npatches * 4;
	if(texturing) {
		ntverts = levelTVerts * TVlevels;
		ntpatches = npatches;
		}

	pmesh.setNumVerts(nverts);
	pmesh.setNumVecs(nvecs);
	pmesh.setNumPatches(npatches);
	pmesh.setNumTVerts(ntverts);
	pmesh.setNumTVPatches(ntpatches);

	// Create the vertices!
	int vert = 0;
	int level;
	Point3 offset1, offset2;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int knots = spline->KnotCount();
		for(level = 0; level <= levels; ++level) {
			Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			if(level == 0)
				offset1 = offset;
			else
			if(level == levels)
				offset2 = offset;
			for(knot = 0; knot < knots; ++knot) {
				Point3 p = spline->GetKnotPoint(knot);
				pmesh.setVert(vert++, p + offset);
				}
			}
		}
	assert(vert == nverts);

    BOOL usePhysUVs = GetUsePhysicalScaleUVs();
	// Maybe create the texture vertices
	if(texturing) {
		int tvert = 0;
		int level;
		for(poly = 0; poly < polys; ++poly) {
			Spline3D *spline = bShape.splines[poly];
			if(!spline->KnotCount())
				continue;
			// Make it a polyline
			PolyLine pline;
			spline->MakePolyLine(pline, 10);
			int knots = spline->KnotCount();
			for(level = 0; level < TVlevels; ++level) {
				float tV = (float)level / (float)(TVlevels - 1);
                float vScale = usePhysUVs ? amount : 1.0f;
				int lverts = pline.numPts;
				int tp = 0;
				int texPts = spline->Segments() + 1;
				float cumLen = 0.0f;
				float totLen = pline.CurveLength();
                float uScale = usePhysUVs ? totLen : 1.0f;
				Point3 prevPt = pline.pts[0].p;
				int plix = 0;
				while(tp < texPts) {
					Point3 &pt = pline[plix].p;
					cumLen += Length(pt - prevPt);
					prevPt = pt;
					if(pline[plix].flags & POLYPT_KNOT) {
						float tU;
						if(tp == (texPts - 1))
							tU = 1.0f;
						else
							tU = cumLen / totLen;
						pmesh.setTVert(tvert++, UVVert(uScale*tU, vScale*tV, 0.0f));
						tp++;
						}
					plix = (plix + 1) % pline.numPts;
					}
				}
			}
		assert(tvert == ntverts);
		}

	// Create the vectors!
	int seg;
	int vec = 0;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int segs = spline->Segments();
		int knots = spline->KnotCount();
		// First, the vectors on each level
		for(level = 0; level <= levels; ++level) {
			Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			for(seg = 0; seg < segs; ++seg) {
				int seg2 = (seg + 1) % knots;
				if(spline->GetLineType(seg) == LTYPE_CURVE) {
					Point3 p = spline->GetOutVec(seg);
					pmesh.setVec(vec++, p + offset);
					p = spline->GetInVec(seg2);
					pmesh.setVec(vec++, p + offset);
					}
				else {
					Point3 p = spline->InterpBezier3D(seg, 0.333333f);
					pmesh.setVec(vec++, p + offset);
					p = spline->InterpBezier3D(seg, 0.666666f);
					pmesh.setVec(vec++, p + offset);
					}
				}
			}
		// Now, the vectors between the levels
		int baseVec = vec;
		for(level = 0; level < levels; ++level) {
			Point3 offsetA = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			Point3 offsetB = Point3(0.0f, 0.0f, baseZ + (float)(level + 1) / (float)levels * zSize);
			Point3 offset1 = offsetA + (offsetB - offsetA) * 0.333333333f;
			Point3 offset2 = offsetA + (offsetB - offsetA) * 0.666666666f;
			for(knot = 0; knot < knots; ++knot) {
				Point3 p = spline->GetKnotPoint(knot);
				pmesh.setVec(vec++, p + offset1);
				pmesh.setVec(vec++, p + offset2);
				}
			}
		}

	// Create the patches!
	int np = 0;
	int baseVert = 0;
	int baseVec = 0;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int knots = spline->KnotCount();
		int segs = spline->Segments();
		int baseVec1 = baseVec;	// Base vector index for this level
		int baseVec2 = baseVec + segs * 2 * (levels + 1);	// Base vector index for between levels
		for(level = 0; level < levels; ++level) {
			int sm = 0;
			BOOL firstSmooth = (spline->GetLineType(0) == LTYPE_CURVE && spline->GetLineType(segs-1) == LTYPE_CURVE && (spline->GetKnotType(0) == KTYPE_AUTO || spline->GetKnotType(0) == KTYPE_BEZIER)) ? TRUE : FALSE;
			for(seg = 0; seg < segs; ++seg, vec += 4) {
				int prevseg = (seg + segs - 1) % segs;
				int seg2 = (seg + 1) % knots;
				int a,b,c,d,ab,ba,bc,cb,cd,dc,da,ad;
				MtlID mtl = useShapeIDs ? spline->GetMatID(seg) : 2;
				a = baseVert + seg;
				b = baseVert + seg2;
				c = b + knots;
				d = a + knots;
				ab = baseVec1 + seg * 2;
				ba = ab + 1;
				bc = baseVec2 + seg2 * 2;
				cb = bc + 1;
				cd = ba + (segs * 2);
				dc = ab + (segs * 2);
				da = baseVec2 + seg * 2 + 1;
				ad = da - 1;
//DebugPrint(_T("Making patch %d: %d (%d %d) %d (%d %d) %d (%d %d) %d (%d %d)\n"),np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad);
				// If the vertex is not smooth, go to the next group!
				if(seg > 0 && !(spline->GetLineType(prevseg) == LTYPE_CURVE && spline->GetLineType(seg) == LTYPE_CURVE && (spline->GetKnotType(seg) == KTYPE_AUTO || spline->GetKnotType(seg) == KTYPE_BEZIER))) {
					sm++;
					if(sm > 2)
						sm = 1;
					}
				DWORD smoothGroup = 1 << sm;
				if(seg == segs - 1 && firstSmooth) {
					smoothGroup |= 1;
					}
				pmesh.MakeQuadPatch(np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad, vec, vec+1, vec+2, vec+3, smooth ? smoothGroup : 0);
				pmesh.setPatchMtlIndex(np++, genMatIDs ? mtl : 0);
				}
			baseVert += knots;
			baseVec1 += (segs * 2);
			baseVec2 += (knots * 2);
			}
		baseVert += knots;
		baseVec += (segs * 2 * (levels + 1) + knots * 2 * levels);
		}
	assert(vec == nvecs);
	assert(np == npatches);

 	// Maybe create the texture patches!
	if(texturing) {
		int ntp = 0;
		int baseTVert = 0;
		for(poly = 0; poly < polys; ++poly) {
			Spline3D *spline = bShape.splines[poly];
			if(!spline->KnotCount())
				continue;
			int pknots = spline->Segments() + 1;
			int pverts = pknots * TVlevels;
			int segs = spline->Segments();
			for(level = 0; level < levels; ++level) {
				for(seg = 0; seg < segs; ++seg) {
					int prevseg = (seg + segs - 1) % segs;
					int seg2 = seg + 1;
					int a,b,c,d;
					a = baseTVert + seg;
					b = baseTVert + seg2;
					c = b + pknots;
					d = a + pknots;
					TVPatch &tp = pmesh.getTVPatch(ntp++);
					tp.setTVerts(a, b, c, d);
					
					}
				baseTVert += pknots;
				}
			baseTVert += pknots;
			}
		assert(ntp == ntpatches);
		}

	// If capping, do it!
	if(anyClosed && (capStart || capEnd)) {
		PatchCapInfo capInfo;
		bShape.MakeCap(t, capInfo);

		// Build information for capping
		PatchCapper capper(bShape);
		if(capStart) {
			vert = 0;
			int baseVec = 0;
			for(poly = 0; poly < polys; ++poly) {
				Spline3D *spline = bShape.splines[poly];
				if(!spline->KnotCount())
					continue;
				PatchCapPoly &capline = capper[poly];
				int lverts = spline->KnotCount();
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				vert += lverts * levels;
				vec = baseVec;
				int lvecs = spline->Segments() * 2;
				for(int v = 0; v < lvecs; ++v)
					capline.SetVec(v, vec++);			// Gives this vec's location in the mesh!
				baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2;
				}
			// Create a work matrix for capping
			Matrix3 mat = TransMatrix(offset1);
			int oldPatches = pmesh.numPatches;
			capper.CapPatchMesh(pmesh, capInfo, TRUE, 16, &mat, genMatIDs ? -1 : 0);
			// If texturing, create the texture patches and vertices
			if(texturing)
				MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs);
			}
		if(capEnd) {
			int baseVert = 0;
			int baseVec = 0;
			for(poly = 0; poly < polys; ++poly) {
				Spline3D *spline = bShape.splines[poly];
				if(!spline->KnotCount())
					continue;
				PatchCapPoly &capline = capper[poly];
				int lverts = spline->KnotCount();
				int vert = baseVert + lverts * levels;
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				baseVert += lverts * (levels + 1);
				int lvecs = spline->Segments()*2;
				int vec = baseVec + lvecs * levels;
				for(int v = 0; v < lvecs; ++v)
					capline.SetVec(v, vec++);			// Gives this vec's location in the mesh!
				baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2;
				}
			// Create a work matrix for grid capping
			Matrix3 mat = TransMatrix(offset2);
			int oldPatches = pmesh.numPatches;
			capper.CapPatchMesh(pmesh, capInfo, FALSE, 16, &mat, genMatIDs ? -1 : 0);
			// If texturing, create the texture patches and vertices
			if(texturing)
				MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs);
			}
		}

	//watje new mapping
	if(texturing)
		{
		if (ver < 4)
			{
			for (int i = 0; i < pmesh.numPatches; i++)
				pmesh.patches[i].flags |= PATCH_LINEARMAPPING;
			}
		}


	// Ready the patch representation!
	if( !pmesh.buildLinkages() )
   {
      assert(0);
   }
	pmesh.computeInteriors();
	}
示例#14
0
文件: mirror.cpp 项目: 2asoft/xray
void MirrorMod::ModifyObject(
		TimeValue t, ModContext &mc, ObjectState *os, INode *node)
	{	
	Matrix3 itm = CompMatrix(t,NULL,&mc);
	Matrix3 tm  = Inverse(itm);
	Interval iv = FOREVER;
	int axis, copy;
	float offset;
	pblock->GetValue(PB_AXIS,t,axis,iv);
	pblock->GetValue(PB_COPY,t,copy,iv);
	pblock->GetValue(PB_OFFSET,t,offset,iv);
	DWORD oldLevel;
	BOOL convertedShape = FALSE;
	BitArray oldFaceSelections;

	// support for TriObjects
	if (os->obj->IsSubClassOf(triObjectClassID)) {
		TriObject *tobj = (TriObject*)os->obj;
		Mesh &mesh = tobj->GetMesh();		
		switch (mesh.selLevel) {
			case MESH_OBJECT: mesh.faceSel.SetAll(); break;			
			case MESH_VERTEX: {
				for (int i=0; i<mesh.getNumFaces(); i++) {
					for (int j=0; j<3; j++) {
						if (mesh.vertSel[mesh.faces[i].v[j]]) {
							mesh.faceSel.Set(i);
							}
						}
					}
				break;
				}
			
			case MESH_EDGE:	{
				for (int i=0; i<mesh.getNumFaces(); i++) {
					for (int j=0; j<3; j++) {
						if (mesh.edgeSel[i*3+j]) {
							mesh.faceSel.Set(i);
							}
						}
					}
				break;
				}		
			}		
		oldLevel = mesh.selLevel;
		mesh.selLevel = MESH_FACE;
		if (copy) {
			mesh.CloneFaces(mesh.faceSel);
			mesh.ClearVSelectionWeights ();
		}
		if (axis<3) {
			for (int i=0; i<mesh.getNumFaces(); i++) {
				if (mesh.faceSel[i]) mesh.FlipNormal(i);
			}
		}
	}

#ifndef NO_PATCHES
	// support for PatchObjects
	if (os->obj->IsSubClassOf(patchObjectClassID)) {
		PatchObject *pobj = (PatchObject*)os->obj;
		PatchMesh &pmesh = pobj->GetPatchMesh(t);
		switch (pmesh.selLevel) {
			case PATCH_OBJECT: pmesh.patchSel.SetAll(); break;			
			case PATCH_VERTEX: {
				for (int i=0; i<pmesh.getNumPatches(); i++) {
					Patch &p = pmesh.patches[i];
					for (int j=0; j<p.type; j++) {
						if (pmesh.vertSel[p.v[j]]) {
							pmesh.patchSel.Set(i);
							break;
							}
						}
					}
				break;
				}
			
			case PATCH_EDGE:	{
				for (int i=0; i<pmesh.getNumPatches(); i++) {
					Patch &p = pmesh.patches[i];
					for (int j=0; j<p.type; j++) {
						if (pmesh.edgeSel[p.edge[j]]) {
							pmesh.patchSel.Set(i);
							break;
							}
						}
					}
				break;
				}		
			}		
		oldLevel = pmesh.selLevel;
		pmesh.selLevel = PATCH_PATCH;
		if (copy)
			pmesh.ClonePatchParts();	// Copy the selected patches
		if (axis<3)
			pmesh.FlipPatchNormal(-1);	// Flip selected normals
	}
#endif // NO_PATCHES

	// support for PolyObjects
	else if (os->obj->IsSubClassOf(polyObjectClassID)) {
		PolyObject * pPolyOb = (PolyObject*)os->obj;
		MNMesh &mesh = pPolyOb->GetMesh();

		// Luna task 747
		// We don't support specified normals here because it would take special code
		mesh.ClearSpecifiedNormals ();

		BitArray faceSelections;
		mesh.getFaceSel (faceSelections);
		switch (mesh.selLevel) {
			case MNM_SL_OBJECT: faceSelections.SetAll(); break;			
			case MNM_SL_VERTEX: {
				faceSelections.ClearAll ();
				for (int i=0; i<mesh.FNum(); i++) {
					for (int j=0; j<mesh.F(i)->deg; j++) {
						int vertIndex = mesh.F(i)->vtx[j];
						if (mesh.V(vertIndex)->GetFlag(MN_SEL)) {
							faceSelections.Set(i);
							break;
						}
					}
				}
				break;
			}
			
			case MNM_SL_EDGE:	{
				faceSelections.ClearAll ();
				for (int i=0; i<mesh.FNum(); i++) {
					for (int j=0; j<mesh.F(i)->deg; j++) {
						int edgeIndex = mesh.F(i)->edg[j];
						if (mesh.E(edgeIndex)->GetFlag(MN_SEL)) {
							faceSelections.Set(i);
							break;
						}
					}
				}
				break;
			}
		}

		// preserve the existing selection settings
		oldLevel = mesh.selLevel;
		mesh.getFaceSel (oldFaceSelections);

		// set the face selections
		mesh.ClearFFlags (MN_SEL);
		mesh.FaceSelect(faceSelections);
		mesh.selLevel = MNM_SL_FACE;

		// copy the selected faces and flip Normal direction as needed
		if (copy) {
			mesh.CloneFaces();
			mesh.freeVSelectionWeights ();
		}

		// Now, note that by PolyMesh rules, we can only flip entire selected elements.
		// So we broaden our selection to include entire elements that are only partially selected:
		for (int i=0; i<mesh.numf; i++) {
			if (mesh.f[i].GetFlag (MN_DEAD)) continue;
			if (!mesh.f[i].GetFlag (MN_SEL)) continue;
			mesh.PaintFaceFlag (i, MN_SEL);
		}

		if (axis<3) {
			for (i=0; i<mesh.FNum(); i++) {
				if (mesh.F(i)->GetFlag(MN_SEL)) mesh.FlipNormal(i);
			}
			if (mesh.GetFlag (MN_MESH_FILLED_IN)) {
				// We also need to flip edge normals:
				for (i=0; i<mesh.ENum(); i++) {
					if (mesh.f[mesh.e[i].f1].GetFlag (MN_SEL)) {
						int hold = mesh.e[i].v1;
						mesh.e[i].v1 = mesh.e[i].v2;
						mesh.e[i].v2 = hold;
					}
				}
			}
		}
	}

	// support for shape objects
	else
	if (os->obj->IsSubClassOf(splineShapeClassID)) {
		SplineShape *ss = (SplineShape*)os->obj;
		BezierShape &shape = ss->shape;		
		oldLevel = shape.selLevel;
		switch (shape.selLevel) {
			case SHAPE_OBJECT:			
			case SHAPE_VERTEX:
				shape.selLevel = SHAPE_SPLINE;
				shape.polySel.SetAll();
				break;
				 
			case SHAPE_SPLINE:
			case SHAPE_SEGMENT:
				break;
			}		
		if (copy)
			shape.CloneSelectedParts((axis < 3 && splineMethod == SPLINE_REVERSE) ? TRUE : FALSE);
		}
	else
	if(os->obj->SuperClassID() == SHAPE_CLASS_ID) {
		ShapeObject *so = (ShapeObject *)os->obj;
		if(so->CanMakeBezier()) {
			SplineShape *ss = new SplineShape();
			so->MakeBezier(t, ss->shape);
			ss->SetChannelValidity(GEOM_CHAN_NUM, GetValidity(t) & so->ObjectValidity(t));
			os->obj = ss;
			os->obj->UnlockObject();
			convertedShape = TRUE;
			BezierShape &shape = ss->shape;		
			oldLevel = shape.selLevel;
			switch (shape.selLevel) {
				case SHAPE_OBJECT:			
				case SHAPE_VERTEX:
					shape.selLevel = SHAPE_SPLINE;
					shape.polySel.SetAll();
					break;
					 
				case SHAPE_SPLINE:
				case SHAPE_SEGMENT:
					break;
				}		
			if (copy)
				shape.CloneSelectedParts((axis < 3 && splineMethod == SPLINE_REVERSE) ? TRUE : FALSE);
			}
		}

	MirrorDeformer deformer(axis,offset,tm,itm);


	os->obj->Deform(&deformer, TRUE);	

//	if (axis < 3 && splineMethod == SPLINE_REVERSE)
		{
		if (os->obj->IsSubClassOf(splineShapeClassID)) {
			SplineShape *ss = (SplineShape*)os->obj;
			BezierShape &shape = ss->shape;		
			for (int i = 0; i < shape.bindList.Count(); i++)
				{
				int index = 0;
				int spindex = shape.bindList[i].pointSplineIndex;
//			Point3 p=shape.splines[spindex]->GetKnot(index).Knot();
				if (shape.bindList[i].isEnd)
					index = shape.splines[spindex]->KnotCount()-1;
				shape.bindList[i].bindPoint = shape.splines[spindex]->GetKnotPoint(index);
				shape.bindList[i].segPoint = shape.splines[spindex]->GetKnotPoint(index);
				}
			shape.UpdateBindList(TRUE);
	
			}
		else
		if(os->obj->SuperClassID() == SHAPE_CLASS_ID) {
			ShapeObject *so = (ShapeObject *)os->obj;
			if(so->CanMakeBezier()) {
				SplineShape *ss = new SplineShape();
				so->MakeBezier(t, ss->shape);
				ss->SetChannelValidity(GEOM_CHAN_NUM, GetValidity(t) & so->ObjectValidity(t));
				os->obj = ss;
				os->obj->UnlockObject();
				convertedShape = TRUE;
				BezierShape &shape = ss->shape;		
				for (int i = 0; i < shape.bindList.Count(); i++)
					{
					int index = 0;
					int spindex = shape.bindList[i].pointSplineIndex;
//				Point3 p;
					if (shape.bindList[i].isEnd)
						index = shape.splines[spindex]->KnotCount()-1;
					shape.bindList[i].bindPoint = shape.splines[spindex]->GetKnotPoint(index);
					shape.bindList[i].segPoint = shape.splines[spindex]->GetKnotPoint(index);
					}
				shape.UpdateBindList(TRUE);

				}

			}
		}

	os->obj->UpdateValidity(GEOM_CHAN_NUM,GetValidity(t));	
	
	// restore the original selections
	if (os->obj->IsSubClassOf(triObjectClassID)) {
		TriObject *tobj = (TriObject*)os->obj;
		tobj->GetMesh().selLevel = oldLevel;
		}
#ifndef NO_PATCHES
	else if (os->obj->IsSubClassOf(patchObjectClassID)) {
		PatchObject *pobj = (PatchObject*)os->obj;
		pobj->GetPatchMesh(t).selLevel = oldLevel;
		}
#endif // NO_PATCHES
	else if (os->obj->IsSubClassOf(polyObjectClassID)) {
		PolyObject *pPolyOb = (PolyObject*)os->obj;
		pPolyOb->GetMesh().selLevel = oldLevel;
		pPolyOb->GetMesh().dispFlags = 0;
		switch (oldLevel) {
		case MNM_SL_VERTEX:
			pPolyOb->GetMesh().dispFlags = MNDISP_SELVERTS | MNDISP_VERTTICKS;
			break;
		case MNM_SL_EDGE:
			pPolyOb->GetMesh().dispFlags = MNDISP_SELEDGES;
			break;
		case MNM_SL_FACE:
			pPolyOb->GetMesh().dispFlags = MNDISP_SELFACES;
			break;
		}
		pPolyOb->GetMesh().FaceSelect(oldFaceSelections);
		}
	else
	if(os->obj->IsSubClassOf(splineShapeClassID) || convertedShape) {
		SplineShape *ss = (SplineShape*)os->obj;
		ss->shape.selLevel = oldLevel;
		}
	}
示例#15
0
//[-------------------------------------------------------]
//[ Private virtual PLSceneNode functions                 ]
//[-------------------------------------------------------]
void PLSceneSpline::WriteToFile(XmlElement &cSceneElement, const String &sApplicationDrive, const String &sApplicationDir)
{
	// Do NOT save it as scene node, it's just a 'resource'

	// Get path filename
	const String sFilename = sApplicationDrive + sApplicationDir + PLTools::GetResourceFilename(PLTools::ResourcePath, GetName() + ".path");

	// Get the IGame spline object of the given IGame node
	IGameObject *pIGameObject = GetIGameNode()->GetIGameObject();
	if (pIGameObject) {
		// Check the type of the IGame object
		if (pIGameObject->GetIGameType() == IGameObject::IGAME_SPLINE && pIGameObject->InitializeData()) {
			IGameSpline &cIGameSpline = *static_cast<IGameSpline*>(pIGameObject);
			if (cIGameSpline.GetNumberOfSplines () > 0) {
				// We only support spline 0
				IGameSpline3D *pIGameSpline3D = cIGameSpline.GetIGameSpline3D(0);
				if (pIGameSpline3D) {
					// Get the local transform matrix
					GMatrix mTransform = cIGameSpline.GetIGameObjectTM();

					// Get the 3ds Max shape object
					ShapeObject *pMaxShapeObject = static_cast<ShapeObject*>(pIGameObject->GetMaxObject()->ConvertToType(TIME_PosInfinity, Class_ID(GENERIC_SHAPE_CLASS_ID, 0)));
					if (pMaxShapeObject != nullptr && pMaxShapeObject->NumberOfCurves() == cIGameSpline.GetNumberOfSplines()) {
						// Create XML document
						XmlDocument cDocument;

						// Add declaration
						XmlDeclaration *pDeclaration = new XmlDeclaration("1.0", "ISO-8859-1", "");
						cDocument.LinkEndChild(*pDeclaration);

						// Add path
						XmlElement *pPathElement = new XmlElement("Path");

						// Setup attributes
						pPathElement->SetAttribute("Version", "1");
						pPathElement->SetAttribute("Closed",  String::Format("%d", pMaxShapeObject->CurveClosed(0, 0)));

						// Add all nodes
						for (int nKnot=0; nKnot<pIGameSpline3D->GetIGameKnotCount(); nKnot++) {
							IGameKnot *pIGameKnot = pIGameSpline3D->GetIGameKnot(nKnot);
							if (pIGameKnot) {
								// Get knot point in object space (although it is not documented it looks like object space...)
								Point3 cPoint = pIGameKnot->GetKnotPoint();

								// We really need to flip the coordinates to OpenGL style, IGame is not doing this automatically...
								cPoint = PLTools::Convert3dsMaxVectorToOpenGLVector(cPoint);

								// Transform to world space
								cPoint = cPoint*mTransform;

								// If there's a parent container, make the position of this scene node relative to it
								PLSceneContainer *pContainer = GetContainer();
								if (pContainer)
									cPoint -= pContainer->GetWorldSpaceCenter();

								// Add node
								XmlElement *pNodeElement = new XmlElement("Node");
								pNodeElement->SetAttribute("Name",     String::Format("%d",       nKnot));
								pNodeElement->SetAttribute("Position", String::Format("%f %f %f", cPoint.x, cPoint.y, cPoint.z));

								// Link general element
								pPathElement->LinkEndChild(*pNodeElement);
							}
						}

						// Link material element
						cDocument.LinkEndChild(*pPathElement);

						// Save settings
						if (cDocument.Save(sFilename))
							g_pLog->LogFLine(PLLog::Hint, "Created '%s'", sFilename.GetASCII());
						else
							g_pLog->LogFLine(PLLog::Error, "Can't create '%s'!", sFilename.GetASCII());
					}
				}
			}
		} else {
			g_pLog->LogFLine(PLLog::Error, "%s: IGame object is no known spline object!", GetIGameNode()->GetName());
		}

		// Release the IGame object
		GetIGameNode()->ReleaseIGameObject();
	} else {
		g_pLog->LogFLine(PLLog::Error, "%s: IGame node has no IGame object!", GetIGameNode()->GetName());
	}
}