//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.  

#include "geometry/PxGeometry.h"
#include "Ps.h"
#include "GuCCDSweepConvexMesh.h"
#include "PsHashMap.h"
#include "PxsIslandSim.h"

#ifndef PXS_CCD_H
#define PXS_CCD_H

#define CCD_DEBUG_PRINTS						0
#define CCD_POST_DEPENETRATE_DIST				0.001f
#define CCD_ROTATION_LOCKING					0
#define CCD_MIN_TIME_LEFT						0.01f
#define CCD_ANGULAR_IMPULSE						0

#define DEBUG_RENDER_CCD						0

#if CCD_DEBUG_PRINTS
namespace physx {
	extern void printCCDDebug(const char* msg, const PxsRigidBody* atom0, PxGeometryType::Enum g0, bool printPtr = true);
	extern void printShape(PxsRigidBody* atom0, PxGeometryType::Enum g0, const char* annotation, PxReal dt, PxU32 pass, bool printPtr = true);
}
#define PRINTCCDSHAPE(x) printShape x
#define PRINTCCDDEBUG(x) printCCDDebug x
#else
#define PRINTCCDSHAPE(x)
#define PRINTCCDDEBUG(x)
#endif

namespace physx
{

// ------------------------------------------------------------------------------------------------------------
// a fraction of objects will be CCD active so this is dynamic, not a member of PsxRigidBody
// CCD code builds a temporary array of PxsCCDPair objects (allocated in blocks)
// this is done to gather scattered data from memory and also to reduce PxsRidigBody permanent memory footprint
// we have to do it every pass since new CMs can become fast moving after each pass (and sometimes cease to be)
//
struct PxsCCDBody;
class PxsRigidBody;
struct PxsShapeCore;
struct PxsRigidCore;
class PxsContactManager;
class PxsContext;
class PxCCDContactModifyCallback;
class PxcNpThreadContext;

class PxvNphaseImplementationContext;

namespace Dy
{
	class ThresholdStream;
}


/**
\brief structure to represent interactions between a given body and another body.
*/
struct PxsCCDOverlap
{
	//The body the interaction relates to
	PxsCCDBody* mBody;
	//The next interaction in the list
	PxsCCDOverlap* mNext;
};

/**
\brief Temporary CCD representation for a shape.

Stores data about a shape that may be frequently used in CCD. It also stores update counters per-shape that can be compared with the body's update
counter to determine if the shape needs its transforms re-calculated. This avoids us needing to store a list of shapes in a CCD body.
*/
struct PxsCCDShape : public Gu::CCDShape
{
public:
	const PxsShapeCore*			mShapeCore;					//Shape core (can be shared)
	const PxsRigidCore*			mRigidCore;					//Rigid body core
	IG::NodeIndex				mNodeIndex;

	/**
	\brief Returns the world-space pose for this shape
	\param[in] atom The rigid body that this CCD shape is associated with
	*/
	PxTransform										getAbsPose(const PxsRigidBody* atom)			const;
	/**
	\brief Returns the world-space previous pose for this shape
	\param[in] atom The rigid body that this CCD shape is associated with
	*/
	PxTransform										getLastCCDAbsPose(const PxsRigidBody* atom)		const;						
};

/**
\brief Structure to represent a body in the CCD system. 
*/
struct PxsCCDBody
{
	Cm::SpatialVector			mPreSolverVelocity;
	PxU16						mIndex;						//The CCD body's index
	bool						mPassDone;					//Whether it has been processed in the current CCD pass
	bool						mHasAnyPassDone;			//Whether this body was influenced by any passes
	PxReal						mTimeLeft;					//CCD time left to elapse (normalized in range 0-1)
	PxsRigidBody*				mBody;						//The rigid body 
	PxsCCDOverlap*				mOverlappingObjects;		//A list of overlapping bodies for island update
	PxU32						mUpdateCount;				//How many times this body has eben updated in the CCD. This is correlated with CCD shapes' update counts.
	PxU32						mNbInteractionsThisPass;	//How many interactions this pass

	

	/**
	\brief Returns the CCD body's index.
	\return The CCD body's index.
	*/
	PX_FORCE_INLINE PxU32 getIndex() const { return mIndex; }

