void ApexRenderMeshAsset::releaseActor(NxRenderMeshActor& renderMeshActor)
{
	ApexRenderMeshActor* actor = DYNAMIC_CAST(ApexRenderMeshActor*)(&renderMeshActor);
	actor->destroy();

	// Last one out turns out the lights
	if (!mActorList.getSize())
	{
		NxUserRenderResourceManager* rrm = NiGetApexSDK()->getUserRenderResourceManager();
		for (physx::PxU32 i = 0 ; i < mRuntimeSubmeshData.size() ; i++)
		{
			if (mRuntimeSubmeshData[i].staticVertexBuffer != NULL)
			{
				rrm->releaseVertexBuffer(*mRuntimeSubmeshData[i].staticVertexBuffer);
				mRuntimeSubmeshData[i].staticVertexBuffer = NULL;
			}
			if (mRuntimeSubmeshData[i].skinningVertexBuffer != NULL)
			{
				rrm->releaseVertexBuffer(*mRuntimeSubmeshData[i].skinningVertexBuffer);
				mRuntimeSubmeshData[i].skinningVertexBuffer = NULL;
			}
			if (mRuntimeSubmeshData[i].dynamicVertexBuffer != NULL)
			{
				rrm->releaseVertexBuffer(*mRuntimeSubmeshData[i].dynamicVertexBuffer);
				mRuntimeSubmeshData[i].dynamicVertexBuffer = NULL;
			}
		}
		mRuntimeSubmeshData.clear();
	}
}
NxParameterized::Interface* ImpactEmitterAsset::getDefaultAssetPreviewDesc()
{
	NX_WRITE_ZONE();
	NxParameterized::Traits* traits = NiGetApexSDK()->getParameterizedTraits();
	PX_ASSERT(traits);
	if (!traits)
	{
		return NULL;
	}

	// create if not yet created
	if (!mDefaultPreviewParams)
	{
		const char* className = EmitterAssetPreviewParameters::staticClassName();
		NxParameterized::Interface* param = traits->createNxParameterized(className);
		mDefaultPreviewParams = static_cast<EmitterAssetPreviewParameters*>(param);

		PX_ASSERT(param);
		if (!param)
		{
			return NULL;
		}
	}

	return mDefaultPreviewParams;
}
ClothFactory ClothingScene::getClothFactory(bool& useCuda)
{
#ifdef PX_WINDOWS
	if (useCuda)
	{
		if (mGpuFactory.factory == NULL)
		{
			PxCudaContextManager* contextManager = NULL;
			PxGpuDispatcher* gpuDispatcher = mApexScene->getTaskManager()->getGpuDispatcher();
			if (gpuDispatcher != NULL)
			{
				contextManager = gpuDispatcher->getCudaContextManager();
			}

			if (contextManager != NULL)
			{
				mGpuFactory = mModule->createClothFactory(contextManager);
				if (mGpuFactory.factory != NULL)
				{
					NiApexSDK* apexSdk = NiGetApexSDK();
					mPhysXGpuIndicator = apexSdk->registerPhysXIndicatorGpuClient();
				}
			}
		}

		//APEX_DEBUG_INFO("Gpu Factory %p", mGpuFactory);
		if (mGpuFactory.factory != NULL)
		{
			return mGpuFactory;
		}
		else
		{
			APEX_DEBUG_INFO("Gpu Factory could not be created");
			useCuda = false;
		}
	}
	
	if (!useCuda)
#else
	PX_UNUSED(useCuda);
#endif
	{
		if (mCpuFactory.factory == NULL)
		{
			mCpuFactory = mModule->createClothFactory(NULL);
		}

		//APEX_DEBUG_INFO("Cpu Factory %p", mCpuFactory.factory);
		return mCpuFactory;
	}

#ifdef PX_WINDOWS
	PX_ALWAYS_ASSERT_MESSAGE("this code path is unreachable, at least it used to be.");
	return ClothFactory(NULL, NULL);
#endif
}
// Load all of our named resources (that consists of materials) if they are
// not registered in the NRP
physx::PxU32 ApexRenderMeshAsset::forceLoadAssets()
{
	physx::PxU32 assetLoadedCount = 0;
	NiResourceProvider* nrp = NiGetApexSDK()->getInternalResourceProvider();
	NxResID materialNS = NiGetApexSDK()->getMaterialNameSpace();

	for (physx::PxU32 i = 0; i < mMaterialIDs.size(); i++)
	{

		if (!nrp->checkResource(materialNS, mParams->materialNames.buf[i]))
		{
			/* we know for SURE that createResource() has already been called, so just getResource() */
			nrp->getResource(mMaterialIDs[i]);
			assetLoadedCount++;
		}
	}

	return assetLoadedCount;
}
ApexRenderMeshAsset::~ApexRenderMeshAsset()
{
	// this should have been cleared in releaseActor()
	PX_ASSERT(mRuntimeSubmeshData.empty());

	// Release named resources
	NiResourceProvider* resourceProvider = NiGetApexSDK()->getInternalResourceProvider();
	for (physx::PxU32 i = 0 ; i < mMaterialIDs.size() ; i++)
	{
		resourceProvider->releaseResource(mMaterialIDs[i]);
	}

	setSubmeshCount(0);
}
NxParameterized::Interface* ImpactEmitterAsset::getDefaultActorDesc()
{
	NX_WRITE_ZONE();
	NxParameterized::ErrorType error = NxParameterized::ERROR_NONE;
	PX_UNUSED(error);

	NxParameterized::Traits* traits = NiGetApexSDK()->getParameterizedTraits();
	PX_ASSERT(traits);
	if (!traits)
	{
		return NULL;
	}

	// create if not yet created
	if (!mDefaultActorParams)
	{
		const char* className = ImpactEmitterActorParameters::staticClassName();
		NxParameterized::Interface* param = traits->createNxParameterized(className);
		mDefaultActorParams = static_cast<ImpactEmitterActorParameters*>(param);

		PX_ASSERT(param);
		if (!param)
		{
			return NULL;
		}
	}
	NxParameterized::Handle hDest(*mDefaultActorParams);
	
#if NX_SDK_VERSION_MAJOR == 2
	NxParameterized::Interface* explParams = 0;
	error = mDefaultActorParams->getParameterHandle("explosionEnv", hDest);
	PX_ASSERT(NxParameterized::ERROR_NONE == error);

	mDefaultActorParams->initParamRef(hDest, hDest.parameterDefinition()->refVariantVal(0), true);
	mDefaultActorParams->getParamRef(hDest, explParams);

	PX_ASSERT(explParams);
	if (explParams)
	{
		explParams->initDefaults();
	}
#endif

	return mDefaultActorParams;
}
ImpactEmitterAsset::ImpactEmitterAsset(ModuleEmitter* m, NxResourceList& list, const char* name) :
	mModule(m),
	mName(name),
	mIofxAssetTracker(m->mSdk, NX_IOFX_AUTHORING_TYPE_NAME),
	mIosAssetTracker(m->mSdk),
