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) {
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) {
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) {
// irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader.
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
// 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.");
}
ParseNode_Root();
//delete mReader;
} // namespace Assimp
// <amf
@ -408,11 +297,6 @@ void AMFImporter::ParseNode_Root() {
version = root->attribute("version").as_string();
// 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
if (!mUnit.empty()) {
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)->Version = version;
// Check for child nodes
for (pugi::xml_node &currentNode : root->children()) {
const std::string currentName = currentNode.name();
if (currentName == "object") {
@ -443,32 +328,6 @@ void AMFImporter::ParseNode_Root() {
}
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.
}
@ -483,10 +342,6 @@ void AMFImporter::ParseNode_Root() {
void AMFImporter::ParseNode_Constellation(XmlNode &node) {
std::string id;
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.
AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
@ -497,6 +352,7 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
als.ID = id;
}
// Check for child nodes
for (pugi::xml_node &currentNode : node.children()) {
std::string name = currentNode.name();
if (name == "instance") {
@ -509,26 +365,6 @@ void AMFImporter::ParseNode_Constellation(XmlNode &node) {
mNodeElement_Cur->Child.push_back(ne);
}
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
@ -542,9 +378,6 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
AMFNodeElementBase *ne(nullptr);
// 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();
// 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.");
}
// create and define new grouping object.
//ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
ne = new AMFInstance(mNodeElement_Cur);
//CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience
AMFInstance &als = *((AMFInstance *)ne);
als.ObjectID = objectid;
@ -584,29 +415,6 @@ void AMFImporter::ParseNode_Instance(XmlNode &node) {
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.
}
@ -623,10 +431,8 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
AMFNodeElementBase *ne(nullptr);
// 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();
// create and if needed - define new geometry object.
ne = new AMFObject(mNodeElement_Cur);
@ -652,35 +458,6 @@ void AMFImporter::ParseNode_Object(XmlNode &node) {
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.
}
@ -711,12 +488,6 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
value = node.value();
// 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);
((AMFMetadata *)ne)->Type = type;
((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.
}
/*********************************************************************************************************************************************/
/******************************************************** Functions: BaseImporter set ********************************************************/
/*********************************************************************************************************************************************/
bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
const std::string extension = GetExtension(pFile);

View File

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

View File

@ -81,29 +81,6 @@ void AMFImporter::ParseNode_Mesh(XmlNode &node) {
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) {
mNodeElement_Cur->Child.push_back(ne);
} // 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
} // 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.
}
@ -157,6 +120,8 @@ void AMFImporter::ParseNode_Vertex(XmlNode &node) {
// create new mesh object.
ne = new AMFVertex(mNodeElement_Cur);
// Check for child nodes
pugi::xml_node colorNode = node.child("color");
bool col_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
}
// 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.
}
@ -238,25 +167,6 @@ void AMFImporter::ParseNode_Coordinates(XmlNode &node) {
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.
}
@ -275,13 +185,6 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur);
// 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
((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.
}
@ -354,14 +227,15 @@ void AMFImporter::ParseNode_Volume(XmlNode &node) {
void AMFImporter::ParseNode_Triangle(XmlNode &node) {
AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur);
// create new color object.
//ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
// create new triangle object.
AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience
if (node.empty()) {
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 read_flag[3] = { false, false, false };
for (pugi::xml_node currentNode : node.children()) {
@ -387,59 +261,11 @@ void AMFImporter::ParseNode_Triangle(XmlNode &node) {
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.
}

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team
All rights reserved.
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();
// Check for child nodes
//if (!mXmlParser->isEmptyElement()) {
// XML_ReadNode_GetVal_AsString(enc64_data);
//}
// check that all components was defined
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 "ColladaParser.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/Defines.h>
#include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/anim.h>
#include <assimp/fast_atof.h>
#include "math.h"
#include "time.h"
#include <assimp/importerdesc.h>
#include <assimp/scene.h>
#include <math.h>
#include <time.h>
#include <algorithm>
#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <memory>
#include <numeric>
@ -125,20 +122,17 @@ ColladaLoader::~ColladaLoader() {
bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
// check file extension
const std::string extension = GetExtension(pFile);
bool readSig = checkSig && (pIOHandler != nullptr);
const bool readSig = checkSig && (pIOHandler != nullptr);
if (!readSig) {
if (extension == "dae" || extension == "zae") {
return true;
}
}
if (readSig) {
} else {
// Look for a DAE file inside, but don't extract it
ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
if (zip_archive.isOpen())
if (zip_archive.isOpen()) {
return !ColladaParser::ReadZaeManifest(zip_archive).empty();
}
}
// 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
aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
if ( meshid.empty()) {
if (meshid.empty()) {
return nullptr;
}
for (unsigned int i = 0; i < mMeshes.size(); ++i) {
if (std::string(mMeshes[i]->mName.data) == meshid) {
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
mat.d4 = 1.0f;
dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ;
dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ;
dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ;
dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds;
dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds;
dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds;
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)
morphChannels.push_back(e);
}
if (!morphChannels.empty() ) {
if (!morphChannels.empty()) {
// either 1) morph weight animation count should contain morph target count channels
// or 2) one channel with morph target count arrays
// 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].mWeights = new double[morphChannels.size()];
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ;
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) {
morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds;
for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex) {
morphAnim->mKeys[key].mValues[valueIndex] = 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;
} else {
switch (effect.mShadeType) {
case Collada::Shade_Constant:
shadeMode = aiShadingMode_NoShading;
break;
case Collada::Shade_Lambert:
shadeMode = aiShadingMode_Gouraud;
break;
case Collada::Shade_Blinn:
shadeMode = aiShadingMode_Blinn;
break;
case Collada::Shade_Phong:
shadeMode = aiShadingMode_Phong;
break;
case Collada::Shade_Constant:
shadeMode = aiShadingMode_NoShading;
break;
case Collada::Shade_Lambert:
shadeMode = aiShadingMode_Gouraud;
break;
case Collada::Shade_Blinn:
shadeMode = aiShadingMode_Blinn;
break;
case Collada::Shade_Phong:
shadeMode = aiShadingMode_Phong;
break;
default:
ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
shadeMode = aiShadingMode_Gouraud;
break;
default:
ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
shadeMode = aiShadingMode_Gouraud;
break;
}
}
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
mTextures.push_back(tex);
return result;
}
}
if (imIt->second.mFileName.empty()) {
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();
}
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()));
std::unique_ptr<irr::io::IrrXMLReader> manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get()));
while (manifest_reader->read()) {
/*while (manifest_reader->read()) {
// find the manifest "dae_root" element
if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) {
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();
}
@ -314,7 +329,6 @@ void ColladaParser::ReadContents(XmlNode &node) {
// ------------------------------------------------------------------------------------------------
// Reads the structure of the file
<<<<<<< HEAD
void ColladaParser::ReadStructure(XmlNode &node) {
for (pugi::xml_node curNode : node.children()) {
const std::string name = std::string(curNode.name());
@ -341,7 +355,7 @@ void ColladaParser::ReadStructure(XmlNode &node) {
else if (name == "library_cameras")
ReadCameraLibrary(curNode);
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")
ReadScene(curNode);
//else
@ -381,44 +395,6 @@ void ColladaParser::ReadStructure(XmlNode &node) {
} else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
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();
PostProcessControllers();
@ -436,7 +412,7 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
pugi::xml_attribute attr = curNode.attribute("meter");
mUnitSize = 1.f;
if (attr) {
mUnitSize = attr.as_double();
mUnitSize = static_cast<ai_real>(attr.as_double());
}
} else if (name == "up_axis") {
const char *content = curNode.value();
@ -602,7 +578,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
if (urlName[0] != '#') {
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()) {
const std::string currentName = curNode.name();
if (currentName == "input") {
pugi::xml_attribute semantic = curNode.attribute("semantic");
if (semantic) {
pugi::xml_attribute semanticAttr = curNode.attribute("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())
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 (IsElement("controller")) {
// 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;
}
}
}*/
}
// ------------------------------------------------------------------------------------------------
@ -1001,7 +1012,54 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
// initial values
pController.mType = Skin;
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) {
// two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other
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)
ThrowException("Expected end of <controller> element.");
}
}
}*/
}
// ------------------------------------------------------------------------------------------------
// Reads the joint definitions for the given controller
void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) {
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();
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == "input") {
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;
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");
}
} 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
void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) {
// read vertex count from attributes and resize the array accordingly
int indexCount = GetAttribute("count");
size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount);
// Read vertex count from attributes and resize the array accordingly
int indexCount = node.attribute("count").as_int();
size_t vertexCount = node.attributes.begin() + indexCount;
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) {
// Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT"
if (IsElement("input") && vertexCount > 0) {
@ -1196,7 +1336,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
break;
}
}
}*/
}
// ------------------------------------------------------------------------------------------------
@ -1208,75 +1348,54 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
/*if (mReader->isEmptyElement())
return;*/
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);
for (XmlNode currentNode : node.children()) {
const std::string name = currentNode.name();
if (name == "image") {
int attrID = currentNode.attribute("id").as_int();
std::string id = currentNode.attributes.begin() + attrID;
mImageLibrary[id] = Image();
// 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;
// read on from there
ReadImage(currentNode, mImageLibrary[id]);
}
}
/*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
void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
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")) {
for (XmlNode currentNode : node.children()) {
const std::string currentName = currentNode.name();
if (currentName == "image") {
// Ignore
continue;
} else if (currentName == "init_from") {
if (mFormat == FV_1_4_n) {
// FIX: C4D exporter writes empty <init_from/> tags
if (!currentNode.empty()) {
// element content is filename - hopefully
const char *sz = TestTextContent();
if (sz) {
@ -1284,39 +1403,150 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
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");
TestClosing("init_from");
}
} else {
// ignore the rest
SkipElement();
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 = 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) {
if (strcmp(mReader->getNodeName(), "image") == 0)
break;
}
} else if (mFormat == FV_1_5_n) {
XmlNode refChild = currentNode.child("ref");
XmlNode hexChild = currentNode.child("hex");
if (refChild) {
// element content is filename - hopefully
const char *sz = refChild.value();
if (sz) {
aiString filepath(sz);
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;*/
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 (IsElement("material")) {
// read ID. By now you probably know my opinion about this "specification"
@ -1368,7 +1627,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
break;
}
}
}*/
}
// ------------------------------------------------------------------------------------------------
@ -2778,7 +3037,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
return;
}
/* if (mReader->isEmptyElement())
/* if (mReader->isEmptyElement())
return;*/
while (mReader->read()) {
@ -2796,7 +3055,6 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
if (attrName > -1)
child->mName = mReader->getAttributeValue(attrName);
if (pNode) {
pNode->mChildren.push_back(child);
child->mParent = pNode;
@ -3034,7 +3292,30 @@ void ColladaParser::ReadScene(XmlNode &node) {
/*if (mReader->isEmptyElement())
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 (IsElement("instance_visual_scene")) {
// 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) {
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
int ColladaParser::GetAttribute(const char *pAttr) const {
/*int ColladaParser::GetAttribute(const char *pAttr) const {
int index = TestAttribute(pAttr);
if (index == -1) {
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
return index;
}
}*/
// ------------------------------------------------------------------------------------------------
// 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++)
if (strcmp(mReader->getAttributeName(a), pAttr) == 0)
return a;
return -1;
}
}*/
// ------------------------------------------------------------------------------------------------
// 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();
if (!sz) {
ThrowException("Invalid contents in element \"n\".");
}
return sz;
}
}*/
// ------------------------------------------------------------------------------------------------
// 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
if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement())
return nullptr;
@ -3209,7 +3490,7 @@ const char *ColladaParser::TestTextContent() {
SkipSpacesAndLineEnd(&text);
return text;
}
}*/
// ------------------------------------------------------------------------------------------------
// 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
All rights reserved.
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 "OgreBinarySerializer.h"
#include "OgreParsingUtils.h"
#include <assimp/TinyFormatter.h>
#include <assimp/DefaultLogger.hpp>
#include <memory>
@ -56,85 +54,86 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
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 XmlReader *reader, const std::string &name, const std::string &error) {
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 std::string &nodeName, const std::string &name, const std::string &error) {
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 {
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 <>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name )) {
ThrowAttibuteError(mParser, name);
}
return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name));
pugi::xml_attribute attr = xmlNode.attribute(name);
return static_cast<int32_t>(attr.as_int());
}
template <>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name);
}
// @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 temp = ReadAttribute<int32_t>(name);
int32_t temp = ReadAttribute<int32_t>(xmlNode, name);
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);
}
template <>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name);
}
return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
return static_cast<uint16_t>(xmlNode.attribute(name).as_int());
}
template <>
float OgreXmlSerializer::ReadAttribute<float>(const char *name) const {
if (!HasAttribute(name)) {
ThrowAttibuteError(m_reader, name);
float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name);
}
return m_reader->getAttributeValueAsFloat(name);
return xmlNode.attribute(name).as_float();
}
template <>
std::string OgreXmlSerializer::ReadAttribute<std::string>(const char *name) const {
const char *value = m_reader->getAttributeValue(name);
if (nullptr == value) {
ThrowAttibuteError(m_reader, name);
std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name);
}
return std::string(value);
return xmlNode.attribute(name).as_string();
}
template <>
bool OgreXmlSerializer::ReadAttribute<bool>(const char *name) const {
std::string value = Ogre::ToLower(ReadAttribute<std::string>(name));
bool OgreXmlSerializer::ReadAttribute<bool>(XmlNode &xmlNode, const char *name) const {
std::string value = Ogre::ToLower(ReadAttribute<std::string>(xmlNode, name));
if (ASSIMP_stricmp(value, "true") == 0) {
return true;
} else if (ASSIMP_stricmp(value, "false") == 0) {
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 {
return (m_reader->getAttributeValue(name) != 0);
}
std::string &OgreXmlSerializer::NextNode() {
/*std::string &OgreXmlSerializer::NextNode() {
do {
if (!m_reader->read()) {
m_currentNodeName = "";
@ -178,7 +177,7 @@ std::string &OgreXmlSerializer::SkipCurrentNode() {
return NextNode();
}
*/
// Mesh XML constants
// <mesh>
@ -247,15 +246,14 @@ static const char *nnTranslate = "translate";
static const char *nnRotate = "rotate";
// Common XML constants
static const char *anX = "x";
static const char *anY = "y";
static const char *anZ = "z";
// Mesh
MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
OgreXmlSerializer serializer(reader);
MeshXml *OgreXmlSerializer::ImportMesh(XmlParser *xmlParser) {
OgreXmlSerializer serializer(xmlParser);
MeshXml *mesh = new MeshXml();
serializer.ReadMesh(mesh);
@ -264,16 +262,32 @@ MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
}
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>");
}
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");
NextNode();
//NextNode();
// Root level nodes
while (m_currentNodeName == nnSharedGeometry ||
/*while (m_currentNodeName == nnSharedGeometry ||
m_currentNodeName == nnSubMeshes ||
m_currentNodeName == nnSkeletonLink ||
m_currentNodeName == nnBoneAssignments ||
@ -298,26 +312,33 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
NextNode();
}
// Assimp incompatible/ignored nodes
else
else {
SkipCurrentNode();
}
}
}*/
}
void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest) {
dest->count = ReadAttribute<uint32_t>("vertexcount");
void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) {
dest->count = ReadAttribute<uint32_t>(node, "vertexcount");
ASSIMP_LOG_VERBOSE_DEBUG_F(" - Reading geometry of ", dest->count, " vertices");
NextNode();
while (m_currentNodeName == nnVertexBuffer) {
ReadGeometryVertexBuffer(dest);
for (XmlNode currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == nnVertexBuffer) {
ReadGeometryVertexBuffer(currentNode, dest);
}
}
//NextNode();
/*while (m_currentNodeName == nnVertexBuffer) {
ReadGeometryVertexBuffer(dest);
}*/
}
void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions"));
bool normals = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
bool tangents = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
uint32_t uvs = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0);
void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) {
bool positions = (hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions"));
bool normals = (hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals"));
bool tangents = (hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents"));
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.
if (!positions && !dest->HasPositions()) {
@ -348,9 +369,38 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
bool warnColorDiffuse = 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 == nnNormal ||
m_currentNodeName == nnTangent ||
@ -422,11 +472,11 @@ void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest) {
if (warn) {
ASSIMP_LOG_WARN_F("Vertex buffer attribute read not implemented for element: ", m_currentNodeName);
}
}
}*/
// Advance
NextNode();
}
//NextNode();
//}
// Sanity checks
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 *anUseSharedVertices = "usesharedvertices";
static const char *anCount = "count";
@ -457,10 +507,10 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
SubMeshXml *submesh = new SubMeshXml();
if (HasAttribute(anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(anMaterial);
if (hasAttribute(node, anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(node, anMaterial);
}
if (HasAttribute(anUseSharedVertices)) {
if (hasAttribute(node, anUseSharedVertices)) {
submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
}
@ -474,7 +524,46 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
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 ||
m_currentNodeName == nnGeometry ||
m_currentNodeName == nnTextures ||
@ -523,13 +612,13 @@ void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh) {
else {
SkipCurrentNode();
}
}
}*/
submesh->index = static_cast<unsigned int>(mesh->subMeshes.size());
mesh->subMeshes.push_back(submesh);
}
void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
void OgreXmlSerializer::ReadBoneAssignments(XmlNode &node, VertexDataXml *dest) {
if (!dest) {
throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
}
@ -539,8 +628,20 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
static const char *anWeight = "weight";
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) {
VertexBoneAssignment ba;
ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
@ -551,7 +652,7 @@ void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest) {
influencedVertices.insert(ba.vertexIndex);
NextNode();
}
}*/
/** Normalize 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";
}
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
if (!reader.get())
XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!xmlParser.get())
return false;
Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get());
OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton);
mesh->skeleton = skeleton;
return true;
}
bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh) {
if (!mesh || mesh->skeletonRef.empty())
if (!mesh || mesh->skeletonRef.empty()) {
return false;
}
XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
if (!reader.get())
XmlParserPtr xmlParser = OpenXmlParser(pIOHandler, mesh->skeletonRef);
if (!xmlParser.get()) {
return false;
}
Skeleton *skeleton = new Skeleton();
OgreXmlSerializer serializer(reader.get());
OgreXmlSerializer serializer(xmlParser.get());
serializer.ReadSkeleton(skeleton);
mesh->skeleton = skeleton;
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)) {
ASSIMP_LOG_ERROR_F("Imported Mesh is referencing to unsupported '", filename, "' skeleton file.");
return XmlReaderPtr();
return XmlParserPtr();
}
if (!pIOHandler->Exists(filename)) {
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));
@ -635,27 +738,36 @@ XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const s
throw DeadlyImportError("Failed to open skeleton file " + filename);
}
std::unique_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get()));
if (!reader.get()) {
XmlParserPtr xmlParser = XmlParserPtr(new XmlParser);
if (!xmlParser->parse(file.get())) {
throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
}
return reader;
return xmlParser;
}
void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
if (NextNode() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>");
void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
if (node.name() != nnSkeleton) {
throw DeadlyImportError("Root node is <" + node.name() + "> expecting <skeleton>");
}
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
// Optional blend mode from root node
if (HasAttribute("blendmode")) {
skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
if (hasAttribute(node, "blendmode")) {
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
while (m_currentNodeName == nnBones ||
@ -670,17 +782,35 @@ void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton) {
ReadAnimations(skeleton);
else
SkipCurrentNode();
}
}*/
}
void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) {
void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) {
throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
}
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) {
Animation *anim = new Animation(skeleton);
anim->name = ReadAttribute<std::string>("name");
@ -694,11 +824,29 @@ void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton) {
skeleton->animations.push_back(anim);
ASSIMP_LOG_VERBOSE_DEBUG_F(" ", anim->name, " (", anim->length, " sec, ", anim->tracks.size(), " tracks)");
}
}*/
}
void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) {
NextNode();
void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
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) {
VertexAnimationTrack track;
track.type = VertexAnimationTrack::VAT_TRANSFORM;
@ -711,13 +859,52 @@ void OgreXmlSerializer::ReadAnimationTracks(Animation *dest) {
ReadAnimationKeyFrames(dest, &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);
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) {
TransformKeyFrame keyframe;
keyframe.timePos = ReadAttribute<float>("time");
@ -756,15 +943,33 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationT
}
dest->transformKeyFrames.push_back(keyframe);
}
}*/
}
void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) {
void OgreXmlSerializer::ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton) {
if (skeleton->bones.empty()) {
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 parentName = ReadAttribute<std::string>("parent");
@ -775,7 +980,7 @@ void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton) {
parent->AddChild(bone);
else
throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
}
}*/
// Calculate bone matrices for root bones. Recursively calculates their children.
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);
}
void OgreXmlSerializer::ReadBones(Skeleton *skeleton) {
void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
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();
while (m_currentNodeName == nnBone) {
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 <assimp/XmlParser.h>
namespace Assimp
{
namespace Ogre
{
namespace Assimp {
namespace Ogre {
typedef irr::io::IrrXMLReader XmlReader;
typedef std::shared_ptr<XmlReader> XmlReaderPtr;
//typedef irr::io::IrrXMLReader XmlReader;
using XmlParserPtr = std::shared_ptr<XmlParser> ;
class OgreXmlSerializer
{
class OgreXmlSerializer {
public:
/// Imports mesh and returns the result.
/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
static MeshXml *ImportMesh(XmlReader *reader);
static MeshXml *ImportMesh(XmlParser *parser);
/// Imports skeleton to @c mesh.
/** If mesh does not have a skeleton reference or the skeleton file
cannot be found it is not a fatal DeadlyImportError.
@return If skeleton import was successful. */
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
static bool ImportSkeleton(IOSystem *pIOHandler, MeshXml *mesh);
static bool ImportSkeleton(IOSystem *pIOHandler, Mesh *mesh);
private:
explicit OgreXmlSerializer(XmlReader *reader) :
m_reader(reader)
{
}
explicit OgreXmlSerializer(XmlParser *xmlParser);
static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
static XmlParserPtr OpenXmlParser(Assimp::IOSystem *pIOHandler, const std::string &filename);
// Mesh
void ReadMesh(MeshXml *mesh);
void ReadSubMesh(MeshXml *mesh);
void ReadSubMesh(XmlNode &node, MeshXml *mesh);
void ReadGeometry(VertexDataXml *dest);
void ReadGeometryVertexBuffer(VertexDataXml *dest);
void ReadGeometry(XmlNode &node, VertexDataXml *dest);
void ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest);
void ReadBoneAssignments(VertexDataXml *dest);
void ReadBoneAssignments(XmlNode &node, VertexDataXml *dest);
// Skeleton
void ReadSkeleton(Skeleton *skeleton);
void ReadSkeleton(XmlNode &node, Skeleton *skeleton);
void ReadBones(Skeleton *skeleton);
void ReadBoneHierarchy(Skeleton *skeleton);
void ReadBones(XmlNode &node, Skeleton *skeleton);
void ReadBoneHierarchy(XmlNode &node, Skeleton *skeleton);
void ReadAnimations(Skeleton *skeleton);
void ReadAnimationTracks(Animation *dest);
void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest);
void ReadAnimations(XmlNode &node, Skeleton *skeleton);
void ReadAnimationTracks(XmlNode &node, Animation *dest);
void ReadAnimationKeyFrames(XmlNode &node, Animation *anim, VertexAnimationTrack *dest);
template<typename T>
T ReadAttribute(const char *name) const;
bool HasAttribute(const char *name) const;
template <typename T>
T ReadAttribute(XmlNode &xmlNode, const char *name) const;
//bool HasAttribute(const char *name) const;
std::string &NextNode();
std::string &SkipCurrentNode();
//std::string &NextNode();
//std::string &SkipCurrentNode();
bool CurrentNodeNameEquals(const std::string &name) const;
std::string CurrentNodeName(bool forceRead = false);
//bool CurrentNodeNameEquals(const std::string &name) const;
//std::string CurrentNodeName(bool forceRead = false);
XmlReader *m_reader;
XmlParser *mParser;
std::string m_currentNodeName;
};
} // Ogre
} // Assimp
inline OgreXmlSerializer::OgreXmlSerializer(XmlParser *xmlParser) :
mParser(xmlParser) {
// empty
}
} // namespace Ogre
} // namespace Assimp
#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
#endif // AI_OGREXMLSERIALIZER_H_INC