	/**
	\brief Tests whether this body has already registered an overlap with a given body.
	\param[in] body The body to test against.
	\return Whether this body has already registered an overlap with a given body.
	*/
	bool overlaps(PxsCCDBody* body) const
	{
		PxsCCDOverlap* overlaps = mOverlappingObjects;

		while(overlaps)
		{
			if(overlaps->mBody == body)
				return true;
			overlaps = overlaps->mNext;
		}
		return false;
	}

	/**
	\brief Registers an overlap with a given body
	\param[in] overlap The CCD overlap to register.
	*/
	void addOverlap(PxsCCDOverlap* overlap)
	{
		overlap->mNext = mOverlappingObjects;
		mOverlappingObjects = overlap;
	}

};

/**
\brief a container class used in the CCD that minimizes frequency of hitting the allocator.

This class stores a set of blocks of memory. It is effectively an array that resizes more efficiently because it doesn't need to 
reallocate an entire buffer and copy data.
*/
template<typename T, int BLOCK_SIZE>
struct PxsCCDBlockArray
{
	/**
	\brief A block of data
	*/
	struct Block : Ps::UserAllocated { T items[BLOCK_SIZE]; };
	/**
	\brief A header for a block of data.
	*/
	struct BlockInfo
	{
		Block* block;
		PxU32 count; // number of elements in this block
		BlockInfo(Block* aBlock, PxU32 aCount) : block(aBlock), count(aCount) {}
	};
	/*
	\brief An array of block headers
	*/
	Ps::Array<BlockInfo> blocks;
	/**
	\brief The current block.
	*/
	PxU32 currentBlock;

	/**
	\brief Constructor
	*/
	PxsCCDBlockArray() : currentBlock(0)
	{
		blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
	}

	/**
	\brief Destructor
	*/
	~PxsCCDBlockArray()
	{
		for (PxU32 i = 0; i < blocks.size(); i++)
		{
			PX_DELETE(blocks[i].block);
		}
		currentBlock = 0;
	}

	/**
	\brief Clears this block array.
	\note This clear function also deletes all additional blocks
	*/
	void clear()
	{
		for (PxU32 i = 0; i < blocks.size(); i++)
		{
			PX_DELETE(blocks[i].block);
		}
		blocks.clear();
		blocks.pushBack(BlockInfo(PX_NEW(Block), 0)); // at least one block is expected to always be present in the array
		currentBlock = 0;
	}

	/**
	\brief Clears this block array but does not release the memory.
	*/
	void clear_NoDelete()
	{
		currentBlock = 0;
		blocks[0].count = 0;
	}

	/**
	\brief Push a new element onto the back of the block array
	\return The new element
	*/
	T& pushBack()
	{
		PxU32 numBlocks = blocks.size();
		if (blocks[currentBlock].count == BLOCK_SIZE)
		{
			if((currentBlock + 1) == numBlocks)
			{
				blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
				numBlocks ++;
			}
			currentBlock++;
			blocks[currentBlock].count = 0;
		}
		const PxU32 count = blocks[currentBlock].count ++;

		return blocks[currentBlock].block->items[count];
	}

	/**
	\brief Pushes a new element onto the back of this array, intitializing it to match the data
	\param data The data to initialize the new element to
	\return The new element
	*/
	T& pushBack(T& data)
	{
		PxU32 numBlocks = blocks.size();
		if (blocks[currentBlock].count == BLOCK_SIZE)
		{
			if((currentBlock + 1) == numBlocks)
			{
				blocks.pushBack(BlockInfo(PX_NEW(Block), 0));
				numBlocks ++;
			}
			currentBlock++;
			blocks[currentBlock].count = 0;
		}
		const PxU32 count = blocks[currentBlock].count ++;
		blocks[currentBlock].block->items[count] = data;
		return blocks[currentBlock].block->items[count];
	}

	/**
	\brief Pops the last element from the list.
	*/
	void popBack()
	{
		PX_ASSERT(blocks[currentBlock].count > 0);
		if (blocks[currentBlock].count > 1)
			blocks[currentBlock].count --;
		else
		{
			PX_DELETE(blocks[currentBlock].block);
			blocks.popBack();
			currentBlock--;
		}
	}

	/**
	\brief Returns the current size of the array.
	\return The current size of the array.
	*/
	PxU32 size() const
	{
		return (currentBlock)*BLOCK_SIZE + blocks[currentBlock].count;
	}

