/*
 * Copyright 2009-2010 NVIDIA Corporation.  All rights reserved.
 *
 * NOTICE TO USER:
 *
 * This source code is subject to NVIDIA ownership rights under U.S. and
 * international Copyright laws.  Users and possessors of this source code
 * are hereby granted a nonexclusive, royalty-free license to use this code
 * in individual and commercial software.
 *
 * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
 * CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
 * IMPLIED WARRANTY OF ANY KIND.  NVIDIA DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
 * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 * OF USE, DATA OR PROFITS,  WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION,  ARISING OUT OF OR IN CONNECTION WITH THE USE
 * OR PERFORMANCE OF THIS SOURCE CODE.
 *
 * U.S. Government End Users.   This source code is a "commercial item" as
 * that term is defined at  48 C.F.R. 2.101 (OCT 1995), consisting  of
 * "commercial computer  software"  and "commercial computer software
 * documentation" as such terms are  used in 48 C.F.R. 12.212 (SEPT 1995)
 * and is provided to the U.S. Government only as a commercial end item.
 * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
 * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
 * source code with only those rights set forth herein.
 *
 * Any use of this source code in individual and commercial software must
 * include, in the user documentation and internal comments to the code,
 * the above Disclaimer and U.S. Government End Users Notice.
 */
#include "MirrorScene.h"
#include "PxScene.h"
#include "PxRigidDynamic.h"
#include "PxMaterial.h"
#include "PxSphereGeometry.h"
#include "PxRigidDynamic.h"
#include "PxRigidStatic.h"
#include "PxShape.h"

#pragma warning(disable:4100)

