Browse Source

WIP - Default texture parameters in BSL

BearishSun 10 năm trước cách đây
mục cha
commit
e100cbbe8e

+ 58 - 113
BansheeEngine/Include/BsBuiltinResources.h

@@ -8,148 +8,105 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	/**
-	 * @brief	Types of builtin meshes that are always available in the engine.
-	 */
+	/**	Types of builtin meshes that are always available in the engine. */
 	enum class BuiltinMesh
 	enum class BuiltinMesh
 	{
 	{
 		Box, Sphere, Cone, Quad, Disc
 		Box, Sphere, Cone, Quad, Disc
 	};
 	};
 
 
-	/**
-	 * @brief	Holds references to built-in resources used by the core engine.
-	 */
+	/**	Types of builtin textures that are always available in the engine. */
+	enum class BuiltinTexture
+	{
+		White, Black, Normal
+	};
+
+	/**	Holds references to built-in resources used by the core engine. */
 	class BS_EXPORT BuiltinResources : public BansheeEngine::Module<BuiltinResources>
 	class BS_EXPORT BuiltinResources : public BansheeEngine::Module<BuiltinResources>
 	{
 	{
 	public:
 	public:
 		BuiltinResources();
 		BuiltinResources();
 		~BuiltinResources();
 		~BuiltinResources();
 
 
-		/**
-		 * @brief	Returns the default skin used by engine GUI elements.
-		 */
+		/**	Returns the default skin used by engine GUI elements. */
 		const HGUISkin& getGUISkin() const { return mSkin; }
 		const HGUISkin& getGUISkin() const { return mSkin; }
 
 
-		/**
-		 * @brief	Returns an empty skin used to be used when no other is available.
-		 */
+		/**	Returns an empty skin used to be used when no other is available. */
 		const HGUISkin& getEmptyGUISkin() const { return mEmptySkin; }
 		const HGUISkin& getEmptyGUISkin() const { return mEmptySkin; }
 
 
-		/**
-		 * @brief	Returns a small entirely white texture.
-		 */
+		/**	Returns a small entirely white texture. */
 		const HSpriteTexture& getWhiteSpriteTexture() const { return mWhiteSpriteTexture; }
 		const HSpriteTexture& getWhiteSpriteTexture() const { return mWhiteSpriteTexture; }
 
 
-		/**
-		 * @brief	Returns a 2x2 sprite texture that can be used when no other is available.
-		 */
+		/**	Returns a 2x2 sprite texture that can be used when no other is available. */
 		const HSpriteTexture& getDummySpriteTexture() const { return mDummySpriteTexture; }
 		const HSpriteTexture& getDummySpriteTexture() const { return mDummySpriteTexture; }
 
 
-		/**
-		 * @brief	Returns a dummy 2x2 texture that may be used when no other is available. Don't modify the returned texture.
-		 */
+		/**	Returns a dummy 2x2 texture that may be used when no other is available. Don't modify the returned texture. */
 		const HTexture& getDummyTexture() const { return mDummyTexture; }
 		const HTexture& getDummyTexture() const { return mDummyTexture; }
 
 
-		/**
-		 * @brief	Returns image data for an arrow cursor, along with its hotspot.
-		 */
+		/**	Returns image data for an arrow cursor, along with its hotspot. */
 		const PixelData& getCursorArrow(Vector2I& hotSpot);
 		const PixelData& getCursorArrow(Vector2I& hotSpot);
 
 
-		/**
-		 * @brief	Returns image data for an arrow with dragged object cursor, along with its hotspot.
-		 */
+		/**	Returns image data for an arrow with dragged object cursor, along with its hotspot. */
 		const PixelData& getCursorArrowDrag(Vector2I& hotSpot);
 		const PixelData& getCursorArrowDrag(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a wait cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a wait cursor, along with its hotspot. */
 		const PixelData& getCursorWait(Vector2I& hotSpot);
 		const PixelData& getCursorWait(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for an "I" beam cursor, along with its hotspot.
-		 */
+		/**	Returns image data for an "I" beam cursor, along with its hotspot. */
 		const PixelData& getCursorIBeam(Vector2I& hotSpot);
 		const PixelData& getCursorIBeam(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a NESW resize cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a NESW resize cursor, along with its hotspot. */
 		const PixelData& getCursorSizeNESW(Vector2I& hotSpot);
 		const PixelData& getCursorSizeNESW(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a NS resize cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a NS resize cursor, along with its hotspot. */
 		const PixelData& getCursorSizeNS(Vector2I& hotSpot);
 		const PixelData& getCursorSizeNS(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a NWSE resize cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a NWSE resize cursor, along with its hotspot. */
 		const PixelData& getCursorSizeNWSE(Vector2I& hotSpot);
 		const PixelData& getCursorSizeNWSE(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a WE resize cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a WE resize cursor, along with its hotspot. */
 		const PixelData& getCursorSizeWE(Vector2I& hotSpot);
 		const PixelData& getCursorSizeWE(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a deny cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a deny cursor, along with its hotspot. */
 		const PixelData& getCursorDeny(Vector2I& hotSpot);
 		const PixelData& getCursorDeny(Vector2I& hotSpot);
 		
 		
-		/**
-		 * @brief	Returns image data for a move left-right cursor, along with its hotspot.
-		 */
+		/**	Returns image data for a move left-right cursor, along with its hotspot. */
 		const PixelData& getCursorMoveLeftRight(Vector2I& hotSpot);
 		const PixelData& getCursorMoveLeftRight(Vector2I& hotSpot);
 
 
-		/**
-		 * @brief	Returns the default application icon.
-		 */
+		/**	Returns the default application icon. */
 		const PixelData& getBansheeIcon();
 		const PixelData& getBansheeIcon();
 
 
-		/**
-		 * @brief	Returns a shader used for rendering only a diffuse texture.
-		 */
+		/**	Returns a shader used for rendering only a diffuse texture. */
 		HShader getDiffuseShader() const { return mShaderDiffuse; }
 		HShader getDiffuseShader() const { return mShaderDiffuse; }
 
 
-		/**
-		 * @brief	Creates material used for textual sprite rendering (e.g. text in GUI).
-		 */
+		/**	Creates material used for textual sprite rendering (e.g. text in GUI). */
 		HMaterial createSpriteTextMaterial() const;
 		HMaterial createSpriteTextMaterial() const;
 
 
-		/**
-		 * @brief	Creates material used for image sprite rendering (e.g. images in GUI).
-		 */
+		/**	Creates material used for image sprite rendering (e.g. images in GUI). */
 		HMaterial createSpriteImageMaterial() const;
 		HMaterial createSpriteImageMaterial() const;
 
 
-		/**
-		* @brief	Creates material used for non-transparent image sprite rendering (e.g. images in GUI).
-		*/
+		/**	Creates material used for non-transparent image sprite rendering (e.g. images in GUI). */
 		HMaterial createSpriteNonAlphaImageMaterial() const;
 		HMaterial createSpriteNonAlphaImageMaterial() const;
 
 
-		/**
-		 * @brief	Retrieves one of the builtin meshes.
-		 */
+		/**	Retrieves one of the builtin meshes. */
 		HMesh getMesh(BuiltinMesh mesh) const;
 		HMesh getMesh(BuiltinMesh mesh) const;
 
 
 		/**
 		/**
-		 * @brief	Loads a shader at the specified path.
+		 * Loads a shader at the specified path.
 		 * 
 		 * 
-		 * @param	Path relative to the default shader folder with no file extension.
+		 * @param[in]	Path relative to the default shader folder with no file extension.
 		 */
 		 */
 		HShader getShader(const Path& path);
 		HShader getShader(const Path& path);
 
 
-		/**
-		 * @brief	Returns image data the Banshee Engine splash screen.
-		 */
+		/**	Retrieves one of the builtin textures. */
+		static HTexture getTexture(BuiltinTexture type);
+
+		/**	Returns image data the Banshee Engine splash screen. */
 		static PixelDataPtr getSplashScreen();
 		static PixelDataPtr getSplashScreen();
 
 
-		/**
-		 * @brief	Returns path to the builtin shader include folder, relative to the working directory.
-		 */
+		/**	Returns path to the builtin shader include folder, relative to the working directory. */
 		static Path getShaderIncludeFolder();
 		static Path getShaderIncludeFolder();
 
 
-		/**
-		 * @brief	Returns path to the builtin icons folder, relative to the working directory.
-		 */
+		/**	Returns path to the builtin icons folder, relative to the working directory. */
 		static Path getIconFolder();
 		static Path getIconFolder();
 
 
 		static const WString IconTextureName;
 		static const WString IconTextureName;
@@ -157,31 +114,23 @@ namespace BansheeEngine
 		static const String MultiLineLabelStyle;
 		static const String MultiLineLabelStyle;
 	private:
 	private:
 		/**
 		/**
-		 * @brief	Imports all necessary resources and converts them to engine-ready format.
+		 * Imports all necessary resources and converts them to engine-ready format.
 		 *
 		 *
-		 * @note	Normally you only want to use this during development phase and then ship
-		 *			with engine-ready format only.
+		 * @note	
+		 * Normally you only want to use this during development phase and then ship with engine-ready format only.
 		 */
 		 */
 		void preprocess();
 		void preprocess();
 
 
-		/**
-		 * @brief	Generates the default engine skin and all GUI element styles.
-		 */
+		/**	Generates the default engine skin and all GUI element styles. */
 		GUISkinPtr generateGUISkin();
 		GUISkinPtr generateGUISkin();
 
 
-		/**
-		 * @brief	Generates the builtin meshes.
-		 */
+		/**	Generates the builtin meshes. */
 		void generateMeshes();
 		void generateMeshes();
 
 
-		/**
-		 * @brief	Loads a GUI skin texture with the specified filename.
-		 */
+		/**	Loads a GUI skin texture with the specified filename. */
 		HSpriteTexture getSkinTexture(const WString& name);
 		HSpriteTexture getSkinTexture(const WString& name);
 
 
-		/**
-		 * @brief	Loads a cursor texture with the specified filename.
-		 */
+		/**	Loads a cursor texture with the specified filename. */
 		HTexture getCursorTexture(const WString& name);
 		HTexture getCursorTexture(const WString& name);
 
 
 		HGUISkin mEmptySkin;
 		HGUISkin mEmptySkin;
@@ -339,45 +288,41 @@ namespace BansheeEngine
 		static const WString MeshConeFile;
 		static const WString MeshConeFile;
 		static const WString MeshQuadFile;
 		static const WString MeshQuadFile;
 		static const WString MeshDiscFile;
 		static const WString MeshDiscFile;
+
+		static HTexture sWhiteTexture;
+		static HTexture sBlackTexture;
+		static HTexture sNormalTexture;
 	};
 	};
 
 
-	/**
-	 * @brief	Provides various methods commonly used for managing builtin resources.
-	 */
+	/**	Provides various methods commonly used for managing builtin resources. */
 	class BS_EXPORT BuiltinResourcesHelper
 	class BS_EXPORT BuiltinResourcesHelper
 	{
 	{
 	public:
 	public:
 		/**
 		/**
-		 * @brief	Imports all recognized assets in the specified folder and saves
-		 *			them to the specified output folder. All saved resources are registered in the
-		 *			provided resource manifest.
+		 * Imports all recognized assets in the specified folder and saves them to the specified output folder. All saved
+		 * resources are registered in the provided resource manifest.
 		 */
 		 */
 		static void importAssets(const Path& inputFolder, const Path& outputFolder, const ResourceManifestPtr& manifest);
 		static void importAssets(const Path& inputFolder, const Path& outputFolder, const ResourceManifestPtr& manifest);
 
 
 		/**
 		/**
-		 * @brief	Imports a font from the specified file. Imported font assets
-		 *			are saved in the output folder. All saved resources are registered in the
-		 *			provided resource manifest.
+		 * Imports a font from the specified file. Imported font assets are saved in the output folder. All saved resources
+		 * are registered in the provided resource manifest.
 		 */
 		 */
 		static void importFont(const Path& inputFile, const WString& outputName, const Path& outputFolder, 
 		static void importFont(const Path& inputFile, const WString& outputName, const Path& outputFolder, 
 			const Vector<UINT32>& fontSizes, bool antialiasing, const ResourceManifestPtr& manifest);
 			const Vector<UINT32>& fontSizes, bool antialiasing, const ResourceManifestPtr& manifest);
 
 
 		/**
 		/**
-		 * @brief	Generates sprite textures for all texture assets in the specified folder.
-		 *			Results are written in the same folder with a "sprite_" prefix. All saved 
-		 *			resources are registered in the provided resource manifest.
+		 * Generates sprite textures for all texture assets in the specified folder. Results are written in the same folder
+		 * with a "sprite_" prefix. All saved resources are registered in the provided resource manifest.
 		 */
 		 */
 		static void generateSpriteTextures(const Path& folder, const ResourceManifestPtr& manifest);
 		static void generateSpriteTextures(const Path& folder, const ResourceManifestPtr& manifest);
 
 
-		/**
-		 * @brief	Writes a timestamp with the current date and time in the specified file.
-		 */
+		/** Writes a timestamp with the current date and time in the specified file. */
 		static void writeTimestamp(const Path& file);
 		static void writeTimestamp(const Path& file);
 
 
 		/**
 		/**
-		 * @brief	Checks all files in the specified folder for modifications compared to the
-		 *			time stored in the timestamp file. Timestamp file must have been saved
-		 *			using "writeTimestamp".
+		 * Checks all files in the specified folder for modifications compared to the time stored in the timestamp file. 
+		 * Timestamp file must have been saved using writeTimestamp().
 		 */
 		 */
 		static bool checkForModifications(const Path& folder, const Path& timeStampFile);
 		static bool checkForModifications(const Path& folder, const Path& timeStampFile);
 	};
 	};

+ 62 - 6
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -46,6 +46,10 @@ namespace BansheeEngine
 	const char* BuiltinResources::ShaderIncludeFolder = "Includes\\";
 	const char* BuiltinResources::ShaderIncludeFolder = "Includes\\";
 	const char* BuiltinResources::MeshFolder = "Meshes\\";
 	const char* BuiltinResources::MeshFolder = "Meshes\\";
 
 
+	HTexture BuiltinResources::sWhiteTexture;
+	HTexture BuiltinResources::sBlackTexture;
+	HTexture BuiltinResources::sNormalTexture;
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								GUI TEXTURES                      		*/
 	/* 								GUI TEXTURES                      		*/
 	/************************************************************************/
 	/************************************************************************/
@@ -236,14 +240,14 @@ namespace BansheeEngine
 		mShaderSpriteNonAlphaImage = getShader(ShaderSpriteImageNoAlphaFile);
 		mShaderSpriteNonAlphaImage = getShader(ShaderSpriteImageNoAlphaFile);
 		mShaderDiffuse = getShader(ShaderDiffuseFile);
 		mShaderDiffuse = getShader(ShaderDiffuseFile);
 
 
-		PixelDataPtr pixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+		PixelDataPtr dummyPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
 
 
-		pixelData->setColorAt(Color::Red, 0, 0);
-		pixelData->setColorAt(Color::Red, 0, 1);
-		pixelData->setColorAt(Color::Red, 1, 0);
-		pixelData->setColorAt(Color::Red, 1, 1);
+		dummyPixelData->setColorAt(Color::Red, 0, 0);
+		dummyPixelData->setColorAt(Color::Red, 0, 1);
+		dummyPixelData->setColorAt(Color::Red, 1, 0);
+		dummyPixelData->setColorAt(Color::Red, 1, 1);
 
 
-		mDummyTexture = Texture::create(pixelData);
+		mDummyTexture = Texture::create(dummyPixelData);
 
 
 		mWhiteSpriteTexture = getSkinTexture(WhiteTex);
 		mWhiteSpriteTexture = getSkinTexture(WhiteTex);
 		mDummySpriteTexture = SpriteTexture::create(mDummyTexture);
 		mDummySpriteTexture = SpriteTexture::create(mDummyTexture);
@@ -1019,6 +1023,58 @@ namespace BansheeEngine
 		return gResources().load<Mesh>(meshPath);
 		return gResources().load<Mesh>(meshPath);
 	}
 	}
 
 
+	HTexture BuiltinResources::getTexture(BuiltinTexture type)
+	{
+		switch(type)
+		{
+		case BuiltinTexture::Black:
+			if(sBlackTexture == nullptr)
+			{
+				PixelDataPtr blackPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+
+				blackPixelData->setColorAt(Color::Black, 0, 0);
+				blackPixelData->setColorAt(Color::Black, 0, 1);
+				blackPixelData->setColorAt(Color::Black, 1, 0);
+				blackPixelData->setColorAt(Color::Black, 1, 1);
+
+				sBlackTexture = Texture::create(blackPixelData);
+			}
+
+			return sBlackTexture;
+		case BuiltinTexture::White:
+			if (sWhiteTexture == nullptr)
+			{
+				PixelDataPtr whitePixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+
+				whitePixelData->setColorAt(Color::White, 0, 0);
+				whitePixelData->setColorAt(Color::White, 0, 1);
+				whitePixelData->setColorAt(Color::White, 1, 0);
+				whitePixelData->setColorAt(Color::White, 1, 1);
+
+				sWhiteTexture = Texture::create(whitePixelData);
+			}
+
+			return sWhiteTexture;
+		case BuiltinTexture::Normal:
+			if (sNormalTexture == nullptr)
+			{
+				PixelDataPtr normalPixelData = PixelData::create(2, 2, 1, PF_R8G8B8A8);
+
+				Color encodedNormal(0.0f, 0.0f, 1.0f);
+				normalPixelData->setColorAt(encodedNormal, 0, 0);
+				normalPixelData->setColorAt(encodedNormal, 0, 1);
+				normalPixelData->setColorAt(encodedNormal, 1, 0);
+				normalPixelData->setColorAt(encodedNormal, 1, 1);
+
+				sNormalTexture = Texture::create(normalPixelData);
+			}
+
+			return sNormalTexture;
+		}
+
+		return HTexture();
+	}
+
 	HMaterial BuiltinResources::createSpriteTextMaterial() const
 	HMaterial BuiltinResources::createSpriteTextMaterial() const
 	{
 	{
 		return Material::create(mShaderSpriteText);
 		return Material::create(mShaderSpriteText);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 405 - 396
BansheeSL/BsParserFX.c


+ 881 - 870
BansheeSL/BsParserFX.y

@@ -1,871 +1,882 @@
-%{
-#include "BsParserFX.h"
-#include "BsLexerFX.h"
-#define inline
-
-void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg);
-%}
-
-%code requires{
-#include "BsMMAlloc.h"
-#include "BsASTFX.h"
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-	typedef void* yyscan_t;
-#endif
-
-#define ADD_PARAMETER(OUTPUT, TYPE, NAME)															\
-			OUTPUT = nodeCreate(parse_state->memContext, NT_Parameter);								\
-			nodePush(parse_state, OUTPUT);															\
-																									\
-			NodeOption paramType;																	\
-			paramType.type = OT_ParamType;															\
-			paramType.value.intValue = TYPE;														\
-																									\
-			NodeOption paramName;																	\
-			paramName.type = OT_Identifier;															\
-			paramName.value.strValue = NAME;														\
-																									\
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramType);		\
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramName);		\
-
-}
-
-%output  "BsParserFX.c"
-%defines "BsParserFX.h"
-
-%define api.pure
-%locations
-%lex-param { yyscan_t scanner }
-%parse-param { ParseState* parse_state }
-%parse-param { yyscan_t scanner }
-%glr-parser
-
-%union {
-	int intValue;
-	float floatValue;
-	float matrixValue[16];
-	const char* strValue;
-	ASTFXNode* nodePtr;
-	NodeOption nodeOption;
-}
-
-	/* Value types */
-%token <intValue>	TOKEN_INTEGER
-%token <floatValue> TOKEN_FLOAT
-%token <intValue>	TOKEN_BOOLEAN
-%token <strValue>	TOKEN_STRING
-%token <strValue>	TOKEN_IDENTIFIER
-
-%token <intValue>	TOKEN_FILLMODEVALUE
-%token <intValue>	TOKEN_CULLMODEVALUE
-%token <intValue>	TOKEN_COMPFUNCVALUE
-%token <intValue>	TOKEN_OPVALUE
-%token <intValue>	TOKEN_COLORMASK
-%token <intValue>	TOKEN_ADDRMODEVALUE
-%token <intValue>	TOKEN_FILTERVALUE
-%token <intValue>	TOKEN_BLENDOPVALUE
-%token <intValue>	TOKEN_BUFFERUSAGE
-
-%token <intValue> TOKEN_FLOATTYPE 
-%token <intValue> TOKEN_FLOAT2TYPE 
-%token <intValue> TOKEN_FLOAT3TYPE 
-%token <intValue> TOKEN_FLOAT4TYPE
-%token <intValue> TOKEN_COLORTYPE
-
-%token <intValue> TOKEN_MAT2x2TYPE 
-%token <intValue> TOKEN_MAT2x3TYPE 
-%token <intValue> TOKEN_MAT2x4TYPE
-
-%token <intValue> TOKEN_MAT3x2TYPE 
-%token <intValue> TOKEN_MAT3x3TYPE 
-%token <intValue> TOKEN_MAT3x4TYPE
-
-%token <intValue> TOKEN_MAT4x2TYPE 
-%token <intValue> TOKEN_MAT4x3TYPE 
-%token <intValue> TOKEN_MAT4x4TYPE
-
-%token <intValue> TOKEN_SAMPLER1D 
-%token <intValue> TOKEN_SAMPLER2D 
-%token <intValue> TOKEN_SAMPLER3D 
-%token <intValue> TOKEN_SAMPLERCUBE 
-%token <intValue> TOKEN_SAMPLER2DMS
-
-%token <intValue> TOKEN_TEXTURE1D 
-%token <intValue> TOKEN_TEXTURE2D 
-%token <intValue> TOKEN_TEXTURE3D 
-%token <intValue> TOKEN_TEXTURECUBE 
-%token <intValue> TOKEN_TEXTURE2DMS
-
-%token <intValue> TOKEN_BYTEBUFFER 
-%token <intValue> TOKEN_STRUCTBUFFER 
-%token <intValue> TOKEN_RWTYPEDBUFFER 
-%token <intValue> TOKEN_RWBYTEBUFFER
-%token <intValue> TOKEN_RWSTRUCTBUFFER 
-%token <intValue> TOKEN_RWAPPENDBUFFER 
-%token <intValue> TOKEN_RWCONSUMEBUFFER
-
-%token TOKEN_PARAMSBLOCK
-
-	/* Qualifiers */
-%token TOKEN_AUTO TOKEN_ALIAS TOKEN_SHARED TOKEN_USAGE
-
-	/* Shader keywords */
-%token TOKEN_SEPARABLE TOKEN_QUEUE TOKEN_PRIORITY TOKEN_TRANSPARENT
-%token TOKEN_PARAMETERS TOKEN_BLOCKS TOKEN_TECHNIQUE
-
-	/* Technique keywords */
-%token	TOKEN_RENDERER TOKEN_LANGUAGE TOKEN_INCLUDE TOKEN_PASS
-
-	/* Pass keywords */
-%token	TOKEN_VERTEX TOKEN_FRAGMENT TOKEN_GEOMETRY TOKEN_HULL TOKEN_DOMAIN TOKEN_COMPUTE TOKEN_COMMON
-%token	TOKEN_STENCILREF
-
-%token	TOKEN_FILLMODE TOKEN_CULLMODE TOKEN_DEPTHBIAS TOKEN_SDEPTHBIAS
-%token	TOKEN_DEPTHCLIP TOKEN_SCISSOR TOKEN_MULTISAMPLE TOKEN_AALINE
-
-%token	TOKEN_DEPTHREAD TOKEN_DEPTHWRITE TOKEN_COMPAREFUNC TOKEN_STENCIL
-%token	TOKEN_STENCILREADMASK TOKEN_STENCILWRITEMASK TOKEN_STENCILOPFRONT TOKEN_STENCILOPBACK
-%token	TOKEN_FAIL TOKEN_ZFAIL
-
-%token	TOKEN_ALPHATOCOVERAGE TOKEN_INDEPENDANTBLEND TOKEN_TARGET TOKEN_INDEX
-%token	TOKEN_BLEND TOKEN_COLOR TOKEN_ALPHA TOKEN_WRITEMASK
-%token	TOKEN_SOURCE TOKEN_DEST TOKEN_OP
-
-	/* Sampler state keywords */
-%token	TOKEN_ADDRMODE TOKEN_MINFILTER TOKEN_MAGFILTER TOKEN_MIPFILTER
-%token	TOKEN_MAXANISO TOKEN_MIPBIAS TOKEN_MIPMIN TOKEN_MIPMAX
-%token	TOKEN_BORDERCOLOR TOKEN_U TOKEN_V TOKEN_W
-
-%type <nodePtr>		shader;
-%type <nodeOption>	shader_statement;
-%type <nodeOption>	shader_option;
-
-%type <nodePtr>		technique;
-%type <nodePtr>		technique_header;
-%type <nodeOption>	technique_statement;
-%type <nodeOption>	technique_option;
-
-%type <nodePtr>		pass;
-%type <nodePtr>		pass_header;
-%type <nodeOption>	pass_statement;
-%type <nodeOption>	pass_option;
-
-%type <nodePtr>		code;
-%type <nodePtr>		code_header;
-
-%type <nodePtr>		stencil_op_front_header;
-%type <nodePtr>		stencil_op_back_header;
-%type <nodeOption>	stencil_op_option;
-
-%type <nodePtr>		target;
-%type <nodePtr>		target_header;
-%type <nodeOption>	target_statement;
-%type <nodeOption>	target_option;
-
-%type <nodePtr>		blend_color_header;
-%type <nodePtr>		blend_alpha_header;
-%type <nodeOption>	blenddef_option;
-
-%type <nodeOption>	sampler_state_option;
-
-%type <nodePtr>		addr_mode;
-%type <nodePtr>		addr_mode_header;
-%type <nodeOption>	addr_mode_option;
-
-%type <nodePtr> parameters
-%type <nodePtr> parameters_header
-%type <nodeOption> parameter
-
-%type <nodePtr> block_header
-%type <nodeOption> block
-%type <nodePtr> blocks_header
-%type <nodePtr> blocks
-
-%type <nodeOption> qualifier
-
-%type <matrixValue> float2;
-%type <matrixValue> float3;
-%type <matrixValue> float4;
-%type <matrixValue> mat6;
-%type <matrixValue> mat8;
-%type <matrixValue> mat9;
-%type <matrixValue> mat12;
-%type <matrixValue> mat16;
-
-%type <nodePtr> param_header_float
-%type <nodePtr> param_header_float2
-%type <nodePtr> param_header_float3
-%type <nodePtr> param_header_float4
-%type <nodePtr> param_header_color
-%type <nodePtr> param_header_mat2x2
-%type <nodePtr> param_header_mat2x3
-%type <nodePtr> param_header_mat2x4
-%type <nodePtr> param_header_mat3x2
-%type <nodePtr> param_header_mat3x3
-%type <nodePtr> param_header_mat3x4
-%type <nodePtr> param_header_mat4x2
-%type <nodePtr> param_header_mat4x3
-%type <nodePtr> param_header_mat4x4
-%type <nodePtr> param_header_sampler
-%type <nodePtr> param_header_generic
-%type <nodePtr> param_header_qualified_sampler
-
-%type <nodeOption> param_body_float
-%type <nodeOption> param_body_float2
-%type <nodeOption> param_body_float3
-%type <nodeOption> param_body_float4
-%type <nodeOption> param_body_mat6
-%type <nodeOption> param_body_mat8
-%type <nodeOption> param_body_mat9
-%type <nodeOption> param_body_mat12
-%type <nodeOption> param_body_mat16
-%type <nodeOption> param_body_sampler
-
-%%
-
-	/* Shader */
-
-shader
-	: /* empty */				{ }
-	| shader_statement shader	{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-shader_statement
-	: shader_option
-	| technique			{ $$.type = OT_Technique; $$.value.nodePtr = $1; }
-	| parameters		{ $$.type = OT_Parameters; $$.value.nodePtr = $1; }
-	| blocks			{ $$.type = OT_Blocks; $$.value.nodePtr = $1; }
-	;
-
-shader_option
-	: TOKEN_SEPARABLE '=' TOKEN_BOOLEAN ';'		{ $$.type = OT_Separable; $$.value.intValue = $3; }
-	| TOKEN_QUEUE '=' TOKEN_INTEGER ';'			{ $$.type = OT_Queue; $$.value.intValue = $3; }
-	| TOKEN_PRIORITY '=' TOKEN_INTEGER ';'		{ $$.type = OT_Priority; $$.value.intValue = $3; }
-	| TOKEN_INCLUDE '=' TOKEN_STRING ';'		{ $$.type = OT_Include; $$.value.strValue = $3; }
-	| TOKEN_TRANSPARENT '=' TOKEN_BOOLEAN ';'	{ $$.type = OT_Transparent; $$.value.intValue = $3; }
-	;
-
-	/* Technique */
-
-technique
-	: technique_header '{' technique_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-technique_header
-	: TOKEN_TECHNIQUE '=' 
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Technique); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-technique_body
-	: /* empty */
-	| technique_statement technique_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-technique_statement
-	: technique_option
-	| pass				{ $$.type = OT_Pass; $$.value.nodePtr = $1; }
-	| pass_option
-	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
-	;
-
-technique_option
-	: TOKEN_RENDERER '=' TOKEN_STRING ';'	{ $$.type = OT_Renderer; $$.value.strValue = $3; }
-	| TOKEN_LANGUAGE '=' TOKEN_STRING ';'	{ $$.type = OT_Language; $$.value.strValue = $3; }
-	;
-
-	/* Pass */
-
-pass
-	: pass_header '{' pass_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-pass_header
-	: TOKEN_PASS '=' 
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Pass); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-pass_body
-	: /* empty */
-	| pass_statement pass_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-pass_statement
-	: pass_option
-	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
-	;
-
-pass_option
-	: TOKEN_INDEX '=' TOKEN_INTEGER ';'							{ $$.type = OT_Index; $$.value.intValue = $3; }
-	| TOKEN_FILLMODE '=' TOKEN_FILLMODEVALUE ';'				{ $$.type = OT_FillMode; $$.value.intValue = $3; }
-	| TOKEN_CULLMODE '=' TOKEN_CULLMODEVALUE ';'				{ $$.type = OT_CullMode; $$.value.intValue = $3; }
-	| TOKEN_DEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_DepthBias; $$.value.floatValue = $3; }
-	| TOKEN_SDEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_SDepthBias; $$.value.floatValue = $3; }
-	| TOKEN_DEPTHCLIP '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthClip; $$.value.intValue = $3; }
-	| TOKEN_SCISSOR '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Scissor; $$.value.intValue = $3; }
-	| TOKEN_MULTISAMPLE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Multisample; $$.value.intValue = $3; }
-	| TOKEN_AALINE '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_AALine; $$.value.intValue = $3; }
-	| TOKEN_DEPTHREAD '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthRead; $$.value.intValue = $3; }
-	| TOKEN_DEPTHWRITE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_DepthWrite; $$.value.intValue = $3; }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'				{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	| TOKEN_STENCIL '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Stencil; $$.value.intValue = $3; }
-	| TOKEN_STENCILREADMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilReadMask; $$.value.intValue = $3; }
-	| TOKEN_STENCILWRITEMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilWriteMask; $$.value.intValue = $3; }
-	| stencil_op_front_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
-	| stencil_op_back_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
-	| stencil_op_front_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
-	| stencil_op_back_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
-	| TOKEN_ALPHATOCOVERAGE '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_AlphaToCoverage; $$.value.intValue = $3; }
-	| TOKEN_INDEPENDANTBLEND '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_IndependantBlend; $$.value.intValue = $3; }
-	| target													{ $$.type = OT_Target; $$.value.nodePtr = $1; }
-	| TOKEN_STENCILREF '=' TOKEN_INTEGER ';'					{ $$.type = OT_StencilRef; $$.value.intValue = $3; }
-	;
-
-	/* Code blocks */
-
-code
-	: code_header '{' TOKEN_INDEX '=' TOKEN_INTEGER ';' '}' ';'
-	{
-		NodeOption index;
-		index.type = OT_Index; 
-		index.value.intValue = $5;
-
-		nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &index);
-
-		nodePop(parse_state); 
-		$$ = $1;
-	}
-	;
-
-code_header
-	: TOKEN_VERTEX '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_FRAGMENT '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_GEOMETRY '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_HULL '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_DOMAIN '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_COMPUTE '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_COMMON '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Code); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-	/* Stencil op */
-
-stencil_op_front_header
-	: TOKEN_STENCILOPFRONT '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-stencil_op_back_header
-	: TOKEN_STENCILOPBACK '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-stencil_op_body_init
-	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_COMPFUNCVALUE
-		{
-			NodeOption fail; fail.type = OT_Fail; fail.value.intValue = $1;
-			NodeOption zfail; zfail.type = OT_ZFail; zfail.value.intValue = $3;
-			NodeOption pass; pass.type = OT_PassOp; pass.value.intValue = $5;
-			NodeOption cmp; cmp.type = OT_CompareFunc; cmp.value.intValue = $7;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &fail);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &zfail);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &pass);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &cmp);
-		}
-	;
-
-stencil_op_body
-	: /* empty */
-	| stencil_op_option stencil_op_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-stencil_op_option
-	: TOKEN_FAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Fail; $$.value.intValue = $3; }
-	| TOKEN_ZFAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_ZFail; $$.value.intValue = $3; }
-	| TOKEN_PASS '=' TOKEN_OPVALUE ';'					{ $$.type = OT_PassOp; $$.value.intValue = $3; }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'		{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	; 
-
-	/* Target */
-target
-	: target_header '{' target_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-target_header
-	: TOKEN_TARGET '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Target); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-target_body
-	: /* empty */
-	| target_statement target_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-target_statement
-	: target_option
-	;
-
-target_option
-	: TOKEN_INDEX '=' TOKEN_INTEGER ';'					{ $$.type = OT_Index; $$.value.intValue = $3; }
-	| TOKEN_BLEND '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Blend; $$.value.intValue = $3; }
-	| blend_color_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
-	| blend_alpha_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
-	| blend_color_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
-	| blend_alpha_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
-	| TOKEN_WRITEMASK '=' TOKEN_COLORMASK ';'			{ $$.type = OT_WriteMask; $$.value.intValue = $3; }
-	;
-
-	/* Blend definition */
-blend_color_header
-	: TOKEN_COLOR '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blend_alpha_header
-	: TOKEN_ALPHA '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blenddef_body
-	: /* empty */
-	| blenddef_option blenddef_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-blenddef_body_init
-	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_BLENDOPVALUE
-		{
-			NodeOption src; src.type = OT_Source; src.value.intValue = $1;
-			NodeOption dst; dst.type = OT_Dest; dst.value.intValue = $3;
-			NodeOption op; op.type = OT_Op; op.value.intValue = $5;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &src);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &dst);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &op);
-		}
-	;
-
-blenddef_option
-	: TOKEN_SOURCE '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Source; $$.value.intValue = $3; }
-	| TOKEN_DEST '=' TOKEN_OPVALUE ';'						{ $$.type = OT_Dest; $$.value.intValue = $3; }
-	| TOKEN_OP '=' TOKEN_BLENDOPVALUE ';'					{ $$.type = OT_Op; $$.value.intValue = $3; }
-	;
-
-	/* Sampler state */
-
-sampler_state_body
-	: /* empty */
-	| sampler_state_option sampler_state_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-sampler_state_option
-	: addr_mode												{ $$.type = OT_AddrMode; $$.value.nodePtr = $1; }
-	| TOKEN_MINFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MinFilter; $$.value.intValue = $3; }
-	| TOKEN_MAGFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MagFilter; $$.value.intValue = $3; }
-	| TOKEN_MIPFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MipFilter; $$.value.intValue = $3; }
-	| TOKEN_MAXANISO '=' TOKEN_INTEGER ';'					{ $$.type = OT_MaxAniso; $$.value.intValue = $3; }
-	| TOKEN_MIPBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipBias; $$.value.floatValue = $3; }
-	| TOKEN_MIPMIN '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMin; $$.value.floatValue = $3; }
-	| TOKEN_MIPMAX '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMax; $$.value.floatValue = $3; }
-	| TOKEN_BORDERCOLOR '=' float4 ';'						{ $$.type = OT_BorderColor; memcpy($$.value.matrixValue, $3, sizeof($3)); }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'			{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	;
-
-	/* Addresing mode */
-addr_mode
-	: addr_mode_header '{' addr_mode_body '}' ';'		{ nodePop(parse_state); $$ = $1; }
-	| addr_mode_header '{' addr_mode_body_init '}' ';'	{ nodePop(parse_state); $$ = $1; }
-	;
-
-addr_mode_header
-	: TOKEN_ADDRMODE '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_AddrMode); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-addr_mode_body_init
-	: TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE
-		{
-			NodeOption u; u.type = OT_U; u.value.intValue = $1;
-			NodeOption v; v.type = OT_V; v.value.intValue = $3;
-			NodeOption w; w.type = OT_W; w.value.intValue = $5;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &u);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &v);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &w);
-		}
-	;
-
-addr_mode_body
-	: /* empty */
-	| addr_mode_option addr_mode_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-addr_mode_option
-	: TOKEN_U '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_U; $$.value.intValue = $3; }
-	| TOKEN_V '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_V; $$.value.intValue = $3; }
-	| TOKEN_W '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_W; $$.value.intValue = $3; }
-	;
-
-	/* Value types */
-float2
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; }
-	;
-
-float3
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
-	;
-
-float4
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
-	;
-
-mat6
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-		}
-	;
-
-mat8
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-			$$[6] = $14; $$[7] = $16;
-		}
-	;
-
-mat9
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-			$$[6] = $14; $$[7] = $16; $$[8] = $18;
-		}
-	;
-
-mat12
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
-			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
-			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
-		}
-	;
-
-mat16
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
-			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
-			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
-			$$[12] = $26; $$[13] = $28; $$[14] = $30; $$[15] = $32;
-		}
-	;
-
-	/* Parameters */
-parameters
-	: parameters_header '{' parameters_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-parameters_header
-	: TOKEN_PARAMETERS '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Parameters); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-parameters_body
-	: /* empty */
-	| parameter parameters_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-parameter
-	: param_header_float	qualifier_list param_body_float		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float2	qualifier_list param_body_float2	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float3	qualifier_list param_body_float3	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float4	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_color	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x2	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x3	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x4	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x2	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x3	qualifier_list param_body_mat9		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x4	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x2	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x3	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x4	qualifier_list param_body_mat16		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_generic	qualifier_list						';' { nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_qualified_sampler		param_body_sampler	';' 
-		{ 
-			nodePop(parse_state);
-
-			NodeOption samplerState;
-			samplerState.type = OT_SamplerState;
-			samplerState.value.nodePtr = $1;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &samplerState); 
-
-			$$.type = OT_Parameter; $$.value.nodePtr = parse_state->topNode; 
-			nodePop(parse_state); 
-		}
-	;
-
-param_header_float 
-	: TOKEN_FLOATTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float2
-	: TOKEN_FLOAT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float3
-	: TOKEN_FLOAT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float4 
-	: TOKEN_FLOAT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_color
-	: TOKEN_COLORTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x2
-	: TOKEN_MAT2x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x3
-	: TOKEN_MAT2x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x4
-	: TOKEN_MAT2x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x2
-	: TOKEN_MAT3x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x3
-	: TOKEN_MAT3x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x4
-	: TOKEN_MAT3x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x2
-	: TOKEN_MAT4x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x3
-	: TOKEN_MAT4x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x4
-	: TOKEN_MAT4x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_sampler
-	: TOKEN_SAMPLER1D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER3D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLERCUBE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2DMS TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_generic
-	: TOKEN_TEXTURE1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURECUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_BYTEBUFFER		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_STRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWTYPEDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWBYTEBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWSTRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWAPPENDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWCONSUMEBUFFER TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_qualified_sampler
-	: param_header_sampler qualifier_list	
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_SamplerState); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-param_body_float 
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' TOKEN_FLOAT	{ $$.type = OT_ParamValue; $$.value.floatValue = $2; }
-	;
-
-param_body_float2
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float2		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_float3
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float3		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_float4
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float4		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat6
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat6			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat8
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat8			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat9
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat9			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat12
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat12			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat16
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat16			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_sampler
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' '{' sampler_state_body '}' { }
-	;
-
-	/* Blocks */
-blocks
-	: blocks_header '{' blocks_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-blocks_header
-	: TOKEN_BLOCKS '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Blocks); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blocks_body
-	: /* empty */
-	| block blocks_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-block
-	: block_header qualifier_list ';' { nodePop(parse_state); $$.type = OT_Block; $$.value.nodePtr = $1; }
-	;
-
-block_header
-	: TOKEN_PARAMSBLOCK TOKEN_IDENTIFIER
-		{
-			$$ = nodeCreate(parse_state->memContext, NT_Block);
-			nodePush(parse_state, $$);
-
-			NodeOption blockName;
-			blockName.type = OT_Identifier;
-			blockName.value.strValue = $2;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &blockName);
-		}
-	;
-
-	/* Qualifiers */
-qualifier_list
-	: /* empty */
-	| qualifier qualifier_list		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-qualifier
-	: ':' TOKEN_ALIAS '(' TOKEN_STRING ')'		{ $$.type = OT_Alias; $$.value.strValue = $4; }
-	| ':' TOKEN_AUTO '(' TOKEN_STRING ')'		{ $$.type = OT_Auto; $$.value.strValue = $4; }
-	| ':' TOKEN_SHARED '(' TOKEN_BOOLEAN ')'	{ $$.type = OT_Shared; $$.value.intValue = $4; }
-	| ':' TOKEN_USAGE '(' TOKEN_BUFFERUSAGE ')'	{ $$.type = OT_Usage; $$.value.intValue = $4; }
-	;
-%%
-
-void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg) 
-{ 
-	parse_state->hasError = 1;
-	parse_state->errorLine = locp->first_line;
-	parse_state->errorColumn = locp->first_column;
-	parse_state->errorMessage = mmalloc_strdup(parse_state->memContext, msg);
+%{
+#include "BsParserFX.h"
+#include "BsLexerFX.h"
+#define inline
+
+void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg);
+%}
+
+%code requires{
+#include "BsMMAlloc.h"
+#include "BsASTFX.h"
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+	typedef void* yyscan_t;
+#endif
+
+#define ADD_PARAMETER(OUTPUT, TYPE, NAME)															\
+			OUTPUT = nodeCreate(parse_state->memContext, NT_Parameter);								\
+			nodePush(parse_state, OUTPUT);															\
+																									\
+			NodeOption paramType;																	\
+			paramType.type = OT_ParamType;															\
+			paramType.value.intValue = TYPE;														\
+																									\
+			NodeOption paramName;																	\
+			paramName.type = OT_Identifier;															\
+			paramName.value.strValue = NAME;														\
+																									\
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramType);		\
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramName);		\
+
+}
+
+%output  "BsParserFX.c"
+%defines "BsParserFX.h"
+
+%define api.pure
+%locations
+%lex-param { yyscan_t scanner }
+%parse-param { ParseState* parse_state }
+%parse-param { yyscan_t scanner }
+%glr-parser
+
+%union {
+	int intValue;
+	float floatValue;
+	float matrixValue[16];
+	const char* strValue;
+	ASTFXNode* nodePtr;
+	NodeOption nodeOption;
+}
+
+	/* Value types */
+%token <intValue>	TOKEN_INTEGER
+%token <floatValue> TOKEN_FLOAT
+%token <intValue>	TOKEN_BOOLEAN
+%token <strValue>	TOKEN_STRING
+%token <strValue>	TOKEN_IDENTIFIER
+
+%token <intValue>	TOKEN_FILLMODEVALUE
+%token <intValue>	TOKEN_CULLMODEVALUE
+%token <intValue>	TOKEN_COMPFUNCVALUE
+%token <intValue>	TOKEN_OPVALUE
+%token <intValue>	TOKEN_COLORMASK
+%token <intValue>	TOKEN_ADDRMODEVALUE
+%token <intValue>	TOKEN_FILTERVALUE
+%token <intValue>	TOKEN_BLENDOPVALUE
+%token <intValue>	TOKEN_BUFFERUSAGE
+
+%token <intValue> TOKEN_FLOATTYPE 
+%token <intValue> TOKEN_FLOAT2TYPE 
+%token <intValue> TOKEN_FLOAT3TYPE 
+%token <intValue> TOKEN_FLOAT4TYPE
+%token <intValue> TOKEN_COLORTYPE
+
+%token <intValue> TOKEN_MAT2x2TYPE 
+%token <intValue> TOKEN_MAT2x3TYPE 
+%token <intValue> TOKEN_MAT2x4TYPE
+
+%token <intValue> TOKEN_MAT3x2TYPE 
+%token <intValue> TOKEN_MAT3x3TYPE 
+%token <intValue> TOKEN_MAT3x4TYPE
+
+%token <intValue> TOKEN_MAT4x2TYPE 
+%token <intValue> TOKEN_MAT4x3TYPE 
+%token <intValue> TOKEN_MAT4x4TYPE
+
+%token <intValue> TOKEN_SAMPLER1D 
+%token <intValue> TOKEN_SAMPLER2D 
+%token <intValue> TOKEN_SAMPLER3D 
+%token <intValue> TOKEN_SAMPLERCUBE 
+%token <intValue> TOKEN_SAMPLER2DMS
+
+%token <intValue> TOKEN_TEXTURE1D 
+%token <intValue> TOKEN_TEXTURE2D 
+%token <intValue> TOKEN_TEXTURE3D 
+%token <intValue> TOKEN_TEXTURECUBE 
+%token <intValue> TOKEN_TEXTURE2DMS
+
+%token <intValue> TOKEN_BYTEBUFFER 
+%token <intValue> TOKEN_STRUCTBUFFER 
+%token <intValue> TOKEN_RWTYPEDBUFFER 
+%token <intValue> TOKEN_RWBYTEBUFFER
+%token <intValue> TOKEN_RWSTRUCTBUFFER 
+%token <intValue> TOKEN_RWAPPENDBUFFER 
+%token <intValue> TOKEN_RWCONSUMEBUFFER
+
+%token TOKEN_PARAMSBLOCK
+
+	/* Qualifiers */
+%token TOKEN_AUTO TOKEN_ALIAS TOKEN_SHARED TOKEN_USAGE
+
+	/* Shader keywords */
+%token TOKEN_SEPARABLE TOKEN_QUEUE TOKEN_PRIORITY TOKEN_TRANSPARENT
+%token TOKEN_PARAMETERS TOKEN_BLOCKS TOKEN_TECHNIQUE
+
+	/* Technique keywords */
+%token	TOKEN_RENDERER TOKEN_LANGUAGE TOKEN_INCLUDE TOKEN_PASS
+
+	/* Pass keywords */
+%token	TOKEN_VERTEX TOKEN_FRAGMENT TOKEN_GEOMETRY TOKEN_HULL TOKEN_DOMAIN TOKEN_COMPUTE TOKEN_COMMON
+%token	TOKEN_STENCILREF
+
+%token	TOKEN_FILLMODE TOKEN_CULLMODE TOKEN_DEPTHBIAS TOKEN_SDEPTHBIAS
+%token	TOKEN_DEPTHCLIP TOKEN_SCISSOR TOKEN_MULTISAMPLE TOKEN_AALINE
+
+%token	TOKEN_DEPTHREAD TOKEN_DEPTHWRITE TOKEN_COMPAREFUNC TOKEN_STENCIL
+%token	TOKEN_STENCILREADMASK TOKEN_STENCILWRITEMASK TOKEN_STENCILOPFRONT TOKEN_STENCILOPBACK
+%token	TOKEN_FAIL TOKEN_ZFAIL
+
+%token	TOKEN_ALPHATOCOVERAGE TOKEN_INDEPENDANTBLEND TOKEN_TARGET TOKEN_INDEX
+%token	TOKEN_BLEND TOKEN_COLOR TOKEN_ALPHA TOKEN_WRITEMASK
+%token	TOKEN_SOURCE TOKEN_DEST TOKEN_OP
+
+	/* Sampler state keywords */
+%token	TOKEN_ADDRMODE TOKEN_MINFILTER TOKEN_MAGFILTER TOKEN_MIPFILTER
+%token	TOKEN_MAXANISO TOKEN_MIPBIAS TOKEN_MIPMIN TOKEN_MIPMAX
+%token	TOKEN_BORDERCOLOR TOKEN_U TOKEN_V TOKEN_W
+
+%type <nodePtr>		shader;
+%type <nodeOption>	shader_statement;
+%type <nodeOption>	shader_option;
+
+%type <nodePtr>		technique;
+%type <nodePtr>		technique_header;
+%type <nodeOption>	technique_statement;
+%type <nodeOption>	technique_option;
+
+%type <nodePtr>		pass;
+%type <nodePtr>		pass_header;
+%type <nodeOption>	pass_statement;
+%type <nodeOption>	pass_option;
+
+%type <nodePtr>		code;
+%type <nodePtr>		code_header;
+
+%type <nodePtr>		stencil_op_front_header;
+%type <nodePtr>		stencil_op_back_header;
+%type <nodeOption>	stencil_op_option;
+
+%type <nodePtr>		target;
+%type <nodePtr>		target_header;
+%type <nodeOption>	target_statement;
+%type <nodeOption>	target_option;
+
+%type <nodePtr>		blend_color_header;
+%type <nodePtr>		blend_alpha_header;
+%type <nodeOption>	blenddef_option;
+
+%type <nodeOption>	sampler_state_option;
+
+%type <nodePtr>		addr_mode;
+%type <nodePtr>		addr_mode_header;
+%type <nodeOption>	addr_mode_option;
+
+%type <nodePtr> parameters
+%type <nodePtr> parameters_header
+%type <nodeOption> parameter
+
+%type <nodePtr> block_header
+%type <nodeOption> block
+%type <nodePtr> blocks_header
+%type <nodePtr> blocks
+
+%type <nodeOption> qualifier
+
+%type <matrixValue> float2;
+%type <matrixValue> float3;
+%type <matrixValue> float4;
+%type <matrixValue> mat6;
+%type <matrixValue> mat8;
+%type <matrixValue> mat9;
+%type <matrixValue> mat12;
+%type <matrixValue> mat16;
+
+%type <nodePtr> param_header_float
+%type <nodePtr> param_header_float2
+%type <nodePtr> param_header_float3
+%type <nodePtr> param_header_float4
+%type <nodePtr> param_header_color
+%type <nodePtr> param_header_mat2x2
+%type <nodePtr> param_header_mat2x3
+%type <nodePtr> param_header_mat2x4
+%type <nodePtr> param_header_mat3x2
+%type <nodePtr> param_header_mat3x3
+%type <nodePtr> param_header_mat3x4
+%type <nodePtr> param_header_mat4x2
+%type <nodePtr> param_header_mat4x3
+%type <nodePtr> param_header_mat4x4
+%type <nodePtr> param_header_sampler
+%type <nodePtr> param_header_texture
+%type <nodePtr> param_header_buffer
+%type <nodePtr> param_header_qualified_sampler
+
+%type <nodeOption> param_body_float
+%type <nodeOption> param_body_float2
+%type <nodeOption> param_body_float3
+%type <nodeOption> param_body_float4
+%type <nodeOption> param_body_mat6
+%type <nodeOption> param_body_mat8
+%type <nodeOption> param_body_mat9
+%type <nodeOption> param_body_mat12
+%type <nodeOption> param_body_mat16
+%type <nodeOption> param_body_sampler
+%type <nodeOption> param_body_tex
+
+%%
+
+	/* Shader */
+
+shader
+	: /* empty */				{ }
+	| shader_statement shader	{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+shader_statement
+	: shader_option
+	| technique			{ $$.type = OT_Technique; $$.value.nodePtr = $1; }
+	| parameters		{ $$.type = OT_Parameters; $$.value.nodePtr = $1; }
+	| blocks			{ $$.type = OT_Blocks; $$.value.nodePtr = $1; }
+	;
+
+shader_option
+	: TOKEN_SEPARABLE '=' TOKEN_BOOLEAN ';'		{ $$.type = OT_Separable; $$.value.intValue = $3; }
+	| TOKEN_QUEUE '=' TOKEN_INTEGER ';'			{ $$.type = OT_Queue; $$.value.intValue = $3; }
+	| TOKEN_PRIORITY '=' TOKEN_INTEGER ';'		{ $$.type = OT_Priority; $$.value.intValue = $3; }
+	| TOKEN_INCLUDE '=' TOKEN_STRING ';'		{ $$.type = OT_Include; $$.value.strValue = $3; }
+	| TOKEN_TRANSPARENT '=' TOKEN_BOOLEAN ';'	{ $$.type = OT_Transparent; $$.value.intValue = $3; }
+	;
+
+	/* Technique */
+
+technique
+	: technique_header '{' technique_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+technique_header
+	: TOKEN_TECHNIQUE '=' 
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Technique); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+technique_body
+	: /* empty */
+	| technique_statement technique_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+technique_statement
+	: technique_option
+	| pass				{ $$.type = OT_Pass; $$.value.nodePtr = $1; }
+	| pass_option
+	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
+	;
+
+technique_option
+	: TOKEN_RENDERER '=' TOKEN_STRING ';'	{ $$.type = OT_Renderer; $$.value.strValue = $3; }
+	| TOKEN_LANGUAGE '=' TOKEN_STRING ';'	{ $$.type = OT_Language; $$.value.strValue = $3; }
+	;
+
+	/* Pass */
+
+pass
+	: pass_header '{' pass_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+pass_header
+	: TOKEN_PASS '=' 
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Pass); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+pass_body
+	: /* empty */
+	| pass_statement pass_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+pass_statement
+	: pass_option
+	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
+	;
+
+pass_option
+	: TOKEN_INDEX '=' TOKEN_INTEGER ';'							{ $$.type = OT_Index; $$.value.intValue = $3; }
+	| TOKEN_FILLMODE '=' TOKEN_FILLMODEVALUE ';'				{ $$.type = OT_FillMode; $$.value.intValue = $3; }
+	| TOKEN_CULLMODE '=' TOKEN_CULLMODEVALUE ';'				{ $$.type = OT_CullMode; $$.value.intValue = $3; }
+	| TOKEN_DEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_DepthBias; $$.value.floatValue = $3; }
+	| TOKEN_SDEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_SDepthBias; $$.value.floatValue = $3; }
+	| TOKEN_DEPTHCLIP '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthClip; $$.value.intValue = $3; }
+	| TOKEN_SCISSOR '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Scissor; $$.value.intValue = $3; }
+	| TOKEN_MULTISAMPLE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Multisample; $$.value.intValue = $3; }
+	| TOKEN_AALINE '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_AALine; $$.value.intValue = $3; }
+	| TOKEN_DEPTHREAD '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthRead; $$.value.intValue = $3; }
+	| TOKEN_DEPTHWRITE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_DepthWrite; $$.value.intValue = $3; }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'				{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	| TOKEN_STENCIL '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Stencil; $$.value.intValue = $3; }
+	| TOKEN_STENCILREADMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilReadMask; $$.value.intValue = $3; }
+	| TOKEN_STENCILWRITEMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilWriteMask; $$.value.intValue = $3; }
+	| stencil_op_front_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
+	| stencil_op_back_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
+	| stencil_op_front_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
+	| stencil_op_back_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
+	| TOKEN_ALPHATOCOVERAGE '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_AlphaToCoverage; $$.value.intValue = $3; }
+	| TOKEN_INDEPENDANTBLEND '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_IndependantBlend; $$.value.intValue = $3; }
+	| target													{ $$.type = OT_Target; $$.value.nodePtr = $1; }
+	| TOKEN_STENCILREF '=' TOKEN_INTEGER ';'					{ $$.type = OT_StencilRef; $$.value.intValue = $3; }
+	;
+
+	/* Code blocks */
+
+code
+	: code_header '{' TOKEN_INDEX '=' TOKEN_INTEGER ';' '}' ';'
+	{
+		NodeOption index;
+		index.type = OT_Index; 
+		index.value.intValue = $5;
+
+		nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &index);
+
+		nodePop(parse_state); 
+		$$ = $1;
+	}
+	;
+
+code_header
+	: TOKEN_VERTEX '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_FRAGMENT '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_GEOMETRY '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_HULL '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_DOMAIN '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_COMPUTE '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_COMMON '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Code); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+	/* Stencil op */
+
+stencil_op_front_header
+	: TOKEN_STENCILOPFRONT '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+stencil_op_back_header
+	: TOKEN_STENCILOPBACK '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+stencil_op_body_init
+	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_COMPFUNCVALUE
+		{
+			NodeOption fail; fail.type = OT_Fail; fail.value.intValue = $1;
+			NodeOption zfail; zfail.type = OT_ZFail; zfail.value.intValue = $3;
+			NodeOption pass; pass.type = OT_PassOp; pass.value.intValue = $5;
+			NodeOption cmp; cmp.type = OT_CompareFunc; cmp.value.intValue = $7;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &fail);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &zfail);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &pass);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &cmp);
+		}
+	;
+
+stencil_op_body
+	: /* empty */
+	| stencil_op_option stencil_op_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+stencil_op_option
+	: TOKEN_FAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Fail; $$.value.intValue = $3; }
+	| TOKEN_ZFAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_ZFail; $$.value.intValue = $3; }
+	| TOKEN_PASS '=' TOKEN_OPVALUE ';'					{ $$.type = OT_PassOp; $$.value.intValue = $3; }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'		{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	; 
+
+	/* Target */
+target
+	: target_header '{' target_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+target_header
+	: TOKEN_TARGET '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Target); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+target_body
+	: /* empty */
+	| target_statement target_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+target_statement
+	: target_option
+	;
+
+target_option
+	: TOKEN_INDEX '=' TOKEN_INTEGER ';'					{ $$.type = OT_Index; $$.value.intValue = $3; }
+	| TOKEN_BLEND '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Blend; $$.value.intValue = $3; }
+	| blend_color_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
+	| blend_alpha_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
+	| blend_color_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
+	| blend_alpha_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
+	| TOKEN_WRITEMASK '=' TOKEN_COLORMASK ';'			{ $$.type = OT_WriteMask; $$.value.intValue = $3; }
+	;
+
+	/* Blend definition */
+blend_color_header
+	: TOKEN_COLOR '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blend_alpha_header
+	: TOKEN_ALPHA '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blenddef_body
+	: /* empty */
+	| blenddef_option blenddef_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+blenddef_body_init
+	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_BLENDOPVALUE
+		{
+			NodeOption src; src.type = OT_Source; src.value.intValue = $1;
+			NodeOption dst; dst.type = OT_Dest; dst.value.intValue = $3;
+			NodeOption op; op.type = OT_Op; op.value.intValue = $5;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &src);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &dst);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &op);
+		}
+	;
+
+blenddef_option
+	: TOKEN_SOURCE '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Source; $$.value.intValue = $3; }
+	| TOKEN_DEST '=' TOKEN_OPVALUE ';'						{ $$.type = OT_Dest; $$.value.intValue = $3; }
+	| TOKEN_OP '=' TOKEN_BLENDOPVALUE ';'					{ $$.type = OT_Op; $$.value.intValue = $3; }
+	;
+
+	/* Sampler state */
+
+sampler_state_body
+	: /* empty */
+	| sampler_state_option sampler_state_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+sampler_state_option
+	: addr_mode												{ $$.type = OT_AddrMode; $$.value.nodePtr = $1; }
+	| TOKEN_MINFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MinFilter; $$.value.intValue = $3; }
+	| TOKEN_MAGFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MagFilter; $$.value.intValue = $3; }
+	| TOKEN_MIPFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MipFilter; $$.value.intValue = $3; }
+	| TOKEN_MAXANISO '=' TOKEN_INTEGER ';'					{ $$.type = OT_MaxAniso; $$.value.intValue = $3; }
+	| TOKEN_MIPBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipBias; $$.value.floatValue = $3; }
+	| TOKEN_MIPMIN '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMin; $$.value.floatValue = $3; }
+	| TOKEN_MIPMAX '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMax; $$.value.floatValue = $3; }
+	| TOKEN_BORDERCOLOR '=' float4 ';'						{ $$.type = OT_BorderColor; memcpy($$.value.matrixValue, $3, sizeof($3)); }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'			{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	;
+
+	/* Addresing mode */
+addr_mode
+	: addr_mode_header '{' addr_mode_body '}' ';'		{ nodePop(parse_state); $$ = $1; }
+	| addr_mode_header '{' addr_mode_body_init '}' ';'	{ nodePop(parse_state); $$ = $1; }
+	;
+
+addr_mode_header
+	: TOKEN_ADDRMODE '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_AddrMode); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+addr_mode_body_init
+	: TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE
+		{
+			NodeOption u; u.type = OT_U; u.value.intValue = $1;
+			NodeOption v; v.type = OT_V; v.value.intValue = $3;
+			NodeOption w; w.type = OT_W; w.value.intValue = $5;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &u);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &v);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &w);
+		}
+	;
+
+addr_mode_body
+	: /* empty */
+	| addr_mode_option addr_mode_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+addr_mode_option
+	: TOKEN_U '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_U; $$.value.intValue = $3; }
+	| TOKEN_V '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_V; $$.value.intValue = $3; }
+	| TOKEN_W '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_W; $$.value.intValue = $3; }
+	;
+
+	/* Value types */
+float2
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; }
+	;
+
+float3
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
+	;
+
+float4
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
+	;
+
+mat6
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+		}
+	;
+
+mat8
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+			$$[6] = $14; $$[7] = $16;
+		}
+	;
+
+mat9
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+			$$[6] = $14; $$[7] = $16; $$[8] = $18;
+		}
+	;
+
+mat12
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
+			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
+			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
+		}
+	;
+
+mat16
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
+			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
+			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
+			$$[12] = $26; $$[13] = $28; $$[14] = $30; $$[15] = $32;
+		}
+	;
+
+	/* Parameters */
+parameters
+	: parameters_header '{' parameters_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+parameters_header
+	: TOKEN_PARAMETERS '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Parameters); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+parameters_body
+	: /* empty */
+	| parameter parameters_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+parameter
+	: param_header_float	qualifier_list param_body_float		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float2	qualifier_list param_body_float2	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float3	qualifier_list param_body_float3	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float4	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_color	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x2	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x3	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x4	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x2	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x3	qualifier_list param_body_mat9		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x4	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x2	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x3	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x4	qualifier_list param_body_mat16		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_texture	qualifier_list param_body_tex		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_buffer	qualifier_list						';' { nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_qualified_sampler		param_body_sampler	';' 
+		{ 
+			nodePop(parse_state);
+
+			NodeOption samplerState;
+			samplerState.type = OT_SamplerState;
+			samplerState.value.nodePtr = $1;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &samplerState); 
+
+			$$.type = OT_Parameter; $$.value.nodePtr = parse_state->topNode; 
+			nodePop(parse_state); 
+		}
+	;
+
+param_header_float 
+	: TOKEN_FLOATTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float2
+	: TOKEN_FLOAT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float3
+	: TOKEN_FLOAT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float4 
+	: TOKEN_FLOAT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_color
+	: TOKEN_COLORTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x2
+	: TOKEN_MAT2x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x3
+	: TOKEN_MAT2x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x4
+	: TOKEN_MAT2x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x2
+	: TOKEN_MAT3x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x3
+	: TOKEN_MAT3x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x4
+	: TOKEN_MAT3x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x2
+	: TOKEN_MAT4x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x3
+	: TOKEN_MAT4x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x4
+	: TOKEN_MAT4x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_sampler
+	: TOKEN_SAMPLER1D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER3D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLERCUBE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2DMS TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_texture
+	: TOKEN_TEXTURE1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURECUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_buffer
+	: TOKEN_BYTEBUFFER		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_STRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTYPEDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWBYTEBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWSTRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWAPPENDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWCONSUMEBUFFER TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_qualified_sampler
+	: param_header_sampler qualifier_list	
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_SamplerState); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+param_body_float 
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' TOKEN_FLOAT	{ $$.type = OT_ParamValue; $$.value.floatValue = $2; }
+	;
+
+param_body_float2
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float2		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_float3
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float3		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_float4
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float4		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat6
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat6			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat8
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat8			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat9
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat9			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat12
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat12			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat16
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat16			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_sampler
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' '{' sampler_state_body '}' { }
+	;
+
+param_body_tex
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' TOKEN_STRING	{ $$.type = OT_ParamStrValue; $$.value.strValue = $2; }
+	;
+
+	/* Blocks */
+blocks
+	: blocks_header '{' blocks_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+blocks_header
+	: TOKEN_BLOCKS '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Blocks); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blocks_body
+	: /* empty */
+	| block blocks_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+block
+	: block_header qualifier_list ';' { nodePop(parse_state); $$.type = OT_Block; $$.value.nodePtr = $1; }
+	;
+
+block_header
+	: TOKEN_PARAMSBLOCK TOKEN_IDENTIFIER
+		{
+			$$ = nodeCreate(parse_state->memContext, NT_Block);
+			nodePush(parse_state, $$);
+
+			NodeOption blockName;
+			blockName.type = OT_Identifier;
+			blockName.value.strValue = $2;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &blockName);
+		}
+	;
+
+	/* Qualifiers */
+qualifier_list
+	: /* empty */
+	| qualifier qualifier_list		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+qualifier
+	: ':' TOKEN_ALIAS '(' TOKEN_STRING ')'		{ $$.type = OT_Alias; $$.value.strValue = $4; }
+	| ':' TOKEN_AUTO '(' TOKEN_STRING ')'		{ $$.type = OT_Auto; $$.value.strValue = $4; }
+	| ':' TOKEN_SHARED '(' TOKEN_BOOLEAN ')'	{ $$.type = OT_Shared; $$.value.intValue = $4; }
+	| ':' TOKEN_USAGE '(' TOKEN_BUFFERUSAGE ')'	{ $$.type = OT_Usage; $$.value.intValue = $4; }
+	;
+%%
+
+void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg) 
+{ 
+	parse_state->hasError = 1;
+	parse_state->errorLine = locp->first_line;
+	parse_state->errorColumn = locp->first_column;
+	parse_state->errorMessage = mmalloc_strdup(parse_state->memContext, msg);
 }
 }

