//============================================================================== 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 = ∈ 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); }
//============================================================================== 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(); }