	/**
	\brief Returns the element at a given index in the array
	\param[in] index The index of the element in the array
	\return The element at a given index in the array.
	*/
	T& operator[] (PxU32 index) const
	{
		PX_ASSERT(index/BLOCK_SIZE < blocks.size());
		PX_ASSERT(index%BLOCK_SIZE < blocks[index/BLOCK_SIZE].count);
		return blocks[index/BLOCK_SIZE].block->items[index%BLOCK_SIZE];
	}
};

/**
\brief A structure to represent a potential CCD interaction between a pair of shapes
*/
struct PxsCCDPair
{
	/**
	\brief Defines whether this is an estimated TOI or an accurate TOI.

	We store pairs in a priority queue based on the TOIs. We use cheap estimates to cull away work and lazily evaluate TOIs. This means that an element in the 
	priority queue may either be an estimate or a precise result.
	*/
	enum E_TOIType
	{
		eEstimate,
		ePrecise
	};
	PxsRigidBody*			mBa0;					// Body A. Can be NULL for statics
	PxsRigidBody*			mBa1;					// Body B. Can be NULL for statics
	PxsCCDShape*			mCCDShape0;				// Shape A
	PxsCCDShape*			mCCDShape1;				// Shape B
	PxVec3					mMinToiNormal;			// The contact normal. Only valid for precise results. On the surface of body/shape A
	PxReal					mMinToi;				// Min TOI. Valid for both precise and estimated results but estimates may be too early (i.e. conservative).
	PxReal					mPenetrationPostStep;	// Valid only for precise sweeps. Only used for initial intersections (i.e. at TOI = 0).
	PxVec3					mMinToiPoint;			// The contact point. Only valid for precise sweep results.
	PxReal					mPenetration;			// The penetration. Only valid for precise sweep results.
	PxsContactManager*		mCm;					// The contact manager.
	PxU32					mIslandId;				// The index of the island this pair is in
	PxGeometryType::Enum	mG0, mG1;				// The geometry types for shapes 0 and 1
	bool					mIsEarliestToiHit;		// Indicates this was the earliest hit for one of the bodies in the pair
	bool					mIsModifiable;			// Indicates whether this contact is modifiable
	PxU32					mFaceIndex;				// The face index. Only valid for precise sweeps involving meshes or heightfields.
	PxU16					mMaterialIndex0;		// The material index for shape 0
	PxU16					mMaterialIndex1;		// The material index for shape 1
	PxReal					mDynamicFriction;		// The dynamic friction coefficient
	PxReal					mStaticFriction;		// The static friction coefficient
	PxReal					mRestitution;			// The restitution coefficient
	PxU32					mEstimatePass;			// The current estimation pass. Used after a sweep hit was found to determine if the pair needs re-estimating.
	PxReal					mAppliedForce;			// The applied force for this pair. Only valid if the pair has been responded to.
	PxReal					mMaxImpulse;			// The maximum impulse to be applied 

	E_TOIType				mToiType;				// The TOI type (estimate, precise).
	bool					mHasFriction;			// Whether we want to simulate CCD friction for this pair

	/**
	\brief Perform a precise sweep for this pair
	\param[in] threadContext The per-thread context
	\param[in] dt The time-step
	\param[in] pass The current CCD pass
	\return The normalized TOI. <=1.0 indicates a hit. Otherwise PX_MAX_REAL.
	*/
	PxReal	sweepFindToi(PxcNpThreadContext& threadContext, PxReal dt, PxU32 pass, PxReal ccdThreshold);
	/**
	\brief Performs a sweep estimation for this pair
	\return The normalized TOI. <= 1.0 indicates a potential hit, otherwise PX_MAX_REAL.
	*/
	PxReal	sweepEstimateToi(PxReal ccdThreshold);
	/**
	\brief Advances this pair to the TOI
	\param[in] dt The time-step
	\param[in] clipTrajectoryToToi Indicates whether we clip the body's trajectory to the end pose. Only done in the final pass
	\return Whether the advance was successful. An advance will be unsuccessful if body bodies were already updated.
	*/
	bool	sweepAdvanceToToi(PxReal dt, bool clipTrajectoryToToi);
	/**
	\brief Updates the transforms of the shapes involved in this pair.
	*/
	void	updateShapes();

};

/**
\brief Block array of CCD bodies
*/
typedef PxsCCDBlockArray<PxsCCDBody, 128> PxsCCDBodyArray;
/**
\brief Block array of CCD pairs
*/
typedef PxsCCDBlockArray<PxsCCDPair, 128> PxsCCDPairArray;
/**
\brief Block array of CCD overlaps
*/
typedef PxsCCDBlockArray<PxsCCDOverlap, 128> PxsCCDOverlapArray;
/**
\brief Block array of CCD shapes
*/
typedef PxsCCDBlockArray<PxsCCDShape, 128> PxsCCDShapeArray;

/**
\brief Pair structure to be able to look-up a rigid body-shape pair in a map
*/
typedef Ps::Pair<const PxsRigidCore*, const PxsShapeCore*> PxsRigidShapePair;


/**
\brief CCD context object.
*/
class PxsCCDContext
{
public:

	/**
	\brief Creates this PxsCCDContext
	*/
	static PxsCCDContext* create(PxsContext* context, Dy::ThresholdStream& dynamicsContext, PxvNphaseImplementationContext& nPhaseContext,
		PxReal ccdThreshold);

	/**
	\brief Destroys this PxsCCDContext
	*/
	void						destroy();

	/**
	\brief Returns the CCD contact modification callback
	\return The CCD contact modification callback
	*/
	PX_FORCE_INLINE		PxCCDContactModifyCallback*	getCCDContactModifyCallback()					const		{ return mCCDContactModifyCallback;	}
	/**
	\brief Sets the CCD contact modification callback
	\param[in] c The CCD contact modification callback
	*/
	PX_FORCE_INLINE		void						setCCDContactModifyCallback(PxCCDContactModifyCallback* c)	{ mCCDContactModifyCallback = c;	}
	/**
	\brief Returns the maximum number of CCD passes
	\return The maximum number of CCD passes
	*/
	PX_FORCE_INLINE		PxU32					getCCDMaxPasses()				const						{ return mCCDMaxPasses;	}
	/**
	\brief Sets the maximum number of CCD passes
	\param[in] ccdMaxPasses The maximum number of CCD passes
	*/
	PX_FORCE_INLINE		void					setCCDMaxPasses(PxU32 ccdMaxPasses)							{ mCCDMaxPasses = ccdMaxPasses;		}
	/**
	\brief Returns the current CCD pass
	\return The current CCD pass
	*/
	PX_FORCE_INLINE		PxU32					getCurrentCCDPass()				const						{ return miCCDPass;					}
	/**
	\brief Returns The number of swept hits reported
	\return The number of swept hits reported
	*/
	PX_FORCE_INLINE		PxI32					getNumSweepHits()				const						{ return mSweepTotalHits;			}
	/**
	\brief Returns The number of updated bodies
	\return The number of updated bodies in this CCD pass
	*/
	PX_FORCE_INLINE		PxU32					getNumUpdatedBodies()			const						{ return mUpdatedCCDBodies.size(); }
	/**
	\brief Returns The update bodies array
	\return The updated bodies array from this CCD pass
	*/
	PX_FORCE_INLINE		PxsRigidBody*const*			getUpdatedBodies()				const						{ return mUpdatedCCDBodies.begin(); }

	/**
	\brief Returns Clears the updated bodies array
	*/
	PX_FORCE_INLINE		void						clearUpdatedBodies()										{ mUpdatedCCDBodies.forceSize_Unsafe(0); }

	PX_FORCE_INLINE		PxReal						getCCDThreshold() const										{ return mCCDThreshold;}

	/**
	\brief Runs the CCD contact modification.
	\param[in] contacts The list of modifiable contacts
	\param[in] contactCount The number of contacts
	\param[in] shapeCore0 The first shape core
	\param[in] shapeCore1 The second shape core
	\param[in] rigidCore0 The first rigid core
	\param[in] rigidCore1 The second rigid core
	\param[in] rigid0 The first rigid body
	\param[in] rigid1 The second rigid body
	*/
						void					runCCDModifiableContact(PxModifiableContact* PX_RESTRICT contacts, PxU32 contactCount, const PxsShapeCore* PX_RESTRICT shapeCore0, 
													const PxsShapeCore* PX_RESTRICT shapeCore1, const PxsRigidCore* PX_RESTRICT rigidCore0, const PxsRigidCore* PX_RESTRICT rigidCore1,
													const PxsRigidBody* PX_RESTRICT rigid0, const PxsRigidBody* PX_RESTRICT rigid1);
	
