// 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 "foundation/PxPreprocessor.h"
#if PX_SUPPORT_PVD
#include "common/PxProfileZone.h"
#include "common/PxRenderBuffer.h"
#include "PxParticleSystem.h"
#include "PxPBDParticleSystem.h"
#include "PxPhysics.h"
#include "PxConstraintDesc.h"
#include "NpPvdSceneClient.h"
#include "ScBodySim.h"
#include "ScConstraintSim.h"
#include "ScConstraintCore.h"
#include "PxsMaterialManager.h"
#include "PvdTypeNames.h"
#include "PxPvdUserRenderer.h"
#include "PxvNphaseImplementationContext.h"
#include "NpConstraint.h"
#include "NpRigidStatic.h"
#include "NpRigidDynamic.h"
#include "NpArticulationLink.h"
#include "NpDeformableSurface.h"
#include "NpDeformableVolume.h"
#include "NpAggregate.h"
#include "NpScene.h"
#include "NpArticulationJointReducedCoordinate.h"
#include "NpArticulationReducedCoordinate.h"

using namespace physx;
using namespace physx::Vd;
using namespace physx::pvdsdk;

namespace
{
	PX_FORCE_INLINE	PxU64	getContextId(NpScene& scene) { return scene.getScScene().getContextId(); }

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

	// Sc-to-Np
	PX_FORCE_INLINE static NpConstraint* getNpConstraint(Sc::ConstraintCore* scConstraint)
	{
		return reinterpret_cast<NpConstraint*>(reinterpret_cast<char*>(scConstraint) - NpConstraint::getCoreOffset());
	}

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

	PX_FORCE_INLINE static const PxActor* getPxActor(const NpActor* scActor)
	{
		return scActor->getPxActor();
	}

	struct CreateOp
	{
		CreateOp& operator=(const CreateOp&);
		physx::pvdsdk::PvdDataStream& mStream;
		PvdMetaDataBinding& mBinding;
		PsPvd* mPvd;
		PxScene& mScene;
		CreateOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind, PsPvd* pvd, PxScene& scene)
			: mStream(str), mBinding(bind), mPvd(pvd), mScene(scene)
		{
		}
		template <typename TDataType>
		void operator()(const TDataType& dtype)
		{
			mBinding.createInstance(mStream, dtype, mScene, PxGetPhysics(), mPvd);
		}
		void operator()(const PxArticulationLink&)
		{
		}
	};

	struct UpdateOp
	{
		UpdateOp& operator=(const UpdateOp&);
		physx::pvdsdk::PvdDataStream& mStream;
		PvdMetaDataBinding& mBinding;
		UpdateOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind) : mStream(str), mBinding(bind)
		{
		}
		template <typename TDataType>
		void operator()(const TDataType& dtype)
		{
			mBinding.sendAllProperties(mStream, dtype);
		}
	};

	struct DestroyOp
	{
		DestroyOp& operator=(const DestroyOp&);
		physx::pvdsdk::PvdDataStream& mStream;
		PvdMetaDataBinding& mBinding;
		PxScene& mScene;
		DestroyOp(physx::pvdsdk::PvdDataStream& str, PvdMetaDataBinding& bind, PxScene& scene)
			: mStream(str), mBinding(bind), mScene(scene)
		{
		}
		template <typename TDataType>
		void operator()(const TDataType& dtype)
		{
			mBinding.destroyInstance(mStream, dtype, mScene);
		}
		void operator()(const PxArticulationLink& dtype)
		{
			mBinding.destroyInstance(mStream, dtype);
		}
	};

	template <typename TOperator>
	inline void BodyTypeOperation(const NpActor* scBody, TOperator op)
	{
//		const bool isArticulationLink = scBody->getActorType_() == PxActorType::eARTICULATION_LINK;
		const bool isArticulationLink = scBody->getNpType() == NpType::eBODY_FROM_ARTICULATION_LINK;
		if(isArticulationLink)
		{
			const NpArticulationLink* link = static_cast<const NpArticulationLink*>(scBody);
			op(*static_cast<const PxArticulationLink*>(link));
		}
		else
		{
			const NpRigidDynamic* npRigidDynamic = static_cast<const NpRigidDynamic*>(scBody);
			op(*static_cast<const PxRigidDynamic*>(npRigidDynamic));
		}
	}

	template <typename TOperator>
	inline void ActorTypeOperation(const PxActor* actor, TOperator op)
	{
		switch(actor->getType())
		{
		case PxActorType::eRIGID_STATIC:
			op(*static_cast<const PxRigidStatic*>(actor));
			break;
		case PxActorType::eRIGID_DYNAMIC:
			op(*static_cast<const PxRigidDynamic*>(actor));
			break;
		case PxActorType::eARTICULATION_LINK:
			op(*static_cast<const PxArticulationLink*>(actor));
			break;
#if PX_SUPPORT_GPU_PHYSX
		case PxActorType::eDEFORMABLE_SURFACE:
			op(*static_cast<const PxDeformableSurface*>(actor));
			break;
		case PxActorType::eDEFORMABLE_VOLUME:
			op(*static_cast<const PxDeformableVolume*>(actor));
			break;
#else
		case PxActorType::eDEFORMABLE_SURFACE:
		case PxActorType::eDEFORMABLE_VOLUME:
			PX_ASSERT(false);
			break;
#endif
		case PxActorType::ePBD_PARTICLESYSTEM:
			op(*static_cast<const PxPBDParticleSystem*>(actor));
			break;
		case PxActorType::eACTOR_COUNT:
		case PxActorType::eACTOR_FORCE_DWORD:
			PX_ASSERT(false);
			break;
		};
	}

	namespace
	{
		struct PvdConstraintVisualizer : public PxConstraintVisualizer
		{
			PX_NOCOPY(PvdConstraintVisualizer)
		public:
			physx::pvdsdk::PvdUserRenderer& mRenderer;

			PvdConstraintVisualizer(const void* id, physx::pvdsdk::PvdUserRenderer& r) : mRenderer(r)
			{
				mRenderer.setInstanceId(id);
			}

			virtual void visualizeJointFrames(const PxTransform& parent, const PxTransform& child)	PX_OVERRIDE
			{
				mRenderer.visualizeJointFrames(parent, child);
			}

			virtual void visualizeLinearLimit(const PxTransform& t0, const PxTransform& t1, PxReal value)	PX_OVERRIDE
			{
				mRenderer.visualizeLinearLimit(t0, t1, PxF32(value));
			}

			virtual void visualizeAngularLimit(const PxTransform& t0, PxReal lower, PxReal upper)	PX_OVERRIDE
			{
				mRenderer.visualizeAngularLimit(t0, PxF32(lower), PxF32(upper));
			}

			virtual void visualizeLimitCone(const PxTransform& t, PxReal tanQSwingY, PxReal tanQSwingZ)	PX_OVERRIDE
			{
				mRenderer.visualizeLimitCone(t, PxF32(tanQSwingY), PxF32(tanQSwingZ));
			}

			virtual void visualizeDoubleCone(const PxTransform& t, PxReal angle)	PX_OVERRIDE
			{
				mRenderer.visualizeDoubleCone(t, PxF32(angle));
			}

			virtual void visualizeLine( const PxVec3& p0, const PxVec3& p1, PxU32 color)	PX_OVERRIDE
			{
				const PxDebugLine line(p0, p1, color);
				mRenderer.drawLines(&line, 1);
			}
		};
	}

	class SceneRendererClient : public RendererEventClient, public physx::PxUserAllocated
	{
		PX_NOCOPY(SceneRendererClient)
	public:
		SceneRendererClient(PvdUserRenderer* renderer, PxPvd* pvd):mRenderer(renderer)
		{
			mStream = PvdDataStream::create(pvd); 
			mStream->createInstance(renderer);
		}

		~SceneRendererClient()
		{
			mStream->destroyInstance(mRenderer);
			mStream->release();
		}

		virtual void handleBufferFlush(const uint8_t* inData, uint32_t inLength)
		{
			mStream->setPropertyValue(mRenderer, "events", inData, inLength);
		}

	private:

		PvdUserRenderer* mRenderer;
		PvdDataStream* mStream;
	};

} // namespace

