Exemplo n.º 1
0
void SetupAttachmentScene()
{
    sprintf(gTitleString, "Attachment Demo");

	// Create objects in scene
	groundPlane = CreateGroundPlane();
	NxActor* box1 = CreateBox(NxVec3(-7,12.25,0), NxVec3(2.5,1,1), 0);
	NxActor* box2 = CreateBox(NxVec3(0,12.25,0), NxVec3(2.5,1,1), 0);
	NxActor* box3 = CreateBox(NxVec3(7,12.25,0), NxVec3(2.5,1,1), 0);	

	NxActor* attachedBox = CreateBox(NxVec3(-7.2,4.5,1.6), NxVec3(1.25,1,1), 1);
	NxActor* attachedSphere = CreateSphere(NxVec3(-0.25,4.0,2.0), 1.3, 1);
	NxActor* attachedCapsule = CreateCapsule(NxVec3(9.0,5.5,2.0),2.0, 1, 1); 

	NxReal damping = 0.3;
	attachedBox->setAngularDamping(damping);
	attachedBox->setLinearDamping(damping);
	attachedSphere->setAngularDamping(damping);
	attachedSphere->setLinearDamping(damping);
	attachedCapsule->setAngularDamping(damping);
	attachedCapsule->setLinearDamping(damping);

	NxQuat q;
	q.fromAngleAxis(90,NxVec3(0,0,1));
	attachedCapsule->setGlobalOrientationQuat(q);

	// Cloth
	NxClothDesc clothDesc;
	clothDesc.globalPose.M.rotX(1.3);
	clothDesc.thickness = 0.3;	
	clothDesc.attachmentResponseCoefficient = 1;
	clothDesc.flags |= NX_CLF_BENDING;
	clothDesc.flags |= NX_CLF_BENDING_ORTHO;
	clothDesc.flags |= NX_CLF_DAMPING | NX_CLF_VISUALIZATION;

	if (gHardwareCloth)
		clothDesc.flags |= NX_CLF_HARDWARE;

	// Cloth attaching to sphere
	clothDesc.globalPose.t = NxVec3(0.75,5,2);
	MyCloth* regularCloth1 = new MyCloth(gScene, clothDesc, 2, 8, 0.4);
	regularCloth1->getNxCloth()->attachToCollidingShapes(NX_CLOTH_ATTACHMENT_TWOWAY);
	gCloths.push_back(regularCloth1);

	// Cloth attaching to box
	clothDesc.globalPose.t = NxVec3(-6.2,5,2);
	MyCloth* regularCloth2 = new MyCloth(gScene, clothDesc, 2, 8, 0.4);
	regularCloth2->getNxCloth()->attachToCollidingShapes(NX_CLOTH_ATTACHMENT_TWOWAY);
	gCloths.push_back(regularCloth2);

	// Cloth attaching to capsule
	clothDesc.globalPose.t = NxVec3(8.0,5,2);
	clothDesc.attachmentTearFactor = 2.0;
	MyCloth* regularCloth3 = new MyCloth(gScene, clothDesc, 2, 8, 0.4);
	regularCloth3->getNxCloth()->attachToShape(box3->getShapes()[0], NX_CLOTH_ATTACHMENT_TEARABLE);
	regularCloth3->getNxCloth()->attachToShape(attachedCapsule->getShapes()[0], NX_CLOTH_ATTACHMENT_TWOWAY);
	gCloths.push_back(regularCloth3);
}
Exemplo n.º 2
0
void SetupTearingScene()
{
    sprintf(gTitleString, "Tearing Demo");

	// Create the objects in the scene
	groundPlane = CreateGroundPlane();
	NxActor* bar = CreateBox(NxVec3(0,12,0), NxVec3(3,0.5,0.5), 0);
	NxActor* box = CreateBox(NxVec3(-2.3,4.0,0), NxVec3(0.5,0.5,0.5), 10); 

	// Cloth
	NxClothDesc clothDesc;
	clothDesc.globalPose.t = NxVec3(2.5,12,0);
	clothDesc.globalPose.M.rotX(-NxHalfPiF32);
	clothDesc.thickness = 0.1;
	clothDesc.tearFactor = 2;
	clothDesc.flags |= NX_CLF_BENDING;
	clothDesc.flags |= NX_CLF_COLLISION_TWOWAY;
	clothDesc.flags |= NX_CLF_TEARABLE | NX_CLF_VISUALIZATION; // Tearable cloth

	if (gHardwareCloth)
		clothDesc.flags |= NX_CLF_HARDWARE;

	MyCloth* regularCloth = new MyCloth(gScene, clothDesc, 5, 8, 0.1, "rug512.bmp", gTearLines);
	gCloths.push_back(regularCloth);

	regularCloth->getNxCloth()->attachToShape(*bar->getShapes(), 0);
	regularCloth->getNxCloth()->attachToShape(*box->getShapes(), NX_CLOTH_ATTACHMENT_TWOWAY);
}
Exemplo n.º 3
0
//
//	EPhysXPhysEngine::BuildConvexMesh
//
NxConvexMesh *ESciVis::BuildConvexMesh( const IPxTriMesh input_mesh )
{
	//IPxTriMesh	mesh	=	input_mesh->Clone();
	//mesh->SetFormat( GE_MESH_POSITION );
	//mesh->MergeVertices();				//This command causes convex cook crash

	NxConvexMeshDesc	convex_mesh_desc;

	NxArray<NxVec3>	verts;
	
	for (uint i=0; i<input_mesh->GetVertexNum(); i++) {
		EVertex v;
		v = input_mesh->GetVertex(i);
		verts.push_back( NxVec3(v.position.x, v.position.y, v.position.z) );
	}

    convex_mesh_desc.numVertices		= input_mesh->GetVertexNum();
    convex_mesh_desc.pointStrideBytes	= sizeof(NxVec3);
    convex_mesh_desc.points				= &verts[0];
	convex_mesh_desc.flags				= NX_CF_COMPUTE_CONVEX;
	
	ASSERT( convex_mesh_desc.isValid() );

	MemoryWriteBuffer	buf;	
	bool r = nx_cook->NxCookConvexMesh(convex_mesh_desc, buf);
	
	if (!r) {
		RUNTIME_ERROR("mesh contains to many vertices");
	}

	return nx->createConvexMesh(MemoryReadBuffer(buf.data));
}
Exemplo n.º 4
0
// ----------------------------------------------------------------------------------------------------------
void MeshHash::query(const NxBounds3 &bounds, NxArray<int> &itemIndices, int maxIndices)
{
	int x1,y1,z1;
	int x2,y2,z2;
	int x,y,z;

	cellCoordOf(bounds.min, x1,y1,z1);
	cellCoordOf(bounds.max, x2,y2,z2);

	itemIndices.clear();

	for (x = x1; x <= x2; x++)
  {
		for (y = y1; y <= y2; y++)
	  {
			for (z = z1; z <= z2; z++)
		  {
				int h = hashFunction(x,y,z);
				MeshHashRoot &r = mHashIndex[h];
				if (r.timeStamp != mTime) continue;
				int i = r.first;
				while (i >= 0)
			  {
					MeshHashEntry &entry = mEntries[i];
					itemIndices.push_back(entry.itemIndex);
					if (maxIndices >= 0 && (int)itemIndices.size() >= maxIndices) return;
					i = entry.next;
				}
			}
		}
	}
}
Exemplo n.º 5
0
// ----------------------------------------------------------------------------------------------------------
void MeshHash::query(const NxVec3 &pos, NxArray<int> &itemIndices, int maxIndices)
{
	int x,y,z;
	cellCoordOf(pos, x,y,z);
	itemIndices.clear();

	int h = hashFunction(x,y,z);
	MeshHashRoot &r = mHashIndex[h];
	if (r.timeStamp != mTime) return;
	int i = r.first;
	while (i >= 0)
  {
		MeshHashEntry &entry = mEntries[i];
		itemIndices.push_back(entry.itemIndex);
		if (maxIndices >= 0 && (int)itemIndices.size() >= maxIndices) return;
		i = entry.next;
	}
}
Exemplo n.º 6
0
// -----------------------------------------------------------------------
void VertexWelder::initialize(const NxClothMeshDesc& unweldedMesh)
{
	NxArray<NxU32> mapping;
	NxReal squaredEpsilon = mEpsilon * mEpsilon;
	for (NxU32 i = 0; i < unweldedMesh.numVertices; i++)
	{
		const NxVec3& curVec = *(const NxVec3*)(((const char*)unweldedMesh.points) + (i * unweldedMesh.pointStrideBytes));

		// Find Vertex in newVertices
		NxU32 newIndex = 0;
		for (newIndex = 0; newIndex < mNewVertices.size(); newIndex++)
		{
			NxVec3& newVec = mNewVertices[newIndex];
			if ((mEpsilon == 0 && newVec == curVec) || (newVec.distanceSquared(curVec) < squaredEpsilon))
			//if (newVec == curVec)
			{
				break;
			}
		}

		if (newIndex == mNewVertices.size())
		{
			// Not found in previous list
			mNewVertices.push_back(curVec);
		}

		mapping.push_back(newIndex);
	}

	// Store mapping
	mMappingSize = mapping.size();
	mMappingSpace = unweldedMesh.numTriangles * 3;
	mMappingDomain = mNewVertices.size();
	mMapping = (NxU32*)malloc(sizeof(NxU32) * mMappingSpace);
	memcpy(mMapping, &mapping[0], sizeof(NxU32) * mMappingSize);
	memset(((NxU32*)mMapping) + mMappingSize, 0, sizeof(NxU32) * (mMappingSpace - mMappingSize));
	mapping.clear();

	if (mNewVertices.size() < unweldedMesh.numVertices)
	{
		mUsed = true;
	}
	else
	{
		return;
	}

	if (unweldedMesh.flags & NX_MF_16_BIT_INDICES)
	{
		mNewFaces16 = (NxU16*)malloc(sizeof(NxU16) * unweldedMesh.numTriangles * 3);
	}
	else
	{
		mNewFaces32 = (NxU32*)malloc(sizeof(NxU32) * unweldedMesh.numTriangles * 3);
	}

	for (NxU32 i = 0; i < unweldedMesh.numTriangles; i++)
	{
		NxU32 triangles[3];
		const char* triangleChar = ((const char*)unweldedMesh.triangles) + (unweldedMesh.triangleStrideBytes * i);
		if (mNewFaces16)
		{
			const NxU16* tris = (const NxU16*)triangleChar;
			triangles[0] = tris[0];
			triangles[1] = tris[1];
			triangles[2] = tris[2];
		}
		else
		{
			assert(mNewFaces32 != NULL);
			const NxU32* tris = (const NxU32*)triangleChar;
			triangles[0] = tris[0];
			triangles[1] = tris[1];
			triangles[2] = tris[2];
		}

		for (NxU32 j = 0; j < 3; j++)
		{
			triangles[j] = getMapping(triangles[j]);
		}

		if (mNewFaces16)
		{
			for (NxU32 j = 0; j < 3; j++)
			{
				mNewFaces16[3*i+j] = (NxU16)(triangles[j] & 0xffff);
			}
		}
		else
		{
			for (NxU32 j = 0; j < 3; j++)
			{
				mNewFaces32[3*i+j] = triangles[j];
			}
		}
	}
}
Exemplo n.º 7
0
void VertexWelder::update(NxMeshData meshData)
{
	assert(mWriteVerticesPtr != NULL);

	bool updateVertices = (*(meshData.dirtyBufferFlagsPtr) & (NX_MDF_VERTICES_POS_DIRTY | NX_MDF_VERTICES_NORMAL_DIRTY)) > 0;
	bool updateIndices = (*(meshData.dirtyBufferFlagsPtr) & (NX_MDF_INDICES_DIRTY | NX_MDF_PARENT_INDICES_DIRTY)) > 0;

	NxU32 numNewVertices = *meshData.numVerticesPtr;
	NxU32 numTriangles = *meshData.numIndicesPtr / 3;
	NxU32 oldMappingDomain = mMappingDomain;
	
	NxArray<NewVertex> newVertices;
	NxArray<DifficultVertex> difficultVertices;

	mMappingDomainAddition = 0;

	if (updateVertices)
	{
		
		if (mMappingDomain < numNewVertices)
		{
#ifdef DEBUG_WELDER
			printf("------------------------------------\n");
#endif
			for (NxU32 i = mMappingDomain; i < numNewVertices; i++)
			{
				NewVertex v;
				v.index = i;
				v.parent = *(NxU32*)(((char*)meshData.parentIndicesBegin) + meshData.parentIndicesByteStride * i);
				while (v.parent >= (NxI32)mMappingDomain) {
					v.parent = *(NxU32*)(((char*)meshData.parentIndicesBegin) + meshData.parentIndicesByteStride * v.parent);
				}
#ifdef DEBUG_WELDER
				printf("New Vertex: %d %d\n", v.index, v.parent);
#endif
				newVertices.push_back(v);
			}
			std::sort(newVertices.begin(), newVertices.end(), sortParent);
		}
		
		for (NxU32 i = 0; i < mMappingSize; i++)
		{
			NxU32 mappedIndex = getMapping(i);

			NewVertex newV;
			newV.parent = mappedIndex;
			// Find all vertices that are a parent for a newly created vertex
			NxArray<NewVertex>::iterator found = std::lower_bound(newVertices.begin(), newVertices.end(), newV, sortParent);
			while (found != NULL && found->parent == mappedIndex)
			{
				found->mappedVertices ++;
				if (found->mappedVertices == 1)
				{
					found->unMapParent = i;
#ifdef DEBUG_WELDER
					printf("New Vertex Update, %d %d %d\n", found->index, found->parent, found->unMapParent);
#endif
				}
				else
				{
					// several unmapped parents
					DifficultVertex v;
					v.mappedIndex = found->index;
					v.unMappedIndex = i;
					difficultVertices.push_back(v);
#ifdef DEBUG_WELDER
					printf("Difficult Vertex %d %d\n", v.unMappedIndex, v.mappedIndex);
#endif

					if (found->mappedVertices == 2)
					{
						v.unMappedIndex = found->unMapParent;
						difficultVertices.push_back(v);
#ifdef DEBUG_WELDER
						printf("Difficult Vertex %d %d\n", v.unMappedIndex, v.mappedIndex);
#endif
					}

					found->unMapParent = -2;
				}
				found++;
			}
			

			NxVec3& vertex = *(NxVec3*)(((char*)mWriteVerticesPtr) + mWriteVerticesStride * i);
			NxVec3& normal = *(NxVec3*)(((char*)mWriteNormalsPtr) + mWriteNormalsStride* i);
			//float* texCoord = (float*)(((char*)texCoords) + texStride * i);

			const NxVec3& oldVertex = *(NxVec3*)(((char*)meshData.verticesPosBegin) + meshData.verticesPosByteStride * mappedIndex);
			const NxVec3& oldNormal = *(NxVec3*)(((char*)meshData.verticesNormalBegin) + meshData.verticesNormalByteStride * mappedIndex);

			vertex = oldVertex;
			normal = oldNormal;
		}
		// Adapt the mapping table
		std::sort(newVertices.begin(), newVertices.end(), sortIndex);
		std::sort(difficultVertices.begin(), difficultVertices.end(), sortDifficultExt);	
	}

	if (updateIndices)
	{
		std::vector<bool> bitVector(mMappingSpace, false);
#ifdef DEBUG_WELDER
		printf("updateIndices: Vertices: %d, Indices %d, gfx Vertices: %d\n", *meshData.numVerticesPtr, *meshData.numIndicesPtr, mMappingSize);
#endif
		if (difficultVertices.size() > 0)
		{
#ifdef DEBUG_WELDER
			printf("    Difficult Vertices:\n");
#endif
			for (NxU32 i = 0; i < difficultVertices.size(); i++)
			{
				DifficultVertex& v = difficultVertices[i];
#ifdef DEBUG_WELDER
				printf("      V %d %d\n", v.unMappedIndex, v.mappedIndex);
#endif
			}
		}
		assert((meshData.flags & NX_MF_16_BIT_INDICES) == 0);
		assert(meshData.indicesByteStride == 4);
		for (NxU32 i = 0; i < numTriangles; i++)
		{
			const NxU32* simTriangle = (NxU32*)(((char*)meshData.indicesBegin) + meshData.indicesByteStride * (i*3));
			NxU32* gfxTriangle = (NxU32*)(((char*)mWriteIndicesPtr) + mWriteIndicesStride* i);
			
			if (simTriangle[0] == simTriangle[1] && simTriangle[1] == simTriangle[2])
			{
				// Face was deleted (outside valid bounds probably)
				gfxTriangle[0] = gfxTriangle[1] = gfxTriangle[2] = 0;
				continue;
			}
			for (NxU32 j = 0; j < 3; j++)
			{

				DifficultVertex v;
				v.mappedIndex = simTriangle[j];
				v.unMappedIndex = gfxTriangle[j];
				if (std::binary_search(difficultVertices.begin(), difficultVertices.end(), v, sortDifficult))
				{
					NxArray<DifficultVertex>::iterator it = std::lower_bound(difficultVertices.begin(), difficultVertices.end(), v, sortDifficultExt);
#ifdef DEBUG_WELDER
					printf("-- Triangle %d (%d) (%d %d %d) (%d %d %d)", i, j, simTriangle[0], simTriangle[1], simTriangle[2], gfxTriangle[0], gfxTriangle[1], gfxTriangle[2]);
					printf(" %d %d\n", v.unMappedIndex, v.mappedIndex);
#endif

					if (it == NULL || it->mappedIndex != simTriangle[j])
					{
						// element hasn't been found

						//insert element
#ifdef DEBUG_WELDER
						printf("Adding Diff %d %d\n", v.unMappedIndex, v.mappedIndex);
#endif
						difficultVertices.push_back(v);

						// sort now, don't know whether this could be done less often, so far the list is extremely small
						std::sort(difficultVertices.begin(), difficultVertices.end(), sortDifficultExt);

						// get the freshly created item
						it = std::lower_bound(difficultVertices.begin(), difficultVertices.end(), v, sortDifficultExt);

						// element has to exist
						assert(it != NULL);
					}

					if (it->newUnMappedIndex >= 0)
					{
						gfxTriangle[j] = it->newUnMappedIndex;
					}
					else if (bitVector[it->unMappedIndex])
					{
#ifdef DEBUG_WELDER
						printf("Bit %d is true\n", it->unMappedIndex);
#endif
						// create a new gfx vertex
						it->newUnMappedIndex = mMappingSize;
						addNewVertex(gfxTriangle[j]);
						setMapping(it->newUnMappedIndex, simTriangle[j]);
						gfxTriangle[j] = it->newUnMappedIndex;
						bitVector[it->newUnMappedIndex] = true;
					}
					else
					{
#ifdef DEBUG_WELDER
						printf("Set Bit %d to true\n", it->unMappedIndex);
#endif
						bitVector[it->unMappedIndex] = true;
						it->newUnMappedIndex = it->unMappedIndex;
						setMapping(it->newUnMappedIndex, simTriangle[j]);
					}
				}
				else if (simTriangle[j] >= oldMappingDomain) // only used when not a difficult vertex
				{
					// unamp index and update
					for (NxU32 k = 0; k < newVertices.size(); k++)
					{
						NewVertex& v = newVertices[k];
						if (v.index == simTriangle[j] && v.mappedVertices == 1)
						{
#ifdef DEBUG_WELDER
							printf("- Triangle %d (%d %d %d) (%d %d %d)", i, simTriangle[0], simTriangle[1], simTriangle[2], gfxTriangle[0], gfxTriangle[1], gfxTriangle[2]);
							printf(" %d %d\n", v.unMapIndex, v.index);
#endif
							if (v.unMapIndex == -1)
							{
#ifdef DEBUG_WELDER
								printf("Add Simple\n");
#endif
								v.unMapIndex = mMappingSize;
								//addNewVertex(vertices, vertexStride, normals, normalStride, texCoords, texStride, v.unMapParent);
								addNewVertex(gfxTriangle[j]);
								gfxTriangle[j] = v.unMapIndex;
								setMapping(v.unMapIndex, v.index);
							}
							else
							{
#ifdef DEBUG_WELDER
								printf("Use Simple\n");
#endif
								gfxTriangle[j] = v.unMapIndex;
							}
							break; // for (k)
						}
					}
				}
			}
		}
	}

	if (updateVertices)
	{
		mMappingDomain = *meshData.numVerticesPtr;

#ifdef DEBUG_WELDER
		static bool sanityCheck = true;
		if (sanityCheck)
		{
			// sanity check
			NxU32 temp = 0;
			for (NxU32 i = 0; i < mMappingSize; i++)
			{
				temp = NxMath::max(getMapping(i), temp);
			}
			if (temp != mMappingDomain - 1)
			{
				printf("Mapping Domain not right, is %d, should be %d\n", temp, mMappingDomain-1);
				assert(0);
			}
			for (NxU32 i = 0; i < numTriangles; i++)
			{
				const NxU32* simTriangle = (NxU32*)(((char*)meshData.indicesBegin) + meshData.indicesByteStride * (i*3));
				NxU32* gfxTriangle = (NxU32*)(((char*)mWriteIndicesPtr) + mWriteIndicesStride * i);
				for (NxU32 j = 0; j < 3; j++)
				{
					if (simTriangle[j] != getMapping(gfxTriangle[j]))
					{
						printf("Triangle %d (%d) not correct (%d %d %d) -> (%d %d %d) != (%d %d %d)\n",
							i, 3*i+j,
							gfxTriangle[0], gfxTriangle[1], gfxTriangle[2],
							getMapping(gfxTriangle[0]), getMapping(gfxTriangle[1]), getMapping(gfxTriangle[2]),
							simTriangle[0], simTriangle[1], simTriangle[2]);
						assert(0);
					}
				}
			}
		}
#endif
	}

	return;
}
bool NxuPhysicsExport::Write(NxJoint *j,const char *userProperties,const char *id)
{
	bool ret = false;

	NxSceneDesc *current = getCurrentScene();

	CustomCopy cc(mCollection,current);

	NxJointDesc *joint = 0;

	switch ( j->getType() )
	{
		case NX_JOINT_PRISMATIC:
			if ( 1 )
			{
				::NxPrismaticJointDesc d1;
				NxPrismaticJoint *sj = j->isPrismaticJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxPrismaticJointDesc *desc = new NxPrismaticJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_REVOLUTE:
			if ( 1 )
			{
				::NxRevoluteJointDesc d1;
				NxRevoluteJoint *sj = j->isRevoluteJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxRevoluteJointDesc *desc = new NxRevoluteJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_CYLINDRICAL:
			if ( 1 )
			{
				::NxCylindricalJointDesc d1;
				NxCylindricalJoint *sj = j->isCylindricalJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxCylindricalJointDesc *desc = new NxCylindricalJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_SPHERICAL:
			if ( 1 )
			{
				::NxSphericalJointDesc d1;
				NxSphericalJoint *sj = j->isSphericalJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxSphericalJointDesc *desc = new NxSphericalJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_POINT_ON_LINE:
			if ( 1 )
			{
				::NxPointOnLineJointDesc d1;
				NxPointOnLineJoint *sj = j->isPointOnLineJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxPointOnLineJointDesc *desc = new NxPointOnLineJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_POINT_IN_PLANE:
			if ( 1 )
			{
				::NxPointInPlaneJointDesc d1;
				NxPointInPlaneJoint *sj = j->isPointInPlaneJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxPointInPlaneJointDesc *desc = new NxPointInPlaneJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_DISTANCE:
			if ( 1 )
			{
				::NxDistanceJointDesc d1;
				NxDistanceJoint *sj = j->isDistanceJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxDistanceJointDesc *desc = new NxDistanceJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_PULLEY:
			if ( 1 )
			{
				::NxPulleyJointDesc d1;
				NxPulleyJoint *sj = j->isPulleyJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxPulleyJointDesc *desc = new NxPulleyJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_FIXED:
			if ( 1 )
			{
				::NxFixedJointDesc d1;
				NxFixedJoint *sj = j->isFixedJoint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxFixedJointDesc *desc = new NxFixedJointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		case NX_JOINT_D6:
			if ( 1 )
			{
				::NxD6JointDesc d1;
				NxD6Joint *sj = j->isD6Joint();
				sj->saveToDesc(d1);
				addActor( d1.actor[0] );
				addActor( d1.actor[1] );
				NxD6JointDesc *desc = new NxD6JointDesc;
				desc->copyFrom(d1,cc);
				joint = static_cast<NxJointDesc *>(desc);
			}
			break;
		default:
			break;

	}


	//Add	Limits
	// in	addition,	we also	have to	write	out	its	limit	planes!
	j->resetLimitPlaneIterator();
	if (j->hasMoreLimitPlanes())
	{
		// write limit point
		joint->mOnActor2 = j->getLimitPoint(joint->mPlaneLimitPoint);

		NxArray< NxPlaneInfoDesc *> plist;


		// write the plane normals
		while	(j->hasMoreLimitPlanes())
		{
			NxPlaneInfoDesc *pInfo	=	new	NxPlaneInfoDesc();
#if NX_SDK_VERSION_NUMBER >= 272
			j->getNextLimitPlane(pInfo->mPlaneNormal,	pInfo->mPlaneD, &pInfo->restitution);
#else
			j->getNextLimitPlane(pInfo->mPlaneNormal,	pInfo->mPlaneD);
#endif
			plist.push_back(pInfo);
		}

		if ( plist.size() )
		{
			for (int i=plist.size()-1; i>=0; i--)
			{
				NxPlaneInfoDesc *p = plist[i];
				joint->mPlaneInfo.pushBack(p);
			}
		}

	}


	if ( joint )
	{
		if ( id )
		{
			joint->mId = id;
		}
		else
		{
      char scratch[512];
      sprintf(scratch,"Joint_%d", current->mJoints.size());
      joint->mId = getGlobalString(scratch);
      joint->mUserProperties = getGlobalString(userProperties);
    }
		current->mJoints.push_back(joint);
		ret = true;
	}

  return ret;
}