/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmSDKAPI.h"
#include "glmEntityClothesInterface.h"
#include "glmString.h"
#include "glmSimuEntityHandle.h"
#include "glmClothVertex.h"

namespace nvidia
{
	namespace apex
	{
		class ClothingCollision;
		class ClothingAsset;
		class ClothingActor;
		class ClothingSphere;
		class ClothingCapsule;
	}
}

namespace glm
{
	class Simulation;
	class RagdollEntityComponent_PhysX;
	class PhysicsWorld_PhysX;
	class PhysicsContext_PhysX;
	class PhysicsRigidBody;
	class CharacterSkinMeshes;
	struct ClothingAssetWithCacheData;

	struct GLM_SDK_API ClothingActor
	{
		GLM_CLASS_STAT_ID(glm::MemoryStatIds::Simulation);

		ClothingActor()
			: _clothingActor(NULL) 
			, _clothingAsset(NULL)
			, _entityMeshAssetIndex(-1)
			, _atlasGeometryMeshIndex(-1)
			, _nextUpdateMode(2)	//ClothingTeleportMode::TeleportAndReset
			, _meshName("")
			, _frozenClothBoneBinding(-1)
		{}

		ClothingActor(const glm::GlmString& meshName, int entityMeshAssetIndex, int atlasGeometryMeshIndex, nvidia::apex::ClothingActor* clothingActor, ClothingAssetWithCacheData* clothingAsset, int nextUpdateMode)
			: _clothingActor(clothingActor)
			, _clothingAsset(clothingAsset)
			, _entityMeshAssetIndex(entityMeshAssetIndex)
			, _atlasGeometryMeshIndex(atlasGeometryMeshIndex)
			, _nextUpdateMode(nextUpdateMode)
			, _meshName(meshName)
			, _frozenClothBoneBinding(-1)
		{}

		void updateRenderArrays();

		nvidia::apex::ClothingActor* _clothingActor;
		ClothingAssetWithCacheData* _clothingAsset;

		int _entityMeshAssetIndex;		//the index of the mesh in the getSimulation()->getMeshAssets()[index]; list
		int _atlasGeometryMeshIndex;	//the index to use in the CharacterSkinMeshes::getAtlasGeometrySubmesh(...) method
		int _nextUpdateMode;
		
		float _additionalClothScale = 1.f;
		bool _additionalSupportScale = true;

		glm::Array<PhysicsRigidBody*> _rigidBodiesColliders;					//configuration
		glm::Array<nvidia::apex::ClothingCollision*> _clothingCollisions;		//filled up by initialization

		glm::GlmString _meshName;

		int _frozenClothBoneBinding;

		glm::PODArray<ClothVertex> _clothVerticesForRendering;	// one for each triangle vertex
		glm::PODArray<uint32_t> _clothIndicesForRendering;		// one for each triangle vertex, matches _clothVerticesForRendering indices
	};

	class GLM_SDK_API ApexEntityClothes : public EntityClothesInterface
	{
	public:		//methods
		ApexEntityClothes()
			: _simulation(NULL)
		{}
		virtual ~ApexEntityClothes() { }

		bool isValid() const;
		Entity* getEntity();
		const Entity* getEntity() const;

		size_t getSimulatedClothesCount() const;
		bool isClothValid(size_t clothIndex) const;
		int getSimulatedClothAssetMeshIndex(size_t clothIndex) const;
		void getSimulatedClothMeshVertices(glm::PODArray<uint32_t>& meshVertexCountPerMeshIndex, glm::Array<Vector3>& meshVertices, const Vector3& coordinateSystemPos, const Quaternion& coordinateSystemOri, const size_t clothIndex) const;

		size_t getFrozenClothesCount() const;
		bool isFrozenClothValid(size_t clothIndex) const;
		int getFrozenClothAssetMeshIndex(size_t clothIndex) const;
		void getFrozenClothMeshVertices(glm::PODArray<uint32_t>& meshVertexCountPerMeshIndex, glm::Array<Vector3>& meshVertices, const Vector3& coordinateSystemPos, const Quaternion& coordinateSystemOri, const size_t clothIndex) const;

	public:	//data
		Simulation* _simulation;
		SimuEntityHandle _entityHandle;

		glm::Array<ClothingActor*> _activeClothingActors;
		glm::Array<ClothingActor*> _freezedClothingActors;

		friend class PhysicsWorld_PhysX;
		friend class PhysicsContext_PhysX;
	};
}

