/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__SHADER_TREE_COMPILER__
#define	__SHADER_TREE_COMPILER__


		#include "core/shader.h"
		#include "core/shader_block.h"


namespace GS {
	namespace Core {

/// Compiled shader block.
struct	CShaderBlock
{
		String		variable;
		const ShaderBlock *block;
		ShaderInput::DataType output;

		CShaderBlock(const ShaderBlock *render_block) : block(render_block), output(ShaderInput::NoData)
		{
			block = render_block;
			output = ShaderInput::NoData;
		}
};

/*!
	@short	Shader tree compiler.
	Compile a shader tree to a shader.
	@author	Emmanuel Julien (ejulien@gsworks.fr)
*/
class	ShaderTreeCompiler
{
/*!
	@name	Specialized interface.
	@{
*/
protected:

virtual	CShaderBlock	*CompileConstantShaderBlock(const ConstantShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileColorShaderBlock(const ColorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileMaterialParamShaderBlock(const MaterialParamShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileMaterialTextureShaderBlock(const MaterialTextureShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileGeometryVertexShaderBlock(const GeometryVertexShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileGeometryUVShaderBlock(const GeometryUVShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileGeometryNormalShaderBlock(const GeometryNormalShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileGeometrySkinningShaderBlock(const GeometrySkinningShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileGeometryVertexColorShaderBlock(const GeometryVertexColorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileGeometryTangentFrameShaderBlock(const GeometryTangentFrameShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileRenderBufferShaderBlock(const RenderBufferShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileTextureShaderBlock(const TextureShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileTextureSamplerShaderBlock(const TextureSamplerShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileMixShaderBlock(const MixOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileAddShaderBlock(const AddOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileSubShaderBlock(const SubOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileMulShaderBlock(const MulOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileDivShaderBlock(const DivOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileDotShaderBlock(const DotOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileCrossShaderBlock(const CrossOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileClampShaderBlock(const ClampShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileNormalizeBlock(const NormalizeOperatorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileSwizzleShaderBlock(const SwizzleShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileBuildShaderBlock(const BuildShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileCosinusShaderBlock(const CosinusShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileSinusShaderBlock(const SinusShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompilePowShaderBlock(const PowShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileAbsShaderBlock(const AbsShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileUnpackColorToVector(const UnpackColorToVectorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompilePackVectorToColor(const PackVectorToColorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileClockShaderBlock(const ClockShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileScreenUVShaderBlock(const ScreenUVShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileViewVectorShaderBlock(const ViewVectorShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileViewportShaderBlock(const ViewportShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;

virtual	CShaderBlock	*CompileNormalViewMatrixShaderBlock(const NormalViewMatrixShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileNormalMatrixShaderBlock(const NormalMatrixShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileModelViewMatrixShaderBlock(const ModelViewMatrixShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
virtual	CShaderBlock	*CompileModelMatrixShaderBlock(const ModelMatrixShaderBlock *, ShaderInput::Scope = ShaderInput::Pixel) = 0;
/// @}

protected:

		String			id;

		uint			variable_count,
						texture_count;

		Shader			*shader;

		AutoList <ShaderBlock *> temporary_block_list;
		AutoList <CShaderBlock *> compiled_tree_block;

		bool			GetNewVariable(String &constant, const char *prefix = 0);
		CShaderBlock	*GetNewCompiledBlock(const ShaderBlock *);

		String			vertex_declaration,
						vertex_source,
						pixel_declaration,
						pixel_source;

public:

		/// Get current shader id.
		const String	&GetId() const							{	return id;	}

		/// Restart compiler. Derived implementations should call the base class first.
		void			RestartCompiler(Shader *);

		/// Compile a shader block.
		CShaderBlock	*CompileShaderBlock(const ShaderBlock *, const char *prefix = 0, ShaderInput::Scope = ShaderInput::Pixel);
		///	Compile a temporary block. Compiler takes ownership of the block.
		CShaderBlock	*CompileTemporary(ShaderBlock *, const char *prefix = 0, ShaderInput::Scope = ShaderInput::Pixel);

		/// Add a custom prefix to the shader name.
		void			AddPrefix(const char *);

		/// Add code to the vertex shader declaration.
		void			AddVertexDeclaration(const char *d)		{	vertex_declaration += d;	}
		/// Add code to the vertex shader.
		void			AddVertexShader(const char *d)			{	vertex_source += d;	}
		/// Add code to the fragment shader declaration.
		void			AddPixelDeclaration(const char *d)		{	pixel_declaration += d;	}
		/// Add code to the fragment shader.
		void			AddPixelShader(const char *d)			{	pixel_source += d;	}

		/// Get vertex program.
		const String	&GetVertexSource() const				{	return vertex_source;	}
		/// Get fragment program.
		const String	&GetPixelSource() const					{	return pixel_source;	}

		/// Complete a compilation, retrieve the shader.
virtual	Shader			*Finish() = 0;

		/// Free all compiler stats.
		void			Free();

		ShaderTreeCompiler();
virtual	~ShaderTreeCompiler();
};

	} //Core
} // GS


#endif	// __SHADER_TREE_COMPILER__
