//-
// ==========================================================================
// Copyright 2010 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+

///////////////////////////////////////////////////////////////////////////////
//
// apiMeshGeometryOverride.h
//
// Handles vertex data preparation for drawing the user defined shape in
// Viewport 2.0.
//
////////////////////////////////////////////////////////////////////////////////

#include <maya/MPxGeometryOverride.h>
#include <maya/MIntArray.h>
#include <maya/MStateManager.h>
#include <maya/MTextureManager.h>
#include <set>

class apiMesh;
class apiMeshGeom;
namespace MHWRender
{
	class MIndexBuffer;
}

class apiMeshGeometryOverride : public MHWRender::MPxGeometryOverride
{
public:
	static MPxGeometryOverride* Creator(const MObject& obj)
	{
		return new apiMeshGeometryOverride(obj);
	}

	virtual ~apiMeshGeometryOverride();

	virtual MHWRender::DrawAPI supportedDrawAPIs() const;

	virtual void updateDG();
	virtual void updateRenderItems(
		const MDagPath& path,
		MHWRender::MRenderItemList& list);
	virtual void populateGeometry(
		const MHWRender::MGeometryRequirements& requirements,
        const MHWRender::MRenderItemList& renderItems,
		MHWRender::MGeometry& data);
	virtual void cleanUp();

protected:
	void printShader(MHWRender::MShaderInstance* shader);
	void setSolidColor(MHWRender::MShaderInstance* shaderInstance, const float *value);
	void setSolidPointSize(MHWRender::MShaderInstance* shaderInstance, float value);
	void setLineWidth(MHWRender::MShaderInstance* shaderInstance, float lineWidth);
	bool enableActiveComponentDisplay(const MDagPath &path) const;

	// Render item handling methods
	void updateDormantAndTemplateWireframeItems(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateActiveWireframeItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateWireframeModeFaceCenterItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateShadedModeFaceCenterItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateDormantVerticesItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateActiveVerticesItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr, bool enableActiveDisplay);
	void updateVertexNumericItems(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);
	void updateAffectedComponentItems(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr, bool enableActiveDisplay);
	void updateProxyShadedItem(const MDagPath& path, MHWRender::MRenderItemList& list, const MHWRender::MShaderManager* shaderMgr);

	// Data stream (geometry requirements) handling
	void updateGeometryRequirements(const MHWRender::MGeometryRequirements& requirements,
		MHWRender::MGeometry& data,
		unsigned int activeVertexCount,
		unsigned int totalVerts,
		bool debugPopulateGeometry);

	// Indexing for render item handling methods
	void updateIndexingForWireframeItems(MHWRender::MIndexBuffer* wireIndexBuffer,
		const MHWRender::MRenderItem* item,
		MHWRender::MGeometry& data,
		unsigned int totalVerts);
	void updateIndexingForDormantVertices(const MHWRender::MRenderItem* item, MHWRender::MGeometry& data, unsigned int numTriangles);
	void updateIndexingForFaceCenters(const MHWRender::MRenderItem* item, MHWRender::MGeometry& data, bool debugPopulateGeometry);
	void updateIndexingForActiveVertices(const MHWRender::MRenderItem* item, 
		MHWRender::MGeometry& data,
		unsigned int numTriangles,
		unsigned int activeVertexCount,
		std::set<int> & vertexIdSet,
		bool debugPopulateGeometry);
	void updateIndexingForAffectedEdges(const MHWRender::MRenderItem* item,
		MHWRender::MGeometry& data, 
		std::set<int> & vertexIdSet,
		unsigned int totalVerts);
	void updateIndexingForAffectedFaces(const MHWRender::MRenderItem* item,
		MHWRender::MGeometry& data, 
		std::set<int> & vertexIdSet,
		unsigned int numTriangles);
	void updateIndexingForShadedTriangles(const MHWRender::MRenderItem* item,
		MHWRender::MGeometry& data, 
		unsigned int numTriangles);

	apiMeshGeometryOverride(const MObject& obj);

	apiMesh* fMesh;
	apiMeshGeom* fMeshGeom;
	MIntArray fActiveVertices;
	bool fCastsShadows;
    bool fReceivesShadows;

	// Render item names
	MString fWireframeItemName;
	MString fShadedTemplateItemName;
	MString fSelectedWireframeItemName;
	MString fVertexItemName;
	MString fActiveVertexItemName;
	MString fVertexIdItemName;
	MString fVertexPositionItemName;
	MString fShadedModeFaceCenterItemName;
	MString fWireframeModeFaceCenterItemName;
	MString fShadedProxyItemName;
	MString fAffectedEdgeItemName;
	MString fAffectedFaceItemName;

	// Stream names used for filling in different data
	// for different streams required for different render items,
	// and toggle to choose whether to use name streams
	//
	MString fActiveVertexStreamName;
	bool fDrawSharedActiveVertices;
	bool fDrawActiveVerticesWithRamp;
	MHWRender::MTexture *fColorRemapTexture;
	const MHWRender::MSamplerState* fLinearSampler;

	//Vertex stream for face centers which is calculated from faces.
	MString fFaceCenterStreamName;
	bool fDrawFaceCenters;

	// Custom color option
	bool fUseCustomColors;

	// Proxy shader. Fallback shader to use when no shader is assigned
	// if set to < 0 then will use a fragment shader
	int fProxyShader;

	// Test overrides on shaded mode render items
	bool fInternalItems_NoShadowCast;
	bool fInternalItems_NoShadowReceive;
	bool fInternalItems_NoPostEffects;
	bool fExternalItems_NoShadowCast;
	bool fExternalItems_NoShadowReceive;
	bool fExternalItems_NoPostEffects;
	bool fExternalItemsNonTri_NoShadowCast;
	bool fExternalItemsNonTri_NoShadowReceive;
	bool fExternalItemsNonTri_NoPostEffects;
};

