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


		#include "core/shader_tree_compiler_isl.h"
		#include "log/log.h"

		using namespace GS;
		using namespace GS::Core;


//------------------------------------------------------------------------------
#define		__MapCompilerGetNewCompiledBlock(__COMPILED_VAR__)\
	CShaderBlock *__COMPILED_VAR__ = GetNewCompiledBlock(block);\
	if	(!__COMPILED_VAR__)	return NULL;

#define		__MapCompilerCompileInput(__COMPILED_VAR__, __INPUT_INDEX__)\
	CShaderBlock *__COMPILED_VAR__ = CompileShaderBlock(block->GetInput(__INPUT_INDEX__));\
	if	(!__COMPILED_VAR__)	return NULL;
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
bool				ISLShaderTreeCompiler::GetTypeDeclaration(ShaderInput::DataType data_type, String &declaration)
{
	switch (data_type)
	{
		case ShaderInput::Float:	declaration = "float";	return true;
		case ShaderInput::Vector2:	declaration = "vec2";	return true;
		case ShaderInput::Vector3:	declaration = "vec3";	return true;
		case ShaderInput::Vector4:	declaration = "vec4";	return true;
		case ShaderInput::Matrix3:	declaration = "mat3";	return true;
		case ShaderInput::Matrix4:	declaration = "mat4";	return true;

		case ShaderInput::DataTexture2D:		declaration = "sampler2D";			return true;
		case ShaderInput::DataTextureShadow:	declaration = "sampler2DShadow";	return true;
	}
	return false;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileConstantShaderBlock(const ConstantShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "const");
	if	(ShaderInput *parm = shader->DeclareInput(compiled_block->variable, block->constant_type, ShaderInput::Constant, ShaderInput::Uniform, scope))
		parm->parm_v.Set(block->constant[0], block->constant[1], block->constant[2], block->constant[3]);

	compiled_block->output = block->constant_type;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileColorShaderBlock(const ColorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "color");
	if	(ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Constant, ShaderInput::Uniform, scope))
		parm->parm_v = block->color;

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileClockShaderBlock(const ClockShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "clock");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::Clock, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileViewVectorShaderBlock(const ViewVectorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "view_vector");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Vector3, ShaderInput::ViewVector, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Vector3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileViewportShaderBlock(const ViewportShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "viewport");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Viewport, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileNormalViewMatrixShaderBlock(const NormalViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "normal_view_matrix");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalViewMatrix, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Matrix3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileNormalMatrixShaderBlock(const NormalMatrixShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "normal_matrix");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix3, ShaderInput::NormalMatrix, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Matrix3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileModelViewMatrixShaderBlock(const ModelViewMatrixShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "model_view_matrix");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelViewMatrix, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Matrix4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileModelMatrixShaderBlock(const ModelMatrixShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "model_matrix");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Matrix4, ShaderInput::ModelMatrix, ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::Matrix4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileMaterialParamShaderBlock(const MaterialParamShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "mat_param");
	switch (block->param)
	{
		case MaterialParamShaderBlock::MaterialDiffuse:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialDiffuse, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Vector4;
			break;
		case MaterialParamShaderBlock::MaterialSpecular:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSpecular, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Vector4;
			break;
		case MaterialParamShaderBlock::MaterialSelf:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSelf, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Vector4;
			break;
		case MaterialParamShaderBlock::MaterialAmbient:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialAmbient, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Vector4;
			break;
		case MaterialParamShaderBlock::MaterialGlossiness:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialGlossiness, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Float;
			break;
		case MaterialParamShaderBlock::MaterialOpacity:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialOpacity, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Float;
			break;
		case MaterialParamShaderBlock::MaterialReflection:
			shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialReflection, ShaderInput::Uniform, scope);
			compiled_block->output = ShaderInput::Float;
			break;
	}
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileMaterialTextureShaderBlock(const MaterialTextureShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "mat_tex");
	shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::Semantic(ShaderInput::MaterialTexture0 + block->slot), ShaderInput::Uniform, scope);

	compiled_block->output = ShaderInput::DataTexture2D;
	return compiled_block;
}
//------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometrySkinningShaderBlock(const GeometrySkinningShaderBlock *block, ShaderInput::Scope scope)
//----------------------------------------------------------------------------------------------------------------------------------------------------
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "skin_mtx");

	shader->DeclareInput("bone_mtx", ShaderInput::Matrix4, ShaderInput::BoneMatrix, ShaderInput::Uniform, ShaderInput::Vertex, __PL_BONE_LIMIT__);
	shader->DeclareInput("bone_idx", ShaderInput::Vector4, ShaderInput::BoneIndex, ShaderInput::Attribute, ShaderInput::Vertex);
	shader->DeclareInput("bone_w", ShaderInput::Vector4, ShaderInput::BoneWeight, ShaderInput::Attribute, ShaderInput::Vertex);

	shader->DeclareVarying(compiled_block->variable, "mat4");
	vertex_source += String::Format("%s = bone_mtx[int(bone_idx.x)] * bone_w.x + bone_mtx[int(bone_idx.y)] * bone_w.y + bone_mtx[int(bone_idx.z)] * bone_w.z + bone_mtx[int(bone_idx.w)] * bone_w.w;\n", compiled_block->variable.c_str());

	compiled_block->output = ShaderInput::Matrix4;
	return compiled_block;
}

//------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometryTangentFrameShaderBlock(const GeometryTangentFrameShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	/*
		Request the geometry normal.
		Note: If an equivalent block already exists in the map it will be used
			  instead of the newly created one.
	*/
	ShaderBlock *normal_block = new GeometryNormalShaderBlock;
	CShaderBlock *gl_normal_block = CompileShaderBlock(normal_block);
	_safe_delete(normal_block);

	// Compile the tangent frame generation code.
	GetNewVariable(compiled_block->variable, "tangent_frame");

	ShaderInput *a_tangent = shader->DeclareInput("a_tangent", ShaderInput::Vector3, ShaderInput::Tangent, ShaderInput::Attribute, ShaderInput::Vertex),
				 *a_bitangent = shader->DeclareInput("a_bitangent", ShaderInput::Vector3, ShaderInput::Bitangent, ShaderInput::Attribute, ShaderInput::Vertex);

	shader->DeclareVarying("_T", "vec3");
	shader->DeclareVarying("_B", "vec3");
	vertex_source += String::Format("_T = %s;\n _B = %s;\n", a_tangent->name.c_str(), a_bitangent->name.c_str());

	pixel_source += String::Format("mat3 %s = _build_mat3(normalize(_T), normalize(_B), %s);\n", compiled_block->variable.c_str(), gl_normal_block->variable.c_str());

	compiled_block->output = ShaderInput::Matrix3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometryVertexShaderBlock(const GeometryVertexShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "vertex");
	ShaderInput *pos_parm = shader->DeclareInput("a_position", ShaderInput::Vector3, ShaderInput::Position, ShaderInput::Attribute, ShaderInput::Vertex);

	shader->DeclareVarying(compiled_block->variable, "vec4");
	vertex_source += String::Format("%s = vec4(%s, 1.0);\n", compiled_block->variable.c_str(), pos_parm->name.c_str());

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometryNormalShaderBlock(const GeometryNormalShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	String varying;
	GetNewVariable(varying, "varying_normal");
	GetNewVariable(compiled_block->variable, "normal");
	ShaderInput *nrm_parm = shader->DeclareInput("a_normal", ShaderInput::Vector3, ShaderInput::Normal, ShaderInput::Attribute, ShaderInput::Vertex);
	shader->DeclareVarying(varying, "vec3");
	vertex_source += String::Format("%s = %s;\n", varying.c_str(), nrm_parm->name.c_str());
	pixel_source += String::Format("vec3 %s = normalize(%s);\n", compiled_block->variable.c_str(), varying.c_str());

	compiled_block->output = ShaderInput::Vector3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometryVertexColorShaderBlock(const GeometryVertexColorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "vertex_color");
	ShaderInput *rgb_parm = shader->DeclareInput("a_rgb", ShaderInput::Vector4, ShaderInput::VertexColor, ShaderInput::Attribute, ShaderInput::Vertex);
	shader->DeclareVarying(compiled_block->variable, "vec4");
	vertex_source += String::Format("%s = %s;\n", compiled_block->variable.c_str(), rgb_parm->name.c_str());

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileGeometryUVShaderBlock(const GeometryUVShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "uv");
	ShaderInput *uv_parm = shader->DeclareInput(String::Format("a_uv%d", block->channel), ShaderInput::Vector2, ShaderInput::Semantic(ShaderInput::UV0 + block->channel), ShaderInput::Attribute, ShaderInput::Vertex);
	shader->DeclareVarying(compiled_block->variable, "vec2");
	vertex_source += String::Format("%s = %s;\n", compiled_block->variable.c_str(), uv_parm->name.c_str());

	compiled_block->output = ShaderInput::Vector2;
	return compiled_block;
}
//------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileRenderBufferShaderBlock(const RenderBufferShaderBlock *block, ShaderInput::Scope scope)
//--------------------------------------------------------------------------------------------------------------------------------------------
{
/*
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "render_buffer");
	fragment_declaration += String::Format("uniform sampler2D %s;\n", compiled_block->variable.c_str());
	compiled_block->output = ShaderBlock::RenderPinTexture;
	return compiled_block;
*/
	return NULL;
}

