/*
								+----------------------------------+
								|                                  |
								| *** ÜberLame material system *** |
								|                                  |
								|   Copyright © -tHE SWINe- 2007   |
								|                                  |
								|            Material.h            |
								|                                  |
								+----------------------------------+
*/

#pragma once
#ifndef __MATERIAL_SYSTEM_INCLUDED
#define __MATERIAL_SYSTEM_INCLUDED

/**
 *	@file dev/Material.h
 *	@date 2007
 *	@author -tHE SWINe-
 *	@brief ÜberLame material system
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64, added \#define for GL_GLEXT_LEGACY (for linux builds)
 *
 *	@date 2009-05-23
 *
 *	removed all instances of std::vector::reserve and replaced them by stl_ut::Reserve_*
 *
 *	@date 2009-10-20
 *
 *	fixed some warnings when compiling under VC 2005, implemented "Security
 *	Enhancements in the CRT" for VC 2008. compare against MyProjects_2009-10-19_
 *
 *	@date 2012-06-19
 *
 *	Moved multiple inclusion guard before file documentation comment.
 *
 */

#include "../Scanner.h"

/*
 *	MATERIAL_LEXER_TOKEN_DUMP
 *		- if defined, class CMaterialLexer::TToken has member
 *		  function Dump() which prints token contents to stdout
 */
#define MATERIAL_LEXER_TOKEN_DUMP

/*
 *	class CMaterialLexer
 *		- lexical analyzer of shader / material file language (css like)
 */
class CMaterialLexer {
public:
	/*
	 *	CMaterialLexer::<unnamed>
	 *		- token type values
	 */
	enum {
		token_White,
		token_Colon,
		token_Semicolon,
		token_LeftPar,
		token_RightPar,
		token_Begin,
		token_End, // it's important so operator tokens are in one piece
		token_Node,
		token_String,
		token_CData,
		token_Bool,
		token_Int,
		token_GLenum,
		token_Float,
		token_Pass,
		token_Texture1D,
		token_Texture2D,
		token_Texture3D,
		token_TextureCube, // it's important so texture tokens are in one piece
		token_URI,
		token_Reflect,
		token_Refract,
		token_Custom,
		token_DepthMap, // it's important so all other keyword tokens are in one piece
		token_EOF
	};

	/*
	 *	struct CMaterialLexer::TToken
	 *		- simple token structure for material file lexical analysis
	 */
	struct TToken {
	protected:
		int n_line, n_col;
		int n_type;
		union {
			int n_value;
			float f_value;
			char *p_s_value;
		} t_value;

	public:
		/*
		 *	CMaterialLexer::TToken::TToken()
		 *		- default constructor; sets line and column to 0 and type to token_EOF
		 */
		TToken();

		/*
		 *	CMaterialLexer::TToken::TToken(int _n_line, int _n_col, int _n_type)
		 *		- constructor for tokens with no data
		 *		- sets line to _n_line, column to _n_col and type to _n_type
		 */
		TToken(int _n_line, int _n_col, int _n_type);

		/*
		 *	CMaterialLexer::TToken::TToken(int _n_line, int _n_col, int _n_type, int n_value)
		 *		- constructor for tokens with integer data
		 *		- sets line to _n_line, column to _n_col and type to _n_type
		 *		- sets int value to n_value
		 */
		TToken(int _n_line, int _n_col, int _n_type, int n_value);

		/*
		 *	CMaterialLexer::TToken::TToken(int _n_line, int _n_col, int _n_type, float f_value)
		 *		- constructor for tokens with floating point data
		 *		- sets line to _n_line, column to _n_col and type to _n_type
		 *		- sets float value to f_value
		 */
		TToken(int _n_line, int _n_col, int _n_type, float f_value);

		/*
		 *	CMaterialLexer::TToken::TToken(int _n_line, int _n_col,
		 *		int _n_type, const char *p_s_value)
		 *		- constructor for tokens with string data
		 *		- sets line to _n_line, column to _n_col and type to _n_type
		 *		- sets string value to p_s_value (a new string is allocated and copied,
		 *		  check wheter allocation was successful)
		 */
		TToken(int _n_line, int _n_col, int _n_type, const char *p_s_value);

		/*
		 *	CMaterialLexer::TToken::TToken(const TToken &r_t_token)
		 *		- copy-constructor
		 *		- note in case token is supposed to contain string data, a new string
		 *		  is allocated and copied, check wheter allocation was successful
		 */
		TToken(const TToken &r_t_token);

		/*
		 *	CMaterialLexer::TToken::~TToken()
		 *		- default destructor; deallocates string data in case it was present
		 */
		~TToken();

		/*
		 *	bool CMaterialLexer::TToken::operator =(const TToken &r_t_token)
		 *		- copy-operator
		 *		- returns true on success, false in case there was
		 *		  not enough memory for string data
		 */
		bool operator =(const TToken &r_t_token);

		/*
		 *	inline int CMaterialLexer::TToken::n_Line() const
		 *		- returns zero-based index of line where token lies in source file
		 */
		inline int n_Line() const
		{
			return n_line;
		}

		/*
		 *	inline int CMaterialLexer::TToken::n_Column() const
		 *		- returns zero-based index of column where token starts in source file
		 */
		inline int n_Column() const
		{
			return n_col;
		}

		/*
		 *	inline int CMaterialLexer::TToken::n_Type() const
		 *		- returns token type
		 */
		inline int n_Type() const
		{
			return n_type;
		}

		/*
		 *	inline int CMaterialLexer::TToken::n_Value() const
		 *		- returns token integer value
		 *		- note this should be osed on tokens of type token_Int or token_Bool only
		 */
		inline int n_Value() const
		{
			_ASSERTE(n_type >= token_Bool && n_type <= token_GLenum);
			return t_value.n_value;
		}

		/*
		 *	inline float CMaterialLexer::TToken::f_Value() const
		 *		- returns token float value
		 *		- note this should be osed on tokens of type token_Float only
		 */
		inline float f_Value() const
		{
			_ASSERTE(n_type == token_Float);
			return t_value.f_value;
		}

		/*
		 *	inline const char *CMaterialLexer::TToken::p_s_Value() const
		 *		- returns token string value
		 *		- note this should be used on tokens of type token_Node,
		 *		  token_GLenum, token_String or token_CData only
		 */
		inline const char *p_s_Value() const
		{
			_ASSERTE(n_type >= token_Node && n_type <= token_CData);
			return t_value.p_s_value;
		}

#ifdef MATERIAL_LEXER_TOKEN_DUMP
		/*
		 *	void CMaterialLexer::TToken::Dump() const
		 *		- prints token contents
		 *		- note this is compiled only if MATERIAL_LEXER_TOKEN_DUMP is defined
		 */
		void Dump() const;
#endif // MATERIAL_LEXER_TOKEN_DUMP
	};

protected:
	TToken m_t_token;

	class CTokenEmit;

	class CTokenEmitAdapter {
	protected:
		CTokenEmit **m_p_emit_obj_list;

	public:
		inline CTokenEmitAdapter(CTokenEmit **p_emit_obj_list);
		inline bool operator ()(const char *p_s_buffer,
			int n_regexp_id, int n_line, int n_column) const;
	};

#pragma pack(1)
	struct TTransition {
		uint32_t n_char_max;
		uint16_t n_char_min;
		uint16_t n_state;
	};

	struct TState {
		const TTransition *p_transition;
		int8_t n_regexp_id;
		uint16_t n_transition_num;
	};
#pragma pack()

	static TState m_p_state[33];
	static const TTransition m_p_transition[78];

	CScanner<char, TState, TTransition, CTokenEmitAdapter> m_scanner;
	CTokenEmit *m_p_emit[8];

	class CFileReader;

	CFileReader *m_p_file;

	class CEmitSkip;
	class CEmitNode;
	class CEmitOperator;
	class CEmitString;
	class CEmitInt;
	class CEmitFloat;
	class CEmitGLenum;
	class CEmitCData;

public:
	/*
	 *	CMaterialLexer::CMaterialLexer(const char *p_s_filename)
	 *		- default constructor; creates a new parser, bound to p_s_filename
	 *		- call b_Status() to see wheter file was opened successfully
	 *		  (no parsing occurs at this moment)
	 *		- note all parsing occurs in us-ascii encoding
	 */
	CMaterialLexer(const char *p_s_filename);

	/*
	 *	CMaterialLexer::~CMaterialLexer()
	 *		- default destructor
	 */
	~CMaterialLexer();

	/*
	 *	bool CMaterialLexer::b_Status() const
	 *		- returns status of parser
	 *		- returns true if no errors occured, returns false if
	 *		  constructor or parsing failed
	 */
	bool b_Status() const;

	/*
	 *	bool CMaterialLexer::Get_NextToken()
	 *		- parses next token from file
	 *		- returns true on success, false on parsing / memory failure
	 *		- note reading past the end of the file is not an error
	 *		- always fails in case b_Status() returns false
	 */
	bool Get_NextToken();

	/*
	 *	inline bool CMaterialLexer::Get_NextToken(int n_accept_type)
	 *		- parses next token from file
	 *		- returns true on success and only if token type is equal
	 *		  to n_accept_type, otherwise returns false
	 *		- note reading past the end of the file is not an error
	 *		  if n_accept_type is token_EOF
	 *		- always fails in case b_Status() returns false
	 */
	inline bool Get_NextToken(int n_accept_type)
	{
		if(!Get_NextToken())
			return false;
		return m_t_token.n_Type() == n_accept_type;
	}

	/*
	 *	int CMaterialLexer::n_Cur_Line() const
	 *		- returns zero-based index of line where the parser last stopped
	 *		- this is useful for printing error messages on where parsing failed
	 */
	int n_Cur_Line() const;

	/*
	 *	int CMaterialLexer::n_Cur_Column() const
	 *		- returns zero-based index of column where the parser last stopped
	 *		- this is useful for printing error messages on where parsing failed
	 */
	int n_Cur_Column() const;

	/*
	 *	const CMaterialLexer::TToken &CMaterialLexer::t_Cur_Token() const
	 *		- returns constant reference to current token
	 *		- note in case no token was read, this returns token_EOF at line 0, col 0
	 *		- return value is undefined in case b_Status() returns false
	 */
	const TToken &t_Cur_Token() const;

	/*
	 *	inline int CMaterialLexer::n_Cur_Token() const
	 *		- returns type of current token
	 *		- note in case no token was read, this returns token_EOF
	 *		- return value is undefined in case b_Status() returns false
	 */
	inline int n_Cur_Token() const
	{
		return t_Cur_Token().n_Type();
	}
};

/*
 *	class CGLenumTable
 *		- small class for converting string values
 *		  of OpenGL enums to their numeric form
 */
class CGLenumTable {
protected:
	static const struct TTable {
		const char *p_s_name;
		unsigned short n_value;
	} m_p_table[];

public:
	/*
	 *	static int CGLenumTable::n_Value(const char *p_s_name)
	 *		- returns value of OpenGL enum p_s_name
	 *		- returns -1 in case p_s_name is not found in the table
	 */
	static int n_Value(const char *p_s_name);
};

/*
 *	class CTextureConfig
 *		- contains texture unit configuration
 *		- able to parse itself from material file
 */
class CTextureConfig {
protected:
	GLenum m_n_target;
	int m_n_texture_unit;

	char *m_p_s_source, *m_p_s_source_alpha;
	int m_n_source_type;

	GLenum m_n_internal_format;