PvdSceneClient::PvdSceneClient(NpScene& scene) :
	mPvd			(NULL),
	mScene			(scene),
	mPvdDataStream	(NULL),
	mUserRender		(NULL),
	mRenderClient	(NULL),
	mIsConnected	(false)
{
}

PvdSceneClient::~PvdSceneClient()
{
	if(mPvd)
		mPvd->removeClient(this);
}

void PvdSceneClient::updateCamera(const char* name, const PxVec3& origin, const PxVec3& up, const PxVec3& target)
{
	if(mIsConnected)
		mPvdDataStream->updateCamera(name, origin, up, target);
}

void PvdSceneClient::drawPoints(const PxDebugPoint* points, PxU32 count)
{
	if(mUserRender)
		mUserRender->drawPoints(points, count);
}

void PvdSceneClient::drawLines(const PxDebugLine* lines, PxU32 count)
{
	if(mUserRender)
		mUserRender->drawLines(lines, count);
}

void PvdSceneClient::drawTriangles(const PxDebugTriangle* triangles, PxU32 count)
{
	if(mUserRender)
		mUserRender->drawTriangles(triangles, count);
}

void PvdSceneClient::drawText(const PxDebugText& text)
{
	if(mUserRender)
		mUserRender->drawText(text);
}

void PvdSceneClient::setScenePvdFlag(PxPvdSceneFlag::Enum flag, bool value)
{
	if(value)
		mFlags |= flag;
	else
		mFlags &= ~flag;
}

void PvdSceneClient::onPvdConnected()
{
	if(mIsConnected || !mPvd)
		return;

	mIsConnected = true;

	mPvdDataStream = PvdDataStream::create(mPvd);

	mUserRender = PvdUserRenderer::create();
	mRenderClient = PX_NEW(SceneRendererClient)(mUserRender, mPvd);	
	mUserRender->setClient(mRenderClient);

	sendEntireScene();
}

