/* Parses through the shader file and processes the tokens delivered by
 * DefTokeniser.
 */
void ShaderFileLoader::parseShaderFile(std::istream& inStr,
									   const std::string& filename)
{
	// Parse the file with a blocktokeniser, the actual block contents
	// will be parsed separately.
	parser::BasicDefBlockTokeniser<std::istream> tokeniser(inStr);

	while (tokeniser.hasMoreBlocks())
	{
		// Get the next block
		parser::BlockTokeniser::Block block = tokeniser.nextBlock();

		// Skip tables
		if (block.name.substr(0, 5) == "table")
		{
			std::string tableName = block.name.substr(6);

			if (tableName.empty())
			{
				rError() << "[shaders] " << filename << ": Missing table name." << std::endl;
				continue;
			}

			TableDefinitionPtr table(new TableDefinition(tableName, block.contents));

			if (!GetShaderSystem()->addTableDefinition(table))
			{
				rError() << "[shaders] " << filename
					<< ": table " << tableName << " already defined." << std::endl;
			}

			continue;
		}
		else if (block.name.substr(0, 5) == "skin ")
		{
			continue; // skip skin definition
		}
		else if (block.name.substr(0, 9) == "particle ")
		{
			continue; // skip particle definition
		}

		boost::algorithm::replace_all(block.name, "\\", "/"); // use forward slashes

		ShaderTemplatePtr shaderTemplate(new ShaderTemplate(block.name, block.contents));

		// Construct the ShaderDefinition wrapper class
		ShaderDefinition def(shaderTemplate, filename);

		// Insert into the definitions map, if not already present
		if (!GetShaderLibrary().addDefinition(block.name, def))
		{
    		rError() << "[shaders] " << filename
				<< ": shader " << block.name << " already defined." << std::endl;
		}
	}
}
ShaderDiscardCase* makeDiscardCase (Context& context, DiscardTemplate tmpl, DiscardMode mode)
{
	StringTemplate shaderTemplate(getTemplate(tmpl));

	map<string, string> params;

	switch (mode)
	{
		case DISCARDMODE_ALWAYS:	params["DISCARD"] = "discard";										break;
		case DISCARDMODE_NEVER:		params["DISCARD"] = "if (false) discard";							break;
		case DISCARDMODE_UNIFORM:	params["DISCARD"] = "if (ui_one > 0) discard";						break;
		case DISCARDMODE_DYNAMIC:	params["DISCARD"] = "if (v_coords.x+v_coords.y > 0.0) discard";		break;
		case DISCARDMODE_TEXTURE:	params["DISCARD"] = "if (texture(ut_brick, v_coords.xy*0.25+0.5).x < 0.7) discard";	break;
		default:
			DE_ASSERT(DE_FALSE);
			break;
	}

	string name			= string(getTemplateName(tmpl)) + "_" + getModeName(mode);
	string description	= string(getModeDesc(mode)) + " in " + getTemplateDesc(tmpl);

	return new ShaderDiscardCase(context, name.c_str(), description.c_str(), shaderTemplate.specialize(params).c_str(), getEvalFunc(mode), mode == DISCARDMODE_TEXTURE);
}