	bool m_b_mipmaps;

	GLenum m_p_wrap_mode[3];

	GLenum m_n_min_filter, m_n_mag_filter;

	float m_f_min_lod, m_f_max_lod, m_f_lod_bias;

	int m_n_base_level, m_n_max_level;

	GLenum m_n_depth_tex_mode;
	GLenum m_n_depth_tex_compare_mode;
	GLenum m_n_depth_tex_compare_func;
	// use in case it's depth component internal format only

	struct TNodeHandler {
		const char *p_s_node_name;
		bool (CTextureConfig::*p_handler_func)(CMaterialLexer &r_scanner, int n_flag);
		char n_flag;
	};

	static const TNodeHandler m_p_handler_table[];

public:
	/*
	 *	CTextureConfig::<unnamed>
	 *		- this enum contains texture source types
	 *		- tex_Reflect is reflection texture, it should have the same size
	 *		  as screen and pixels of surfaces textured by it should contain image
	 *		  of perfect mirror reflection (generated via stencil and recursive scene rendering)
	 *		- tex_Refract is similar to tex_Reflect, but it contains scene *behind*
	 *		  surfaces textured by it (such as underwater portion of the scene)
	 *		- tex_Custom means texture will be bound by rendering loop and not the material system
	 *		  (texture properties may or may not be applied on it)
	 *		- tex_DepthMap is depth-map texture rendered from light point of view (shadow-mapping)
	 *		- tex_Static marks the texture will be loaded from image files
	 */
	enum {
		tex_Reflect, tex_Refract,
		tex_Custom, tex_DepthMap, tex_Static
	};

	/*
	 *	CTextureConfig::CTextureConfig(CMaterialLexer &r_scanner)
	 *		- default destructor; parses texture data from r_scanner
	 *		- call b_Status() to see wheter parsing was successful
	 */
	CTextureConfig(CMaterialLexer &r_scanner);

	/*
	 *	CTextureConfig::~CTextureConfig()
	 *		- default destructor
	 */
	~CTextureConfig();

	/*
	 *	bool CTextureConfig::b_Status() const
	 *		- if constructor was successful, returns true. otherwise returns false
	 */
	bool b_Status() const;

	/*
	 *	inline GLenum CTextureConfig::n_Target() const
	 *		- returns texture target (ie. one of GL_TEXTURE_1D, GL_TEXTURE_2D,
	 *		  GL_TEXTURE_3D or GL_TEXTURE_CUBE)
	 *		- returns 0 in case constructor failed
	 */
	inline GLenum n_Target() const
	{
		return m_n_target;
	}

	/*
	 *	inline int CTextureConfig::n_Texture_Unit() const
	 *		- returns texture unit this texture is supposed to be bound to
	 */
	inline int n_Texture_Unit() const
	{
		return m_n_texture_unit;
	}

	/*
	 *	inline int CTextureConfig::n_Texture_Source() const
	 *		- returns texture source, ie. one of tex_Reflect, tex_Refract, tex_Custom,
	 *		  tex_DepthMap or tex_Static
	 *		- note tex_Static only is supposed to be loaded from texture image file
	 */
	inline int n_Texture_Source() const
	{
		return m_n_source_type;
	}

	/*
	 *	inline const char *CTextureConfig::p_s_Texture_File() const
	 *		- returns filename of bitmap containing texture image
	 *		  or 0 if texture source is not static texture (ie. it's realtime generated texture)
	 */
	inline const char *p_s_Texture_File() const
	{
		return (m_n_source_type == tex_Static)? m_p_s_source : 0;
	}

	/*
	 *	inline const char *CTextureConfig::p_s_TextureAlpha_File() const
	 *		- returns filename of additional bitmap containing texture alpha channel
	 *		  or 0 if there's no alpha channel required, it's contained in
	 *		  primary bitmap along with color information or texture source is not
	 *		  static texture (ie. it's some kind of generated texture)
	 */
	inline const char *p_s_TextureAlpha_File() const
	{
		return (m_n_source_type == tex_Static)? m_p_s_source_alpha : 0;
	}

	/*
	 *	inline GLenum CTextureConfig::n_Internal_Format() const
	 *		- returns texture internal format
	 */
	inline GLenum n_Internal_Format() const
	{
		return m_n_internal_format;
	}

	/*
	 *	inline bool CTextureConfig::b_Generate_MipMaps() const
	 *		- returns true in case texture is required to
	 *		  have mipmaps generated, otherwise returns false
	 */
	inline bool b_Generate_MipMaps() const
	{
		return m_b_mipmaps;
	}

	/*
	 *	void CTextureConfig::ApplyTextureParameters(CGLTextureParams &r_texture_params)
	 *		- sets all but mipmap generation texture parameters to r_texture_params
	 *		- note the texture is supposed to be bound and enabled
	 */
	void ApplyTextureParameters(CGLTextureParams &r_texture_params);

	/*
	 *	static char *CTextureConfig::p_s_Parse_URI(CMaterialLexer &r_scanner)
	 *		- parses URI sequence uri('string')
	 *		- r_scanner is scanner, current token must be token_URI
	 *		- returns string on success, 0 on failure (which might
	 *		  involve insufficient memory for the string)
	 *		- note returned string must be deleted when no longer needed
	 */
	static char *p_s_Parse_URI(CMaterialLexer &r_scanner);

	/*
	 *	inline bool CTextureConfig::operator <(const CTextureConfig &r_tex_data) const
	 *		- less-than compare function for sorting by target texture unit
	 */
	inline bool operator <(const CTextureConfig &r_tex_data) const
	{
		return m_n_texture_unit < r_tex_data.m_n_texture_unit;
	}

protected:
	bool Parse(CMaterialLexer &r_scanner);
	bool Read_Source(CMaterialLexer &r_scanner, int n_flag);
	bool Read_Format(CMaterialLexer &r_scanner, int n_flag);
	bool Read_MipMap(CMaterialLexer &r_scanner, int n_flag);
	bool Read_Wrap(CMaterialLexer &r_scanner, int n_flag);
	bool Read_Filter(CMaterialLexer &r_scanner, int n_flag);
	bool Read_LOD(CMaterialLexer &r_scanner, int n_flag);
	bool Read_MipLevel(CMaterialLexer &r_scanner, int n_flag);
	bool Read_DepthTexMode(CMaterialLexer &r_scanner, int n_flag);
	bool Read_DepthTexCompare(CMaterialLexer &r_scanner, int n_flag);
};

/*
 *	class CMaterialPass
 *		- description of one rendering pass of material
 *		- can parse itself from material file
 */
class CMaterialPass {
protected:
	char *m_p_s_name;

	GLfloat m_f_point_size;
	GLfloat m_f_line_width;

	GLenum m_p_polygon_mode[2]; // back, front

	bool m_b_cull_face;
	GLenum m_n_cull_face;
	GLenum m_n_front_face;

	GLfloat m_f_polygon_offset_factor;
	GLfloat m_f_polygon_offset_units;
	bool m_p_polygon_offset_enabled[3]; // point, line, fill

	GLenum m_n_blend_src, m_n_blend_dst;
	GLenum m_n_blend_equation;
	bool m_b_blend_func, m_b_blend_equation;
	GLclampf m_p_blend_color[4];

	bool m_b_depth_test;
	GLenum m_n_depth_func;

	bool m_b_alpha_test;
	GLenum m_n_alpha_func;
	GLclampf m_f_alpha_ref;

	bool m_b_stencil_test;
	GLenum m_n_stencil_func;
	GLint m_n_stencil_ref, m_n_stencil_mask;

	GLenum m_p_stencil_op[3]; // sfail zfail zpass

	bool m_b_depth_write;
	GLuint m_n_stencil_write_mask;
	bool m_p_color_write[4];

	char *m_p_s_vertex_shader;
	int m_n_vertex_shader_type;
	char *m_p_s_fragment_shader;
	int m_n_fragment_shader_type;

	std::vector<CTextureConfig*> m_texture_list;

	struct TNodeHandler {
		const char *p_s_node_name;
		bool (CMaterialPass::*p_handler_func)(CMaterialLexer &r_scanner, int n_flag);
		char n_flag;
	};

	static const TNodeHandler m_p_handler_table[];

	class CFindConflict;

public:
	/*
	 *	CMaterialPass::<unnamed>
	 *		- determines shader type; inline shader means shader string contains (GLSLang)
	 *		  shader source, file shader means shader string contains URI of file with the shader
	 */
	enum {
		shader_None, shader_Inline, shader_File
	};

	/*
	 *	CMaterialPass::CMaterialPass(CMaterialLexer &r_scanner)
	 *		- default constructor; loads material pass from scanner r_scanner
	 *		- precondition is current token is token_Pass
	 *		- call b_Status() to see wheter parsing was successful
	 */
	CMaterialPass(CMaterialLexer &r_scanner);

	/*
	 *	CMaterialPass::~CMaterialPass()
	 *		- default destructor
	 */
	~CMaterialPass();

	/*
	 *	bool CMaterialPass::b_Status() const
	 *		- if constructor was successful, returns true. otherwise returns false
	 */
	bool b_Status() const;

	/*
	 *	const char *CMaterialPass::p_s_Name() const
	 *		- returns material name
	 *		- note it returns 0 in case constructor failed
	 */
	const char *p_s_Name() const;

	/*
	 *	inline bool operator ==(const char *p_s_name) const
	 *		- comparison operator for finding pass by name
	 */
	inline bool operator ==(const char *p_s_name) const
	{
		return m_p_s_name && !strcmp(p_s_name, m_p_s_name);
	}

	// todo - access texture params

	/*
	 *	void CMaterialPass::Set(CGLState *p_state)
	 *		- sets OpenGL state described by this material pass
	 *		  (aparts from shaders and textures and their parameters)
	 *		- p_state is OpenGL state guard
	 */
	void Set(CGLState *p_state)
	{
		p_state->PointSize(m_f_point_size);
		p_state->LineWidth(m_f_line_width);
		// primitive sizes

		p_state->PolygonModeBack(m_p_polygon_mode[0]);
		p_state->PolygonModeFront(m_p_polygon_mode[1]);
		// polygon mode

		if(m_b_cull_face) {
			p_state->EnableCullFace();
			p_state->CullFace(m_n_cull_face);
			p_state->FrontFace(m_n_front_face);
		} else
			p_state->DisableCullFace();
		// backface culling

		if(m_p_polygon_offset_enabled[0])
			p_state->EnablePolygonOffset_Point();
		else
			p_state->DisablePolygonOffset_Point();
		if(m_p_polygon_offset_enabled[1])
			p_state->EnablePolygonOffset_Line();
		else
			p_state->DisablePolygonOffset_Line();
		if(m_p_polygon_offset_enabled[2])
			p_state->EnablePolygonOffset_Fill();
		else
			p_state->DisablePolygonOffset_Fill();
		if(m_p_polygon_offset_enabled[0] ||
		   m_p_polygon_offset_enabled[1] || m_p_polygon_offset_enabled[2])
			p_state->PolygonOffset(m_f_polygon_offset_factor, m_f_polygon_offset_units);
		// polygon offset

		if(m_b_blend_func) {
			p_state->EnableBlend();
			p_state->BlendFunc(m_n_blend_src, m_n_blend_dst);
		} else if(m_b_blend_equation) {
			p_state->BlendEquation(m_n_blend_equation);
			p_state->BlendColor4f(m_p_blend_color[0], m_p_blend_color[1],
				m_p_blend_color[2], m_p_blend_color[3]);
		} else
			p_state->DisableBlend();
		// blending

		if(m_b_depth_test) {
			p_state->EnableDepthTest();
			p_state->DepthFunc(m_n_depth_func);
		} else
			p_state->DisableDepthTest();
		// depth test

		if(m_b_alpha_test) {
			p_state->EnableAlphaTest();
			p_state->AlphaFunc(m_n_alpha_func, m_f_alpha_ref);
		} else
			p_state->DisableAlphaTest();
		// alpha test

		if(m_b_stencil_test) {
			p_state->EnableStencilTest();
			p_state->StencilFunc(m_n_stencil_func, m_n_stencil_ref, m_n_stencil_mask);
			p_state->StencilOp(m_p_stencil_op[0], m_p_stencil_op[1], m_p_stencil_op[2]);
			p_state->StencilMask(m_n_stencil_mask);
		} else
			p_state->DisableStencilTest();
		// stencil test

		p_state->DepthMask(m_b_depth_write);
		p_state->StencilMask(m_n_stencil_write_mask);
		p_state->ColorMask(m_p_color_write[0], m_p_color_write[1],
			m_p_color_write[2], m_p_color_write[3]);
		// write-masks
	}

protected:
	static inline void DeleteTextureData(CTextureConfig *p_tex_data);
	bool Parse(CMaterialLexer &r_scanner);
	bool Read_PointSize(CMaterialLexer &r_scanner, int n_flag);
	bool Read_LineWidth(CMaterialLexer &r_scanner, int n_flag);
	bool Read_PolygonMode(CMaterialLexer &r_scanner, int n_flag);
	bool Read_CullFace(CMaterialLexer &r_scanner, int n_flag);
	bool Read_FrontFace(CMaterialLexer &r_scanner, int n_flag);
	bool Read_PolygonOffset(CMaterialLexer &r_scanner, int n_flag);
	bool Read_PolygonOffset_Mode(CMaterialLexer &r_scanner, int n_flag);
	bool Read_BlendFunc(CMaterialLexer &r_scanner, int n_flag);
	bool Read_BlendEquation(CMaterialLexer &r_scanner, int n_flag);
	bool Read_BlendColor(CMaterialLexer &r_scanner, int n_flag);
	bool Read_DepthTest(CMaterialLexer &r_scanner, int n_flag);
	bool Read_DepthFunc(CMaterialLexer &r_scanner, int n_flag);
	bool Read_StencilTest(CMaterialLexer &r_scanner, int n_flag);
	bool Read_StencilFunc(CMaterialLexer &r_scanner, int n_flag);
	bool Read_StencilOp(CMaterialLexer &r_scanner, int n_flag);
	bool Read_AlphaTest(CMaterialLexer &r_scanner, int n_flag);
	bool Read_AlphaFunc(CMaterialLexer &r_scanner, int n_flag);
	bool Read_WriteMask(CMaterialLexer &r_scanner, int n_flag);
	bool Read_StencilWriteMask(CMaterialLexer &r_scanner, int n_flag);
	bool Read_Shader(CMaterialLexer &r_scanner, int n_flag);
	bool Read_TextureSection(CMaterialLexer &r_scanner);
	static inline bool CompareTextures(const CTextureConfig *p_tex0, const CTextureConfig *p_tex1);
};

/*
 *	class CMaterial
 *		- class containing material description
 *		- can parse itself from material file
 */
class CMaterial {
protected:
	std::vector<CMaterialPass*> m_pass_list;
	char *m_p_s_name;

	class CFindPass;

public:
	/*
	 *	CMaterial::CMaterial(CMaterialLexer &r_scanner)
	 *		- default constructor
	 *		- r_scanner is scanner with opened material file (assuming newly
	 *		  opened file that contains no other data than shader)
	 *		- call b_Status() to see wheter parsing was successful
	 */
	CMaterial(CMaterialLexer &r_scanner);

	/*
	 *	CMaterial::~CMaterial()
	 *		- default destructor
	 */
	~CMaterial();

	/*
	 *	bool CMaterial::b_Status() const
	 *		- if constructor succeeded in parsing
	 *		  material returns true, otherwise returns false
	 */
	bool b_Status() const;

	/*
	 *	const char *CMaterial::p_s_Name() const
	 *		- returns material name
	 *		- note if constructor failed this returns 0
	 */
	const char *p_s_Name() const;

	/*
	 *	int CMaterial::n_Pass_Num() const
	 *		- returns number of material passes
	 */
	int n_Pass_Num() const;

	/*
	 *	int CMaterial::n_Find_Pass(const char *p_s_name) const
	 *		- finds pass by name p_s_name
	 *		- returns pass index or in case no pass called p_s_name was found, returns -1
	 *		- note this isn't optimised and shouldn't be called on pass-bind basis
	 */
	int n_Find_Pass(const char *p_s_name) const;

	/*
	 *	inline CMaterialPass &CMaterial::r_Pass(int n_index)
	 *		- returns reference to material pass with index n_index
	 */
	inline CMaterialPass &r_Pass(int n_index)
	{
		return *m_pass_list[n_index];
	}

	/*
	 *	inline const CMaterialPass &CMaterial::r_Pass(int n_index) const
	 *		- returns const reference to material pass with index n_index
	 */
	inline const CMaterialPass &r_Pass(int n_index) const
	{
		return *m_pass_list[n_index];
	}

	/*
	 *	inline CMaterialPass &CMaterial::r_Pass(const char *p_s_name)
	 *		- returns reference to material pass with name p_s_name
	 */
	inline CMaterialPass &r_Pass(const char *p_s_name)
	{
		return r_Pass(n_Find_Pass(p_s_name));
	}

	/*
	 *	inline const CMaterialPass &CMaterial::r_Pass(const char *p_s_name) const
	 *		- returns const reference to material pass with name p_s_name
	 */
	inline const CMaterialPass &r_Pass(const char *p_s_name) const
	{
		return r_Pass(n_Find_Pass(p_s_name));
	}

protected:
	static inline void DeleteMaterialPass(CMaterialPass *p_pass);
	bool Parse(CMaterialLexer &r_scanner);
	bool Read_PassSection(CMaterialLexer &r_scanner);
};

// todo - parse shaders

/*
 *	class CShaderInfo
 *		- shader info container
 *		- parses itself from material file
 */
class CShaderInfo {
protected:
	TShaderInfo *m_p_info;

public:
	/*
	 *	CShaderInfo::CShaderInfo(CMaterialLexer &r_scanner)
	 *		- default constructor
	 *		- r_scanner is scanner with opened shader file (assuming newly
	 *		  opened file that contains no other data than shader)
	 *		- call b_Status() to see wheter parsing was successful
	 */
	CShaderInfo(CMaterialLexer &r_scanner);

	/*
	 *	CShaderInfo::~CShaderInfo()
	 *		- default destructor
	 */
	~CShaderInfo();

	/*
	 *	bool CShaderInfo::b_Status() const
	 *		- if constructor succeeded in parsing
	 *		  shader returns true, otherwise returns false
	 */
	bool b_Status() const;

	/*
	 *	const char *CShaderInfo::p_s_Name() const
	 *		- returns shader name
	 *		- note if constructor failed this returns 0
	 */
	const char *p_s_Name() const;

	/*
	 *	const TShaderInfo *CShaderInfo::p_ShaderInfo() const
	 *		- returns const pointer to TShaderInfo (for constructing shader object)
	 */
	const TShaderInfo *p_ShaderInfo() const;

protected:
	bool Parse(CMaterialLexer &r_scanner);
};

#endif // __MATERIAL_SYSTEM_INCLUDED