	/**
	\brief Performs a single CCD update
	This occurs after broad phase and is responsible for creating islands, finding the TOI of collisions, filtering contacts, issuing modification callbacks and responding to 
	collisions. At the end of this phase all bodies will have stepper to their first TOI if they were involved in a CCD collision this frame.
	\param[in] dt The timestep to simulate
	\param[in] continuation The continuation task
	\param[in] islandSim The island manager
	\param[in] disableResweep If this is true, we perform a reduced-fidelity CCD approach
	*/
						void					updateCCD(PxReal dt, PxBaseTask* continuation, IG::IslandSim& islandSim, bool disableResweep, PxI32 numFastMovingShapes);

	/**
	\brief Signals the beginning of a CCD multi-pass update
	*/
						void					updateCCDBegin();

	/**
	\brief Resets the CCD contact state in any contact managers that previously had a reported CCD touch. This must be called if CCD update is bypassed for a frame
	*/
						void					resetContactManagers();
	

	

protected:

	/**
	\brief Constructor for PxsCCDContext
	\param[in] context The PxsContext that is associated with this PxsCCDContext.
	*/
	PxsCCDContext(PxsContext* context, Dy::ThresholdStream& thresholdStream, PxvNphaseImplementationContext& nPhaseContext,
		PxReal ccdThreshold);
	/**
	\brief Destructor for PxsCCDContext
	*/
		~PxsCCDContext();

private:

	
	/**
	\brief Verifies the consistency of the CCD context at the beginning
	*/
						void					verifyCCDBegin();

	/**
	\brief Cleans up after the CCD update has completed
	*/
						void					updateCCDEnd();

	/**
	\brief Spawns the update island tasks after the initial sweep estimates have been performed
	\param[in] continuation The continuation task
	*/
						void					postCCDSweep(PxBaseTask* continuation);
	/**
	\brief Creates contact buffers for CCD contacts. These will be sent to the user in the contact notification.
	\param[in] continuation The continuation task
	*/
						void					postCCDAdvance(PxBaseTask* continuation);
	/**
	\brief The final phase of the CCD task chain. Cleans up after the parallel update/postCCDAdvance stages.
	\param[in] continuation The continuation task
	*/
						void					postCCDDepenetrate(PxBaseTask* continuation);

		typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDSweep> PostCCDSweepTask;
		typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDAdvance> PostCCDAdvanceTask;
		typedef Cm::DelegateTask<PxsCCDContext, &PxsCCDContext::postCCDDepenetrate> PostCCDDepenetrateTask;

		PostCCDSweepTask mPostCCDSweepTask;
		PostCCDAdvanceTask mPostCCDAdvanceTask;
		PostCCDDepenetrateTask mPostCCDDepenetrateTask;

		PxCCDContactModifyCallback*					mCCDContactModifyCallback;
		
		// CCD global data
		bool					mDisableCCDResweep;
		PxU32					miCCDPass;
		PxI32					mSweepTotalHits;

		// a fraction of objects will be CCD active so PxsCCDBody is dynamic, not a member of PxsRigidBody
		PxsCCDBodyArray mCCDBodies;
		PxsCCDOverlapArray mCCDOverlaps;
		PxsCCDShapeArray mCCDShapes;
		Ps::Array<PxsCCDBody*> mIslandBodies;
		Ps::Array<PxU16> mIslandSizes;
		Ps::Array<PxsRigidBody*> mUpdatedCCDBodies;
		Ps::HashMap<PxsRigidShapePair, PxsCCDShape*> mMap;

		// temporary array updated during CCD update
		//Array<PxsCCDPair> mCCDPairs;
		PxsCCDPairArray mCCDPairs;
		Ps::Array<PxsCCDPair*> mCCDPtrPairs;
		// number of pairs per island
		Ps::Array<PxU32> mCCDIslandHistogram; 
		// thread context valid during CCD update
		PxcNpThreadContext* mCCDThreadContext;
		// number of pairs to process per thread
		PxU32 mCCDPairsPerBatch;
		PxU32 mCCDMaxPasses;

		PxsContext* mContext;
		Dy::ThresholdStream& mThresholdStream;

		PxvNphaseImplementationContext& mNphaseContext;

		Ps::Mutex mMutex;

		PxReal mCCDThreshold;

private:

	PX_NOCOPY(PxsCCDContext)
};


}



#endif

