// 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-2025 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 "GuMidphaseInterface.h"
#include "GuTetrahedronMesh.h"
#include "GuBox.h"

using namespace physx;
using namespace Gu;

void TetrahedronMesh::onRefCountZero()
{
	if (mMeshFactory)
	{
		::onRefCountZero(this, mMeshFactory, false, "PxTetrahedronMesh::release: double deletion detected!");
	}
}

void DeformableVolumeMesh::onRefCountZero()
{
	if (mMeshFactory)
	{
		::onRefCountZero(this, mMeshFactory, false, "PxDeformableVolumeMesh::release: double deletion detected!");
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DeformableVolumeAuxData::DeformableVolumeAuxData(DeformableVolumeSimulationData& d, DeformableVolumeCollisionData& c, CollisionMeshMappingData& e)
	: PxDeformableVolumeAuxData(PxType(PxConcreteType::eDEFORMABLE_VOLUME_STATE), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
	, mGridModelInvMass(d.mGridModelInvMass)
	, mGridModelTetraRestPoses(d.mGridModelTetraRestPoses)
	, mGridModelOrderedTetrahedrons(d.mGridModelOrderedTetrahedrons)
	, mGMNbPartitions(d.mGridModelNbPartitions)
	, mGMMaxMaxTetsPerPartitions(d.mGridModelMaxTetsPerPartitions)
	, mGMRemapOutputSize(d.mGMRemapOutputSize)
	, mGMRemapOutputCP(d.mGMRemapOutputCP)
	, mGMAccumulatedPartitionsCP(d.mGMAccumulatedPartitionsCP)
	, mGMAccumulatedCopiesCP(d.mGMAccumulatedCopiesCP)
	, mCollisionAccumulatedTetrahedronsRef(e.mCollisionAccumulatedTetrahedronsRef)
	, mCollisionTetrahedronsReferences(e.mCollisionTetrahedronsReferences)
	, mCollisionNbTetrahedronsReferences(e.mCollisionNbTetrahedronsReferences)
	, mCollisionSurfaceVertsHint(e.mCollisionSurfaceVertsHint)
	, mCollisionSurfaceVertToTetRemap(e.mCollisionSurfaceVertToTetRemap)
	, mVertsBarycentricInGridModel(e.mVertsBarycentricInGridModel)
	, mVertsRemapInGridModel(e.mVertsRemapInGridModel)
	, mTetsRemapColToSim(e.mTetsRemapColToSim)
	, mTetsRemapSize(e.mTetsRemapSize)
	, mTetsAccumulatedRemapColToSim(e.mTetsAccumulatedRemapColToSim)

	, mGMPullIndices(d.mGMPullIndices)
	, mTetraRestPoses(c.mTetraRestPoses)
	, mNumTetsPerElement(d.mNumTetsPerElement)

{
	// this constructor takes ownership of memory from the data object
	d.mGridModelInvMass = 0;
	d.mGridModelTetraRestPoses = 0;
	d.mGridModelOrderedTetrahedrons = 0;
	d.mGMRemapOutputCP = 0;
	d.mGMAccumulatedPartitionsCP = 0;
	d.mGMAccumulatedCopiesCP = 0;
	e.mCollisionAccumulatedTetrahedronsRef = 0;
	e.mCollisionTetrahedronsReferences = 0;
	e.mCollisionSurfaceVertsHint = 0;
	e.mCollisionSurfaceVertToTetRemap = 0;
	d.mGMPullIndices = 0;

	e.mVertsBarycentricInGridModel = 0;
	e.mVertsRemapInGridModel = 0;
	e.mTetsRemapColToSim = 0;
	e.mTetsAccumulatedRemapColToSim = 0;
	
	c.mTetraRestPoses = 0;
}

DeformableVolumeAuxData::~DeformableVolumeAuxData()
{
	PX_FREE(mGridModelInvMass);

	PX_FREE(mGridModelTetraRestPoses);
	PX_FREE(mGridModelOrderedTetrahedrons);
	PX_FREE(mGMRemapOutputCP);
	PX_FREE(mGMAccumulatedPartitionsCP);
	PX_FREE(mGMAccumulatedCopiesCP);
	PX_FREE(mCollisionAccumulatedTetrahedronsRef);
	PX_FREE(mCollisionTetrahedronsReferences);
	PX_FREE(mCollisionSurfaceVertsHint);
	PX_FREE(mCollisionSurfaceVertToTetRemap);

	PX_FREE(mVertsBarycentricInGridModel);
	PX_FREE(mVertsRemapInGridModel);
	PX_FREE(mTetsRemapColToSim);
	PX_FREE(mTetsAccumulatedRemapColToSim);

	PX_FREE(mGMPullIndices); 
	PX_FREE(mTetraRestPoses);
}

TetrahedronMesh::TetrahedronMesh(PxU32 nbVertices, PxVec3* vertices, PxU32 nbTetrahedrons, void* tetrahedrons, PxU8 flags, PxBounds3 aabb, PxReal geomEpsilon)
	: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
	, mNbVertices(nbVertices)
	, mVertices(vertices)
	, mNbTetrahedrons(nbTetrahedrons)
	, mTetrahedrons(tetrahedrons)
	, mFlags(flags)
	, mMaterialIndices(NULL)
	, mAABB(aabb)
	, mGeomEpsilon(geomEpsilon)
{
}

TetrahedronMesh::TetrahedronMesh(TetrahedronMeshData& mesh)
	: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
	, mNbVertices(mesh.mNbVertices)
	, mVertices(mesh.mVertices)
	, mNbTetrahedrons(mesh.mNbTetrahedrons)
	, mTetrahedrons(mesh.mTetrahedrons)
	, mFlags(mesh.mFlags)
	, mMaterialIndices(mesh.mMaterialIndices)
	, mAABB(mesh.mAABB)
	, mGeomEpsilon(mesh.mGeomEpsilon)
{
	// this constructor takes ownership of memory from the data object	
	mesh.mVertices = 0;
	mesh.mTetrahedrons = 0;	
	mesh.mMaterialIndices = 0;
}

TetrahedronMesh::TetrahedronMesh(MeshFactory* meshFactory, TetrahedronMeshData& mesh) 
	: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)	
	, mNbVertices(mesh.mNbVertices)
	, mVertices(mesh.mVertices)
	, mNbTetrahedrons(mesh.mNbTetrahedrons)
	, mTetrahedrons(mesh.mTetrahedrons)
	, mFlags(mesh.mFlags)
	, mMaterialIndices(mesh.mMaterialIndices)
	, mAABB(mesh.mAABB)
	, mGeomEpsilon(mesh.mGeomEpsilon)	
	, mMeshFactory(meshFactory)
{
	// this constructor takes ownership of memory from the data object	
	mesh.mVertices = 0;
	mesh.mTetrahedrons = 0;
	mesh.mMaterialIndices = 0;
}

TetrahedronMesh::~TetrahedronMesh()
{
	PX_FREE(mTetrahedrons);
	PX_FREE(mVertices);
	PX_FREE(mMaterialIndices);
}

BVTetrahedronMesh::BVTetrahedronMesh(TetrahedronMeshData& mesh, DeformableVolumeCollisionData& d, MeshFactory* factory) : TetrahedronMesh(mesh)
, mFaceRemap(d.mFaceRemap)
, mGRB_tetraIndices(d.mGRB_primIndices)
, mGRB_tetraSurfaceHint(d.mGRB_tetraSurfaceHint)
, mGRB_faceRemap(d.mGRB_faceRemap)
, mGRB_faceRemapInverse(d.mGRB_faceRemapInverse)
, mGRB_BV32Tree(d.mGRB_BV32Tree)
{
	mMeshFactory = factory;

	bool has16BitIndices = (mesh.mFlags & PxMeshFlag::e16_BIT_INDICES) ? true : false;

	mMeshInterface4.mVerts = mVertices; // mesh.mVertices;
	mMeshInterface4.mNbVerts = mesh.mNbVertices;
	mMeshInterface4.mNbTetrahedrons = mesh.mNbTetrahedrons;
	mMeshInterface4.mTetrahedrons16 = has16BitIndices ? reinterpret_cast<IndTetrahedron16*>(mTetrahedrons/*mesh.mTetrahedrons*/) : NULL;
	mMeshInterface4.mTetrahedrons32 = has16BitIndices ? NULL : reinterpret_cast<IndTetrahedron32*>(mTetrahedrons/*mesh.mTetrahedrons*/);

	mBV4Tree = d.mBV4Tree;
	mBV4Tree.mMeshInterface = &mMeshInterface4;

	if (mGRB_BV32Tree)
	{
		mMeshInterface32.mVerts = mVertices; //  mesh.mVertices;
		mMeshInterface32.mNbVerts = mesh.mNbVertices;
		mMeshInterface32.mNbTetrahedrons = mesh.mNbTetrahedrons;
		mMeshInterface32.mTetrahedrons16 = has16BitIndices ? reinterpret_cast<IndTetrahedron16*>(d.mGRB_primIndices) : NULL;
		mMeshInterface32.mTetrahedrons32 = has16BitIndices ? NULL : reinterpret_cast<IndTetrahedron32*>(d.mGRB_primIndices);

		mGRB_BV32Tree->mMeshInterface = &mMeshInterface32;
	}

	// this constructor takes ownership of memory from the data object
	d.mGRB_tetraSurfaceHint = NULL;
	d.mFaceRemap = NULL;

	d.mGRB_primIndices = NULL;
	d.mGRB_faceRemap = NULL;
	d.mGRB_faceRemapInverse = NULL;
	d.mGRB_BV32Tree = NULL;

	mesh.mVertices = NULL;
	mesh.mTetrahedrons = NULL;
}

DeformableVolumeMesh::DeformableVolumeMesh(MeshFactory* factory, DeformableVolumeMeshData& d)
	: PxDeformableVolumeMesh(PxType(PxConcreteType::eDEFORMABLE_VOLUME_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
	, mMeshFactory(factory)
{
	mDeformableVolumeAuxData = PX_NEW(DeformableVolumeAuxData)(d.mSimulationData, d.mCollisionData, d.mMappingData);
	mCollisionMesh = PX_NEW(BVTetrahedronMesh)(d.mCollisionMesh, d.mCollisionData, factory);
	mSimulationMesh = PX_NEW(TetrahedronMesh)(factory, d.mSimulationMesh);
}

DeformableVolumeMesh::~DeformableVolumeMesh()
{	
	if (getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
	{
		PX_DELETE(mDeformableVolumeAuxData);
		PX_DELETE(mCollisionMesh);
		PX_DELETE(mSimulationMesh);
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// PT: used to be automatic but making it manual saves bytes in the internal mesh

void DeformableVolumeMesh::exportExtraData(PxSerializationContext& stream)
{
	//PX_DEFINE_DYNAMIC_ARRAY(TriangleMesh, mVertices, PxField::eVEC3, mNbVertices, Ps::PxFieldFlag::eSERIALIZE),
	if (getCollisionMeshFast()->mVertices)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(getCollisionMeshFast()->mVertices, getCollisionMeshFast()->mNbVertices * sizeof(PxVec3));
	}

	/*if (mSurfaceTriangles)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(mSurfaceTriangles, mNbTriangles * 3 * sizeof(PxU32));
	}*/

	if (getCollisionMeshFast()->mTetrahedrons)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(getCollisionMeshFast()->mTetrahedrons, getCollisionMeshFast()->mNbTetrahedrons * 4 * sizeof(PxU32));
	}

	/*if (mTetSurfaceHint)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(mTetSurfaceHint, mNbTetrahedrons * sizeof(PxU8));
	}*/

	if (getCollisionMeshFast()->mMaterialIndices)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(getCollisionMeshFast()->mMaterialIndices, getCollisionMeshFast()->mNbTetrahedrons * sizeof(PxU16));
	}

	if (getCollisionMeshFast()->mFaceRemap)
	{
		stream.alignData(PX_SERIAL_ALIGN);
		stream.writeData(getCollisionMeshFast()->mFaceRemap, getCollisionMeshFast()->mNbTetrahedrons * sizeof(PxU32));
	}
}

void DeformableVolumeMesh::importExtraData(PxDeserializationContext& context)
{
	// PT: vertices are followed by indices, so it will be safe to V4Load vertices from a deserialized binary file
	if (getCollisionMeshFast()->mVertices)
		getCollisionMeshFast()->mVertices = context.readExtraData<PxVec3, PX_SERIAL_ALIGN>(getCollisionMeshFast()->mNbVertices);

	if (getCollisionMeshFast()->mTetrahedrons)
		getCollisionMeshFast()->mTetrahedrons = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(4 * getCollisionMeshFast()->mNbTetrahedrons);

	if (getCollisionMeshFast()->mFaceRemap)
		getCollisionMeshFast()->mFaceRemap = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(getCollisionMeshFast()->mNbTetrahedrons);
		
	getCollisionMeshFast()->mGRB_tetraIndices = NULL;
	getCollisionMeshFast()->mGRB_tetraSurfaceHint = NULL;
	getCollisionMeshFast()->mGRB_faceRemap = NULL;
	getCollisionMeshFast()->mGRB_faceRemapInverse = NULL;
	getCollisionMeshFast()->mGRB_BV32Tree = NULL;
}

void DeformableVolumeMesh::release()
{
	Cm::RefCountable_decRefCount(*this);
}

//PxVec3* TetrahedronMesh::getVerticesForModification()
//{
//	PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxDeformableVolumeMesh::getVerticesForModification() is not currently supported.");
//
//	return NULL;
//}

//PxBounds3 BVTetrahedronMesh::refitBVH()
//{
//	PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxDeformableVolumeMesh::refitBVH() is not currently supported.");
//
//	return PxBounds3(mAABB.getMin(), mAABB.getMax());
//}