namespace physx
{

// This helper class copies properties from the source actor to the destination actor; but only after
// running the shapes through the application filter callback.
// Returns true if a valid actor is available.  This allows the application to specify some shapes to be
// mirrored but not others.
static bool copyStaticProperties(PxRigidActor& to, const PxRigidActor& from,NxMirrorScene::MirrorFilter &mirrorFilter)
{
#ifdef USE_STL
	ArrayContainer<PxShape*> shapes;
#else
	physx::shdfnd::InlineArray<PxShape*, 64> shapes;
#endif
	shapes.resize(from.getNbShapes());

	PxU32 shapeCount = from.getNbShapes();
#ifdef USE_STL
	from.getShapes(&shapes[0], shapeCount);
	ArrayContainer<PxMaterial*> materials;
#else
	from.getShapes(shapes.begin(), shapeCount);
	physx::shdfnd::InlineArray<PxMaterial*, 64> materials;
#endif
	for(PxU32 i = 0; i < shapeCount; i++)
	{
		PxShape* s = shapes[i];

		if ( mirrorFilter.shouldMirror(*s) )
		{
			PxU32 materialCount = s->getNbMaterials();
			materials.resize(materialCount);
#ifdef USE_STL
			s->getMaterials(&materials[0], materialCount);
			PxShape* shape = to.createShape(s->getGeometry().any(), &materials[0], materialCount, s->getLocalPose());
#else
			s->getMaterials(materials.begin(), materialCount);
			PxShape* shape = to.createShape(s->getGeometry().any(), materials.begin(), materialCount, s->getLocalPose());
#endif

			shape->setContactOffset(s->getContactOffset());
			shape->setRestOffset(s->getRestOffset());
			shape->setFlags(s->getFlags());
			shape->setSimulationFilterData(s->getSimulationFilterData());
			shape->setQueryFilterData(s->getQueryFilterData());
			shape->setFlag(PxShapeFlag::eUSE_SWEPT_BOUNDS,false); // disable swept bounds
			mirrorFilter.reviseMirrorShape(*shape);
		}
	}

	to.setActorFlags(from.getActorFlags());
	to.setOwnerClient(from.getOwnerClient());
	to.setClientBehaviorBits(from.getClientBehaviorBits());
	to.setDominanceGroup(from.getDominanceGroup());

	if ( to.getNbShapes() )
	{
		mirrorFilter.reviseMirrorActor(to);
	}

	return to.getNbShapes() != 0;
}

// Clone's a static actor
static PxRigidStatic* CloneStatic(PxPhysics& physicsSDK, 
							 const PxTransform& transform, 
							 const PxRigidActor& from,
							 NxMirrorScene::MirrorFilter &mirrorFilter)
{
	PxRigidStatic* to = physicsSDK.createRigidStatic(transform);
	if(!to)
		return NULL;

	if ( !copyStaticProperties(*to, from,mirrorFilter) )
	{
		to->release();
		to = NULL;
	}

	return to;
}

// Clone's a dynamic actor
PxRigidDynamic* CloneDynamic(PxPhysics& physicsSDK, 
							   const PxTransform& transform,
							   const PxRigidDynamic& from,
							   NxMirrorScene::MirrorFilter &mirrorFilter)
{
	PxRigidDynamic* to = physicsSDK.createRigidDynamic(transform);
	if(!to)
		return NULL;

	if ( !copyStaticProperties(*to, from, mirrorFilter) )
	{
		to->release();
		to = NULL;
		return NULL;
	}

	to->setRigidDynamicFlags(from.getRigidDynamicFlags());

	to->setMass(from.getMass());
	to->setMassSpaceInertiaTensor(from.getMassSpaceInertiaTensor());
	to->setCMassLocalPose(from.getCMassLocalPose());

	if ( !(to->getRigidDynamicFlags() & PxRigidDynamicFlag::eKINEMATIC) )
	{
		to->setLinearVelocity(from.getLinearVelocity());
		to->setAngularVelocity(from.getAngularVelocity());
	}

	to->setLinearDamping(from.getAngularDamping());
	to->setAngularDamping(from.getAngularDamping());

	to->setMaxAngularVelocity(from.getMaxAngularVelocity());

	PxU32 posIters, velIters;
	from.getSolverIterationCounts(posIters, velIters);
	to->setSolverIterationCounts(posIters, velIters);

	to->setSleepThreshold(from.getSleepThreshold());

	to->setContactReportThreshold(from.getContactReportThreshold());

	return to;
}

// MirrorScene constructor
MirrorScene::MirrorScene(physx::PxScene &primaryScene,
	physx::PxScene &mirrorScene,
	NxMirrorScene::MirrorFilter &mirrorFilter,
	physx::PxF32 mirrorStaticDistance,
	physx::PxF32 mirrorDynamicDistance,
	physx::PxF32 mirrorDistanceThreshold) : mPrimaryScene(primaryScene), 
	mMirrorScene(mirrorScene),
	mMirrorFilter(mirrorFilter),
	mMirrorStaticDistance(mirrorStaticDistance),
	mMirrorDynamicDistance(mirrorDynamicDistance),
	mTriggerActor(NULL),
	mTriggerMaterial(NULL),
	mTriggerShapeStatic(NULL),
	mTriggerShapeDynamic(NULL),
	mSimulationEventCallback(NULL),
	mMirrorDistanceThreshold(mirrorDistanceThreshold*mirrorDistanceThreshold)
{
	mLastCameraLocation = PxVec3(1e9,1e9,1e9);
}

// MirrorScene destructor.
MirrorScene::~MirrorScene(void)
{
	// Release the trigger actor from the primary scene if we created one.
	if ( mTriggerActor )
	{
		mPrimaryScene.lockWrite(__FILE__,__LINE__);
		mTriggerActor->release();
		mPrimaryScene.unlockWrite();
	}
	// Release the scratch trigger material
	if ( mTriggerMaterial )
	{
		mTriggerMaterial->release();
	}
}

// Helper class to create the trigger actor to be used to monitor dynamic and static objects
// in the primary scene.  It does this by creating two spheres registered for trigger events.
void MirrorScene::createTriggerActor(const physx::PxVec3 &cameraPosition)
{
	PX_ASSERT( mTriggerActor == NULL );
	mTriggerActor = mPrimaryScene.getPhysics().createRigidDynamic( physx::PxTransform(cameraPosition) );
	PX_ASSERT(mTriggerActor);
	if ( mTriggerActor )
	{
		mTriggerActor->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC,true);
		physx::PxSphereGeometry staticSphere;
		physx::PxSphereGeometry dynamicSphere;
		staticSphere.radius = mMirrorStaticDistance;
		dynamicSphere.radius = mMirrorDynamicDistance;
		mTriggerMaterial = mPrimaryScene.getPhysics().createMaterial(1,1,1);
		PX_ASSERT(mTriggerMaterial);
		if ( mTriggerMaterial )
		{
			mTriggerShapeStatic = mTriggerActor->createShape(staticSphere,*mTriggerMaterial);
			mTriggerShapeDynamic = mTriggerActor->createShape(dynamicSphere,*mTriggerMaterial);
			PX_ASSERT(mTriggerShapeStatic);
			PX_ASSERT(mTriggerShapeDynamic);
			if ( mTriggerShapeStatic && mTriggerShapeDynamic )
			{
				mPrimaryScene.lockWrite(__FILE__,__LINE__);

				mTriggerActor->setOwnerClient(0);
				mTriggerShapeStatic->setFlag(physx::PxShapeFlag::eSCENE_QUERY_SHAPE,false);
				mTriggerShapeStatic->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
				mTriggerShapeStatic->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE,true);

				mTriggerShapeDynamic->setFlag(physx::PxShapeFlag::eSCENE_QUERY_SHAPE,false);
				mTriggerShapeDynamic->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,false);
				mTriggerShapeDynamic->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE,true);

