Pārlūkot izejas kodu

BansheeSL: Refactored code, added a proper importer

Marko Pintera 10 gadi atpakaļ
vecāks
revīzija
634dccf9e0

+ 1 - 1
BansheeCore/Include/BsGpuProgIncludeImporter.h

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 {
 	/**
 	/**
 	 * @brief	Importer using for importing GPU program (i.e. shader) include files.
 	 * @brief	Importer using for importing GPU program (i.e. shader) include files.
-	 * 			Include files are just text files ending with ".gpuinc" extension.
+	 * 			Include files are just text files ending with ".bsi" extension.
 	 */
 	 */
 	class BS_CORE_EXPORT GpuProgIncludeImporter : public SpecificImporter
 	class BS_CORE_EXPORT GpuProgIncludeImporter : public SpecificImporter
 	{
 	{

+ 8 - 2
BansheeCore/Include/BsShader.h

@@ -299,11 +299,17 @@ namespace BansheeEngine
 		static bool isBuffer(GpuParamObjectType type);
 		static bool isBuffer(GpuParamObjectType type);
 
 
 		/**
 		/**
-		 * @brief	Returns an empty shader object with the specified name. Caller must register
-		 *			techniques with the shader before using it in a Material.
+		 * @brief	Creates a new shader resource using the provided descriptor and techniques.
 		 */
 		 */
 		static HShader create(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques);
 		static HShader create(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques);
 
 
+		/**
+		 * @brief	Creates a new shader object using the provided descriptor and techniques.
+		 *
+		 * @note	Internal method.
+		 */
+		static ShaderPtr _createPtr(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques);
+
 		/**
 		/**
 		 * @brief	Returns a shader object but doesn't initialize it.
 		 * @brief	Returns a shader object but doesn't initialize it.
 		 */
 		 */

+ 1 - 1
BansheeCore/Source/BsGpuProgIncludeImporter.cpp

@@ -21,7 +21,7 @@ namespace BansheeEngine
 		WString lowerCaseExt = ext;
 		WString lowerCaseExt = ext;
 		StringUtil::toLowerCase(lowerCaseExt);
 		StringUtil::toLowerCase(lowerCaseExt);
 
 
-		return lowerCaseExt == L"gpuinc";
+		return lowerCaseExt == L"bsi";
 	}
 	}
 
 
 	bool GpuProgIncludeImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
 	bool GpuProgIncludeImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const

+ 8 - 1
BansheeCore/Source/BsShader.cpp

@@ -310,12 +310,19 @@ namespace BansheeEngine
 	}
 	}
 
 
 	HShader Shader::create(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques)
 	HShader Shader::create(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques)
+	{
+		ShaderPtr newShader = _createPtr(name, desc, techniques);
+
+		return static_resource_cast<Shader>(gResources()._createResourceHandle(newShader));
+	}
+
+	ShaderPtr Shader::_createPtr(const String& name, const SHADER_DESC& desc, const Vector<SPtr<Technique>>& techniques)
 	{
 	{
 		ShaderPtr newShader = bs_core_ptr<Shader, PoolAlloc>(new (bs_alloc<Shader, PoolAlloc>()) Shader(name, desc, techniques));
 		ShaderPtr newShader = bs_core_ptr<Shader, PoolAlloc>(new (bs_alloc<Shader, PoolAlloc>()) Shader(name, desc, techniques));
 		newShader->_setThisPtr(newShader);
 		newShader->_setThisPtr(newShader);
 		newShader->initialize();
 		newShader->initialize();
 
 
-		return static_resource_cast<Shader>(gResources()._createResourceHandle(newShader));
+		return newShader;
 	}
 	}
 
 
 	ShaderPtr Shader::createEmpty()
 	ShaderPtr Shader::createEmpty()

+ 3 - 0
BansheeEditor/Source/BsEditorApplication.cpp

@@ -175,6 +175,9 @@ namespace BansheeEngine
 		/* 								DEBUG CODE                      		*/
 		/* 								DEBUG CODE                      		*/
 		/************************************************************************/
 		/************************************************************************/
 
 
+		HShader dummyParsedShader = Importer::instance().import<Shader>("..\\..\\..\\..\\Data\\Raw\\Engine\\Shaders\\DummyFX.bsl");
+		assert(dummyParsedShader != nullptr);
+
 		RenderAPICore* renderSystem = RenderAPICore::instancePtr();
 		RenderAPICore* renderSystem = RenderAPICore::instancePtr();
 
 
 		HSceneObject testModelGO = SceneObject::create("TestMesh");
 		HSceneObject testModelGO = SceneObject::create("TestMesh");

+ 4 - 0
BansheeSL/BansheeSL.vcxproj

@@ -264,6 +264,8 @@
     <ClInclude Include="BsLexerFX.h" />
     <ClInclude Include="BsLexerFX.h" />
     <ClInclude Include="BsParserFX.h" />
     <ClInclude Include="BsParserFX.h" />
     <ClInclude Include="Include\BsASTFX.h" />
     <ClInclude Include="Include\BsASTFX.h" />
+    <ClInclude Include="Include\BsSLFXCompiler.h" />
+    <ClInclude Include="Include\BsSLImporter.h" />
     <ClInclude Include="Include\BsMMAlloc.h" />
     <ClInclude Include="Include\BsMMAlloc.h" />
     <ClInclude Include="Include\BsSLPrerequisites.h" />
     <ClInclude Include="Include\BsSLPrerequisites.h" />
   </ItemGroup>
   </ItemGroup>
@@ -282,6 +284,8 @@
     </ClCompile>
     </ClCompile>
     <ClCompile Include="Source\BsASTFX.c" />
     <ClCompile Include="Source\BsASTFX.c" />
     <ClCompile Include="Source\BSMMAlloc.c" />
     <ClCompile Include="Source\BSMMAlloc.c" />
+    <ClCompile Include="Source\BsSLFXCompiler.cpp" />
+    <ClCompile Include="Source\BsSLImporter.cpp" />
     <ClCompile Include="Source\BsSLPlugin.cpp" />
     <ClCompile Include="Source\BsSLPlugin.cpp" />
   </ItemGroup>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 12 - 0
BansheeSL/BansheeSL.vcxproj.filters

@@ -30,6 +30,12 @@
     <ClInclude Include="Include\BsMMAlloc.h">
     <ClInclude Include="Include\BsMMAlloc.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsSLImporter.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsSLFXCompiler.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <None Include="BsLexerFX.l" />
     <None Include="BsLexerFX.l" />
@@ -51,5 +57,11 @@
     <ClCompile Include="Source\BSMMAlloc.c">
     <ClCompile Include="Source\BSMMAlloc.c">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsSLImporter.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsSLFXCompiler.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 234 - 0
BansheeSL/Include/BsSLFXCompiler.h

@@ -0,0 +1,234 @@
+#pragma once
+
+#include "BsSLPrerequisites.h"
+#include "BsShader.h"
+#include "BsGpuProgram.h"
+
+extern "C" {
+#include "BsASTFX.h"
+}
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Transforms a source file written in BSL FX syntax into a Shader object.
+	 */
+	class BSLFXCompiler
+	{
+		/**
+		 * @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
+		{
+			GpuProgramType type;
+			String code;
+		};
+
+	public:
+		/**
+		 * @brief	Transforms a source file written in BSL FX syntax into a Shader object.
+		 *
+		 * @note	If error occurs a nullptr will be returned and the error will be logged.
+		 */
+		static ShaderPtr 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	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 object, or an invalid
+		 *			handle in case AST node is empty. 
+		 */
+		static HBlendState parseBlendState(ASTFXNode* passNode);
+
+		/**
+		 * @brief	Parses the rasterizer state AST node and outputs a rasterizer state object, or an invalid
+		 *			handle in case AST node is empty. 
+		 */
+		static HRasterizerState parseRasterizerState(ASTFXNode* passNode);
+
+		/**
+		 * @brief	Parses the depth-stencil state AST node and outputs a depth-stencil state object, or an invalid
+		 *			handle in case AST node is empty. 
+		 */
+		static HDepthStencilState parseDepthStencilState(ASTFXNode* passNode);
+
+		/**
+		 * @brief	Parses the sampler state AST node and outputs a sampler state object, or an invalid
+		 *			handle in case AST node is empty. 
+		 */
+		static HSamplerState parseSamplerState(ASTFXNode* samplerStateNode);
+
+		/**
+		 * @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	includes		Files paths relative to the current executable that will be injected
+		 *							into GPU program code before compilation.
+		 * @param	renderAPI		API to use for compiling the GPU programs.
+		 * @param	language		GPU program language to use for parsing the provided code blocks.
+		 */
+		static PassPtr parsePass(ASTFXNode* passNode, const Vector<CodeBlock>& codeBlocks, const Vector<String>& includes, const StringID& renderAPI, const String& language);
+
+		/**
+		 * @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	rootNode	Root node of the AST hierarchy retrieved from "parseFX".
+		 * @param	codeBlocks	GPU program source code retrieved from "parseCodeBlocks".
+		 *
+		 * @return	A generated shader object, or a nullptr if shader was invalid.
+		 */
+		static ShaderPtr parseShader(const String& name, ASTFXNode* rootNode, const 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);
+	};
+}

+ 27 - 0
BansheeSL/Include/BsSLImporter.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "BsSLPrerequisites.h"
+#include "BsSpecificImporter.h"
+
+namespace BansheeEngine
+{
+	/**
+	* @brief	Importer using for importing a shader written using the BSL syntax.
+	* 			Shader files are plain text files ending with ".bsl" extension.
+	*/
+	class BS_SL_EXPORT SLImporter : public SpecificImporter
+	{
+	public:
+		SLImporter();
+		virtual ~SLImporter();
+
+		/** @copydoc SpecificImporter::isExtensionSupported */
+		virtual bool isExtensionSupported(const WString& ext) const;
+
+		/** @copydoc SpecificImporter::isMagicNumberSupported */
+		virtual bool isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const;
+
+		/** @copydoc SpecificImporter::import */
+		virtual ResourcePtr import(const Path& filePath, ConstImportOptionsPtr importOptions);
+	};
+}

+ 1139 - 0
BansheeSL/Source/BsSLFXCompiler.cpp

@@ -0,0 +1,1139 @@
+#include "BsSLFXCompiler.h"
+#include "BsGpuProgram.h"
+#include <regex>
+#include "BsShader.h"
+#include "BsTechnique.h"
+#include "BsPass.h"
+#include "BsSamplerState.h"
+#include "BsRasterizerState.h"
+#include "BsDepthStencilState.h"
+#include "BsBlendState.h"
+#include "BsRenderAPI.h"
+#include "BsDebug.h"
+
+extern "C" {
+#include "BsMMAlloc.h"
+#include "BsParserFX.h"
+#include "BsLexerFX.h"
+}
+
+namespace BansheeEngine
+{
+	// Print out the FX AST, only for debug purposes
+	void SLFXDebugPrint(ASTFXNode* node, String indent)
+	{
+		LOGWRN(indent + "NODE " + toString(node->type));
+
+		for (int i = 0; i < node->options->count; i++)
+		{
+			OptionDataType odt = OPTION_LOOKUP[(int)node->options->entries[i].type].dataType;
+			if (odt == ODT_Complex)
+			{
+				LOGWRN(indent + toString(i) + ". " + toString(node->options->entries[i].type));
+				SLFXDebugPrint(node->options->entries[i].value.nodePtr, indent + "\t");
+				continue;
+			}
+
+			String value;
+			switch (odt)
+			{
+			case ODT_Bool:
+				value = toString(node->options->entries[i].value.intValue != 0);
+				break;
+			case ODT_Int:
+				value = toString(node->options->entries[i].value.intValue);
+				break;
+			case ODT_Float:
+				value = toString(node->options->entries[i].value.floatValue);
+				break;
+			case ODT_String:
+				value = node->options->entries[i].value.strValue;
+				break;
+			case ODT_Matrix:
+			{
+				Matrix4 mat4 = *(Matrix4*)(node->options->entries[i].value.matrixValue);
+				value = toString(mat4);
+			}
+				break;
+			}
+
+			LOGWRN(indent + toString(i) + ". " + toString(node->options->entries[i].type) + " = " + value);
+		}
+	}
+
+	ShaderPtr BSLFXCompiler::compile(const String& source)
+	{
+		String parsedSource = source;
+
+		ParseState* parseState = parseStateCreate();
+		Vector<CodeBlock> codeBlocks = parseCodeBlocks(parsedSource);
+		parseFX(parseState, parsedSource.c_str());
+
+		ShaderPtr output;
+		if (parseState->hasError > 0)
+		{
+			LOGERR("Error while parsing a Shader: " + String(parseState->errorMessage) + ". Location: " +
+				toString(parseState->errorLine) + " (" + toString(parseState->errorColumn) + ")");
+		}
+		else
+		{
+			output = parseShader("Shader", parseState->rootNode, codeBlocks);
+
+			// Only enable for debug purposes
+			//SLFXDebugPrint(parseState->rootNode, "");
+		}
+
+		parseStateDelete(parseState);
+
+		return output;
+	}
+
+	void BSLFXCompiler::parseFX(ParseState* parseState, const char* source)
+	{
+		yyscan_t scanner;
+		YY_BUFFER_STATE state;
+
+		if (yylex_init_extra(parseState, &scanner))
+			return;
+
+		state = yy_scan_string(source, scanner);
+
+		if (yyparse(parseState, scanner))
+			return;
+
+		yy_delete_buffer(state, scanner);
+		yylex_destroy(scanner);
+	}
+
+	Vector<BSLFXCompiler::CodeBlock> BSLFXCompiler::parseCodeBlocks(String& source)
+	{
+		std::regex pattern = std::regex(R"((Vertex|Fragment|Geometry|Hull|Domain|Compute)\s*=\s*\{)");
+		std::smatch matches;
+
+		Vector<CodeBlock> codeBlocks;
+
+		UINT32 offset = 0;
+		while (std::regex_search(source.cbegin() + offset, source.cend(), matches, pattern))
+		{
+			UINT32 idx = (UINT32)codeBlocks.size();
+
+			codeBlocks.push_back(CodeBlock());
+			CodeBlock& newBlock = codeBlocks.back();
+
+			std::string type = matches[1].str();
+			if (type == "Vertex")
+				newBlock.type = GPT_VERTEX_PROGRAM;
+			else if (type == "Fragment")
+				newBlock.type = GPT_FRAGMENT_PROGRAM;
+			else if (type == "Geometry")
+				newBlock.type = GPT_GEOMETRY_PROGRAM;
+			else if (type == "Hull")
+				newBlock.type = GPT_HULL_PROGRAM;
+			else if (type == "Domain")
+				newBlock.type = GPT_DOMAIN_PROGRAM;
+			else if (type == "Compute")
+				newBlock.type = GPT_COMPUTE_PROGRAM;
+
+			offset += (UINT32)matches.position() + (UINT32)matches.length();
+
+			StringStream newDataStream;
+			newDataStream << "Index = " + toString(idx) + ";";
+
+			StringStream codeStream;
+			UINT32 ummatchedBrackets = 1;
+			for (UINT32 i = offset; i < (UINT32)source.length(); i++)
+			{
+				if (source[i] == '{')
+					ummatchedBrackets++;
+
+				if (source[i] == '}')
+					ummatchedBrackets--;
+
+				if (ummatchedBrackets == 0)
+					break;
+
+				if (source[i] == '\r' || source[i] == '\n')
+					newDataStream << source[i];
+
+				codeStream << source[i];
+			}
+
+			newBlock.code = codeStream.str();
+
+			source.erase(source.cbegin() + offset, source.cbegin() + offset + (UINT32)newBlock.code.size());
+
+			String newData = newDataStream.str();
+			source.insert(offset, newData);
+			offset += (UINT32)newData.size();
+		}
+
+		return codeBlocks;
+	}
+
+	StringID BSLFXCompiler::parseRenderer(const String& name)
+	{
+		if (name == "Any")
+			return RendererAny;
+		else if (name == "Default")
+			return RendererDefault;
+
+		return RendererAny;
+	}
+
+	void BSLFXCompiler::parseLanguage(const String& name, StringID& renderAPI, String& language)
+	{
+		if (name == "HLSL" || name == "HLSL11")
+		{
+			renderAPI = RenderAPIDX11;
+			language = "hlsl";
+		}
+		else if (name == "HLSL9")
+		{
+			renderAPI = RenderAPIDX9;
+			language = "hlsl";
+		}
+		else if (name == "GLSL")
+		{
+			renderAPI = RenderAPIOpenGL;
+			language = "glsl";
+		}
+		else
+		{
+			renderAPI = RenderAPIAny;
+			language = "";
+		}
+	}
+
+	GpuParamBlockUsage BSLFXCompiler::parseBlockUsage(BufferUsageValue usage)
+	{
+		if (usage == BUV_Dynamic)
+			return GPBU_DYNAMIC;
+
+		return GPBU_STATIC;
+	}
+
+	UINT32 BSLFXCompiler::parseFilterMode(FilterValue filter)
+	{
+		switch (filter)
+		{
+		case FV_Point:
+			return FO_POINT;
+		case FV_Linear:
+			return FO_LINEAR;
+		case FV_Anisotropic:
+			return FO_ANISOTROPIC;
+		case FV_PointCmp:
+			return FO_POINT | FO_USE_COMPARISON;
+		case FV_LinearCmp:
+			return FO_LINEAR | FO_USE_COMPARISON;
+		case FV_AnisotropicCmp:
+			return FO_ANISOTROPIC | FO_USE_COMPARISON;
+		}
+
+		return FO_NONE;
+	}
+
+	CompareFunction BSLFXCompiler::parseCompFunc(CompFuncValue compFunc)
+	{
+		switch (compFunc)
+		{
+		case CFV_Pass:
+			return CMPF_ALWAYS_PASS;
+		case CFV_Fail:
+			return CMPF_ALWAYS_FAIL;
+		case CFV_LT:
+			return CMPF_LESS;
+		case CFV_LTE:
+			return CMPF_LESS_EQUAL;
+		case CFV_EQ:
+			return CMPF_EQUAL;
+		case CFV_NEQ:
+			return CMPF_NOT_EQUAL;
+		case CFV_GT:
+			return CMPF_GREATER;
+		case CFV_GTE:
+			return CMPF_GREATER_EQUAL;
+		}
+
+		return CMPF_ALWAYS_PASS;
+	}
+
+	TextureAddressingMode BSLFXCompiler::parseAddrMode(AddrModeValue addrMode)
+	{
+		switch (addrMode)
+		{
+		case AMV_Wrap:
+			return TAM_WRAP;
+		case AMV_Mirror:
+			return TAM_MIRROR;
+		case AMV_Clamp:
+			return TAM_CLAMP;
+		case AMV_Border:
+			return TAM_BORDER;
+		}
+
+		return TAM_WRAP;
+	}
+
+	BlendFactor BSLFXCompiler::parseBlendFactor(OpValue factor)
+	{
+		switch (factor)
+		{
+		case OV_One:
+			return BF_ONE;
+		case OV_Zero:
+			return BF_ZERO;
+		case OV_DestColor:
+			return BF_DEST_COLOR;
+		case OV_SrcColor:
+			return BF_SOURCE_COLOR;
+		case OV_InvDestColor:
+			return BF_INV_DEST_COLOR;
+		case OV_InvSrcColor:
+			return BF_INV_SOURCE_COLOR;
+		case OV_DestAlpha:
+			return BF_DEST_ALPHA;
+		case OV_SrcAlpha:
+			return BF_SOURCE_ALPHA;
+		case OV_InvDestAlpha:
+			return BF_INV_DEST_ALPHA;
+		case OV_InvSrcAlpha:
+			return BF_INV_SOURCE_ALPHA;
+		}
+
+		return BF_ONE;
+	}
+
+	BlendOperation BSLFXCompiler::parseBlendOp(BlendOpValue op)
+	{
+		switch (op)
+		{
+		case BOV_Add:
+			return BO_ADD;
+		case BOV_Max:
+			return BO_MAX;
+		case BOV_Min:
+			return BO_MIN;
+		case BOV_Subtract:
+			return BO_SUBTRACT;
+		case BOV_RevSubtract:
+			return BO_REVERSE_SUBTRACT;
+		}
+
+		return BO_ADD;
+	}
+
+	void BSLFXCompiler::parseParamType(ParamType type, bool& isObjType, UINT32& typeId)
+	{
+		struct ParamData
+		{
+			UINT32 type;
+			bool isObjType;
+		};
+
+		static bool initialized = false;
+		static ParamData lookup[PT_Count];
+
+		if (!initialized)
+		{
+			lookup[PT_Float] = { { GPDT_FLOAT1 }, false };
+			lookup[PT_Float2] = { { GPDT_FLOAT2 }, false };
+			lookup[PT_Float3] = { { GPDT_FLOAT3 }, false };
+			lookup[PT_Float4] = { { GPDT_FLOAT4 }, false };
+
+			lookup[PT_Mat2x2] = { { GPDT_MATRIX_2X2 }, false };
+			lookup[PT_Mat2x3] = { { GPDT_MATRIX_2X3 }, false };
+			lookup[PT_Mat2x4] = { { GPDT_MATRIX_2X4 }, false };
+
+			lookup[PT_Mat3x2] = { { GPDT_MATRIX_3X2 }, false };
+			lookup[PT_Mat3x3] = { { GPDT_MATRIX_3X3 }, false };
+			lookup[PT_Mat3x4] = { { GPDT_MATRIX_3X4 }, false };
+
+			lookup[PT_Mat4x2] = { { GPDT_MATRIX_4X2 }, false };
+			lookup[PT_Mat4x3] = { { GPDT_MATRIX_4X3 }, false };
+			lookup[PT_Mat4x4] = { { GPDT_MATRIX_4X4 }, false };
+
+			lookup[PT_Sampler1D] = { { GPOT_SAMPLER1D }, true };
+			lookup[PT_Sampler2D] = { { GPOT_SAMPLER2D }, true };
+			lookup[PT_Sampler3D] = { { GPOT_SAMPLER3D }, true };
+			lookup[PT_SamplerCUBE] = { { GPOT_SAMPLERCUBE }, true };
+			lookup[PT_Sampler2DMS] = { { GPOT_SAMPLER2DMS }, true };
+
+			lookup[PT_Texture1D] = { { GPOT_TEXTURE1D }, true };
+			lookup[PT_Texture2D] = { { GPOT_TEXTURE2D }, true };
+			lookup[PT_Texture3D] = { { GPOT_TEXTURE3D }, true };
+			lookup[PT_TextureCUBE] = { { GPOT_TEXTURECUBE }, true };
+			lookup[PT_Texture2DMS] = { { GPOT_TEXTURE2DMS }, true };
+
+			lookup[PT_ByteBuffer] = { { GPOT_BYTE_BUFFER }, true };
+			lookup[PT_StructBuffer] = { { GPOT_STRUCTURED_BUFFER }, true };
+			lookup[PT_TypedBufferRW] = { { GPOT_RWTYPED_BUFFER }, true };
+			lookup[PT_ByteBufferRW] = { { GPOT_RWBYTE_BUFFER }, true };
+			lookup[PT_StructBufferRW] = { { GPOT_RWSTRUCTURED_BUFFER }, true };
+			lookup[PT_AppendBuffer] = { { GPOT_RWAPPEND_BUFFER }, true };
+			lookup[PT_ConsumeBuffer] = { { GPOT_RWCONSUME_BUFFER }, true };
+
+			initialized = true;
+		}
+
+		isObjType = lookup[type].isObjType;
+		typeId = lookup[type].type;
+	}
+
+	StencilOperation BSLFXCompiler::parseStencilOp(OpValue op)
+	{
+		switch (op)
+		{
+		case OV_Keep:
+			return SOP_KEEP;
+		case OV_Zero:
+			return SOP_ZERO;
+		case OV_Replace:
+			return SOP_REPLACE;
+		case OV_Incr:
+			return SOP_INCREMENT;
+		case OV_Decr:
+			return SOP_DECREMENT;
+		case OV_IncrWrap:
+			return SOP_INCREMENT_WRAP;
+		case OV_DecrWrap:
+			return SOP_DECREMENT_WRAP;
+		case OV_Invert:
+			return SOP_INVERT;
+		}
+
+		return SOP_KEEP;
+	}
+
+	CullingMode BSLFXCompiler::parseCullMode(CullModeValue cm)
+	{
+		switch (cm)
+		{
+		case CMV_None:
+			return CULL_NONE;
+		case CMV_CW:
+			return CULL_CLOCKWISE;
+		case CMV_CCW:
+			return CULL_COUNTERCLOCKWISE;
+		}
+
+		return CULL_COUNTERCLOCKWISE;
+	}
+
+	PolygonMode BSLFXCompiler::parseFillMode(FillModeValue fm)
+	{
+		if (fm == FMV_Wire)
+			return PM_WIREFRAME;
+
+		return PM_SOLID;
+	}
+
+	void BSLFXCompiler::parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
+	{
+		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
+			return;
+
+		for (int i = 0; i < stencilOpNode->options->count; i++)
+		{
+			NodeOption* option = &stencilOpNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Fail:
+				desc.frontStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_ZFail:
+				desc.frontStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_PassOp:
+				desc.frontStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_CompareFunc:
+				desc.frontStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
+	{
+		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
+			return;
+
+		for (int i = 0; i < stencilOpNode->options->count; i++)
+		{
+			NodeOption* option = &stencilOpNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Fail:
+				desc.backStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_ZFail:
+				desc.backStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_PassOp:
+				desc.backStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_CompareFunc:
+				desc.backStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseAddrMode(SAMPLER_STATE_DESC& desc, ASTFXNode* addrModeNode)
+	{
+		if (addrModeNode == nullptr || addrModeNode->type != NT_AddrMode)
+			return;
+
+		for (int i = 0; i < addrModeNode->options->count; i++)
+		{
+			NodeOption* option = &addrModeNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_U:
+				desc.addressMode.u = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			case OT_V:
+				desc.addressMode.v = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			case OT_W:
+				desc.addressMode.w = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
+	{
+		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
+			return;
+
+		for (int i = 0; i < blendDefNode->options->count; i++)
+		{
+			NodeOption* option = &blendDefNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Source:
+				desc.srcBlend = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Dest:
+				desc.dstBlend = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Op:
+				desc.blendOp = parseBlendOp((BlendOpValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
+	{
+		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
+			return;
+
+		for (int i = 0; i < blendDefNode->options->count; i++)
+		{
+			NodeOption* option = &blendDefNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Source:
+				desc.srcBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Dest:
+				desc.dstBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Op:
+				desc.blendOpAlpha = parseBlendOp((BlendOpValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode)
+	{
+		if (targetNode == nullptr || targetNode->type != NT_Target)
+			return;
+
+		UINT32 index = 0;
+
+		for (int i = 0; i < targetNode->options->count; i++)
+		{
+			NodeOption* option = &targetNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Index:
+				index = option->value.intValue;
+				break;
+			}
+		}
+
+		if (index >= BS_MAX_MULTIPLE_RENDER_TARGETS)
+			return;
+
+		RENDER_TARGET_BLEND_STATE_DESC& rtDesc = desc.renderTargetDesc[index];
+		for (int i = 0; i < targetNode->options->count; i++)
+		{
+			NodeOption* option = &targetNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Blend:
+				rtDesc.blendEnable = option->value.intValue > 0;
+				break;
+			case OT_Color:
+				parseColorBlendDef(rtDesc, option->value.nodePtr);
+				break;
+			case OT_Alpha:
+				parseAlphaBlendDef(rtDesc, option->value.nodePtr);
+				break;
+			case OT_WriteMask:
+				rtDesc.renderTargetWriteMask = option->value.intValue;
+				break;
+			}
+		}
+	}
+
+	HBlendState BSLFXCompiler::parseBlendState(ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || passNode->type != NT_Pass)
+			return HBlendState();
+
+		BLEND_STATE_DESC desc;
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_AlphaToCoverage:
+				desc.alphaToCoverageEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_IndependantBlend:
+				desc.independantBlendEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Target:
+				parseRenderTargetBlendState(desc, option->value.nodePtr);
+				default = false;
+				break;
+			}
+		}
+
+		if (default)
+			return HBlendState();
+
+		return BlendState::create(desc);
+	}
+
+	HRasterizerState BSLFXCompiler::parseRasterizerState(ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || passNode->type != NT_Pass)
+			return HRasterizerState();
+
+		RASTERIZER_STATE_DESC desc;
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_FillMode:
+				desc.polygonMode = parseFillMode((FillModeValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_CullMode:
+				desc.cullMode = parseCullMode((CullModeValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_DepthBias:
+				desc.depthBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_SDepthBias:
+				desc.slopeScaledDepthBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_DepthClip:
+				desc.depthClipEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Scissor:
+				desc.scissorEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Multisample:
+				desc.multisampleEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_AALine:
+				desc.antialiasedLineEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			}
+		}
+
+		if (default)
+			return HRasterizerState();
+
+		return RasterizerState::create(desc);
+	}
+
+	HDepthStencilState BSLFXCompiler::parseDepthStencilState(ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || passNode->type != NT_Pass)
+			return HDepthStencilState();
+
+		DEPTH_STENCIL_STATE_DESC desc;
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_DepthRead:
+				desc.depthReadEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_DepthWrite:
+				desc.depthWriteEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_CompareFunc:
+				desc.depthComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_Stencil:
+				desc.stencilEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_StencilReadMask:
+				desc.stencilReadMask = (UINT8)option->value.intValue;
+				default = false;
+				break;
+			case OT_StencilWriteMask:
+				desc.stencilWriteMask = (UINT8)option->value.intValue;
+				default = false;
+				break;
+			case OT_StencilOpFront:
+				parseStencilFront(desc, option->value.nodePtr);
+				default = false;
+				break;
+			case OT_StencilOpBack:
+				parseStencilBack(desc, option->value.nodePtr);
+				default = false;
+				break;
+			}
+		}
+
+		if (default)
+			return HDepthStencilState();
+
+		return DepthStencilState::create(desc);
+	}
+
+	HSamplerState BSLFXCompiler::parseSamplerState(ASTFXNode* samplerStateNode)
+	{
+		if (samplerStateNode == nullptr || samplerStateNode->type != NT_SamplerState)
+			return HSamplerState();
+
+		SAMPLER_STATE_DESC desc;
+		bool default = true;
+
+		for (int i = 0; i < samplerStateNode->options->count; i++)
+		{
+			NodeOption* option = &samplerStateNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_AddrMode:
+				parseAddrMode(desc, option->value.nodePtr);
+				default = false;
+				break;
+			case OT_MinFilter:
+				desc.minFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MagFilter:
+				desc.magFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MipFilter:
+				desc.mipFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MaxAniso:
+				desc.maxAniso = option->value.intValue;
+				default = false;
+				break;
+			case OT_MipBias:
+				desc.mipmapBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_MipMin:
+				desc.mipMin = option->value.floatValue;
+				default = false;
+				break;
+			case OT_MipMax:
+				desc.mipMax = option->value.floatValue;
+				default = false;
+				break;
+			case OT_BorderColor:
+				desc.borderColor = Color(option->value.matrixValue[0], option->value.matrixValue[1],
+					option->value.matrixValue[2], option->value.matrixValue[3]);
+				default = false;
+				break;
+			case OT_CompareFunc:
+				desc.comparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				default = false;
+				break;
+			}
+		}
+
+		if (default)
+			return HSamplerState();
+
+		return SamplerState::create(desc);
+	}
+
+	PassPtr BSLFXCompiler::parsePass(ASTFXNode* passNode, const Vector<CodeBlock>& codeBlocks, const Vector<String>& includes, const StringID& renderAPI, const String& language)
+	{
+		if (passNode == nullptr || passNode->type != NT_Pass)
+			return nullptr;
+
+		PASS_DESC passDesc;
+
+		passDesc.blendState = parseBlendState(passNode);
+		passDesc.rasterizerState = parseRasterizerState(passNode);
+		passDesc.depthStencilState = parseDepthStencilState(passNode);
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_StencilRef:
+				passDesc.stencilRefValue = option->value.intValue;
+				break;
+			case OT_Code:
+			{
+				ASTFXNode* codeNode = option->value.nodePtr;
+
+				if (codeNode != nullptr && codeNode->type == NT_Code)
+				{
+					UINT32 index = (UINT32)-1;
+					for (int j = 0; j < codeNode->options->count; j++)
+					{
+						if (codeNode->options->entries[j].type == OT_Index)
+							index = codeNode->options->entries[j].value.intValue;
+					}
+
+					if (index != (UINT32)-1 && index < (UINT32)codeBlocks.size())
+					{
+						const CodeBlock& codeBlock = codeBlocks[index];
+						switch (codeBlock.type)
+						{
+						case GPT_VERTEX_PROGRAM:
+							passDesc.vertexProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						case GPT_FRAGMENT_PROGRAM:
+							passDesc.fragmentProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						case GPT_GEOMETRY_PROGRAM:
+							passDesc.geometryProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						case GPT_HULL_PROGRAM:
+							passDesc.hullProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						case GPT_DOMAIN_PROGRAM:
+							passDesc.domainProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						case GPT_COMPUTE_PROGRAM:
+							passDesc.computeProgram = GpuProgram::create(codeBlock.code, "main", language,
+								codeBlock.type, getProfile(renderAPI, codeBlock.type));
+							break;
+						}
+					}
+				}
+			}
+				break;
+			}
+		}
+
+		return Pass::create(passDesc);
+	}
+
+	TechniquePtr BSLFXCompiler::parseTechnique(ASTFXNode* techniqueNode, const Vector<CodeBlock>& codeBlocks)
+	{
+		if (techniqueNode == nullptr || techniqueNode->type != NT_Technique)
+			return nullptr;
+
+		Vector<ASTFXNode*> passNodes;
+		StringID renderer = RendererAny;
+		StringID renderAPI = RenderAPIAny;
+		String language;
+		Vector<String> includes; // TODO - Need to figure out what to do with these
+
+		for (int i = 0; i < techniqueNode->options->count; i++)
+		{
+			NodeOption* option = &techniqueNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Pass:
+				passNodes.push_back(option->value.nodePtr);
+				break;
+			case OT_Include:
+			{
+				String include = removeQuotes(option->value.strValue);
+				includes.push_back(include);
+			}
+				break;
+			case OT_Renderer:
+				renderer = parseRenderer(removeQuotes(option->value.strValue));
+				break;
+			case OT_Language:
+				parseLanguage(removeQuotes(option->value.strValue), renderAPI, language);
+				break;
+			}
+		}
+
+		Vector<PassPtr> passes;
+		for (auto& passNode : passNodes)
+		{
+			PassPtr pass = parsePass(passNode, codeBlocks, includes, renderAPI, language);
+			if (pass != nullptr)
+				passes.push_back(pass);
+		}
+
+		if (passes.size() > 0)
+			return Technique::create(renderAPI, renderer, passes);
+
+		return nullptr;
+	}
+
+	void BSLFXCompiler::parseParameters(SHADER_DESC& desc, ASTFXNode* parametersNode)
+	{
+		if (parametersNode == nullptr || parametersNode->type != NT_Parameters)
+			return;
+
+		for (int i = 0; i < parametersNode->options->count; i++)
+		{
+			NodeOption* option = &parametersNode->options->entries[i];
+
+			if (option->type != OT_Parameter)
+				continue;
+
+			ASTFXNode* parameter = option->value.nodePtr;
+
+			String name;
+			String alias;
+
+			float defaultValue[16];
+			UINT32 typeId;
+			bool isObjType = false;
+			StringID semantic;
+
+			for (int j = 0; j < parameter->options->count; j++)
+			{
+				NodeOption* paramOption = &parameter->options->entries[j];
+
+				switch (paramOption->type)
+				{
+				case OT_Identifier:
+					name = paramOption->value.strValue;
+					break;
+				case OT_Alias:
+					alias = removeQuotes(paramOption->value.strValue);
+					break;
+				case OT_ParamValue:
+					memcpy(defaultValue, paramOption->value.matrixValue, sizeof(defaultValue));
+					break;
+				case OT_ParamType:
+					parseParamType((ParamType)paramOption->value.intValue, isObjType, typeId);
+					break;
+				case OT_Auto:
+					semantic = removeQuotes(paramOption->value.strValue);
+					break;
+				case OT_SamplerState:
+					HSamplerState samplerState = parseSamplerState(paramOption->value.nodePtr);
+					// TODO - How to deal with sampler-state default value?
+					break;
+				}
+			}
+
+			if (name.empty())
+				continue;
+
+			if (isObjType)
+				desc.addParameter(name, name, (GpuParamObjectType)typeId, semantic);
+			else
+				desc.addParameter(name, name, (GpuParamDataType)typeId, semantic); // TODO - Add default value
+
+			if (!alias.empty())
+			{
+				if (isObjType)
+					desc.addParameter(name, alias, (GpuParamObjectType)typeId, semantic);
+				else
+					desc.addParameter(name, alias, (GpuParamDataType)typeId, semantic); // TODO - Add default value
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseBlocks(SHADER_DESC& desc, ASTFXNode* blocksNode)
+	{
+		if (blocksNode == nullptr || blocksNode->type != NT_Blocks)
+			return;
+
+		for (int i = 0; i < blocksNode->options->count; i++)
+		{
+			NodeOption* option = &blocksNode->options->entries[i];
+
+			if (option->type != OT_Block)
+				continue;
+
+			ASTFXNode* parameter = option->value.nodePtr;
+
+			String name;
+			bool shared;
+			GpuParamBlockUsage usage;
+			StringID semantic;
+
+			for (int j = 0; j < parameter->options->count; j++)
+			{
+				NodeOption* paramOption = &parameter->options->entries[j];
+
+				switch (paramOption->type)
+				{
+				case OT_Identifier:
+					name = paramOption->value.strValue;
+					break;
+				case OT_Shared:
+					shared = paramOption->value.intValue > 0;
+					break;
+				case OT_Usage:
+					usage = parseBlockUsage((BufferUsageValue)paramOption->value.intValue);
+					break;
+				case OT_Auto:
+					semantic = removeQuotes(paramOption->value.strValue);
+					break;
+				}
+			}
+
+			if (name.empty())
+				continue;
+
+			desc.setParamBlockAttribs(name, shared, usage, semantic);
+		}
+	}
+
+	ShaderPtr BSLFXCompiler::parseShader(const String& name, ASTFXNode* rootNode, const Vector<CodeBlock>& codeBlocks)
+	{
+		SHADER_DESC shaderDesc;
+		Vector<TechniquePtr> techniques;
+
+		if (rootNode->type == NT_Shader)
+		{
+			for (int i = 0; i < rootNode->options->count; i++)
+			{
+				NodeOption* option = &rootNode->options->entries[i];
+
+				switch (option->type)
+				{
+				case OT_Separable:
+					shaderDesc.separablePasses = option->value.intValue > 1;
+					break;
+				case OT_Queue:
+					shaderDesc.queuePriority = option->value.intValue;
+					break;
+				case OT_Priority:
+					shaderDesc.queuePriority = option->value.intValue;
+					break;
+				case OT_Technique:
+				{
+					TechniquePtr technique = parseTechnique(option->value.nodePtr, codeBlocks);
+					if (technique != nullptr)
+						techniques.push_back(technique);
+
+					break;
+				}
+				case OT_Parameters:
+					parseParameters(shaderDesc, option->value.nodePtr);
+					break;
+				case OT_Blocks:
+					parseBlocks(shaderDesc, option->value.nodePtr);
+					break;
+				}
+			}
+		}
+
+		return Shader::_createPtr(name, shaderDesc, techniques);
+	}
+
+	String BSLFXCompiler::removeQuotes(const char* input)
+	{
+		UINT32 len = (UINT32)strlen(input);
+		String output(len - 2, ' ');
+
+		for (UINT32 i = 0; i < (len - 2); i++)
+			output[i] = input[i + 1];
+
+		return output;
+	}
+
+	GpuProgramProfile BSLFXCompiler::getProfile(const StringID& renderAPI, GpuProgramType type)
+	{
+		StringID target = renderAPI;
+		if (target == RenderAPIAny)
+			target = RenderAPICore::instance().getName();
+
+		if (target == RenderAPIDX11 || target == RenderAPIOpenGL)
+		{
+			switch (type)
+			{
+			case GPT_VERTEX_PROGRAM:
+				return GPP_VS_5_0;
+			case GPT_FRAGMENT_PROGRAM:
+				return GPP_FS_5_0;
+			case GPT_GEOMETRY_PROGRAM:
+				return GPP_GS_5_0;
+			case GPT_HULL_PROGRAM:
+				return GPP_HS_5_0;
+			case GPT_DOMAIN_PROGRAM:
+				return GPP_DS_5_0;
+			case GPT_COMPUTE_PROGRAM:
+				return GPP_CS_5_0;
+			}
+		}
+		else if (target == RenderAPIDX9)
+		{
+			switch (type)
+			{
+			case GPT_VERTEX_PROGRAM:
+				return GPP_VS_3_0;
+			case GPT_FRAGMENT_PROGRAM:
+				return GPP_FS_3_0;
+			}
+		}
+
+		return GPP_NONE;
+	}
+}

+ 39 - 0
BansheeSL/Source/BsSLImporter.cpp

@@ -0,0 +1,39 @@
+#include "BsSLImporter.h"
+#include "BsDataStream.h"
+#include "BsFileSystem.h"
+#include "BsSLFXCompiler.h"
+
+namespace BansheeEngine
+{
+	SLImporter::SLImporter()
+		:SpecificImporter()
+	{
+
+	}
+
+	SLImporter::~SLImporter()
+	{
+
+	}
+
+	bool SLImporter::isExtensionSupported(const WString& ext) const
+	{
+		WString lowerCaseExt = ext;
+		StringUtil::toLowerCase(lowerCaseExt);
+
+		return lowerCaseExt == L"bsl";
+	}
+
+	bool SLImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
+	{
+		return true; // Plain-text so I don't even check for magic number
+	}
+
+	ResourcePtr SLImporter::import(const Path& filePath, ConstImportOptionsPtr importOptions)
+	{
+		DataStreamPtr stream = FileSystem::openFile(filePath);
+		String source = stream->getAsString();
+
+		return BSLFXCompiler::compile(source);
+	}
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 2 - 1084
BansheeSL/Source/BsSLPlugin.cpp


+ 3 - 5
TODO.txt

@@ -128,11 +128,10 @@ ShaderManager will also be needed when I'm changing shader defines
 ShaderManager will also be needed when switching render APIs during runtime (if that will be possible)
 ShaderManager will also be needed when switching render APIs during runtime (if that will be possible)
  - It can also serve as a place where we perform shader caching
  - It can also serve as a place where we perform shader caching
 
 
--------------------
+ - Separate languages for DX9 and DX11
+ - If I import a shader that tries to compile for a language different than we have available, create a null GpuProgram
 
 
-TODO STAGE 1:
- - Testing:
-   - If there are any new problems due to semantic and techniques using StringID
+-------------------
 
 
 TODO STAGE 2:
 TODO STAGE 2:
  - Handle include files (include files should just be plain text files with no additional parsing)
  - Handle include files (include files should just be plain text files with no additional parsing)
@@ -149,7 +148,6 @@ TODO STAGE 2:
 
 
 TODO STAGE 3:
 TODO STAGE 3:
  - Move all builtin shaders to the new .shader file model
  - Move all builtin shaders to the new .shader file model
- - Store example shader somewhere in Banshee data so I can use it for easy testing.
 
 
 TODO LATER:
 TODO LATER:
  - Add GpuProgram caching (e.g. save compiled programs somewhere for later use)
  - Add GpuProgram caching (e.g. save compiled programs somewhere for later use)

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels