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


		#include "core/shader_tree_compiler_tinyc.h"
		#include "core/graphic_resource_factory.h"
		#include "core/material.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				TinyCShaderTreeCompiler::GetTypeDeclaration(ShaderInput::DataType type, String &declaration)
//---------------------------------------------------------------------------------------------------------------------
{
	switch	(type)
	{
	case	ShaderInput::Float:		declaration = "struct nVector";		return true;
	case	ShaderInput::Vector2:	declaration = "struct nVector";		return true;
	case	ShaderInput::Vector3:	declaration = "struct nVector";		return true;
	case	ShaderInput::Vector4:	declaration = "struct nVector";		return true;
	case	ShaderInput::Matrix3:	declaration = "struct nMatrix3";		return true;
	case	ShaderInput::Matrix4:	declaration = "struct nMatrix4";		return true;
	case	ShaderInput::DataTexture2D:	declaration = "struct nTexture";	return true;

	default:
		break;
	}
	return false;
}

//------------------------------------------------------------------------------
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel))
		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		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel))
		parm->parm_v = block->color;

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Vector3;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Vector4;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Matrix3;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Matrix3;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Matrix4;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);

	compiled_block->output = ShaderInput::Matrix4;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Vector4;
		break;
	case	MaterialParamShaderBlock::MaterialSpecular:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSpecular, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Vector4;
		break;
	case	MaterialParamShaderBlock::MaterialSelf:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialSelf, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Vector4;
		break;
	case	MaterialParamShaderBlock::MaterialAmbient:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Vector4, ShaderInput::MaterialAmbient, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Vector4;
		break;
	case	MaterialParamShaderBlock::MaterialGlossiness:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialGlossiness, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Float;
		break;
	case	MaterialParamShaderBlock::MaterialOpacity:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialOpacity, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Float;
		break;
	case	MaterialParamShaderBlock::MaterialReflection:
		shader->DeclareInput(compiled_block->variable, ShaderInput::Float, ShaderInput::MaterialReflection, ShaderInput::Uniform, ShaderInput::Pixel);
		compiled_block->output = ShaderInput::Float;
		break;
	}
	return compiled_block;
}

//------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*TinyCShaderTreeCompiler::CompileMaterialTextureShaderBlock(const MaterialTextureShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

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

	pixel_declaration += String::Format("struct nTexture %s;\n", compiled_block->variable.c_str());

		pixel_source += String::Format("%s.TexPnt = (void *)texture_slot_%d;\n", compiled_block->variable.c_str(), block->slot);

	compiled_block->output = ShaderInput::DataTexture2D;
	return compiled_block;
}
//------------------------------------------------------------------------------------------------------------------------
CShaderBlock		*TinyCShaderTreeCompiler::CompileGeometrySkinningShaderBlock(const GeometrySkinningShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------------
{
	//__MapCompilerGetNewCompiledBlock(compiled_block)

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

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

	//vertex_declaration += String::Format("varying mat4 %s;\n", compiled_block->variable.c_str());
	//vertex_shader += String::Format("%s = (bone_mtx[int(bone_id.x)] * bone_w.x + bone_mtx[int(bone_id.y)] * bone_w.y + bone_mtx[int(bone_id.z)] * bone_w.z + bone_mtx[int(bone_id.w)] * bone_w.w) / (bone_w.x + bone_w.y + bone_w.z + bone_w.w);\n", compiled_block->variable.c_str());
	//fragment_declaration += String::Format("varying mat4 %s;\n", compiled_block->variable.c_str());

	//compiled_block->output = ShaderBlock::RenderShaderInput::Matrix4;
	//return compiled_block;
	return NULL;
}

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

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

	pixel_declaration += String::Format("struct nMatrix3 %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("TinyCGeometryTangentFrame(&%s, trace);\n", compiled_block->variable.c_str());

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

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

	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("TinyCGeometryVertex(&%s, trace);\n", compiled_block->variable.c_str());

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

		GetNewVariable(compiled_block->variable, "normal");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("TinyCGeometryNormal(&%s, trace);\n", compiled_block->variable.c_str());	

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

	GetNewVariable(compiled_block->variable, "vertex_color");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("TinyCGeometryVertexColor(&%s, trace);\n", compiled_block->variable.c_str());

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

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

	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("TinyCGeometryUV(&%s, trace, %d);\n", compiled_block->variable.c_str(), block->channel);	

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

/*
vec3	vector_offset = (%s.xyz - vec3(0.5, 0.5, 0.0)) * vec3(2.0, 2.0, 1.0);\n\

{
// Object space normal map.
pixel_program += "vec3 normal = gl_NormalMatrix * normalize(texture2D(normal_texture, normal_uv).xzy - vec3(0.5, 0.5, 0.5));\n";
}
*/

//----------------------------------------------------------------------------------------------------------------
CShaderBlock		*TinyCShaderTreeCompiler::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		*TinyCShaderTreeCompiler::CompileTextureShaderBlock(const TextureShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)

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

	pixel_declaration += String::Format("struct nTexture %s;\n", compiled_block->variable.c_str());

	if(((TextureShaderBlock *)block)->texture)
	//	fragment_shader += String::Format("%s.TexName = \"%s\";\n", compiled_block->variable.c_str(), ((nTextureShaderBlock *)block)->texture->name.CleanFilePath());	
		pixel_source += String::Format("%s.TexPnt = (void *)%d;\n", compiled_block->variable.c_str(), graphic_factory.LoadPicture(((TextureShaderBlock *)block)->texture.CleanFilePath()));
	else
		pixel_source += String::Format("%s.TexPnt = 0;\n", compiled_block->variable.c_str());	

	compiled_block->output = ShaderInput::DataTexture2D;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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)
		)
		__ERR__(__LOG_E__ << "Invalid input to the sampler2D block.\n", NULL)

		GetNewVariable(compiled_block->variable, "texel");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	pixel_source += String::Format("	nTexture_LowLevelSampling(&%s, &%s, %s.TexPnt, %d, %d);\n", compiled_block->variable.c_str(), uv_block->variable.c_str(), texture_block->variable.c_str(), /* block->wrap[0]?1:0 */ 0, /* block->wrap[1]?1:0 */ 0);

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

//------------------------------------------------------------------------------
CShaderBlock		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	pixel_source += String::Format("nReturnMix(%s, %s, %s, %s.x);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str(), mix_block->variable.c_str());
	compiled_block->output = left_block->output;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorAddVector(%s , %s, %s);\n", 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		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorMinusnVector(%s, %s, %s);\n", 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		*TinyCShaderTreeCompiler::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;	
		CShaderBlock* tmp_block; tmp_block = left_block; left_block = right_block; right_block = tmp_block;	
	}

	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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	if	(left_type == right_type)
	{
		switch	(left_type)
		{
		case	ShaderInput::Float:	
		case	ShaderInput::Vector3:	
		case	ShaderInput::Vector4:	
			pixel_source += String::Format("nReturnVectorMultiplyVector(%s, %s, %s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			break;
		case	ShaderInput::Matrix3:
			pixel_source += String::Format("nReturnnMatrix3MultiplynMatrix3(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			break;
		case	ShaderInput::Matrix4:	
			pixel_source += String::Format("nReturnnMatrix4MultiplynMatrix4(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			break;							
		default: 
			pixel_source += String::Format("nReturnVector(%s,1, 1, 1);\n", compiled_block->variable.c_str());
		}
	}
	else
	{
		if	(left_type == ShaderInput::Float ||
			left_type == ShaderInput::Vector3 ||
			left_type == ShaderInput::Vector4)
		{
			if	(right_type == ShaderInput::Matrix3)
				pixel_source += String::Format("nReturnnVectorMultiplynMatrix3(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			else	if	(right_type == ShaderInput::Matrix4)	
				pixel_source += String::Format("nReturnnVectorMultiplynMatrix4(&%s, &%s, &%s);\n", compiled_block->variable.c_str(), left_block->variable.c_str(), right_block->variable.c_str());
			else
			if	(right_type == ShaderInput::Vector3 ||
				left_type == ShaderInput::Vector4)
				pixel_source += String::Format("nReturnVectorMultiplyFloat(&%s, &%s, &%s.x);\n", compiled_block->variable.c_str(), right_block->variable.c_str(), left_block->variable.c_str());
			else
				pixel_source += String::Format("nReturnVector(%s, 1, 1, 1);\n", compiled_block->variable.c_str());
		}
		else		
			pixel_source += String::Format("nReturnVector(%s, 1, 1, 1);\n", compiled_block->variable.c_str());
	}

	compiled_block->output = left_type;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorDivnVector(%s, %s, %s);\n", 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		*TinyCShaderTreeCompiler::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_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorDotnVector(%s, %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		*TinyCShaderTreeCompiler::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_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorCrossnVector(%s, %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		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorClampMinMax(%s, %s, %s, %s);\n", 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		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	pixel_source += String::Format(" nReturnVector4(%s, ", compiled_block->variable.c_str());
	for (int n = 0; n < 4; ++n)
	{
		if	(block->swizzle[n] != SwizzleShaderBlock::SwizzleNone)
			switch(block->swizzle[n] - SwizzleShaderBlock::SwizzleX)
		{
			case 0:		//SwizzleX
				pixel_source += String::Format("%s.x", input_block->variable.c_str());
				break;
			case 1:		//SwizzleY
				pixel_source += String::Format("%s.y", input_block->variable.c_str());
				break;
			case 2:		//SwizzleZ
				pixel_source += String::Format("%s.z", input_block->variable.c_str());
				break;
			case 3:		//SwizzleW
				pixel_source += String::Format("%s.w", input_block->variable.c_str());
				break;
			default:	//SwizzleNone
				pixel_source += String::Format("0");
		}
		else  //SwizzleNone
			pixel_source += String::Format("0");

		// check to put the , or the )
		if(n<3)
			pixel_source += String::Format(",");
		else
			pixel_source += String::Format(");");
	}
	pixel_source += "\n";
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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++] = String::Format("%s.x", 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");
		pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
		pixel_source += String::Format("nReturnVector4(%s, ", compiled_block->variable.c_str());

		switch	(count)
		{
		case	1:
			pixel_source += String::Format("%s, 0, 0, 1);\n", component[0].c_str());
			compiled_block->output = ShaderInput::Float;
			break;
		case	2:
			pixel_source += String::Format("%s, %s, 0, 1);\n", component[0].c_str(), component[1].c_str());
			compiled_block->output = ShaderInput::Vector2;
			break;
		case	3:
			pixel_source += String::Format("%s, %s, %s, 1);\n", component[0].c_str(), component[1].c_str(), component[2].c_str());
			compiled_block->output = ShaderInput::Vector3;
			break;
		case	4:
			pixel_source += String::Format("%s, %s, %s, %s);\n", 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		*TinyCShaderTreeCompiler::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_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnPow(&%s.x, &%s.x, &%s.x);\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		*TinyCShaderTreeCompiler::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");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	switch (value_block->output)
	{
	case	ShaderInput::Float:	pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str());			break;
	case	ShaderInput::Vector2:	pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str());			break;
	case	ShaderInput::Vector3:	pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);nReturnFabs(&%s.z, &%s.z);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str());			break;
	case	ShaderInput::Vector4:	pixel_source += String::Format("nReturnFabs(&%s.x , &%s.x);nReturnFabs(&%s.y, &%s.y);nReturnFabs(&%s.z, &%s.z);nReturnFabs(&%s.w, &%s.w);\n", compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str(), compiled_block->variable.c_str(), value_block->variable.c_str());	break;
	}
	compiled_block->output = value_block->output;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnCosinus(&%s.x, &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::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_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnSinus(&%s.x, &%s.x);\n", compiled_block->variable.c_str(), value_block->variable.c_str());
	compiled_block->output = ShaderInput::Float;
	return compiled_block;
}
CShaderBlock		*TinyCShaderTreeCompiler::CompileNormalizeBlock(const NormalizeOperatorShaderBlock *block, ShaderInput::Scope scope)
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	GetNewVariable(compiled_block->variable, "normalized");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());
	pixel_source += String::Format("nReturnVectorNormalize(&%s, &%s);\n", compiled_block->variable.c_str(), input_block->variable.c_str());

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

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

	GetNewVariable(compiled_block->variable, "screen_uv");
	pixel_declaration += String::Format("struct nVector %s; nReturnVector4(%s, 0.5f,, 0.5f, 0.5f, 1.0f);\n", compiled_block->variable.c_str(), compiled_block->variable.c_str());

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

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

	GetNewVariable(compiled_block->variable, "packed_vector");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	switch	(input_block->output)
	{
	case	ShaderInput::Float:
	case	ShaderInput::Vector3:
	case	ShaderInput::Vector4:
		pixel_source += String::Format("TinyCPackVectorToColor(&%s, &%s);\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		*TinyCShaderTreeCompiler::CompileUnpackColorToVector(const UnpackColorToVectorShaderBlock *block, ShaderInput::Scope scope)
//------------------------------------------------------------------------------------------------------------------
{
	__MapCompilerGetNewCompiledBlock(compiled_block)
	__MapCompilerCompileInput(input_block, 0)

	GetNewVariable(compiled_block->variable, "unpacked_vector");
	pixel_declaration += String::Format("struct nVector %s;\n", compiled_block->variable.c_str());

	switch	(input_block->output)
	{
	case	ShaderInput::Float:
	case	ShaderInput::Vector3:
	case	ShaderInput::Vector4:
		pixel_source += String::Format("TinyCUnpackColorToVector(&%s, &%s);\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;
}

//----------------------------------------------------------------------------
void				TinyCShaderTreeCompiler::SetShaderInputs( const Material &m)
{
	// declaration of the input
	ListForeachPtr(ShaderInput *, input, shader->input_list)
	{
		String			type_declaration;
		if	(GetTypeDeclaration(input->data_type, type_declaration))
		{
			switch	(input->type)
			{
			case	ShaderInput::Attribute:
				if	(input->scope & ShaderInput::Vertex)
					vertex_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
				if	(input->scope & ShaderInput::Pixel)
					pixel_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
				break;

			case	ShaderInput::Uniform:
				if	(input->scope & ShaderInput::Vertex)
					vertex_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
				if	(input->scope & ShaderInput::Pixel)
					pixel_declaration += String::Format("%s %s;\n", type_declaration.c_str(), input->name.c_str());
				break;
			}
		}
		else
			__LOG_E__ << "Unsupported input '" << input->name << "' type (" << input->type << ").\n";
	}

	// fill the base input
	ListForeachPtr(ShaderInput *, input, shader->input_list)
	{
		switch (input->semantic)
		{
		case	ShaderInput::NormalMatrix:
			pixel_declaration += String::Format("TinyCNormalMatrix(&%s, trace);\n", input->name.c_str());
			break;

		case	ShaderInput::NormalViewMatrix:
			pixel_declaration += String::Format("TinyCNormalViewMatrix(&%s, trace);\n", input->name.c_str());			
			break;

		case	ShaderInput::ModelMatrix:
			pixel_declaration += String::Format("TinyCModelMatrix(&%s, trace);\n", input->name.c_str());		
				break;

		case	ShaderInput::ModelViewMatrix:
			pixel_declaration += String::Format("TinyCModelViewMatrix(&%s, trace);\n", input->name.c_str());		
			break;

		case	ShaderInput::ViewVector:
			pixel_declaration += String::Format("TinyCViewVector(&%s, trace);\n", input->name.c_str());		
			break;

		case	ShaderInput::Clock:
			pixel_declaration += String::Format("nReturnVector(%s, 0.0f, 0.0f, 0.0f);\n", input->name.c_str());		
			break;

	/*	case	ShaderInput::ModelViewProjectionMatrix:
			fragment_shader += String::Format("TinyCModelViewMatrix(&%s, trace);\n", input->name.c_str());	
			break;*/
		case	ShaderInput::Constant:		pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), input->parm_v.x, input->parm_v.y, input->parm_v.z, input->parm_v.w);		break;

		case	ShaderInput::MaterialDiffuse:		pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.diffuse.x, m.diffuse.y, m.diffuse.z, m.diffuse.w);		break;
		case	ShaderInput::MaterialSpecular:		pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.specular.x, m.specular.y, m.specular.z, m.specular.w);		break;
		case	ShaderInput::MaterialAmbient:		pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(),m.ambient.x, m.ambient.y, m.ambient.z, m.ambient.w);		break;
		case	ShaderInput::MaterialSelf:			pixel_declaration += String::Format("nReturnVector4(%s, %f, %f, %f, %f)\n", input->name.c_str(), m.self.x, m.self.y, m.self.z, m.self.w);		break;

		case	ShaderInput::MaterialOpacity:		pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), m.opacity);		break;
		case	ShaderInput::MaterialGlossiness:	pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), m.glossiness);		break;
		case	ShaderInput::MaterialReflection:	pixel_declaration += String::Format("nReturnVector4(%s, %f, 0, 0, 1)\n", input->name.c_str(), 0.2f/*m.reflection*/);		break;
		}
	}
}

//----------------------------------------------------------------------------

Shader				*TinyCShaderTreeCompiler::Finish()
{
	// Finish shader programs.
	shader->pixel.Clear();
	if	(!pixel_declaration.IsEmpty())
		shader->pixel += pixel_declaration;

	if	(!pixel_source.IsEmpty())
		shader->pixel += String::Format("%s \n}\n", pixel_source.c_str());
	else	shader->pixel += "struct nVector TempValue;\n nReturnVector(TempValue, 1, 1, 1);\n return TempValue;\n }\n";

	return shader;
}
//------------------------------------------------------------------------------