void PvdSceneClient::onPvdDisconnected()
{
	if(!mIsConnected)
		return;
	mIsConnected = false;

	PX_DELETE(mRenderClient);
	mUserRender->release();
	mUserRender = NULL;
	mPvdDataStream->release();
	mPvdDataStream = NULL;
}

void PvdSceneClient::updatePvdProperties()
{
	mMetaDataBinding.sendAllProperties(*mPvdDataStream, mScene);
}

void PvdSceneClient::releasePvdInstance()
{
	if(mPvdDataStream)
	{		
		PxScene* theScene = &mScene;
		// remove from parent	
		mPvdDataStream->removeObjectRef(&PxGetPhysics(), "Scenes", theScene);
		mPvdDataStream->destroyInstance(theScene);
	}
}

// PT: this is only called once, from "onPvdConnected"
void PvdSceneClient::sendEntireScene()
{
	NpScene* npScene = &mScene;

	if(npScene->getFlagsFast() & PxSceneFlag::eREQUIRE_RW_LOCK) // getFlagsFast() will trigger a warning of lock check
		npScene->lockRead(PX_FL);

	PxPhysics& physics = PxGetPhysics();
	{
		PxScene* theScene = &mScene;
		mPvdDataStream->createInstance(theScene);
		updatePvdProperties();

		// Create parent/child relationship.
		mPvdDataStream->setPropertyValue(theScene, "Physics", reinterpret_cast<const void*>(&physics));
		mPvdDataStream->pushBackObjectRef(&physics, "Scenes", theScene);
	}

	// materials:
	{
		PxsMaterialManager& manager = mScene.getScScene().getMaterialManager();
		PxsMaterialManagerIterator<PxsMaterialCore> iter(manager);
		PxsMaterialCore* mat;
		while(iter.getNextMaterial(mat))
		{
			const PxMaterial* theMaterial = mat->mMaterial;
			if(mPvd->registerObject(theMaterial))
				mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, physics);
		};
	}

	if(mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
	{
		PxArray<PxActor*> actorArray;

		// RBs
		// static:
		{
			PxU32 numActors = npScene->getNbActors(PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC);
			actorArray.resize(numActors);
			npScene->getActors(PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC, actorArray.begin(), actorArray.size());
			for(PxU32 i = 0; i < numActors; i++)
			{
				PxActor* pxActor = actorArray[i];
				if(pxActor->getConcreteType()==PxConcreteType::eRIGID_STATIC)
					mMetaDataBinding.createInstance(*mPvdDataStream, *static_cast<PxRigidStatic*>(pxActor), *npScene, physics, mPvd);
				else
					mMetaDataBinding.createInstance(*mPvdDataStream, *static_cast<PxRigidDynamic*>(pxActor), *npScene, physics, mPvd);
			}
		}
		// articulations & links
		{
			PxArray<PxArticulationReducedCoordinate*> articulations;
			PxU32 numArticulations = npScene->getNbArticulations();
			articulations.resize(numArticulations);
			npScene->getArticulations(articulations.begin(), articulations.size());
			for(PxU32 i = 0; i < numArticulations; i++)
				mMetaDataBinding.createInstance(*mPvdDataStream, *articulations[i], *npScene, physics, mPvd);
		}

		// joints
		{
			Sc::ConstraintCore*const * constraints = mScene.getScScene().getConstraints();
			PxU32 nbConstraints = mScene.getScScene().getNbConstraints();
			for(PxU32 i = 0; i < nbConstraints; i++)
			{
				updateConstraint(*constraints[i], PxPvdUpdateType::CREATE_INSTANCE);
				updateConstraint(*constraints[i], PxPvdUpdateType::UPDATE_ALL_PROPERTIES);
			}
		}
	}

	if(npScene->getFlagsFast() & PxSceneFlag::eREQUIRE_RW_LOCK)
		npScene->unlockRead();
}

void PvdSceneClient::updateConstraint(const Sc::ConstraintCore& scConstraint, PxU32 updateType)
{
	PxConstraintConnector* conn = scConstraint.getPxConnector();
	if(conn && checkPvdDebugFlag())	
		conn->updatePvdProperties(*mPvdDataStream, scConstraint.getPxConstraint(), PxPvdUpdateType::Enum(updateType));
}

void PvdSceneClient::createPvdInstance(const PxActor* actor)
{
	if(checkPvdDebugFlag())	
		ActorTypeOperation(actor, CreateOp(*mPvdDataStream, mMetaDataBinding, mPvd, mScene));
}

void PvdSceneClient::updatePvdProperties(const PxActor* actor)
{
	if(checkPvdDebugFlag())	
		ActorTypeOperation(actor, UpdateOp(*mPvdDataStream, mMetaDataBinding));
}