				mSimulationEventCallback = mPrimaryScene.getSimulationEventCallback(); // get a copy of the original callback
				mPrimaryScene.setSimulationEventCallback(this,0);
				mPrimaryScene.addActor(*mTriggerActor);

				mPrimaryScene.unlockWrite();
			}
		}
	}
}

// Each frame, we do a shape query for static and dynamic objects
// If this is the first time the synchronize has been called, then we create
// a trigger actor with two spheres in the primary scene.  This trigger
// actor is used to detect when objects move in and outside of the static and dynamic
// mirror range specified.
void MirrorScene::synchronizePrimaryScene(const physx::PxVec3 &cameraPos)
{
	PxVec3 diff = cameraPos - mLastCameraLocation;
	PxF32 dist = diff.magnitudeSquared();
	if ( dist > mMirrorDistanceThreshold )
	{
		mLastCameraLocation = cameraPos;
		if ( mTriggerActor == NULL )
		{
			createTriggerActor(cameraPos);	// Create the scene mirroring trigger actor 
		}
		if ( mTriggerActor )
		{
			mPrimaryScene.lockWrite(__FILE__,__LINE__);
			mTriggerActor->setKinematicTarget( PxTransform(cameraPos) );	// Update the position of the trigger actor to be the current camera location
			mPrimaryScene.unlockWrite();
		}
	}
	// Now, iterate on all of the current actors which are being mirrored
	// Only the primary scene after modifies this hash, so it is safe to do this
	// without any concerns of thread locking.
	// The mirrored scene thread does access the contents of this hash (MirrorActor)
	{
		mPrimaryScene.lockRead(__FILE__,__LINE__);
#ifdef USE_STL
		for (ActorHash::iterator i=mActors.begin(); i!=mActors.end(); ++i)
#else
		for (ActorHash::Iterator i=mActors.getIterator(); !i.done(); ++i)
#endif
		{
			MirrorActor *ma = i->second;
			ma->synchronizePose();	// check to see if the position of this object in the primary
			// scene has changed.  If it has, then we create a command for the mirror scene to update
			// it's mirror actor to that new position.
		}
		mPrimaryScene.unlockRead();
	}
}

