ogre + collada migration.

pull/2966/head
Kim Kulling 2020-07-10 22:25:38 +02:00
parent 77b705048b
commit 21678df589
9 changed files with 892 additions and 807 deletions

View File

@ -181,118 +181,10 @@ void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) {
} }
} }
/*void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeName) {
static const size_t Uns_Skip_Len = 3;
const char *Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
static bool skipped_before[Uns_Skip_Len] = { false, false, false };
std::string nn(mReader->getNodeName());
bool found = false;
bool close_found = false;
size_t sk_idx;
for (sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) {
if (nn != Uns_Skip[sk_idx]) continue;
found = true;
if (mReader->isEmptyElement()) {
close_found = true;
goto casu_cres;
}
while (mReader->read()) {
if ((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) {
close_found = true;
goto casu_cres;
}
}
} // for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
casu_cres:
if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
if (!close_found) Throw_CloseNotFound(nn);
if (!skipped_before[sk_idx]) {
skipped_before[sk_idx] = true;
ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
}
}*/
bool AMFImporter::XML_SearchNode(const std::string &nodeName) { bool AMFImporter::XML_SearchNode(const std::string &nodeName) {
return nullptr != mXmlParser->findNode(nodeName); return nullptr != mXmlParser->findNode(nodeName);
} }
/*bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) {
std::string val(mReader->getAttributeValue(pAttrIdx));
if ((val == "false") || (val == "0"))
return false;
else if ((val == "true") || (val == "1"))
return true;
else
throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
}
float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) {
std::string val;
float tvalf;
ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) {
return strtoul10(mReader->getAttributeValue(pAttrIdx));
}
float AMFImporter::XML_ReadNode_GetVal_AsFloat() {
std::string val;
float tvalf;
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
fast_atoreal_move(val.c_str(), tvalf, false);
return tvalf;
}
uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32() {
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
return strtoul10(mReader->getNodeData());
}
void AMFImporter::XML_ReadNode_GetVal_AsString(std::string &pValue) {
if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
if (mReader->getNodeType() != irr::io::EXN_TEXT)
throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
pValue = mReader->getNodeData();
}*/
/*********************************************************************************************************************************************/
/************************************************************ Functions: parse set ***********************************************************/
/*********************************************************************************************************************************************/
/*void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement *pNode) {
mNodeElement_Cur->Child.push_back(pNode); // add new element to current element child list.
mNodeElement_Cur = pNode; // switch current element to new one.
}
void AMFImporter::ParseHelper_Node_Exit() {
// check if we can walk up.
if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
}
*/
void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) { void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
size_t instr_len; size_t instr_len;
@ -369,7 +261,6 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
} }
void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) { void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
// irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb")); std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// Check whether we can read from the file // Check whether we can read from the file
@ -388,8 +279,6 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
throw DeadlyImportError("Root node \"amf\" not found."); throw DeadlyImportError("Root node \"amf\" not found.");
} }
ParseNode_Root(); ParseNode_Root();
//delete mReader;
} // namespace Assimp } // namespace Assimp
// <amf // <amf
@ -408,11 +297,6 @@ void AMFImporter::ParseNode_Root() {
version = root->attribute("version").as_string(); version = root->attribute("version").as_string();
// Read attributes for node <amf>. // Read attributes for node <amf>.
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND_WSKIP;*/
// Check attributes // Check attributes
if (!mUnit.empty()) { if (!mUnit.empty()) {
if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) { if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) {
@ -428,6 +312,7 @@ void AMFImporter::ParseNode_Root() {
((AMFRoot *)ne)->Unit = unit; ((AMFRoot *)ne)->Unit = unit;
((AMFRoot *)ne)->Version = version; ((AMFRoot *)ne)->Version = version;
// Check for child nodes
for (pugi::xml_node &currentNode : root->children()) { for (pugi::xml_node &currentNode : root->children()) {
const std::string currentName = currentNode.name(); const std::string currentName = currentNode.name();
if (currentName == "object") { if (currentName == "object") {
@ -443,32 +328,6 @@ void AMFImporter::ParseNode_Root() {
} }
mNodeElement_Cur = ne; // force restore "current" element mNodeElement_Cur = ne; // force restore "current" element
} }
// Check for child nodes
/*if (!mReader->isEmptyElement()) {
MACRO_NODECHECK_LOOPBEGIN("amf");
if (XML_CheckNode_NameEqual("object")) {
ParseNode_Object();
continue;
}
if (XML_CheckNode_NameEqual("material")) {
ParseNode_Material();
continue;
}
if (XML_CheckNode_NameEqual("texture")) {
ParseNode_Texture();
continue;
}
if (XML_CheckNode_NameEqual("constellation")) {
ParseNode_Constellation();
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("amf");
mNodeElement_Cur = ne; // force restore "current" element
} // if(!mReader->isEmptyElement())*/
mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
} }
@ -483,10 +342,6 @@ void AMFImporter::ParseNode_Root() {
void AMFImporter::ParseNode_Constellation(XmlNode &node) { void AMFImporter::ParseNode_Constellation(XmlNode &node) {
std::string id; std::string id;
id = node.attribute("id").as_string(); id = node.attribute("id").as_string();
// Read attributes for node <constellation>.
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;*/
// create and if needed - define new grouping object. // create and if needed - define new grouping object.
AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
@ -497,6 +352,7 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
als.ID = id; als.ID = id;
} }
// Check for child nodes
for (pugi::xml_node &currentNode : node.children()) { for (pugi::xml_node &currentNode : node.children()) {
std::string name = currentNode.name(); std::string name = currentNode.name();
if (name == "instance") { if (name == "instance") {
@ -509,26 +365,6 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
mNodeElement_Cur->Child.push_back(ne); mNodeElement_Cur->Child.push_back(ne);
} }
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
// Check for child nodes
/*if (!mReader->isEmptyElement()) {
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("constellation");
if (XML_CheckNode_NameEqual("instance")) {
ParseNode_Instance();
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("constellation");
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.*/
} }
// <instance // <instance
@ -542,9 +378,6 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
AMFNodeElementBase *ne(nullptr); AMFNodeElementBase *ne(nullptr);
// Read attributes for node <constellation>. // Read attributes for node <constellation>.
/* MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;*/
std::string objectid = node.attribute("objectid").as_string(); std::string objectid = node.attribute("objectid").as_string();
// used object id must be defined, check that. // used object id must be defined, check that.
@ -552,9 +385,7 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
throw DeadlyImportError("\"objectid\" in <instance> must be defined."); throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
} }
// create and define new grouping object. // create and define new grouping object.
//ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
ne = new AMFInstance(mNodeElement_Cur); ne = new AMFInstance(mNodeElement_Cur);
//CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience
AMFInstance &als = *((AMFInstance *)ne); AMFInstance &als = *((AMFInstance *)ne);
als.ObjectID = objectid; als.ObjectID = objectid;
@ -584,29 +415,6 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
als.Delta.z = (ai_real)std::atof(currentNode.value()); als.Delta.z = (ai_real)std::atof(currentNode.value());
} }
} }
// Check for child nodes
/*if (!mReader->isEmptyElement()) {
als.Delta.Set(0, 0, 0);
als.Rotation.Set(0, 0, 0);
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("instance");
MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
MACRO_NODECHECK_LOOPEND("instance");
ParseHelper_Node_Exit();
// also convert degrees to radians.
als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -623,10 +431,8 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
AMFNodeElementBase *ne(nullptr); AMFNodeElementBase *ne(nullptr);
// Read attributes for node <object>. // Read attributes for node <object>.
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;*/
std::string id = node.attribute("id").as_string(); std::string id = node.attribute("id").as_string();
// create and if needed - define new geometry object. // create and if needed - define new geometry object.
ne = new AMFObject(mNodeElement_Cur); ne = new AMFObject(mNodeElement_Cur);
@ -652,35 +458,6 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
ParseNode_Metadata(currentNode); ParseNode_Metadata(currentNode);
} }
} }
/*if (!mReader->isEmptyElement()) {
bool col_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("object");
if (XML_CheckNode_NameEqual("color")) {
// Check if color already defined for object.
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if (XML_CheckNode_NameEqual("mesh")) {
ParseNode_Mesh();
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("object");
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {*/
//mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
//} // if(!mReader->isEmptyElement()) else
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -711,12 +488,6 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
value = node.value(); value = node.value();
// read attribute // read attribute
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;*/
// and value of node.
//value = mReader->getNodeData();
// Create node element and assign read data.
ne = new AMFMetadata(mNodeElement_Cur); ne = new AMFMetadata(mNodeElement_Cur);
((AMFMetadata *)ne)->Type = type; ((AMFMetadata *)ne)->Type = type;
((AMFMetadata *)ne)->Value = value; ((AMFMetadata *)ne)->Value = value;
@ -724,10 +495,6 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
/*********************************************************************************************************************************************/
/******************************************************** Functions: BaseImporter set ********************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const { bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);

View File

@ -101,7 +101,6 @@ class AMFImporter : public BaseImporter {
private: private:
struct SPP_Material; // forward declaration struct SPP_Material; // forward declaration
/// \struct SPP_Composite
/// Data type for post-processing step. More suitable container for part of material's composition. /// Data type for post-processing step. More suitable container for part of material's composition.
struct SPP_Composite { struct SPP_Composite {
SPP_Material *Material; ///< Pointer to material - part of composition. SPP_Material *Material; ///< Pointer to material - part of composition.

View File

@ -81,29 +81,6 @@ void AMFImporter::ParseNode_Mesh(XmlNode &node) {
found_volumes = true; found_volumes = true;
} }
/*if(!mReader->isEmptyElement())
{
bool vert_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("mesh");
if(XML_CheckNode_NameEqual("vertices"))
{
// Check if data already defined.
if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
// read data and set flag about it
ParseNode_Vertices();
vert_read = true;
continue;
}
if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; }
MACRO_NODECHECK_LOOPEND("mesh");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else*/
// Add element to child list of current element
if (!found_verts && !found_volumes) { if (!found_verts && !found_volumes) {
mNodeElement_Cur->Child.push_back(ne); mNodeElement_Cur->Child.push_back(ne);
} // if(!mReader->isEmptyElement()) else } // if(!mReader->isEmptyElement()) else
@ -130,20 +107,6 @@ void AMFImporter::ParseNode_Vertices(XmlNode &node) {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else } // if(!mReader->isEmptyElement()) else
/*if (!mReader->isEmptyElement()) {
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertices");
if (XML_CheckNode_NameEqual("vertex")) {
ParseNode_Vertex();
continue;
}
MACRO_NODECHECK_LOOPEND("vertices");
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -157,6 +120,8 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) {
// create new mesh object. // create new mesh object.
ne = new AMFVertex(mNodeElement_Cur); ne = new AMFVertex(mNodeElement_Cur);
// Check for child nodes
pugi::xml_node colorNode = node.child("color"); pugi::xml_node colorNode = node.child("color");
bool col_read = false; bool col_read = false;
bool coord_read = false; bool coord_read = false;
@ -173,42 +138,6 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} }
// Check for child nodes
/* if (!mReader->isEmptyElement()) {
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("vertex");
if (XML_CheckNode_NameEqual("color")) {
// Check if data already defined.
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if (XML_CheckNode_NameEqual("coordinates")) {
// Check if data already defined.
if (coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for <vertex>.");
// read data and set flag about it
ParseNode_Coordinates();
coord_read = true;
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("vertex");
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -238,25 +167,6 @@ void AMFImporter::ParseNode_Coordinates(XmlNode &node) {
mNodeElement_Cur->Child.push_back(ne); mNodeElement_Cur->Child.push_back(ne);
} }
/*// Check for child nodes
if (!mReader->isEmptyElement()) {
bool read_flag[3] = { false, false, false };
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("coordinates");
MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x);
MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y);
MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z);
MACRO_NODECHECK_LOOPEND("coordinates");
ParseHelper_Node_Exit();
// check that all components was defined
if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined.");
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -275,13 +185,6 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur);
// Read attributes for node <color>. // Read attributes for node <color>.
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;*/
// create new object.
//ne = new CAMFImporter_NodeElement_Volume(mNodeElement_Cur);
// and assign read data // and assign read data
((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string(); ((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string();
@ -308,36 +211,6 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
} }
} }
/*if (!mReader->isEmptyElement()) {
bool col_read = false;
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("volume");
if (XML_CheckNode_NameEqual("color")) {
// Check if data already defined.
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <volume>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if (XML_CheckNode_NameEqual("triangle")) {
ParseNode_Triangle();
continue;
}
if (XML_CheckNode_NameEqual("metadata")) {
ParseNode_Metadata();
continue;
}
MACRO_NODECHECK_LOOPEND("volume");
ParseHelper_Node_Exit();
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }
@ -354,14 +227,15 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
void AMFImporter::ParseNode_Triangle(XmlNode &node) { void AMFImporter::ParseNode_Triangle(XmlNode &node) {
AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur); AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur);
// create new color object. // create new triangle object.
//ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience
if (node.empty()) { if (node.empty()) {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} }
// Check for child nodes
bool col_read = false, tex_read = false; bool col_read = false, tex_read = false;
bool read_flag[3] = { false, false, false }; bool read_flag[3] = { false, false, false };
for (pugi::xml_node currentNode : node.children()) { for (pugi::xml_node currentNode : node.children()) {
@ -387,59 +261,11 @@ void AMFImporter::ParseNode_Triangle(XmlNode &node) {
read_flag[2] = true; read_flag[2] = true;
} }
} }
if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined."); if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) {
throw DeadlyImportError("Not all vertices of the triangle are defined.");
}
// Check for child nodes
/*if (!mReader->isEmptyElement()) {
bool col_read = false, tex_read = false;
bool read_flag[3] = { false, false, false };
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("triangle");
if (XML_CheckNode_NameEqual("color")) {
// Check if data already defined.
if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <triangle>.");
// read data and set flag about it
ParseNode_Color();
col_read = true;
continue;
}
if (XML_CheckNode_NameEqual("texmap")) // new name of node: "texmap".
{
// Check if data already defined.
if (tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for <triangle>.");
// read data and set flag about it
ParseNode_TexMap();
tex_read = true;
continue;
} else if (XML_CheckNode_NameEqual("map")) // old name of node: "map".
{
// Check if data already defined.
if (tex_read) Throw_MoreThanOnceDefined("map", "Only one texture coordinate can be defined for <triangle>.");
// read data and set flag about it
ParseNode_TexMap(true);
tex_read = true;
continue;
}
MACRO_NODECHECK_READCOMP_U32("v1", read_flag[0], als.V[0]);
MACRO_NODECHECK_READCOMP_U32("v2", read_flag[1], als.V[1]);
MACRO_NODECHECK_READCOMP_U32("v3", read_flag[2], als.V[2]);
MACRO_NODECHECK_LOOPEND("triangle");
ParseHelper_Node_Exit();
// check that all components was defined
if ((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined.");
} // if(!mReader->isEmptyElement())
else {
mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
} // if(!mReader->isEmptyElement()) else
*/
mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph. mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
} }

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,

View File

@ -177,9 +177,6 @@ void AMFImporter::ParseNode_Texture(XmlNode &node) {
std::string enc64_data = node.value(); std::string enc64_data = node.value();
// Check for child nodes // Check for child nodes
//if (!mXmlParser->isEmptyElement()) {
// XML_ReadNode_GetVal_AsString(enc64_data);
//}
// check that all components was defined // check that all components was defined
if (id.empty()) { if (id.empty()) {

View File

@ -45,24 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaLoader.h" #include "ColladaLoader.h"
#include "ColladaParser.h" #include "ColladaParser.h"
#include <assimp/ColladaMetaData.h> #include <assimp/ColladaMetaData.h>
#include <assimp/Defines.h>
#include <assimp/anim.h>
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/CreateAnimMesh.h> #include <assimp/CreateAnimMesh.h>
#include <assimp/Defines.h>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/anim.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/importerdesc.h>
#include "math.h" #include <assimp/scene.h>
#include "time.h" #include <math.h>
#include <time.h>
#include <algorithm> #include <algorithm>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
@ -125,20 +122,17 @@ ColladaLoader::~ColladaLoader() {
bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
// check file extension // check file extension
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
const bool readSig = checkSig && (pIOHandler != nullptr);
bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) { if (!readSig) {
if (extension == "dae" || extension == "zae") { if (extension == "dae" || extension == "zae") {
return true; return true;
} }
} } else {
if (readSig) {
// Look for a DAE file inside, but don't extract it // Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile); ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen()) if (zip_archive.isOpen()) {
return !ColladaParser::ReadZaeManifest(zip_archive).empty(); return !ColladaParser::ReadZaeManifest(zip_archive).empty();
}
} }
// XML - too generic, we need to open the file and search for typical keywords // XML - too generic, we need to open the file and search for typical keywords
@ -585,10 +579,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Colla
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Find mesh from either meshes or morph target meshes // Find mesh from either meshes or morph target meshes
aiMesh *ColladaLoader::findMesh(const std::string &meshid) { aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
if ( meshid.empty()) { if (meshid.empty()) {
return nullptr; return nullptr;
} }
for (unsigned int i = 0; i < mMeshes.size(); ++i) { for (unsigned int i = 0; i < mMeshes.size(); ++i) {
if (std::string(mMeshes[i]->mName.data) == meshid) { if (std::string(mMeshes[i]->mName.data) == meshid) {
return mMeshes[i]; return mMeshes[i];
@ -1377,9 +1371,9 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
double time = double(mat.d4); // remember? time is stored in mat.d4 double time = double(mat.d4); // remember? time is stored in mat.d4
mat.d4 = 1.0f; mat.d4 = 1.0f;
dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ; dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds;
dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ; dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds;
dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ; dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds;
mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
} }
@ -1400,7 +1394,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
if (e.mTargetId.find("morph-weights") != std::string::npos) if (e.mTargetId.find("morph-weights") != std::string::npos)
morphChannels.push_back(e); morphChannels.push_back(e);
} }
if (!morphChannels.empty() ) { if (!morphChannels.empty()) {
// either 1) morph weight animation count should contain morph target count channels // either 1) morph weight animation count should contain morph target count channels
// or 2) one channel with morph target count arrays // or 2) one channel with morph target count arrays
// assume first // assume first
@ -1434,8 +1428,8 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ; morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds;
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) { for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex) {
morphAnim->mKeys[key].mValues[valueIndex] = valueIndex; morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex); morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
} }
@ -1552,23 +1546,23 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce
shadeMode = aiShadingMode_Flat; shadeMode = aiShadingMode_Flat;
} else { } else {
switch (effect.mShadeType) { switch (effect.mShadeType) {
case Collada::Shade_Constant: case Collada::Shade_Constant:
shadeMode = aiShadingMode_NoShading; shadeMode = aiShadingMode_NoShading;
break; break;
case Collada::Shade_Lambert: case Collada::Shade_Lambert:
shadeMode = aiShadingMode_Gouraud; shadeMode = aiShadingMode_Gouraud;
break; break;
case Collada::Shade_Blinn: case Collada::Shade_Blinn:
shadeMode = aiShadingMode_Blinn; shadeMode = aiShadingMode_Blinn;
break; break;
case Collada::Shade_Phong: case Collada::Shade_Phong:
shadeMode = aiShadingMode_Phong; shadeMode = aiShadingMode_Phong;
break; break;
default: default:
ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading"); ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
shadeMode = aiShadingMode_Gouraud; shadeMode = aiShadingMode_Gouraud;
break; break;
} }
} }
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL); mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
@ -1734,7 +1728,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
// and add this texture to the list // and add this texture to the list
mTextures.push_back(tex); mTextures.push_back(tex);
return result; return result;
} }
if (imIt->second.mFileName.empty()) { if (imIt->second.mFileName.empty()) {
throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");

View File

@ -160,11 +160,26 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
return file_list.front(); return file_list.front();
} }
XmlParser manifestParser;
XmlNode *root = manifestParser.parse(manifestfile.get());
if (nullptr == root) {
return std::string();
}
const std::string name = root->name();
if (name != "dae_root") {
root = manifestParser.findNode("dae_root");
if (nullptr == root) {
return std::string();
}
const char *filepath = root->value();
aiString ai_str(filepath);
UriDecodePath(ai_str);
return std::string(ai_str.C_Str());
}
/*std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get()));
std::unique_ptr<irr::io::IrrXMLReader> manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get()));*/
std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get())); /*while (manifest_reader->read()) {
std::unique_ptr<irr::io::IrrXMLReader> manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get()));
while (manifest_reader->read()) {
// find the manifest "dae_root" element // find the manifest "dae_root" element
if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) { if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) {
if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) { if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) {
@ -183,7 +198,7 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
return std::string(ai_str.C_Str()); return std::string(ai_str.C_Str());
} }
} }
} }*/
return std::string(); return std::string();
} }
@ -314,7 +329,6 @@ void ColladaParser::ReadContents(XmlNode &node) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the structure of the file // Reads the structure of the file
<<<<<<< HEAD
void ColladaParser::ReadStructure(XmlNode &node) { void ColladaParser::ReadStructure(XmlNode &node) {
for (pugi::xml_node curNode : node.children()) { for (pugi::xml_node curNode : node.children()) {
const std::string name = std::string(curNode.name()); const std::string name = std::string(curNode.name());
@ -341,7 +355,7 @@ void ColladaParser::ReadStructure(XmlNode &node) {
else if (name == "library_cameras") else if (name == "library_cameras")
ReadCameraLibrary(curNode); ReadCameraLibrary(curNode);
else if (name == "library_nodes") else if (name == "library_nodes")
ReadSceneNode(NULL); /* some hacking to reuse this piece of code */ ReadSceneNode(curNode, nullptr); /* some hacking to reuse this piece of code */
else if (name == "scene") else if (name == "scene")
ReadScene(curNode); ReadScene(curNode);
//else //else
@ -381,44 +395,6 @@ void ColladaParser::ReadStructure(XmlNode &node) {
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
break; break;
}*/ }*/
=======
void ColladaParser::ReadStructure() {
while (mReader->read()) {
// beginning of elements
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("asset"))
ReadAssetInfo();
else if (IsElement("library_animations"))
ReadAnimationLibrary();
else if (IsElement("library_animation_clips"))
ReadAnimationClipLibrary();
else if (IsElement("library_controllers"))
ReadControllerLibrary();
else if (IsElement("library_images"))
ReadImageLibrary();
else if (IsElement("library_materials"))
ReadMaterialLibrary();
else if (IsElement("library_effects"))
ReadEffectLibrary();
else if (IsElement("library_geometries"))
ReadGeometryLibrary();
else if (IsElement("library_visual_scenes"))
ReadSceneLibrary();
else if (IsElement("library_lights"))
ReadLightLibrary();
else if (IsElement("library_cameras"))
ReadCameraLibrary();
else if (IsElement("library_nodes"))
ReadSceneNode(nullptr); /* some hacking to reuse this piece of code */
else if (IsElement("scene"))
ReadScene();
else
SkipElement();
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
break;
}
}
>>>>>>> master
PostProcessRootAnimations(); PostProcessRootAnimations();
PostProcessControllers(); PostProcessControllers();
@ -436,7 +412,7 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
pugi::xml_attribute attr = curNode.attribute("meter"); pugi::xml_attribute attr = curNode.attribute("meter");
mUnitSize = 1.f; mUnitSize = 1.f;
if (attr) { if (attr) {
mUnitSize = attr.as_double(); mUnitSize = static_cast<ai_real>(attr.as_double());
} }
} else if (name == "up_axis") { } else if (name == "up_axis") {
const char *content = curNode.value(); const char *content = curNode.value();
@ -602,7 +578,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
if (urlName[0] != '#') { if (urlName[0] != '#') {
ThrowException("Unknown reference format"); ThrowException("Unknown reference format");
} }
clip.second.push_back(url); clip.second.push_back(url.as_string());
} }
} }
@ -919,8 +895,27 @@ void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChanne
for (pugi::xml_node &curNode : node.children()) { for (pugi::xml_node &curNode : node.children()) {
const std::string currentName = curNode.name(); const std::string currentName = curNode.name();
if (currentName == "input") { if (currentName == "input") {
pugi::xml_attribute semantic = curNode.attribute("semantic"); pugi::xml_attribute semanticAttr = curNode.attribute("semantic");
if (semantic) { if (!semanticAttr.empty()) {
const char *semantic = semanticAttr.as_string();
pugi::xml_attribute sourceAttr = curNode.attribute("source");
if (!sourceAttr.empty()) {
const char *source = sourceAttr.as_string();
if (source[0] != '#')
ThrowException("Unsupported URL format");
source++;
if (strcmp(semantic, "INPUT") == 0)
pChannel.mSourceTimes = source;
else if (strcmp(semantic, "OUTPUT") == 0)
pChannel.mSourceValues = source;
else if (strcmp(semantic, "IN_TANGENT") == 0)
pChannel.mInTanValues = source;
else if (strcmp(semantic, "OUT_TANGENT") == 0)
pChannel.mOutTanValues = source;
else if (strcmp(semantic, "INTERPOLATION") == 0)
pChannel.mInterpolationValues = source;
}
} }
} }
} }
@ -970,7 +965,23 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
/*if (mReader->isEmptyElement()) /*if (mReader->isEmptyElement())
return;*/ return;*/
while (mReader->read()) { const std::string name = node.name();
if (name != "controller") {
return;
}
int attrId = node.attribute("id").as_int();
std::string id = node.value();
mControllerLibrary[id] = Controller();
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == "controller") {
int attrID = currentNode.attribute("id").as_int();
std::string controllerId = currentNode.attribute(itoa(attrID, NULL, 10)).value();
ReadController(node, mControllerLibrary[controllerId]);
}
}
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("controller")) { if (IsElement("controller")) {
// read ID. Ask the spec if it's necessary or optional... you might be surprised. // read ID. Ask the spec if it's necessary or optional... you might be surprised.
@ -992,7 +1003,7 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
break; break;
} }
} }*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1001,7 +1012,54 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
// initial values // initial values
pController.mType = Skin; pController.mType = Skin;
pController.mMethod = Normalized; pController.mMethod = Normalized;
while (mReader->read()) { for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == "morph") {
pController.mType = Morph;
int baseIndex = currentNode.attribute("source").as_int();
pController.mMeshId = currentNode.attribute.begin() + baseIndex + 1;
int methodIndex = currentNode.attribute("method").as_int();
if (methodIndex > 0) {
const char *method = currentNode.attribute("method").value();
if (strcmp(method, "RELATIVE") == 0) {
pController.mMethod = Relative;
}
}
} else if (currentName == "skin") {
int sourceIndex = currentNode.attribute("source").as_int();
pController.mMeshId = currentNode.attribute.begin() + sourceIndex + 1;
} else if (currentName == "bind_shape_matrix") {
const char *content = currentNode.value();
for (unsigned int a = 0; a < 16; a++) {
// read a number
content = fast_atoreal_move<ai_real>(content, pController.mBindShapeMatrix[a]);
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
}
} else if (currentName == "source") {
ReadSource(currentNode);
} else if (IsElement("joints")) {
ReadControllerJoints(currentNode, pController);
} else if (IsElement("vertex_weights")) {
ReadControllerWeights(currentNode, pController);
} else if (IsElement("targets")) {
for (XmlNode currendChildNode : currentNode.children()) {
const std::string currentChildName = currendChildNode.name();
if (currentChildName == "input") {
int semanticsIndex = currendChildNode.attribute("semantic").as_int();
int sourceIndex = currendChildNode.attribute("source").as_int();
const char *semantics = currendChildNode.attributes.begin() + semanticsIndex;
const char *source = currendChildNode.attributes.begin() + sourceIndex;
if (strcmp(semantics, "MORPH_TARGET") == 0) {
pController.mMorphTarget = source + 1;
} else if (strcmp(semantics, "MORPH_WEIGHT") == 0) {
pController.mMorphWeight = source + 1;
}
}
}
}
}
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
// two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
if (IsElement("morph")) { if (IsElement("morph")) {
@ -1071,59 +1129,141 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
else if (strcmp(mReader->getNodeName(), "skin") != 0 && strcmp(mReader->getNodeName(), "morph") != 0) else if (strcmp(mReader->getNodeName(), "skin") != 0 && strcmp(mReader->getNodeName(), "morph") != 0)
ThrowException("Expected end of <controller> element."); ThrowException("Expected end of <controller> element.");
} }
} }*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the joint definitions for the given controller // Reads the joint definitions for the given controller
void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) { void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) {
while (mReader->read()) { for (XmlNode currentNode : node.children()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { const std::string currentName = currentNode.name();
// Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" if (currentName == "input") {
if (IsElement("input")) { int indexSemantic = currentNode.attribute("semantic").as_int();
int indexSemantic = GetAttribute("semantic"); const char *attrSemantic = currentNode.attributes.begin() + indexSemantic;
const char *attrSemantic = mReader->getAttributeValue(indexSemantic); int indexSource = currentNode.attribute("source").as_int();
int indexSource = GetAttribute("source"); const char *attrSource = currentNode.attributes.begin() + indexSource;
const char *attrSource = mReader->getAttributeValue(indexSource); if (attrSource[0] != '#') {
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <joints> data <input> element");
// local URLS always start with a '#'. We don't support global URLs }
if (attrSource[0] != '#') attrSource++;
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <joints> data <input> element"); // parse source URL to corresponding source
attrSource++; if (strcmp(attrSemantic, "JOINT") == 0) {
pController.mJointNameSource = attrSource;
// parse source URL to corresponding source } else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
if (strcmp(attrSemantic, "JOINT") == 0) pController.mJointOffsetMatrixSource = attrSource;
pController.mJointNameSource = attrSource; } else {
else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <joints> data <input> element");
pController.mJointOffsetMatrixSource = attrSource;
else
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <joints> data <input> element");
// skip inner data, if present
if (!mReader->isEmptyElement())
SkipElement();
} else {
// ignore the rest
SkipElement();
} }
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "joints") != 0)
ThrowException("Expected end of <joints> element.");
break;
} }
} }
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
// Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX"
if (IsElement("input")) {
int indexSemantic = GetAttribute("semantic");
const char *attrSemantic = mReader->getAttributeValue(indexSemantic);
int indexSource = GetAttribute("source");
const char *attrSource = mReader->getAttributeValue(indexSource);
// local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#')
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <joints> data <input> element");
attrSource++;
// parse source URL to corresponding source
if (strcmp(attrSemantic, "JOINT") == 0)
pController.mJointNameSource = attrSource;
else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0)
pController.mJointOffsetMatrixSource = attrSource;
else
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <joints> data <input> element");
// skip inner data, if present
if (!mReader->isEmptyElement())
SkipElement();
} else {
// ignore the rest
SkipElement();
}
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "joints") != 0)
ThrowException("Expected end of <joints> element.");
break;
}
}*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the joint weights for the given controller // Reads the joint weights for the given controller
void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) { void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) {
// read vertex count from attributes and resize the array accordingly // Read vertex count from attributes and resize the array accordingly
int indexCount = GetAttribute("count"); int indexCount = node.attribute("count").as_int();
size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); size_t vertexCount = node.attributes.begin() + indexCount;
pController.mWeightCounts.resize(vertexCount); pController.mWeightCounts.resize(vertexCount);
while (mReader->read()) { /*// read vertex count from attributes and resize the array accordingly
int indexCount = GetAttribute("count");
size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount);
pController.mWeightCounts.resize(vertexCount);*/
for (XmlNode currentNode : node.children()) {
std::string currentName = currentNode.name();
if (currentName == "input") {
InputChannel channel;
int indexSemantic = currentNode.attribute("semantic").as_int();
const char *attrSemantic = currentNode.attributes.begin() + indexSemantic;
int indexSource = currentNode.attribute("source").as_int();
const char *attrSource = currentNode.attributes.begin() + indexSource;
int indexOffset = currentNode.attribute("offset").as_int();
if (indexOffset >= 0)
channel.mOffset = currentNode.attributes.begin + indexOffset;
// local URLS always start with a '#'. We don't support global URLs
if (attrSource[0] != '#')
ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of <vertex_weights> data <input> element");
channel.mAccessor = attrSource + 1;
// parse source URL to corresponding source
if (strcmp(attrSemantic, "JOINT") == 0) {
pController.mWeightInputJoints = channel;
} else if (strcmp(attrSemantic, "WEIGHT") == 0) {
pController.mWeightInputWeights = channel;
} else {
ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in <vertex_weights> data <input> element");
}
} else if (currentName == "vcount" && vertexCount > 0) {
const char *text = currentNode.value();
size_t numWeights = 0;
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
if (*text == 0) {
ThrowException("Out of data while reading <vcount>");
}
*it = strtoul10(text, &text);
numWeights += *it;
SkipSpacesAndLineEnd(&text);
}
// reserve weight count
pController.mWeights.resize(numWeights);
} else if (currentName == "v" && vertexCount > 0) {
// read JointIndex - WeightIndex pairs
const char *text = currentNode.value();
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
if (*text == 0) {
ThrowException("Out of data while reading <vertex_weights>");
}
it->first = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text);
if (*text == 0)
ThrowException("Out of data while reading <vertex_weights>");
it->second = strtoul10(text, &text);
SkipSpacesAndLineEnd(&text);
}
}
}
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
// Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT" // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT"
if (IsElement("input") && vertexCount > 0) { if (IsElement("input") && vertexCount > 0) {
@ -1196,7 +1336,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
break; break;
} }
} }*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1208,75 +1348,54 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
/*if (mReader->isEmptyElement()) /*if (mReader->isEmptyElement())
return;*/ return;*/
while (mReader->read()) { for (XmlNode currentNode : node.children()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { const std::string name = currentNode.name();
if (IsElement("image")) { if (name == "image") {
// read ID. Another entry which is "optional" by design but obligatory in reality int attrID = currentNode.attribute("id").as_int();
int attrID = GetAttribute("id"); std::string id = currentNode.attributes.begin() + attrID;
std::string id = mReader->getAttributeValue(attrID); mImageLibrary[id] = Image();
// create an entry and store it in the library under its ID // read on from there
mImageLibrary[id] = Image(); ReadImage(currentNode, mImageLibrary[id]);
// read on from there
ReadImage(mImageLibrary[id]);
} else {
// ignore the rest
SkipElement();
}
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "library_images") != 0)
ThrowException("Expected end of <library_images> element.");
break;
} }
} }
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("image")) {
// read ID. Another entry which is "optional" by design but obligatory in reality
int attrID = GetAttribute("id");
std::string id = mReader->getAttributeValue(attrID);
// create an entry and store it in the library under its ID
mImageLibrary[id] = Image();
// read on from there
ReadImage(mImageLibrary[id]);
} else {
// ignore the rest
SkipElement();
}
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "library_images") != 0)
ThrowException("Expected end of <library_images> element.");
break;
}
}*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads an image entry into the given image // Reads an image entry into the given image
void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
while (mReader->read()) { for (XmlNode currentNode : node.children()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { const std::string currentName = currentNode.name();
// Need to run different code paths here, depending on the Collada XSD version if (currentName == "image") {
if (IsElement("image")) { // Ignore
SkipElement(); continue;
} else if (IsElement("init_from")) { } else if (currentName == "init_from") {
if (mFormat == FV_1_4_n) { if (mFormat == FV_1_4_n) {
// FIX: C4D exporter writes empty <init_from/> tags // FIX: C4D exporter writes empty <init_from/> tags
if (!mReader->isEmptyElement()) { if (!currentNode.empty()) {
// element content is filename - hopefully
const char *sz = TestTextContent();
if (sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
TestClosing("init_from");
}
if (!pImage.mFileName.length()) {
pImage.mFileName = "unknown_texture";
}
} else if (mFormat == FV_1_5_n) {
// make sure we skip over mip and array initializations, which
// we don't support, but which could confuse the loader if
// they're not skipped.
int attrib = TestAttribute("array_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
continue;
}
attrib = TestAttribute("mip_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
continue;
}
// TODO: correctly jump over cube and volume maps?
}
} else if (mFormat == FV_1_5_n) {
if (IsElement("ref")) {
// element content is filename - hopefully // element content is filename - hopefully
const char *sz = TestTextContent(); const char *sz = TestTextContent();
if (sz) { if (sz) {
@ -1284,39 +1403,150 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
UriDecodePath(filepath); UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str(); pImage.mFileName = filepath.C_Str();
} }
TestClosing("ref"); TestClosing("init_from");
} else if (IsElement("hex") && !pImage.mFileName.length()) {
// embedded image. get format
const int attrib = TestAttribute("format");
if (-1 == attrib)
ASSIMP_LOG_WARN("Collada: Unknown image file format");
else
pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
const char *data = GetTextContent();
// hexadecimal-encoded binary octets. First of all, find the
// required buffer size to reserve enough storage.
const char *cur = data;
while (!IsSpaceOrNewLine(*cur))
cur++;
const unsigned int size = (unsigned int)(cur - data) * 2;
pImage.mImageData.resize(size);
for (unsigned int i = 0; i < size; ++i)
pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1));
TestClosing("hex");
} }
} else { if (!pImage.mFileName.length()) {
// ignore the rest pImage.mFileName = "unknown_texture";
SkipElement(); }
} else if (mFormat == FV_1_5_n) {
// make sure we skip over mip and array initializations, which
// we don't support, but which could confuse the loader if
// they're not skipped.
int attrib = currentNode.attribute("ref").as_int();
int v = currentNode.attributes.begin + attrib;
if (attrib != -1 && v > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
continue;
}
attrib = currentNode.attribute("mip_index").as_int();
v = currentNode.attributes.begin + attrib;
if (attrib != -1 && v > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
continue;
}
// TODO: correctly jump over cube and volume maps?
} }
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { } else if (mFormat == FV_1_5_n) {
if (strcmp(mReader->getNodeName(), "image") == 0) XmlNode refChild = currentNode.child("ref");
break; XmlNode hexChild = currentNode.child("hex");
} if (refChild) {
// element content is filename - hopefully
const char *sz = refChild.value();
if (sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
} else if (hexChild && !pImage.mFileName.length()) {
// embedded image. get format
const int attrib = hexChild.attribute("format").as_int();
if (-1 == attrib) {
ASSIMP_LOG_WARN("Collada: Unknown image file format");
} else {
pImage.mEmbeddedFormat = hexChild.attributes.begin() + attrib;
}
const char *data = hexChild.value();
// hexadecimal-encoded binary octets. First of all, find the
// required buffer size to reserve enough storage.
const char *cur = data;
while (!IsSpaceOrNewLine(*cur)) {
++cur;
}
const unsigned int size = (unsigned int)(cur - data) * 2;
pImage.mImageData.resize(size);
for (unsigned int i = 0; i < size; ++i) {
pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1));
}
}
}
} }
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
// Need to run different code paths here, depending on the Collada XSD version
if (IsElement("image")) {
SkipElement();
} else if (IsElement("init_from")) {
if (mFormat == FV_1_4_n) {
// FIX: C4D exporter writes empty <init_from/> tags
if (!mReader->isEmptyElement()) {
// element content is filename - hopefully
const char *sz = TestTextContent();
if (sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
TestClosing("init_from");
}
if (!pImage.mFileName.length()) {
pImage.mFileName = "unknown_texture";
}
} else if (mFormat == FV_1_5_n) {
// make sure we skip over mip and array initializations, which
// we don't support, but which could confuse the loader if
// they're not skipped.
int attrib = TestAttribute("array_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
continue;
}
attrib = TestAttribute("mip_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
continue;
}
// TODO: correctly jump over cube and volume maps?
}
} else if (mFormat == FV_1_5_n) {
if (IsElement("ref")) {
// element content is filename - hopefully
const char *sz = TestTextContent();
if (sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
}
TestClosing("ref");
} else if (IsElement("hex") && !pImage.mFileName.length()) {
// embedded image. get format
const int attrib = TestAttribute("format");
if (-1 == attrib)
ASSIMP_LOG_WARN("Collada: Unknown image file format");
else
pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
const char *data = GetTextContent();
// hexadecimal-encoded binary octets. First of all, find the
// required buffer size to reserve enough storage.
const char *cur = data;
while (!IsSpaceOrNewLine(*cur))
cur++;
const unsigned int size = (unsigned int)(cur - data) * 2;
pImage.mImageData.resize(size);
for (unsigned int i = 0; i < size; ++i)
pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1));
TestClosing("hex");
}
} else {
// ignore the rest
SkipElement();
}
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
if (strcmp(mReader->getNodeName(), "image") == 0)
break;
}
}*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1329,7 +1559,36 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
return;*/ return;*/
std::map<std::string, int> names; std::map<std::string, int> names;
while (mReader->read()) {
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
int attrID = currentNode.attribute("id").as_int();
std::string id = currentNode.attributes.begin() + attrID;
std::string name;
int attrName = currentNode.attribute("name").as_int();
if (attrName >= 0) {
name = currentNode.attributes.begin() + attrName;
}
mMaterialLibrary[id] = Material();
if (!name.empty()) {
std::map<std::string, int>::iterator it = names.find(name);
if (it != names.end()) {
std::ostringstream strStream;
strStream << ++it->second;
name.append(" " + strStream.str());
} else {
names[name] = 0;
}
mMaterialLibrary[id].mName = name;
}
ReadMaterial(currentNode, mMaterialLibrary[id]);
}
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("material")) { if (IsElement("material")) {
// read ID. By now you probably know my opinion about this "specification" // read ID. By now you probably know my opinion about this "specification"
@ -1368,7 +1627,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
break; break;
} }
} }*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -2778,7 +3037,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
return; return;
} }
/* if (mReader->isEmptyElement()) /* if (mReader->isEmptyElement())
return;*/ return;*/
while (mReader->read()) { while (mReader->read()) {
@ -2796,7 +3055,6 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
if (attrName > -1) if (attrName > -1)
child->mName = mReader->getAttributeValue(attrName); child->mName = mReader->getAttributeValue(attrName);
if (pNode) { if (pNode) {
pNode->mChildren.push_back(child); pNode->mChildren.push_back(child);
child->mParent = pNode; child->mParent = pNode;
@ -3034,7 +3292,30 @@ void ColladaParser::ReadScene(XmlNode &node) {
/*if (mReader->isEmptyElement()) /*if (mReader->isEmptyElement())
return;*/ return;*/
while (mReader->read()) { for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == "instance_visual_scene") {
// should be the first and only occurrence
if (mRootNode)
ThrowException("Invalid scene containing multiple root nodes in <instance_visual_scene> element");
// read the url of the scene to instance. Should be of format "#some_name"
int urlIndex = currentNode.attribute("url").as_int();
const char *url = currentNode.attributes.begin() + urlIndex;
if (url[0] != '#') {
ThrowException("Unknown reference format in <instance_visual_scene> element");
}
// find the referred scene, skip the leading #
NodeLibrary::const_iterator sit = mNodeLibrary.find(url + 1);
if (sit == mNodeLibrary.end()) {
ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in <instance_visual_scene> element.");
}
mRootNode = sit->second;
}
}
/*while (mReader->read()) {
if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (mReader->getNodeType() == irr::io::EXN_ELEMENT) {
if (IsElement("instance_visual_scene")) { if (IsElement("instance_visual_scene")) {
// should be the first and only occurrence // should be the first and only occurrence
@ -3058,7 +3339,7 @@ void ColladaParser::ReadScene(XmlNode &node) {
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
break; break;
} }
} }*/
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -3159,7 +3440,7 @@ void ColladaParser::ReportWarning(const char *msg, ...) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes
int ColladaParser::GetAttribute(const char *pAttr) const { /*int ColladaParser::GetAttribute(const char *pAttr) const {
int index = TestAttribute(pAttr); int index = TestAttribute(pAttr);
if (index == -1) { if (index == -1) {
ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">.");
@ -3167,31 +3448,31 @@ int ColladaParser::GetAttribute(const char *pAttr) const {
// attribute not found -> throw an exception // attribute not found -> throw an exception
return index; return index;
} }*/
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Tests the present element for the presence of one attribute, returns its index or throws an exception if not found // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found
int ColladaParser::TestAttribute(const char *pAttr) const { /*int ColladaParser::TestAttribute(const char *pAttr) const {
for (int a = 0; a < mReader->getAttributeCount(); a++) for (int a = 0; a < mReader->getAttributeCount(); a++)
if (strcmp(mReader->getAttributeName(a), pAttr) == 0) if (strcmp(mReader->getAttributeName(a), pAttr) == 0)
return a; return a;
return -1; return -1;
} }*/
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. // Reads the text contents of an element, throws an exception if not given. Skips leading whitespace.
const char *ColladaParser::GetTextContent() { /*const char *ColladaParser::GetTextContent() {
const char *sz = TestTextContent(); const char *sz = TestTextContent();
if (!sz) { if (!sz) {
ThrowException("Invalid contents in element \"n\"."); ThrowException("Invalid contents in element \"n\".");
} }
return sz; return sz;
} }*/
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Reads the text contents of an element, returns nullptr if not given. Skips leading whitespace. // Reads the text contents of an element, returns nullptr if not given. Skips leading whitespace.
const char *ColladaParser::TestTextContent() { /*const char *ColladaParser::TestTextContent() {
// present node should be the beginning of an element // present node should be the beginning of an element
if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement())
return nullptr; return nullptr;
@ -3209,7 +3490,7 @@ const char *ColladaParser::TestTextContent() {
SkipSpacesAndLineEnd(&text); SkipSpacesAndLineEnd(&text);
return text; return text;
} }*/
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Calculates the resulting transformation from all the given transform steps // Calculates the resulting transformation from all the given transform steps

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -43,7 +42,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OgreXmlSerializer.h" #include "OgreXmlSerializer.h"
#include "OgreBinarySerializer.h" #include "OgreBinarySerializer.h"
#include "OgreParsingUtils.h" #include "OgreParsingUtils.h"
#include <assimp/TinyFormatter.h> #include <assimp/TinyFormatter.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <memory> #include <memory>
@ -56,85 +54,86 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace Ogre { namespace Ogre {
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowAttibuteError(const XmlParser *reader, const std::string &name, const std::string &error = "") AI_WONT_RETURN_SUFFIX;
AI_WONT_RETURN void ThrowAttibuteError(const XmlReader *reader, const std::string &name, const std::string &error) {
AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::string &name, const std::string &error) {
if (!error.empty()) { if (!error.empty()) {
throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'"); throw DeadlyImportError(error + " in node '" + nodeName + "' and attribute '" + name + "'");
} else { } else {
throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'"); throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + nodeName + "'");
} }
} }
static inline bool hasAttribute( XmlNode &xmlNode, const char *name ) {
pugi::xml_attribute attr = xmlNode.attribute(name);
return !attr.empty();
}
template <> template <>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const { int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!hasAttribute(xmlNode, name )) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(mParser, name);
} }
pugi::xml_attribute attr = xmlNode.attribute(name);
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name)); return static_cast<int32_t>(attr.as_int());
} }
template <> template <>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const { uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(mParser, name);
} }
// @note This is hackish. But we are never expecting unsigned values that go outside the // @note This is hackish. But we are never expecting unsigned values that go outside the
// int32_t range. Just monitor for negative numbers and kill the import. // int32_t range. Just monitor for negative numbers and kill the import.
int32_t temp = ReadAttribute<int32_t>(name); int32_t temp = ReadAttribute<int32_t>(xmlNode, name);
if (temp < 0) { if (temp < 0) {
ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value"); ThrowAttibuteError(mParser, name, "Found a negative number value where expecting a uint32_t value");
} }
return static_cast<uint32_t>(temp); return static_cast<uint32_t>(temp);
} }
template <> template <>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const { uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(mParser, name);
} }
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name)); return static_cast<uint16_t>(xmlNode.attribute(name).as_int());
} }
template <> template <>
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const { float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const {
if (!HasAttribute(name)) { if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(m_reader, name); ThrowAttibuteError(mParser, name);
} }
return m_reader->getAttributeValueAsFloat(name); return xmlNode.attribute(name).as_float();
} }
template <> template <>
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const { std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const {
const char *value = m_reader->getAttributeValue(name); if (!hasAttribute(xmlNode, name)) {
if (nullptr == value) { ThrowAttibuteError(mParser, name);
ThrowAttibuteError(m_reader, name);
} }
return std::string(value); return xmlNode.attribute(name).as_string();
} }
template <> template <>
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const { bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name) const {
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name)); std::string value = Ogre::ToLower(ReadAttribute<std::string>(xmlNode, name));
if (ASSIMP_stricmp(value, "true") == 0) { if (ASSIMP_stricmp(value, "true") == 0) {
return true; return true;
} else if (ASSIMP_stricmp(value, "false") == 0) { } else if (ASSIMP_stricmp(value, "false") == 0) {
return false; return false;
} else { }
ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
return false; ThrowAttibuteError(mParser, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
} return false;
} }
bool OgreXmlSerializer::HasAttribute(const char *name) const { /*std::string &OgreXmlSerializer::NextNode() {
return (m_reader->getAttributeValue(name) != 0);
}
std::string &OgreXmlSerializer::NextNode() {
do { do {
if (!m_reader->read()) { if (!m_reader->read()) {
m_currentNodeName = ""; m_currentNodeName = "";
@ -178,7 +177,7 @@ std::string &OgreXmlSerializer::SkipCurrentNode() {
return NextNode(); return NextNode();
} }
*/
// Mesh XML constants // Mesh XML constants
// <mesh> // <mesh>
@ -247,15 +246,14 @@ static const char *nnTranslate = "translate";
static const char *nnRotate = "rotate"; static const char *nnRotate = "rotate";
// Common XML constants // Common XML constants
static const char *anX = "x"; static const char *anX = "x";
static const char *anY = "y"; static const char *anY = "y";
static const char *anZ = "z"; static const char *anZ = "z";
// Mesh // Mesh
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) { MeshXml *OgreXmlSerializer::ImportMesh(XmlParser *xmlParser) {
OgreXmlSerializer serializer(reader); OgreXmlSerializer serializer(xmlParser);
MeshXml *mesh = new MeshXml(); MeshXml *mesh = new MeshXml();
serializer.ReadMesh(mesh); serializer.ReadMesh(mesh);
@ -264,16 +262,32 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
} }
void OgreXmlSerializer::ReadMesh(MeshXml *mesh) { void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
if (NextNode() != nnMesh) { const XmlNode *root = mParser->getRootNode();
if (nullptr == root || std::string(nnMesh)!=root->name()) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>"); throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
} }
for (XmlNode currentNode : root->children()) {
const std::string currentName = currentNode.name();
if (currentName == nnSharedGeometry) {
mesh->sharedVertexData = new VertexDataXml();
ReadGeometry(currentNode, mesh->sharedVertexData);
} else if (currentName == nnSubMesh) {
ReadSubMesh(currentNode, mesh);
} else if (currentName == nnBoneAssignments) {
ReadBoneAssignments(currentNode, mesh->sharedVertexData);
} else if (currentName == nnSkeletonLink) {
}
}
/*if (NextNode() != nnMesh) {
}*/
ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Mesh");
NextNode(); //NextNode();
// Root level nodes // Root level nodes
while (m_currentNodeName == nnSharedGeometry || /*while (m_currentNodeName == nnSharedGeometry ||
m_currentNodeName == nnSubMeshes || m_currentNodeName == nnSubMeshes ||
m_currentNodeName == nnSkeletonLink || m_currentNodeName == nnSkeletonLink ||
m_currentNodeName == nnBoneAssignments || m_currentNodeName == nnBoneAssignments ||
@ -298,26 +312,33 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
NextNode(); NextNode();
} }
// Assimp incompatible/ignored nodes // Assimp incompatible/ignored nodes
else else {
SkipCurrentNode(); SkipCurrentNode();
} }
}*/
} }
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) { void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) {
dest->count = ReadAttribute<uint32_t>("vertexcount"); dest->count = ReadAttribute<uint32_t>(node, "vertexcount");
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices"); ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices");
NextNode(); for (XmlNode currentNode : node.children()) {
while (m_currentNodeName == nnVertexBuffer) { const std::string &currentName = currentNode.name();
ReadGeometryVertexBuffer(dest); if (currentName == nnVertexBuffer) {
ReadGeometryVertexBuffer(currentNode, dest);
}
} }
//NextNode();
/*while (m_currentNodeName == nnVertexBuffer) {
ReadGeometryVertexBuffer(dest);
}*/
} }
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) { void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) {
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions")); bool positions = (hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions"));
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals")); bool normals = (hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals"));
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents")); bool tangents = (hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents"));
uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0); uint32_t uvs = (hasAttribute(node, "texture_coords") ? ReadAttribute<uint32_t>(node, "texture_coords") : 0);
// Not having positions is a error only if a previous vertex buffer did not have them. // Not having positions is a error only if a previous vertex buffer did not have them.
if (!positions && !dest->HasPositions()) { if (!positions && !dest->HasPositions()) {
@ -348,9 +369,38 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
bool warnColorDiffuse = true; bool warnColorDiffuse = true;
bool warnColorSpecular = true; bool warnColorSpecular = true;
NextNode(); //NextNode();
for (XmlNode currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (positions && currentName == nnPosition) {
aiVector3D pos;
pos.x = ReadAttribute<float>(currentNode, anX);
pos.y = ReadAttribute<float>(currentNode, anY);
pos.z = ReadAttribute<float>(currentNode, anZ);
dest->positions.push_back(pos);
} else if (normals && currentName == nnNormal) {
aiVector3D normal;
normal.x = ReadAttribute<float>(currentNode, anX);
normal.y = ReadAttribute<float>(currentNode, anY);
normal.z = ReadAttribute<float>(currentNode, anZ);
dest->normals.push_back(normal);
} else if (tangents && currentName == nnTangent) {
aiVector3D tangent;
tangent.x = ReadAttribute<float>(currentNode, anX);
tangent.y = ReadAttribute<float>(currentNode, anY);
tangent.z = ReadAttribute<float>(currentNode, anZ);
dest->tangents.push_back(tangent);
} else if (uvs > 0 && currentName == nnTexCoord) {
for (auto &curUvs : dest->uvs) {
aiVector3D uv;
uv.x = ReadAttribute<float>(currentNode, "u");
uv.y = (ReadAttribute<float>(currentNode, "v") * -1) + 1; // Flip UV from Ogre to Assimp form
curUvs.push_back(uv);
}
}
}
while (m_currentNodeName == nnVertex || /*while (m_currentNodeName == nnVertex ||
m_currentNodeName == nnPosition || m_currentNodeName == nnPosition ||
m_currentNodeName == nnNormal || m_currentNodeName == nnNormal ||
m_currentNodeName == nnTangent || m_currentNodeName == nnTangent ||
@ -422,11 +472,11 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
if (warn) { if (warn) {
ASSIMP_LOG_WARN_F("Vertex buffer attribute read not implemented for element: ", m_currentNodeName); ASSIMP_LOG_WARN_F("Vertex buffer attribute read not implemented for element: ", m_currentNodeName);
} }
} }*/
// Advance // Advance
NextNode(); //NextNode();
} //}
// Sanity checks // Sanity checks
if (dest->positions.size() != dest->count) { if (dest->positions.size() != dest->count) {
@ -446,7 +496,7 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
} }
} }
void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) { void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
static const char *anMaterial = "material"; static const char *anMaterial = "material";
static const char *anUseSharedVertices = "usesharedvertices"; static const char *anUseSharedVertices = "usesharedvertices";
static const char *anCount = "count"; static const char *anCount = "count";
@ -457,10 +507,10 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
SubMeshXml *submesh = new SubMeshXml(); SubMeshXml *submesh = new SubMeshXml();
if (HasAttribute(anMaterial)) { if (hasAttribute(node, anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(anMaterial); submesh->materialRef = ReadAttribute<std::string>(node, anMaterial);
} }
if (HasAttribute(anUseSharedVertices)) { if (hasAttribute(node, anUseSharedVertices)) {
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices); submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
} }
@ -474,7 +524,46 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
bool quadWarned = false; bool quadWarned = false;
NextNode(); for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == nnFaces) {
submesh->indexData->faceCount = ReadAttribute<uint32_t>(currentNode, anCount);
submesh->indexData->faces.reserve(submesh->indexData->faceCount);
for (XmlNode currentChildNode : currentNode.children()) {
const std::string &currentChildName = currentNode.name();
if (currentChildName == nnFace) {
aiFace face;
face.mNumIndices = 3;
face.mIndices = new unsigned int[3];
face.mIndices[0] = ReadAttribute<uint32_t>(currentChildNode, anV1);
face.mIndices[1] = ReadAttribute<uint32_t>(currentChildNode, anV2);
face.mIndices[2] = ReadAttribute<uint32_t>(currentChildNode, anV3);
/// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it)
if (!quadWarned && hasAttribute(currentChildNode, anV4)) {
ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!");
quadWarned = true;
}
}
}
if (submesh->indexData->faces.size() == submesh->indexData->faceCount) {
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Faces ", submesh->indexData->faceCount);
} else {
throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount);
}
} else if (currentName == nnGeometry) {
if (submesh->usesSharedVertexData) {
throw DeadlyImportError("Found <geometry> in <submesh> when use shared geometry is true. Invalid mesh file.");
}
submesh->vertexData = new VertexDataXml();
ReadGeometry(currentNode, submesh->vertexData);
} else if (m_currentNodeName == nnBoneAssignments) {
ReadBoneAssignments(currentNode, submesh->vertexData);
}
}
/*NextNode();
while (m_currentNodeName == nnFaces || while (m_currentNodeName == nnFaces ||
m_currentNodeName == nnGeometry || m_currentNodeName == nnGeometry ||
m_currentNodeName == nnTextures || m_currentNodeName == nnTextures ||
@ -523,13 +612,13 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
else { else {
SkipCurrentNode(); SkipCurrentNode();
} }
} }*/
submesh->index = static_cast<unsigned int>(mesh->subMeshes.size()); submesh->index = static_cast<unsigned int>(mesh->subMeshes.size());
mesh->subMeshes.push_back(submesh); mesh->subMeshes.push_back(submesh);
} }
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) { void OgreXmlSerializer::ReadBoneAssignments(XmlNode &node, VertexDataXml *dest) {
if (!dest) { if (!dest) {
throw DeadlyImportError("Cannot read bone assignments, vertex data is null."); throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
} }
@ -539,8 +628,20 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
static const char *anWeight = "weight"; static const char *anWeight = "weight";
std::set<uint32_t> influencedVertices; std::set<uint32_t> influencedVertices;
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == nnVertexBoneAssignment) {
VertexBoneAssignment ba;
ba.vertexIndex = ReadAttribute<uint32_t>(currentNode, anVertexIndex);
ba.boneIndex = ReadAttribute<uint16_t>(currentNode, anBoneIndex);
ba.weight = ReadAttribute<float>(currentNode, anWeight);
NextNode(); dest->boneAssignments.push_back(ba);
influencedVertices.insert(ba.vertexIndex);
}
}
/*NextNode();
while (m_currentNodeName == nnVertexBoneAssignment) { while (m_currentNodeName == nnVertexBoneAssignment) {
VertexBoneAssignment ba; VertexBoneAssignment ba;
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex); ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
@ -551,7 +652,7 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
influencedVertices.insert(ba.vertexIndex); influencedVertices.insert(ba.vertexIndex);
NextNode(); NextNode();
} }*/
/** Normalize bone weights. /** Normalize bone weights.
Some exporters won't care if the sum of all bone weights Some exporters won't care if the sum of all bone weights
@ -593,41 +694,43 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
mesh->skeletonRef = mesh->skeletonRef + ".xml"; mesh->skeletonRef = mesh->skeletonRef + ".xml";
} }
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!reader.get()) if (!xmlParser.get())
return false; return false;
Skeleton *skeleton = new Skeleton(); Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get()); OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton); serializer.ReadSkeleton(skeleton);
mesh->skeleton = skeleton; mesh->skeleton = skeleton;
return true; return true;
} }
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) { bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
if (!mesh || mesh->skeletonRef.empty()) if (!mesh || mesh->skeletonRef.empty()) {
return false; return false;
}
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!reader.get()) if (!xmlParser.get()) {
return false; return false;
}
Skeleton *skeleton = new Skeleton(); Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get()); OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton); serializer.ReadSkeleton(skeleton);
mesh->skeleton = skeleton; mesh->skeleton = skeleton;
return true; return true;
} }
XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename) { XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename) {
if (!EndsWith(filename, ".skeleton.xml", false)) { if (!EndsWith(filename, ".skeleton.xml", false)) {
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file."); ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
return XmlReaderPtr(); return XmlParserPtr();
} }
if (!pIOHandler->Exists(filename)) { if (!pIOHandler->Exists(filename)) {
ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh."); ASSIMP_LOG_ERROR_F("Failed to find skeleton file '", filename, "' that is referenced by imported Mesh.");
return XmlReaderPtr(); return XmlParserPtr();
} }
std::unique_ptr<IOStream> file(pIOHandler->Open(filename)); std::unique_ptr<IOStream> file(pIOHandler->Open(filename));
@ -635,27 +738,36 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s
throw DeadlyImportError("Failed to open skeleton file " + filename); throw DeadlyImportError("Failed to open skeleton file " + filename);
} }
std::unique_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get())); XmlParserPtr xmlParser = XmlParserPtr(new XmlParser);
XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get())); if (!xmlParser->parse(file.get())) {
if (!reader.get()) {
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename); throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
} }
return reader; return xmlParser;
} }
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) { void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
if (NextNode() != nnSkeleton) { if (node.name() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>"); throw DeadlyImportError("Root node is <" + node.name() + "> expecting <skeleton>");
} }
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
// Optional blend mode from root node // Optional blend mode from root node
if (HasAttribute("blendmode")) { if (hasAttribute(node, "blendmode")) {
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); skeleton->blendMode = (ToLower(ReadAttribute<std::string>(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
} }
NextNode(); for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnBones) {
ReadBones(currentNode, skeleton);
} else if (currentName == nnBoneHierarchy) {
ReadBoneHierarchy(currentNode, skeleton);
} else if (currentName == nnAnimations) {
ReadAnimations(currentNode, skeleton);
}
}
/*NextNode();
// Root level nodes // Root level nodes
while (m_currentNodeName == nnBones || while (m_currentNodeName == nnBones ||
@ -670,17 +782,35 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
ReadAnimations(skeleton); ReadAnimations(skeleton);
else else
SkipCurrentNode(); SkipCurrentNode();
} }*/
} }
void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) { void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) { if (skeleton->bones.empty()) {
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones"); throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
} }
ASSIMP_LOG_VERBOSE_DEBUG(" - Animations"); ASSIMP_LOG_VERBOSE_DEBUG(" - Animations");
NextNode(); for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnAnimation) {
Animation *anim = new Animation(skeleton);
anim->name = ReadAttribute<std::string>(currentNode, "name");
anim->length = ReadAttribute<float>(currentNode , "length");
for (XmlNode &currentChildNode : currentNode.children()) {
const std::string currentChildName = currentNode.name();
if (currentChildName == nnTracks) {
ReadAnimationTracks(currentChildNode, anim);
skeleton->animations.push_back(anim);
} else {
throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << anim->name);
}
}
}
}
/* NextNode();
while (m_currentNodeName == nnAnimation) { while (m_currentNodeName == nnAnimation) {
Animation *anim = new Animation(skeleton); Animation *anim = new Animation(skeleton);
anim->name = ReadAttribute<std::string>("name"); anim->name = ReadAttribute<std::string>("name");
@ -694,11 +824,29 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) {
skeleton->animations.push_back(anim); skeleton->animations.push_back(anim);
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)"); ASSIMP_LOG_VERBOSE_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)");
} }*/
} }
void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) { void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
NextNode(); for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnTrack) {
VertexAnimationTrack track;
track.type = VertexAnimationTrack::VAT_TRANSFORM;
track.boneName = ReadAttribute<std::string>(currentNode, "bone");
for (XmlNode &currentChildNode : currentNode.children()) {
const std::string currentChildName = currentNode.name();
if (currentChildName == nnKeyFrames) {
ReadAnimationKeyFrames(currentChildNode, dest, &track);
dest->tracks.push_back(track);
} else {
throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << dest->name);
}
}
}
}
/*NextNode();
while (m_currentNodeName == nnTrack) { while (m_currentNodeName == nnTrack) {
VertexAnimationTrack track; VertexAnimationTrack track;
track.type = VertexAnimationTrack::VAT_TRANSFORM; track.type = VertexAnimationTrack::VAT_TRANSFORM;
@ -711,13 +859,52 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) {
ReadAnimationKeyFrames(dest, &track); ReadAnimationKeyFrames(dest, &track);
dest->tracks.push_back(track); dest->tracks.push_back(track);
} }*/
} }
void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest) { void OgreXmlSerializer::ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest) {
const aiVector3D zeroVec(0.f, 0.f, 0.f); const aiVector3D zeroVec(0.f, 0.f, 0.f);
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnKeyFrame) {
TransformKeyFrame keyframe;
keyframe.timePos = ReadAttribute<float>(currentNode, "time");
for (XmlNode &currentChildNode : currentNode.children()) {
const std::string currentChildName = currentNode.name();
if (currentChildName == nnTranslate) {
keyframe.position.x = ReadAttribute<float>(currentChildNode, anX);
keyframe.position.y = ReadAttribute<float>(currentChildNode, anY);
keyframe.position.z = ReadAttribute<float>(currentChildNode, anZ);
} else if (currentChildName == nnRotate) {
float angle = ReadAttribute<float>(currentChildNode, "angle");
for (XmlNode &currentChildChildNode : currentNode.children()) {
const std::string currentChildChildName = currentNode.name();
if (currentChildChildName == nnAxis) {
aiVector3D axis;
axis.x = ReadAttribute<float>(currentChildChildNode, anX);
axis.y = ReadAttribute<float>(currentChildChildNode, anY);
axis.z = ReadAttribute<float>(currentChildChildNode, anZ);
if (axis.Equal(zeroVec)) {
axis.x = 1.0f;
if (angle != 0) {
ASSIMP_LOG_WARN_F("Found invalid a key frame with a zero rotation axis in animation: ", anim->name);
}
}
keyframe.rotation = aiQuaternion(axis, angle);
}
}
} else if (currentChildName == nnScale) {
keyframe.scale.x = ReadAttribute<float>(currentChildNode, anX);
keyframe.scale.y = ReadAttribute<float>(currentChildNode, anY);
keyframe.scale.z = ReadAttribute<float>(currentChildNode, anZ);
NextNode(); }
}
}
dest->transformKeyFrames.push_back(keyframe);
}
/*NextNode();
while (m_currentNodeName == nnKeyFrame) { while (m_currentNodeName == nnKeyFrame) {
TransformKeyFrame keyframe; TransformKeyFrame keyframe;
keyframe.timePos = ReadAttribute<float>("time"); keyframe.timePos = ReadAttribute<float>("time");
@ -756,15 +943,33 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
} }
dest->transformKeyFrames.push_back(keyframe); dest->transformKeyFrames.push_back(keyframe);
} }*/
} }
void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) { void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) { if (skeleton->bones.empty()) {
throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones"); throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
} }
while (NextNode() == nnBoneParent) { for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnBoneParent) {
const std::string name = ReadAttribute<std::string>(currentNode, "bone");
const std::string parentName = ReadAttribute<std::string>(currentNode, "parent");
Bone *bone = skeleton->BoneByName(name);
Bone *parent = skeleton->BoneByName(parentName);
if (bone && parent) {
parent->AddChild(bone);
} else {
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
}
}
}
/*while (NextNode() == nnBoneParent) {
const std::string name = ReadAttribute<std::string>("bone"); const std::string name = ReadAttribute<std::string>("bone");
const std::string parentName = ReadAttribute<std::string>("parent"); const std::string parentName = ReadAttribute<std::string>("parent");
@ -775,7 +980,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) {
parent->AddChild(bone); parent->AddChild(bone);
else else
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName); throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
} }*/
// Calculate bone matrices for root bones. Recursively calculates their children. // Calculate bone matrices for root bones. Recursively calculates their children.
for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) { for (size_t i = 0, len = skeleton->bones.size(); i < len; ++i) {
@ -792,9 +997,28 @@ static bool BoneCompare(Bone *a, Bone *b) {
return (a->id < b->id); return (a->id < b->id);
} }
void OgreXmlSerializer::ReadBones(Skeleton *skeleton) { void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG(" - Bones"); ASSIMP_LOG_VERBOSE_DEBUG(" - Bones");
for (XmlNode &currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == nnBone) {
Bone *bone = new Bone();
bone->id = ReadAttribute<uint16_t>(currentNode, "id");
bone->name = ReadAttribute<std::string>(currentNode, "name");
for (XmlNode &currentChildNode : currentNode.children()) {
const std::string currentChildName = currentNode.name();
if (currentChildName == nnPosition) {
bone->position.x = ReadAttribute<float>(currentChildNode, anX);
bone->position.y = ReadAttribute<float>(currentChildNode, anY);
bone->position.z = ReadAttribute<float>(currentChildNode, anZ);
} else if (currentChildName == nnScale) {
} else if (currentChildName == nnScale) {
}
}
}
}
NextNode(); NextNode();
while (m_currentNodeName == nnBone) { while (m_currentNodeName == nnBone) {
Bone *bone = new Bone(); Bone *bone = new Bone();

View File

@ -48,71 +48,70 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "OgreStructs.h" #include "OgreStructs.h"
#include <assimp/XmlParser.h> #include <assimp/XmlParser.h>
namespace Assimp namespace Assimp {
{ namespace Ogre {
namespace Ogre
{
typedef irr::io::IrrXMLReader XmlReader; //typedef irr::io::IrrXMLReader XmlReader;
typedef std::shared_ptr<XmlReader> XmlReaderPtr; using XmlParserPtr = std::shared_ptr<XmlParser> ;
class OgreXmlSerializer class OgreXmlSerializer {
{
public: public:
/// Imports mesh and returns the result. /// Imports mesh and returns the result.
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */ /** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
static MeshXml *ImportMesh(XmlReader *reader); static MeshXml *ImportMesh(XmlParser *parser);
/// Imports skeleton to @c mesh. /// Imports skeleton to @c mesh.
/** If mesh does not have a skeleton reference or the skeleton file /** If mesh does not have a skeleton reference or the skeleton file
cannot be found it is not a fatal DeadlyImportError. cannot be found it is not a fatal DeadlyImportError.
@return If skeleton import was successful. */ @return If skeleton import was successful. */
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh); static bool ImportSkeleton(IOSystem *pIOHandler, MeshXml *mesh);
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh); static bool ImportSkeleton(IOSystem *pIOHandler, Mesh *mesh);
private: private:
explicit OgreXmlSerializer(XmlReader *reader) : explicit OgreXmlSerializer(XmlParser *xmlParser);
m_reader(reader)
{
}
static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename); static XmlParserPtr OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename);
// Mesh // Mesh
void ReadMesh(MeshXml *mesh); void ReadMesh(MeshXml *mesh);
void ReadSubMesh(MeshXml *mesh); void ReadSubMesh(XmlNode &node, MeshXml *mesh);
void ReadGeometry(VertexDataXml *dest); void ReadGeometry(XmlNode &node, VertexDataXml *dest);
void ReadGeometryVertexBuffer(VertexDataXml *dest); void ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest);
void ReadBoneAssignments(VertexDataXml *dest); void ReadBoneAssignments(XmlNode &node, VertexDataXml *dest);
// Skeleton // Skeleton
void ReadSkeleton(Skeleton *skeleton); void ReadSkeleton(XmlNode &node, Skeleton *skeleton);
void ReadBones(Skeleton *skeleton); void ReadBones(XmlNode &node, Skeleton *skeleton);
void ReadBoneHierarchy(Skeleton *skeleton); void ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton);
void ReadAnimations(Skeleton *skeleton); void ReadAnimations(XmlNode &node, Skeleton *skeleton);
void ReadAnimationTracks(Animation *dest); void ReadAnimationTracks(XmlNode &node, Animation *dest);
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest); void ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest);
template<typename T> template <typename T>
T ReadAttribute(const char *name) const; T ReadAttribute(XmlNode &xmlNode, const char *name) const;
bool HasAttribute(const char *name) const; //bool HasAttribute(const char *name) const;
std::string &NextNode(); //std::string &NextNode();
std::string &SkipCurrentNode(); //std::string &SkipCurrentNode();
bool CurrentNodeNameEquals(const std::string &name) const; //bool CurrentNodeNameEquals(const std::string &name) const;
std::string CurrentNodeName(bool forceRead = false); //std::string CurrentNodeName(bool forceRead = false);
XmlReader *m_reader; XmlParser *mParser;
std::string m_currentNodeName; std::string m_currentNodeName;
}; };
} // Ogre inline OgreXmlSerializer::OgreXmlSerializer(XmlParser *xmlParser) :
} // Assimp mParser(xmlParser) {
// empty
}
} // namespace Ogre
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER #endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
#endif // AI_OGREXMLSERIALIZER_H_INC #endif // AI_OGREXMLSERIALIZER_H_INC