void PvdSceneClient::releasePvdInstance(const PxActor* actor)
{
	if(checkPvdDebugFlag())	
		ActorTypeOperation(actor, DestroyOp(*mPvdDataStream, mMetaDataBinding, mScene));
}

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

void PvdSceneClient::createPvdInstance(const NpActor* actor)
{
	// PT: why not UPDATE_PVD_PROPERTIES_CHECK() here?
	createPvdInstance(getPxActor(actor));
}

void PvdSceneClient::updatePvdProperties(const NpActor* actor)
{
	// PT: why not UPDATE_PVD_PROPERTIES_CHECK() here?
	updatePvdProperties(getPxActor(actor));
}

void PvdSceneClient::releasePvdInstance(const NpActor* actor)
{
	// PT: why not UPDATE_PVD_PROPERTIES_CHECK() here?
	releasePvdInstance(getPxActor(actor));
}

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

void PvdSceneClient::createPvdInstance(const NpRigidDynamic* body)
{
	if(checkPvdDebugFlag() && body->getNpType() != NpType::eBODY_FROM_ARTICULATION_LINK)
		BodyTypeOperation(body, CreateOp(*mPvdDataStream, mMetaDataBinding, mPvd, mScene));
}

void PvdSceneClient::createPvdInstance(const NpArticulationLink* body)
{
	if(checkPvdDebugFlag() && body->getNpType() != NpType::eBODY_FROM_ARTICULATION_LINK)
		BodyTypeOperation(body, CreateOp(*mPvdDataStream, mMetaDataBinding, mPvd, mScene));
}

void PvdSceneClient::releasePvdInstance(const NpRigidDynamic* body)
{
	releasePvdInstance(getPxActor(body));
}

void PvdSceneClient::releasePvdInstance(const NpArticulationLink* body)
{
	releasePvdInstance(getPxActor(body));
}

void PvdSceneClient::updateBodyPvdProperties(const NpActor* body)
{
	if(checkPvdDebugFlag())
	{
		if(body->getNpType() == NpType::eBODY_FROM_ARTICULATION_LINK)
			updatePvdProperties(static_cast<const NpArticulationLink*>(body));
		else if(body->getNpType() == NpType::eBODY)
			updatePvdProperties(static_cast<const NpRigidDynamic*>(body));
		else PX_ASSERT(0);
	}
}

void PvdSceneClient::updatePvdProperties(const NpRigidDynamic* body)
{
	if(checkPvdDebugFlag())	
		BodyTypeOperation(body, UpdateOp(*mPvdDataStream, mMetaDataBinding));
}

void PvdSceneClient::updatePvdProperties(const NpArticulationLink* body)
{
	if(checkPvdDebugFlag())	
		BodyTypeOperation(body, UpdateOp(*mPvdDataStream, mMetaDataBinding));
}

void PvdSceneClient::updateKinematicTarget(const NpActor* body, const PxTransform& p)
{
	if(checkPvdDebugFlag())
	{
		if(body->getNpType() == NpType::eBODY_FROM_ARTICULATION_LINK)
			mPvdDataStream->setPropertyValue(static_cast<const NpArticulationLink*>(body), "KinematicTarget", p);
		else if(body->getNpType() == NpType::eBODY)
			mPvdDataStream->setPropertyValue(static_cast<const NpRigidDynamic*>(body), "KinematicTarget", p);
		else PX_ASSERT(0);
	}
}

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

void PvdSceneClient::releasePvdInstance(const NpRigidStatic* rigidStatic)
{
	releasePvdInstance(static_cast<const NpActor*>(rigidStatic));
}

void PvdSceneClient::createPvdInstance(const NpRigidStatic* rigidStatic)
{	
	if(checkPvdDebugFlag())	
		mMetaDataBinding.createInstance(*mPvdDataStream, *rigidStatic, mScene, PxGetPhysics(), mPvd);
}

void PvdSceneClient::updatePvdProperties(const NpRigidStatic* rigidStatic)
{
	if(checkPvdDebugFlag())	
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *rigidStatic);
}

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

void PvdSceneClient::createPvdInstance(const NpConstraint* constraint)
{
	if(checkPvdDebugFlag())	
		updateConstraint(constraint->getCore(), PxPvdUpdateType::CREATE_INSTANCE);
}

void PvdSceneClient::updatePvdProperties(const NpConstraint* constraint)
{
	if(checkPvdDebugFlag())	
		updateConstraint(constraint->getCore(), PxPvdUpdateType::UPDATE_ALL_PROPERTIES);
}

void PvdSceneClient::releasePvdInstance(const NpConstraint* constraint)
{	
	const Sc::ConstraintCore& scConstraint = constraint->getCore();
	PxConstraintConnector* conn;
	if(checkPvdDebugFlag() && (conn = scConstraint.getPxConnector()) != NULL)
		conn->updatePvdProperties(*mPvdDataStream, scConstraint.getPxConstraint(), PxPvdUpdateType::RELEASE_INSTANCE);
}

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

void PvdSceneClient::createPvdInstance(const NpArticulationReducedCoordinate* articulation)
{
	if (checkPvdDebugFlag())
	{
		mMetaDataBinding.createInstance(*mPvdDataStream, *articulation, mScene, PxGetPhysics(), mPvd);
	}
}

void PvdSceneClient::updatePvdProperties(const NpArticulationReducedCoordinate* articulation)
{
	if(checkPvdDebugFlag())
	{
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *articulation);
	}
}

void PvdSceneClient::releasePvdInstance(const NpArticulationReducedCoordinate* articulation)
{
	if (checkPvdDebugFlag())
	{
		mMetaDataBinding.destroyInstance(*mPvdDataStream, *articulation, mScene);
	}
}

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

void PvdSceneClient::createPvdInstance(const NpArticulationJointReducedCoordinate* articulationJoint)
{
	PX_UNUSED(articulationJoint);
}

void PvdSceneClient::updatePvdProperties(const NpArticulationJointReducedCoordinate* articulationJoint)
{
	if (checkPvdDebugFlag())
	{
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *articulationJoint);
	}
}

void PvdSceneClient::releasePvdInstance(const NpArticulationJointReducedCoordinate* articulationJoint)
{
	PX_UNUSED(articulationJoint);
}
/////////////////////////////////////////////////////////////////////////////////

void PvdSceneClient::createPvdInstance(const NpArticulationSpatialTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

void PvdSceneClient::updatePvdProperties(const NpArticulationSpatialTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

void PvdSceneClient::releasePvdInstance(const NpArticulationSpatialTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

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

void PvdSceneClient::createPvdInstance(const NpArticulationFixedTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

void PvdSceneClient::updatePvdProperties(const NpArticulationFixedTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

void PvdSceneClient::releasePvdInstance(const NpArticulationFixedTendon* articulationTendon)
{
	PX_UNUSED(articulationTendon);
}

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

void PvdSceneClient::createPvdInstance(const NpArticulationMimicJoint* mimicJoint)
{
	PX_UNUSED(mimicJoint);
}

void PvdSceneClient::updatePvdProperties(const NpArticulationMimicJoint* mimicJoint)
{
	PX_UNUSED(mimicJoint);
}

void PvdSceneClient::releasePvdInstance(const NpArticulationMimicJoint* mimicJoint)
{
	PX_UNUSED(mimicJoint);
}


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

void PvdSceneClient::createPvdInstance(const PxsMaterialCore* materialCore)
{	
	if(checkPvdDebugFlag())	
	{
		const PxMaterial* theMaterial = materialCore->mMaterial;
		if(mPvd->registerObject(theMaterial))
			mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, PxGetPhysics());
	}
}

void PvdSceneClient::updatePvdProperties(const PxsMaterialCore* materialCore)
{
	if(checkPvdDebugFlag())	
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *materialCore->mMaterial);
}

void PvdSceneClient::releasePvdInstance(const PxsMaterialCore* materialCore)
{
	if(checkPvdDebugFlag() && mPvd->unRegisterObject(materialCore->mMaterial))
		mMetaDataBinding.destroyInstance(*mPvdDataStream, *materialCore->mMaterial, PxGetPhysics());
}

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

void PvdSceneClient::createPvdInstance(const PxsDeformableSurfaceMaterialCore* materialCore)
{
	if (checkPvdDebugFlag())
	{
		const PxDeformableSurfaceMaterial* theMaterial = materialCore->mMaterial;
		if (mPvd->registerObject(theMaterial))
			mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, PxGetPhysics());
	}
}

void PvdSceneClient::updatePvdProperties(const PxsDeformableSurfaceMaterialCore* materialCore)
{
	if (checkPvdDebugFlag())
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *materialCore->mMaterial);
}

void PvdSceneClient::releasePvdInstance(const PxsDeformableSurfaceMaterialCore* materialCore)
{
	if (checkPvdDebugFlag() && mPvd->unRegisterObject(materialCore->mMaterial))
		mMetaDataBinding.destroyInstance(*mPvdDataStream, *materialCore->mMaterial, PxGetPhysics());
}

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

void PvdSceneClient::createPvdInstance(const PxsDeformableVolumeMaterialCore* materialCore)
{
	if (checkPvdDebugFlag())
	{
		const PxDeformableVolumeMaterial* theMaterial = materialCore->mMaterial;
		if (mPvd->registerObject(theMaterial))
			mMetaDataBinding.createInstance(*mPvdDataStream, *theMaterial, PxGetPhysics());
	}
}

void PvdSceneClient::updatePvdProperties(const PxsDeformableVolumeMaterialCore* materialCore)
{
	if (checkPvdDebugFlag())
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *materialCore->mMaterial);
}

void PvdSceneClient::releasePvdInstance(const PxsDeformableVolumeMaterialCore* materialCore)
{
	if (checkPvdDebugFlag() && mPvd->unRegisterObject(materialCore->mMaterial))
		mMetaDataBinding.destroyInstance(*mPvdDataStream, *materialCore->mMaterial, PxGetPhysics());
}

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

void PvdSceneClient::createPvdInstance(const PxsPBDMaterialCore* /*materialCore*/)
{
//	PX_ASSERT(0);
}

void PvdSceneClient::updatePvdProperties(const PxsPBDMaterialCore* /*materialCore*/)
{
//	PX_ASSERT(0);
}

void PvdSceneClient::releasePvdInstance(const PxsPBDMaterialCore* /*materialCore*/)
{
//	PX_ASSERT(0);
}

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

void PvdSceneClient::createPvdInstance(const NpShape* npShape, PxActor& owner)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScene));
		mMetaDataBinding.createInstance(*mPvdDataStream, *npShape, static_cast<PxRigidActor&>(owner), PxGetPhysics(), mPvd);
	}
}

static void addShapesToPvd(PxU32 nbShapes, NpShape* const* shapes, PxActor& pxActor, PsPvd* pvd, PvdDataStream& stream, PvdMetaDataBinding& binding)
{
	PxPhysics& physics = PxGetPhysics();
	for(PxU32 i=0;i<nbShapes;i++)
	{
		const NpShape* npShape = shapes[i];
		binding.createInstance(stream, *npShape, static_cast<PxRigidActor&>(pxActor), physics, pvd);
	}
}

void PvdSceneClient::addBodyAndShapesToPvd(NpRigidDynamic& b)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScene));
		createPvdInstance(&b);

		PxActor& pxActor = *b.getCore().getPxActor();
		NpShape* const* shapes;
		const PxU32 nbShapes = NpRigidDynamicGetShapes(b, shapes);
		addShapesToPvd(nbShapes, shapes, pxActor, mPvd, *mPvdDataStream, mMetaDataBinding);
	}
}

void PvdSceneClient::addStaticAndShapesToPvd(NpRigidStatic& s)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScene));
		createPvdInstance(&s);

		PxActor& pxActor = static_cast<PxRigidStatic&>(s);
		NpShape* const* shapes;
		const PxU32 nbShapes = NpRigidStaticGetShapes(s, shapes);
		addShapesToPvd(nbShapes, shapes, pxActor, mPvd, *mPvdDataStream, mMetaDataBinding);
	}
}

void PvdSceneClient::updateMaterials(const NpShape* npShape)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.updateMaterials(*mPvdDataStream, *npShape, mPvd);
}

void PvdSceneClient::updatePvdProperties(const NpShape* npShape)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *npShape);
}

void PvdSceneClient::releaseAndRecreateGeometry(const NpShape* npShape)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.releaseAndRecreateGeometry(*mPvdDataStream, *npShape, NpPhysics::getInstance(), mPvd);
}

void PvdSceneClient::releasePvdInstance(const NpShape* npShape, PxActor& owner)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId(mScene));

		mMetaDataBinding.destroyInstance(*mPvdDataStream, *npShape, static_cast<PxRigidActor&>(owner));

		const PxU32 numMaterials = npShape->getNbMaterials();
		PX_ALLOCA(materialPtr, PxMaterial*, numMaterials);
		npShape->getMaterials(materialPtr, numMaterials);

		for(PxU32 idx = 0; idx < numMaterials; ++idx)
			releasePvdInstance(&(static_cast<NpMaterial*>(materialPtr[idx])->mMaterial));
	}
}

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

void PvdSceneClient::originShift(PxVec3 shift)
{
	mMetaDataBinding.originShift(*mPvdDataStream, &mScene, shift);
}

void PvdSceneClient::frameStart(PxReal simulateElapsedTime)
{	
	PX_PROFILE_ZONE("Basic.pvdFrameStart", mScene.getScScene().getContextId());

	if(!mIsConnected)
		return;

	mPvdDataStream->flushPvdCommand();
	mMetaDataBinding.sendBeginFrame(*mPvdDataStream, &mScene, simulateElapsedTime);
}

void PvdSceneClient::frameEnd()
{
	PX_PROFILE_ZONE("Basic.pvdFrameEnd", mScene.getScScene().getContextId());

	if(!mIsConnected)
	{
		if(mPvd)
			mPvd->flush(); // Even if we aren't connected, we may need to flush buffered events.
		return;
	}

	PxScene* theScene = &mScene;
	
	mMetaDataBinding.sendStats(*mPvdDataStream, theScene);

	// flush our data to the main connection
	mPvd->flush();

	// End the frame *before* we send the dynamic object current data.
	// This ensures that contacts end up synced with the rest of the system.
	// Note that contacts were sent much earler in NpScene::fetchResults.
	mMetaDataBinding.sendEndFrame(*mPvdDataStream, &mScene);

	if(mPvd->getInstrumentationFlags() & PxPvdInstrumentationFlag::eDEBUG)
	{
		PX_PROFILE_ZONE("PVD.sceneUpdate", getContextId(mScene));

		PvdVisualizer* vizualizer = NULL;
		const bool visualizeJoints = getScenePvdFlagsFast() & PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS;
		if(visualizeJoints)
			vizualizer = this;

		mMetaDataBinding.updateDynamicActorsAndArticulations(*mPvdDataStream, theScene, vizualizer);
	}

	// frame end moved to update contacts to have them in the previous frame.
}

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