// When the mirrored scene is synchronized, we grab the mirror command buffer
// And then despool all of the create/release/update commands that got posted previously by the
// primary scene thread.  A mutex is used to safe brief access to the command buffer.
// A copy of the command buffer is made so that we only grab the mutex for the shorted period
// of time possible.
void MirrorScene::synchronizeMirrorScene(void)
{
	MirrorCommandArray temp;
	mMirrorCommandMutex.lock();
	temp = mMirrorCommands;
	mMirrorCommands.clear();
	mMirrorCommandMutex.unlock();
	if ( !temp.empty() )
	{
		mMirrorScene.lockWrite(__FILE__,__LINE__);
		for (PxU32 i=0; i<temp.size(); i++)
		{
			MirrorCommand &mc = temp[i];
			switch ( mc.mType )
			{
				case MCT_CREATE_ACTOR:
					{
						mc.mMirrorActor->createActor(mMirrorScene);
					}
					break;
				case MCT_RELEASE_ACTOR:
					{
						delete mc.mMirrorActor;
					}
					break;
				case MCT_UPDATE_POSE:
					{
						mc.mMirrorActor->updatePose(mc.mPose);
					}
					break;
			}
		}
		mMirrorScene.unlockWrite();
	}
}

void MirrorScene::release(void)
{
	delete this;
}


/**
\brief This is called when a breakable constraint breaks.

\note The user should not release the constraint shader inside this call!

\param[in] constraints - The constraints which have been broken.
\param[in] count       - The number of constraints

@see PxConstraint PxConstraintDesc.linearBreakForce PxConstraintDesc.angularBreakForce
*/
void MirrorScene::onConstraintBreak(PxConstraintInfo* constraints, PxU32 count)
{
	if ( mSimulationEventCallback )
	{
		mSimulationEventCallback->onConstraintBreak(constraints,count);
	}
}

/**
\brief This is called during PxScene::fetchResults with the actors which have just been woken up.

\note Only supported by rigid bodies yet.
\note Only called on actors for which the PxActorFlag eSEND_SLEEP_NOTIFIES has been set.

\param[in] actors - The actors which just woke up.
\param[in] count  - The number of actors

@see PxScene.setSimulationEventCallback() PxSceneDesc.simulationEventCallback PxActorFlag PxActor.setActorFlag()
*/
void MirrorScene::onWake(PxActor** actors, PxU32 count)
{
	if ( mSimulationEventCallback )
	{
		mSimulationEventCallback->onWake(actors,count);
	}
}

/**
\brief This is called during PxScene::fetchResults with the actors which have just been put to sleep.

\note Only supported by rigid bodies yet.
\note Only called on actors for which the PxActorFlag eSEND_SLEEP_NOTIFIES has been set.  

\param[in] actors - The actors which have just been put to sleep.
\param[in] count  - The number of actors

@see PxScene.setSimulationEventCallback() PxSceneDesc.simulationEventCallback PxActorFlag PxActor.setActorFlag()
*/
void MirrorScene::onSleep(PxActor** actors, PxU32 count)
{
	if ( mSimulationEventCallback )
	{
		mSimulationEventCallback->onSleep(actors,count);
	}

}

/**
\brief The user needs to implement this interface class in order to be notified when
certain contact events occur.

The method will be called for a pair of actors if one of the colliding shape pairs requested contact notification.
You request which events are reported using the filter shader/callback mechanism (see #PxSimulationFilterShader,
#PxSimulationFilterCallback, #PxPairFlag).

Do not keep references to the passed objects, as they will be 
invalid after this function returns.

\param[in] pairHeader Information on the two actors whose shapes triggered a contact report.
\param[in] pairs The contact pairs of two actors for which contact reports have been requested. See #PxContactPair.
\param[in] nbPairs The number of provided contact pairs.

@see PxScene.setSimulationEventCallback() PxSceneDesc.simulationEventCallback PxContactPair PxPairFlag PxSimulationFilterShader PxSimulationFilterCallback
*/
void MirrorScene::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs)
{
	if ( mSimulationEventCallback )
	{
		mSimulationEventCallback->onContact(pairHeader,pairs,nbPairs);
	}

}

