//==============================================================================
void MaterialProgramCreator::parseInputsTag(const XmlElement& programEl)
{
	XmlElement inputsEl = programEl.getChildElementOptional("inputs");
	if(!inputsEl)
	{
		return;
	}

	// Get shader type
	GLbitfield glshaderbit;
	GLenum glshader;
	U shaderidx;
	getShaderInfo(
		programEl.getChildElement("type").getText(), 
		glshader, glshaderbit, shaderidx);

	XmlElement inputEl = inputsEl.getChildElement("input");
	do
	{
		Input inpvar(m_alloc);

		// <name>
		inpvar.m_name = inputEl.getChildElement("name").getText();

		// <type>
		inpvar.m_type = inputEl.getChildElement("type").getText();

		// <value>
		XmlElement valueEl = inputEl.getChildElement("value");
		if(valueEl.getText())
		{
			inpvar.m_value = MPStringList::splitString(
				valueEl.getText(), ' ', m_alloc);
		}

		// <const>
		XmlElement constEl = inputEl.getChildElementOptional("const");
		inpvar.m_constant = (constEl) ? constEl.getInt() : false;

		// <arraySize>
		XmlElement arrSizeEl = inputEl.getChildElementOptional("arraySize");
		inpvar.m_arraySize = (arrSizeEl) ? arrSizeEl.getInt() : 0;

		// <instanced>
		if(inpvar.m_arraySize == 0)
		{
			XmlElement instancedEl = 
				inputEl.getChildElementOptional("instanced");

			inpvar.m_instanced = (instancedEl) ? instancedEl.getInt() : 0;

			// If one input var is instanced notify the whole program that 
			// it's instanced
			if(inpvar.m_instanced)
			{
				m_instanced = true;
			}
		}

		// Now you have the info to check if duplicate
		Input* duplicateInp = nullptr;
		for(Input& in : m_inputs)
		{
			if(in.m_name == inpvar.m_name)
			{
				duplicateInp = &in;
				break;
			}
		}

		if(duplicateInp != nullptr)
		{
			// Duplicate. Make sure it's the same as the other shader
			Bool same = duplicateInp->m_type == inpvar.m_type
				|| duplicateInp->m_value == inpvar.m_value
				|| duplicateInp->m_constant == inpvar.m_constant
				|| duplicateInp->m_arraySize == inpvar.m_arraySize
				|| duplicateInp->m_instanced == inpvar.m_instanced;

			if(!same)
			{
				throw ANKI_EXCEPTION("Variable defined differently between "
					"shaders: %s", &inpvar.m_name[0]);
			}

			duplicateInp->m_shaderDefinedMask |= glshaderbit;

			goto advance;
		}

		if(inpvar.m_constant == false)
		{
			// Handle NON-consts

			inpvar.m_line = inpvar.m_type + " " + inpvar.m_name;
				
			if(inpvar.m_arraySize > 1)
			{
				MPString tmp(MPString::toString(inpvar.m_arraySize, m_alloc));
				inpvar.m_line += "[" + tmp + "U]";
			}

			if(inpvar.m_instanced)
			{
				MPString tmp(
					MPString::toString(ANKI_GL_MAX_INSTANCES, m_alloc));
				inpvar.m_line += "[" +  tmp + "U]";
			}

			inpvar.m_line += ";";

			// Can put it block
			if(inpvar.m_type == "sampler2D" || inpvar.m_type == "samplerCube")
			{
				MPString tmp(
					MPString::toString(m_texBinding++, m_alloc));

				inpvar.m_line = ANKI_STRL("layout(binding = ") 
					+ tmp + ") uniform " + inpvar.m_line;
		
				inpvar.m_inBlock = false;
			}
			else
			{
				inpvar.m_inBlock = true;

				m_uniformBlock.push_back(inpvar.m_line);
				m_uniformBlockReferencedMask |= glshaderbit;
			}
		}
		else
		{
			// Handle consts

			if(inpvar.m_value.size() == 0)
			{
				throw ANKI_EXCEPTION("Empty value and const is illogical");
			}

			if(inpvar.m_arraySize > 0)
			{
				throw ANKI_EXCEPTION("Const arrays currently cannot "
					"be handled");
			}

			inpvar.m_inBlock = false;

			inpvar.m_line = ANKI_STRL("const ") 
				+ inpvar.m_type + " " + inpvar.m_name 
				+ " = " + inpvar.m_type + "(" + inpvar.m_value.join(", ") 
				+  ");";
		}

		inpvar.m_shaderDefinedMask = glshaderbit;
		m_inputs.push_back(inpvar);

advance:
		// Advance
		inputEl = inputEl.getNextSiblingElement("input");
	} while(inputEl);
}
Пример #2
0
//==============================================================================
void Material::parseMaterialTag(const XmlElement& materialEl,
	ResourceInitializer& rinit)
{
	// levelsOfDetail
	//
	XmlElement lodEl = materialEl.getChildElementOptional("levelsOfDetail");

	if(lodEl)
	{
		I tmp = lodEl.getInt();
		m_lodsCount = (tmp < 1) ? 1 : tmp;
	}
	else
	{
		m_lodsCount = 1;
	}

	// shadow
	//
	XmlElement shadowEl = materialEl.getChildElementOptional("shadow");

	if(shadowEl)
	{
		m_shadow = shadowEl.getInt();
	}

	// blendFunctions
	//
	XmlElement blendFunctionsEl =
		materialEl.getChildElementOptional("blendFunctions");

	if(blendFunctionsEl)
	{
		// sFactor
		m_blendingSfactor = blendToEnum(
			blendFunctionsEl.getChildElement("sFactor").getText());

		// dFactor
		m_blendingDfactor = blendToEnum(
			blendFunctionsEl.getChildElement("dFactor").getText());
	}
	else
	{
		m_passesCount = 2;
	}

	// depthTesting
	//
	XmlElement depthTestingEl =
		materialEl.getChildElementOptional("depthTesting");

	if(depthTestingEl)
	{
		m_depthTesting = depthTestingEl.getInt();
	}

	// wireframe
	//
	XmlElement wireframeEl = materialEl.getChildElementOptional("wireframe");

	if(wireframeEl)
	{
		m_wireframe = wireframeEl.getInt();
	}

	// shaderProgram
	//
	MaterialProgramCreator mspc(
		materialEl.getChildElement("programs"),
		rinit.m_tempAlloc);

	m_tessellation = mspc.hasTessellation();
	U tessCount = m_tessellation ? 2 : 1;

	// Alloc program vector
	U progCount = 0;
	progCount += m_passesCount * m_lodsCount * tessCount;
	if(m_tessellation)
	{
		progCount += m_passesCount * m_lodsCount * 2;
	}
	progCount += m_passesCount * m_lodsCount;
	m_progs.resize(progCount);

	// Aloc progam descriptors
	m_pplines.resize(m_passesCount * m_lodsCount * tessCount);

	m_hash = 0;
	for(U shader = 0; shader < 5; shader++)
	{
		if(!m_tessellation && (shader == 1 || shader == 2))
		{
			continue;
		}

		if(shader == 3)
		{
			continue;
		}

		for(U level = 0; level < m_lodsCount; ++level)
		{
			for(U pid = 0; pid < m_passesCount; ++pid)
			{
				for(U tess = 0; tess < tessCount; ++tess)
				{
					TempResourceString src(rinit.m_tempAlloc);

					src.sprintf("#define LOD %u\n"
						"#define PASS %u\n"
						"#define TESSELLATION %u\n", 
						level, pid, tess);

					TempResourceString filename =
						createProgramSourceToChache(src);

					RenderingKey key((Pass)pid, level, tess);
					ProgramResourcePointer& progr = getProgram(key, shader);
					progr.load(filename.toCString(), &rinit.m_resources);

					// Update the hash
					m_hash ^= computeHash(&src[0], src.getLength());
				}
			}
		}
	}

	populateVariables(mspc);

	// Get uniform block size
	ANKI_ASSERT(m_progs.size() > 0);
	m_shaderBlockSize = 
		m_progs[0]->getGlProgram().findBlock("bDefaultBlock").getSize();
}