//
// 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.  

#ifndef PX_PHYSICS_SCP_SHAPESIM
#define PX_PHYSICS_SCP_SHAPESIM

#include "ScElementSim.h"
#include "ScShapeCore.h"
#include "ScRigidSim.h"
#include "PxsShapeSim.h"

namespace physx
{
	class PxsTransformCache;
namespace Gu
{
	class TriangleMesh;
	class HeightField;
}

/** Simulation object corresponding to a shape core object. This object is created when
    a ShapeCore object is added to the simulation, and destroyed when it is removed
*/

struct PxsRigidCore;

namespace Sc
{
	class RigidSim;
	class ShapeCore;
	class Scene;
	class BodySim;
	class StaticSim;

	class ShapeSim : public ElementSim
	{
		ShapeSim &operator=(const ShapeSim &);
	public:

		// passing in a pointer for the shape to output its bounds allows us not to have to compute them twice.
		// A neater way to do this would be to ask the AABB Manager for the bounds after the shape has been 
		// constructed, but there is currently no spec for what the AABBMgr is allowed to do with the bounds, 
		// hence better not to assume anything.

												ShapeSim(RigidSim&, const ShapeCore& core);
												~ShapeSim();

						void					reinsertBroadPhase();

		PX_FORCE_INLINE	const ShapeCore&		getCore()				const	{ return mCore; }

						// TODO: compile time coupling

		PX_INLINE		PxGeometryType::Enum	getGeometryType()		const	{ return mCore.getGeometryType();	}

		// This is just for getting a reference for the user, so we cast away const-ness

		PX_INLINE		PxShape*				getPxShape()			const	{ return const_cast<PxShape*>(mCore.getPxShape());	}
		
		PX_FORCE_INLINE	PxReal					getRestOffset()			const	{ return mCore.getRestOffset();		}
		PX_FORCE_INLINE	PxReal					getTorsionalPatchRadius() const { return mCore.getTorsionalPatchRadius(); }
		PX_FORCE_INLINE	PxReal					getMinTorsionalPatchRadius() const { return mCore.getMinTorsionalPatchRadius(); }
		PX_FORCE_INLINE	PxU32					getFlags()				const	{ return mCore.getFlags();			}
		PX_FORCE_INLINE	PxReal					getContactOffset()		const	{ return mCore.getContactOffset();	}

		PX_FORCE_INLINE	RigidSim&				getRbSim()				const	{ return static_cast<RigidSim&>(getActor());	}
						BodySim*				getBodySim()			const;

						PxsRigidCore&			getPxsRigidCore()		const;

						void					onFilterDataChange();
						void					onRestOffsetChange();
						void					onFlagChange(PxShapeFlags oldFlags);
						void					onResetFiltering();
						void					onVolumeOrTransformChange(bool forceBoundsUpdate);
						void					onMaterialChange();  // remove when material properties are gone from PxcNpWorkUnit
						void					onContactOffsetChange();
						void					markBoundsForUpdate(bool forceBoundsUpdate);

						void					getAbsPoseAligned(PxTransform* PX_RESTRICT globalPose)	const;

		PX_FORCE_INLINE	PxU32					getID()								const	{ return mId;		}
		PX_FORCE_INLINE	PxU32					getTransformCacheID()				const	{ return getElementID();	}

						void					removeFromBroadPhase(bool wakeOnLostTouch);

						void					createSqBounds();
						void					destroySqBounds();

		PX_FORCE_INLINE PxU32					getSqBoundsId()						const	{ return mSqBoundsId; }
		PX_FORCE_INLINE void					setSqBoundsId(PxU32 id)						{ mSqBoundsId = id; }

						void					updateCached(PxU32 transformCacheFlags, Cm::BitMapPinned* shapeChangedMap);
						void					updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray);
						void					updateContactDistance(PxReal* contactDistance, const PxReal inflation, const PxVec3 angVel, const PxReal dt, Bp::BoundsArray& boundsArray);
						Ps::IntBool				updateSweptBounds();
						void					updateBPGroup();

		PX_FORCE_INLINE PxsShapeSim&			getLLShapeSim() 							{ return mLLShape; }
	private:
						PxsShapeSim				mLLShape;
						const ShapeCore&		mCore;
						PxU32					mId;
						PxU32					mSqBoundsId;

		PX_FORCE_INLINE	void					internalAddToBroadPhase();
		PX_FORCE_INLINE	void					internalRemoveFromBroadPhase(bool wakeOnLostTouch=true);
						void					initSubsystemsDependingOnElementID();
						Bp::FilterGroup::Enum	getBPGroup()	const;
	};

#if !PX_P64_FAMILY
//	PX_COMPILE_TIME_ASSERT(32==sizeof(Sc::ShapeSim)); // after removing bounds from shapes
//	PX_COMPILE_TIME_ASSERT((sizeof(Sc::ShapeSim) % 16) == 0); // aligned mem bounds are better for prefetching
#endif

} // namespace Sc

}

#endif