/*
Here we process the trigger events which belong to use, and then retain the ones 
belonging to the application and pass them onto it.
*/
void MirrorScene::onTrigger(PxTriggerPair* pairs, PxU32 count)
{
	mTriggerPairs.clear();
	for (PxU32 i=0; i<count; i++)
	{
		PxTriggerPair &tp = pairs[i];

		if ( ( tp.triggerShape == mTriggerShapeStatic ) || ( tp.triggerShape == mTriggerShapeDynamic ) )
		{
			if ( tp.flags & PxTriggerPairFlag::eDELETED_SHAPE_OTHER ) // actor was deleted!
			{
				// handle shape release..
				mirrorShape(tp);
			}
			else
			{
				PxActor *actor = &tp.otherShape->getActor();
				if( mMirrorFilter.shouldMirror(*actor) ) // let the application telll us whether this is an actor we want to mirror or not
				{
					if ( tp.triggerShape == mTriggerShapeStatic ) 
					{
						if ( actor->getType() == PxActorType::eRIGID_STATIC )
						{
							mirrorShape(tp);
						}
					}
					else if ( tp.triggerShape == mTriggerShapeDynamic )
					{
						if ( actor->getType() == PxActorType::eRIGID_DYNAMIC )
						{
							mirrorShape(tp);
						}
					}
				}
			}
		}
		else
		{
#ifdef USE_STL
			mTriggerPairs.push_back(tp);
#else
			mTriggerPairs.pushBack(tp);
#endif
		}
	}
	if ( !mTriggerPairs.empty() ) // If some of the triggers were for the application; then we pass them on
	{
		mSimulationEventCallback->onTrigger(&mTriggerPairs[0],mTriggerPairs.size());
	}
}

void MirrorScene::mirrorShape(const PxTriggerPair &tp)
{
	size_t hash = (size_t)tp.otherShape;
#ifdef USE_STL
	MirrorActor *ma = NULL;
	ShapeHash::iterator found = mShapes.find(hash);
	if ( found != mShapes.end() )
	{
		ma = (*found).second;
	}
#else
	const ShapeHash::Entry *found = mShapes.find(hash);
	MirrorActor *ma = found ? found->second : NULL;
#endif
	if ( tp.flags & PxTriggerPairFlag::eDELETED_SHAPE_OTHER )
	{
		if ( ma )
		{
			bool kill = ma->removeShape();
			mShapes.erase(hash);
			if ( kill )
			{
				ma->release();
				mActors.erase( ma->mActorHash );
			}
		}
	}
	else if ( tp.status == PxPairFlag::eNOTIFY_TOUCH_FOUND )
	{
		size_t actorHash = (size_t) &tp.otherShape->getActor();
#ifdef USE_STL
		ActorHash::iterator foundActor = mActors.find(actorHash);
		if ( foundActor == mActors.end() )
		{
			ma = PX_NEW(MirrorActor)(actorHash,tp.otherShape->getActor(),*this);
			mActors[actorHash] = ma;
		}
		else
		{
			ma = (*foundActor).second;
		}
#else
		PX_ASSERT( found == NULL );
		const ActorHash::Entry *foundActor = mActors.find(actorHash);
		if ( foundActor == NULL )
		{
			ma = PX_NEW(MirrorActor)(actorHash,tp.otherShape->getActor(),*this);
			mActors[actorHash] = ma;
		}
		else
		{
			ma = foundActor->second;
		}
#endif
		ma->addShape();
		mShapes[hash] = ma;
	}
	else if ( tp.status == PxPairFlag::eNOTIFY_TOUCH_LOST )
	{
#ifndef USE_STL
		PX_ASSERT( found );
#endif
		bool kill = ma->removeShape();
		mShapes.erase(hash);
		if ( kill )
		{
			mActors.erase( ma->mActorHash );
			ma->release();
		}
	}

}

void MirrorScene::postCommand(const MirrorCommand &mc)
{
	mMirrorCommandMutex.lock();
#ifdef USE_STL
	mMirrorCommands.push_back(mc);
#else
	mMirrorCommands.pushBack(mc);
#endif
	mMirrorCommandMutex.unlock();
}

MirrorActor::MirrorActor(size_t actorHash,
						 physx::PxRigidActor &actor,
						 MirrorScene &mirrorScene) : mActorHash(actorHash), mPrimaryActor(&actor), mMirrorScene(mirrorScene)
{
	mReleasePosted = false;
	mMirrorActor = NULL;
	mShapeCount = 0;
	PxScene *scene = actor.getScene();
	PX_ASSERT(scene);
	if ( scene )
	{
		scene->lockWrite(__FILE__,__LINE__);
		mPrimaryActor->registerObserver(*this);
		mPrimaryGlobalPose = actor.getGlobalPose();
		PxPhysics *sdk = &scene->getPhysics();
		if ( actor.getType() == physx::PxActorType::eRIGID_STATIC )
		{
			mMirrorActor = CloneStatic(*sdk,actor.getGlobalPose(),actor, mirrorScene.getMirrorFilter());
		}
		else
		{
			physx::PxRigidDynamic *rd = static_cast< physx::PxRigidDynamic *>(&actor);
			mMirrorActor = CloneDynamic(*sdk,actor.getGlobalPose(),*rd, mirrorScene.getMirrorFilter());
			if ( mMirrorActor )
			{
				rd = static_cast< physx::PxRigidDynamic *>(mMirrorActor);
				rd->setRigidDynamicFlag(physx::PxRigidDynamicFlag::eKINEMATIC,true);
			}
		}
		scene->unlockWrite();
		if ( mMirrorActor )
		{
			MirrorCommand mc(MCT_CREATE_ACTOR,this);
			mMirrorScene.postCommand(mc);
		}
	}
}

MirrorActor::~MirrorActor(void)
{
	if ( mMirrorActor )
	{
		mMirrorActor->release();
	}
}

void MirrorActor::release(void)
{
	PX_ASSERT( mReleasePosted == false );
	if ( !mReleasePosted )
	{
		if ( mPrimaryActor )
		{
			mPrimaryActor->unregisterObserver(*this);
		}
		MirrorCommand mc(MCT_RELEASE_ACTOR,this);
		mMirrorScene.postCommand(mc);
		mReleasePosted = true;
	}
}

void MirrorActor::createActor(PxScene &scene)
{
	if ( mMirrorActor )
	{
		scene.addActor(*mMirrorActor);
	}
}

static bool sameTransform(const PxTransform &a,const PxTransform &b)
{
	if ( a.p == b.p && 
		 a.q.x == b.q.x && 
		 a.q.y == b.q.y &&
		 a.q.z == b.q.z &&
		 a.q.w == b.q.w )
	{
		return true;
	}
	return false;
}

void MirrorActor::synchronizePose(void)
{
	if ( mPrimaryActor )
	{
		physx::PxTransform p = mPrimaryActor->getGlobalPose();
		if ( !sameTransform(p,mPrimaryGlobalPose) )
		{
			mPrimaryGlobalPose = p;
			MirrorCommand mc(MCT_UPDATE_POSE,this,p);
			mMirrorScene.postCommand(mc);
		}
	}
}

void MirrorActor::updatePose(const PxTransform &pose)
{
	if ( mMirrorActor )
	{
		if ( mMirrorActor->getType() == PxActorType::eRIGID_STATIC )
		{
			PxRigidStatic *p = static_cast< PxRigidStatic *>(mMirrorActor);
			p->setGlobalPose(pose);
		}
		else
		{
			PxRigidDynamic *p = static_cast< PxRigidDynamic *>(mMirrorActor);
			p->setKinematicTarget(pose);
		}
	}
}

NxMirrorScene *createMirrorScene(physx::PxScene &primaryScene,	// The primary scene that is being mirrored
								 physx::PxScene &mirrorScene,	// The scene to mirror objects into
								 NxMirrorScene::MirrorFilter &mirrorFilter,	// The application interface to determine which objects should be mirrored
								 physx::PxF32 mirrorStaticDistance,		// The distance to mirror static objects
								 physx::PxF32 mirrorDynamicDistance,		// The distance to mirror dynamic objects
								 physx::PxF32 mirrorRefreshDistance)	// The camera movement distance before a refresh of the trigger spheres takes place
{
	MirrorScene *ms = PX_NEW(MirrorScene)(primaryScene,mirrorScene,mirrorFilter,mirrorStaticDistance,mirrorDynamicDistance,mirrorRefreshDistance);
	return static_cast< NxMirrorScene *>(ms);
}


}; // end physx namespace