void PvdSceneClient::createPvdInstance(const NpAggregate* npAggregate)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.createPVDInstance", getContextId(mScene));
		mMetaDataBinding.createInstance(*mPvdDataStream, *npAggregate, mScene);
	}
}

void PvdSceneClient::updatePvdProperties(const NpAggregate* npAggregate)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.sendAllProperties(*mPvdDataStream, *npAggregate);
}

void PvdSceneClient::attachAggregateActor(const NpAggregate* npAggregate, NpActor* actor)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.attachAggregateActor(*mPvdDataStream, *npAggregate, *getPxActor(actor));
}

void PvdSceneClient::detachAggregateActor(const NpAggregate* npAggregate, NpActor* actor)
{
	if(checkPvdDebugFlag())
		mMetaDataBinding.detachAggregateActor(*mPvdDataStream, *npAggregate, *getPxActor(actor));
}

void PvdSceneClient::releasePvdInstance(const NpAggregate* npAggregate)
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.releasePVDInstance", getContextId(mScene));
		mMetaDataBinding.destroyInstance(*mPvdDataStream, *npAggregate, mScene);
	}
}

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

#if PX_SUPPORT_GPU_PHYSX
void PvdSceneClient::createPvdInstance(const NpDeformableVolume* deformableVolume)
{
	PX_UNUSED(deformableVolume);
	//Todo
}

void PvdSceneClient::updatePvdProperties(const NpDeformableVolume* deformableVolume)
{
	PX_UNUSED(deformableVolume);
	//Todo
}

