#ifndef Renderer_hpp
#define Renderer_hpp

#include "VertexProcessor.hpp"
#include "PixelProcessor.hpp"

namespace swShader
{
	class Clipper;
	class Viewport;
	class VertexBuffer;
	class IndexBuffer;

	class Renderer : protected VertexProcessor, protected PixelProcessor
	{
	public:
		Renderer(const RenderTarget *renderTarget = 0);

		~Renderer();

		void drawPrimitive(const VertexBuffer *VB, const IndexBuffer *IB);

		void setRenderTarget(const RenderTarget *renderTarget);

		void setPixelShader(const char *pixelShaderFile);
		void setVertexShader(const char *vertexShaderFile);
			
		void setTextureMap(int stage, Texture *texture);
		void releaseTextures();

		// Fixed-function pipeline
		void setTexCoordIndex(int stage, int texCoordIndex);
		void setStageOperation(int stage, Sampler::StageOperation stageOperation);
		void setFirstArgument(int stage, Sampler::SourceArgument firstArgument);
		void setSecondArgument(int stage, Sampler::SourceArgument secondArgument);
		void setThirdArgument(int stage, Sampler::SourceArgument thirdArgument);
		void setFirstModifier(int stage, Sampler::ArgumentModifier firstModifier);
		void setSecondModifier(int stage, Sampler::ArgumentModifier secondModifier);
		void setThirdModifier(int stage, Sampler::ArgumentModifier thirdModifier);
		void setDestinationArgument(int stage, Sampler::DestinationArgument destinationArgument);
		void setTextureFilter(int sampler, Sampler::FilterType textureFilter);
		void setAddressingMode(int sampler, Sampler::AddressingMode addressingMode);

		void setDepthCompare(DepthCompareMode depthCompareMode);
		void setAlphaCompare(AlphaCompareMode alphaCompareMode);
		void setDepthWriteEnable(bool depthWriteEnable);
		void setAlphaTestEnable(bool alphaTestEnable);
		void setCullMode(CullMode cullMode);

		void setAlphaBlendEnable(bool alphaBlendEnable);
		void setSourceBlendFactor(BlendFactor sourceBlendFactor);
		void setDestBlendFactor(BlendFactor destBlendFactor);

		void setAlphaReference(int alphaReference);

		// Lighting pipeline
		void setLightEnable(int light, bool lightEnable);
		void setShadingMode(ShadingMode shadingMode);
		void setSpecularEnable(int light, bool specularEnable);

		void setAmbientLight(const Color<float> &ambientLight);
		void setLightPosition(int light, const Point &lightPosition);
		void setLightColor(int light, const Color<float> &lightColor);
		void setLightAttenuation(int light, float constant, float linear, float quadratic);
		void setLightRange(int light, float range);

		void setMaterialEmission(const Color<float> &emission);
		void setMaterialAmbient(const Color<float> &materialAmbient);
		void setMaterialDiffuse(const Color<float> &diffuseColor);
		void setMaterialSpecular(const Color<float> &specularColor);
		void setMaterialShininess(float specularPowerR, float specularPowerG, float specularPowerB, float specularPowerA);

		// Programmable pipelines
		void setPixelShaderConstantF(int index, const float value[4], int count = 1);

		void setPixelShaderConstant(int index, const Matrix &M);
		void setPixelShaderConstant(int index, const Vector &vector);
		void setPixelShaderConstant(int index, const Point &point);

		void setVertexShaderConstantF(int index, const float value[4], int count = 1);
		void setVertexShaderConstantI(int index, const int value[4], int count = 1);
		void setVertexShaderConstantB(int index, const bool *boolean, int count = 1);

		void setVertexShaderConstantF(int index, const Matrix &M);
		void setVertexShaderConstantF(int index, const Vector &vector);
		void setVertexShaderConstantF(int index, const Point &point);

		// Clipper
		void setFOV(float FOV);
		void setNearClip(float nearClip);
		void setFarClip(float farClip);

		void setClipFlags(int flags);
		void setClipPlane(int index, const float plane[4]);
		const float *getClipPlane(int index);

		// Partial transform
		void setModelMatrix(const Matrix &M);
		void setViewMatrix(const Matrix &V);
		void setBaseMatrix(const Matrix &B);

		// Full transform
		const Matrix &getModelTransform();
		const Matrix &getViewTransform();

	private:
		void updateClipper();

		int batchSize;
		XVertex *triangleBatch;

		Clipper *clipper;
		Viewport *viewport;

		bool updateViewMatrix;
		bool updateBaseMatrix;
		bool updateProjectionMatrix;

		// User-defined clipping planes
		float plane[6][4];

		bool updateVertexShader;
		bool updateClipPlanes;
	};
}

#endif   // Renderer_hpp