//------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileTextureShaderBlock(const TextureShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "texture");

	switch (block->texture_type)
	{
		default:
		case TextureShaderBlock::Texture2D:
			if	(ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTexture2D, ShaderInput::Texture2D, ShaderInput::Uniform, ShaderInput::Pixel))
				parm->parm_t = block->texture;
			compiled_block->output = ShaderInput::DataTexture2D;
			break;

		case TextureShaderBlock::Texture3D:
			if	(ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTexture3D, ShaderInput::Texture3D, ShaderInput::Uniform, ShaderInput::Pixel))
				parm->parm_t = block->texture;
			compiled_block->output = ShaderInput::DataTexture3D;
			break;

		case TextureShaderBlock::TextureCube:
			if	(ShaderInput *parm = shader->DeclareInput(compiled_block->variable, ShaderInput::DataTextureCube, ShaderInput::TextureCube, ShaderInput::Uniform, ShaderInput::Pixel))
				parm->parm_t = block->texture;
			compiled_block->output = ShaderInput::DataTextureCube;
			break;
	}
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileTextureSamplerShaderBlock(const TextureSamplerShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(texture_block, 0)
	__MapCompilerCompileInput(uv_block, 1)

	if	(
		!(	((texture_block->output == ShaderInput::DataTexture2D) && (uv_block->output == ShaderInput::Vector2)) ||
			((texture_block->output == ShaderInput::DataTexture3D) && (uv_block->output == ShaderInput::Vector3)) ||
			((texture_block->output == ShaderInput::DataTextureCube) && (uv_block->output == ShaderInput::Vector3))	)
		)
		__ERR__(__LOG_E__ << "Invalid input to the texture sampler block.\n", NULL)

	GetNewVariable(compiled_block->variable, "texel");

	switch (block->sampler_type)
	{
		default:
		case TextureSamplerShaderBlock::Sampler2D:
			pixel_source += String::Format("vec4 %s = texture2D(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
			break;
		case TextureSamplerShaderBlock::Sampler3D:
			pixel_source += String::Format("vec4 %s = texture3D(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
			break;
		case TextureSamplerShaderBlock::SamplerCube:
			pixel_source += String::Format("vec4 %s = textureCube(%s, %s);\n", compiled_block->variable.c_str(), texture_block->variable.c_str(), uv_block->variable.c_str());
			break;
	}

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileMixShaderBlock(const MixOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)
	__MapCompilerCompileInput(mix_block, 2)

	if	(left_block->output != right_block->output)
		__ERR__(__LOG_E__ << "Cannot mix blocks, output do not match.\n", NULL)

	switch (left_block->output)
	{
		case ShaderInput::NoData:
			__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
		case ShaderInput::Matrix3:
		case ShaderInput::Matrix4:
		case ShaderInput::DataTexture2D:
			__ERR__(__LOG_E__ << "Cannot mix blocks, incorrect type (" << left_block->output << ").\n", NULL)

		default:
			break;
	}

	GetNewVariable(compiled_block->variable, "mix");
	String	type;
	GetTypeDeclaration(left_block->output, type);
	pixel_source += String::Format("%s %s = mix(%s, %s, %s);\n", type.c_str(), compiled_block->variable.c_str(), right_block->variable.c_str(), left_block->variable.c_str(), mix_block->variable.c_str());
	compiled_block->output = left_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileAddShaderBlock(const AddOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	if	(left_block->output != right_block->output)
		__ERR__(__LOG_E__ << "Cannot add blocks, output do not match.\n", NULL)

	switch (left_block->output)
	{
		case ShaderInput::NoData:
			__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
		case ShaderInput::Matrix3:
		case ShaderInput::Matrix4:
		case ShaderInput::DataTexture2D:
			__ERR__(__LOG_E__ << "Cannot add blocks (" << left_block->output << ").\n", NULL)

		default:
			break;
	}

	GetNewVariable(compiled_block->variable, "add");
	String	type;
	GetTypeDeclaration(left_block->output, type);
	pixel_source += String::Format("%s %s = %s + %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
	compiled_block->output = left_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileSubShaderBlock(const SubOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	if	(left_block->output != right_block->output)
		__ERR__(__LOG_E__ << "Cannot subtract blocks, output do not match.\n", NULL)

	switch (left_block->output)
	{
		case ShaderInput::NoData:
			__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
		case ShaderInput::Matrix3:
		case ShaderInput::Matrix4:
		case ShaderInput::DataTexture2D:
			__ERR__(__LOG_E__ << "Cannot subtract blocks (" << left_block->output << ").\n", NULL)

		default:
			break;
	}

	GetNewVariable(compiled_block->variable, "sub");
	String	type;
	GetTypeDeclaration(left_block->output, type);
	pixel_source += String::Format("%s %s = %s - %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
	compiled_block->output = left_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileMulShaderBlock(const MulOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	// Check type compatibility.
	ShaderInput::DataType left_type = left_block->output, right_type = right_block->output;

	if	(left_type > right_type)
	{	ShaderInput::DataType tmp; tmp = left_type; left_type = right_type; right_type = tmp;	}

	if	(
			!(
				(left_type == right_type) ||
				((left_type == ShaderInput::Vector3) && (right_type == ShaderInput::Matrix3)) ||
				((left_type == ShaderInput::Vector4) && (right_type == ShaderInput::Matrix4))
			)
		)
		__ERR__(__LOG_E__ << "Cannot multiply blocks, output do not match.\n", NULL)

	// Check type validity.
	if	(left_type == right_type)
		switch (left_block->output)
		{
			case ShaderInput::NoData:
				__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
			case ShaderInput::DataTexture2D:
				__ERR__(__LOG_E__ << "Cannot multiply textures.\n", NULL)
		}

	// Compile operator.
	GetNewVariable(compiled_block->variable, "mul");
	String	type;
	GetTypeDeclaration(left_type, type);

	switch (right_type)
	{
		// n_mtx_mul
		case ShaderInput::Matrix3:
		case ShaderInput::Matrix4:
			pixel_source += String::Format("%s %s = n_mtx_mul(%s, %s);\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			break;

		default:
			pixel_source += String::Format("%s %s = %s * %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			break;
	}

	compiled_block->output = left_type;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileDivShaderBlock(const DivOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	if	(left_block->output != right_block->output)
		__ERR__(__LOG_E__ << "Cannot divide blocks, output do not match.\n", NULL)

	switch (left_block->output)
	{
		case	ShaderInput::NoData:
			__ERR__(__LOG_E__ << "Block has no output.\n", NULL)
		case	ShaderInput::Matrix3:
		case	ShaderInput::Matrix4:
		case	ShaderInput::DataTexture2D:
			__ERR__(__LOG_E__ << "Cannot divide blocks (" << left_block->output << ").\n", NULL)
	}

	GetNewVariable(compiled_block->variable, "div");
	String	type;
	GetTypeDeclaration(left_block->output, type);
	pixel_source += String::Format("%s %s = %s / %s;\n", type.c_str(), compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
	compiled_block->output = left_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileDotShaderBlock(const DotOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	if	(left_block->output != right_block->output)
		__ERR__(__LOG_E__ << "Cannot compute dot operator, output do not match.\n", NULL)

	GetNewVariable(compiled_block->variable, "dot");
	pixel_source += String::Format("float %s = dot(%s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileCrossShaderBlock(const CrossOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(left_block, 0)
	__MapCompilerCompileInput(right_block, 1)

	if	((left_block->output != right_block->output) && (left_block->output != ShaderInput::Vector3))
		__ERR__(__LOG_E__ << "Cannot only compute cross product on Vector3.\n", NULL)

	GetNewVariable(compiled_block->variable, "cross");
	pixel_source += String::Format("vec3 %s = cross(%s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
	compiled_block->output = ShaderInput::Vector3;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileClampShaderBlock(const ClampShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(value_block, 0)
	__MapCompilerCompileInput(min_block, 1)
	__MapCompilerCompileInput(max_block, 2)

	if	((min_block->output != max_block->output) && (value_block->output != min_block->output))
		__ERR__(__LOG_E__ << ".\n", NULL)

	GetNewVariable(compiled_block->variable, "clamp");
	String	type;
	GetTypeDeclaration(value_block->output, type);
	pixel_source += String::Format("%s %s = clamp(%s, %s, %s);\n", type.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), min_block->variable.c_str(), max_block->variable.c_str());
	compiled_block->output = value_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileSwizzleShaderBlock(const SwizzleShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	// Set block output.
	if	((compiled_block->output = (ShaderInput::DataType)block->GetOutputType()) == ShaderInput::NoData)
		__ERR__(__LOG_E__ << "Invalid swizzle, no output.\n", NULL)

	String	output_type;
	GetTypeDeclaration(compiled_block->output, output_type);

	// Build fragment shader swizzle.
	GetNewVariable(compiled_block->variable, "swizzle");

	if	(input_block->output == ShaderInput::Float)
			pixel_source += String::Format("%s %s = %s(", output_type.c_str(), compiled_block->variable.c_str(), output_type.c_str());
	else	pixel_source += String::Format("%s %s = %s.", output_type.c_str(), compiled_block->variable.c_str(), input_block->variable.c_str());

	switch (input_block->output)
	{
		case ShaderInput::Float:
			for (int n = 0; (n < 4) && (block->swizzle[n] != SwizzleShaderBlock::SwizzleNone); ++n)
			{
				if	(block->swizzle[n] != SwizzleShaderBlock::SwizzleX)
					__ERR__(__LOG_E__ << "Impossible swizzle.\n", NULL)

				pixel_source +=	((n == 3) || (block->swizzle[n + 1] == SwizzleShaderBlock::SwizzleNone)) ?
									String::Format("%s)", input_block->variable.c_str()) :
									String::Format("%s,", input_block->variable.c_str());
			}
			break;

		case ShaderInput::Vector2:
			for (int n = 0; n < 4; ++n)
				switch	(block->swizzle[n])
				{
					case SwizzleShaderBlock::SwizzleX:	pixel_source += "x";	break;
					case SwizzleShaderBlock::SwizzleY:	pixel_source += "y";	break;
					case SwizzleShaderBlock::SwizzleNone: break;
					default:	__ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
				}
			break;

		case ShaderInput::Vector3:
			for (int n = 0; n < 4; ++n)
				switch	(block->swizzle[n])
				{
					case SwizzleShaderBlock::SwizzleX:	pixel_source += "x";	break;
					case SwizzleShaderBlock::SwizzleY:	pixel_source += "y";	break;
					case SwizzleShaderBlock::SwizzleZ:	pixel_source += "z";	break;
					case SwizzleShaderBlock::SwizzleNone: break;
					default:	__ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
				}
			break;

		case ShaderInput::Vector4:
			for (int n = 0; n < 4; ++n)
				switch	(block->swizzle[n])
				{
					case SwizzleShaderBlock::SwizzleX:	pixel_source += "x";	break;
					case SwizzleShaderBlock::SwizzleY:	pixel_source += "y";	break;
					case SwizzleShaderBlock::SwizzleZ:	pixel_source += "z";	break;
					case SwizzleShaderBlock::SwizzleW:	pixel_source += "w";	break;
					case SwizzleShaderBlock::SwizzleNone: break;
					default:	__ERR__(__LOG_E__ << "Invalid component to swizzle.\n", NULL)
				}
			break;
	}

	pixel_source += ";\n";
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileBuildShaderBlock(const BuildShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	String component[4];
	int count = 0;

	for (int n = 0; n < 4; ++n)
	{
		switch (block->build[n])
		{
			case BuildShaderBlock::BuildZero:
				component[count++] = "0.0";
				break;
			case BuildShaderBlock::BuildOne:
				component[count++] = "1.0";
				break;

			case BuildShaderBlock::BuildX:
			case BuildShaderBlock::BuildY:
			case BuildShaderBlock::BuildZ:
			case BuildShaderBlock::BuildW:
				if	(!block->input[n])
					n = 4;
				else
				{
					__MapCompilerCompileInput(input, n)

					if	(input->output == ShaderInput::Float)
						component[count++] = input->variable.c_str();
					else
						switch (block->build[n])
						{
							case BuildShaderBlock::BuildX:	component[count++] = String::Format("%s.x", input->variable.c_str());	break;
							case BuildShaderBlock::BuildY:	component[count++] = String::Format("%s.y", input->variable.c_str());	break;
							case BuildShaderBlock::BuildZ:	component[count++] = String::Format("%s.z", input->variable.c_str());	break;
							case BuildShaderBlock::BuildW:	component[count++] = String::Format("%s.w", input->variable.c_str());	break;
						}
				}
				break;
		}
	}

	if	(!count)
		compiled_block->output = ShaderInput::NoData;
	else
	{
		GetNewVariable(compiled_block->variable, "built");

		switch (count)
		{
			case 1:
				pixel_source += String::Format("float %s = %s;\n", compiled_block->variable.c_str(), component[0].c_str());
				compiled_block->output = ShaderInput::Float;
				break;
			case 2:
				pixel_source += String::Format("vec2 %s = vec2(%s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str());
				compiled_block->output = ShaderInput::Vector2;
				break;
			case 3:
				pixel_source += String::Format("vec3 %s = vec3(%s, %s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str(), component[2].c_str());
				compiled_block->output = ShaderInput::Vector3;
				break;
			case 4:
				pixel_source += String::Format("vec4 %s = vec4(%s, %s, %s, %s);\n", compiled_block->variable.c_str(), component[0].c_str(), component[1].c_str(), component[2].c_str(), component[3].c_str());
				compiled_block->output = ShaderInput::Vector4;
				break;
		}
	}
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompilePowShaderBlock(const PowShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(value_block, 0)
	__MapCompilerCompileInput(power_block, 1)

	if	(value_block->output != ShaderInput::Float)
		__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
	if	(power_block->output != ShaderInput::Float)
		__ERR__(__LOG_E__ << "Incompatible power type.\n", NULL)

	GetNewVariable(compiled_block->variable, "pow");
	pixel_source += String::Format("float %s = pow(%s, %s);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), power_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileAbsShaderBlock(const AbsShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(value_block, 0)

	switch (value_block->output)
	{
		case ShaderInput::Float:
		case ShaderInput::Vector2:
		case ShaderInput::Vector3:
		case ShaderInput::Vector4:
			break;
		default:
			__ERR__(__LOG_E__ << "Incompatible value type.\n", NULL)
	}

	GetNewVariable(compiled_block->variable, "abs");

	switch (value_block->output)
	{
		case ShaderInput::Float:	pixel_source += String::Format("float %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());			break;
		case ShaderInput::Vector2:	pixel_source += String::Format("vec2 %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());			break;
		case ShaderInput::Vector3:	pixel_source += String::Format("vec3 %s = abs(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());			break;
		case ShaderInput::Vector4:	pixel_source += String::Format("vec4 %s = abs(%s.xyz, 1.0);\n", compiled_block->variable.c_str(), value_block->variable.c_str());	break;
	}
	compiled_block->output = value_block->output;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileCosinusShaderBlock(const CosinusShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(value_block, 0)

	if	(value_block->output != ShaderInput::Float)
		__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)

	GetNewVariable(compiled_block->variable, "cos");
	pixel_source += String::Format("float %s = cos(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileSinusShaderBlock(const SinusShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(value_block, 0)

	if	(value_block->output != ShaderInput::Float)
		__ERR__(__LOG_E__ << "Incompatible source type.\n", NULL)

	GetNewVariable(compiled_block->variable, "sin");
	pixel_source += String::Format("float %s = sin(%s);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*ISLShaderTreeCompiler::CompileNormalizeBlock(const NormalizeOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	GetNewVariable(compiled_block->variable, "normalized");
	String	type;
	GetTypeDeclaration(input_block->output, type);
	pixel_source += String::Format("%s %s = normalize(%s);\n", type.c_str(), compiled_block->variable.c_str(), input_block->variable.c_str());

	compiled_block->output = input_block->output;
	return compiled_block;
}
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileScreenUVShaderBlock(const ScreenUVShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------------------------
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

	GetNewVariable(compiled_block->variable, "screen_uv");
	pixel_source += String::Format("vec2 %s = gl_FragCoord.xy;\n", compiled_block->variable.c_str());
	compiled_block->output = ShaderInput::Vector2;
	return compiled_block;
}

//-------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompilePackVectorToColor(const PackVectorToColorShaderBlock *block, ShaderInput::Scope scope)
//-------------------------------------------------------------------------------------------------------------------------------------------
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	GetNewVariable(compiled_block->variable, "packed_vector");

	switch (input_block->output)
	{
		case ShaderInput::Float:
			pixel_source += String::Format("float %s = (%s + 1.0) * 0.5;\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;
		case ShaderInput::Vector3:
			pixel_source += String::Format("vec3 %s = (%s + vec3(1.0, 1.0, 1.0)) * vec3(0.5, 0.5, 0.5);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;
		case ShaderInput::Vector4:
			pixel_source += String::Format("vec4 %s = (%s + vec4(1.0, 1.0, 1.0, 0.0)) * vec3(0.5, 0.5, 0.5, 1.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;

		default:
			__ERR__(__LOG_E__ << "Invalid input to pack to vector.\n", NULL)
	}
	compiled_block->output = input_block->output;
	return compiled_block;
}

//-----------------------------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*ISLShaderTreeCompiler::CompileUnpackColorToVector(const UnpackColorToVectorShaderBlock *block, ShaderInput::Scope scope)
//-----------------------------------------------------------------------------------------------------------------------------------------------
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	GetNewVariable(compiled_block->variable, "unpacked_vector");

	switch (input_block->output)
	{
		case ShaderInput::Float:
			pixel_source += String::Format("float %s = (%s - 0.5) * 2.0;\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;
		case ShaderInput::Vector3:
			pixel_source += String::Format("vec3 %s = (%s - vec3(0.5, 0.5, 0.5)) * vec3(2.0, 2.0, 2.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;
		case ShaderInput::Vector4:
			pixel_source += String::Format("vec4 %s = (%s - vec4(0.5, 0.5, 0.5, 0.0)) * vec4(2.0, 2.0, 2.0, 1.0);\n", compiled_block->variable.c_str(), input_block->variable.c_str());
			break;

		default:
			__ERR__(__LOG_E__ << "Invalid input to unpack to vector.\n", NULL)
	}
	compiled_block->output = input_block->output;
	return compiled_block;
}

//------------------------------------------------------------------------------
Shader				*ISLShaderTreeCompiler::Finish()
{
	__LOG__ << "Done compiling shader tree '" << id << "'.\n";
	return shader;
}
//------------------------------------------------------------------------------