#if NX_SDK_VERSION_MAJOR == 2
	mExplosionAssetTracker(m->mSdk, NX_EXPLOSION_AUTHORING_TYPE_NAME),
#endif
	mDefaultActorParams(NULL),
	mDefaultPreviewParams(NULL)
{
	NxParameterized::Traits* traits = NiGetApexSDK()->getParameterizedTraits();
	mParams = (ImpactEmitterAssetParameters*)traits->createNxParameterized(ImpactEmitterAssetParameters::staticClassName());

	PX_ASSERT(mParams);

	mParams->setSerializationCallback(this);
	list.add(*this);
}
void ApexRenderMeshAsset::createLocalData()
{
	mMaterialIDs.resize((physx::PxU32)mParams->materialNames.arraySizes[0]);
	NiResourceProvider* resourceProvider = NiGetApexSDK()->getInternalResourceProvider();
	NxResID materialNS = NiGetApexSDK()->getMaterialNameSpace();
	NxResID customVBNS = NiGetApexSDK()->getCustomVBNameSpace();


	// Resolve material names using the NRP...
	for (physx::PxU32 i = 0; i < (physx::PxU32)mParams->materialNames.arraySizes[0]; ++i)
	{
		if (resourceProvider)
		{
			mMaterialIDs[i] = resourceProvider->createResource(materialNS, mParams->materialNames.buf[i]);
		}
		else
		{
			mMaterialIDs[i] = INVALID_RESOURCE_ID;
		}
	}

	// Resolve custom vertex buffer semantics using the NRP...
	mRuntimeCustomSubmeshData.resize(getSubmeshCount());
	//JPB memset(mRuntimeCustomSubmeshData.begin(), 0, sizeof(CustomSubmeshData) * mRuntimeCustomSubmeshData.size());

	for (physx::PxU32 i = 0; i < getSubmeshCount(); ++i)
	{
		const NxVertexFormat& fmt = getSubmesh(i).getVertexBuffer().getFormat();

		mRuntimeCustomSubmeshData[i].customBufferFormats.resize(fmt.getCustomBufferCount());
		mRuntimeCustomSubmeshData[i].customBufferVoidPtrs.resize(fmt.getCustomBufferCount());

		physx::PxU32 customBufferIndex = 0;
		for (physx::PxU32 j = 0; j < fmt.getBufferCount(); ++j)
		{
			if (fmt.getBufferSemantic(j) != NxRenderVertexSemantic::CUSTOM)
			{
				continue;
			}
			NxRenderDataFormat::Enum f = fmt.getBufferFormat(j);
			const char* name = fmt.getBufferName(j);

			mRuntimeCustomSubmeshData[i].customBufferFormats[customBufferIndex] = f;
			mRuntimeCustomSubmeshData[i].customBufferVoidPtrs[customBufferIndex] = 0;

			if (resourceProvider)
			{
				NxResID id = resourceProvider->createResource(customVBNS, name, true);
				mRuntimeCustomSubmeshData[i].customBufferVoidPtrs[customBufferIndex] = NiGetApexSDK()->getInternalResourceProvider()->getResource(id);
			}

			++customBufferIndex;
		}
	}

	// find the bone count
	// LRR - required for new deserialize path
	// PH - mBoneCount is now serialized
	if (mParams->boneCount == 0)
	{
		for (physx::PxU32 i = 0; i < getSubmeshCount(); i++)
		{

			NxRenderDataFormat::Enum format;
			const NxVertexBuffer& vb = mSubmeshes[i]->getVertexBuffer();
			const NxVertexFormat& vf = vb.getFormat();
			physx::PxU32 bufferIndex = (physx::PxU32)vf.getBufferIndexFromID(vf.getSemanticID(physx::NxRenderVertexSemantic::BONE_INDEX));
			physx::PxU16* boneIndices = (physx::PxU16*)vb.getBufferAndFormat(format, bufferIndex);

			if (boneIndices == NULL)
			{
				continue;
			}

			if (!vertexSemanticFormatValid(NxRenderVertexSemantic::BONE_INDEX, format))
			{
				continue;
			}

			const PxU32 bonesPerVert = vertexSemanticFormatElementCount(NxRenderVertexSemantic::BONE_INDEX, format);

			PX_ASSERT(format == NxRenderDataFormat::USHORT1 || format == NxRenderDataFormat::USHORT2 || format == NxRenderDataFormat::USHORT3 || format == NxRenderDataFormat::USHORT4);

			const PxU32 numVertices = vb.getVertexCount();
			for (PxU32 v = 0; v < numVertices; v++)
			{
				for (PxU32 b = 0; b < bonesPerVert; b++)
				{
					mParams->boneCount = physx::PxMax(mParams->boneCount, (physx::PxU32)(boneIndices[v * bonesPerVert + b] + 1));
				}
			}
		}
	}

	// PH - have one bone at all times, if it's just one, it is used as current pose (see ApexRenderMeshActor::dispatchRenderResources)
	if (mParams->boneCount == 0)
	{
		mParams->boneCount = 1;
	}
}
void ClothingScene::destroy()
{
	for (PxU32 i = 0; i < mActorArray.size(); i++)
	{
		ClothingActor* clothingActor = static_cast<ClothingActor*>(mActorArray[i]);
		clothingActor->waitForFetchResults();
	}

	removeAllActors();

	mClothingAssetsMutex.lock();
	for (physx::PxU32 i = 0 ; i < mClothingAssets.size(); i++)
	{
		if (mPhysXScene != NULL)
		{
			mClothingAssets[i]->hintSceneDeletion(mPhysXScene);
		}

		// for PhysX3: making sure that fabrics (in assets) are released before the factories (in mSimulationTask)
		mClothingAssets[i]->releaseCookedInstances();
	}
	mClothingAssets.clear();
	mClothingAssetsMutex.unlock();

	// clear render list
	for(HashMap<NiApexRenderMeshAsset*, Array<ClothingRenderProxy*> >::Iterator iter = mRenderProxies.getIterator(); !iter.done(); ++iter)
	{
		Array<ClothingRenderProxy*>& renderProxies = iter->second;

		for (PxI32 i = (physx::PxI32)renderProxies.size()-1; i >= 0 ; --i)
		{
			PxU32 timeInPool = renderProxies[(physx::PxU32)i]->getTimeInPool();
			if (timeInPool > 0)
			{
				PX_DELETE(renderProxies[(physx::PxU32)i]);
				renderProxies.replaceWithLast((physx::PxU32)i);
			}
			else
			{
				// actually the scene is released, but we just want to make sure
				// that the render proxy deletes itself when it's returned next time
				renderProxies[(physx::PxU32)i]->notifyAssetRelease();
			}
		}

		renderProxies.clear();
	}
	//mRenderProxies.clear();

	while (mCurrentCookingTask != NULL)
	{
		submitCookingTask(NULL);
		physx::Thread::sleep(0); // wait for remaining cooking tasks to finish
	}

	if (mSimulationTask != NULL)
	{
		setModulePhysXScene(NULL); // does some cleanup necessary here. Only needed when module gets deleted without the apex scene being deleted before!
		PX_DELETE(mSimulationTask);
		mSimulationTask = NULL;
	}

	if (mWaitForSolverTask != NULL)
	{
		PX_DELETE(mWaitForSolverTask);
		mWaitForSolverTask = NULL;
	}

	{
		if (mCpuFactory.factory != NULL)
		{
			mModule->releaseClothFactory(NULL);
			mCpuFactory.clear();
		}

#ifdef PX_WINDOWS
		PX_ASSERT(mGpuFactory.factory == NULL);

		NiApexSDK* apexSdk = NiGetApexSDK();
		apexSdk->unregisterPhysXIndicatorGpuClient(mPhysXGpuIndicator);
		mPhysXGpuIndicator = NULL;
#endif
	}

	mApexScene->moduleReleased(*this);
	delete this;
}