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

#pragma once
#include "glmSDKAPI.h"

#include <glmMemory.h>
#include <glmArray.h>
#include <glmPODArray.h>

#include <glmApex.h>
#include "glmClothVertex.h"

namespace glm
{
	/**
	\brief Used for storing per-vertex data for rendering.
	*/
	class GlmApexRenderVertexBuffer : public nvidia::apex::UserRenderVertexBuffer
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		GlmApexRenderVertexBuffer(const nvidia::apex::UserRenderVertexBufferDesc& desc);
		~GlmApexRenderVertexBuffer();

		/**
		\brief Called when APEX wants to update the contents of the vertex buffer.

		The source data type is assumed to be the same as what was defined in the descriptor.
		APEX should call this function and supply data for ALL semantics that were originally
		requested during creation every time its called.

		\param [in] data				Contains the source data for the vertex buffer.
		\param [in] firstVertex			first vertex to start writing to.
		\param [in] numVertices			number of vertices to write.
		*/
		void writeBuffer(const nvidia::apex::RenderVertexBufferData& data, physx::PxU32 firstVertex, physx::PxU32 numVertices);

		bool _containsPositions;
		bool _containsNormals;
		bool _containsTextCoords;
		glm::PODArray<ClothVertex> _vertices;
	};

	/**
	\brief Used for storing index data for rendering.
	*/
	class GlmApexRenderIndexBuffer : public nvidia::apex::UserRenderIndexBuffer
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		GlmApexRenderIndexBuffer(const nvidia::apex::UserRenderIndexBufferDesc& desc);
		~GlmApexRenderIndexBuffer();

		//! write some data into the buffer.
		//  the source data type is assumed to be the same as what was defined in the descriptor.
		void writeBuffer(const void* srcData, physx::PxU32 srcStride, physx::PxU32 firstDestElement, physx::PxU32 numElements);

		nvidia::apex::RenderDataFormat::Enum _inputFormat;
		glm::PODArray<uint32_t> _indices;
	};

	/**
	\brief Used for storing skeletal bone information used during skinning.

	Separated out into its own interface as we don't know how the user is going to implement this
	it could be in another vertex buffer, a texture or just an array and skinned on CPU depending
	on engine and hardware support.
	*/
	class GlmApexRenderBoneBuffer : public nvidia::apex::UserRenderBoneBuffer
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		GlmApexRenderBoneBuffer(const nvidia::apex::UserRenderBoneBufferDesc& desc);
		~GlmApexRenderBoneBuffer();

		/**
		\brief Called when APEX wants to update the contents of the bone buffer.

		The source data type is assumed to be the same as what was defined in the descriptor.
		APEX should call this function and supply data for ALL semantics that were originally
		requested during creation every time its called.

		\param [in] data				Contains the source data for the bone buffer.
		\param [in] firstBone			first bone to start writing to.
		\param [in] numBones			number of bones to write.
		*/
		virtual void writeBuffer(const nvidia::apex::RenderBoneBufferData& data, physx::PxU32 firstBone, physx::PxU32 numBones);

		glm::Array<physx::PxTransform> _bones;
	};

	/**
	\brief A renderable resource
	*/
	class GlmApexRenderResource : public nvidia::apex::UserRenderResource
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		GlmApexRenderResource(nvidia::apex::UserRenderResourceDesc desc);
		virtual ~GlmApexRenderResource() {}

		/** \brief Set vertex buffer range */
		void setVertexBufferRange(physx::PxU32 firstVertex, physx::PxU32 numVerts) { _firstVertex = firstVertex; _numVerts = numVerts; }
		/** \brief Set index buffer range */
		void setIndexBufferRange(physx::PxU32 firstIndex, physx::PxU32 numIndices) { _firstIndex = firstIndex; _numIndices = numIndices; }
		/** \brief Set bone buffer range */
		void setBoneBufferRange(physx::PxU32 firstBone, physx::PxU32 numBones) { _firstBone = firstBone; _numBones = numBones; }
		/** \brief Set instance buffer range */
		void setInstanceBufferRange(physx::PxU32 firstInstance, physx::PxU32 numInstances) { _firstInstance = firstInstance; _numInstances = numInstances; }
		/** \brief Set sprite buffer range */
		void setSpriteBufferRange(physx::PxU32 firstSprite, physx::PxU32 numSprites) { _firstSprite = firstSprite; _numSprites = numSprites; }
		/** \brief Set sprite visible count */
		void setSpriteVisibleCount(physx::PxU32 visibleCount) { _visibleSpriteCount = visibleCount; }
		/** \brief Set material */
		void setMaterial(void* material) { _material = material; }

		/** \brief Get number of vertex buffers */
		physx::PxU32			getNbVertexBuffers() const { return (physx::PxU32)_vertexBuffers.size(); }
		/** \brief Get vertex buffer */
		nvidia::apex::UserRenderVertexBuffer*	getVertexBuffer(physx::PxU32 index) const { return _vertexBuffers[index]; }
		/** \brief Get index buffer */
		nvidia::apex::UserRenderIndexBuffer*	getIndexBuffer() const { return const_cast<GlmApexRenderIndexBuffer*>(_indexBuffer); }	// apex inherited interface uses const getter but non-const return values...
		/** \brief Get bone buffer */
		nvidia::apex::UserRenderBoneBuffer*		getBoneBuffer() const { return const_cast<GlmApexRenderBoneBuffer*>(_boneBuffer); }	// apex inherited interface uses const getter but non-const return values...
		/** \brief Get instance buffer */
		nvidia::apex::UserRenderInstanceBuffer*	getInstanceBuffer() const { return instanceBuffer; }
		/** \brief Get sprite buffer */
		nvidia::apex::UserRenderSpriteBuffer*	getSpriteBuffer() const { return spriteBuffer; }



	protected: //data
		glm::Array<GlmApexRenderVertexBuffer*> _vertexBuffers;
		physx::PxU32 _firstVertex;		//!< First vertex to render
		physx::PxU32 _numVerts;			//!< Number of vertices to render

		GlmApexRenderIndexBuffer* _indexBuffer;		//!< optional index buffer used when rendering this resource.
		physx::PxU32 _firstIndex;			//!< First index to render
		physx::PxU32 _numIndices;			//!< Number of indices to render

		GlmApexRenderBoneBuffer* _boneBuffer;			//!< optional bone buffer used for skinned meshes.
		physx::PxU32 _firstBone;			//!< First bone to render
		physx::PxU32 _numBones;			//!< Number of bones to render

		nvidia::apex::UserRenderInstanceBuffer*		instanceBuffer;	//!< optional instance buffer if rendering multiple instances of the same resource.
		physx::PxU32 _firstInstance;		//!< First instance to render
		physx::PxU32 _numInstances;		//!< Number of instances to render

		nvidia::apex::UserRenderSpriteBuffer*		spriteBuffer;		//!< optional sprite buffer if rendering sprites
		physx::PxU32 _firstSprite;		//!< First sprite to render
		physx::PxU32 _numSprites;			//!< Number of sprites to render
		physx::PxU32 _visibleSpriteCount; //!< If the sprite buffer is using the view direction modifier; this will represent the number of sprites visible in front of the camera (Not necessarily in the frustum but in front of the camera)

		void* _material;			//!< user defined material used when rendering this resource.
	};



	/**
	\brief User defined renderable resource manager

	A render resource manager is an object that creates and manages renderable resources...
	This is given to the APEX SDK at creation time via the descriptor and must be persistent through the lifetime
	of the SDK.
	*/
	class GlmApexRenderResourceManager : public nvidia::apex::UserRenderResourceManager
	{
	public:
		GLM_CLASS_STAT_ID( glm::MemoryStatIds::Simulation)

		virtual	~GlmApexRenderResourceManager();

		virtual nvidia::apex::UserRenderVertexBuffer*   createVertexBuffer(const nvidia::apex::UserRenderVertexBufferDesc& /*desc*/);
		virtual void                        releaseVertexBuffer(nvidia::apex::UserRenderVertexBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderIndexBuffer*    createIndexBuffer(const nvidia::apex::UserRenderIndexBufferDesc& /*desc*/);
		virtual void                        releaseIndexBuffer(nvidia::apex::UserRenderIndexBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderBoneBuffer*     createBoneBuffer(const nvidia::apex::UserRenderBoneBufferDesc& /*desc*/);
		virtual void                        releaseBoneBuffer(nvidia::apex::UserRenderBoneBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderInstanceBuffer* createInstanceBuffer(const nvidia::apex::UserRenderInstanceBufferDesc& /*desc*/);
		virtual void                        releaseInstanceBuffer(nvidia::apex::UserRenderInstanceBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderSpriteBuffer*   createSpriteBuffer(const nvidia::apex::UserRenderSpriteBufferDesc& /*desc*/);
		virtual void                        releaseSpriteBuffer(nvidia::apex::UserRenderSpriteBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderSurfaceBuffer*  createSurfaceBuffer(const nvidia::apex::UserRenderSurfaceBufferDesc& /*desc*/);
		virtual void                        releaseSurfaceBuffer(nvidia::apex::UserRenderSurfaceBuffer& /*buffer*/);

		virtual nvidia::apex::UserRenderResource*       createResource(const nvidia::apex::UserRenderResourceDesc& /*desc*/);
		virtual void                        releaseResource(nvidia::apex::UserRenderResource& /*resource*/);

		virtual physx::PxU32                       getMaxBonesForMaterial(void* /*material*/);

		virtual bool getSpriteLayoutData(physx::PxU32 /*spriteCount*/, physx::PxU32 /*spriteSemanticsBitmap*/, nvidia::apex::UserRenderSpriteBufferDesc* /*textureDescArray*/);

		virtual bool getInstanceLayoutData(physx::PxU32 /*spriteCount*/, physx::PxU32 /*spriteSemanticsBitmap*/, nvidia::apex::UserRenderInstanceBufferDesc* /*instanceDescArray*/);

		//data
		glm::Array<GlmApexRenderVertexBuffer*> _vertexBuffers;
		glm::Array<GlmApexRenderIndexBuffer*> _indexBuffers;
		glm::Array<GlmApexRenderBoneBuffer*> _boneBuffers;
		glm::Array<GlmApexRenderResource*> _renderRessources;
	};
}

