Introduce node iterator.

pull/2966/head
Kim Kulling 2020-08-30 21:10:04 +02:00
parent 30a4eae17f
commit 6d5c388780
5 changed files with 172 additions and 100 deletions

View File

@ -291,10 +291,13 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
void AMFImporter::ParseNode_Root() {
std::string unit, version;
AMFNodeElementBase *ne(nullptr);
pugi::xml_node *root = mXmlParser->findNode("amf");
unit = root->attribute("unit").as_string();
version = root->attribute("version").as_string();
XmlNode *root = mXmlParser->findNode("amf");
if (nullptr == root) {
throw DeadlyImportError("Root node \"amf\" not found.");
}
XmlNode node = *root;
unit = node.attribute("unit").as_string();
version = node.attribute("version").as_string();
// Read attributes for node <amf>.
// Check attributes
@ -313,7 +316,7 @@ void AMFImporter::ParseNode_Root() {
((AMFRoot *)ne)->Version = version;
// Check for child nodes
for (pugi::xml_node &currentNode : root->children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "object") {
ParseNode_Object(currentNode);
@ -353,7 +356,7 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
}
// Check for child nodes
for (pugi::xml_node &currentNode : node.children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
std::string name = currentNode.name();
if (name == "instance") {
ParseNode_Instance(currentNode);
@ -392,7 +395,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
if (node.empty()) {
mNodeElement_Cur->Child.push_back(ne);
}
for (pugi::xml_node currentNode : node.children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
bool read_flag[6] = { false, false, false, false, false, false };
std::string currentName = currentNode.name();
if (currentName == "deltax") {
@ -447,7 +450,7 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
if (node.empty()) {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
}
for (pugi::xml_node &currentNode : node.children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "color") {
ParseNode_Color(currentNode);

View File

@ -196,7 +196,7 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
}
bool col_read = false;
for (pugi::xml_node currentNode : node.children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "color") {
if (col_read) Throw_MoreThanOnceDefined(currentName ,"color", "Only one color can be defined for <volume>.");
@ -238,7 +238,7 @@ void AMFImporter::ParseNode_Triangle(XmlNode &node) {
// Check for child nodes
bool col_read = false, tex_read = false;
bool read_flag[3] = { false, false, false };
for (pugi::xml_node currentNode : node.children()) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "color") {
if (col_read) Throw_MoreThanOnceDefined(currentName , "color", "Only one color can be defined for <triangle>.");

View File

@ -98,9 +98,13 @@ void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElem
return;
}
pVertexCoordinateArray.reserve(vn->Child.size()); // all coordinates stored as child and we need to reserve space for future push_back's.
pVertexColorArray.resize(vn->Child.size()); // colors count equal vertices count.
// all coordinates stored as child and we need to reserve space for future push_back's.
pVertexCoordinateArray.reserve(vn->Child.size());
// colors count equal vertices count.
pVertexColorArray.resize(vn->Child.size());
col_idx = 0;
// Inside vertices collect all data and place to arrays
for (AMFNodeElementBase *vn_child : vn->Child) {
// vertices, colors
@ -118,26 +122,20 @@ void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElem
pVertexColorArray[col_idx] = (AMFColor *)vtx;
continue;
}
} // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
}
col_idx++;
} // if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
} // for(CAMFImporter_NodeElement* vn_child: vn->Child)
}
}
}
size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B,
const std::string &pID_A) {
size_t TextureConverted_Index;
std::string TextureConverted_ID;
// check input data
if (pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty())
size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) {
if (r.empty() && g.empty() && b.empty() && a.empty()) {
throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
}
// Create ID
TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A;
// Check if texture specified by set of IDs is converted already.
TextureConverted_Index = 0;
std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a;
size_t TextureConverted_Index = 0;
for (const SPP_Texture &tex_convd : mTexture_Converted) {
if (tex_convd.ID == TextureConverted_ID) {
return TextureConverted_Index;
@ -146,10 +144,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
}
}
//
// Converted texture not found, create it.
//
AMFTexture *src_texture[4]{ nullptr };
AMFTexture *src_texture[4] {
nullptr
};
std::vector<AMFTexture *> src_texture_4check;
SPP_Texture converted_texture;
@ -157,8 +155,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
AMFNodeElementBase *t_tex = nullptr;
// R
if (!pID_R.empty()) {
if (!Find_NodeElement(pID_R, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
if (!r.empty()) {
if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) Throw_ID_NotFound(r);
src_texture[0] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
@ -167,8 +165,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
}
// G
if (!pID_G.empty()) {
if (!Find_NodeElement(pID_G, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
if (!g.empty()) {
if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(g);
src_texture[1] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
@ -177,8 +175,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
}
// B
if (!pID_B.empty()) {
if (!Find_NodeElement(pID_B, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
if (!b.empty()) {
if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(b);
src_texture[2] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
@ -187,8 +185,8 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
}
// A
if (!pID_A.empty()) {
if (!Find_NodeElement(pID_A, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
if (!a.empty()) {
if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) Throw_ID_NotFound(a);
src_texture[3] = (AMFTexture *)t_tex;
src_texture_4check.push_back((AMFTexture *)t_tex);
@ -218,10 +216,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
// Create format hint.
strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
if (!pID_R.empty()) converted_texture.FormatHint[4] = '8';
if (!pID_G.empty()) converted_texture.FormatHint[5] = '8';
if (!pID_B.empty()) converted_texture.FormatHint[6] = '8';
if (!pID_A.empty()) converted_texture.FormatHint[7] = '8';
if (!r.empty()) converted_texture.FormatHint[4] = '8';
if (!g.empty()) converted_texture.FormatHint[5] = '8';
if (!b.empty()) converted_texture.FormatHint[6] = '8';
if (!a.empty()) converted_texture.FormatHint[7] = '8';
// Сopy data of textures.
size_t tex_size = 0;
@ -230,19 +228,19 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
size_t off_b = 0;
// Calculate size of the target array and rule how data will be copied.
if (!pID_R.empty() && nullptr != src_texture[0]) {
if (!r.empty() && nullptr != src_texture[0]) {
tex_size += src_texture[0]->Data.size();
step++, off_g++, off_b++;
}
if (!pID_G.empty() && nullptr != src_texture[1]) {
if (!g.empty() && nullptr != src_texture[1]) {
tex_size += src_texture[1]->Data.size();
step++, off_b++;
}
if (!pID_B.empty() && nullptr != src_texture[2]) {
if (!b.empty() && nullptr != src_texture[2]) {
tex_size += src_texture[2]->Data.size();
step++;
}
if (!pID_A.empty() && nullptr != src_texture[3]) {
if (!a.empty() && nullptr != src_texture[3]) {
tex_size += src_texture[3]->Data.size();
step++;
}
@ -260,10 +258,10 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
}
}; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
CopyTextureData(pID_R, 0, step, 0);
CopyTextureData(pID_G, off_g, step, 1);
CopyTextureData(pID_B, off_b, step, 2);
CopyTextureData(pID_A, step - 1, step, 3);
CopyTextureData(r, 0, step, 0);
CopyTextureData(g, off_g, step, 1);
CopyTextureData(b, off_b, step, 2);
CopyTextureData(a, step - 1, step, 3);
// Store new converted texture ID
converted_texture.ID = TextureConverted_ID;

View File

@ -170,8 +170,9 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
if (nullptr == root) {
return std::string();
}
const char *filepath = root->value();
aiString ai_str(filepath);
std::string v;
XmlParser::getValueAsString(*root, v);
aiString ai_str(v);
UriDecodePath(ai_str);
return std::string(ai_str.C_Str());
}
@ -302,10 +303,11 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
mUnitSize = static_cast<ai_real>(attr.as_double());
}
} else if (name == "up_axis") {
const char *content = currentNode.value();
if (strncmp(content, "X_UP", 4) == 0) {
std::string v;
XmlParser::getValueAsString(currentNode, v);
if (v == "X_UP" ) {
mUpDirection = UP_X;
} else if (strncmp(content, "Z_UP", 4) == 0) {
} else if (v == "Z_UP" ) {
mUpDirection = UP_Z;
} else {
mUpDirection = UP_Y;
@ -334,21 +336,23 @@ void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) {
const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
const std::string name = node.name();
if (!name.empty()) {
const char *value_char = node.value();
if (nullptr != value_char) {
aiString aistr;
aistr.Set(value_char);
if (name.empty()) {
return;
}
std::string camel_key_str(name);
ToCamelCase(camel_key_str);
std::string v;
if (XmlParser::getValueAsString(node, v)) {
aiString aistr;
aistr.Set(v);
size_t found_index;
if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
metadata.emplace(key_renaming[found_index].second, aistr);
} else {
metadata.emplace(camel_key_str, aistr);
}
std::string camel_key_str(name);
ToCamelCase(camel_key_str);
size_t found_index;
if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
metadata.emplace(key_renaming[found_index].second, aistr);
} else {
metadata.emplace(camel_key_str, aistr);
}
}
}
@ -588,17 +592,9 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
return;
}
int attrId = node.attribute("id").as_int();
std::string id = node.value();
std::string id = node.attribute("id").as_string();
mControllerLibrary[id] = Controller();
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string currentName = currentNode.name();
if (currentName == "controller") {
attrId = currentNode.attribute("id").as_int();
std::string controllerId = currentNode.attribute(std::to_string(attrId).c_str()).value();
ReadController(node, mControllerLibrary[controllerId]);
}
}
ReadController(node, mControllerLibrary[id]);
}
// ------------------------------------------------------------------------------------------------
@ -614,8 +610,10 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
pController.mMeshId = currentNode.attribute("source").as_string();
int methodIndex = currentNode.attribute("method").as_int();
if (methodIndex > 0) {
const char *method = currentNode.attribute("method").value();
if (strcmp(method, "RELATIVE") == 0) {
std::string method;
XmlParser::getValueAsString(currentNode, method);
if (method == "RELATIVE" ) {
pController.mMethod = Relative;
}
}
@ -722,9 +720,11 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
pController.mWeights.resize(numWeights);
} else if (currentName == "v" && vertexCount > 0) {
// read JointIndex - WeightIndex pairs
const char *text = currentNode.value();
std::string stdText;
XmlParser::getValueAsString(currentNode, stdText);
const char *text = stdText.c_str();
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
if (*text == 0) {
if (text == 0) {
ThrowException("Out of data while reading <vertex_weights>");
}
it->first = strtoul10(text, &text);
@ -770,13 +770,12 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
// FIX: C4D exporter writes empty <init_from/> tags
if (!currentNode.empty()) {
// element content is filename - hopefully
const char *sz = currentNode.value();
const char *sz = currentNode.text().as_string();
if (sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
// TestClosing("init_from");
}
if (!pImage.mFileName.length()) {
pImage.mFileName = "unknown_texture";
@ -800,13 +799,13 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
// TODO: correctly jump over cube and volume maps?
}
} else if (mFormat == FV_1_5_n) {
std::string value;
XmlNode refChild = currentNode.child("ref");
XmlNode hexChild = currentNode.child("hex");
if (refChild) {
// element content is filename - hopefully
const char *sz = refChild.value();
if (sz) {
aiString filepath(sz);
if (XmlParser::getValueAsString(refChild, value)) {
aiString filepath(value);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
@ -817,8 +816,8 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
ASSIMP_LOG_WARN("Collada: Unknown image file format");
}
const char *data = hexChild.value();
XmlParser::getValueAsString(hexChild, value);
const char *data = value.c_str();
// hexadecimal-encoded binary octets. First of all, find the
// required buffer size to reserve enough storage.
const char *cur = data;
@ -924,7 +923,10 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
// ------------------------------------------------------------------------------------------------
// Reads a light entry into the given light
void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
XmlNodeIterator xmlIt;
xmlIt.collectChildrenPreOrder(node);
XmlNode currentNode;
while (xmlIt.getNext(currentNode)) {
const std::string &currentName = currentNode.name();
if (currentName == "spot") {
pLight.mType = aiLightSource_SPOT;
@ -936,7 +938,9 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
pLight.mType = aiLightSource_POINT;
} else if (currentName == "color") {
// text content contains 3 floats
const char *content = currentNode.value();
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
SkipSpacesAndLineEnd(&content);
@ -1156,8 +1160,9 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) {
} else if (currentName == "rotateUV") {
XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mRotation);
} else if (currentName == "blend_mode") {
const char *sz = currentNode.value();
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *sz = v.c_str();
// http://www.feelingsoftware.com/content/view/55/72/lang,en/
// NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE
if (0 == ASSIMP_strincmp(sz, "ADD", 3))
@ -1196,7 +1201,9 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p
const std::string &currentName = currentNode.name();
if (currentName == "color") {
// text content contains 4 floats
const char *content = currentNode.value();
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
content = fast_atoreal_move<ai_real>(content, (ai_real &)pColor.r);
SkipSpacesAndLineEnd(&content);
@ -1353,9 +1360,10 @@ void ColladaParser::ReadSource(XmlNode &node) {
if (currentName == "float_array" || currentName == "IDREF_array" || currentName == "Name_array") {
ReadDataArray(currentNode);
} else if (currentName == "technique_common") {
// I don't care for your profiles
} else if (currentName == "accessor") {
ReadAccessor(currentNode, sourceID);
XmlNode technique = currentNode.child("accessor");
if (!technique.empty()) {
ReadAccessor(technique, sourceID);
}
}
}
}
@ -1371,7 +1379,9 @@ void ColladaParser::ReadDataArray(XmlNode &node) {
XmlParser::getStdStrAttribute(node, "id", id);
unsigned int count;
XmlParser::getUIntAttribute(node, "count", count);
const char *content = node.value();
std::string v;
XmlParser::getValueAsString(node, v);
const char *content = v.c_str();
// read values and store inside an array in the data library
mDataLibrary[id] = Data();
@ -1575,7 +1585,9 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
if (numPrimitives) // It is possible to define a mesh without any primitives
{
// case <polylist> - specifies the number of indices for each polygon
const char *content = currentNode.value();
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
vcount.reserve(numPrimitives);
for (unsigned int a = 0; a < numPrimitives; a++) {
if (*content == 0)
@ -1694,7 +1706,9 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
if (pNumPrimitives > 0) // It is possible to not contain any indices
{
const char *content = node.value();
std::string v;
XmlParser::getValueAsString(node, v);
const char *content = v.c_str();
while (*content != 0) {
// read a value.
// Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways.

View File

@ -209,7 +209,18 @@ public:
}
private:
static inline bool getValueAsString( XmlNode &node, std::string &text ) {
text = "";
if (node.empty()) {
return false;
}
text = node.text().as_string();
return true;
}
private:
pugi::xml_document *mDoc;
TNodeType *mRoot;
TNodeType mCurrent;
@ -218,6 +229,52 @@ private:
using XmlParser = TXmlParser<pugi::xml_node>;
class XmlNodeIterator {
public:
XmlNodeIterator() :
mNodes(),
mIndex(9999999) {
// empty
}
void collectChildrenPreOrder( XmlNode &node ) {
mNodes.push_back(&node);
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
collectChildrenPreOrder(currentNode);
}
}
void collectChildrenPostOrder(XmlNode &node) {
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
collectChildrenPostOrder(currentNode);
}
mNodes.push_back(&node);
}
bool getNext(XmlNode &next) {
if (mIndex == mNodes.size()) {
return false;
}
mNodes[mIndex];
++mIndex;
return true;
}
void clear() {
if (mNodes.empty()) {
return;
}
mNodes.clear();
}
private:
std::vector<XmlNode *> mNodes;
size_t mIndex;
TraverseOrder mTraverseOrder;
};
} // namespace Assimp
#endif // !! INCLUDED_AI_IRRXML_WRAPPER