void PvdSceneClient::attachAggregateActor(const NpDeformableVolume* deformableVolume, NpActor* actor)
{
	PX_UNUSED(deformableVolume);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::detachAggregateActor(const NpDeformableVolume* deformableVolume, NpActor* actor)
{
	PX_UNUSED(deformableVolume);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::releasePvdInstance(const NpDeformableVolume* deformableVolume)
{
	PX_UNUSED(deformableVolume);
	//Todo
}

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

void PvdSceneClient::createPvdInstance(const NpDeformableSurface* femCloth)
{
	PX_UNUSED(femCloth);
	//Todo
}

void PvdSceneClient::updatePvdProperties(const NpDeformableSurface* femCloth)
{
	PX_UNUSED(femCloth);
	//Todo
}

void PvdSceneClient::attachAggregateActor(const NpDeformableSurface* femCloth, NpActor* actor)
{
	PX_UNUSED(femCloth);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::detachAggregateActor(const NpDeformableSurface* femCloth, NpActor* actor)
{
	PX_UNUSED(femCloth);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::releasePvdInstance(const NpDeformableSurface* femCloth)
{
	PX_UNUSED(femCloth);
	//Todo
}

///////////////////////////////////////////////////////////////////////////////
void PvdSceneClient::createPvdInstance(const NpPBDParticleSystem* particleSystem)
{
	PX_UNUSED(particleSystem);
	//Todo
}

void PvdSceneClient::updatePvdProperties(const NpPBDParticleSystem* particleSystem)
{
	PX_UNUSED(particleSystem);
	//Todo
}

void PvdSceneClient::attachAggregateActor(const NpPBDParticleSystem* particleSystem, NpActor* actor)
{
	PX_UNUSED(particleSystem);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::detachAggregateActor(const NpPBDParticleSystem* particleSystem, NpActor* actor)
{
	PX_UNUSED(particleSystem);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::releasePvdInstance(const NpPBDParticleSystem* particleSystem)
{
	PX_UNUSED(particleSystem);
	//Todo
}

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

void PvdSceneClient::createPvdInstance(const NpDeformableAttachment* attachment)
{
	PX_UNUSED(attachment);
	//Todo
}

void PvdSceneClient::updatePvdProperties(const NpDeformableAttachment* attachment)
{
	PX_UNUSED(attachment);
	//Todo
}

void PvdSceneClient::attachAggregateActor(const NpDeformableAttachment* attachment, NpActor* actor)
{
	PX_UNUSED(attachment);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::detachAggregateActor(const NpDeformableAttachment* attachment, NpActor* actor)
{
	PX_UNUSED(attachment);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::releasePvdInstance(const NpDeformableAttachment* attachment)
{
	PX_UNUSED(attachment);
	//Todo
}

void PvdSceneClient::createPvdInstance(const NpDeformableElementFilter* elementFilter)
{
	PX_UNUSED(elementFilter);
	//Todo
}

void PvdSceneClient::updatePvdProperties(const NpDeformableElementFilter* elementFilter)
{
	PX_UNUSED(elementFilter);
	//Todo
}

void PvdSceneClient::attachAggregateActor(const NpDeformableElementFilter* elementFilter, NpActor* actor)
{
	PX_UNUSED(elementFilter);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::detachAggregateActor(const NpDeformableElementFilter* elementFilter, NpActor* actor)
{
	PX_UNUSED(elementFilter);
	PX_UNUSED(actor);
	//Todo
}

void PvdSceneClient::releasePvdInstance(const NpDeformableElementFilter* elementFilter)
{
	PX_UNUSED(elementFilter);
	//Todo
}

#endif

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

void PvdSceneClient::updateJoints()
{
	if(checkPvdDebugFlag())
	{
		PX_PROFILE_ZONE("PVD.updateJoints", getContextId(mScene));

		const bool visualizeJoints = getScenePvdFlagsFast() & PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS;

		Sc::ConstraintCore*const * constraints = mScene.getScScene().getConstraints();
		const PxU32 nbConstraints = mScene.getScScene().getNbConstraints();

		for(PxU32 i=0; i<nbConstraints; i++)
		{
			Sc::ConstraintCore* constraint = constraints[i];
			PxPvdUpdateType::Enum updateType = getNpConstraint(constraint)->isDirty()
				? PxPvdUpdateType::UPDATE_ALL_PROPERTIES
				: PxPvdUpdateType::UPDATE_SIM_PROPERTIES;
			updateConstraint(*constraint, updateType);
			PxConstraintConnector* conn = constraint->getPxConnector();
			// visualization is updated here
			{
				PxU32 typeId = 0;
				void* joint = NULL;
				if(conn)
					joint = conn->getExternalReference(typeId);
				// visualize:
				Sc::ConstraintSim* sim = constraint->getSim();
				if(visualizeJoints && sim && sim->getConstantsLL() && joint && constraint->getVisualize())
				{
					Sc::BodySim* b0 = sim->getBody(0);
					Sc::BodySim* b1 = sim->getBody(1);
					PxTransform t0 = b0 ? b0->getBody2World() : PxTransform(PxIdentity);
					PxTransform t1 = b1 ? b1->getBody2World() : PxTransform(PxIdentity);
					PvdConstraintVisualizer viz(joint, *mUserRender);
					(*constraint->getVisualize())(viz, sim->getConstantsLL(), t0, t1, 0xffffFFFF);
				}
			}
		}

		mUserRender->flushRenderEvents();
	}
}

void PvdSceneClient::updateContacts()
{
	if(!checkPvdDebugFlag())
		return;

	PX_PROFILE_ZONE("PVD.updateContacts", getContextId(mScene));

	// if contacts are disabled, send empty array and return
	const PxScene* theScene = &mScene;
	if(!(getScenePvdFlagsFast() & PxPvdSceneFlag::eTRANSMIT_CONTACTS))
	{
		mMetaDataBinding.sendContacts(*mPvdDataStream, *theScene);
		return;
	}

	PxsContactManagerOutputIterator outputIter;

	Sc::ContactIterator contactIter;
	mScene.getScScene().initContactsIterator(contactIter, outputIter);
	Sc::ContactIterator::Pair* pair;
	Sc::Contact* contact;
	PxArray<Sc::Contact> contacts;
	while ((pair = contactIter.getNextPair()) != NULL)
	{
		while ((contact = pair->getNextContact()) != NULL)
			contacts.pushBack(*contact);
	}
	
	mMetaDataBinding.sendContacts(*mPvdDataStream, *theScene, contacts);
}

void PvdSceneClient::updateSceneQueries()
{
	if(checkPvdDebugFlag() && (getScenePvdFlagsFast() & PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES))
		mMetaDataBinding.sendSceneQueries(*mPvdDataStream, mScene, mPvd);
}

void PvdSceneClient::visualize(PxArticulationLink& link)
{
#if PX_ENABLE_DEBUG_VISUALIZATION
	NpArticulationLink& npLink = static_cast<NpArticulationLink&>(link);
	const void* itemId = npLink.getInboundJoint();
	if(itemId && mUserRender)
	{
		PvdConstraintVisualizer viz(itemId, *mUserRender);
		npLink.visualizeJoint(viz);
	}
#else
	PX_CATCH_UNDEFINED_ENABLE_DEBUG_VISUALIZATION
	PX_UNUSED(link);
#endif
}

void PvdSceneClient::visualize(const PxRenderBuffer& debugRenderable)
{
	if(mUserRender)
	{
		// PT: I think the mUserRender object can contain extra data (including things coming from the user), because the various
		// draw functions are exposed e.g. in PxPvdSceneClient.h. So I suppose we have to keep the render buffer around regardless
		// of the connection flags. Thus I only skip the "drawRenderbuffer" call, for minimal intrusion into this file.
		if(checkPvdDebugFlag())
		{
			mUserRender->drawRenderbuffer(
				reinterpret_cast<const PxDebugPoint*>(debugRenderable.getPoints()), debugRenderable.getNbPoints(),
				reinterpret_cast<const PxDebugLine*>(debugRenderable.getLines()), debugRenderable.getNbLines(),
				reinterpret_cast<const PxDebugTriangle*>(debugRenderable.getTriangles()), debugRenderable.getNbTriangles());
		}
		mUserRender->flushRenderEvents();
	}
}

#endif
