Parse the <build> node + refactoring
parent
629147043e
commit
eda967bd02
|
@ -55,6 +55,8 @@ namespace XmlTag {
|
|||
static const std::string resources = "resources";
|
||||
static const std::string object = "object";
|
||||
static const std::string mesh = "mesh";
|
||||
static const std::string components = "components";
|
||||
static const std::string component = "component";
|
||||
static const std::string vertices = "vertices";
|
||||
static const std::string vertex = "vertex";
|
||||
static const std::string triangles = "triangles";
|
||||
|
|
|
@ -66,19 +66,73 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace D3MF {
|
||||
|
||||
enum class ResourceType {
|
||||
RT_Object,
|
||||
RT_BaseMaterials,
|
||||
RT_Unknown
|
||||
}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
|
||||
|
||||
class Resource
|
||||
{
|
||||
public:
|
||||
Resource(int id) :
|
||||
mId(id) {}
|
||||
|
||||
virtual ~Resource() {}
|
||||
|
||||
int mId;
|
||||
|
||||
virtual ResourceType getType() {
|
||||
return ResourceType::RT_Unknown;
|
||||
}
|
||||
};
|
||||
|
||||
class BaseMaterials : public Resource {
|
||||
public:
|
||||
BaseMaterials(int id) :
|
||||
Resource(id),
|
||||
mMaterials(),
|
||||
mMaterialIndex() {}
|
||||
|
||||
std::vector<aiMaterial *> mMaterials;
|
||||
std::vector<unsigned int> mMaterialIndex;
|
||||
|
||||
virtual ResourceType getType() {
|
||||
return ResourceType::RT_BaseMaterials;
|
||||
}
|
||||
};
|
||||
|
||||
class Object : public Resource {
|
||||
public:
|
||||
std::vector<aiMesh*> mMeshes;
|
||||
std::vector<unsigned int> mMeshIndex;
|
||||
std::vector<int> mComponents;
|
||||
|
||||
Object(int id) :
|
||||
Resource(id) {}
|
||||
|
||||
virtual ResourceType getType() {
|
||||
return ResourceType::RT_Object;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class XmlSerializer {
|
||||
public:
|
||||
|
||||
XmlSerializer(XmlParser *xmlParser) :
|
||||
mMeshes(),
|
||||
mBasematerialsDictionnary(),
|
||||
mResourcesDictionnary(),
|
||||
mMaterialCount(0),
|
||||
mMeshCount(0),
|
||||
mXmlParser(xmlParser) {
|
||||
// empty
|
||||
}
|
||||
|
||||
~XmlSerializer() {
|
||||
// empty
|
||||
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void ImportXml(aiScene *scene) {
|
||||
|
@ -86,10 +140,8 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
scene->mRootNode = new aiNode();
|
||||
std::vector<aiNode *> children;
|
||||
scene->mRootNode = new aiNode("3MF");
|
||||
|
||||
std::string nodeName;
|
||||
XmlNode node = mXmlParser->getRootNode().child("model");
|
||||
if (node.empty()) {
|
||||
return;
|
||||
|
@ -98,9 +150,7 @@ public:
|
|||
for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||
const std::string ¤tNodeName = currentNode.name();
|
||||
if (currentNodeName == D3MF::XmlTag::object) {
|
||||
children.push_back(ReadObject(currentNode, scene));
|
||||
} else if (currentNodeName == D3MF::XmlTag::build) {
|
||||
//
|
||||
ReadObject(currentNode);;
|
||||
} else if (currentNodeName == D3MF::XmlTag::basematerials) {
|
||||
ReadBaseMaterials(currentNode);
|
||||
} else if (currentNodeName == D3MF::XmlTag::meta) {
|
||||
|
@ -108,10 +158,75 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (scene->mRootNode->mName.length == 0) {
|
||||
scene->mRootNode->mName.Set("3MF");
|
||||
XmlNode buildNode = node.child("build");
|
||||
for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||
const std::string ¤tNodeName = currentNode.name();
|
||||
if (currentNodeName == D3MF::XmlTag::item) {
|
||||
int objectId = -1;
|
||||
std::string transform;
|
||||
getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId);
|
||||
bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transform);
|
||||
|
||||
aiNode *sceneNode = new aiNode("item");
|
||||
auto it = mResourcesDictionnary.find(objectId);
|
||||
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
|
||||
Object *obj = static_cast<Object *>(it->second);
|
||||
std::vector<unsigned int> meshes;
|
||||
getMeshesList(obj, meshes);
|
||||
sceneNode->mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
|
||||
std::copy(meshes.begin(), meshes.end(), sceneNode->mMeshes);
|
||||
|
||||
if (hasTransform) {
|
||||
// split the string
|
||||
std::vector<float> numbers;
|
||||
std::string currentNumber;
|
||||
for (size_t i = 0; i < transform.size(); ++i) {
|
||||
const char c = transform[i];
|
||||
if (c == ' ') {
|
||||
if (currentNumber.size() > 0) {
|
||||
float f = std::stof(currentNumber);
|
||||
numbers.push_back(f);
|
||||
currentNumber.clear();
|
||||
}
|
||||
} else {
|
||||
currentNumber.push_back(c);
|
||||
}
|
||||
}
|
||||
if (currentNumber.size() > 0) {
|
||||
float f = std::stof(currentNumber);
|
||||
numbers.push_back(f);
|
||||
}
|
||||
|
||||
aiMatrix4x4 transformMatrix;
|
||||
transformMatrix.a1 = numbers[0];
|
||||
transformMatrix.b1 = numbers[1];
|
||||
transformMatrix.c1 = numbers[2];
|
||||
transformMatrix.d1 = 0;
|
||||
|
||||
transformMatrix.a2 = numbers[3];
|
||||
transformMatrix.b2 = numbers[4];
|
||||
transformMatrix.c2 = numbers[5];
|
||||
transformMatrix.d2 = 0;
|
||||
|
||||
transformMatrix.a3 = numbers[6];
|
||||
transformMatrix.b3 = numbers[7];
|
||||
transformMatrix.c3 = numbers[8];
|
||||
transformMatrix.d3 = 0;
|
||||
|
||||
transformMatrix.a4 = numbers[9];
|
||||
transformMatrix.b4 = numbers[10];
|
||||
transformMatrix.c4 = numbers[11];
|
||||
transformMatrix.d4 = 1;
|
||||
sceneNode->mTransformation = transformMatrix;
|
||||
}
|
||||
|
||||
scene->mRootNode->addChildren(1, &sceneNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// import the metadata
|
||||
if (!mMetaData.empty()) {
|
||||
const size_t numMeta(mMetaData.size());
|
||||
|
@ -131,17 +246,15 @@ public:
|
|||
scene->mNumMaterials = static_cast<unsigned int>(mMaterialCount);
|
||||
if (0 != scene->mNumMaterials) {
|
||||
scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
|
||||
for (auto it = mBasematerialsDictionnary.begin(); it != mBasematerialsDictionnary.end(); it++) {
|
||||
for (unsigned int i = 0; i < it->second.size(); ++i) {
|
||||
scene->mMaterials[it->second[i].first] = it->second[i].second;
|
||||
for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
|
||||
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
|
||||
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
|
||||
for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) {
|
||||
scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create the scene-graph
|
||||
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
|
||||
scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
|
||||
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -156,53 +269,79 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
aiNode *ReadObject(XmlNode &node, aiScene *scene) {
|
||||
std::unique_ptr<aiNode> nodePtr(new aiNode());
|
||||
bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
|
||||
std::string strValue;
|
||||
bool ret = getNodeAttribute(node, attribute, strValue);
|
||||
if (ret) {
|
||||
value = std::atoi(strValue.c_str());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned long> meshIds;
|
||||
void getMeshesList(Object *obj, std::vector<unsigned int> &meshes) {
|
||||
for (size_t i = 0; i < obj->mMeshIndex.size(); ++i) {
|
||||
meshes.push_back(obj->mMeshIndex[i]);
|
||||
}
|
||||
for (size_t i = 0; i < obj->mComponents.size(); ++i) {
|
||||
int componentId = obj->mComponents[i];
|
||||
auto it = mResourcesDictionnary.find(componentId);
|
||||
if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object)
|
||||
getMeshesList(static_cast<Object*>(it->second), meshes);
|
||||
}
|
||||
}
|
||||
|
||||
std::string id, type, pid, pindex;
|
||||
void ReadObject(XmlNode &node) {
|
||||
int id = -1, pid = -1, pindex = -1;
|
||||
bool hasId = getNodeAttribute(node, D3MF::XmlTag::id, id);
|
||||
//bool hasType = getNodeAttribute(node, D3MF::XmlTag::type, type); not used currently
|
||||
bool hasPid = getNodeAttribute(node, D3MF::XmlTag::pid, pid);
|
||||
bool hasPindex = getNodeAttribute(node, D3MF::XmlTag::pindex, pindex);
|
||||
|
||||
std::string idStr = to_string(id);
|
||||
|
||||
if (!hasId) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nodePtr->mParent = scene->mRootNode;
|
||||
nodePtr->mName.Set(id);
|
||||
|
||||
size_t meshIdx = mMeshes.size();
|
||||
Object *obj = new Object(id);
|
||||
|
||||
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == D3MF::XmlTag::mesh) {
|
||||
auto mesh = ReadMesh(currentNode);
|
||||
mesh->mName.Set(id);
|
||||
if (hasPid && hasPindex && mBasematerialsDictionnary.find(atoi(pid.c_str())) != mBasematerialsDictionnary.end()) {
|
||||
int iPid = atoi(pid.c_str());
|
||||
int iPindex = atoi(pindex.c_str());
|
||||
mesh->mMaterialIndex = mBasematerialsDictionnary[iPid][iPindex].first;
|
||||
mesh->mName.Set(idStr);
|
||||
|
||||
if (hasPid) {
|
||||
auto it = mResourcesDictionnary.find(pid);
|
||||
if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) {
|
||||
BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
|
||||
mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
|
||||
}
|
||||
}
|
||||
mMeshes.push_back(mesh);
|
||||
meshIds.push_back(static_cast<unsigned long>(meshIdx));
|
||||
++meshIdx;
|
||||
|
||||
obj->mMeshes.push_back(mesh);
|
||||
obj->mMeshIndex.push_back(mMeshCount);
|
||||
mMeshCount++;
|
||||
} else if (currentName == D3MF::XmlTag::components) {
|
||||
for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) {
|
||||
if (currentSubNode.name() == D3MF::XmlTag::component) {
|
||||
int objectId = -1;
|
||||
if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId))
|
||||
obj->mComponents.push_back(objectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodePtr->mNumMeshes = static_cast<unsigned int>(meshIds.size());
|
||||
|
||||
nodePtr->mMeshes = new unsigned int[nodePtr->mNumMeshes];
|
||||
|
||||
std::copy(meshIds.begin(), meshIds.end(), nodePtr->mMeshes);
|
||||
|
||||
return nodePtr.release();
|
||||
mResourcesDictionnary.insert(std::make_pair(id, obj));
|
||||
}
|
||||
|
||||
aiMesh *ReadMesh(XmlNode &node) {
|
||||
aiMesh *mesh = new aiMesh();
|
||||
|
||||
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == D3MF::XmlTag::vertices) {
|
||||
|
@ -241,6 +380,7 @@ private:
|
|||
|
||||
mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
|
||||
mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
||||
mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
|
||||
std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
|
||||
}
|
||||
|
||||
|
@ -258,14 +398,23 @@ private:
|
|||
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == D3MF::XmlTag::triangle) {
|
||||
faces.push_back(ReadTriangle(currentNode));
|
||||
const char *pidToken = currentNode.attribute(D3MF::XmlTag::pid.c_str()).as_string();
|
||||
const char *p1Token = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string();
|
||||
if (nullptr != pidToken && nullptr != p1Token && mBasematerialsDictionnary.find(std::atoi(pidToken)) != mBasematerialsDictionnary.end()) {
|
||||
int pid(std::atoi(pidToken));
|
||||
int p1(std::atoi(p1Token));
|
||||
mesh->mMaterialIndex = mBasematerialsDictionnary[pid][p1].first;
|
||||
// TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material
|
||||
aiFace face = ReadTriangle(currentNode);
|
||||
faces.push_back(face);
|
||||
|
||||
int pid, p1;
|
||||
bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
|
||||
bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
|
||||
|
||||
if (hasPid && hasP1) {
|
||||
auto it = mResourcesDictionnary.find(pid);
|
||||
if (it != mResourcesDictionnary.end())
|
||||
{
|
||||
if (it->second->getType() == ResourceType::RT_BaseMaterials) {
|
||||
BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
|
||||
mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
|
||||
}
|
||||
// TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,21 +439,20 @@ private:
|
|||
}
|
||||
|
||||
void ReadBaseMaterials(XmlNode &node) {
|
||||
std::vector<unsigned int> MatIdArray;
|
||||
const char *baseMaterialId = node.attribute(D3MF::XmlTag::basematerials_id.c_str()).as_string();
|
||||
if (nullptr != baseMaterialId) {
|
||||
unsigned int id = std::atoi(baseMaterialId);
|
||||
std::vector<std::pair<unsigned int, aiMaterial *> > materials;
|
||||
int id = -1;
|
||||
if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) {
|
||||
BaseMaterials* baseMaterials = new BaseMaterials(id);
|
||||
|
||||
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling())
|
||||
{
|
||||
if (currentNode.name() == D3MF::XmlTag::basematerials_base) {
|
||||
materials.push_back(std::make_pair(mMaterialCount, readMaterialDef(currentNode, id)));
|
||||
baseMaterials->mMaterialIndex.push_back(mMaterialCount);
|
||||
baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
|
||||
mMaterialCount++;
|
||||
}
|
||||
}
|
||||
|
||||
mBasematerialsDictionnary.insert(std::make_pair(id, materials));
|
||||
mResourcesDictionnary.insert(std::make_pair(id, baseMaterials));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,37 +468,24 @@ private:
|
|||
}
|
||||
|
||||
const char *buf(color);
|
||||
if ('#' != *buf) {
|
||||
if ('#' != buf[0]) {
|
||||
return false;
|
||||
}
|
||||
++buf;
|
||||
char comp[3] = { 0, 0, '\0' };
|
||||
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.r = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
char r[3] = { buf[1], buf[2], '\0' };
|
||||
diffuse.r = static_cast<ai_real>(strtol(r, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.g = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
char g[3] = { buf[3], buf[4], '\0' };
|
||||
diffuse.g = static_cast<ai_real>(strtol(g, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.b = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
char b[3] = { buf[5], buf[6], '\0' };
|
||||
diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
if (7 == len)
|
||||
return true;
|
||||
comp[0] = *buf;
|
||||
++buf;
|
||||
comp[1] = *buf;
|
||||
++buf;
|
||||
diffuse.a = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
char a[3] = { buf[7], buf[8], '\0' };
|
||||
diffuse.a = static_cast<ai_real>(strtol(a, nullptr, 16)) / ai_real(255.0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -364,32 +499,29 @@ private:
|
|||
}
|
||||
|
||||
aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) {
|
||||
aiMaterial *mat(nullptr);
|
||||
const char *name(nullptr);
|
||||
const std::string nodeName = node.name();
|
||||
if (nodeName == D3MF::XmlTag::basematerials_base) {
|
||||
name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string();
|
||||
std::string stdMatName;
|
||||
aiString matName;
|
||||
std::string strId(to_string(basematerialsId));
|
||||
stdMatName += "id";
|
||||
stdMatName += strId;
|
||||
stdMatName += "_";
|
||||
if (nullptr != name) {
|
||||
stdMatName += std::string(name);
|
||||
} else {
|
||||
stdMatName += "basemat_";
|
||||
stdMatName += to_string(mMaterialCount - basematerialsId);
|
||||
}
|
||||
matName.Set(stdMatName);
|
||||
aiMaterial *material = new aiMaterial();
|
||||
material->mNumProperties = 0;
|
||||
std::string name;
|
||||
bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
|
||||
|
||||
mat = new aiMaterial;
|
||||
mat->AddProperty(&matName, AI_MATKEY_NAME);
|
||||
|
||||
assignDiffuseColor(node, mat);
|
||||
std::string stdMaterialName;
|
||||
std::string strId(to_string(basematerialsId));
|
||||
stdMaterialName += "id";
|
||||
stdMaterialName += strId;
|
||||
stdMaterialName += "_";
|
||||
if (hasName) {
|
||||
stdMaterialName += std::string(name);
|
||||
} else {
|
||||
stdMaterialName += "basemat_";
|
||||
stdMaterialName += to_string(mMaterialCount - basematerialsId);
|
||||
}
|
||||
|
||||
return mat;
|
||||
aiString assimpMaterialName(stdMaterialName);
|
||||
material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME);
|
||||
|
||||
assignDiffuseColor(node, material);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -399,8 +531,8 @@ private:
|
|||
};
|
||||
std::vector<MetaEntry> mMetaData;
|
||||
std::vector<aiMesh *> mMeshes;
|
||||
std::map<unsigned int, std::vector<std::pair<unsigned int, aiMaterial *>>> mBasematerialsDictionnary;
|
||||
unsigned int mMaterialCount;
|
||||
std::map<unsigned int, Resource*> mResourcesDictionnary;
|
||||
unsigned int mMaterialCount, mMeshCount;
|
||||
XmlParser *mXmlParser;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue