//============================================================================== void Skeleton::load(const CString& filename, ResourceInitializer& init) { XmlDocument doc; doc.loadFile(filename, init.m_tempAlloc); XmlElement rootEl = doc.getChildElement("skeleton"); XmlElement bonesEl = rootEl.getChildElement("bones"); // count the bones count U bonesCount = 0; XmlElement boneEl = bonesEl.getChildElement("bone"); do { ++bonesCount; boneEl = boneEl.getNextSiblingElement("bone"); } while(boneEl); // Alloc the vector m_bones = std::move(ResourceVector<Bone>(init.m_alloc)); m_bones.resize(bonesCount, Bone(init.m_alloc)); // Load every bone boneEl = bonesEl.getChildElement("bone"); bonesCount = 0; do { Bone& bone = m_bones[bonesCount++]; // <name> XmlElement nameEl = boneEl.getChildElement("name"); bone.m_name = nameEl.getText(); // <transform> XmlElement trfEl = boneEl.getChildElement("transform"); bone.m_transform = trfEl.getMat4(); // Advance boneEl = boneEl.getNextSiblingElement("bone"); } while(boneEl); }
//============================================================================== void MaterialProgramCreator::parseProgramsTag(const XmlElement& el) { // // First gather all the inputs // XmlElement programEl = el.getChildElement("program"_cstr); do { parseInputsTag(programEl); programEl = programEl.getNextSiblingElement("program"_cstr); } while(programEl); // Sort them by name to decrease the change of creating unique shaders std::sort(m_inputs.begin(), m_inputs.end(), InputSortFunctor()); // // Then parse the includes, operations and other parts of the program // programEl = el.getChildElement("program"_cstr); do { parseProgramTag(programEl); programEl = programEl.getNextSiblingElement("program"_cstr); } while(programEl); // // Sanity checks // // Check that all input is referenced for(Input& in : m_inputs) { if(in.m_shaderDefinedMask != in.m_shaderReferencedMask) { throw ANKI_EXCEPTION("Variable not referenced or not defined %s", &in.m_name[0]); } } }
Error Skeleton::load(const ResourceFilename& filename) { XmlDocument doc; ANKI_CHECK(openFileParseXml(filename, doc)); XmlElement rootEl; ANKI_CHECK(doc.getChildElement("skeleton", rootEl)); XmlElement bonesEl; ANKI_CHECK(rootEl.getChildElement("bones", bonesEl)); // count the bones count XmlElement boneEl; U32 bonesCount = 0; ANKI_CHECK(bonesEl.getChildElement("bone", boneEl)); ANKI_CHECK(boneEl.getSiblingElementsCount(bonesCount)); ++bonesCount; m_bones.create(getAllocator(), bonesCount); // Load every bone bonesCount = 0; do { Bone& bone = m_bones[bonesCount++]; // <name> XmlElement nameEl; ANKI_CHECK(boneEl.getChildElement("name", nameEl)); CString tmp; ANKI_CHECK(nameEl.getText(tmp)); bone.m_name.create(getAllocator(), tmp); // <transform> XmlElement trfEl; ANKI_CHECK(boneEl.getChildElement("transform", trfEl)); ANKI_CHECK(trfEl.getMat4(bone.m_transform)); // Advance ANKI_CHECK(boneEl.getNextSiblingElement("bone", boneEl)); } while(boneEl); return ErrorCode::NONE; }
//============================================================================== void MaterialProgramCreator::parseOperationTag( const XmlElement& operationTag, GLenum glshader, GLbitfield glshaderbit, MPString& out) { static const char OUT[] = {"out"}; // <id></id> I id = operationTag.getChildElement("id").getInt(); // <returnType></returnType> XmlElement retTypeEl = operationTag.getChildElement("returnType"); MPString retType(retTypeEl.getText(), m_alloc); MPString operationOut(m_alloc); if(retType != "void") { MPString tmp(MPString::toString(id, m_alloc)); operationOut = ANKI_STRL(OUT) + tmp; } // <function>functionName</function> MPString funcName( operationTag.getChildElement("function").getText(), m_alloc); // <arguments></arguments> XmlElement argsEl = operationTag.getChildElementOptional("arguments"); MPStringList argsList(m_alloc); if(argsEl) { // Get all arguments XmlElement argEl = argsEl.getChildElement("argument"); do { MPString arg(argEl.getText(), m_alloc); // Search for all the inputs and mark the appropriate Input* input = nullptr; for(Input& in : m_inputs) { // Check that the first part of the string is equal to the // variable and the following char is '[' if(in.m_name == arg) { input = ∈ in.m_shaderReferencedMask = glshaderbit; break; } } // The argument should be an input variable or an outXX if(!(input != nullptr || std::strncmp(&arg[0], OUT, sizeof(OUT) - 1) == 0)) { throw ANKI_EXCEPTION("Incorrect argument: %s", &arg[0]); } // Add to a list and do something special if instanced if(input && input->m_instanced) { if(glshader == GL_VERTEX_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[gl_InstanceID]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_TESS_CONTROL_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[vInstanceId[0]]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_TESS_EVALUATION_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[commonPatch.instanceId]"); m_instanceIdMask |= glshaderbit; } else if(glshader == GL_FRAGMENT_SHADER) { argsList.push_back(ANKI_STRL(argEl.getText()) + "[vInstanceId]"); m_instanceIdMask |= glshaderbit; } else { throw ANKI_EXCEPTION( "Cannot access the instance ID in all shaders"); } } else { argsList.push_back(MPString(argEl.getText(), m_alloc)); } // Advance argEl = argEl.getNextSiblingElement("argument"); } while(argEl); } // Now write everything MPString lines(m_alloc); lines.reserve(256); lines += "#if defined(" + funcName + "_DEFINED)"; // Write the defines for the operationOuts for(const MPString& arg : argsList) { if(arg.find(OUT) == 0) { lines += " && defined(" + arg + "_DEFINED)"; } } lines += "\n"; if(retType != "void") { lines += "#\tdefine " + operationOut + "_DEFINED\n\t" + retTypeEl.getText() + " " + operationOut + " = "; } else { lines += "\t"; } // write the blah = func(args...) lines += funcName + "("; lines += argsList.join(", "); lines += ");\n"; lines += "#endif"; // Done out = std::move(lines); }
//============================================================================== 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 MaterialProgramCreator::parseProgramTag( const XmlElement& programEl) { // <type> CString type = programEl.getChildElement("type"_cstr).getText(); GLbitfield glshaderbit; GLenum glshader; U shaderidx; getShaderInfo(type, glshader, glshaderbit, shaderidx); m_source[shaderidx] = MPStringList(m_alloc); auto& lines = m_source[shaderidx]; lines.push_back(ANKI_STRL("#pragma anki type "_cstr) + type); if(glshader == GL_TESS_CONTROL_SHADER || glshader == GL_TESS_EVALUATION_SHADER) { m_tessellation = true; } // <includes></includes> XmlElement includesEl = programEl.getChildElement("includes"_cstr); XmlElement includeEl = includesEl.getChildElement("include"_cstr); do { MPString fname(includeEl.getText(), m_alloc); lines.push_back( ANKI_STRL("#pragma anki include \""_cstr) + fname + "\""_cstr); includeEl = includeEl.getNextSiblingElement("include"_cstr); } while(includeEl); // Inputs // Block if(m_uniformBlock.size() > 0 && (m_uniformBlockReferencedMask | glshaderbit)) { // TODO Make block SSB when driver bug is fixed lines.push_back(ANKI_STRL( "\nlayout(binding = 0, std140) uniform bDefaultBlock\n{"_cstr)); lines.insert( lines.end(), m_uniformBlock.begin(), m_uniformBlock.end()); lines.push_back(ANKI_STRL("};")); } // Other variables for(Input& in : m_inputs) { if(!in.m_inBlock && (in.m_shaderDefinedMask | glshaderbit)) { lines.push_back(in.m_line); } } // <operations></operations> lines.push_back(ANKI_STRL("\nvoid main()\n{")); XmlElement opsEl = programEl.getChildElement("operations"); XmlElement opEl = opsEl.getChildElement("operation"); do { MPString out(m_alloc); parseOperationTag(opEl, glshader, glshaderbit, out); lines.push_back(out); // Advance opEl = opEl.getNextSiblingElement("operation"); } while(opEl); lines.push_back(ANKI_STRL("}\n")); }
//============================================================================== Error Animation::load(const ResourceFilename& filename) { XmlElement el; I64 tmp; F64 ftmp; m_startTime = MAX_F32; F32 maxTime = MIN_F32; // Document XmlDocument doc; ANKI_CHECK(openFileParseXml(filename, doc)); XmlElement rootel; ANKI_CHECK(doc.getChildElement("animation", rootel)); // Count the number of identity keys. If all of the keys are identities // drop a vector U identPosCount = 0; U identRotCount = 0; U identScaleCount = 0; // <repeat> XmlElement repel; ANKI_CHECK(rootel.getChildElementOptional("repeat", repel)); if(repel) { ANKI_CHECK(repel.getI64(tmp)); m_repeat = tmp; } else { m_repeat = false; } // <channels> XmlElement channelsEl; ANKI_CHECK(rootel.getChildElement("channels", channelsEl)); XmlElement chEl; ANKI_CHECK(channelsEl.getChildElement("channel", chEl)); U32 channelCount = 0; ANKI_CHECK(chEl.getSiblingElementsCount(channelCount)); if(channelCount == 0) { ANKI_LOGE("Didn't found any channels"); return ErrorCode::USER_DATA; } m_channels.create(getAllocator(), channelCount); // For all channels channelCount = 0; do { AnimationChannel& ch = m_channels[channelCount]; // <name> ANKI_CHECK(chEl.getChildElement("name", el)); CString strtmp; ANKI_CHECK(el.getText(strtmp)); ch.m_name.create(getAllocator(), strtmp); XmlElement keysEl, keyEl; // <positionKeys> ANKI_CHECK(chEl.getChildElementOptional("positionKeys", keysEl)); if(keysEl) { ANKI_CHECK(keysEl.getChildElement("key", keyEl)); U32 count = 0; ANKI_CHECK(keyEl.getSiblingElementsCount(count)); ch.m_positions.create(getAllocator(), count); count = 0; do { Key<Vec3>& key = ch.m_positions[count++]; // <time> ANKI_CHECK(keyEl.getChildElement("time", el)); ANKI_CHECK(el.getF64(ftmp)); key.m_time = ftmp; m_startTime = std::min(m_startTime, key.m_time); maxTime = std::max(maxTime, key.m_time); // <value> ANKI_CHECK(keyEl.getChildElement("value", el)); ANKI_CHECK(el.getVec3(key.m_value)); // Check ident if(key.m_value == Vec3(0.0)) { ++identPosCount; } // Move to next ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl)); } while(keyEl); } // <rotationKeys> ANKI_CHECK(chEl.getChildElement("rotationKeys", keysEl)); if(keysEl) { ANKI_CHECK(keysEl.getChildElement("key", keyEl)); U32 count = 0; ANKI_CHECK(keysEl.getSiblingElementsCount(count)); ch.m_rotations.create(getAllocator(), count); count = 0; do { Key<Quat>& key = ch.m_rotations[count++]; // <time> ANKI_CHECK(keyEl.getChildElement("time", el)); ANKI_CHECK(el.getF64(ftmp)); key.m_time = ftmp; m_startTime = std::min(m_startTime, key.m_time); maxTime = std::max(maxTime, key.m_time); // <value> Vec4 tmp2; ANKI_CHECK(keyEl.getChildElement("value", el)); ANKI_CHECK(el.getVec4(tmp2)); key.m_value = Quat(tmp2); // Check ident if(key.m_value == Quat::getIdentity()) { ++identRotCount; } // Move to next ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl)); } while(keyEl); } // <scalingKeys> ANKI_CHECK(chEl.getChildElementOptional("scalingKeys", keysEl)); if(keysEl) { ANKI_CHECK(keysEl.getChildElement("key", keyEl)); U32 count = 0; ANKI_CHECK(keyEl.getSiblingElementsCount(count)); ch.m_scales.create(getAllocator(), count); count = 0; do { Key<F32>& key = ch.m_scales[count++]; // <time> ANKI_CHECK(keyEl.getChildElement("time", el)); ANKI_CHECK(el.getF64(ftmp)); key.m_time = ftmp; m_startTime = std::min(m_startTime, key.m_time); maxTime = std::max(maxTime, key.m_time); // <value> ANKI_CHECK(keyEl.getChildElement("value", el)); ANKI_CHECK(el.getF64(ftmp)); key.m_value = ftmp; // Check ident if(isZero(key.m_value - 1.0)) { ++identScaleCount; } // Move to next ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl)); } while(keyEl); } // Remove identity vectors if(identPosCount == ch.m_positions.getSize()) { ch.m_positions.destroy(getAllocator()); } if(identRotCount == ch.m_rotations.getSize()) { ch.m_rotations.destroy(getAllocator()); } if(identScaleCount == ch.m_scales.getSize()) { ch.m_scales.destroy(getAllocator()); } // Move to next channel ++channelCount; ANKI_CHECK(chEl.getNextSiblingElement("channel", chEl)); } while(chEl); m_duration = maxTime - m_startTime; return ErrorCode::NONE; }