+ 256 - 255
BansheeSL/Include/BsASTFX.h

@@ -1,256 +1,257 @@
-#ifndef __ASTFX_H__
-#define __ASTFX_H__
-
-#include <stdlib.h>
-#include <string.h>
-
-typedef enum tagNodeType NodeType;
-typedef enum tagOptionType OptionType;
-typedef enum tagOptionDataType OptionDataType;
-typedef enum tagParamType ParamType;
-typedef struct tagParseState ParseState;
-typedef struct tagOptionInfo OptionInfo;
-typedef union tagOptionData OptionData;
-typedef struct tagNodeOptions NodeOptions;
-typedef struct tagNodeOption NodeOption;
-typedef struct tagASTFXNode ASTFXNode;
-typedef struct tagNodeLink NodeLink;
-typedef enum tagFillModeValue FillModeValue;
-typedef enum tagCullModeValue CullModeValue;
-typedef enum tagCompFuncValue CompFuncValue;
-typedef enum tagOpValue OpValue;
-typedef enum tagBlendOpValue BlendOpValue;
-typedef enum tagAddrModeValue AddrModeValue;
-typedef enum tagFilterValue FilterValue;
-typedef enum tagBufferUsageValue BufferUsageValue;
-
-enum tagNodeType
-{
-	NT_Shader,
-	NT_Technique,
-	NT_Parameters,
-	NT_Blocks,
-	NT_Pass,
-	NT_StencilOp,
-	NT_Target,
-	NT_BlendDef,
-	NT_SamplerState,
-	NT_AddrMode,
-	NT_Parameter,
-	NT_Block,
-	NT_Code
-};
-
-enum tagOptionType
-{
-	OT_None = 0,
-	OT_Separable,
-	OT_Priority,
-	OT_Queue,
-	OT_Transparent,
-	OT_Technique,
-	OT_Renderer,
-	OT_Language,
-	OT_Include,
-	OT_Pass,
-	OT_FillMode,
-	OT_CullMode,
-	OT_DepthBias,
-	OT_SDepthBias,
-	OT_DepthClip,
-	OT_Scissor,
-	OT_Multisample,
-	OT_AALine,
-	OT_DepthRead,
-	OT_DepthWrite,
-	OT_CompareFunc,
-	OT_Stencil,
-	OT_StencilReadMask,
-	OT_StencilWriteMask,
-	OT_StencilOpFront,
-	OT_StencilOpBack,
-	OT_PassOp,
-	OT_Fail,
-	OT_ZFail,
-	OT_AlphaToCoverage,
-	OT_IndependantBlend,
-	OT_Target,
-	OT_Index,
-	OT_Blend,
-	OT_Color,
-	OT_Alpha,
-	OT_WriteMask,
-	OT_Source,
-	OT_Dest,
-	OT_Op,
-	OT_AddrMode,
-	OT_MinFilter,
-	OT_MagFilter,
-	OT_MipFilter,
-	OT_MaxAniso,
-	OT_MipBias,
-	OT_MipMin,
-	OT_MipMax,
-	OT_BorderColor,
-	OT_U,
-	OT_V,
-	OT_W,
-	OT_Alias,
-	OT_Auto,
-	OT_Shared,
-	OT_Usage,
-	OT_ParamType,
-	OT_Identifier,
-	OT_ParamValue,
-	OT_Parameters,
-	OT_Blocks,
-	OT_Parameter,
-	OT_Block,
-	OT_SamplerState,
-	OT_Code,
-	OT_StencilRef
-};
-
-enum tagOptionDataType
-{
-	ODT_Int,
-	ODT_Float,
-	ODT_Bool,
-	ODT_String,
-	ODT_Complex,
-	ODT_Matrix
-};
-
-enum tagParamType
-{
-	PT_Float, PT_Float2, PT_Float3, PT_Float4, PT_Color,
-	PT_Mat2x2, PT_Mat2x3, PT_Mat2x4,
-	PT_Mat3x2, PT_Mat3x3, PT_Mat3x4,
-	PT_Mat4x2, PT_Mat4x3, PT_Mat4x4,
-	PT_Sampler1D, PT_Sampler2D, PT_Sampler3D, PT_SamplerCUBE, PT_Sampler2DMS,
-	PT_Texture1D, PT_Texture2D, PT_Texture3D, PT_TextureCUBE, PT_Texture2DMS,
-	PT_ByteBuffer, PT_StructBuffer, PT_ByteBufferRW, PT_StructBufferRW,
-	PT_TypedBufferRW, PT_AppendBuffer, PT_ConsumeBuffer,
-	PT_Count // Keep at end
-};
-
-enum tagFillModeValue 
-{ 
-	FMV_Wire, FMV_Solid 
-};
-
-enum tagCullModeValue 
-{ 
-	CMV_None, CMV_CW, CMV_CCW 
-};
-
-enum tagCompFuncValue
-{ 
-	CFV_Fail, CFV_Pass, CFV_LT, CFV_LTE, 
-	CFV_EQ, CFV_NEQ, CFV_GTE, CFV_GT
-};
-
-enum tagOpValue 
-{ 
-	OV_Keep, OV_Zero, OV_Replace, OV_Incr, OV_Decr, 
-	OV_IncrWrap, OV_DecrWrap, OV_Invert, OV_One, OV_DestColor, 
-	OV_SrcColor, OV_InvDestColor, OV_InvSrcColor, OV_DestAlpha, 
-	OV_SrcAlpha, OV_InvDestAlpha, OV_InvSrcAlpha
-};
-
-enum tagBlendOpValue 
-{ 
-	BOV_Add, BOV_Subtract, BOV_RevSubtract, 
-	BOV_Min, BOV_Max 
-};
-
-enum tagAddrModeValue
-{
-	AMV_Wrap, AMV_Mirror, AMV_Clamp, AMV_Border
-};
-
-enum tagFilterValue 
-{ 
-	FV_None, FV_Point, FV_Linear, FV_Anisotropic, 
-	FV_PointCmp, FV_LinearCmp, FV_AnisotropicCmp 
-};
-
-enum tagBufferUsageValue 
-{ 
-	BUV_Static, BUV_Dynamic 
-};
-
-struct tagNodeLink
-{
-	ASTFXNode* node;
-	NodeLink* next;
-};
-
-struct tagParseState
-{
-	ASTFXNode* rootNode;
-	ASTFXNode* topNode;
-	void* memContext;
-
-	int hasError;
-	int errorLine;
-	int errorColumn;
-	const char* errorMessage;
-
-	NodeLink* nodeStack;
-};
-
-struct tagOptionInfo
-{
-	OptionType type;
-	OptionDataType dataType;
-};
-
-union tagOptionData
-{
-	int intValue;
-	float floatValue;
-	const char* strValue;
-	float matrixValue[16];
-	ASTFXNode* nodePtr;
-};
-
-struct tagNodeOption
-{
-	OptionType type;
-	OptionData value;
-};
-
-struct tagNodeOptions
-{
-	NodeOption* entries;
-
-	int count;
-	int bufferSize;
-};
-
-struct tagASTFXNode
-{
-	NodeType type;
-	NodeOptions* options;
-};
-
-OptionInfo OPTION_LOOKUP[];
-
-NodeOptions* nodeOptionsCreate(void* context);
-void nodeOptionDelete(NodeOption* option);
-void nodeOptionsDelete(NodeOptions* options);
-void nodeOptionsResize(void* context, NodeOptions* options, int size);
-void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options);
-void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option);
-
-ASTFXNode* nodeCreate(void* context, NodeType type);
-void nodeDelete(ASTFXNode* node);
-
-void nodePush(ParseState* parseState, ASTFXNode* node);
-void nodePop(ParseState* parseState);
-
-ParseState* parseStateCreate();
-void parseStateDelete(ParseState* parseState);
-
+#ifndef __ASTFX_H__
+#define __ASTFX_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef enum tagNodeType NodeType;
+typedef enum tagOptionType OptionType;
+typedef enum tagOptionDataType OptionDataType;
+typedef enum tagParamType ParamType;
+typedef struct tagParseState ParseState;
+typedef struct tagOptionInfo OptionInfo;
+typedef union tagOptionData OptionData;
+typedef struct tagNodeOptions NodeOptions;
+typedef struct tagNodeOption NodeOption;
+typedef struct tagASTFXNode ASTFXNode;
+typedef struct tagNodeLink NodeLink;
+typedef enum tagFillModeValue FillModeValue;
+typedef enum tagCullModeValue CullModeValue;
+typedef enum tagCompFuncValue CompFuncValue;
+typedef enum tagOpValue OpValue;
+typedef enum tagBlendOpValue BlendOpValue;
+typedef enum tagAddrModeValue AddrModeValue;
+typedef enum tagFilterValue FilterValue;
+typedef enum tagBufferUsageValue BufferUsageValue;
+
+enum tagNodeType
+{
+	NT_Shader,
+	NT_Technique,
+	NT_Parameters,
+	NT_Blocks,
+	NT_Pass,
+	NT_StencilOp,
+	NT_Target,
+	NT_BlendDef,
+	NT_SamplerState,
+	NT_AddrMode,
+	NT_Parameter,
+	NT_Block,
+	NT_Code
+};
+
+enum tagOptionType
+{
+	OT_None = 0,
+	OT_Separable,
+	OT_Priority,
+	OT_Queue,
+	OT_Transparent,
+	OT_Technique,
+	OT_Renderer,
+	OT_Language,
+	OT_Include,
+	OT_Pass,
+	OT_FillMode,
+	OT_CullMode,
+	OT_DepthBias,
+	OT_SDepthBias,
+	OT_DepthClip,
+	OT_Scissor,
+	OT_Multisample,
+	OT_AALine,
+	OT_DepthRead,
+	OT_DepthWrite,
+	OT_CompareFunc,
+	OT_Stencil,
+	OT_StencilReadMask,
+	OT_StencilWriteMask,
+	OT_StencilOpFront,
+	OT_StencilOpBack,
+	OT_PassOp,
+	OT_Fail,
+	OT_ZFail,
+	OT_AlphaToCoverage,
+	OT_IndependantBlend,
+	OT_Target,
+	OT_Index,
+	OT_Blend,
+	OT_Color,
+	OT_Alpha,
+	OT_WriteMask,
+	OT_Source,
+	OT_Dest,
+	OT_Op,
+	OT_AddrMode,
+	OT_MinFilter,
+	OT_MagFilter,
+	OT_MipFilter,
+	OT_MaxAniso,
+	OT_MipBias,
+	OT_MipMin,
+	OT_MipMax,
+	OT_BorderColor,
+	OT_U,
+	OT_V,
+	OT_W,
+	OT_Alias,
+	OT_Auto,
+	OT_Shared,
+	OT_Usage,
+	OT_ParamType,
+	OT_Identifier,
+	OT_ParamValue,
+	OT_ParamStrValue,
+	OT_Parameters,
+	OT_Blocks,
+	OT_Parameter,
+	OT_Block,
+	OT_SamplerState,
+	OT_Code,
+	OT_StencilRef
+};
+
+enum tagOptionDataType
+{
+	ODT_Int,
+	ODT_Float,
+	ODT_Bool,
+	ODT_String,
+	ODT_Complex,
+	ODT_Matrix
+};
+
+enum tagParamType
+{
+	PT_Float, PT_Float2, PT_Float3, PT_Float4, PT_Color,
+	PT_Mat2x2, PT_Mat2x3, PT_Mat2x4,
+	PT_Mat3x2, PT_Mat3x3, PT_Mat3x4,
+	PT_Mat4x2, PT_Mat4x3, PT_Mat4x4,
+	PT_Sampler1D, PT_Sampler2D, PT_Sampler3D, PT_SamplerCUBE, PT_Sampler2DMS,
+	PT_Texture1D, PT_Texture2D, PT_Texture3D, PT_TextureCUBE, PT_Texture2DMS,
+	PT_ByteBuffer, PT_StructBuffer, PT_ByteBufferRW, PT_StructBufferRW,
+	PT_TypedBufferRW, PT_AppendBuffer, PT_ConsumeBuffer,
+	PT_Count // Keep at end
+};
+
+enum tagFillModeValue 
+{ 
+	FMV_Wire, FMV_Solid 
+};
+
+enum tagCullModeValue 
+{ 
+	CMV_None, CMV_CW, CMV_CCW 
+};
+
+enum tagCompFuncValue
+{ 
+	CFV_Fail, CFV_Pass, CFV_LT, CFV_LTE, 
+	CFV_EQ, CFV_NEQ, CFV_GTE, CFV_GT
+};
+
+enum tagOpValue 
+{ 
+	OV_Keep, OV_Zero, OV_Replace, OV_Incr, OV_Decr, 
+	OV_IncrWrap, OV_DecrWrap, OV_Invert, OV_One, OV_DestColor, 
+	OV_SrcColor, OV_InvDestColor, OV_InvSrcColor, OV_DestAlpha, 
+	OV_SrcAlpha, OV_InvDestAlpha, OV_InvSrcAlpha
+};
+
+enum tagBlendOpValue 
+{ 
+	BOV_Add, BOV_Subtract, BOV_RevSubtract, 
+	BOV_Min, BOV_Max 
+};
+
+enum tagAddrModeValue
+{
+	AMV_Wrap, AMV_Mirror, AMV_Clamp, AMV_Border
+};
+
+enum tagFilterValue 
+{ 
+	FV_None, FV_Point, FV_Linear, FV_Anisotropic, 
+	FV_PointCmp, FV_LinearCmp, FV_AnisotropicCmp 
+};
+
+enum tagBufferUsageValue 
+{ 
+	BUV_Static, BUV_Dynamic 
+};
+
+struct tagNodeLink
+{
+	ASTFXNode* node;
+	NodeLink* next;
+};
+
+struct tagParseState
+{
+	ASTFXNode* rootNode;
+	ASTFXNode* topNode;
+	void* memContext;
+
+	int hasError;
+	int errorLine;
+	int errorColumn;
+	const char* errorMessage;
+
+	NodeLink* nodeStack;
+};
+
+struct tagOptionInfo
+{
+	OptionType type;
+	OptionDataType dataType;
+};
+
+union tagOptionData
+{
+	int intValue;
+	float floatValue;
+	const char* strValue;
+	float matrixValue[16];
+	ASTFXNode* nodePtr;
+};
+
+struct tagNodeOption
+{
+	OptionType type;
+	OptionData value;
+};
+
+struct tagNodeOptions
+{
+	NodeOption* entries;
+
+	int count;
+	int bufferSize;
+};
+
+struct tagASTFXNode
+{
+	NodeType type;
+	NodeOptions* options;
+};
+
+OptionInfo OPTION_LOOKUP[];
+
+NodeOptions* nodeOptionsCreate(void* context);
+void nodeOptionDelete(NodeOption* option);
+void nodeOptionsDelete(NodeOptions* options);
+void nodeOptionsResize(void* context, NodeOptions* options, int size);
+void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options);
+void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option);
+
+ASTFXNode* nodeCreate(void* context, NodeType type);
+void nodeDelete(ASTFXNode* node);
+
+void nodePush(ParseState* parseState, ASTFXNode* node);
+void nodePop(ParseState* parseState);
+
+ParseState* parseStateCreate();
+void parseStateDelete(ParseState* parseState);
+
 #endif
 #endif

