move hasAttribute to XmlParser scope.

pull/2966/head
Kim Kulling 2020-08-19 00:19:56 +02:00
commit 56381241c5
28 changed files with 264 additions and 11441 deletions

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -46,12 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <cassert> #include <cassert>
#include <map> #include <map>
#include <memory> #include <memory>
@ -61,7 +60,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/irrXMLWrapper.h>
#include <iomanip> #include <iomanip>
@ -73,12 +71,12 @@ public:
using MatArray = std::vector<aiMaterial *>; using MatArray = std::vector<aiMaterial *>;
using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>; using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
XmlSerializer(XmlReader *xmlReader) : XmlSerializer(XmlParser *xmlParser) :
mMeshes(), mMeshes(),
mMatArray(), mMatArray(),
mActiveMatGroup(99999999), mActiveMatGroup(99999999),
mMatId2MatArray(), mMatId2MatArray(),
xmlReader(xmlReader) { mXmlParser(xmlParser) {
// empty // empty
} }
@ -95,16 +93,17 @@ public:
std::vector<aiNode *> children; std::vector<aiNode *> children;
std::string nodeName; std::string nodeName;
while (ReadToEndElement(D3MF::XmlTag::model)) { XmlNode *root = mXmlParser->getRootNode();
nodeName = xmlReader->getNodeName(); for (XmlNode &currentNode : root->children()) {
if (nodeName == D3MF::XmlTag::object) { const std::string &currentNodeName = currentNode.name();
children.push_back(ReadObject(scene)); if (currentNodeName == D3MF::XmlTag::object) {
} else if (nodeName == D3MF::XmlTag::build) { children.push_back(ReadObject(currentNode, scene));
} else if (currentNodeName == D3MF::XmlTag::build) {
// //
} else if (nodeName == D3MF::XmlTag::basematerials) { } else if (currentNodeName == D3MF::XmlTag::basematerials) {
ReadBaseMaterials(); ReadBaseMaterials(currentNode);
} else if (nodeName == D3MF::XmlTag::meta) { } else if (currentNodeName == D3MF::XmlTag::meta) {
ReadMetadata(); ReadMetadata(currentNode);
} }
} }
@ -141,31 +140,30 @@ public:
} }
private: private:
aiNode *ReadObject(aiScene *scene) { aiNode *ReadObject(XmlNode &node, aiScene *scene) {
std::unique_ptr<aiNode> node(new aiNode()); std::unique_ptr<aiNode> nodePtr(new aiNode());
std::vector<unsigned long> meshIds; std::vector<unsigned long> meshIds;
const char *attrib(nullptr);
std::string name, type; std::string name, type;
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str()); pugi::xml_attribute attr = node.attribute(D3MF::XmlTag::id.c_str());
if (nullptr != attrib) { if (!attr.empty()) {
name = attrib; name = attr.as_string();
} }
attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str()); attr = node.attribute(D3MF::XmlTag::id.c_str());
if (nullptr != attrib) { if (!attr.empty()) {
type = attrib; type = attr.as_string();
} }
node->mParent = scene->mRootNode; nodePtr->mParent = scene->mRootNode;
node->mName.Set(name); nodePtr->mName.Set(name);
size_t meshIdx = mMeshes.size(); size_t meshIdx = mMeshes.size();
while (ReadToEndElement(D3MF::XmlTag::object)) { for (pugi::xml_node &currentNode : node.children()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) { const std::string &currentName = currentNode.name();
auto mesh = ReadMesh(); if (currentName == D3MF::XmlTag::mesh) {
auto mesh = ReadMesh(currentNode);
mesh->mName.Set(name); mesh->mName.Set(name);
mMeshes.push_back(mesh); mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx)); meshIds.push_back(static_cast<unsigned long>(meshIdx));
@ -173,33 +171,34 @@ private:
} }
} }
node->mNumMeshes = static_cast<unsigned int>(meshIds.size()); nodePtr->mNumMeshes = static_cast<unsigned int>(meshIds.size());
node->mMeshes = new unsigned int[node->mNumMeshes]; nodePtr->mMeshes = new unsigned int[nodePtr->mNumMeshes];
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); std::copy(meshIds.begin(), meshIds.end(), nodePtr->mMeshes);
return node.release(); return nodePtr.release();
} }
aiMesh *ReadMesh() { aiMesh *ReadMesh(XmlNode &node) {
aiMesh *mesh = new aiMesh(); aiMesh *mesh = new aiMesh();
while (ReadToEndElement(D3MF::XmlTag::mesh)) { for (pugi::xml_node &currentNode : node.children()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) { const std::string &currentName = currentNode.name();
ImportVertices(mesh); if (currentName == D3MF::XmlTag::vertices) {
} else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) { ImportVertices(currentNode, mesh);
ImportTriangles(mesh); } else if (currentName == D3MF::XmlTag::triangles) {
ImportTriangles(currentNode, mesh);
} }
} }
return mesh; return mesh;
} }
void ReadMetadata() { void ReadMetadata(XmlNode &node) {
const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str()); pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str());
xmlReader->read(); const std::string name = attribute.as_string();
const std::string value = xmlReader->getNodeData(); const std::string value = node.value();
if (name.empty()) { if (name.empty()) {
return; return;
} }
@ -210,37 +209,36 @@ private:
mMetaData.push_back(entry); mMetaData.push_back(entry);
} }
void ImportVertices(aiMesh *mesh) { void ImportVertices(XmlNode &node, aiMesh *mesh) {
std::vector<aiVector3D> vertices; std::vector<aiVector3D> vertices;
while (ReadToEndElement(D3MF::XmlTag::vertices)) { for (pugi::xml_node &currentNode : node.children()) {
if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) { const std::string &currentName = currentNode.name();
vertices.push_back(ReadVertex()); if (currentName == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex(currentNode));
} }
} }
mesh->mNumVertices = static_cast<unsigned int>(vertices.size()); mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices); std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
} }
aiVector3D ReadVertex() { aiVector3D ReadVertex(XmlNode &node) {
aiVector3D vertex; aiVector3D vertex;
vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr);
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr);
vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr); vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr);
vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr);
return vertex; return vertex;
} }
void ImportTriangles(aiMesh *mesh) { void ImportTriangles(XmlNode &node, aiMesh *mesh) {
std::vector<aiFace> faces; std::vector<aiFace> faces;
for (pugi::xml_node &currentNode : node.children()) {
while (ReadToEndElement(D3MF::XmlTag::triangles)) { const std::string &currentName = currentNode.name();
const std::string nodeName(xmlReader->getNodeName()); if (currentName == D3MF::XmlTag::triangle) {
if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) { faces.push_back(ReadTriangle(currentNode));
faces.push_back(ReadTriangle()); const char *pidToken = currentNode.attribute(D3MF::XmlTag::p1.c_str()).as_string();
const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
if (nullptr != pidToken) { if (nullptr != pidToken) {
int matIdx(std::atoi(pidToken)); int matIdx(std::atoi(pidToken));
mesh->mMaterialIndex = matIdx; mesh->mMaterialIndex = matIdx;
@ -255,21 +253,21 @@ private:
std::copy(faces.begin(), faces.end(), mesh->mFaces); std::copy(faces.begin(), faces.end(), mesh->mFaces);
} }
aiFace ReadTriangle() { aiFace ReadTriangle(XmlNode &node) {
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices = new unsigned int[face.mNumIndices];
face.mIndices[0] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str()))); face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string()));
face.mIndices[1] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str()))); face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v2.c_str()).as_string()));
face.mIndices[2] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str()))); face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v3.c_str()).as_string()));
return face; return face;
} }
void ReadBaseMaterials() { void ReadBaseMaterials(XmlNode &node) {
std::vector<unsigned int> MatIdArray; std::vector<unsigned int> MatIdArray;
const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str())); const char *baseMaterialId = node.attribute(D3MF::XmlTag::basematerials_id.c_str()).as_string();
if (nullptr != baseMaterialId) { if (nullptr != baseMaterialId) {
unsigned int id = std::atoi(baseMaterialId); unsigned int id = std::atoi(baseMaterialId);
const size_t newMatIdx(mMatArray.size()); const size_t newMatIdx(mMatArray.size());
@ -287,9 +285,7 @@ private:
mMatId2MatArray[mActiveMatGroup] = MatIdArray; mMatId2MatArray[mActiveMatGroup] = MatIdArray;
} }
while (ReadToEndElement(D3MF::XmlTag::basematerials)) { mMatArray.push_back(readMaterialDef(node));
mMatArray.push_back(readMaterialDef());
}
} }
bool parseColor(const char *color, aiColor4D &diffuse) { bool parseColor(const char *color, aiColor4D &diffuse) {
@ -339,19 +335,23 @@ private:
return true; return true;
} }
void assignDiffuseColor(aiMaterial *mat) { void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str()); const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string();
//const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
aiColor4D diffuse; aiColor4D diffuse;
if (parseColor(color, diffuse)) { if (parseColor(color, diffuse)) {
mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
} }
} }
aiMaterial *readMaterialDef() {
aiMaterial *readMaterialDef(XmlNode &node) {
aiMaterial *mat(nullptr); aiMaterial *mat(nullptr);
const char *name(nullptr); const char *name(nullptr);
const std::string nodeName(xmlReader->getNodeName()); const std::string nodeName = node.name();
//const std::string nodeName(xmlReader->getNodeName());
if (nodeName == D3MF::XmlTag::basematerials_base) { if (nodeName == D3MF::XmlTag::basematerials_base) {
name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str()); name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string();
//name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str());
std::string stdMatName; std::string stdMatName;
aiString matName; aiString matName;
std::string strId(to_string(mActiveMatGroup)); std::string strId(to_string(mActiveMatGroup));
@ -368,40 +368,12 @@ private:
mat = new aiMaterial; mat = new aiMaterial;
mat->AddProperty(&matName, AI_MATKEY_NAME); mat->AddProperty(&matName, AI_MATKEY_NAME);
assignDiffuseColor(mat); assignDiffuseColor(node, mat);
} }
return mat; return mat;
} }
private:
bool ReadToStartElement(const std::string &startTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false;
}
}
return false;
}
bool ReadToEndElement(const std::string &closeTag) {
while (xmlReader->read()) {
const std::string &nodeName(xmlReader->getNodeName());
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
return false;
}
}
ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
return false;
}
private: private:
struct MetaEntry { struct MetaEntry {
std::string name; std::string name;
@ -412,7 +384,7 @@ private:
MatArray mMatArray; MatArray mMatArray;
unsigned int mActiveMatGroup; unsigned int mActiveMatGroup;
MatId2MatArray mMatId2MatArray; MatId2MatArray mMatId2MatArray;
XmlReader *xmlReader; XmlParser *mXmlParser;
}; };
} //namespace D3MF } //namespace D3MF
@ -468,12 +440,14 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) { void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); //std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); //std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
D3MF::XmlSerializer xmlSerializer(xmlReader.get());
XmlParser xmlParser;
if (xmlParser.parse(opcPackage.RootStream())) {
D3MF::XmlSerializer xmlSerializer(&xmlParser);
xmlSerializer.ImportXml(pScene); xmlSerializer.ImportXml(pScene);
}
} }
} // Namespace Assimp } // Namespace Assimp

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -45,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/XmlParser.h>
#include <assimp/ZipArchiveIOSystem.h> #include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -68,27 +68,23 @@ typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
class OpcPackageRelationshipReader { class OpcPackageRelationshipReader {
public: public:
OpcPackageRelationshipReader(XmlReader *xmlReader) { OpcPackageRelationshipReader(XmlParser &parser) {
while (xmlReader->read()) { XmlNode *root = parser.getRootNode();
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && if (nullptr != root) {
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) { ParseRootNode(*root);
ParseRootNode(xmlReader);
}
} }
} }
void ParseRootNode(XmlReader *xmlReader) { void ParseRootNode(XmlNode &node) {
ParseAttributes(xmlReader); ParseAttributes(node);
for (XmlNode currentNode : node.children()) {
ParseChildNode(currentNode);
while (xmlReader->read()) {
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
ParseChildNode(xmlReader);
}
} }
} }
void ParseAttributes(XmlReader *) { void ParseAttributes(XmlNode &/*node*/) {
// empty // empty
} }
@ -99,12 +95,12 @@ public:
return true; return true;
} }
void ParseChildNode(XmlReader *xmlReader) { void ParseChildNode(XmlNode &node) {
OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str()); relPtr->id = node.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string();
relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str()); relPtr->type = node.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string();
relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str()); relPtr->target = node.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string();
if (validateRels(relPtr)) { if (validateRels(relPtr)) {
m_relationShips.push_back(relPtr); m_relationShips.push_back(relPtr);
} }
@ -115,7 +111,8 @@ public:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) : D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
mRootStream(nullptr), mZipArchive() { mRootStream(nullptr),
mZipArchive() {
mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile)); mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
if (!mZipArchive->isOpen()) { if (!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile + "."); throw DeadlyImportError("Failed to open file " + rFile + ".");
@ -182,10 +179,12 @@ bool D3MFOpcPackage::validate() {
} }
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) { std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream)); XmlParser xmlParser;
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get())); if (!xmlParser.parse(stream)) {
return "";
}
OpcPackageRelationshipReader reader(xml.get()); OpcPackageRelationshipReader reader(xmlParser);
auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) { auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) {
return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -44,18 +43,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define D3MFOPCPACKAGE_H #define D3MFOPCPACKAGE_H
#include <memory> #include <memory>
#include <string>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/irrXMLWrapper.h> //#include <assimp/irrXMLWrapper.h>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem; class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ;
using XmlReaderPtr = std::shared_ptr<XmlReader> ;
struct OpcPackageRelationship { struct OpcPackageRelationship {
std::string id; std::string id;
std::string type; std::string type;
@ -64,7 +60,7 @@ struct OpcPackageRelationship {
class D3MFOpcPackage { class D3MFOpcPackage {
public: public:
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile ); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& file );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate(); bool validate();

View File

@ -68,7 +68,7 @@ AI_WONT_RETURN void ThrowAttibuteError(const std::string &nodeName, const std::s
template <> template <>
int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const { int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name )) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name); ThrowAttibuteError(mParser, name);
} }
pugi::xml_attribute attr = xmlNode.attribute(name); pugi::xml_attribute attr = xmlNode.attribute(name);
@ -77,7 +77,7 @@ int32_t OgreXmlSerializer::ReadAttribute<int32_t>(XmlNode &xmlNode, const char *
template <> template <>
uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const { uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name); ThrowAttibuteError(mParser, name);
} }
@ -93,7 +93,7 @@ uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(XmlNode &xmlNode, const char
template <> template <>
uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const { uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name); ThrowAttibuteError(mParser, name);
} }
@ -102,7 +102,7 @@ uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(XmlNode &xmlNode, const char
template <> template <>
float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const { float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name); ThrowAttibuteError(mParser, name);
} }
@ -111,7 +111,7 @@ float OgreXmlSerializer::ReadAttribute<float>(XmlNode &xmlNode, const char *name
template <> template <>
std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const { std::string OgreXmlSerializer::ReadAttribute<std::string>(XmlNode &xmlNode, const char *name) const {
if (!hasAttribute(xmlNode, name)) { if (!XmlParser::hasAttribute(xmlNode, name)) {
ThrowAttibuteError(mParser, name); ThrowAttibuteError(mParser, name);
} }
@ -298,10 +298,10 @@ void OgreXmlSerializer::ReadGeometry(XmlNode &node, VertexDataXml *dest) {
} }
void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) { void OgreXmlSerializer::ReadGeometryVertexBuffer(XmlNode &node, VertexDataXml *dest) {
bool positions = (hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions")); bool positions = (XmlParser::hasAttribute(node, "positions") && ReadAttribute<bool>(node, "positions"));
bool normals = (hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals")); bool normals = (XmlParser::hasAttribute(node, "normals") && ReadAttribute<bool>(node, "normals"));
bool tangents = (hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents")); bool tangents = (XmlParser::hasAttribute(node, "tangents") && ReadAttribute<bool>(node, "tangents"));
uint32_t uvs = (hasAttribute(node, "texture_coords") ? ReadAttribute<uint32_t>(node, "texture_coords") : 0); uint32_t uvs = (XmlParser::hasAttribute(node, "texture_coords") ? ReadAttribute<uint32_t>(node, "texture_coords") : 0);
// Not having positions is a error only if a previous vertex buffer did not have them. // Not having positions is a error only if a previous vertex buffer did not have them.
if (!positions && !dest->HasPositions()) { if (!positions && !dest->HasPositions()) {
@ -470,10 +470,10 @@ void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
SubMeshXml *submesh = new SubMeshXml(); SubMeshXml *submesh = new SubMeshXml();
if (hasAttribute(node, anMaterial)) { if (XmlParser::hasAttribute(node, anMaterial)) {
submesh->materialRef = ReadAttribute<std::string>(node, anMaterial); submesh->materialRef = ReadAttribute<std::string>(node, anMaterial);
} }
if (hasAttribute(node, anUseSharedVertices)) { if (XmlParser::hasAttribute(node, anUseSharedVertices)) {
submesh->usesSharedVertexData = ReadAttribute<bool>(node, anUseSharedVertices); submesh->usesSharedVertexData = ReadAttribute<bool>(node, anUseSharedVertices);
} }
@ -502,7 +502,7 @@ void OgreXmlSerializer::ReadSubMesh(XmlNode &node, MeshXml *mesh) {
face.mIndices[1] = ReadAttribute<uint32_t>(currentChildNode, anV2); face.mIndices[1] = ReadAttribute<uint32_t>(currentChildNode, anV2);
face.mIndices[2] = ReadAttribute<uint32_t>(currentChildNode, anV3); 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) /// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it)
if (!quadWarned && hasAttribute(currentChildNode, anV4)) { if (!quadWarned && XmlParser::hasAttribute(currentChildNode, anV4)) {
ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!"); ASSIMP_LOG_WARN("Submesh <face> has quads with <v4>, only triangles are supported at the moment!");
quadWarned = true; quadWarned = true;
} }
@ -722,7 +722,7 @@ void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton"); ASSIMP_LOG_VERBOSE_DEBUG("Reading Skeleton");
// Optional blend mode from root node // Optional blend mode from root node
if (hasAttribute(node, "blendmode")) { if (XmlParser::hasAttribute(node, "blendmode")) {
skeleton->blendMode = (ToLower(ReadAttribute<std::string>(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE); skeleton->blendMode = (ToLower(ReadAttribute<std::string>(node, "blendmode")) == "cumulative" ? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
} }
@ -997,15 +997,15 @@ void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
} }
} }
} else if (currentChildName == nnScale) { } else if (currentChildName == nnScale) {
if (hasAttribute(currentChildNode, "factor")) { if (XmlParser::hasAttribute(currentChildNode, "factor")) {
float factor = ReadAttribute<float>(currentChildNode, "factor"); float factor = ReadAttribute<float>(currentChildNode, "factor");
bone->scale.Set(factor, factor, factor); bone->scale.Set(factor, factor, factor);
} else { } else {
if (hasAttribute(currentChildNode, anX)) if (XmlParser::hasAttribute(currentChildNode, anX))
bone->scale.x = ReadAttribute<float>(currentChildNode, anX); bone->scale.x = ReadAttribute<float>(currentChildNode, anX);
if (hasAttribute(currentChildNode, anY)) if (XmlParser::hasAttribute(currentChildNode, anY))
bone->scale.y = ReadAttribute<float>(currentChildNode, anY); bone->scale.y = ReadAttribute<float>(currentChildNode, anY);
if (hasAttribute(currentChildNode, anZ)) if (XmlParser::hasAttribute(currentChildNode, anZ))
bone->scale.z = ReadAttribute<float>(currentChildNode, anZ); bone->scale.z = ReadAttribute<float>(currentChildNode, anZ);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file FIReader.hpp
/// \brief Reader for Fast Infoset encoded binary XML files.
/// \date 2017
/// \author Patrick Daehne
#ifndef INCLUDED_AI_FI_READER_H
#define INCLUDED_AI_FI_READER_H
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include <cerrno>
#include <cwchar>
#include <memory>
#include <string>
#include <vector>
#include <assimp/XmlParser.h>
namespace Assimp {
struct FIValue {
virtual const std::string &toString() const = 0;
virtual ~FIValue() {}
};
struct FIStringValue : public FIValue {
std::string value;
static std::shared_ptr<FIStringValue> create(std::string &&value);
};
struct FIByteValue : public FIValue {
std::vector<uint8_t> value;
};
struct FIHexValue : public FIByteValue {
static std::shared_ptr<FIHexValue> create(std::vector<uint8_t> &&value);
};
struct FIBase64Value : public FIByteValue {
static std::shared_ptr<FIBase64Value> create(std::vector<uint8_t> &&value);
};
struct FIShortValue : public FIValue {
std::vector<int16_t> value;
static std::shared_ptr<FIShortValue> create(std::vector<int16_t> &&value);
};
struct FIIntValue : public FIValue {
std::vector<int32_t> value;
static std::shared_ptr<FIIntValue> create(std::vector<int32_t> &&value);
};
struct FILongValue : public FIValue {
std::vector<int64_t> value;
static std::shared_ptr<FILongValue> create(std::vector<int64_t> &&value);
};
struct FIBoolValue : public FIValue {
std::vector<bool> value;
static std::shared_ptr<FIBoolValue> create(std::vector<bool> &&value);
};
struct FIFloatValue : public FIValue {
std::vector<float> value;
static std::shared_ptr<FIFloatValue> create(std::vector<float> &&value);
};
struct FIDoubleValue : public FIValue {
std::vector<double> value;
static std::shared_ptr<FIDoubleValue> create(std::vector<double> &&value);
};
struct FIUUIDValue : public FIByteValue {
static std::shared_ptr<FIUUIDValue> create(std::vector<uint8_t> &&value);
};
struct FICDATAValue : public FIStringValue {
static std::shared_ptr<FICDATAValue> create(std::string &&value);
};
struct FIDecoder {
virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) = 0;
virtual ~FIDecoder() {}
};
struct FIQName {
const char *name;
const char *prefix;
const char *uri;
};
struct FIVocabulary {
const char **restrictedAlphabetTable;
size_t restrictedAlphabetTableSize;
const char **encodingAlgorithmTable;
size_t encodingAlgorithmTableSize;
const char **prefixTable;
size_t prefixTableSize;
const char **namespaceNameTable;
size_t namespaceNameTableSize;
const char **localNameTable;
size_t localNameTableSize;
const char **otherNCNameTable;
size_t otherNCNameTableSize;
const char **otherURITable;
size_t otherURITableSize;
const std::shared_ptr<const FIValue> *attributeValueTable;
size_t attributeValueTableSize;
const std::shared_ptr<const FIValue> *charactersTable;
size_t charactersTableSize;
const std::shared_ptr<const FIValue> *otherStringTable;
size_t otherStringTableSize;
const FIQName *elementNameTable;
size_t elementNameTableSize;
const FIQName *attributeNameTable;
size_t attributeNameTableSize;
};
class IOStream;
class FIReader {
public:
virtual ~FIReader();
virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const = 0;
virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char *name) const = 0;
virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) = 0;
virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) = 0;
virtual bool read() = 0;
static std::unique_ptr<FIReader> create(IOStream *stream);
}; // class IFIReader
inline FIReader::~FIReader() {
// empty
}
} // namespace Assimp
#endif // #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#endif // INCLUDED_AI_FI_READER_H

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -48,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDED_AI_X3D_IMPORTER_H #ifndef INCLUDED_AI_X3D_IMPORTER_H
#define INCLUDED_AI_X3D_IMPORTER_H #define INCLUDED_AI_X3D_IMPORTER_H
#include "X3DImporter_Node.hpp"
// Header files, Assimp. // Header files, Assimp.
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
@ -57,8 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <assimp/XmlParser.h> #include <assimp/XmlParser.h>
#include "FIReader.hpp" #include <assimp/scene.h>
//#include <regex>
#include <list>
namespace Assimp { namespace Assimp {
@ -234,6 +233,62 @@ inline void LogInfo(const std::string &message) {
/// ///
/// That's all for now. Enjoy /// That's all for now. Enjoy
/// ///
enum class X3DElemType {
ENET_Group, ///< Element has type "Group".
ENET_MetaBoolean, ///< Element has type "Metadata boolean".
ENET_MetaDouble, ///< Element has type "Metadata double".
ENET_MetaFloat, ///< Element has type "Metadata float".
ENET_MetaInteger, ///< Element has type "Metadata integer".
ENET_MetaSet, ///< Element has type "Metadata set".
ENET_MetaString, ///< Element has type "Metadata string".
ENET_Arc2D, ///< Element has type "Arc2D".
ENET_ArcClose2D, ///< Element has type "ArcClose2D".
ENET_Circle2D, ///< Element has type "Circle2D".
ENET_Disk2D, ///< Element has type "Disk2D".
ENET_Polyline2D, ///< Element has type "Polyline2D".
ENET_Polypoint2D, ///< Element has type "Polypoint2D".
ENET_Rectangle2D, ///< Element has type "Rectangle2D".
ENET_TriangleSet2D, ///< Element has type "TriangleSet2D".
ENET_Box, ///< Element has type "Box".
ENET_Cone, ///< Element has type "Cone".
ENET_Cylinder, ///< Element has type "Cylinder".
ENET_Sphere, ///< Element has type "Sphere".
ENET_ElevationGrid, ///< Element has type "ElevationGrid".
ENET_Extrusion, ///< Element has type "Extrusion".
ENET_Coordinate, ///< Element has type "Coordinate".
ENET_Normal, ///< Element has type "Normal".
ENET_TextureCoordinate, ///< Element has type "TextureCoordinate".
ENET_IndexedFaceSet, ///< Element has type "IndexedFaceSet".
ENET_IndexedLineSet, ///< Element has type "IndexedLineSet".
ENET_IndexedTriangleSet, ///< Element has type "IndexedTriangleSet".
ENET_IndexedTriangleFanSet, ///< Element has type "IndexedTriangleFanSet".
ENET_IndexedTriangleStripSet, ///< Element has type "IndexedTriangleStripSet".
ENET_LineSet, ///< Element has type "LineSet".
ENET_PointSet, ///< Element has type "PointSet".
ENET_TriangleSet, ///< Element has type "TriangleSet".
ENET_TriangleFanSet, ///< Element has type "TriangleFanSet".
ENET_TriangleStripSet, ///< Element has type "TriangleStripSet".
ENET_Color, ///< Element has type "Color".
ENET_ColorRGBA, ///< Element has type "ColorRGBA".
ENET_Shape, ///< Element has type "Shape".
ENET_Appearance, ///< Element has type "Appearance".
ENET_Material, ///< Element has type "Material".
ENET_ImageTexture, ///< Element has type "ImageTexture".
ENET_TextureTransform, ///< Element has type "TextureTransform".
ENET_DirectionalLight, ///< Element has type "DirectionalLight".
ENET_PointLight, ///< Element has type "PointLight".
ENET_SpotLight, ///< Element has type "SpotLight".
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
struct X3DNodeElementBase {
X3DNodeElementBase *Parent;
std::string ID;
std::list<X3DNodeElementBase *> Child;
X3DElemType Type;
};
class X3DImporter : public BaseImporter class X3DImporter : public BaseImporter
{ {
public: public:
@ -259,526 +314,12 @@ public:
/// \param [in] pFile - name of file to be parsed. /// \param [in] pFile - name of file to be parsed.
/// \param [in] pIOHandler - pointer to IO helper object. /// \param [in] pIOHandler - pointer to IO helper object.
void ParseFile( const std::string& pFile, IOSystem* pIOHandler ); void ParseFile( const std::string& pFile, IOSystem* pIOHandler );
/***********************************************/
/********* Functions: BaseImporter set *********/
/***********************************************/
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig ) const; bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig ) const;
void GetExtensionList( std::set<std::string>& pExtensionList ); void GetExtensionList( std::set<std::string>& pExtensionList );
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ); void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler );
const aiImporterDesc* GetInfo()const; const aiImporterDesc* GetInfo()const;
private:
/// Disabled copy constructor.
X3DImporter(const X3DImporter& pScene);
/// Disabled assign operator.
X3DImporter& operator=(const X3DImporter& pScene);
/// Clear all temporary data.
void Clear(); void Clear();
/***********************************************/
/************* Functions: find set *************/
/***********************************************/
/// Find requested node element. Search will be made in all existing nodes.
/// \param [in] pID - ID of requested element.
/// \param [in] pType - type of requested element.
/// \param [out] pElement - pointer to pointer to item found.
/// \return true - if the element is found, else - false.
bool FindNodeElement_FromRoot(const std::string& pID, const X3DNodeElementBase::EType pType, X3DNodeElementBase** pElement);
/// Find requested node element. Search will be made from pointed node down to childs.
/// \param [in] pStartNode - pointer to start node.
/// \param [in] pID - ID of requested element.
/// \param [in] pType - type of requested element.
/// \param [out] pElement - pointer to pointer to item found.
/// \return true - if the element is found, else - false.
bool FindNodeElement_FromNode(X3DNodeElementBase* pStartNode, const std::string& pID, const X3DNodeElementBase::EType pType,
X3DNodeElementBase** pElement);
/// Find requested node element. For "Node"'s accounting flag "Static".
/// \param [in] pName - name of requested element.
/// \param [in] pType - type of requested element.
/// \param [out] pElement - pointer to pointer to item found.
/// \return true - if the element is found, else - false.
bool FindNodeElement(const std::string& pName, const X3DNodeElementBase::EType pType, X3DNodeElementBase** pElement);
/***********************************************/
/********* Functions: postprocess set **********/
/***********************************************/
/// \return transformation matrix from global coordinate system to local.
aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const;
/// Check if child elements of node element is metadata and add it to temporary list.
/// \param [in] pNodeElement - node element where metadata is searching.
/// \param [out] pList - temporary list for collected metadata.
void PostprocessHelper_CollectMetadata(const X3DNodeElementBase& pNodeElement, std::list<X3DNodeElementBase*>& pList) const;
/// Check if type of node element is metadata. E.g. <MetadataSet>, <MetadataString>.
/// \param [in] pType - checked type.
/// \return true - if the type corresponds to the metadata.
bool PostprocessHelper_ElementIsMetadata(const X3DNodeElementBase::EType pType) const;
/// Check if type of node element is geometry object and can be used to build mesh. E.g. <Box>, <Arc2D>.
/// \param [in] pType - checked type.
/// \return true - if the type corresponds to the mesh.
bool PostprocessHelper_ElementIsMesh(const X3DNodeElementBase::EType pType) const;
/// Read CX3DImporter_NodeElement_Light, create aiLight and add it to list of the lights.
/// \param [in] pNodeElement - reference to lisght element(<DirectionalLight>, <PointLight>, <SpotLight>).
/// \param [out] pSceneLightList - reference to list of the lights.
void Postprocess_BuildLight(const X3DNodeElementBase& pNodeElement, std::list<aiLight*>& pSceneLightList) const;
/// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract
/// all needed data from scene graph.
/// \param [in] pNodeElement - reference to material element(<Appearance>).
/// \param [out] pMaterial - pointer to pointer to created material. *pMaterial must be nullptr.
void Postprocess_BuildMaterial(const X3DNodeElementBase& pNodeElement, aiMaterial** pMaterial) const;
/// Create filled structure with type \ref aiMaterial from \ref CX3DImporter_NodeElement. This function itseld extract
/// all needed data from scene graph.
/// \param [in] pNodeElement - reference to geometry object.
/// \param [out] pMesh - pointer to pointer to created mesh. *pMesh must be nullptr.
void Postprocess_BuildMesh(const X3DNodeElementBase& pNodeElement, aiMesh** pMesh) const;
/// Create aiNode from CX3DImporter_NodeElement. Also function check children and make recursive call.
/// \param [out] pNode - pointer to pointer to created node. *pNode must be nullptr.
/// \param [in] pNodeElement - CX3DImporter_NodeElement which read.
/// \param [out] pSceneNode - aiNode for filling.
/// \param [out] pSceneMeshList - list with aiMesh which belong to scene.
/// \param [out] pSceneMaterialList - list with aiMaterial which belong to scene.
/// \param [out] pSceneLightList - list with aiLight which belong to scene.
void Postprocess_BuildNode(const X3DNodeElementBase& pNodeElement, aiNode& pSceneNode, std::list<aiMesh*>& pSceneMeshList,
std::list<aiMaterial*>& pSceneMaterialList, std::list<aiLight*>& pSceneLightList) const;
/// To create mesh and material kept in <Schape>.
/// \param pShapeNodeElement - reference to node element which kept <Shape> data.
/// \param pNodeMeshInd - reference to list with mesh indices. When pShapeNodeElement will read new mesh index will be added to this list.
/// \param pSceneMeshList - reference to list with meshes. When pShapeNodeElement will read new mesh will be added to this list.
/// \param pSceneMaterialList - reference to list with materials. When pShapeNodeElement will read new material will be added to this list.
void Postprocess_BuildShape(const X3DShape& pShapeNodeElement, std::list<unsigned int>& pNodeMeshInd,
std::list<aiMesh*>& pSceneMeshList, std::list<aiMaterial*>& pSceneMaterialList) const;
/// Check if child elements of node element is metadata and add it to scene node.
/// \param [in] pNodeElement - node element where metadata is searching.
/// \param [out] pSceneNode - scene node in which metadata will be added.
void Postprocess_CollectMetadata(const X3DNodeElementBase& pNodeElement, aiNode& pSceneNode) const;
/***********************************************/
/************** Functions: XML set *************/
/***********************************************/
/// Check if current node is empty: <node />. If not then exception will throwed.
void XML_CheckNode_MustBeEmpty(XmlNode &node);
/// Check if current node name is equal to pNodeName.
/// \param [in] pNodeName - name for checking.
/// return true if current node name is equal to pNodeName, else - false.
//bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
/// \param [in] pParentNodeName - parent node name. Used for reporting.
void XML_CheckNode_SkipUnsupported(XmlNode &node, const std::string &pParentNodeName);
/// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end.
/// \param [in] pNodeName - requested node name.
/// return true - if node is found, else - false.
bool XML_SearchNode(XmlNode &node, const std::string &pNodeName);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \return read data.
int32_t XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector<bool>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector<int32_t>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector<float>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector<double>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list<aiColor3D>& pValue);
/// \overload void XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::vector<aiColor3D>& pValue)
void XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::vector<aiColor3D>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list<aiColor4D>& pValue);
/// \overload void XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list<aiColor4D>& pValue)
void XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::vector<aiColor4D>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list<aiVector2D>& pValue);
/// \overload void XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list<aiVector2D>& pValue)
void XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::vector<aiVector2D>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list<aiVector3D>& pValue);
/// \overload void XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list<aiVector3D>& pValue)
void XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::vector<aiVector3D>& pValue);
/// Read attribute value.
/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
/// \param [out] pValue - read data.
void XML_ReadNode_GetAttrVal_AsListS(const int pAttrIdx, std::list<std::string>& pValue);
/***********************************************/
/******* Functions: geometry helper set *******/
/***********************************************/
/// Make point on surface oXY.
/// \param [in] pAngle - angle in radians between radius-vector of point and oX axis. Angle extends from the oX axis counterclockwise to the radius-vector.
/// \param [in] pRadius - length of radius-vector.
/// \return made point coordinates.
aiVector3D GeometryHelper_Make_Point2D(const float pAngle, const float pRadius);
/// Make 2D figure - linear circular arc with center in (0, 0). The z-coordinate is 0. The arc extends from the pStartAngle counterclockwise
/// to the pEndAngle. If pStartAngle and pEndAngle have the same value, a circle is specified. If the absolute difference between pStartAngle
/// and pEndAngle is greater than or equal to 2pi, a circle is specified.
/// \param [in] pStartAngle - angle in radians of start of the arc.
/// \param [in] pEndAngle - angle in radians of end of the arc.
/// \param [in] pRadius - radius of the arc.
/// \param [out] pNumSegments - number of segments in arc. In other words - tessellation factor.
/// \param [out] pVertices - generated vertices.
void GeometryHelper_Make_Arc2D(const float pStartAngle, const float pEndAngle, const float pRadius, size_t pNumSegments, std::list<aiVector3D>& pVertices);
/// Create line set from point set.
/// \param [in] pPoint - input points list.
/// \param [out] pLine - made lines list.
void GeometryHelper_Extend_PointToLine(const std::list<aiVector3D>& pPoint, std::list<aiVector3D>& pLine);
/// Create CoordIdx of line set from CoordIdx of polyline set.
/// \param [in] pPolylineCoordIdx - vertices indices divided by delimiter "-1". Must contain faces with two or more indices.
/// \param [out] pLineCoordIdx - made CoordIdx of line set.
void GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list<int32_t>& pPolylineCoordIdx, std::list<int32_t>& pLineCoordIdx);
/// Make 3D body - rectangular parallelepiped with center in (0, 0). QL mean quadlist (\sa pVertices).
/// \param [in] pSize - scale factor for body for every axis. E.g. (1, 2, 1) mean: X-size and Z-size - 1, Y-size - 2.
/// \param [out] pVertices - generated vertices. The list of vertices is grouped in quads.
void GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSize, std::list<aiVector3D>& pVertices);
/// Create faces array from vertices indices array.
/// \param [in] pCoordIdx - vertices indices divided by delimiter "-1".
/// \param [in] pFaces - created faces array.
/// \param [in] pPrimitiveTypes - type of primitives in faces.
void GeometryHelper_CoordIdxStr2FacesArr(const std::vector<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const;
/// Add colors to mesh.
/// a. If colorPerVertex is FALSE, colours are applied to each face, as follows:
/// If the colorIndex field is not empty, one colour is used for each face of the mesh. There shall be at least as many indices in the
/// colorIndex field as there are faces in the mesh. The colorIndex field shall not contain any negative entries.
/// If the colorIndex field is empty, the colours in the X3DColorNode node are applied to each face of the mesh in order.
/// There shall be at least as many colours in the X3DColorNode node as there are faces.
/// b. If colorPerVertex is TRUE, colours are applied to each vertex, as follows:
/// If the colorIndex field is not empty, colours are applied to each vertex of the mesh in exactly the same manner that the coordIndex
/// field is used to choose coordinates for each vertex from the <Coordinate> node. The colorIndex field shall contain end-of-face markers (-1)
/// in exactly the same places as the coordIndex field.
/// If the colorIndex field is empty, the coordIndex field is used to choose colours from the X3DColorNode node.
/// \param [in] pMesh - mesh for adding data.
/// \param [in] pCoordIdx - vertices indices divided by delimiter "-1".
/// \param [in] pColorIdx - color indices for every vertex divided by delimiter "-1" if \ref pColorPerVertex is true. if \ref pColorPerVertex is false
/// then pColorIdx contain color indices for every faces and must not contain delimiter "-1".
/// \param [in] pColors - defined colors.
/// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face.
void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const;
/// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx, const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const;
void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pColorIdx,
const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const;
/// Add colors to mesh.
/// \param [in] pMesh - mesh for adding data.
/// \param [in] pColors - defined colors.
/// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face.
void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const;
/// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const
void MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const;
/// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor;
void MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pNormalIdx,
const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const;
/// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor;
void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const;
/// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor;
void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector<int32_t>& pCoordIdx, const std::vector<int32_t>& pTexCoordIdx,
const std::list<aiVector2D>& pTexCoords) const;
/// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor;
void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<aiVector2D>& pTexCoords) const;
/// Create mesh.
/// \param [in] pCoordIdx - vertices indices divided by delimiter "-1".
/// \param [in] pVertices - vertices of mesh.
/// \return created mesh.
aiMesh* GeometryHelper_MakeMesh(const std::vector<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const;
/***********************************************/
/******** Functions: parse set private *********/
/***********************************************/
/// Create node element with type "Node" in scene graph. That operation is needed when you enter to X3D group node
/// like <Group>, <Transform> etc. When exiting from X3D group node(e.g. </Group>) \ref ParseHelper_Node_Exit must
/// be called.
/// \param [in] pStatic - flag: if true then static node is created(e.g. <StaticGroup>).
void ParseHelper_Group_Begin(const bool pStatic = false);
/// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called.
/// \param [in] pNode - new current node.
void ParseHelper_Node_Enter(X3DNodeElementBase* pNode);
/// This function must be called when exiting from X3D group node(e.g. </Group>). \ref ParseHelper_Group_Begin.
void ParseHelper_Node_Exit();
/// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it
/// must be converted to right form - "0.xxx".
/// \param [in] pInStr - pointer to input string which can contain incorrect form of values.
/// \param [out[ pOutString - output string with right form of values.
void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString);
/// Check if current node has nodes of type X3DMetadataObject. Why we must do it? Because X3DMetadataObject can be in any non-empty X3DNode.
/// Meaning that X3DMetadataObject can be in any non-empty node in <Scene>.
/// \return true - if metadata node are found and parsed, false - metadata not found.
bool ParseHelper_CheckRead_X3DMetadataObject();
/// Check if current node has nodes of type X3DGeometricPropertyNode. X3DGeometricPropertyNode
/// X3DGeometricPropertyNode inheritors:
/// <FogCoordinate>, <HAnimDisplacer>, <Color>, <ColorRGBA>, <Coordinate>, <CoordinateDouble>, <GeoCoordinate>, <Normal>,
/// <MultiTextureCoordinate>, <TextureCoordinate>, <TextureCoordinate3D>, <TextureCoordinate4D>, <TextureCoordinateGenerator>,
/// <FloatVertexAttribute>, <Matrix3VertexAttribute>, <Matrix4VertexAttribute>.
/// \return true - if nodes are found and parsed, false - nodes not found.
bool ParseHelper_CheckRead_X3DGeometricPropertyNode();
/// Parse <X3D> node of the file.
void ParseNode_Root();
/// Parse <head> node of the file.
void ParseNode_Head();
/// Parse <Scene> node of the file.
void ParseNode_Scene();
/// Parse child nodes of <Metadata*> node.
/// \param [in] pNodeName - parsed node name. Must be set because that function is general and name needed for checking the end
/// and error reporing.
/// \param [in] pParentElement - parent metadata element.
void ParseNode_Metadata(X3DNodeElementBase* pParentElement, const std::string& pNodeName);
/// Parse <MetadataBoolean> node of the file.
void ParseNode_MetadataBoolean();
/// Parse <MetadataDouble> node of the file.
void ParseNode_MetadataDouble();
/// Parse <MetadataFloat> node of the file.
void ParseNode_MetadataFloat();
/// Parse <MetadataInteger> node of the file.
void ParseNode_MetadataInteger();
/// Parse <MetadataSet> node of the file.
void ParseNode_MetadataSet();
/// \fn void ParseNode_MetadataString()
/// Parse <MetadataString> node of the file.
void ParseNode_MetadataString();
/// Parse <Arc2D> node of the file.
void ParseNode_Geometry2D_Arc2D(XmlNode &node);
/// Parse <ArcClose2D> node of the file.
void ParseNode_Geometry2D_ArcClose2D(XmlNode &node);
/// Parse <Circle2D> node of the file.
void ParseNode_Geometry2D_Circle2D(XmlNode &node);
/// Parse <Disk2D> node of the file.
void ParseNode_Geometry2D_Disk2D(XmlNode &node);
/// Parse <Polyline2D> node of the file.
void ParseNode_Geometry2D_Polyline2D(XmlNode &node);
/// Parse <Polypoint2D> node of the file.
void ParseNode_Geometry2D_Polypoint2D(XmlNode &node);
/// Parse <Rectangle2D> node of the file.
void ParseNode_Geometry2D_Rectangle2D(XmlNode &node);
/// Parse <TriangleSet2D> node of the file.
void ParseNode_Geometry2D_TriangleSet2D(XmlNode &node);
/// Parse <Box> node of the file.
void ParseNode_Geometry3D_Box(XmlNode &node);
/// Parse <Cone> node of the file.
void ParseNode_Geometry3D_Cone(XmlNode &node);
/// Parse <Cylinder> node of the file.
void ParseNode_Geometry3D_Cylinder(XmlNode &node);
/// Parse <ElevationGrid> node of the file.
void ParseNode_Geometry3D_ElevationGrid(XmlNode &node);
/// Parse <Extrusion> node of the file.
void ParseNode_Geometry3D_Extrusion(XmlNode &node);
/// Parse <IndexedFaceSet> node of the file.
void ParseNode_Geometry3D_IndexedFaceSet(XmlNode &node);
/// Parse <Sphere> node of the file.
void ParseNode_Geometry3D_Sphere(XmlNode &node);
/// Parse <Group> node of the file. And create new node in scene graph.
void ParseNode_Grouping_Group(XmlNode &node);
/// Doing actions at an exit from <Group>. Walk up in scene graph.
void ParseNode_Grouping_GroupEnd();
/// Parse <StaticGroup> node of the file. And create new node in scene graph.
void ParseNode_Grouping_StaticGroup(XmlNode &node);
/// Doing actions at an exit from <StaticGroup>. Walk up in scene graph.
void ParseNode_Grouping_StaticGroupEnd();
/// Parse <Switch> node of the file. And create new node in scene graph.
void ParseNode_Grouping_Switch(XmlNode &node);
/// Doing actions at an exit from <Switch>. Walk up in scene graph.
void ParseNode_Grouping_SwitchEnd();
/// Parse <Transform> node of the file. And create new node in scene graph.
void ParseNode_Grouping_Transform(XmlNode &node);
/// Doing actions at an exit from <Transform>. Walk up in scene graph.
void ParseNode_Grouping_TransformEnd();
/// Parse <Color> node of the file.
void ParseNode_Rendering_Color();
/// Parse <ColorRGBA> node of the file.
void ParseNode_Rendering_ColorRGBA();
/// Parse <Coordinate> node of the file.
void ParseNode_Rendering_Coordinate();
/// Parse <Normal> node of the file.
void ParseNode_Rendering_Normal();
/// Parse <IndexedLineSet> node of the file.
void ParseNode_Rendering_IndexedLineSet();
/// Parse <IndexedTriangleFanSet> node of the file.
void ParseNode_Rendering_IndexedTriangleFanSet();
/// Parse <IndexedTriangleSet> node of the file.
void ParseNode_Rendering_IndexedTriangleSet();
/// Parse <IndexedTriangleStripSet> node of the file.
void ParseNode_Rendering_IndexedTriangleStripSet();
/// Parse <LineSet> node of the file.
void ParseNode_Rendering_LineSet();
/// Parse <PointSet> node of the file.
void ParseNode_Rendering_PointSet();
/// Parse <TriangleFanSet> node of the file.
void ParseNode_Rendering_TriangleFanSet();
/// Parse <TriangleSet> node of the file.
void ParseNode_Rendering_TriangleSet();
/// Parse <TriangleStripSet> node of the file.
void ParseNode_Rendering_TriangleStripSet();
/// Parse <ImageTexture> node of the file.
void ParseNode_Texturing_ImageTexture();
/// Parse <TextureCoordinate> node of the file.
void ParseNode_Texturing_TextureCoordinate();
/// Parse <TextureTransform> node of the file.
void ParseNode_Texturing_TextureTransform();
/// Parse <Shape> node of the file.
void ParseNode_Shape_Shape();
/// Parse <Appearance> node of the file.
void ParseNode_Shape_Appearance();
/// Parse <Material> node of the file.
void ParseNode_Shape_Material();
/// Parse <Inline> node of the file.
void ParseNode_Networking_Inline();
/// Parse <DirectionalLight> node of the file.
void ParseNode_Lighting_DirectionalLight();
/// Parse <PointLight> node of the file.
void ParseNode_Lighting_PointLight();
/// Parse <SpotLight> node of the file.
void ParseNode_Lighting_SpotLight();
private: private:
/***********************************************/ /***********************************************/
/******************** Types ********************/ /******************** Types ********************/
@ -796,7 +337,7 @@ private:
/****************** Variables ******************/ /****************** Variables ******************/
/***********************************************/ /***********************************************/
X3DNodeElementBase* mNodeElementCur;///< Current element. X3DNodeElementBase* mNodeElementCur;///< Current element.
std::unique_ptr<FIReader> mReader;///< Pointer to XML-reader object XmlParser *mXmlParser;
IOSystem *mpIOHandler; IOSystem *mpIOHandler;
};// class X3DImporter };// class X3DImporter

View File

@ -1,521 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Geometry2D.cpp
/// \brief Parsing data from nodes of "Geometry2D" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Node.hpp"
#include "X3DImporter_Macro.hpp"
namespace Assimp
{
// <Arc2D
// DEF="" ID
// USE="" IDREF
// endAngle="1.570796" SFFloat [initializeOnly]
// radius="1" SFFloat [initializeOnly]
// startAngle="0" SFFloat [initializeOnly]
// />
// The Arc2D node specifies a linear circular arc whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
// towards the positive y-axis. The radius field specifies the radius of the circle of which the arc is a portion. The arc extends from the startAngle
// counterclockwise to the endAngle. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different
// angle base unit has been specified). If startAngle and endAngle have the same value, a circle is specified.
void X3DImporter::ParseNode_Geometry2D_Arc2D() {
std::string def, use;
float endAngle = AI_MATH_HALF_PI_F;
float radius = 1;
float startAngle = 0;
X3DNodeElementBase* ne = nullptr;
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;*/
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Arc2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Arc2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// create point list of geometry object and convert it to line set.
std::list<aiVector3D> tlist;
GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
GeometryHelper_Extend_PointToLine(tlist, ((X3DGeometry2D*)ne)->Vertices);
((X3DGeometry2D*)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Arc2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <ArcClose2D
// DEF="" ID
// USE="" IDREF
// closureType="PIE" SFString [initializeOnly], {"PIE", "CHORD"}
// endAngle="1.570796" SFFloat [initializeOnly]
// radius="1" SFFloat [initializeOnly]
// solid="false" SFBool [initializeOnly]
// startAngle="0" SFFloat [initializeOnly]
// />
// The ArcClose node specifies a portion of a circle whose center is at (0,0) and whose angles are measured starting at the positive x-axis and sweeping
// towards the positive y-axis. The end points of the arc specified are connected as defined by the closureType field. The radius field specifies the radius
// of the circle of which the arc is a portion. The arc extends from the startAngle counterclockwise to the endAngle. The value of radius shall be greater
// than zero. The values of startAngle and endAngle shall be in the range [-2pi, 2pi] radians (or the equivalent if a different default angle base unit has
// been specified). If startAngle and endAngle have the same value, a circle is specified and closureType is ignored. If the absolute difference between
// startAngle and endAngle is greater than or equal to 2pi, a complete circle is produced with no chord or radial line(s) drawn from the center.
// A closureType of "PIE" connects the end point to the start point by defining two straight line segments first from the end point to the center and then
// the center to the start point. A closureType of "CHORD" connects the end point to the start point by defining a straight line segment from the end point
// to the start point. Textures are applied individually to each face of the ArcClose2D. On the front (+Z) and back (-Z) faces of the ArcClose2D, when
// viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
void X3DImporter::ParseNode_Geometry2D_ArcClose2D()
{
std::string def, use;
std::string closureType("PIE");
float endAngle = AI_MATH_HALF_PI_F;
float radius = 1;
bool solid = false;
float startAngle = 0;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("closureType", closureType, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("endAngle", endAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("startAngle", startAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_ArcClose2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_ArcClose2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DGeometry2D*)ne)->Solid = solid;
// create point list of geometry object.
GeometryHelper_Make_Arc2D(startAngle, endAngle, radius, 10, ((X3DGeometry2D*)ne)->Vertices);///TODO: IME - AI_CONFIG for NumSeg
// add chord or two radiuses only if not a circle was defined
if(!((std::fabs(endAngle - startAngle) >= AI_MATH_TWO_PI_F) || (endAngle == startAngle)))
{
std::list<aiVector3D>& vlist = ((X3DGeometry2D*)ne)->Vertices;// just short alias.
if((closureType == "PIE") || (closureType == "\"PIE\""))
vlist.push_back(aiVector3D(0, 0, 0));// center point - first radial line
else if((closureType != "CHORD") && (closureType != "\"CHORD\""))
Throw_IncorrectAttrValue("closureType");
vlist.push_back(*vlist.begin());// arc first point - chord from first to last point of arc(if CHORD) or second radial line(if PIE).
}
((X3DGeometry2D*)ne)->NumIndices = ((X3DGeometry2D*)ne)->Vertices.size();
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "ArcClose2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Circle2D
// DEF="" ID
// USE="" IDREF
// radius="1" SFFloat [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry2D_Circle2D()
{
std::string def, use;
float radius = 1;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Circle2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Circle2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// create point list of geometry object and convert it to line set.
std::list<aiVector3D> tlist;
GeometryHelper_Make_Arc2D(0, 0, radius, 10, tlist);///TODO: IME - AI_CONFIG for NumSeg
GeometryHelper_Extend_PointToLine(tlist, ((X3DGeometry2D*)ne)->Vertices);
((X3DGeometry2D*)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Circle2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Disk2D
// DEF="" ID
// USE="" IDREF
// innerRadius="0" SFFloat [initializeOnly]
// outerRadius="1" SFFloat [initializeOnly]
// solid="false" SFBool [initializeOnly]
// />
// The Disk2D node specifies a circular disk which is centred at (0, 0) in the local coordinate system. The outerRadius field specifies the radius of the
// outer dimension of the Disk2D. The innerRadius field specifies the inner dimension of the Disk2D. The value of outerRadius shall be greater than zero.
// The value of innerRadius shall be greater than or equal to zero and less than or equal to outerRadius. If innerRadius is zero, the Disk2D is completely
// filled. Otherwise, the area within the innerRadius forms a hole in the Disk2D. If innerRadius is equal to outerRadius, a solid circular line shall
// be drawn using the current line properties. Textures are applied individually to each face of the Disk2D. On the front (+Z) and back (-Z) faces of
// the Disk2D, when viewed from the +Z-axis, the texture is mapped onto each face with the same orientation as if the image were displayed normally in 2D.
void X3DImporter::ParseNode_Geometry2D_Disk2D()
{
std::string def, use;
float innerRadius = 0;
float outerRadius = 1;
bool solid = false;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("innerRadius", innerRadius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("outerRadius", outerRadius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Disk2D, ne);
}
else
{
std::list<aiVector3D> tlist_o, tlist_i;
if(innerRadius > outerRadius) Throw_IncorrectAttrValue("innerRadius");
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Disk2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// create point list of geometry object.
///TODO: IME - AI_CONFIG for NumSeg
GeometryHelper_Make_Arc2D(0, 0, outerRadius, 10, tlist_o);// outer circle
if(innerRadius == 0.0f)
{// make filled disk
// in tlist_o we already have points of circle. just copy it and sign as polygon.
((X3DGeometry2D*)ne)->Vertices = tlist_o;
((X3DGeometry2D*)ne)->NumIndices = tlist_o.size();
}
else if(innerRadius == outerRadius)
{// make circle
// in tlist_o we already have points of circle. convert it to line set.
GeometryHelper_Extend_PointToLine(tlist_o, ((X3DGeometry2D*)ne)->Vertices);
((X3DGeometry2D*)ne)->NumIndices = 2;
}
else
{// make disk
std::list<aiVector3D>& vlist = ((X3DGeometry2D*)ne)->Vertices;// just short alias.
GeometryHelper_Make_Arc2D(0, 0, innerRadius, 10, tlist_i);// inner circle
//
// create quad list from two point lists
//
if(tlist_i.size() < 2) throw DeadlyImportError("Disk2D. Not enough points for creating quad list.");// tlist_i and tlist_o has equal size.
// add all quads except last
for(std::list<aiVector3D>::iterator it_i = tlist_i.begin(), it_o = tlist_o.begin(); it_i != tlist_i.end();)
{
// do not forget - CCW direction
vlist.push_back(*it_i++);// 1st point
vlist.push_back(*it_o++);// 2nd point
vlist.push_back(*it_o);// 3rd point
vlist.push_back(*it_i);// 4th point
}
// add last quad
vlist.push_back(*tlist_i.end());// 1st point
vlist.push_back(*tlist_o.end());// 2nd point
vlist.push_back(*tlist_o.begin());// 3rd point
vlist.push_back(*tlist_o.begin());// 4th point
((X3DGeometry2D*)ne)->NumIndices = 4;
}
((X3DGeometry2D*)ne)->Solid = solid;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Disk2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Polyline2D
// DEF="" ID
// USE="" IDREF
// lineSegments="" MFVec2F [intializeOnly]
// />
void X3DImporter::ParseNode_Geometry2D_Polyline2D()
{
std::string def, use;
std::list<aiVector2D> lineSegments;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("lineSegments", lineSegments, XML_ReadNode_GetAttrVal_AsListVec2f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polyline2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Polyline2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
//
// convert read point list of geometry object to line set.
//
std::list<aiVector3D> tlist;
// convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2) tlist.push_back(aiVector3D(it2->x, it2->y, 0));
// convert point set to line set
GeometryHelper_Extend_PointToLine(tlist, ((X3DGeometry2D*)ne)->Vertices);
((X3DGeometry2D*)ne)->NumIndices = 2;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Polyline2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Polypoint2D
// DEF="" ID
// USE="" IDREF
// point="" MFVec2F [inputOutput]
// />
void X3DImporter::ParseNode_Geometry2D_Polypoint2D()
{
std::string def, use;
std::list<aiVector2D> point;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Polypoint2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Polypoint2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); ++it2)
{
((X3DGeometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
}
((X3DGeometry2D*)ne)->NumIndices = 1;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Polypoint2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Rectangle2D
// DEF="" ID
// USE="" IDREF
// size="2 2" SFVec2f [initializeOnly]
// solid="false" SFBool [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry2D_Rectangle2D()
{
std::string def, use;
aiVector2D size(2, 2);
bool solid = false;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec2f);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Rectangle2D, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_Rectangle2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
float x1 = -size.x / 2.0f;
float x2 = size.x / 2.0f;
float y1 = -size.y / 2.0f;
float y2 = size.y / 2.0f;
std::list<aiVector3D>& vlist = ((X3DGeometry2D*)ne)->Vertices;// just short alias.
vlist.push_back(aiVector3D(x2, y1, 0));// 1st point
vlist.push_back(aiVector3D(x2, y2, 0));// 2nd point
vlist.push_back(aiVector3D(x1, y2, 0));// 3rd point
vlist.push_back(aiVector3D(x1, y1, 0));// 4th point
((X3DGeometry2D*)ne)->Solid = solid;
((X3DGeometry2D*)ne)->NumIndices = 4;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Rectangle2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <TriangleSet2D
// DEF="" ID
// USE="" IDREF
// solid="false" SFBool [initializeOnly]
// vertices="" MFVec2F [inputOutput]
// />
void X3DImporter::ParseNode_Geometry2D_TriangleSet2D()
{
std::string def, use;
bool solid = false;
std::list<aiVector2D> vertices;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("vertices", vertices, XML_ReadNode_GetAttrVal_AsListVec2f);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_TriangleSet2D, ne);
}
else
{
if(vertices.size() % 3) throw DeadlyImportError("TriangleSet2D. Not enough points for defining triangle.");
// create and if needed - define new geometry object.
ne = new X3DGeometry2D(X3DNodeElementBase::ENET_TriangleSet2D, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2)
{
((X3DGeometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
}
((X3DGeometry2D*)ne)->Solid = solid;
((X3DGeometry2D*)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "TriangleSet2D");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,999 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Geometry3D.cpp
/// \brief Parsing data from nodes of "Geometry3D" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
// Header files, Assimp.
#include <assimp/StandardShapes.h>
namespace Assimp
{
// <Box
// DEF="" ID
// USE="" IDREF
// size="2 2 2" SFVec3f [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
// The Box node specifies a rectangular parallelepiped box centred at (0, 0, 0) in the local coordinate system and aligned with the local coordinate axes.
// By default, the box measures 2 units in each dimension, from -1 to +1. The size field specifies the extents of the box along the X-, Y-, and Z-axes
// respectively and each component value shall be greater than zero.
void X3DImporter::ParseNode_Geometry3D_Box()
{
std::string def, use;
bool solid = true;
aiVector3D size(2, 2, 2);
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("size", size, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Box, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DGeometry3D(X3DNodeElementBase::ENET_Box, mNodeElementCur);
if(!def.empty()) ne->ID = def;
GeometryHelper_MakeQL_RectParallelepiped(size, ((X3DGeometry3D*)ne)->Vertices);// get quad list
((X3DGeometry3D*)ne)->Solid = solid;
((X3DGeometry3D*)ne)->NumIndices = 4;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Box");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Cone
// DEF="" ID
// USE="" IDREF
// bottom="true" SFBool [initializeOnly]
// bottomRadius="1" SFloat [initializeOnly]
// height="2" SFloat [initializeOnly]
// side="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry3D_Cone()
{
std::string use, def;
bool bottom = true;
float bottomRadius = 1;
float height = 2;
bool side = true;
bool solid = true;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("side", side, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("bottom", bottom, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("bottomRadius", bottomRadius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Cone, ne);
}
else
{
const unsigned int tess = 30;///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tvec;// temp array for vertices.
// create and if needed - define new geometry object.
ne = new X3DGeometry3D(X3DNodeElementBase::ENET_Cone, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// make cone or parts according to flags.
if(side)
{
StandardShapes::MakeCone(height, 0, bottomRadius, tess, tvec, !bottom);
}
else if(bottom)
{
StandardShapes::MakeCircle(bottomRadius, tess, tvec);
height = -(height / 2);
for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it) it->y = height;// y - because circle made in oXZ.
}
// copy data from temp array
for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it) ((X3DGeometry3D*)ne)->Vertices.push_back(*it);
((X3DGeometry3D*)ne)->Solid = solid;
((X3DGeometry3D*)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Cone");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Cylinder
// DEF="" ID
// USE="" IDREF
// bottom="true" SFBool [initializeOnly]
// height="2" SFloat [initializeOnly]
// radius="1" SFloat [initializeOnly]
// side="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// top="true" SFBool [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry3D_Cylinder()
{
std::string use, def;
bool bottom = true;
float height = 2;
float radius = 1;
bool side = true;
bool solid = true;
bool top = true;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("bottom", bottom, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("top", top, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("side", side, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Cylinder, ne);
}
else
{
const unsigned int tess = 30;///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tside;// temp array for vertices of side.
std::vector<aiVector3D> tcir;// temp array for vertices of circle.
// create and if needed - define new geometry object.
ne = new X3DGeometry3D(X3DNodeElementBase::ENET_Cylinder, mNodeElementCur);
if(!def.empty()) ne->ID = def;
// make cilynder or parts according to flags.
if(side) StandardShapes::MakeCone(height, radius, radius, tess, tside, true);
height /= 2;// height defined for whole cylinder, when creating top and bottom circle we are using just half of height.
if(top || bottom) StandardShapes::MakeCircle(radius, tess, tcir);
// copy data from temp arrays
std::list<aiVector3D>& vlist = ((X3DGeometry3D*)ne)->Vertices;// just short alias.
for(std::vector<aiVector3D>::iterator it = tside.begin(); it != tside.end(); ++it) vlist.push_back(*it);
if(top)
{
for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it)
{
(*it).y = height;// y - because circle made in oXZ.
vlist.push_back(*it);
}
}// if(top)
if(bottom)
{
for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it)
{
(*it).y = -height;// y - because circle made in oXZ.
vlist.push_back(*it);
}
}// if(top)
((X3DGeometry3D*)ne)->Solid = solid;
((X3DGeometry3D*)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Cylinder");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <ElevationGrid
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// creaseAngle="0" SFloat [initializeOnly]
// height="" MFloat [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// xDimension="0" SFInt32 [initializeOnly]
// xSpacing="1.0" SFloat [initializeOnly]
// zDimension="0" SFInt32 [initializeOnly]
// zSpacing="1.0" SFloat [initializeOnly]
// >
// <!-- ColorNormalTexCoordContentModel -->
// ColorNormalTexCoordContentModel can contain Color (or ColorRGBA), Normal and TextureCoordinate, in any order. No more than one instance of any single
// node type is allowed. A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </ElevationGrid>
// The ElevationGrid node specifies a uniform rectangular grid of varying height in the Y=0 plane of the local coordinate system. The geometry is described
// by a scalar array of height values that specify the height of a surface above each point of the grid. The xDimension and zDimension fields indicate
// the number of elements of the grid height array in the X and Z directions. Both xDimension and zDimension shall be greater than or equal to zero.
// If either the xDimension or the zDimension is less than two, the ElevationGrid contains no quadrilaterals.
void X3DImporter::ParseNode_Geometry3D_ElevationGrid()
{
std::string use, def;
bool ccw = true;
bool colorPerVertex = true;
float creaseAngle = 0;
std::vector<float> height;
bool normalPerVertex = true;
bool solid = true;
int32_t xDimension = 0;
float xSpacing = 1;
int32_t zDimension = 0;
float zSpacing = 1;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsArrF);
MACRO_ATTRREAD_CHECK_RET("xDimension", xDimension, XML_ReadNode_GetAttrVal_AsI32);
MACRO_ATTRREAD_CHECK_RET("xSpacing", xSpacing, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("zDimension", zDimension, XML_ReadNode_GetAttrVal_AsI32);
MACRO_ATTRREAD_CHECK_RET("zSpacing", zSpacing, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_ElevationGrid, ne);
}
else
{
if((xSpacing == 0.0f) || (zSpacing == 0.0f)) throw DeadlyImportError("Spacing in <ElevationGrid> must be grater than zero.");
if((xDimension <= 0) || (zDimension <= 0)) throw DeadlyImportError("Dimension in <ElevationGrid> must be grater than zero.");
if((size_t)(xDimension * zDimension) != height.size()) Throw_IncorrectAttrValue("Heights count must be equal to \"xDimension * zDimension\"");
// create and if needed - define new geometry object.
ne = new X3DElevationGrid(X3DNodeElementBase::ENET_ElevationGrid, mNodeElementCur);
if(!def.empty()) ne->ID = def;
X3DElevationGrid& grid_alias = *((X3DElevationGrid*)ne);// create alias for conveience
{// create grid vertices list
std::vector<float>::const_iterator he_it = height.begin();
for(int32_t zi = 0; zi < zDimension; zi++)// rows
{
for(int32_t xi = 0; xi < xDimension; xi++)// columns
{
aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi);
grid_alias.Vertices.push_back(tvec);
++he_it;
}
}
}// END: create grid vertices list
//
// create faces list. In "coordIdx" format
//
// check if we have quads
if((xDimension < 2) || (zDimension < 2))// only one element in dimension is set, create line set.
{
((X3DElevationGrid*)ne)->NumIndices = 2;// will be holded as line set.
for(size_t i = 0, i_e = (grid_alias.Vertices.size() - 1); i < i_e; i++)
{
grid_alias.CoordIdx.push_back(static_cast<int32_t>(i));
grid_alias.CoordIdx.push_back(static_cast<int32_t>(i + 1));
grid_alias.CoordIdx.push_back(-1);
}
}
else// two or more elements in every dimension is set. create quad set.
{
((X3DElevationGrid*)ne)->NumIndices = 4;
for(int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++)// rows
{
for(int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++)// columns
{
// points direction in face.
if(ccw)
{
// CCW:
// 3 2
// 0 1
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi);
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back(fzi * xDimension + fxi);
}
else
{
// CW:
// 0 1
// 3 2
grid_alias.CoordIdx.push_back(fzi * xDimension + fxi);
grid_alias.CoordIdx.push_back(fzi * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + (fxi + 1));
grid_alias.CoordIdx.push_back((fzi + 1) * xDimension + fxi);
}// if(ccw) else
grid_alias.CoordIdx.push_back(-1);
}// for(int32_t fxi = 0, fxi_e = (xDimension - 1); fxi < fxi_e; fxi++)
}// for(int32_t fzi = 0, fzi_e = (zDimension - 1); fzi < fzi_e; fzi++)
}// if((xDimension < 2) || (zDimension < 2)) else
grid_alias.ColorPerVertex = colorPerVertex;
grid_alias.NormalPerVertex = normalPerVertex;
grid_alias.CreaseAngle = creaseAngle;
grid_alias.Solid = solid;
// check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("ElevationGrid");
// check for X3DComposedGeometryNodes
if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; }
if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; }
if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; }
if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; }
// check for X3DMetadataObject
if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("ElevationGrid");
MACRO_NODECHECK_LOOPEND("ElevationGrid");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
}// if(!mReader->isEmptyElement()) else
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
template<typename TVector>
static void GeometryHelper_Extrusion_CurveIsClosed(std::vector<TVector>& pCurve, const bool pDropTail, const bool pRemoveLastPoint, bool& pCurveIsClosed)
{
size_t cur_sz = pCurve.size();
pCurveIsClosed = false;
// for curve with less than four points checking is have no sense,
if(cur_sz < 4) return;
for(size_t s = 3, s_e = cur_sz; s < s_e; s++)
{
// search for first point of duplicated part.
if(pCurve[0] == pCurve[s])
{
bool found = true;
// check if tail(indexed by b2) is duplicate of head(indexed by b1).
for(size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++)
{
if(pCurve[b1] != pCurve[b2])
{// points not match: clear flag and break loop.
found = false;
break;
}
}// for(size_t b1 = 1, b2 = (s + 1); b2 < cur_sz; b1++, b2++)
// if duplicate tail is found then drop or not it depending on flags.
if(found)
{
pCurveIsClosed = true;
if(pDropTail)
{
if(!pRemoveLastPoint) s++;// prepare value for iterator's arithmetics.
pCurve.erase(pCurve.begin() + s, pCurve.end());// remove tail
}
break;
}// if(found)
}// if(pCurve[0] == pCurve[s])
}// for(size_t s = 3, s_e = (cur_sz - 1); s < s_e; s++)
}
static aiVector3D GeometryHelper_Extrusion_GetNextY(const size_t pSpine_PointIdx, const std::vector<aiVector3D>& pSpine, const bool pSpine_Closed)
{
const size_t spine_idx_last = pSpine.size() - 1;
aiVector3D tvec;
if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last))// at first special cases
{
if(pSpine_Closed)
{// If the spine curve is closed: The SCP for the first and last points is the same and is found using (spine[1] - spine[n - 2]) to compute the Y-axis.
// As we even for closed spine curve last and first point in pSpine are not the same: duplicates(spine[n - 1] which are equivalent to spine[0])
// in tail are removed.
// So, last point in pSpine is a spine[n - 2]
tvec = pSpine[1] - pSpine[spine_idx_last];
}
else if(pSpine_PointIdx == 0)
{// The Y-axis used for the first point is the vector from spine[0] to spine[1]
tvec = pSpine[1] - pSpine[0];
}
else
{// The Y-axis used for the last point it is the vector from spine[n-2] to spine[n-1]. In our case(see above about dropping tail) spine[n - 1] is
// the spine[0].
tvec = pSpine[spine_idx_last] - pSpine[spine_idx_last - 1];
}
}// if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last))
else
{// For all points other than the first or last: The Y-axis for spine[i] is found by normalizing the vector defined by (spine[i+1] - spine[i-1]).
tvec = pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx - 1];
}// if((pSpine_PointIdx == 0) || (pSpine_PointIdx == spine_idx_last)) else
return tvec.Normalize();
}
static aiVector3D GeometryHelper_Extrusion_GetNextZ(const size_t pSpine_PointIdx, const std::vector<aiVector3D>& pSpine, const bool pSpine_Closed,
const aiVector3D pVecZ_Prev)
{
const aiVector3D zero_vec(0);
const size_t spine_idx_last = pSpine.size() - 1;
aiVector3D tvec;
// at first special cases
if(pSpine.size() < 3)// spine have not enough points for vector calculations.
{
tvec.Set(0, 0, 1);
}
else if(pSpine_PointIdx == 0)// special case: first point
{
if(pSpine_Closed)// for calculating use previous point in curve s[n - 2]. In list it's a last point, because point s[n - 1] was removed as duplicate.
{
tvec = (pSpine[1] - pSpine[0]) ^ (pSpine[spine_idx_last] - pSpine[0]);
}
else // for not closed curve first and next point(s[0] and s[1]) has the same vector Z.
{
bool found = false;
// As said: "If the Z-axis of the first point is undefined (because the spine is not closed and the first two spine segments are collinear)
// then the Z-axis for the first spine point with a defined Z-axis is used."
// Walk through spine and find Z.
for(size_t next_point = 2; (next_point <= spine_idx_last) && !found; next_point++)
{
// (pSpine[2] - pSpine[1]) ^ (pSpine[0] - pSpine[1])
tvec = (pSpine[next_point] - pSpine[next_point - 1]) ^ (pSpine[next_point - 2] - pSpine[next_point - 1]);
found = !tvec.Equal(zero_vec);
}
// if entire spine are collinear then use OZ axis.
if(!found) tvec.Set(0, 0, 1);
}// if(pSpine_Closed) else
}// else if(pSpine_PointIdx == 0)
else if(pSpine_PointIdx == spine_idx_last)// special case: last point
{
if(pSpine_Closed)
{// do not forget that real last point s[n - 1] is removed as duplicated. And in this case we are calculating vector Z for point s[n - 2].
tvec = (pSpine[0] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]);
// if taken spine vectors are collinear then use previous vector Z.
if(tvec.Equal(zero_vec)) tvec = pVecZ_Prev;
}
else
{// vector Z for last point of not closed curve is previous vector Z.
tvec = pVecZ_Prev;
}
}
else// regular point
{
tvec = (pSpine[pSpine_PointIdx + 1] - pSpine[pSpine_PointIdx]) ^ (pSpine[pSpine_PointIdx - 1] - pSpine[pSpine_PointIdx]);
// if taken spine vectors are collinear then use previous vector Z.
if(tvec.Equal(zero_vec)) tvec = pVecZ_Prev;
}
// After determining the Z-axis, its dot product with the Z-axis of the previous spine point is computed. If this value is negative, the Z-axis
// is flipped (multiplied by -1).
if((tvec * pVecZ_Prev) < 0) tvec = -tvec;
return tvec.Normalize();
}
// <Extrusion
// DEF="" ID
// USE="" IDREF
// beginCap="true" SFBool [initializeOnly]
// ccw="true" SFBool [initializeOnly]
// convex="true" SFBool [initializeOnly]
// creaseAngle="0.0" SFloat [initializeOnly]
// crossSection="1 1 1 -1 -1 -1 -1 1 1 1" MFVec2f [initializeOnly]
// endCap="true" SFBool [initializeOnly]
// orientation="0 0 1 0" MFRotation [initializeOnly]
// scale="1 1" MFVec2f [initializeOnly]
// solid="true" SFBool [initializeOnly]
// spine="0 0 0 0 1 0" MFVec3f [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry3D_Extrusion()
{
std::string use, def;
bool beginCap = true;
bool ccw = true;
bool convex = true;
float creaseAngle = 0;
std::vector<aiVector2D> crossSection;
bool endCap = true;
std::vector<float> orientation;
std::vector<aiVector2D> scale;
bool solid = true;
std::vector<aiVector3D> spine;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("beginCap", beginCap, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("crossSection", crossSection, XML_ReadNode_GetAttrVal_AsArrVec2f);
MACRO_ATTRREAD_CHECK_RET("endCap", endCap, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("orientation", orientation, XML_ReadNode_GetAttrVal_AsArrF);
MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsArrVec2f);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("spine", spine, XML_ReadNode_GetAttrVal_AsArrVec3f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Extrusion, ne);
}
else
{
//
// check if default values must be assigned
//
if(spine.size() == 0)
{
spine.resize(2);
spine[0].Set(0, 0, 0), spine[1].Set(0, 1, 0);
}
else if(spine.size() == 1)
{
throw DeadlyImportError("ParseNode_Geometry3D_Extrusion. Spine must have at least two points.");
}
if(crossSection.size() == 0)
{
crossSection.resize(5);
crossSection[0].Set(1, 1), crossSection[1].Set(1, -1), crossSection[2].Set(-1, -1), crossSection[3].Set(-1, 1), crossSection[4].Set(1, 1);
}
{// orientation
size_t ori_size = orientation.size() / 4;
if(ori_size < spine.size())
{
float add_ori[4];// values that will be added
if(ori_size == 1)// if "orientation" has one element(means one MFRotation with four components) then use it value for all spine points.
{
add_ori[0] = orientation[0], add_ori[1] = orientation[1], add_ori[2] = orientation[2], add_ori[3] = orientation[3];
}
else// else - use default values
{
add_ori[0] = 0, add_ori[1] = 0, add_ori[2] = 1, add_ori[3] = 0;
}
orientation.reserve(spine.size() * 4);
for(size_t i = 0, i_e = (spine.size() - ori_size); i < i_e; i++)
orientation.push_back(add_ori[0]), orientation.push_back(add_ori[1]), orientation.push_back(add_ori[2]), orientation.push_back(add_ori[3]);
}
if(orientation.size() % 4) throw DeadlyImportError("Attribute \"orientation\" in <Extrusion> must has multiple four quantity of numbers.");
}// END: orientation
{// scale
if(scale.size() < spine.size())
{
aiVector2D add_sc;
if(scale.size() == 1)// if "scale" has one element then use it value for all spine points.
add_sc = scale[0];
else// else - use default values
add_sc.Set(1, 1);
scale.reserve(spine.size());
for(size_t i = 0, i_e = (spine.size() - scale.size()); i < i_e; i++) scale.push_back(add_sc);
}
}// END: scale
//
// create and if needed - define new geometry object.
//
ne = new X3DIndexedSet(X3DNodeElementBase::ENET_Extrusion, mNodeElementCur);
if(!def.empty()) ne->ID = def;
X3DIndexedSet& ext_alias = *((X3DIndexedSet*)ne);// create alias for conveience
// assign part of input data
ext_alias.CCW = ccw;
ext_alias.Convex = convex;
ext_alias.CreaseAngle = creaseAngle;
ext_alias.Solid = solid;
//
// How we done it at all?
// 1. At first we will calculate array of basises for every point in spine(look SCP in ISO-dic). Also "orientation" vector
// are applied vor every basis.
// 2. After that we can create array of point sets: which are scaled, transferred to basis of relative basis and at final translated to real position
// using relative spine point.
// 3. Next step is creating CoordIdx array(do not forget "-1" delimiter). While creating CoordIdx also created faces for begin and end caps, if
// needed. While createing CootdIdx is taking in account CCW flag.
// 4. The last step: create Vertices list.
//
bool spine_closed;// flag: true if spine curve is closed.
bool cross_closed;// flag: true if cross curve is closed.
std::vector<aiMatrix3x3> basis_arr;// array of basises. ROW_a - X, ROW_b - Y, ROW_c - Z.
std::vector<std::vector<aiVector3D> > pointset_arr;// array of point sets: cross curves.
// detect closed curves
GeometryHelper_Extrusion_CurveIsClosed(crossSection, true, true, cross_closed);// true - drop tail, true - remove duplicate end.
GeometryHelper_Extrusion_CurveIsClosed(spine, true, true, spine_closed);// true - drop tail, true - remove duplicate end.
// If both cap are requested and spine curve is closed then we can make only one cap. Because second cap will be the same surface.
if(spine_closed)
{
beginCap |= endCap;
endCap = false;
}
{// 1. Calculate array of basises.
aiMatrix4x4 rotmat;
aiVector3D vecX(0), vecY(0), vecZ(0);
basis_arr.resize(spine.size());
for(size_t i = 0, i_e = spine.size(); i < i_e; i++)
{
aiVector3D tvec;
// get axises of basis.
vecY = GeometryHelper_Extrusion_GetNextY(i, spine, spine_closed);
vecZ = GeometryHelper_Extrusion_GetNextZ(i, spine, spine_closed, vecZ);
vecX = (vecY ^ vecZ).Normalize();
// get rotation matrix and apply "orientation" to basis
aiMatrix4x4::Rotation(orientation[i * 4 + 3], aiVector3D(orientation[i * 4], orientation[i * 4 + 1], orientation[i * 4 + 2]), rotmat);
tvec = vecX, tvec *= rotmat, basis_arr[i].a1 = tvec.x, basis_arr[i].a2 = tvec.y, basis_arr[i].a3 = tvec.z;
tvec = vecY, tvec *= rotmat, basis_arr[i].b1 = tvec.x, basis_arr[i].b2 = tvec.y, basis_arr[i].b3 = tvec.z;
tvec = vecZ, tvec *= rotmat, basis_arr[i].c1 = tvec.x, basis_arr[i].c2 = tvec.y, basis_arr[i].c3 = tvec.z;
}// for(size_t i = 0, i_e = spine.size(); i < i_e; i++)
}// END: 1. Calculate array of basises
{// 2. Create array of point sets.
aiMatrix4x4 scmat;
std::vector<aiVector3D> tcross(crossSection.size());
pointset_arr.resize(spine.size());
for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++)
{
aiVector3D tc23vec;
tc23vec.Set(scale[spi].x, 0, scale[spi].y);
aiMatrix4x4::Scaling(tc23vec, scmat);
for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++)
{
aiVector3D tvecX, tvecY, tvecZ;
tc23vec.Set(crossSection[cri].x, 0, crossSection[cri].y);
// apply scaling to point
tcross[cri] = scmat * tc23vec;
//
// transfer point to new basis
// calculate coordinate in new basis
tvecX.Set(basis_arr[spi].a1, basis_arr[spi].a2, basis_arr[spi].a3), tvecX *= tcross[cri].x;
tvecY.Set(basis_arr[spi].b1, basis_arr[spi].b2, basis_arr[spi].b3), tvecY *= tcross[cri].y;
tvecZ.Set(basis_arr[spi].c1, basis_arr[spi].c2, basis_arr[spi].c3), tvecZ *= tcross[cri].z;
// apply new coordinates and translate it to spine point.
tcross[cri] = tvecX + tvecY + tvecZ + spine[spi];
}// for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; i++)
pointset_arr[spi] = tcross;// store transferred point set
}// for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; i++)
}// END: 2. Create array of point sets.
{// 3. Create CoordIdx.
// add caps if needed
if(beginCap)
{
// add cap as polygon. vertices of cap are places at begin, so just add numbers from zero.
for(size_t i = 0, i_e = crossSection.size(); i < i_e; i++) ext_alias.CoordIndex.push_back(static_cast<int32_t>(i));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
}// if(beginCap)
if(endCap)
{
// add cap as polygon. vertices of cap are places at end, as for beginCap use just sequence of numbers but with offset.
size_t beg = (pointset_arr.size() - 1) * crossSection.size();
for(size_t i = beg, i_e = (beg + crossSection.size()); i < i_e; i++) ext_alias.CoordIndex.push_back(static_cast<int32_t>(i));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
}// if(beginCap)
// add quads
for(size_t spi = 0, spi_e = (spine.size() - 1); spi <= spi_e; spi++)
{
const size_t cr_sz = crossSection.size();
const size_t cr_last = crossSection.size() - 1;
size_t right_col;// hold index basis for points of quad placed in right column;
if(spi != spi_e)
right_col = spi + 1;
else if(spine_closed)// if spine curve is closed then one more quad is needed: between first and last points of curve.
right_col = 0;
else
break;// if spine curve is not closed then break the loop, because spi is out of range for that type of spine.
for(size_t cri = 0; cri < cr_sz; cri++)
{
if(cri != cr_last)
{
MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex,
static_cast<int32_t>(spi * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri + 1),
static_cast<int32_t>(spi * cr_sz + cri + 1));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
}
else if(cross_closed)// if cross curve is closed then one more quad is needed: between first and last points of curve.
{
MACRO_FACE_ADD_QUAD(ccw, ext_alias.CoordIndex,
static_cast<int32_t>(spi * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + cri),
static_cast<int32_t>(right_col * cr_sz + 0),
static_cast<int32_t>(spi * cr_sz + 0));
// add delimiter
ext_alias.CoordIndex.push_back(-1);
}
}// for(size_t cri = 0; cri < cr_sz; cri++)
}// for(size_t spi = 0, spi_e = (spine.size() - 2); spi < spi_e; spi++)
}// END: 3. Create CoordIdx.
{// 4. Create vertices list.
// just copy all vertices
for(size_t spi = 0, spi_e = spine.size(); spi < spi_e; spi++)
{
for(size_t cri = 0, cri_e = crossSection.size(); cri < cri_e; cri++)
{
ext_alias.Vertices.push_back(pointset_arr[spi][cri]);
}
}
}// END: 4. Create vertices list.
//PrintVectorSet("Ext. CoordIdx", ext_alias.CoordIndex);
//PrintVectorSet("Ext. Vertices", ext_alias.Vertices);
// check for child nodes
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Extrusion");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <IndexedFaceSet
// DEF="" ID
// USE="" IDREF
// ccw="true" SFBool [initializeOnly]
// colorIndex="" MFInt32 [initializeOnly]
// colorPerVertex="true" SFBool [initializeOnly]
// convex="true" SFBool [initializeOnly]
// coordIndex="" MFInt32 [initializeOnly]
// creaseAngle="0" SFFloat [initializeOnly]
// normalIndex="" MFInt32 [initializeOnly]
// normalPerVertex="true" SFBool [initializeOnly]
// solid="true" SFBool [initializeOnly]
// texCoordIndex="" MFInt32 [initializeOnly]
// >
// <!-- ComposedGeometryContentModel -->
// ComposedGeometryContentModel is the child-node content model corresponding to X3DComposedGeometryNodes. It can contain Color (or ColorRGBA), Coordinate,
// Normal and TextureCoordinate, in any order. No more than one instance of these nodes is allowed. Multiple VertexAttribute (FloatVertexAttribute,
// Matrix3VertexAttribute, Matrix4VertexAttribute) nodes can also be contained.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </IndexedFaceSet>
void X3DImporter::ParseNode_Geometry3D_IndexedFaceSet()
{
std::string use, def;
bool ccw = true;
std::vector<int32_t> colorIndex;
bool colorPerVertex = true;
bool convex = true;
std::vector<int32_t> coordIndex;
float creaseAngle = 0;
std::vector<int32_t> normalIndex;
bool normalPerVertex = true;
bool solid = true;
std::vector<int32_t> texCoordIndex;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsArrI32);
MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsArrI32);
MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsArrI32);
MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsArrI32);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_IndexedFaceSet, ne);
}
else
{
// check data
if(coordIndex.size() == 0) throw DeadlyImportError("IndexedFaceSet must contain not empty \"coordIndex\" attribute.");
// create and if needed - define new geometry object.
ne = new X3DIndexedSet(X3DNodeElementBase::ENET_IndexedFaceSet, mNodeElementCur);
if(!def.empty()) ne->ID = def;
X3DIndexedSet& ne_alias = *((X3DIndexedSet*)ne);
ne_alias.CCW = ccw;
ne_alias.ColorIndex = colorIndex;
ne_alias.ColorPerVertex = colorPerVertex;
ne_alias.Convex = convex;
ne_alias.CoordIndex = coordIndex;
ne_alias.CreaseAngle = creaseAngle;
ne_alias.NormalIndex = normalIndex;
ne_alias.NormalPerVertex = normalPerVertex;
ne_alias.Solid = solid;
ne_alias.TexCoordIndex = texCoordIndex;
// check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("IndexedFaceSet");
// check for X3DComposedGeometryNodes
if(XML_CheckNode_NameEqual("Color")) { ParseNode_Rendering_Color(); continue; }
if(XML_CheckNode_NameEqual("ColorRGBA")) { ParseNode_Rendering_ColorRGBA(); continue; }
if(XML_CheckNode_NameEqual("Coordinate")) { ParseNode_Rendering_Coordinate(); continue; }
if(XML_CheckNode_NameEqual("Normal")) { ParseNode_Rendering_Normal(); continue; }
if(XML_CheckNode_NameEqual("TextureCoordinate")) { ParseNode_Texturing_TextureCoordinate(); continue; }
// check for X3DMetadataObject
if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("IndexedFaceSet");
MACRO_NODECHECK_LOOPEND("IndexedFaceSet");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
}
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Sphere
// DEF="" ID
// USE="" IDREF
// radius="1" SFloat [initializeOnly]
// solid="true" SFBool [initializeOnly]
// />
void X3DImporter::ParseNode_Geometry3D_Sphere()
{
std::string use, def;
ai_real radius = 1;
bool solid = true;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Sphere, ne);
}
else
{
const unsigned int tess = 3;///TODO: IME tessellation factor through ai_property
std::vector<aiVector3D> tlist;
// create and if needed - define new geometry object.
ne = new X3DGeometry3D(X3DNodeElementBase::ENET_Sphere, mNodeElementCur);
if(!def.empty()) ne->ID = def;
StandardShapes::MakeSphere(tess, tlist);
// copy data from temp array and apply scale
for(std::vector<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it)
{
((X3DGeometry3D*)ne)->Vertices.push_back(*it * radius);
}
((X3DGeometry3D*)ne)->Solid = solid;
((X3DGeometry3D*)ne)->NumIndices = 3;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Sphere");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,393 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Group.cpp
/// \brief Parsing data from nodes of "Grouping" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include <assimp/ParsingUtils.h>
namespace Assimp
{
// <Group
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Group>
// A Group node contains children nodes without introducing a new transformation. It is equivalent to a Transform node containing an identity transform.
void X3DImporter::ParseNode_Grouping_Group(XmlNode &node) {
//std::string def, use;
std::string def = node.attribute("DEF").as_string();
std::string use = node.attribute("USE").as_string();
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_LOOPEND;*/
// if "USE" defined then find already defined element.
if(!use.empty())
{
X3DNodeElementBase *ne = nullptr;
if (def.empty()) {
Throw_DEF_And_USE(node.name());
}
if (!FindNodeElement(use, X3DNodeElementBase::ENET_Group, &ne)) {
Throw_USE_NotFound(node.name(), use);
}
mNodeElementCur->Child.push_back(ne);
//MACRO_USE_CHECKANDAPPLY(def, use, X3DNodeElementBase::ENET_Group, ne);
} else {
ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if (!def.empty()) {
mNodeElementCur->ID = def;
}
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
//if(mReader->isEmptyElement())
if (node.empty()) {
ParseHelper_Node_Exit();
}
}// if(!use.empty()) else
}
void X3DImporter::ParseNode_Grouping_GroupEnd()
{
ParseHelper_Node_Exit();// go up in scene graph
}
// <StaticGroup
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </StaticGroup>
// The StaticGroup node contains children nodes which cannot be modified. StaticGroup children are guaranteed to not change, send events, receive events or
// contain any USE references outside the StaticGroup.
void X3DImporter::ParseNode_Grouping_StaticGroup(XmlNode &node) {
// std::string def, use;
std::string def = node.attribute("DEF").as_string();
std::string use = node.attribute("USE").as_string();
/* MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_LOOPEND;*/
// if "USE" defined then find already defined element.
if(!use.empty())
{
X3DNodeElementBase* ne = nullptr;
if (!FindNodeElement(use, X3DNodeElementBase::ENET_Group, &ne)) {
Throw_USE_NotFound(node.name(), use);
}
mNodeElementCur->Child.push_back(ne);
// MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
}
else
{
ParseHelper_Group_Begin(true);// create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if(!def.empty()) mNodeElementCur->ID = def;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if (node.empty()) {
ParseHelper_Node_Exit();
}
// if(mReader->isEmptyElement()) ParseHelper_Node_Exit();
}// if(!use.empty()) else
}
void X3DImporter::ParseNode_Grouping_StaticGroupEnd()
{
ParseHelper_Node_Exit();// go up in scene graph
}
// <Switch
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// whichChoice="-1" SFInt32 [inputOutput]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Switch>
// The Switch grouping node traverses zero or one of the nodes specified in the children field. The whichChoice field specifies the index of the child
// to traverse, with the first child having index 0. If whichChoice is less than zero or greater than the number of nodes in the children field, nothing
// is chosen.
void X3DImporter::ParseNode_Grouping_Switch(XmlNode &node) {
// std::string def, use;
int32_t whichChoice = -1;
std::string def = node.attribute("DEF").as_string();
std::string use = node.attribute("USE").as_string();
pugi::xml_attribute attr = node.attribute("whichChoise");
whichChoice = attr.as_int();
/*MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("whichChoice", whichChoice, XML_ReadNode_GetAttrVal_AsI32);
MACRO_ATTRREAD_LOOPEND;*/
// if "USE" defined then find already defined element.
if(!use.empty())
{
X3DNodeElementBase* ne = nullptr;
if (!FindNodeElement(use, X3DNodeElementBase::ENET_Group, &ne)) {
Throw_USE_NotFound(node.name(), use);
}
mNodeElementCur->Child.push_back(ne);
// MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
}
else
{
ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if(!def.empty()) mNodeElementCur->ID = def;
// also set values specific to this type of group
((X3DGroup*)mNodeElementCur)->UseChoice = true;
((X3DGroup*)mNodeElementCur)->Choice = whichChoice;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
// if(mReader->isEmptyElement()) ParseHelper_Node_Exit();
if (node.empty()) {
ParseHelper_Node_Exit();
}
}// if(!use.empty()) else
}
void X3DImporter::ParseNode_Grouping_SwitchEnd()
{
// just exit from node. Defined choice will be accepted at post-processing stage.
ParseHelper_Node_Exit();// go up in scene graph
}
void ReadAttrAsVec3f(pugi::xml_node &node, const std::string &attrName, aiVector3D &vec) {
const pugi::xml_attribute &attr = node.attribute(attrName.c_str());
if (attr.empty()) {
return;
}
std::string data = attr.as_string();
std::vector<std::string> token;
tokenize<std::string>(data, token, " ");
vec.x = (ai_real)std::atof(token[0].c_str());
vec.y = (ai_real)std::atof(token[1].c_str());
vec.z = (ai_real)std::atof(token[2].c_str());
}
void ReadAttrAsFloatArray(pugi::xml_node &node, const std::string &attrName, size_t numComponents, std::vector<float> &tvec) {
pugi::xml_attribute attr = node.attribute(attrName.c_str());
std::string data = attr.as_string();
std::vector<std::string> token;
tokenize<std::string>(data, token, " ");
if (token.size() != numComponents) throw DeadlyImportError("<Transform>: rotation vector must have 4 elements.");
for (size_t i = 0; i < numComponents; ++i) {
tvec.push_back((ai_real)std::atof(token[i].c_str()));
}
}
// <Transform
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// center="0 0 0" SFVec3f [inputOutput]
// rotation="0 0 1 0" SFRotation [inputOutput]
// scale="1 1 1" SFVec3f [inputOutput]
// scaleOrientation="0 0 1 0" SFRotation [inputOutput]
// translation="0 0 0" SFVec3f [inputOutput]
// >
// <!-- ChildContentModel -->
// ChildContentModel is the child-node content model corresponding to X3DChildNode, combining all profiles. ChildContentModel can contain most nodes,
// other Grouping nodes, Prototype declarations and ProtoInstances in any order and any combination. When the assigned profile is less than Full, the
// precise palette of legal nodes that are available depends on assigned profile and components.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model.
// </Transform>
// The Transform node is a grouping node that defines a coordinate system for its children that is relative to the coordinate systems of its ancestors.
// Given a 3-dimensional point P and Transform node, P is transformed into point P' in its parent's coordinate system by a series of intermediate
// transformations. In matrix transformation notation, where C (center), SR (scaleOrientation), T (translation), R (rotation), and S (scale) are the
// equivalent transformation matrices,
// P' = T * C * R * SR * S * -SR * -C * P
void X3DImporter::ParseNode_Grouping_Transform(XmlNode &node) {
aiVector3D center(0, 0, 0);
float rotation[4] = { 0, 0, 1, 0 };
aiVector3D scale(1, 1, 1); // A value of zero indicates that any child geometry shall not be displayed
float scale_orientation[4] = { 0, 0, 1, 0 };
aiVector3D translation(0, 0, 0);
aiMatrix4x4 matr, tmatr;
//std::string use, def;
//MACRO_ATTRREAD_LOOPBEG;
std::string def = node.attribute("DEF").as_string();
std::string use = node.attribute("USE").as_string();
//MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
ReadAttrAsVec3f(node, "center", center);
ReadAttrAsVec3f(node, "scale", scale);
ReadAttrAsVec3f(node, "translation", translation);
/*MACRO_ATTRREAD_CHECK_REF("center", center, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_REF("translation", translation, XML_ReadNode_GetAttrVal_AsVec3f);*/
if (hasAttribute(node, "rotation")) {
std::vector<float> tvec;
ReadAttrAsFloatArray(node, "rotation", 4, tvec);
memcpy(rotation, tvec.data(), sizeof(rotation));
}
if (hasAttribute(node, "scaleOrientation")) {
std::vector<float> tvec;
ReadAttrAsFloatArray(node, "rotation", 4, tvec);
::memcpy(scale_orientation, tvec.data(), sizeof(scale_orientation));
}
/*if(an == "rotation")
{
std::vector<float> tvec;
XML_ReadNode_GetAttrVal_AsArrF(idx, tvec);
if(tvec.size() != 4) throw DeadlyImportError("<Transform>: rotation vector must have 4 elements.");
memcpy(rotation, tvec.data(), sizeof(rotation));
continue;
}
if(an == "scaleOrientation"){
std::vector<float> tvec;
XML_ReadNode_GetAttrVal_AsArrF(idx, tvec);
if ( tvec.size() != 4 )
{
throw DeadlyImportError( "<Transform>: scaleOrientation vector must have 4 elements." );
}
::memcpy(scale_orientation, tvec.data(), sizeof(scale_orientation) );
continue;
}
MACRO_ATTRREAD_LOOPEND;*/
// if "USE" defined then find already defined element.
if(!use.empty()) {
X3DNodeElementBase* ne = nullptr;
if (!FindNodeElement(use, X3DNodeElementBase::ENET_Group, &ne)) {
Throw_USE_NotFound(node.name(), use);
}
mNodeElementCur->Child.push_back(ne);
//MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
}
else
{
ParseHelper_Group_Begin();// create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if ( !def.empty() )
{
mNodeElementCur->ID = def;
}
//
// also set values specific to this type of group
//
// calculate transformation matrix
aiMatrix4x4::Translation(translation, matr);// T
aiMatrix4x4::Translation(center, tmatr);// C
matr *= tmatr;
aiMatrix4x4::Rotation(rotation[3], aiVector3D(rotation[0], rotation[1], rotation[2]), tmatr);// R
matr *= tmatr;
aiMatrix4x4::Rotation(scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr);// SR
matr *= tmatr;
aiMatrix4x4::Scaling(scale, tmatr);// S
matr *= tmatr;
aiMatrix4x4::Rotation(-scale_orientation[3], aiVector3D(scale_orientation[0], scale_orientation[1], scale_orientation[2]), tmatr);// -SR
matr *= tmatr;
aiMatrix4x4::Translation(-center, tmatr);// -C
matr *= tmatr;
// and assign it
((X3DGroup*)mNodeElementCur)->Transformation = matr;
// in grouping set of nodes check X3DMetadataObject is not needed, because it is done in <Scene> parser function.
// for empty element exit from node in that place
if ( node.empty() ) {
ParseHelper_Node_Exit();
}
}// if(!use.empty()) else
}
void X3DImporter::ParseNode_Grouping_TransformEnd()
{
ParseHelper_Node_Exit();// go up in scene graph
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,290 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Light.cpp
/// \brief Parsing data from nodes of "Lighting" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
#include <assimp/StringUtils.h>
namespace Assimp {
// <DirectionalLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// direction="0 0 -1" SFVec3f [inputOutput]
// global="false" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// on="true" SFBool [inputOutput]
// />
void X3DImporter::ParseNode_Lighting_DirectionalLight()
{
std::string def, use;
float ambientIntensity = 0;
aiColor3D color(1, 1, 1);
aiVector3D direction(0, 0, -1);
bool global = false;
float intensity = 1;
bool on = true;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_CHECK_REF("direction", direction, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_DirectionalLight, ne);
}
else
{
if(on)
{
// create and if needed - define new geometry object.
ne = new X3DLight(X3DNodeElementBase::ENET_DirectionalLight, mNodeElementCur);
if(!def.empty())
ne->ID = def;
else
ne->ID = "DirectionalLight_" + to_string((size_t)ne);// make random name
((X3DLight*)ne)->AmbientIntensity = ambientIntensity;
((X3DLight*)ne)->Color = color;
((X3DLight*)ne)->Direction = direction;
((X3DLight*)ne)->Global = global;
((X3DLight*)ne)->Intensity = intensity;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
mNodeElementCur->ID = ne->ID;// assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "DirectionalLight");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(on)
}// if(!use.empty()) else
}
// <PointLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// attenuation="1 0 0" SFVec3f [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// global="true" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// location="0 0 0" SFVec3f [inputOutput]
// on="true" SFBool [inputOutput]
// radius="100" SFFloat [inputOutput]
// />
void X3DImporter::ParseNode_Lighting_PointLight()
{
std::string def, use;
float ambientIntensity = 0;
aiVector3D attenuation( 1, 0, 0 );
aiColor3D color( 1, 1, 1 );
bool global = true;
float intensity = 1;
aiVector3D location( 0, 0, 0 );
bool on = true;
float radius = 100;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("attenuation", attenuation, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("location", location, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_PointLight, ne);
}
else
{
if(on)
{
// create and if needed - define new geometry object.
ne = new X3DLight(X3DNodeElementBase::ENET_PointLight, mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DLight*)ne)->AmbientIntensity = ambientIntensity;
((X3DLight*)ne)->Attenuation = attenuation;
((X3DLight*)ne)->Color = color;
((X3DLight*)ne)->Global = global;
((X3DLight*)ne)->Intensity = intensity;
((X3DLight*)ne)->Location = location;
((X3DLight*)ne)->Radius = radius;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
// make random name
if(ne->ID.empty()) ne->ID = "PointLight_" + to_string((size_t)ne);
mNodeElementCur->ID = ne->ID;// assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "PointLight");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(on)
}// if(!use.empty()) else
}
// <SpotLight
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0" SFFloat [inputOutput]
// attenuation="1 0 0" SFVec3f [inputOutput]
// beamWidth="0.7854" SFFloat [inputOutput]
// color="1 1 1" SFColor [inputOutput]
// cutOffAngle="1.570796" SFFloat [inputOutput]
// direction="0 0 -1" SFVec3f [inputOutput]
// global="true" SFBool [inputOutput]
// intensity="1" SFFloat [inputOutput]
// location="0 0 0" SFVec3f [inputOutput]
// on="true" SFBool [inputOutput]
// radius="100" SFFloat [inputOutput]
// />
void X3DImporter::ParseNode_Lighting_SpotLight()
{
std::string def, use;
float ambientIntensity = 0;
aiVector3D attenuation( 1, 0, 0 );
float beamWidth = 0.7854f;
aiColor3D color( 1, 1, 1 );
float cutOffAngle = 1.570796f;
aiVector3D direction( 0, 0, -1 );
bool global = true;
float intensity = 1;
aiVector3D location( 0, 0, 0 );
bool on = true;
float radius = 100;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("attenuation", attenuation, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("beamWidth", beamWidth, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("color", color, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_CHECK_RET("cutOffAngle", cutOffAngle, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("direction", direction, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("global", global, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("intensity", intensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("location", location, XML_ReadNode_GetAttrVal_AsVec3f);
MACRO_ATTRREAD_CHECK_RET("on", on, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("radius", radius, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_SpotLight, ne);
}
else
{
if(on)
{
// create and if needed - define new geometry object.
ne = new X3DLight(X3DNodeElementBase::ENET_SpotLight, mNodeElementCur);
if(!def.empty()) ne->ID = def;
if(beamWidth > cutOffAngle) beamWidth = cutOffAngle;
((X3DLight*)ne)->AmbientIntensity = ambientIntensity;
((X3DLight*)ne)->Attenuation = attenuation;
((X3DLight*)ne)->BeamWidth = beamWidth;
((X3DLight*)ne)->Color = color;
((X3DLight*)ne)->CutOffAngle = cutOffAngle;
((X3DLight*)ne)->Direction = direction;
((X3DLight*)ne)->Global = global;
((X3DLight*)ne)->Intensity = intensity;
((X3DLight*)ne)->Location = location;
((X3DLight*)ne)->Radius = radius;
// Assimp want a node with name similar to a light. "Why? I don't no." )
ParseHelper_Group_Begin(false);
// make random name
if(ne->ID.empty()) ne->ID = "SpotLight_" + to_string((size_t)ne);
mNodeElementCur->ID = ne->ID;// assign name to node and return to light element.
ParseHelper_Node_Exit();
// check for child nodes
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "SpotLight");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(on)
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,195 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Macro.hpp
/// \brief Useful macrodefines.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef X3DIMPORTER_MACRO_HPP_INCLUDED
#define X3DIMPORTER_MACRO_HPP_INCLUDED
/// \def MACRO_USE_CHECKANDAPPLY(pDEF, pUSE, pNE)
/// Used for regular checking while attribute "USE" is defined.
/// \param [in] pDEF - string holding "DEF" value.
/// \param [in] pUSE - string holding "USE" value.
/// \param [in] pType - type of element to find.
/// \param [out] pNE - pointer to found node element.
#define MACRO_USE_CHECKANDAPPLY(pDEF, pUSE, pType, pNE) \
do { \
XML_CheckNode_MustBeEmpty(); \
if(!pDEF.empty()) Throw_DEF_And_USE(); \
if(!FindNodeElement(pUSE, CX3DImporter_NodeElement::pType, &pNE)) Throw_USE_NotFound(pUSE); \
\
NodeElement_Cur->Child.push_back(pNE);/* add found object as child to current element */ \
} while(false)
/// \def MACRO_ATTRREAD_LOOPBEG
/// Begin of loop that read attributes values.
#define MACRO_ATTRREAD_LOOPBEG \
for(int idx = 0, idx_end = mReader->getAttributeCount(); idx < idx_end; idx++) \
{ \
std::string an(mReader->getAttributeName(idx));
/// \def MACRO_ATTRREAD_LOOPEND
/// End of loop that read attributes values.
#define MACRO_ATTRREAD_LOOPEND \
Throw_IncorrectAttr(an); \
}
/// \def MACRO_ATTRREAD_CHECK_REF
/// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
/// "continue" will called.
/// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name.
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
#define MACRO_ATTRREAD_CHECK_REF(pAttrName, pVarName, pFunction) \
if(an == pAttrName) \
{ \
pFunction(idx, pVarName); \
continue; \
}
/// \def MACRO_ATTRREAD_CHECK_RET
/// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
/// If result was read then "continue" will called.
/// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name.
/// \param [in] pFunction - function which read attribute value and write it to pVarName.
#define MACRO_ATTRREAD_CHECK_RET(pAttrName, pVarName, pFunction) \
if(an == pAttrName) \
{ \
pVarName = pFunction(idx); \
continue; \
}
/// \def MACRO_ATTRREAD_CHECKUSEDEF_RET
/// Compact variant for checking "USE" and "DEF". Also skip bbox attributes: "bboxCenter", "bboxSize".
/// If result was read then "continue" will called.
/// \param [out] pDEF_Var - output variable name for "DEF" value.
/// \param [out] pUSE_Var - output variable name for "USE" value.
#define MACRO_ATTRREAD_CHECKUSEDEF_RET(pDEF_Var, pUSE_Var) \
MACRO_ATTRREAD_CHECK_RET("DEF", pDEF_Var, mReader->getAttributeValue); \
MACRO_ATTRREAD_CHECK_RET("USE", pUSE_Var, mReader->getAttributeValue); \
if(an == "bboxCenter") continue; \
if(an == "bboxSize") continue; \
if(an == "containerField") continue; \
do {} while(false)
/// \def MACRO_NODECHECK_LOOPBEGIN(pNodeName)
/// Begin of loop of parsing child nodes. Do not add ';' at end.
/// \param [in] pNodeName - current node name.
#define MACRO_NODECHECK_LOOPBEGIN(pNodeName) \
do { \
bool close_found = false; \
\
while(mReader->read()) \
{ \
if(mReader->getNodeType() == irr::io::EXN_ELEMENT) \
{
/// \def MACRO_NODECHECK_LOOPEND(pNodeName)
/// End of loop of parsing child nodes.
/// \param [in] pNodeName - current node name.
#define MACRO_NODECHECK_LOOPEND(pNodeName) \
}/* if(mReader->getNodeType() == irr::io::EXN_ELEMENT) */ \
else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) \
{ \
if(XML_CheckNode_NameEqual(pNodeName)) \
{ \
close_found = true; \
\
break; \
} \
}/* else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END) */ \
}/* while(mReader->read()) */ \
\
if(!close_found) Throw_CloseNotFound(pNodeName); \
\
} while(false)
#define MACRO_NODECHECK_METADATA(pNodeName) \
MACRO_NODECHECK_LOOPBEGIN(pNodeName) \
/* and childs must be metadata nodes */ \
if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported(pNodeName); \
MACRO_NODECHECK_LOOPEND(pNodeName)
/// \def MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4)
/// Add points as quad. Means that pP1..pP4 set in CCW order.
#define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \
do { \
if(pCCW) \
{ \
pOut.push_back(pIn[pP1]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP4]); \
} \
else \
{ \
pOut.push_back(pIn[pP4]); \
pOut.push_back(pIn[pP3]); \
pOut.push_back(pIn[pP2]); \
pOut.push_back(pIn[pP1]); \
} \
} while(false)
/// \def MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4)
/// Add points as quad. Means that pP1..pP4 set in CCW order.
#define MACRO_FACE_ADD_QUAD(pCCW, pOut, pP1, pP2, pP3, pP4) \
do { \
if(pCCW) \
{ \
pOut.push_back(pP1); \
pOut.push_back(pP2); \
pOut.push_back(pP3); \
pOut.push_back(pP4); \
} \
else \
{ \
pOut.push_back(pP4); \
pOut.push_back(pP3); \
pOut.push_back(pP2); \
pOut.push_back(pP1); \
} \
} while(false)
#endif // X3DIMPORTER_MACRO_HPP_INCLUDED

View File

@ -1,277 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Metadata.cpp
/// \brief Parsing data from nodes of "Metadata" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
namespace Assimp
{
/// \def MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaName)
/// Find element by "USE" or create new one.
/// \param [in] pDEF_Var - variable name with "DEF" value.
/// \param [in] pUSE_Var - variable name with "USE" value.
/// \param [in] pReference - variable name with "reference" value.
/// \param [in] pValue - variable name with "value" value.
/// \param [in, out] pNE - pointer to node element.
/// \param [in] pMetaClass - Class of node.
/// \param [in] pMetaName - Name of node.
/// \param [in] pType - type of element to find.
#define MACRO_METADATA_FINDCREATE(pDEF_Var, pUSE_Var, pReference, pValue, pNE, pMetaClass, pMetaName, pType) \
/* if "USE" defined then find already defined element. */ \
if(!pUSE_Var.empty()) \
{ \
MACRO_USE_CHECKANDAPPLY(pDEF_Var, pUSE_Var, pType, pNE); \
} \
else \
{ \
pNE = new pMetaClass(NodeElement_Cur); \
if(!pDEF_Var.empty()) pNE->ID = pDEF_Var; \
\
((pMetaClass*)pNE)->Reference = pReference; \
((pMetaClass*)pNE)->Value = pValue; \
/* also metadata node can contain childs */ \
if(!mReader->isEmptyElement()) \
ParseNode_Metadata(pNE, pMetaName);/* in that case node element will be added to child elements list of current node. */ \
else \
NodeElement_Cur->Child.push_back(pNE);/* else - add element to child list manually */ \
\
NodeElement_List.push_back(pNE);/* add new element to elements list. */ \
}/* if(!pUSE_Var.empty()) else */ \
\
do {} while(false)
bool X3DImporter::ParseHelper_CheckRead_X3DMetadataObject()
{
if(XML_CheckNode_NameEqual("MetadataBoolean"))
ParseNode_MetadataBoolean();
else if(XML_CheckNode_NameEqual("MetadataDouble"))
ParseNode_MetadataDouble();
else if(XML_CheckNode_NameEqual("MetadataFloat"))
ParseNode_MetadataFloat();
else if(XML_CheckNode_NameEqual("MetadataInteger"))
ParseNode_MetadataInteger();
else if(XML_CheckNode_NameEqual("MetadataSet"))
ParseNode_MetadataSet();
else if(XML_CheckNode_NameEqual("MetadataString"))
ParseNode_MetadataString();
else
return false;
return true;
}
void X3DImporter::ParseNode_Metadata(X3DNodeElementBase* pParentElement, const std::string& /*pNodeName*/)
{
ParseHelper_Node_Enter(pParentElement);
MACRO_NODECHECK_METADATA(mReader->getNodeName());
ParseHelper_Node_Exit();
}
// <MetadataBoolean
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFBool [inputOutput]
// />
void X3DImporter::ParseNode_MetadataBoolean()
{
std::string def, use;
std::string name, reference;
std::vector<bool> value;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrB);
MACRO_ATTRREAD_LOOPEND;
MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, X3DMetaBoolean, "MetadataBoolean", ENET_MetaBoolean);
}
// <MetadataDouble
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFDouble [inputOutput]
// />
void X3DImporter::ParseNode_MetadataDouble()
{
std::string def, use;
std::string name, reference;
std::vector<double> value;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrD);
MACRO_ATTRREAD_LOOPEND;
MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, X3DMetaDouble, "MetadataDouble", ENET_MetaDouble);
}
// <MetadataFloat
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFFloat [inputOutput]
// />
void X3DImporter::ParseNode_MetadataFloat()
{
std::string def, use;
std::string name, reference;
std::vector<float> value;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrF);
MACRO_ATTRREAD_LOOPEND;
MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, X3DMetaFloat, "MetadataFloat", ENET_MetaFloat);
}
// <MetadataInteger
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFInteger [inputOutput]
// />
void X3DImporter::ParseNode_MetadataInteger()
{
std::string def, use;
std::string name, reference;
std::vector<int32_t> value;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrI32);
MACRO_ATTRREAD_LOOPEND;
MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, X3DMetaInteger, "MetadataInteger", ENET_MetaInteger);
}
// <MetadataSet
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// />
void X3DImporter::ParseNode_MetadataSet()
{
std::string def, use;
std::string name, reference;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_MetaSet, ne);
}
else
{
ne = new X3DMetaSet(mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DMetaSet*)ne)->Reference = reference;
// also metadata node can contain childs
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "MetadataSet");
else
mNodeElementCur->Child.push_back(ne);// made object as child to current element
NodeElement_List.push_back(ne);// add new element to elements list.
}// if(!use.empty()) else
}
// <MetadataString
// DEF="" ID
// USE="" IDREF
// name="" SFString [inputOutput]
// reference="" SFString [inputOutput]
// value="" MFString [inputOutput]
// />
void X3DImporter::ParseNode_MetadataString()
{
std::string def, use;
std::string name, reference;
std::list<std::string> value;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue);
MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListS);
MACRO_ATTRREAD_LOOPEND;
MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, X3DMetaString, "MetadataString", ENET_MetaString);
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,134 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Networking.cpp
/// \brief Parsing data from nodes of "Networking" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
// Header files, Assimp.
#include <assimp/DefaultIOSystem.h>
//#include <regex>
namespace Assimp
{
//static std::regex pattern_parentDir(R"((^|/)[^/]+/../)");
static std::string parentDir("/../");
// <Inline
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// load="true" SFBool [inputOutput]
// url="" MFString [inputOutput]
// />
void X3DImporter::ParseNode_Networking_Inline()
{
std::string def, use;
bool load = true;
std::list<std::string> url;
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("load", load, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("url", url, XML_ReadNode_GetAttrVal_AsListS);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
X3DNodeElementBase* ne;
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Group, ne);
}
else
{
ParseHelper_Group_Begin(true);// create new grouping element and go deeper if node has children.
// at this place new group mode created and made current, so we can name it.
if(!def.empty()) mNodeElementCur->ID = def;
if(load && !url.empty())
{
std::string full_path = mpIOHandler->CurrentDirectory() + url.front();
//full_path = std::regex_replace(full_path, pattern_parentDir, "$1");
for (std::string::size_type pos = full_path.find(parentDir); pos != std::string::npos; pos = full_path.find(parentDir, pos)) {
if (pos > 0) {
std::string::size_type pos2 = full_path.rfind('/', pos - 1);
if (pos2 != std::string::npos) {
full_path.erase(pos2, pos - pos2 + 3);
pos = pos2;
}
else {
full_path.erase(0, pos + 4);
pos = 0;
}
}
else {
pos += 3;
}
}
// Attribute "url" can contain list of strings. But we need only one - first.
std::string::size_type slashPos = full_path.find_last_of("\\/");
mpIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : full_path.substr(0, slashPos + 1));
ParseFile(full_path, mpIOHandler);
mpIOHandler->PopDirectory();
}
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement()) ParseNode_Metadata(mNodeElementCur, "Inline");
// exit from node in that place
ParseHelper_Node_Exit();
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,507 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Node.hpp
/// \brief Elements of scene graph.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef INCLUDED_AI_X3D_IMPORTER_NODE_H
#define INCLUDED_AI_X3D_IMPORTER_NODE_H
// Header files, Assimp.
#include <assimp/scene.h>
#include <assimp/types.h>
// Header files, stdlib.
#include <list>
#include <string>
#include <vector>
/// Base class for elements of nodes.
class X3DNodeElementBase {
public:
/// Define what data type contain node element.
enum EType {
ENET_Group, ///< Element has type "Group".
ENET_MetaBoolean, ///< Element has type "Metadata boolean".
ENET_MetaDouble, ///< Element has type "Metadata double".
ENET_MetaFloat, ///< Element has type "Metadata float".
ENET_MetaInteger, ///< Element has type "Metadata integer".
ENET_MetaSet, ///< Element has type "Metadata set".
ENET_MetaString, ///< Element has type "Metadata string".
ENET_Arc2D, ///< Element has type "Arc2D".
ENET_ArcClose2D, ///< Element has type "ArcClose2D".
ENET_Circle2D, ///< Element has type "Circle2D".
ENET_Disk2D, ///< Element has type "Disk2D".
ENET_Polyline2D, ///< Element has type "Polyline2D".
ENET_Polypoint2D, ///< Element has type "Polypoint2D".
ENET_Rectangle2D, ///< Element has type "Rectangle2D".
ENET_TriangleSet2D, ///< Element has type "TriangleSet2D".
ENET_Box, ///< Element has type "Box".
ENET_Cone, ///< Element has type "Cone".
ENET_Cylinder, ///< Element has type "Cylinder".
ENET_Sphere, ///< Element has type "Sphere".
ENET_ElevationGrid, ///< Element has type "ElevationGrid".
ENET_Extrusion, ///< Element has type "Extrusion".
ENET_Coordinate, ///< Element has type "Coordinate".
ENET_Normal, ///< Element has type "Normal".
ENET_TextureCoordinate, ///< Element has type "TextureCoordinate".
ENET_IndexedFaceSet, ///< Element has type "IndexedFaceSet".
ENET_IndexedLineSet, ///< Element has type "IndexedLineSet".
ENET_IndexedTriangleSet, ///< Element has type "IndexedTriangleSet".
ENET_IndexedTriangleFanSet, ///< Element has type "IndexedTriangleFanSet".
ENET_IndexedTriangleStripSet, ///< Element has type "IndexedTriangleStripSet".
ENET_LineSet, ///< Element has type "LineSet".
ENET_PointSet, ///< Element has type "PointSet".
ENET_TriangleSet, ///< Element has type "TriangleSet".
ENET_TriangleFanSet, ///< Element has type "TriangleFanSet".
ENET_TriangleStripSet, ///< Element has type "TriangleStripSet".
ENET_Color, ///< Element has type "Color".
ENET_ColorRGBA, ///< Element has type "ColorRGBA".
ENET_Shape, ///< Element has type "Shape".
ENET_Appearance, ///< Element has type "Appearance".
ENET_Material, ///< Element has type "Material".
ENET_ImageTexture, ///< Element has type "ImageTexture".
ENET_TextureTransform, ///< Element has type "TextureTransform".
ENET_DirectionalLight, ///< Element has type "DirectionalLight".
ENET_PointLight, ///< Element has type "PointLight".
ENET_SpotLight, ///< Element has type "SpotLight".
ENET_Invalid ///< Element has invalid type and possible contain invalid data.
};
const EType Type;
std::string ID; ///< ID of the element. Can be empty. In X3D synonym for "ID" attribute.
X3DNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
std::list<X3DNodeElementBase *> Child; ///< Child elements.
/// @brief The destructor, virtual.
virtual ~X3DNodeElementBase() {
// empty
}
protected:
/// In constructor inheritor must set element type.
/// \param [in] pType - element type.
/// \param [in] pParent - parent element.
X3DNodeElementBase(const EType pType, X3DNodeElementBase *pParent) :
Type(pType), Parent(pParent) {}
X3DNodeElementBase(const X3DNodeElementBase &pNodeElement) = delete;
X3DNodeElementBase &operator=(const X3DNodeElementBase &pNodeElement) = delete;
X3DNodeElementBase() = delete;
}; // class IX3DImporter_NodeElement
/// \class CX3DImporter_NodeElement_Group
/// Class that define grouping node. Define transformation matrix for children.
/// Also can select which child will be kept and others are removed.
class X3DGroup : public X3DNodeElementBase {
public:
aiMatrix4x4 Transformation; ///< Transformation matrix.
/// \var bool Static
/// As you know node elements can use already defined node elements when attribute "USE" is defined.
/// Standard search when looking for an element in the whole scene graph, existing at this moment.
/// If a node is marked as static, the children(or lower) can not search for elements in the nodes upper then static.
bool Static;
bool UseChoice; ///< Flag: if true then use number from \ref Choice to choose what the child will be kept.
int32_t Choice; ///< Number of the child which will be kept.
public:
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pStatic - static node flag.
X3DGroup(X3DNodeElementBase *pParent, const bool pStatic = false) :
X3DNodeElementBase(ENET_Group, pParent),
Static(pStatic),
UseChoice(false) {
// empty
}
}; // class CX3DImporter_NodeElement_Group
/// This struct describe meta-value.
class X3DMeta : public X3DNodeElementBase {
public:
std::string Name; ///< Name of metadata object.
/// If provided, it identifies the metadata standard or other specification that defines the name field. If the reference field is not provided or is
/// empty, the meaning of the name field is considered implicit to the characters in the string.
std::string Reference;
/// In constructor inheritor must set element type.
/// \param [in] pType - element type.
/// \param [in] pParent - pointer to parent node.
X3DMeta(const EType pType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pType, pParent) {}
}; // class CX3DImporter_NodeElement_Meta
/// \struct CX3DImporter_NodeElement_MetaBoolean
/// This struct describe metavalue of type boolean.
struct X3DMetaBoolean : public X3DMeta {
std::vector<bool> Value; ///< Stored value.
/// \fn CX3DImporter_NodeElement_MetaBoolean(CX3DImporter_NodeElement* pParent)
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaBoolean(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaBoolean, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaBoolean
/// \struct CX3DImporter_NodeElement_MetaDouble
/// This struct describe metavalue of type double.
struct X3DMetaDouble : public X3DMeta {
std::vector<double> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaDouble(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaDouble, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaDouble
/// This struct describe metavalue of type float.
struct X3DMetaFloat : public X3DMeta {
std::vector<float> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaFloat(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaFloat, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaFloat
/// This struct describe metavalue of type integer.
struct X3DMetaInteger : public X3DMeta {
std::vector<int32_t> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaInteger(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaInteger, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaInteger
/// This struct describe container for metaobjects.
struct X3DMetaSet : public X3DMeta {
std::list<X3DMeta> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaSet(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaSet, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaSet
/// This struct describe metavalue of type string.
struct X3DMetaString : public X3DMeta {
std::list<std::string> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DMetaString(X3DNodeElementBase *pParent) :
X3DMeta(ENET_MetaString, pParent) {}
}; // struct CX3DImporter_NodeElement_MetaString
/// This struct hold <Color> value.
struct X3DColor : public X3DNodeElementBase {
std::list<aiColor3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DColor(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Color, pParent) {}
}; // struct CX3DImporter_NodeElement_Color
/// This struct hold <ColorRGBA> value.
struct X3DColorRGBA : public X3DNodeElementBase {
std::list<aiColor4D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DColorRGBA(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_ColorRGBA, pParent) {}
}; // struct CX3DImporter_NodeElement_ColorRGBA
/// This struct hold <Coordinate> value.
struct X3DCoordinate : public X3DNodeElementBase {
std::list<aiVector3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DCoordinate(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Coordinate, pParent) {}
}; // struct CX3DImporter_NodeElement_Coordinate
/// This struct hold <Normal> value.
struct X3DNormal : public X3DNodeElementBase {
std::list<aiVector3D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DNormal(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Normal, pParent) {}
}; // struct CX3DImporter_NodeElement_Normal
/// This struct hold <TextureCoordinate> value.
struct X3DTextureCoordinate : public X3DNodeElementBase {
std::list<aiVector2D> Value; ///< Stored value.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DTextureCoordinate(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_TextureCoordinate, pParent) {}
}; // struct CX3DImporter_NodeElement_TextureCoordinate
/// Two-dimensional figure.
class X3DGeometry2D : public X3DNodeElementBase {
public:
std::list<aiVector3D> Vertices; ///< Vertices list.
size_t NumIndices; ///< Number of indices in one face.
bool Solid; ///< Flag: if true then render must use back-face culling, else render must draw both sides of object.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DGeometry2D(const EType pType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pType, pParent), Solid(true) {}
}; // class CX3DImporter_NodeElement_Geometry2D
/// Three-dimensional body.
class X3DGeometry3D : public X3DNodeElementBase {
public:
std::list<aiVector3D> Vertices; ///< Vertices list.
size_t NumIndices; ///< Number of indices in one face.
bool Solid; ///< Flag: if true then render must use back-face culling, else render must draw both sides of object.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DGeometry3D(const EType pType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pType, pParent), Vertices(), NumIndices(0), Solid(true) {
// empty
}
}; // class CX3DImporter_NodeElement_Geometry3D
/// \class CX3DImporter_NodeElement_ElevationGrid
/// Uniform rectangular grid of varying height.
class X3DElevationGrid : public X3DGeometry3D {
public:
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
float CreaseAngle;
std::vector<int32_t> CoordIdx; ///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DElevationGrid(const EType pType, X3DNodeElementBase *pParent) :
X3DGeometry3D(pType, pParent) {}
}; // class CX3DImporter_NodeElement_IndexedSet
/// Shape with indexed vertices.
class X3DIndexedSet : public X3DGeometry3D {
public:
/// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors
/// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to
/// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the
/// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite
/// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the
/// ccw field, results are undefined.
bool CCW;
std::vector<int32_t> ColorIndex; ///< Field to specify the polygonal faces by indexing into the <Color> or <ColorRGBA>.
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
/// The convex field indicates whether all polygons in the shape are convex (TRUE). A polygon is convex if it is planar, does not intersect itself,
/// and all of the interior angles at its vertices are less than 180 degrees. Non planar and self intersecting polygons may produce undefined results
/// even if the convex field is FALSE.
bool Convex;
std::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
/// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are
/// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced.
float CreaseAngle;
std::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DIndexedSet(const EType pType, X3DNodeElementBase *pParent) :
X3DGeometry3D(pType, pParent) {}
}; // class CX3DImporter_NodeElement_IndexedSet
/// Shape with set of vertices.
class X3DSet : public X3DGeometry3D {
public:
/// The ccw field defines the ordering of the vertex coordinates of the geometry with respect to user-given or automatically generated normal vectors
/// used in the lighting model equations. If ccw is TRUE, the normals shall follow the right hand rule; the orientation of each normal with respect to
/// the vertices (taken in order) shall be such that the vertices appear to be oriented in a counterclockwise order when the vertices are viewed (in the
/// local coordinate system of the Shape) from the opposite direction as the normal. If ccw is FALSE, the normals shall be oriented in the opposite
/// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the
/// ccw field, results are undefined.
bool CCW;
bool ColorPerVertex; ///< If true then colors are defined for every vertex, else for every face(line).
bool NormalPerVertex; ///< If true then normals are defined for every vertex, else for every face(line).
std::vector<int32_t> CoordIndex; ///< Field to specify the polygonal faces by indexing into the <Coordinate>.
std::vector<int32_t> NormalIndex; ///< Field to specify the polygonal faces by indexing into the <Normal>.
std::vector<int32_t> TexCoordIndex; ///< Field to specify the polygonal faces by indexing into the <TextureCoordinate>.
std::vector<int32_t> VertexCount; ///< Field describes how many vertices are to be used in each polyline(polygon) from the <Coordinate> field.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DSet(const EType pType, X3DNodeElementBase *pParent) :
X3DGeometry3D(pType, pParent) {}
}; // class CX3DImporter_NodeElement_Set
/// This struct hold <Shape> value.
struct X3DShape : public X3DNodeElementBase {
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DShape(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Shape, pParent) {}
}; // struct CX3DImporter_NodeElement_Shape
/// This struct hold <Appearance> value.
struct X3DAppearance : public X3DNodeElementBase {
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DAppearance(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Appearance, pParent) {}
}; // struct CX3DImporter_NodeElement_Appearance
/// Material.
class X3DMaterial : public X3DNodeElementBase {
public:
float AmbientIntensity; ///< Specifies how much ambient light from light sources this surface shall reflect.
aiColor3D DiffuseColor; ///< Reflects all X3D light sources depending on the angle of the surface with respect to the light source.
aiColor3D EmissiveColor; ///< Models "glowing" objects. This can be useful for displaying pre-lit models.
float Shininess; ///< Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights.
aiColor3D SpecularColor; ///< The specularColor and shininess fields determine the specular highlights.
float Transparency; ///< Specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque.
/// Constructor.
/// \param [in] pParent - pointer to parent node.
/// \param [in] pType - type of geometry object.
X3DMaterial(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_Material, pParent),
AmbientIntensity(0.0f),
DiffuseColor(),
EmissiveColor(),
Shininess(0.0f),
SpecularColor(),
Transparency(1.0f) {
// empty
}
}; // class CX3DImporter_NodeElement_Material
/// This struct hold <ImageTexture> value.
struct X3DImageTexture : public X3DNodeElementBase {
/// RepeatS and RepeatT, that specify how the texture wraps in the S and T directions. If repeatS is TRUE (the default), the texture map is repeated
/// outside the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape. If repeatS is FALSE, the texture coordinates are
/// clamped in the S direction to lie within the [0.0, 1.0] range. The repeatT field is analogous to the repeatS field.
bool RepeatS;
bool RepeatT; ///< See \ref RepeatS.
std::string URL; ///< URL of the texture.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DImageTexture(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_ImageTexture, pParent) {}
}; // struct CX3DImporter_NodeElement_ImageTexture
/// This struct hold <TextureTransform> value.
struct X3DTextureTransform : public X3DNodeElementBase {
aiVector2D Center; ///< Specifies a translation offset in texture coordinate space about which the rotation and scale fields are applied.
float Rotation; ///< Specifies a rotation in angle base units of the texture coordinates about the center point after the scale has been applied.
aiVector2D Scale; ///< Specifies a scaling factor in S and T of the texture coordinates about the center point.
aiVector2D Translation; ///< Specifies a translation of the texture coordinates.
/// Constructor
/// \param [in] pParent - pointer to parent node.
X3DTextureTransform(X3DNodeElementBase *pParent) :
X3DNodeElementBase(ENET_TextureTransform, pParent) {}
}; // struct CX3DImporter_NodeElement_TextureTransform
/// This struct hold <TextureTransform> value.
struct X3DLight : public X3DNodeElementBase {
float AmbientIntensity; ///< Specifies the intensity of the ambient emission from the light.
aiColor3D Color; ///< specifies the spectral colour properties of both the direct and ambient light emission as an RGB value.
aiVector3D Direction; ///< Specifies the direction vector of the illumination emanating from the light source in the local coordinate system.
/// Field that determines whether the light is global or scoped. Global lights illuminate all objects that fall within their volume of lighting influence.
/// Scoped lights only illuminate objects that are in the same transformation hierarchy as the light.
bool Global;
float Intensity; ///< Specifies the brightness of the direct emission from the light.
/// PointLight node's illumination falls off with distance as specified by three attenuation coefficients. The attenuation factor
/// is: "1 / max(attenuation[0] + attenuation[1] * r + attenuation[2] * r2, 1)", where r is the distance from the light to the surface being illuminated.
aiVector3D Attenuation;
aiVector3D Location; ///< Specifies a translation offset of the centre point of the light source from the light's local coordinate system origin.
float Radius; ///< Specifies the radial extent of the solid angle and the maximum distance from location that may be illuminated by the light source.
float BeamWidth; ///< Specifies an inner solid angle in which the light source emits light at uniform full intensity.
float CutOffAngle; ///< The light source's emission intensity drops off from the inner solid angle (beamWidth) to the outer solid angle (cutOffAngle).
/// Constructor
/// \param [in] pParent - pointer to parent node.
/// \param [in] pLightType - type of the light source.
X3DLight(EType pLightType, X3DNodeElementBase *pParent) :
X3DNodeElementBase(pLightType, pParent) {}
}; // struct CX3DImporter_NodeElement_Light
#endif // INCLUDED_AI_X3D_IMPORTER_NODE_H

View File

@ -1,829 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Postprocess.cpp
/// \brief Convert built scenegraph and objects to Assimp scenegraph.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
// Header files, Assimp.
#include <assimp/ai_assert.h>
#include <assimp/StandardShapes.h>
#include <assimp/StringUtils.h>
// Header files, stdlib.
#include <algorithm>
#include <iterator>
#include <string>
namespace Assimp
{
aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const
{
X3DNodeElementBase* cur_node;
std::list<aiMatrix4x4> matr;
aiMatrix4x4 out_matr;
// starting walk from current element to root
cur_node = mNodeElementCur;
if(cur_node != nullptr)
{
do
{
// if cur_node is group then store group transformation matrix in list.
if(cur_node->Type == X3DNodeElementBase::ENET_Group) matr.push_back(((X3DGroup*)cur_node)->Transformation);
cur_node = cur_node->Parent;
} while(cur_node != nullptr);
}
// multiplicate all matrices in reverse order
for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit);
return out_matr;
}
void X3DImporter::PostprocessHelper_CollectMetadata(const X3DNodeElementBase& pNodeElement, std::list<X3DNodeElementBase*>& pList) const
{
// walk through childs and find for metadata.
for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it)
{
if(((*el_it)->Type == X3DNodeElementBase::ENET_MetaBoolean) || ((*el_it)->Type == X3DNodeElementBase::ENET_MetaDouble) ||
((*el_it)->Type == X3DNodeElementBase::ENET_MetaFloat) || ((*el_it)->Type == X3DNodeElementBase::ENET_MetaInteger) ||
((*el_it)->Type == X3DNodeElementBase::ENET_MetaString))
{
pList.push_back(*el_it);
}
else if((*el_it)->Type == X3DNodeElementBase::ENET_MetaSet)
{
PostprocessHelper_CollectMetadata(**el_it, pList);
}
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
}
bool X3DImporter::PostprocessHelper_ElementIsMetadata(const X3DNodeElementBase::EType pType) const
{
if((pType == X3DNodeElementBase::ENET_MetaBoolean) || (pType == X3DNodeElementBase::ENET_MetaDouble) ||
(pType == X3DNodeElementBase::ENET_MetaFloat) || (pType == X3DNodeElementBase::ENET_MetaInteger) ||
(pType == X3DNodeElementBase::ENET_MetaString) || (pType == X3DNodeElementBase::ENET_MetaSet))
{
return true;
}
else
{
return false;
}
}
bool X3DImporter::PostprocessHelper_ElementIsMesh(const X3DNodeElementBase::EType pType) const
{
if((pType == X3DNodeElementBase::ENET_Arc2D) || (pType == X3DNodeElementBase::ENET_ArcClose2D) ||
(pType == X3DNodeElementBase::ENET_Box) || (pType == X3DNodeElementBase::ENET_Circle2D) ||
(pType == X3DNodeElementBase::ENET_Cone) || (pType == X3DNodeElementBase::ENET_Cylinder) ||
(pType == X3DNodeElementBase::ENET_Disk2D) || (pType == X3DNodeElementBase::ENET_ElevationGrid) ||
(pType == X3DNodeElementBase::ENET_Extrusion) || (pType == X3DNodeElementBase::ENET_IndexedFaceSet) ||
(pType == X3DNodeElementBase::ENET_IndexedLineSet) || (pType == X3DNodeElementBase::ENET_IndexedTriangleFanSet) ||
(pType == X3DNodeElementBase::ENET_IndexedTriangleSet) || (pType == X3DNodeElementBase::ENET_IndexedTriangleStripSet) ||
(pType == X3DNodeElementBase::ENET_PointSet) || (pType == X3DNodeElementBase::ENET_LineSet) ||
(pType == X3DNodeElementBase::ENET_Polyline2D) || (pType == X3DNodeElementBase::ENET_Polypoint2D) ||
(pType == X3DNodeElementBase::ENET_Rectangle2D) || (pType == X3DNodeElementBase::ENET_Sphere) ||
(pType == X3DNodeElementBase::ENET_TriangleFanSet) || (pType == X3DNodeElementBase::ENET_TriangleSet) ||
(pType == X3DNodeElementBase::ENET_TriangleSet2D) || (pType == X3DNodeElementBase::ENET_TriangleStripSet))
{
return true;
}
else
{
return false;
}
}
void X3DImporter::Postprocess_BuildLight(const X3DNodeElementBase& pNodeElement, std::list<aiLight*>& pSceneLightList) const
{
const X3DLight& ne = *( ( X3DLight* ) &pNodeElement );
aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent();
aiLight* new_light = new aiLight;
new_light->mName = ne.ID;
new_light->mColorAmbient = ne.Color * ne.AmbientIntensity;
new_light->mColorDiffuse = ne.Color * ne.Intensity;
new_light->mColorSpecular = ne.Color * ne.Intensity;
switch(pNodeElement.Type)
{
case X3DNodeElementBase::ENET_DirectionalLight:
new_light->mType = aiLightSource_DIRECTIONAL;
new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
break;
case X3DNodeElementBase::ENET_PointLight:
new_light->mType = aiLightSource_POINT;
new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
new_light->mAttenuationConstant = ne.Attenuation.x;
new_light->mAttenuationLinear = ne.Attenuation.y;
new_light->mAttenuationQuadratic = ne.Attenuation.z;
break;
case X3DNodeElementBase::ENET_SpotLight:
new_light->mType = aiLightSource_SPOT;
new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
new_light->mAttenuationConstant = ne.Attenuation.x;
new_light->mAttenuationLinear = ne.Attenuation.y;
new_light->mAttenuationQuadratic = ne.Attenuation.z;
new_light->mAngleInnerCone = ne.BeamWidth;
new_light->mAngleOuterCone = ne.CutOffAngle;
break;
default:
throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: " + to_string(pNodeElement.Type) + ".");
}
pSceneLightList.push_back(new_light);
}
void X3DImporter::Postprocess_BuildMaterial(const X3DNodeElementBase& pNodeElement, aiMaterial** pMaterial) const
{
// check argument
if(pMaterial == nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is nullptr.");
if(*pMaterial != nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be nullptr.");
*pMaterial = new aiMaterial;
aiMaterial& taimat = **pMaterial;// creating alias for convenience.
// at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data.
for(std::list<X3DNodeElementBase*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it)
{
if((*el_it)->Type == X3DNodeElementBase::ENET_Material)
{
aiColor3D tcol3;
float tvalf;
X3DMaterial& tnemat = *((X3DMaterial*)*el_it);
tcol3.r = tnemat.AmbientIntensity, tcol3.g = tnemat.AmbientIntensity, tcol3.b = tnemat.AmbientIntensity;
taimat.AddProperty(&tcol3, 1, AI_MATKEY_COLOR_AMBIENT);
taimat.AddProperty(&tnemat.DiffuseColor, 1, AI_MATKEY_COLOR_DIFFUSE);
taimat.AddProperty(&tnemat.EmissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
taimat.AddProperty(&tnemat.SpecularColor, 1, AI_MATKEY_COLOR_SPECULAR);
tvalf = 1;
taimat.AddProperty(&tvalf, 1, AI_MATKEY_SHININESS_STRENGTH);
taimat.AddProperty(&tnemat.Shininess, 1, AI_MATKEY_SHININESS);
tvalf = 1.0f - tnemat.Transparency;
taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY);
}// if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material)
else if((*el_it)->Type == X3DNodeElementBase::ENET_ImageTexture)
{
X3DImageTexture& tnetex = *((X3DImageTexture*)*el_it);
aiString url_str(tnetex.URL.c_str());
int mode = aiTextureOp_Multiply;
taimat.AddProperty(&url_str, AI_MATKEY_TEXTURE_DIFFUSE(0));
taimat.AddProperty(&tnetex.RepeatS, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
taimat.AddProperty(&tnetex.RepeatT, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
taimat.AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
}// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture)
else if((*el_it)->Type == X3DNodeElementBase::ENET_TextureTransform)
{
aiUVTransform trans;
X3DTextureTransform& tnetextr = *((X3DTextureTransform*)*el_it);
trans.mTranslation = tnetextr.Translation - tnetextr.Center;
trans.mScaling = tnetextr.Scale;
trans.mRotation = tnetextr.Rotation;
taimat.AddProperty(&trans, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
}// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_TextureTransform)
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
}
void X3DImporter::Postprocess_BuildMesh(const X3DNodeElementBase& pNodeElement, aiMesh** pMesh) const
{
// check argument
if(pMesh == nullptr) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is nullptr.");
if(*pMesh != nullptr) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be nullptr.");
/************************************************************************************************************************************/
/************************************************************ Geometry2D ************************************************************/
/************************************************************************************************************************************/
if((pNodeElement.Type == X3DNodeElementBase::ENET_Arc2D) || (pNodeElement.Type == X3DNodeElementBase::ENET_ArcClose2D) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_Circle2D) || (pNodeElement.Type == X3DNodeElementBase::ENET_Disk2D) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_Polyline2D) || (pNodeElement.Type == X3DNodeElementBase::ENET_Polypoint2D) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_Rectangle2D) || (pNodeElement.Type == X3DNodeElementBase::ENET_TriangleSet2D))
{
X3DGeometry2D& tnemesh = *((X3DGeometry2D*)&pNodeElement);// create alias for convenience
std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size());
for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
return;// mesh is build, nothing to do anymore.
}
/************************************************************************************************************************************/
/************************************************************ Geometry3D ************************************************************/
/************************************************************************************************************************************/
//
// Predefined figures
//
if((pNodeElement.Type == X3DNodeElementBase::ENET_Box) || (pNodeElement.Type == X3DNodeElementBase::ENET_Cone) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_Cylinder) || (pNodeElement.Type == X3DNodeElementBase::ENET_Sphere))
{
X3DGeometry3D& tnemesh = *((X3DGeometry3D*)&pNodeElement);// create alias for convenience
std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size());
for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
return;// mesh is build, nothing to do anymore.
}
//
// Parametric figures
//
if(pNodeElement.Type == X3DNodeElementBase::ENET_ElevationGrid)
{
X3DElevationGrid& tnemesh = *((X3DElevationGrid*)&pNodeElement);// create alias for convenience
// at first create mesh from existing vertices.
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices);
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, ((X3DNormal*)*ch_it)->Value, tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid)
//
// Indexed primitives sets
//
if(pNodeElement.Type == X3DNodeElementBase::ENET_IndexedFaceSet)
{
X3DIndexedSet& tnemesh = *((X3DIndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColorRGBA*)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNormal*)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet)
if(pNodeElement.Type == X3DNodeElementBase::ENET_IndexedLineSet)
{
X3DIndexedSet& tnemesh = *((X3DIndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColorRGBA*)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet)
if((pNodeElement.Type == X3DNodeElementBase::ENET_IndexedTriangleSet) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_IndexedTriangleFanSet) ||
(pNodeElement.Type == X3DNodeElementBase::ENET_IndexedTriangleStripSet))
{
X3DIndexedSet& tnemesh = *((X3DIndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((X3DColorRGBA*)*ch_it)->Value,
tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNormal*)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \
IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet))
if(pNodeElement.Type == X3DNodeElementBase::ENET_Extrusion)
{
X3DIndexedSet& tnemesh = *((X3DIndexedSet*)&pNodeElement);// create alias for convenience
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, tnemesh.Vertices);
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Extrusion)
//
// Primitives sets
//
if(pNodeElement.Type == X3DNodeElementBase::ENET_PointSet)
{
X3DSet& tnemesh = *((X3DSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
std::vector<aiVector3D> vec_copy;
vec_copy.reserve(((X3DCoordinate*)*ch_it)->Value.size());
for(std::list<aiVector3D>::const_iterator it = ((X3DCoordinate*)*ch_it)->Value.begin();
it != ((X3DCoordinate*)*ch_it)->Value.end(); ++it)
{
vec_copy.push_back(*it);
}
*pMesh = StandardShapes::MakeMesh(vec_copy, 1);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value, true);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, true);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet)
if(pNodeElement.Type == X3DNodeElementBase::ENET_LineSet)
{
X3DSet& tnemesh = *((X3DSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value, true);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, true);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet)
if(pNodeElement.Type == X3DNodeElementBase::ENET_TriangleFanSet)
{
X3DSet& tnemesh = *((X3DSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if ( nullptr == *pMesh ) {
break;
}
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value,tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNormal*)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet)
if(pNodeElement.Type == X3DNodeElementBase::ENET_TriangleSet)
{
X3DSet& tnemesh = *((X3DSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
std::vector<aiVector3D> vec_copy;
vec_copy.reserve(((X3DCoordinate*)*ch_it)->Value.size());
for(std::list<aiVector3D>::const_iterator it = ((X3DCoordinate*)*ch_it)->Value.begin();
it != ((X3DCoordinate*)*ch_it)->Value.end(); ++it)
{
vec_copy.push_back(*it);
}
*pMesh = StandardShapes::MakeMesh(vec_copy, 3);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNormal*)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet)
if(pNodeElement.Type == X3DNodeElementBase::ENET_TriangleStripSet)
{
X3DSet& tnemesh = *((X3DSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh.
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((X3DCoordinate*)*ch_it)->Value);
}
}
// copy additional information from children
for(std::list<X3DNodeElementBase*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{
ai_assert(*pMesh);
if((*ch_it)->Type == X3DNodeElementBase::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((X3DColor*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_ColorRGBA)
MeshGeometry_AddColor(**pMesh, ((X3DColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Coordinate)
{} // skip because already read when mesh created.
else if((*ch_it)->Type == X3DNodeElementBase::ENET_Normal)
MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((X3DNormal*)*ch_it)->Value,
tnemesh.NormalPerVertex);
else if((*ch_it)->Type == X3DNodeElementBase::ENET_TextureCoordinate)
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((X3DTextureCoordinate*)*ch_it)->Value);
else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet)
throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + to_string(pNodeElement.Type) + ".");
}
void X3DImporter::Postprocess_BuildNode(const X3DNodeElementBase& pNodeElement, aiNode& pSceneNode, std::list<aiMesh*>& pSceneMeshList,
std::list<aiMaterial*>& pSceneMaterialList, std::list<aiLight*>& pSceneLightList) const
{
std::list<X3DNodeElementBase*>::const_iterator chit_begin = pNodeElement.Child.begin();
std::list<X3DNodeElementBase*>::const_iterator chit_end = pNodeElement.Child.end();
std::list<aiNode*> SceneNode_Child;
std::list<unsigned int> SceneNode_Mesh;
// At first read all metadata
Postprocess_CollectMetadata(pNodeElement, pSceneNode);
// check if we have deal with grouping node. Which can contain transformation or switch
if(pNodeElement.Type == X3DNodeElementBase::ENET_Group)
{
const X3DGroup& tne_group = *((X3DGroup*)&pNodeElement);// create alias for convenience
pSceneNode.mTransformation = tne_group.Transformation;
if(tne_group.UseChoice)
{
// If Choice is less than zero or greater than the number of nodes in the children field, nothing is chosen.
if((tne_group.Choice < 0) || ((size_t)tne_group.Choice >= pNodeElement.Child.size()))
{
chit_begin = pNodeElement.Child.end();
chit_end = pNodeElement.Child.end();
}
else
{
for(size_t i = 0; i < (size_t)tne_group.Choice; i++) ++chit_begin;// forward iterator to chosen node.
chit_end = chit_begin;
++chit_end;// point end iterator to next element after chosen node.
}
}// if(tne_group.UseChoice)
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group)
// Reserve memory for fast access and check children.
for(std::list<X3DNodeElementBase*>::const_iterator it = chit_begin; it != chit_end; ++it)
{// in this loop we do not read metadata because it's already read at begin.
if((*it)->Type == X3DNodeElementBase::ENET_Group)
{
// if child is group then create new node and do recursive call.
aiNode* new_node = new aiNode;
new_node->mName = (*it)->ID;
new_node->mParent = &pSceneNode;
SceneNode_Child.push_back(new_node);
Postprocess_BuildNode(**it, *new_node, pSceneMeshList, pSceneMaterialList, pSceneLightList);
}
else if((*it)->Type == X3DNodeElementBase::ENET_Shape)
{
// shape can contain only one geometry and one appearance nodes.
Postprocess_BuildShape(*((X3DShape*)*it), SceneNode_Mesh, pSceneMeshList, pSceneMaterialList);
}
else if(((*it)->Type == X3DNodeElementBase::ENET_DirectionalLight) || ((*it)->Type == X3DNodeElementBase::ENET_PointLight) ||
((*it)->Type == X3DNodeElementBase::ENET_SpotLight))
{
Postprocess_BuildLight(*((X3DLight*)*it), pSceneLightList);
}
else if(!PostprocessHelper_ElementIsMetadata((*it)->Type))// skip metadata
{
throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + to_string((*it)->Type) + ".");
}
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++)
// copy data about children and meshes to aiNode.
if(!SceneNode_Child.empty())
{
std::list<aiNode*>::const_iterator it = SceneNode_Child.begin();
pSceneNode.mNumChildren = static_cast<unsigned int>(SceneNode_Child.size());
pSceneNode.mChildren = new aiNode*[pSceneNode.mNumChildren];
for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++;
}
if(!SceneNode_Mesh.empty())
{
std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin();
pSceneNode.mNumMeshes = static_cast<unsigned int>(SceneNode_Mesh.size());
pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *it++;
}
// that's all. return to previous deals
}
void X3DImporter::Postprocess_BuildShape(const X3DShape& pShapeNodeElement, std::list<unsigned int>& pNodeMeshInd,
std::list<aiMesh*>& pSceneMeshList, std::list<aiMaterial*>& pSceneMaterialList) const
{
aiMaterial* tmat = nullptr;
aiMesh* tmesh = nullptr;
X3DNodeElementBase::EType mesh_type = X3DNodeElementBase::ENET_Invalid;
unsigned int mat_ind = 0;
for(std::list<X3DNodeElementBase*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); ++it)
{
if(PostprocessHelper_ElementIsMesh((*it)->Type))
{
Postprocess_BuildMesh(**it, &tmesh);
if(tmesh != nullptr)
{
// if mesh successfully built then add data about it to arrays
pNodeMeshInd.push_back(static_cast<unsigned int>(pSceneMeshList.size()));
pSceneMeshList.push_back(tmesh);
// keep mesh type. Need above for texture coordinate generation.
mesh_type = (*it)->Type;
}
}
else if((*it)->Type == X3DNodeElementBase::ENET_Appearance)
{
Postprocess_BuildMaterial(**it, &tmat);
if(tmat != nullptr)
{
// if material successfully built then add data about it to array
mat_ind = static_cast<unsigned int>(pSceneMaterialList.size());
pSceneMaterialList.push_back(tmat);
}
}
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++)
// associate read material with read mesh.
if((tmesh != nullptr) && (tmat != nullptr))
{
tmesh->mMaterialIndex = mat_ind;
// Check texture mapping. If material has texture but mesh has no texture coordinate then try to ask Assimp to generate texture coordinates.
if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0))
{
int32_t tm;
aiVector3D tvec3;
switch(mesh_type)
{
case X3DNodeElementBase::ENET_Box:
tm = aiTextureMapping_BOX;
break;
case X3DNodeElementBase::ENET_Cone:
case X3DNodeElementBase::ENET_Cylinder:
tm = aiTextureMapping_CYLINDER;
break;
case X3DNodeElementBase::ENET_Sphere:
tm = aiTextureMapping_SPHERE;
break;
default:
tm = aiTextureMapping_PLANE;
break;
}// switch(mesh_type)
tmat->AddProperty(&tm, 1, AI_MATKEY_MAPPING_DIFFUSE(0));
}// if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0))
}// if((tmesh != nullptr) && (tmat != nullptr))
}
void X3DImporter::Postprocess_CollectMetadata(const X3DNodeElementBase& pNodeElement, aiNode& pSceneNode) const
{
std::list<X3DNodeElementBase*> meta_list;
size_t meta_idx;
PostprocessHelper_CollectMetadata(pNodeElement, meta_list);// find metadata in current node element.
if ( !meta_list.empty() )
{
if ( pSceneNode.mMetaData != nullptr ) {
throw DeadlyImportError( "Postprocess. MetaData member in node are not nullptr. Something went wrong." );
}
// copy collected metadata to output node.
pSceneNode.mMetaData = aiMetadata::Alloc( static_cast<unsigned int>(meta_list.size()) );
meta_idx = 0;
for(std::list<X3DNodeElementBase*>::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx)
{
X3DMeta* cur_meta = (X3DMeta*)*it;
// due to limitations we can add only first element of value list.
// Add an element according to its type.
if((*it)->Type == X3DNodeElementBase::ENET_MetaBoolean)
{
if(((X3DMetaBoolean*)cur_meta)->Value.size() > 0) {
const bool v = (bool) *( ( (X3DMetaBoolean*) cur_meta )->Value.begin());
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, v);
}
}
else if((*it)->Type == X3DNodeElementBase::ENET_MetaDouble)
{
if(((X3DMetaDouble*)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, (float)*(((X3DMetaDouble*)cur_meta)->Value.begin()));
}
else if((*it)->Type == X3DNodeElementBase::ENET_MetaFloat)
{
if(((X3DMetaFloat*)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DMetaFloat*)cur_meta)->Value.begin()));
}
else if((*it)->Type == X3DNodeElementBase::ENET_MetaInteger)
{
if(((X3DMetaInteger*)cur_meta)->Value.size() > 0)
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((X3DMetaInteger*)cur_meta)->Value.begin()));
}
else if((*it)->Type == X3DNodeElementBase::ENET_MetaString)
{
if(((X3DMetaString*)cur_meta)->Value.size() > 0)
{
aiString tstr(((X3DMetaString*)cur_meta)->Value.begin()->data());
pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, tstr);
}
}
else
{
throw DeadlyImportError("Postprocess. Unknown metadata type.");
}// if((*it)->Type == CX3DImporter_NodeElement::ENET_Meta*) else
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++)
}// if( !meta_list.empty() )
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

File diff suppressed because it is too large Load Diff

View File

@ -1,250 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Shape.cpp
/// \brief Parsing data from nodes of "Shape" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
namespace Assimp
{
// <Shape
// DEF="" ID
// USE="" IDREF
// bboxCenter="0 0 0" SFVec3f [initializeOnly]
// bboxSize="-1 -1 -1" SFVec3f [initializeOnly]
// >
// <!-- ShapeChildContentModel -->
// "ShapeChildContentModel is the child-node content model corresponding to X3DShapeNode. ShapeChildContentModel can contain a single Appearance node and a
// single geometry node, in any order.
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model."
// </Shape>
// A Shape node is unlit if either of the following is true:
// The shape's appearance field is nullptr (default).
// The material field in the Appearance node is nullptr (default).
// NOTE Geometry nodes that represent lines or points do not support lighting.
void X3DImporter::ParseNode_Shape_Shape()
{
std::string use, def;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Shape, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DShape(mNodeElementCur);
if(!def.empty()) ne->ID = def;
// check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("Shape");
// check for appearance node
if(XML_CheckNode_NameEqual("Appearance")) { ParseNode_Shape_Appearance(); continue; }
// check for X3DGeometryNodes
if(XML_CheckNode_NameEqual("Arc2D")) { ParseNode_Geometry2D_Arc2D(); continue; }
if(XML_CheckNode_NameEqual("ArcClose2D")) { ParseNode_Geometry2D_ArcClose2D(); continue; }
if(XML_CheckNode_NameEqual("Circle2D")) { ParseNode_Geometry2D_Circle2D(); continue; }
if(XML_CheckNode_NameEqual("Disk2D")) { ParseNode_Geometry2D_Disk2D(); continue; }
if(XML_CheckNode_NameEqual("Polyline2D")) { ParseNode_Geometry2D_Polyline2D(); continue; }
if(XML_CheckNode_NameEqual("Polypoint2D")) { ParseNode_Geometry2D_Polypoint2D(); continue; }
if(XML_CheckNode_NameEqual("Rectangle2D")) { ParseNode_Geometry2D_Rectangle2D(); continue; }
if(XML_CheckNode_NameEqual("TriangleSet2D")) { ParseNode_Geometry2D_TriangleSet2D(); continue; }
if(XML_CheckNode_NameEqual("Box")) { ParseNode_Geometry3D_Box(); continue; }
if(XML_CheckNode_NameEqual("Cone")) { ParseNode_Geometry3D_Cone(); continue; }
if(XML_CheckNode_NameEqual("Cylinder")) { ParseNode_Geometry3D_Cylinder(); continue; }
if(XML_CheckNode_NameEqual("ElevationGrid")) { ParseNode_Geometry3D_ElevationGrid(); continue; }
if(XML_CheckNode_NameEqual("Extrusion")) { ParseNode_Geometry3D_Extrusion(); continue; }
if(XML_CheckNode_NameEqual("IndexedFaceSet")) { ParseNode_Geometry3D_IndexedFaceSet(); continue; }
if(XML_CheckNode_NameEqual("Sphere")) { ParseNode_Geometry3D_Sphere(); continue; }
if(XML_CheckNode_NameEqual("IndexedLineSet")) { ParseNode_Rendering_IndexedLineSet(); continue; }
if(XML_CheckNode_NameEqual("LineSet")) { ParseNode_Rendering_LineSet(); continue; }
if(XML_CheckNode_NameEqual("PointSet")) { ParseNode_Rendering_PointSet(); continue; }
if(XML_CheckNode_NameEqual("IndexedTriangleFanSet")) { ParseNode_Rendering_IndexedTriangleFanSet(); continue; }
if(XML_CheckNode_NameEqual("IndexedTriangleSet")) { ParseNode_Rendering_IndexedTriangleSet(); continue; }
if(XML_CheckNode_NameEqual("IndexedTriangleStripSet")) { ParseNode_Rendering_IndexedTriangleStripSet(); continue; }
if(XML_CheckNode_NameEqual("TriangleFanSet")) { ParseNode_Rendering_TriangleFanSet(); continue; }
if(XML_CheckNode_NameEqual("TriangleSet")) { ParseNode_Rendering_TriangleSet(); continue; }
if(XML_CheckNode_NameEqual("TriangleStripSet")) { ParseNode_Rendering_TriangleStripSet(); continue; }
// check for X3DMetadataObject
if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("Shape");
MACRO_NODECHECK_LOOPEND("Shape");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
}
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Appearance
// DEF="" ID
// USE="" IDREF
// >
// <!-- AppearanceChildContentModel -->
// "Child-node content model corresponding to X3DAppearanceChildNode. Appearance can contain FillProperties, LineProperties, Material, any Texture node and
// any TextureTransform node, in any order. No more than one instance of these nodes is allowed. Appearance may also contain multiple shaders (ComposedShader,
// PackagedShader, ProgramShader).
// A ProtoInstance node (with the proper node type) can be substituted for any node in this content model."
// </Appearance>
void X3DImporter::ParseNode_Shape_Appearance()
{
std::string use, def;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Appearance, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DAppearance(mNodeElementCur);
if(!def.empty()) ne->ID = def;
// check for child nodes
if(!mReader->isEmptyElement())
{
ParseHelper_Node_Enter(ne);
MACRO_NODECHECK_LOOPBEGIN("Appearance");
if(XML_CheckNode_NameEqual("Material")) { ParseNode_Shape_Material(); continue; }
if(XML_CheckNode_NameEqual("ImageTexture")) { ParseNode_Texturing_ImageTexture(); continue; }
if(XML_CheckNode_NameEqual("TextureTransform")) { ParseNode_Texturing_TextureTransform(); continue; }
// check for X3DMetadataObject
if(!ParseHelper_CheckRead_X3DMetadataObject()) XML_CheckNode_SkipUnsupported("Appearance");
MACRO_NODECHECK_LOOPEND("Appearance");
ParseHelper_Node_Exit();
}// if(!mReader->isEmptyElement())
else
{
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
}
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <Material
// DEF="" ID
// USE="" IDREF
// ambientIntensity="0.2" SFFloat [inputOutput]
// diffuseColor="0.8 0.8 0.8" SFColor [inputOutput]
// emissiveColor="0 0 0" SFColor [inputOutput]
// shininess="0.2" SFFloat [inputOutput]
// specularColor="0 0 0" SFColor [inputOutput]
// transparency="0" SFFloat [inputOutput]
// />
void X3DImporter::ParseNode_Shape_Material()
{
std::string use, def;
float ambientIntensity = 0.2f;
float shininess = 0.2f;
float transparency = 0;
aiColor3D diffuseColor(0.8f, 0.8f, 0.8f);
aiColor3D emissiveColor(0, 0, 0);
aiColor3D specularColor(0, 0, 0);
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("ambientIntensity", ambientIntensity, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("shininess", shininess, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_RET("transparency", transparency, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("diffuseColor", diffuseColor, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_CHECK_REF("emissiveColor", emissiveColor, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_CHECK_REF("specularColor", specularColor, XML_ReadNode_GetAttrVal_AsCol3f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_Material, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DMaterial(mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DMaterial*)ne)->AmbientIntensity = ambientIntensity;
((X3DMaterial*)ne)->Shininess = shininess;
((X3DMaterial*)ne)->Transparency = transparency;
((X3DMaterial*)ne)->DiffuseColor = diffuseColor;
((X3DMaterial*)ne)->EmissiveColor = emissiveColor;
((X3DMaterial*)ne)->SpecularColor = specularColor;
// check for child nodes
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "Material");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

View File

@ -1,197 +0,0 @@
/*
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,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
/// \file X3DImporter_Texturing.cpp
/// \brief Parsing data from nodes of "Texturing" set of X3D.
/// \date 2015-2016
/// \author smal.root@gmail.com
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
#include "X3DImporter.hpp"
#include "X3DImporter_Macro.hpp"
namespace Assimp
{
// <ImageTexture
// DEF="" ID
// USE="" IDREF
// repeatS="true" SFBool
// repeatT="true" SFBool
// url="" MFString
// />
// When the url field contains no values ([]), texturing is disabled.
void X3DImporter::ParseNode_Texturing_ImageTexture()
{
std::string use, def;
bool repeatS = true;
bool repeatT = true;
std::list<std::string> url;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_RET("repeatS", repeatS, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_RET("repeatT", repeatT, XML_ReadNode_GetAttrVal_AsBool);
MACRO_ATTRREAD_CHECK_REF("url", url, XML_ReadNode_GetAttrVal_AsListS);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_ImageTexture, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DImageTexture(mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DImageTexture*)ne)->RepeatS = repeatS;
((X3DImageTexture*)ne)->RepeatT = repeatT;
// Attribute "url" can contain list of strings. But we need only one - first.
if(!url.empty())
((X3DImageTexture*)ne)->URL = url.front();
else
((X3DImageTexture*)ne)->URL = "";
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "ImageTexture");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <TextureCoordinate
// DEF="" ID
// USE="" IDREF
// point="" MFVec3f [inputOutput]
// />
void X3DImporter::ParseNode_Texturing_TextureCoordinate()
{
std::string use, def;
std::list<aiVector2D> point;
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("point", point, XML_ReadNode_GetAttrVal_AsListVec2f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_TextureCoordinate, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DTextureCoordinate(mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DTextureCoordinate*)ne)->Value = point;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "TextureCoordinate");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
// <TextureTransform
// DEF="" ID
// USE="" IDREF
// center="0 0" SFVec2f [inputOutput]
// rotation="0" SFFloat [inputOutput]
// scale="1 1" SFVec2f [inputOutput]
// translation="0 0" SFVec2f [inputOutput]
// />
void X3DImporter::ParseNode_Texturing_TextureTransform()
{
std::string use, def;
aiVector2D center(0, 0);
float rotation = 0;
aiVector2D scale(1, 1);
aiVector2D translation(0, 0);
X3DNodeElementBase* ne( nullptr );
MACRO_ATTRREAD_LOOPBEG;
MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use);
MACRO_ATTRREAD_CHECK_REF("center", center, XML_ReadNode_GetAttrVal_AsVec2f);
MACRO_ATTRREAD_CHECK_RET("rotation", rotation, XML_ReadNode_GetAttrVal_AsFloat);
MACRO_ATTRREAD_CHECK_REF("scale", scale, XML_ReadNode_GetAttrVal_AsVec2f);
MACRO_ATTRREAD_CHECK_REF("translation", translation, XML_ReadNode_GetAttrVal_AsVec2f);
MACRO_ATTRREAD_LOOPEND;
// if "USE" defined then find already defined element.
if(!use.empty())
{
MACRO_USE_CHECKANDAPPLY(def, use, ENET_TextureTransform, ne);
}
else
{
// create and if needed - define new geometry object.
ne = new X3DTextureTransform(mNodeElementCur);
if(!def.empty()) ne->ID = def;
((X3DTextureTransform*)ne)->Center = center;
((X3DTextureTransform*)ne)->Rotation = rotation;
((X3DTextureTransform*)ne)->Scale = scale;
((X3DTextureTransform*)ne)->Translation = translation;
// check for X3DMetadataObject childs.
if(!mReader->isEmptyElement())
ParseNode_Metadata(ne, "TextureTransform");
else
mNodeElementCur->Child.push_back(ne);// add made object as child to current element
NodeElement_List.push_back(ne);// add element to node element list because its a new object in graph
}// if(!use.empty()) else
}
}// namespace Assimp
#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

File diff suppressed because it is too large Load Diff

View File

@ -249,7 +249,7 @@ void XGLImporter::InternReadFile(const std::string &pFile,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void XGLImporter::ReadWorld(TempScope &scope) { void XGLImporter::ReadWorld(TempScope &scope) {
XmlNode *root = m_xmlParser->getRootNode(); XmlNode *root = mXmlParser->getRootNode();
for (XmlNode &node : root->children()) { for (XmlNode &node : root->children()) {
const std::string &s = node.name(); const std::string &s = node.name();
// XXX right now we'd skip <lighting> if it comes after // XXX right now we'd skip <lighting> if it comes after
@ -261,7 +261,7 @@ void XGLImporter::ReadWorld(TempScope &scope) {
} }
} }
aiNode *const nd = ReadObject(*root, scope, true, "world"); aiNode *const nd = ReadObject( *root, scope, true);
if (!nd) { if (!nd) {
ThrowException("failure reading <world>"); ThrowException("failure reading <world>");
} }
@ -307,7 +307,7 @@ aiLight *XGLImporter::ReadDirectionalLight(XmlNode &node) {
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope, bool skipFirst, const char *closetag) { aiNode *XGLImporter::ReadObject(XmlNode &node, TempScope &scope, bool skipFirst/*, const char *closetag */) {
aiNode *nd = new aiNode; aiNode *nd = new aiNode;
std::vector<aiNode *> children; std::vector<aiNode *> children;
std::vector<unsigned int> meshes; std::vector<unsigned int> meshes;
@ -546,22 +546,22 @@ bool XGLImporter::ReadMesh(XmlNode &node, TempScope &scope) {
TempFace tf[3]; TempFace tf[3];
bool has[3] = { false }; bool has[3] = { false };
for (XmlNode &sub_child : child.children()) { for (XmlNode &sub_child : child.children()) {
const std::string &s = sub_child.name(); const std::string &scn = sub_child.name();
if (s == "fv1" || s == "lv1" || s == "pv1") { if (scn == "fv1" || scn == "lv1" || scn == "pv1") {
ReadFaceVertex(sub_child, t, tf[0]); ReadFaceVertex(sub_child, t, tf[0]);
has[0] = true; has[0] = true;
} else if (s == "fv2" || s == "lv2") { } else if (scn == "fv2" || scn == "lv2") {
ReadFaceVertex(sub_child, t, tf[1]); ReadFaceVertex(sub_child, t, tf[1]);
has[1] = true; has[1] = true;
} else if (s == "fv3") { } else if (scn == "fv3") {
ReadFaceVertex(sub_child, t, tf[2]); ReadFaceVertex(sub_child, t, tf[2]);
has[2] = true; has[2] = true;
} else if (s == "mat") { } else if (scn == "mat") {
if (mid != ~0u) { if (mid != ~0u) {
LogWarn("only one material tag allowed per <f>"); LogWarn("only one material tag allowed per <f>");
} }
mid = ResolveMaterialRef(sub_child, scope); mid = ResolveMaterialRef(sub_child, scope);
} else if (s == "matref") { } else if (scn == "matref") {
if (mid != ~0u) { if (mid != ~0u) {
LogWarn("only one material tag allowed per <f>"); LogWarn("only one material tag allowed per <f>");
} }
@ -688,10 +688,7 @@ void XGLImporter::ReadMaterial(XmlNode &node, TempScope &scope) {
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
void XGLImporter::ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out) { void XGLImporter::ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out) {
const std::string &end = node.name();
bool havep = false; bool havep = false;
//while (ReadElementUpToClosing(end.c_str())) {
for (XmlNode &child : node.children()) { for (XmlNode &child : node.children()) {
const std::string &s = child.name(); const std::string &s = child.name();
if (s == "pref") { if (s == "pref") {

View File

@ -170,27 +170,26 @@ private:
bool ReadElement(); bool ReadElement();
bool ReadElementUpToClosing(const char *closetag); bool ReadElementUpToClosing(const char *closetag);
bool SkipToText(); bool SkipToText();
unsigned int ReadIDAttr(); unsigned int ReadIDAttr(XmlNode &node);
void ReadWorld(TempScope &scope); void ReadWorld(TempScope &scope);
void ReadLighting(TempScope &scope); void ReadLighting(XmlNode &node, TempScope &scope);
aiLight *ReadDirectionalLight(); aiLight *ReadDirectionalLight(XmlNode &node);
aiNode *ReadObject(TempScope &scope, bool skipFirst = false, const char *closetag = "object"); aiNode *ReadObject(XmlNode &node, TempScope &scope, bool skipFirst = false/*, const char *closetag = "object"*/);
bool ReadMesh(TempScope &scope); bool ReadMesh(XmlNode &node, TempScope &scope);
void ReadMaterial(TempScope &scope); void ReadMaterial(XmlNode &node, TempScope &scope);
aiVector2D ReadVec2(); aiVector2D ReadVec2(XmlNode &node);
aiVector3D ReadVec3(); aiVector3D ReadVec3(XmlNode &node);
aiColor3D ReadCol3(); aiColor3D ReadCol3(XmlNode &node);
aiMatrix4x4 ReadTrafo(); aiMatrix4x4 ReadTrafo(XmlNode &node);
unsigned int ReadIndexFromText(); unsigned int ReadIndexFromText(XmlNode &node);
float ReadFloat(); float ReadFloat(XmlNode &node);
aiMesh *ToOutputMesh(const TempMaterialMesh &m); aiMesh *ToOutputMesh(const TempMaterialMesh &m);
void ReadFaceVertex(const TempMesh &t, TempFace &out); void ReadFaceVertex(XmlNode &node, const TempMesh &t, TempFace &out);
unsigned int ResolveMaterialRef(TempScope &scope); unsigned int ResolveMaterialRef(XmlNode &node, TempScope &scope);
private: private:
//std::shared_ptr<irr::io::IrrXMLReader> m_reader;
XmlParser *mXmlParser; XmlParser *mXmlParser;
aiScene *m_scene; aiScene *m_scene;
}; };

View File

@ -800,21 +800,6 @@ ADD_ASSIMP_IMPORTER( X
ADD_ASSIMP_IMPORTER( X3D ADD_ASSIMP_IMPORTER( X3D
AssetLib/X3D/X3DImporter.cpp AssetLib/X3D/X3DImporter.cpp
AssetLib/X3D/X3DImporter.hpp AssetLib/X3D/X3DImporter.hpp
AssetLib/X3D/X3DImporter_Geometry2D.cpp
AssetLib/X3D/X3DImporter_Geometry3D.cpp
AssetLib/X3D/X3DImporter_Group.cpp
AssetLib/X3D/X3DImporter_Light.cpp
AssetLib/X3D/X3DImporter_Macro.hpp
AssetLib/X3D/X3DImporter_Metadata.cpp
AssetLib/X3D/X3DImporter_Networking.cpp
AssetLib/X3D/X3DImporter_Node.hpp
AssetLib/X3D/X3DImporter_Postprocess.cpp
AssetLib/X3D/X3DImporter_Rendering.cpp
AssetLib/X3D/X3DImporter_Shape.cpp
AssetLib/X3D/X3DImporter_Texturing.cpp
#AssetLib/X3D/FIReader.hpp
#AssetLib/X3D/FIReader.cpp
#AssetLib/X3D/X3DVocabulary.cpp
) )
ADD_ASSIMP_IMPORTER( GLTF ADD_ASSIMP_IMPORTER( GLTF

View File

@ -47,12 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_PARSING_UTILS_H_INC #define AI_PARSING_UTILS_H_INC
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC system_header #pragma GCC system_header
#endif #endif
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/defs.h> #include <assimp/defs.h>
#include <vector>
#include <vector> #include <vector>
@ -72,57 +73,53 @@ static const unsigned int BufferSize = 4096;
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE
char_t ToLower( char_t in ) { char_t
return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in+0x20) : in; ToLower(char_t in) {
return (in >= (char_t)'A' && in <= (char_t)'Z') ? (char_t)(in + 0x20) : in;
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE
char_t ToUpper( char_t in) { char_t
return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in-0x20) : in; ToUpper(char_t in) {
return (in >= (char_t)'a' && in <= (char_t)'z') ? (char_t)(in - 0x20) : in;
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool IsUpper(char_t in) {
bool IsUpper( char_t in) {
return (in >= (char_t)'A' && in <= (char_t)'Z'); return (in >= (char_t)'A' && in <= (char_t)'Z');
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool IsLower(char_t in) {
bool IsLower( char_t in) {
return (in >= (char_t)'a' && in <= (char_t)'z'); return (in >= (char_t)'a' && in <= (char_t)'z');
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool IsSpace(char_t in) {
bool IsSpace( char_t in) {
return (in == (char_t)' ' || in == (char_t)'\t'); return (in == (char_t)' ' || in == (char_t)'\t');
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool IsLineEnd(char_t in) {
bool IsLineEnd( char_t in) { return (in == (char_t)'\r' || in == (char_t)'\n' || in == (char_t)'\0' || in == (char_t)'\f');
return (in==(char_t)'\r'||in==(char_t)'\n'||in==(char_t)'\0'||in==(char_t)'\f');
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool IsSpaceOrNewLine(char_t in) {
bool IsSpaceOrNewLine( char_t in) {
return IsSpace<char_t>(in) || IsLineEnd<char_t>(in); return IsSpace<char_t>(in) || IsLineEnd<char_t>(in);
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipSpaces(const char_t *in, const char_t **out) {
bool SkipSpaces( const char_t* in, const char_t** out) { while (*in == (char_t)' ' || *in == (char_t)'\t') {
while( *in == ( char_t )' ' || *in == ( char_t )'\t' ) {
++in; ++in;
} }
*out = in; *out = in;
@ -131,21 +128,19 @@ bool SkipSpaces( const char_t* in, const char_t** out) {
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipSpaces(const char_t **inout) {
bool SkipSpaces( const char_t** inout) { return SkipSpaces<char_t>(*inout, inout);
return SkipSpaces<char_t>(*inout,inout);
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipLine(const char_t *in, const char_t **out) {
bool SkipLine( const char_t* in, const char_t** out) { while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0') {
while( *in != ( char_t )'\r' && *in != ( char_t )'\n' && *in != ( char_t )'\0' ) {
++in; ++in;
} }
// files are opened in binary mode. Ergo there are both NL and CR // files are opened in binary mode. Ergo there are both NL and CR
while( *in == ( char_t )'\r' || *in == ( char_t )'\n' ) { while (*in == (char_t)'\r' || *in == (char_t)'\n') {
++in; ++in;
} }
*out = in; *out = in;
@ -154,16 +149,14 @@ bool SkipLine( const char_t* in, const char_t** out) {
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipLine(const char_t **inout) {
bool SkipLine( const char_t** inout) { return SkipLine<char_t>(*inout, inout);
return SkipLine<char_t>(*inout,inout);
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t *in, const char_t **out) {
bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out) { while (*in == (char_t)' ' || *in == (char_t)'\t' || *in == (char_t)'\r' || *in == (char_t)'\n') {
while( *in == ( char_t )' ' || *in == ( char_t )'\t' || *in == ( char_t )'\r' || *in == ( char_t )'\n' ) {
++in; ++in;
} }
*out = in; *out = in;
@ -172,27 +165,25 @@ bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out) {
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool SkipSpacesAndLineEnd(const char_t **inout) {
bool SkipSpacesAndLineEnd( const char_t** inout) { return SkipSpacesAndLineEnd<char_t>(*inout, inout);
return SkipSpacesAndLineEnd<char_t>(*inout,inout);
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool GetNextLine(const char_t *&buffer, char_t out[BufferSize]) {
bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) { if ((char_t)'\0' == *buffer) {
if( ( char_t )'\0' == *buffer ) {
return false; return false;
} }
char* _out = out; char *_out = out;
char* const end = _out + BufferSize; char *const end = _out + BufferSize;
while( !IsLineEnd( *buffer ) && _out < end ) { while (!IsLineEnd(*buffer) && _out < end) {
*_out++ = *buffer++; *_out++ = *buffer++;
} }
*_out = (char_t)'\0'; *_out = (char_t)'\0';
while( IsLineEnd( *buffer ) && '\0' != *buffer ) { while (IsLineEnd(*buffer) && '\0' != *buffer) {
++buffer; ++buffer;
} }
@ -201,18 +192,16 @@ bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) {
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE bool IsNumeric( char_t in) { AI_FORCE_INLINE bool IsNumeric(char_t in) {
return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in; return (in >= '0' && in <= '9') || '-' == in || '+' == in;
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
template <class char_t> template <class char_t>
AI_FORCE_INLINE AI_FORCE_INLINE bool TokenMatch(char_t *&in, const char *token, unsigned int len) {
bool TokenMatch(char_t*& in, const char* token, unsigned int len) if (!::strncmp(token, in, len) && IsSpaceOrNewLine(in[len])) {
{
if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
if (in[len] != '\0') { if (in[len] != '\0') {
in += len+1; in += len + 1;
} else { } else {
// If EOF after the token make sure we don't go past end of buffer // If EOF after the token make sure we don't go past end of buffer
in += len; in += len;
@ -229,9 +218,9 @@ bool TokenMatch(char_t*& in, const char* token, unsigned int len)
* @param len Number of characters to check * @param len Number of characters to check
*/ */
AI_FORCE_INLINE AI_FORCE_INLINE
bool TokenMatchI(const char*& in, const char* token, unsigned int len) { bool TokenMatchI(const char *&in, const char *token, unsigned int len) {
if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) { if (!ASSIMP_strincmp(token, in, len) && IsSpaceOrNewLine(in[len])) {
in += len+1; in += len + 1;
return true; return true;
} }
return false; return false;
@ -239,22 +228,22 @@ bool TokenMatchI(const char*& in, const char* token, unsigned int len) {
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
AI_FORCE_INLINE AI_FORCE_INLINE
void SkipToken(const char*& in) { void SkipToken(const char *&in) {
SkipSpaces(&in); SkipSpaces(&in);
while ( !IsSpaceOrNewLine( *in ) ) { while (!IsSpaceOrNewLine(*in)) {
++in; ++in;
} }
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
AI_FORCE_INLINE AI_FORCE_INLINE
std::string GetNextToken(const char*& in) { std::string GetNextToken(const char *&in) {
SkipSpacesAndLineEnd(&in); SkipSpacesAndLineEnd(&in);
const char* cur = in; const char *cur = in;
while ( !IsSpaceOrNewLine( *in ) ) { while (!IsSpaceOrNewLine(*in)) {
++in; ++in;
} }
return std::string(cur,(size_t)(in-cur)); return std::string(cur, (size_t)(in - cur));
} }
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@ -290,6 +279,6 @@ AI_FORCE_INLINE unsigned int tokenize(const string_type &str, std::vector<string
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
} // ! namespace Assimp } // namespace Assimp
#endif // ! AI_PARSING_UTILS_H_INC #endif // ! AI_PARSING_UTILS_H_INC