+ 323 - 371
BansheeSL/Include/BsSLFXCompiler.h

@@ -1,372 +1,324 @@
-#pragma once
-
-#include "BsSLPrerequisites.h"
-#include "BsShader.h"
-#include "BsGpuProgram.h"
-#include "BsRasterizerState.h"
-#include "BsDepthStencilState.h"
-#include "BsBlendState.h"
-
-extern "C" {
-#include "BsASTFX.h"
-}
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Contains the results of compilation returned from the BSLFXCompiler.
-	 */
-	struct BSLFXCompileResult
-	{
-		ShaderPtr shader; /**< Resulting shader if compilation was successful. Null if error occurred. */
-		String errorMessage; /**< Error message if compilation failed. */
-		int errorLine = 0; /**< Line of the error if one occurred. */
-		int errorColumn = 0; /**< Column of the error if one occurred. */
-	};
-
-	/**
-	 * @brief	Transforms a source file written in BSL FX syntax into a Shader object.
-	 */
-	class BSLFXCompiler
-	{
-		/**
-		 * @brief	Possible types of code blocks within a shader.
-		 */
-		enum class CodeBlockType
-		{
-			Vertex, Fragment, Geometry, Hull, Domain, Compute, Common
-		};
-
-		/**
-		 * @brief	Represents a block of code written in a GPU program language for
-		 *			a specific GPU program type. (i.e. non-FX code)
-		 */
-		struct CodeBlock
-		{
-			CodeBlockType type;
-			String code;
-		};
-
-		/**
-		 * @brief	Temporary data describing a pass during parsing.
-		 */
-		struct PassData
-		{
-			BLEND_STATE_DESC blendDesc;
-			RASTERIZER_STATE_DESC rasterizerDesc;
-			DEPTH_STENCIL_STATE_DESC depthStencilDesc;
-
-			bool blendIsDefault = true;
-			bool rasterizerIsDefault = true;
-			bool depthStencilIsDefault = true;
-
-			String commonCode;
-			String vertexCode;
-			String fragmentCode;
-			String geometryCode;
-			String hullCode;
-			String domainCode;
-			String computeCode;
-		};
-
-	public:
-		/**
-		 * @brief	Transforms a source file written in BSL FX syntax into a Shader object.
-		 */
-		static BSLFXCompileResult compile(const String& source);
-
-	private:
-		/**
-		 * @brief	Converts the provided source into an abstract syntax tree using the
-		 *			lexer & parser for BSL FX syntax.
-		 */
-		static void parseFX(ParseState* parseState, const char* source);
-
-		/**
-		 * @brief	Retrieves non-FX code blocks (i.e. actual shader code) from the source code and
-		 *			removes them from the input so all that remains is a pure FX code. Found blocks
-		 *			are returned so they may be compiled using their appropriate compiler.
-		 */
-		static Vector<CodeBlock> parseCodeBlocks(String& source);
-
-		/**
-		 * @brief	Merges two shader AST nodes. The first node will contain the 
-		 *			combination of both after the method executes.
-		 *
-		 * @param	mergeInto		Parse state containing the node to be merged into.
-		 * @param	mergeFrom		Second of the nodes to be merged. All the contents of this node
-		 *							will be merged into the first node. This node and its children will
-		 *							remain unmodified.
-		 * @param	codeBlockOffset	Offset to apply to any code block indexes belonging to the second node.
-		 */
-		static void mergeAST(ParseState* mergeInto, ASTFXNode* mergeFrom, UINT32 codeBlockOffset);
-
-		/**
-		 * @brief	Finds the blocks node in the root node of the provided parse state, and merges any entries
-		 *			from "blocksNode" into it. A new node is created if one doesn't exist.
-		 */
-		static void mergeBlocks(ParseState* mergeInto, ASTFXNode* blocksNode);
-
-		/**
-		 * @brief	Finds the parameters node in the root node of the provided parse state, and merges any entries
-		 *			from "paramsNode" into it. A new node is created if one doesn't exist.
-		 */
-		static void mergeParameters(ParseState* mergeInto, ASTFXNode* paramsNode);
-
-		/**
-		 * @brief	Retrieves the renderer and language specified for the technique. These two values are considered
-		 *			a unique identifier for a technique.
-		 */
-		static void getTechniqueIdentifier(ASTFXNode* technique, StringID& renderer, String& language);
-
-		/**
-		 * @brief	Checks if two techniques can be matched based on the options
-		 *			specified in their child nodes.
-		 */
-		static bool isTechniqueMergeValid(ASTFXNode* into, ASTFXNode* from);
-
-		/**
-		 * @brief	Copies an existing AST node option and inserts it into another node options list.
-		 *
-		 * @param	into	Parse state of the into which the node option will be inserted to.
-		 * @param	parent	A set of node options to insert the node option copy into.
-		 * @param	option	Node option to copy.
-		 *
-		 * @returns	True if the copied node was a complex type.
-		 */
-		static bool copyNodeOption(ParseState* into, NodeOptions* parent, NodeOption* option);
-
-		/**
-		 * @brief	Merges pass states and code blocks. All code blocks from "mergeFromNode" 
-		 *			will have their indexes incremented by "codeBlockOffset".
-		 */
-		static void mergePass(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, UINT32 codeBlockOffset);
-
-		/**
-		 * @brief	Merges code blocks. All code blocks from "mergeFromNode"
-		 *			will have their indexes incremented by "codeBlockOffset".
-		 */
-		static void mergeCode(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, UINT32 codeBlockOffset);
-
-		/**
-		 * @brief	Merges all pass states by copying all child nodes and their options to the destination node. 
-		 *			
-		 * @note	Certain node types are ignored as we handle their merging specially.
-		 *			Should only be called on Technique nodes or its children.
-		 */
-		static void mergePassStates(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode);
-
-		/**
-		 * @brief	Merges two techniques. All technique states, code blocks and passes will be merged.
-		 *			Passes will be merged according to the pass index (new passes will be inserted if the destination
-		 *			doesn't already have a pass with an index belonging to the source pass). 
-		 *			All code blocks from "mergeFromNode" will have their indexes incremented by "codeBlockOffset".
-		 */
-		static void mergeTechnique(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, UINT32 codeBlockOffset);
-
-		/**
-		 * @brief	Find matching techniques from the root shader node in "mergeInto" and merges them with "techniqueNode".
-		 *			All code blocks from "mergeFromNode" will have their indexes incremented by "codeBlockOffset".
-		 *
-		 * @see		BSLFXCompiler::mergeTechnique
-		 */
-		static void mergeTechniques(ParseState* mergeInto, ASTFXNode* techniqueNode, UINT32 codeBlockOffset);
-
-		/**
-		 * @brief	Converts FX renderer name into an in-engine renderer identifier.
-		 */
-		static StringID parseRenderer(const String& name);
-
-		/**
-		 * @brief	Converts FX language into an in-engine shader language (e.g. hlsl, glsl) and
-		 *			a rendering API that supports the provided language.
-		 */
-		static void parseLanguage(const String& name, StringID& renderAPI, String& language);
-
-		/**
-		 * @brief	Maps FX buffer usage enum into in-engine param block usage.
-		 */
-		static GpuParamBlockUsage parseBlockUsage(BufferUsageValue usage);
-
-		/**
-		 * @brief	Maps FX filter mode enum into in-engine filter mode.
-		 */
-		static UINT32 parseFilterMode(FilterValue filter);
-
-		/**
-		 * @brief	Maps FX comparison function enum into in-engine compare function.
-		 */
-		static CompareFunction parseCompFunc(CompFuncValue compFunc);
-
-		/**
-		 * @brief	Maps FX addressing mode enum into in-engine addressing mode.
-		 */
-		static TextureAddressingMode parseAddrMode(AddrModeValue addrMode);
-
-		/**
-		 * @brief	Maps FX operation to in-engine blend factor.
-		 */
-		static BlendFactor parseBlendFactor(OpValue factor);
-
-		/**
-		 * @brief	Maps FX blend operation to in-engine blend operation.
-		 */
-		static BlendOperation parseBlendOp(BlendOpValue op);
-
-		/**
-		 * @brief	Maps FX parameter type to in-engine shader parameter.
-		 *
-		 * @param	type		Input FX parameter type.
-		 * @param	isObjType	Output parameter signaling whether the in-engine parameter is
-		 *						a data or an object type.
-		 * @param	typeId		Type ID corresponding to a value of in-game GpuParamDataType or GpuParamObjectType
-		 *						enum (depending on "isObjType").
-		 */
-		static void parseParamType(ParamType type, bool& isObjType, UINT32& typeId);
-
-		/**
-		 * @brief	Maps FX operation to in-engine stencil operation.
-		 */
-		static StencilOperation parseStencilOp(OpValue op);
-		
-		/**
-		 * @brief	Maps FX cull mode enum to in-engine cull mode.
-		 */
-		static CullingMode parseCullMode(CullModeValue cm);
-
-		/**
-		 * @brief	Maps FX fill mode enum to in-engine fill mode.
-		 */
-		static PolygonMode parseFillMode(FillModeValue fm);
-
-		/**
-		 * @brief	Populates the front facing operation portion of the depth-stencil state descriptor
-		 *			from the provided stencil-op AST node.
-		 */
-		static void parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
-
-		/**
-		 * @brief	Populates the back backing operation portion of the depth-stencil state descriptor
-		 *			from the provided stencil-op AST node.
-		 */
-		static void parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
-
-		/**
-		 * @brief	Populates the addressing mode portion of the sampler state descriptor for U/V/W axes from
-		 *			the provided addressing mode AST node.
-		 */
-		static void parseAddrMode(SAMPLER_STATE_DESC& desc, ASTFXNode* addrModeNode);
-
-		/**
-		 * @brief	Populates the color (RGB) portion of the blend state descriptor from the provided
-		 *			blend definition AST node.
-		 */
-		static void parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
-
-		/**
-		 * @brief	Populates the alpha portion of the blend state descriptor from the provided
-		 *			blend definition AST node.
-		 */
-		static void parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
-
-		/**
-		 * @brief	Populates blend state descriptor for a single render target from the provided
-		 *			AST node. Which target gets updated depends on the index set in the AST node.
-		 */
-		static void parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode);
-
-		/**
-		 * @brief	Parses the blend state AST node and outputs a blend state descriptor. Returns false
-		 *			if the descriptor wasn't modified.
-		 */
-		static bool parseBlendState(BLEND_STATE_DESC& desc, ASTFXNode* passNode);
-
-		/**
-		 * @brief	Parses the rasterizer state AST node and outputs a rasterizer state descriptor. Returns false
-		 *			if the descriptor wasn't modified.
-		 */
-		static bool parseRasterizerState(RASTERIZER_STATE_DESC& desc, ASTFXNode* passNode);
-
-		/**
-		 * @brief	Parses the depth-stencil state AST node and outputs a depth-stencil state descriptor. Returns false
-		 *			if the descriptor wasn't modified.
-		 */
-		static bool parseDepthStencilState(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* passNode);
-
-		/**
-		 * @brief	Parses the sampler state AST node and outputs a sampler state object, or a nullptr
-		 *			in case AST node is empty. 
-		 */
-		static SamplerStatePtr parseSamplerState(ASTFXNode* samplerStateNode);
-
-		/**
-		 * @brief	Parses a code AST node and outputs the result in one of the streams within the
-		 *			provided pass data.
-		 *
-		 * @param	codeNode	AST node to parse
-		 * @param	codeBlocks	GPU program source code retrieved from "parseCodeBlocks".
-		 * @param	passData	Pass data containing temporary pass data, including the code streams
-		 *						that the code block code will be written to.
-		 */
-		static void parseCodeBlock(ASTFXNode* codeNode, const Vector<CodeBlock>& codeBlocks, PassData& passData);
-
-		/**
-		 * @brief	Parses the pass AST node and generates a single pass object. Returns null
-		 *			if no pass can be parsed. This method will generate any child state objects and
-		 *			compile any child GPU programs.
-		 *
-		 * @param	passNode		Node to parse.
-		 * @param	codeBlocks		GPU program source code retrieved from "parseCodeBlocks".
-		 * @param	passData		Data containing pass render state descriptors.
-		 * @param	renderAPI		API to use for compiling the GPU programs.
-		 * @param	language		GPU program language to use for parsing the provided code blocks.
-		 * @param	seqIdx			Output sequential index of the pass that determines its rendering order.
-		 */
-		static PassPtr parsePass(ASTFXNode* passNode, const Vector<CodeBlock>& codeBlocks, PassData& passData, 
-			const StringID& renderAPI, const String& language, UINT32& seqIdx);
-
-		/**
-		 * @brief	Parses the technique AST node and generates a single technique object. Returns null
-		 *			if no technique can be parsed.
-		 *
-		 * @param	techniqueNode	Node to parse.
-		 * @param	codeBlocks		GPU program source code retrieved from "parseCodeBlocks".
-		 */
-		static TechniquePtr parseTechnique(ASTFXNode* techniqueNode, const Vector<CodeBlock>& codeBlocks);
-
-		/**
-		 * @brief	Parses the parameters AST node and populates the shader descriptor with information
-		 *			about GPU program parameters and their default values.
-		 */
-		static void parseParameters(SHADER_DESC& desc, ASTFXNode* parametersNode);
-
-		/**
-		 * @brief	Parses the blocks AST node and populates the shader descriptor with information
-		 *			about GPU program parameter blocks.
-		 */
-		static void parseBlocks(SHADER_DESC& desc, ASTFXNode* blocksNode);
-
-		/**
-		 * @brief	Parses the AST node hierarchy and generates a shader object.
-		 *
-		 * @param	name		Optional name for the shader.
-		 * @param	parseState	Parser state object that has previously been initialized with the
-		 *						AST using "parseFX".
-		 * @param	codeBlocks	GPU program source code retrieved from "parseCodeBlocks".
-		 *
-		 * @return	A result object containing the shader if successful, or error message if not.
-		 */
-		static BSLFXCompileResult parseShader(const String& name, ParseState* parseState, Vector<CodeBlock>& codeBlocks);
-
-		/**
-		 * @brief	Converts a null-terminated string into a standard string, and eliminates quotes that are assumed
-		 *			to be at the first and last index.
-		 */
-		static String removeQuotes(const char* input);
-
-		/**
-		 * @brief	Retrieves a GPU program profile to use with the specified API and GPU program type.
-		 */
-		static GpuProgramProfile getProfile(const StringID& renderAPI, GpuProgramType type);
-	};
+#pragma once
+
+#include "BsSLPrerequisites.h"
+#include "BsShader.h"
+#include "BsGpuProgram.h"
+#include "BsRasterizerState.h"
+#include "BsDepthStencilState.h"
+#include "BsBlendState.h"
+
+extern "C" {
+#include "BsASTFX.h"
+}
+
+namespace BansheeEngine
+{
+	/**	Contains the results of compilation returned from the BSLFXCompiler. */
+	struct BSLFXCompileResult
+	{
+		ShaderPtr shader; /**< Resulting shader if compilation was successful. Null if error occurred. */
+		String errorMessage; /**< Error message if compilation failed. */
+		int errorLine = 0; /**< Line of the error if one occurred. */
+		int errorColumn = 0; /**< Column of the error if one occurred. */
+	};
+
+	/**	Transforms a source file written in BSL FX syntax into a Shader object. */
+	class BSLFXCompiler
+	{
+		/**	Possible types of code blocks within a shader. */
+		enum class CodeBlockType
+		{
+			Vertex, Fragment, Geometry, Hull, Domain, Compute, Common
+		};
+
+		/**
+		 * Represents a block of code written in a GPU program language for a specific GPU program type. (i.e. non-FX code)
+		 */
+		struct CodeBlock
+		{
+			CodeBlockType type;
+			String code;
+		};
+
+		/**	Temporary data describing a pass during parsing. */
+		struct PassData
+		{
+			BLEND_STATE_DESC blendDesc;
+			RASTERIZER_STATE_DESC rasterizerDesc;
+			DEPTH_STENCIL_STATE_DESC depthStencilDesc;
+
+			bool blendIsDefault = true;
+			bool rasterizerIsDefault = true;
+			bool depthStencilIsDefault = true;
+
+			String commonCode;
+			String vertexCode;
+			String fragmentCode;
+			String geometryCode;
+			String hullCode;
+			String domainCode;
+			String computeCode;
+		};
+
+	public:
+		/**	Transforms a source file written in BSL FX syntax into a Shader object. */
+		static BSLFXCompileResult compile(const String& source);
+
+	private:
+		/** Converts the provided source into an abstract syntax tree using the lexer & parser for BSL FX syntax. */
+		static void parseFX(ParseState* parseState, const char* source);
+
+		/**
+		 * Retrieves non-FX code blocks (i.e. actual shader code) from the source code and removes them from the input so 
+		 * all that remains is a pure FX code. Found blocks are returned so they may be compiled using their appropriate 
+		 * compiler.
+		 */
+		static Vector<CodeBlock> parseCodeBlocks(String& source);
+
+		/**
+		 * Merges two shader AST nodes. The first node will contain the combination of both after the method executes.
+		 *
+		 * @param[in, out]	mergeInto		Parse state containing the node to be merged into.
+		 * @param[in]		mergeFrom		Second of the nodes to be merged. All the contents of this node will be merged
+		 *									into the first node. This node and its children will remain unmodified.
+		 * @param[in]		codeBlockOffset	Offset to apply to any code block indexes belonging to the second node.
+		 */
+		static void mergeAST(ParseState* mergeInto, ASTFXNode* mergeFrom, UINT32 codeBlockOffset);
+
+		/**
+		 * Finds the blocks node in the root node of the provided parse state, and merges any entries from @p blocksNode
+		 * into it. A new node is created if one doesn't exist.
+		 */
+		static void mergeBlocks(ParseState* mergeInto, ASTFXNode* blocksNode);
+
+		/**
+		 * Finds the parameters node in the root node of the provided parse state, and merges any entries from 
+		 * @p paramsNode into it. A new node is created if one doesn't exist.
+		 */
+		static void mergeParameters(ParseState* mergeInto, ASTFXNode* paramsNode);
+
+		/**
+		 * Retrieves the renderer and language specified for the technique. These two values are considered a unique 
+		 * identifier for a technique.
+		 */
+		static void getTechniqueIdentifier(ASTFXNode* technique, StringID& renderer, String& language);
+
+		/** Checks if two techniques can be matched based on the options specified in their child nodes. */
+		static bool isTechniqueMergeValid(ASTFXNode* into, ASTFXNode* from);
+
+		/**
+		 * Copies an existing AST node option and inserts it into another node options list.
+		 *
+		 * @param[in, out]	into	Parse state of the into which the node option will be inserted to.
+		 * @param[in]		parent	A set of node options to insert the node option copy into.
+		 * @param[in]		option	Node option to copy.
+		 * @return					True if the copied node was a complex type.
+		 */
+		static bool copyNodeOption(ParseState* into, NodeOptions* parent, NodeOption* option);
+
+		/**
+		 * Merges pass states and code blocks. All code blocks from @p mergeFromNode will have their indexes incremented by
+		 * @p codeBlockOffset.
+		 */
+		static void mergePass(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, 
+			UINT32 codeBlockOffset);
+
+		/**
+		 * Merges code blocks. All code blocks from @p mergeFromNode will have their indexes incremented by 
+		 * @p codeBlockOffset.
+		 */
+		static void mergeCode(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, 
+			UINT32 codeBlockOffset);
+
+		/**
+		 * Merges all pass states by copying all child nodes and their options to the destination node. 
+		 *			
+		 * @note	
+		 * Certain node types are ignored as we handle their merging specially. Should only be called on Technique nodes or
+		 * its children.
+		 */
+		static void mergePassStates(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode);
+
+		/**
+		 * Merges two techniques. All technique states, code blocks and passes will be merged. Passes will be merged 
+		 * according to the pass index (new passes will be inserted if the destination doesn't already have a pass with an
+		 * index belonging to the source pass). All code blocks from @p mergeFromNode will have their indexes incremented
+		 * by @p codeBlockOffset.
+		 */
+		static void mergeTechnique(ParseState* mergeInto, ASTFXNode* mergeIntoNode, ASTFXNode* mergeFromNode, 
+			UINT32 codeBlockOffset);
+
+		/**
+		 * Find matching techniques from the root shader node in @p mergeInto and merges them with @p techniqueNode.
+		 * All code blocks from @p techniqueNode will have their indexes incremented by @p codeBlockOffset.
+		 *
+		 * @see		BSLFXCompiler::mergeTechnique
+		 */
+		static void mergeTechniques(ParseState* mergeInto, ASTFXNode* techniqueNode, UINT32 codeBlockOffset);
+
+		/**	Converts FX renderer name into an in-engine renderer identifier. */
+		static StringID parseRenderer(const String& name);
+
+		/**
+		 * Converts FX language into an in-engine shader language (e.g. hlsl, glsl) and a rendering API that supports the
+		 * provided language.
+		 */
+		static void parseLanguage(const String& name, StringID& renderAPI, String& language);
+
+		/**	Maps FX buffer usage enum into in-engine param block usage. */
+		static GpuParamBlockUsage parseBlockUsage(BufferUsageValue usage);
+
+		/**	Maps FX filter mode enum into in-engine filter mode. */
+		static UINT32 parseFilterMode(FilterValue filter);
+
+		/**	Maps FX comparison function enum into in-engine compare function. */
+		static CompareFunction parseCompFunc(CompFuncValue compFunc);
+
+		/**	Maps FX addressing mode enum into in-engine addressing mode. */
+		static TextureAddressingMode parseAddrMode(AddrModeValue addrMode);
+
+		/**	Maps FX operation to in-engine blend factor. */
+		static BlendFactor parseBlendFactor(OpValue factor);
+
+		/**	Maps FX blend operation to in-engine blend operation. */
+		static BlendOperation parseBlendOp(BlendOpValue op);
+
+		/**
+		 * Maps FX parameter type to in-engine shader parameter.
+		 *
+		 * @param[in]	type		Input FX parameter type.
+		 * @param[in]	isObjType	Output parameter signaling whether the in-engine parameter is a data or an object type.
+		 * @param[in]	typeId		Type ID corresponding to a value of in-game GpuParamDataType or GpuParamObjectType
+		 *							enum (depending on isObjType()).
+		 */
+		static void parseParamType(ParamType type, bool& isObjType, UINT32& typeId);
+
+		/**	Maps FX operation to in-engine stencil operation. */
+		static StencilOperation parseStencilOp(OpValue op);
+		
+		/**	Maps FX cull mode enum to in-engine cull mode. */
+		static CullingMode parseCullMode(CullModeValue cm);
+
+		/**	Maps FX fill mode enum to in-engine fill mode. */
+		static PolygonMode parseFillMode(FillModeValue fm);
+
+		/**
+		 * Populates the front facing operation portion of the depth-stencil state descriptor from the provided stencil-op
+		 * AST node.
+		 */
+		static void parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
+
+		/**
+		 * Populates the back backing operation portion of the depth-stencil state descriptor from the provided stencil-op
+		 * AST node.
+		 */
+		static void parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode);
+
+		/**
+		 * Populates the addressing mode portion of the sampler state descriptor for U/V/W axes from the provided addressing
+		 * mode AST node.
+		 */
+		static void parseAddrMode(SAMPLER_STATE_DESC& desc, ASTFXNode* addrModeNode);
+
+		/** Populates the color (RGB) portion of the blend state descriptor from the provided blend definition AST node. */
+		static void parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
+
+		/** Populates the alpha portion of the blend state descriptor from the provided blend definition AST node. */
+		static void parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode);
+
+		/**
+		 * Populates blend state descriptor for a single render target from the provided AST node. Which target gets 
+		 * updated depends on the index set in the AST node.
+		 */
+		static void parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode);
+
+		/**
+		 * Parses the blend state AST node and outputs a blend state descriptor. Returns false if the descriptor wasn't 
+		 * modified.
+		 */
+		static bool parseBlendState(BLEND_STATE_DESC& desc, ASTFXNode* passNode);
+
+		/**
+		 * Parses the rasterizer state AST node and outputs a rasterizer state descriptor. Returns false if the descriptor
+		 * wasn't modified.
+		 */
+		static bool parseRasterizerState(RASTERIZER_STATE_DESC& desc, ASTFXNode* passNode);
+
+		/**
+		 * Parses the depth-stencil state AST node and outputs a depth-stencil state descriptor. Returns false if the 
+		 * descriptor wasn't modified.
+		 */
+		static bool parseDepthStencilState(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* passNode);
+
+		/** Parses the sampler state AST node and outputs a sampler state object, or a nullptr in case AST node is empty. */
+		static SamplerStatePtr parseSamplerState(ASTFXNode* samplerStateNode);
+
+		/**
+		 * Parses a code AST node and outputs the result in one of the streams within the provided pass data.
+		 *
+		 * @param[in]	codeNode	AST node to parse
+		 * @param[in]	codeBlocks	GPU program source code retrieved from parseCodeBlocks().
+		 * @param[in]	passData	Pass data containing temporary pass data, including the code streams that the code 
+		 *							block code will be written to.
+		 */
+		static void parseCodeBlock(ASTFXNode* codeNode, const Vector<CodeBlock>& codeBlocks, PassData& passData);
+
+		/**
+		 * Parses the pass AST node and generates a single pass object. Returns null if no pass can be parsed. This method
+		 * will generate any child state objects and compile any child GPU programs.
+		 *
+		 * @param[in]	passNode		Node to parse.
+		 * @param[in]	codeBlocks		GPU program source code retrieved from parseCodeBlocks().
+		 * @param[in]	passData		Data containing pass render state descriptors.
+		 * @param[in]	renderAPI		API to use for compiling the GPU programs.
+		 * @param[in]	language		GPU program language to use for parsing the provided code blocks.
+		 * @param[in]	seqIdx			Output sequential index of the pass that determines its rendering order.
+		 */
+		static PassPtr parsePass(ASTFXNode* passNode, const Vector<CodeBlock>& codeBlocks, PassData& passData, 
+			const StringID& renderAPI, const String& language, UINT32& seqIdx);
+
+		/**
+		 * Parses the technique AST node and generates a single technique object. Returns null if no technique can be 
+		 * parsed.
+		 *
+		 * @param[in]	techniqueNode	Node to parse.
+		 * @param[in]	codeBlocks		GPU program source code retrieved from parseCodeBlocks().
+		 */
+		static TechniquePtr parseTechnique(ASTFXNode* techniqueNode, const Vector<CodeBlock>& codeBlocks);
+
+		/**
+		 * Parses the parameters AST node and populates the shader descriptor with information about GPU program parameters
+		 * and their default values.
+		 */
+		static void parseParameters(SHADER_DESC& desc, ASTFXNode* parametersNode);
+
+		/**
+		 * Parses the blocks AST node and populates the shader descriptor with information about GPU program parameter 
+		 * blocks.
+		 */
+		static void parseBlocks(SHADER_DESC& desc, ASTFXNode* blocksNode);
+
+		/**
+		 * Parses the AST node hierarchy and generates a shader object.
+		 *
+		 * @param[in]		name		Optional name for the shader.
+		 * @param[in, out]	parseState	Parser state object that has previously been initialized with the AST using 
+		 *								parseFX().
+		 * @param	codeBlocks			GPU program source code retrieved from parseCodeBlocks().
+		 * @return						A result object containing the shader if successful, or error message if not.
+		 */
+		static BSLFXCompileResult parseShader(const String& name, ParseState* parseState, Vector<CodeBlock>& codeBlocks);
+
+		/**
+		 * Converts a null-terminated string into a standard string, and eliminates quotes that are assumed to be at the 
+		 * first and last index.
+		 */
+		static String removeQuotes(const char* input);
+
+		/**	Retrieves a GPU program profile to use with the specified API and GPU program type. */
+		static GpuProgramProfile getProfile(const StringID& renderAPI, GpuProgramType type);
+
+		/** Returns one of the builtin textures based on their name. */
+		static HTexture getBuiltinTexture(const String& name);
+	};
 }
 }

+ 224 - 223
BansheeSL/Source/BsASTFX.c

@@ -1,224 +1,225 @@
-#include "BsASTFX.h"
-#include "BsMMAlloc.h"
-
-OptionInfo OPTION_LOOKUP[] =
-{
-	{ OT_None, ODT_Int },
-	{ OT_Separable, ODT_Bool },
-	{ OT_Priority, ODT_Int },
-	{ OT_Queue, ODT_Int },
-	{ OT_Transparent, ODT_Bool },
-	{ OT_Technique, ODT_Complex }, 
-	{ OT_Renderer, ODT_String }, 
-	{ OT_Language, ODT_String }, 
-	{ OT_Include, ODT_String }, 
-	{ OT_Pass, ODT_Complex }, 
-	{ OT_FillMode, ODT_Int }, 
-	{ OT_CullMode, ODT_Int },
-	{ OT_DepthBias, ODT_Float },
-	{ OT_SDepthBias, ODT_Float },
-	{ OT_DepthClip, ODT_Bool },
-	{ OT_Scissor, ODT_Bool },
-	{ OT_Multisample, ODT_Bool },
-	{ OT_AALine, ODT_Bool },
-	{ OT_DepthRead, ODT_Bool },
-	{ OT_DepthWrite, ODT_Bool },
-	{ OT_CompareFunc, ODT_Int },
-	{ OT_Stencil, ODT_Bool },
-	{ OT_StencilReadMask, ODT_Int },
-	{ OT_StencilWriteMask, ODT_Int },
-	{ OT_StencilOpFront, ODT_Complex },
-	{ OT_StencilOpBack, ODT_Complex },
-	{ OT_PassOp, ODT_Int },
-	{ OT_Fail, ODT_Int },
-	{ OT_ZFail, ODT_Int },
-	{ OT_AlphaToCoverage, ODT_Bool },
-	{ OT_IndependantBlend, ODT_Bool },
-	{ OT_Target, ODT_Complex },
-	{ OT_Index, ODT_Int },
-	{ OT_Blend, ODT_Bool },
-	{ OT_Color, ODT_Complex },
-	{ OT_Alpha, ODT_Complex },
-	{ OT_WriteMask, ODT_Int },
-	{ OT_Source, ODT_Int },
-	{ OT_Dest, ODT_Int },
-	{ OT_Op, ODT_Int },
-	{ OT_AddrMode, ODT_Complex },
-	{ OT_MinFilter, ODT_Int },
-	{ OT_MagFilter, ODT_Int },
-	{ OT_MipFilter, ODT_Int },
-	{ OT_MaxAniso, ODT_Int },
-	{ OT_MipBias, ODT_Float },
-	{ OT_MipMin, ODT_Float },
-	{ OT_MipMax, ODT_Float },
-	{ OT_BorderColor, ODT_Matrix },
-	{ OT_U, ODT_Int },
-	{ OT_V, ODT_Int },
-	{ OT_W, ODT_Int },
-	{ OT_Alias, ODT_String },
-	{ OT_Auto, ODT_String },
-	{ OT_Shared, ODT_Bool },
-	{ OT_Usage, ODT_Int },
-	{ OT_ParamType, ODT_Int },
-	{ OT_Identifier, ODT_String },
-	{ OT_ParamValue, ODT_Matrix },
-	{ OT_Parameters, ODT_Complex },
-	{ OT_Blocks, ODT_Complex },
-	{ OT_Parameter, ODT_Complex },
-	{ OT_Block, ODT_Complex },
-	{ OT_SamplerState, ODT_Complex },
-	{ OT_Code, ODT_Complex },
-	{ OT_StencilRef, ODT_Int }
-};
-
-NodeOptions* nodeOptionsCreate(void* context)
-{
-	static const int BUFFER_SIZE = 5;
-
-	NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions));
-	options->count = 0;
-	options->bufferSize = BUFFER_SIZE;
-
-	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
-	memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize);
-
-	return options;
-}
-
-void nodeOptionDelete(NodeOption* option)
-{
-	if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex)
-	{
-		nodeDelete(option->value.nodePtr);
-		option->value.nodePtr = 0;
-	}
-	else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String)
-	{
-		mmfree((void*)option->value.strValue);
-		option->value.strValue = 0;
-	}
-}
-
-void nodeOptionsDelete(NodeOptions* options)
-{
-	int i = 0;
-
-	for (i = 0; i < options->count; i++)
-		nodeOptionDelete(&options->entries[i]);
-
-	mmfree(options->entries);
-	mmfree(options);
-}
-
-void nodeOptionsResize(void* context, NodeOptions* options, int size)
-{
-	NodeOption* originalEntries = options->entries;
-	int originalSize = options->bufferSize;
-	int originalCount = options->count;
-	int i = 0;
-	int elementsToCopy = originalSize;
-	int sizeToCopy = 0;
-
-	options->bufferSize = size;
-	if (options->count > options->bufferSize)
-		options->count = options->bufferSize;
-
-	if (elementsToCopy > size)
-		elementsToCopy = size;
-
-	sizeToCopy = elementsToCopy * sizeof(NodeOption);
-
-	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
-
-	memcpy(options->entries, originalEntries, sizeToCopy);
-	memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy);
-
-	mmfree(originalEntries);
-}
-
-void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options)
-{
-	static const int BUFFER_GROW = 10;
-
-	if (options->count == options->bufferSize)
-		nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW);
-}
-
-void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option)
-{
-	nodeOptionsGrowIfNeeded(context, options);
-
-	options->entries[options->count] = *option;
-	options->count++;
-}
-
-ASTFXNode* nodeCreate(void* context, NodeType type)
-{
-	ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode));
-	node->options = nodeOptionsCreate(context);
-	node->type = type;
-
-	return node;
-}
-
-void nodeDelete(ASTFXNode* node)
-{
-	nodeOptionsDelete(node->options);
-
-	mmfree(node);
-}
-
-void nodePush(ParseState* parseState, ASTFXNode* node)
-{
-	NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink));
-	linkNode->next = parseState->nodeStack;
-	linkNode->node = node;
-
-	parseState->nodeStack = linkNode;
-	parseState->topNode = node;
-}
-
-void nodePop(ParseState* parseState)
-{
-	if (!parseState->nodeStack)
-		return;
-
-	NodeLink* toRemove = parseState->nodeStack;
-	parseState->nodeStack = toRemove->next;
-
-	if (parseState->nodeStack)
-		parseState->topNode = parseState->nodeStack->node;
-	else
-		parseState->topNode = 0;
-
-	mmfree(toRemove);
-}
-
-ParseState* parseStateCreate()
-{
-	ParseState* parseState = (ParseState*)malloc(sizeof(ParseState));
-	parseState->memContext = mmalloc_new_context();
-	parseState->rootNode = nodeCreate(parseState->memContext, NT_Shader);
-	parseState->topNode = 0;
-	parseState->nodeStack = 0;
-
-	parseState->hasError = 0;
-	parseState->errorLine = 0;
-	parseState->errorColumn = 0;
-	parseState->errorMessage = 0;
-
-	nodePush(parseState, parseState->rootNode);
-
-	return parseState;
-}
-
-void parseStateDelete(ParseState* parseState)
-{
-	while (parseState->nodeStack != 0)
-		nodePop(parseState);
-
-	nodeDelete(parseState->rootNode);
-	mmalloc_free_context(parseState->memContext);
-
-	free(parseState);
+#include "BsASTFX.h"
+#include "BsMMAlloc.h"
+
+OptionInfo OPTION_LOOKUP[] =
+{
+	{ OT_None, ODT_Int },
+	{ OT_Separable, ODT_Bool },
+	{ OT_Priority, ODT_Int },
+	{ OT_Queue, ODT_Int },
+	{ OT_Transparent, ODT_Bool },
+	{ OT_Technique, ODT_Complex }, 
+	{ OT_Renderer, ODT_String }, 
+	{ OT_Language, ODT_String }, 
+	{ OT_Include, ODT_String }, 
+	{ OT_Pass, ODT_Complex }, 
+	{ OT_FillMode, ODT_Int }, 
+	{ OT_CullMode, ODT_Int },
+	{ OT_DepthBias, ODT_Float },
+	{ OT_SDepthBias, ODT_Float },
+	{ OT_DepthClip, ODT_Bool },
+	{ OT_Scissor, ODT_Bool },
+	{ OT_Multisample, ODT_Bool },
+	{ OT_AALine, ODT_Bool },
+	{ OT_DepthRead, ODT_Bool },
+	{ OT_DepthWrite, ODT_Bool },
+	{ OT_CompareFunc, ODT_Int },
+	{ OT_Stencil, ODT_Bool },
+	{ OT_StencilReadMask, ODT_Int },
+	{ OT_StencilWriteMask, ODT_Int },
+	{ OT_StencilOpFront, ODT_Complex },
+	{ OT_StencilOpBack, ODT_Complex },
+	{ OT_PassOp, ODT_Int },
+	{ OT_Fail, ODT_Int },
+	{ OT_ZFail, ODT_Int },
+	{ OT_AlphaToCoverage, ODT_Bool },
+	{ OT_IndependantBlend, ODT_Bool },
+	{ OT_Target, ODT_Complex },
+	{ OT_Index, ODT_Int },
+	{ OT_Blend, ODT_Bool },
+	{ OT_Color, ODT_Complex },
+	{ OT_Alpha, ODT_Complex },
+	{ OT_WriteMask, ODT_Int },
+	{ OT_Source, ODT_Int },
+	{ OT_Dest, ODT_Int },
+	{ OT_Op, ODT_Int },
+	{ OT_AddrMode, ODT_Complex },
+	{ OT_MinFilter, ODT_Int },
+	{ OT_MagFilter, ODT_Int },
+	{ OT_MipFilter, ODT_Int },
+	{ OT_MaxAniso, ODT_Int },
+	{ OT_MipBias, ODT_Float },
+	{ OT_MipMin, ODT_Float },
+	{ OT_MipMax, ODT_Float },
+	{ OT_BorderColor, ODT_Matrix },
+	{ OT_U, ODT_Int },
+	{ OT_V, ODT_Int },
+	{ OT_W, ODT_Int },
+	{ OT_Alias, ODT_String },
+	{ OT_Auto, ODT_String },
+	{ OT_Shared, ODT_Bool },
+	{ OT_Usage, ODT_Int },
+	{ OT_ParamType, ODT_Int },
+	{ OT_Identifier, ODT_String },
+	{ OT_ParamValue, ODT_Matrix },
+	{ OT_ParamStrValue, ODT_String },
+	{ OT_Parameters, ODT_Complex },
+	{ OT_Blocks, ODT_Complex },
+	{ OT_Parameter, ODT_Complex },
+	{ OT_Block, ODT_Complex },
+	{ OT_SamplerState, ODT_Complex },
+	{ OT_Code, ODT_Complex },
+	{ OT_StencilRef, ODT_Int }
+};
+
+NodeOptions* nodeOptionsCreate(void* context)
+{
+	static const int BUFFER_SIZE = 5;
+
+	NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions));
+	options->count = 0;
+	options->bufferSize = BUFFER_SIZE;
+
+	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
+	memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize);
+
+	return options;
+}
+
+void nodeOptionDelete(NodeOption* option)
+{
+	if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex)
+	{
+		nodeDelete(option->value.nodePtr);
+		option->value.nodePtr = 0;
+	}
+	else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String)
+	{
+		mmfree((void*)option->value.strValue);
+		option->value.strValue = 0;
+	}
+}
+
+void nodeOptionsDelete(NodeOptions* options)
+{
+	int i = 0;
+
+	for (i = 0; i < options->count; i++)
+		nodeOptionDelete(&options->entries[i]);
+
+	mmfree(options->entries);
+	mmfree(options);
+}
+
+void nodeOptionsResize(void* context, NodeOptions* options, int size)
+{
+	NodeOption* originalEntries = options->entries;
+	int originalSize = options->bufferSize;
+	int originalCount = options->count;
+	int i = 0;
+	int elementsToCopy = originalSize;
+	int sizeToCopy = 0;
+
+	options->bufferSize = size;
+	if (options->count > options->bufferSize)
+		options->count = options->bufferSize;
+
+	if (elementsToCopy > size)
+		elementsToCopy = size;
+
+	sizeToCopy = elementsToCopy * sizeof(NodeOption);
+
+	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
+
+	memcpy(options->entries, originalEntries, sizeToCopy);
+	memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy);
+
+	mmfree(originalEntries);
+}
+
+void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options)
+{
+	static const int BUFFER_GROW = 10;
+
+	if (options->count == options->bufferSize)
+		nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW);
+}
+
+void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option)
+{
+	nodeOptionsGrowIfNeeded(context, options);
+
+	options->entries[options->count] = *option;
+	options->count++;
+}
+
+ASTFXNode* nodeCreate(void* context, NodeType type)
+{
+	ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode));
+	node->options = nodeOptionsCreate(context);
+	node->type = type;
+
+	return node;
+}
+
+void nodeDelete(ASTFXNode* node)
+{
+	nodeOptionsDelete(node->options);
+
+	mmfree(node);
+}
+
+void nodePush(ParseState* parseState, ASTFXNode* node)
+{
+	NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink));
+	linkNode->next = parseState->nodeStack;
+	linkNode->node = node;
+
+	parseState->nodeStack = linkNode;
+	parseState->topNode = node;
+}
+
+void nodePop(ParseState* parseState)
+{
+	if (!parseState->nodeStack)
+		return;
+
+	NodeLink* toRemove = parseState->nodeStack;
+	parseState->nodeStack = toRemove->next;
+
+	if (parseState->nodeStack)
+		parseState->topNode = parseState->nodeStack->node;
+	else
+		parseState->topNode = 0;
+
+	mmfree(toRemove);
+}
+
+ParseState* parseStateCreate()
+{
+	ParseState* parseState = (ParseState*)malloc(sizeof(ParseState));
+	parseState->memContext = mmalloc_new_context();
+	parseState->rootNode = nodeCreate(parseState->memContext, NT_Shader);
+	parseState->topNode = 0;
+	parseState->nodeStack = 0;
+
+	parseState->hasError = 0;
+	parseState->errorLine = 0;
+	parseState->errorColumn = 0;
+	parseState->errorMessage = 0;
+
+	nodePush(parseState, parseState->rootNode);
+
+	return parseState;
+}
+
+void parseStateDelete(ParseState* parseState)
+{
+	while (parseState->nodeStack != 0)
+		nodePop(parseState);
+
+	nodeDelete(parseState->rootNode);
+	mmalloc_free_context(parseState->memContext);
+
+	free(parseState);
 }
 }

+ 39 - 7
BansheeSL/Source/BsSLFXCompiler.cpp

@@ -10,6 +10,7 @@
 #include "BsShaderManager.h"
 #include "BsShaderManager.h"
 #include "BsShaderInclude.h"
 #include "BsShaderInclude.h"
 #include "BsMatrix4.h"
 #include "BsMatrix4.h"
+#include "BsBuiltinResources.h"
 
 
 extern "C" {
 extern "C" {
 #include "BsMMAlloc.h"
 #include "BsMMAlloc.h"
@@ -1387,13 +1388,13 @@ namespace BansheeEngine
 			String name;
 			String name;
 			String alias;
 			String alias;
 
 
-			float defaultValue[16];
-			bool hasDefaultValue = false;
 			UINT32 typeId = 0;
 			UINT32 typeId = 0;
 			bool isObjType = false;
 			bool isObjType = false;
 			StringID semantic;
 			StringID semantic;
 			SamplerStatePtr samplerState = nullptr;
 			SamplerStatePtr samplerState = nullptr;
-
+			float defaultValue[16];
+			HTexture defaultTexture;
+			bool hasDefaultValue = false;
 			for (int j = 0; j < parameter->options->count; j++)
 			for (int j = 0; j < parameter->options->count; j++)
 			{
 			{
 				NodeOption* paramOption = &parameter->options->entries[j];
 				NodeOption* paramOption = &parameter->options->entries[j];
@@ -1406,12 +1407,19 @@ namespace BansheeEngine
 				case OT_Alias:
 				case OT_Alias:
 					alias = removeQuotes(paramOption->value.strValue);
 					alias = removeQuotes(paramOption->value.strValue);
 					break;
 					break;
+				case OT_ParamType:
+					parseParamType((ParamType)paramOption->value.intValue, isObjType, typeId);
+					break;
 				case OT_ParamValue:
 				case OT_ParamValue:
 					memcpy(defaultValue, paramOption->value.matrixValue, sizeof(defaultValue));
 					memcpy(defaultValue, paramOption->value.matrixValue, sizeof(defaultValue));
 					hasDefaultValue = true;
 					hasDefaultValue = true;
 					break;
 					break;
-				case OT_ParamType:
-					parseParamType((ParamType)paramOption->value.intValue, isObjType, typeId);
+				case OT_ParamStrValue:
+				{
+					String defaultTextureName = removeQuotes(paramOption->value.strValue);
+					defaultTexture = getBuiltinTexture(defaultTextureName);
+					hasDefaultValue = true;
+				}
 					break;
 					break;
 				case OT_Auto:
 				case OT_Auto:
 					semantic = removeQuotes(paramOption->value.strValue);
 					semantic = removeQuotes(paramOption->value.strValue);
@@ -1431,8 +1439,20 @@ namespace BansheeEngine
 				{
 				{
 					GpuParamObjectType objType = (GpuParamObjectType)typeId;
 					GpuParamObjectType objType = (GpuParamObjectType)typeId;
 
 
-					if (Shader::isSampler(objType) && hasDefaultValue)
-						desc.addParameter(paramName, gpuVarName, objType, samplerState, semantic);
+					if (Shader::isSampler(objType))
+					{
+						if(hasDefaultValue)
+							desc.addParameter(paramName, gpuVarName, objType, samplerState, semantic);
+						else
+							desc.addParameter(paramName, gpuVarName, objType, semantic);
+					}
+					else if(Shader::isTexture(objType))
+					{
+						if(hasDefaultValue)
+							desc.addParameter(paramName, gpuVarName, objType, defaultTexture, semantic);
+						else
+							desc.addParameter(paramName, gpuVarName, objType, semantic);
+					}
 					else
 					else
 						desc.addParameter(paramName, gpuVarName, objType, semantic);
 						desc.addParameter(paramName, gpuVarName, objType, semantic);
 				}
 				}
@@ -1693,4 +1713,16 @@ namespace BansheeEngine
 
 
 		return GPP_NONE;
 		return GPP_NONE;
 	}
 	}
+
+	HTexture BSLFXCompiler::getBuiltinTexture(const String& name)
+	{
+		if (StringUtil::compare(name, String("white"), false))
+			return BuiltinResources::getTexture(BuiltinTexture::White);
+		else if (StringUtil::compare(name, String("black"), false))
+			return BuiltinResources::getTexture(BuiltinTexture::Black);
+		else if (StringUtil::compare(name, String("normal"), false))
+			return BuiltinResources::getTexture(BuiltinTexture::Normal);
+
+		return HTexture();
+	}
 }
 }

+ 1 - 1
README.md

@@ -190,7 +190,7 @@ Easiest way to get started with low-level Banshee programming is to check out th
 
 
 # License
 # License
 
 
-Banshee is offered completely free for personal or commercial use under the GNU Lesser General Public License v3 (LGPL v3). A paid commercial per-seat license is also available for those that cannot comply with LGPL terms or just want more flexibility. 
+Banshee is offered completely free for personal or commercial use under the GNU Lesser General Public License v3 (LGPL v3). A commercial license is also available for those that cannot comply with LGPL terms or just want more flexibility. 
 
 
 # Author
 # Author
 
 

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác