123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /*
- Open Asset Import Library (assimp)
- ----------------------------------------------------------------------
- Copyright (c) 2006-2024, 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.cpp
- /// \brief X3D-format files importer for Assimp: main algorithm implementation.
- /// \date 2015-2016
- /// \author [email protected]
- #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
- #include "AssetLib/VRML/VrmlConverter.hpp"
- #include "X3DImporter.hpp"
- #include "X3DImporter_Macro.hpp"
- #include <assimp/DefaultIOSystem.h>
- // Header files, stdlib.
- #include <iterator>
- #include <memory>
- #if defined(ASSIMP_BUILD_NO_VRML_IMPORTER)
- #define X3D_FORMATS_DESCR_STR "Extensible 3D(X3D, X3DB) Importer"
- #define X3D_FORMATS_EXTENSIONS_STR "x3d x3db"
- #else
- #define X3D_FORMATS_DESCR_STR "VRML(WRL, X3DV) and Extensible 3D(X3D, X3DB) Importer"
- #define X3D_FORMATS_EXTENSIONS_STR "wrl x3d x3db x3dv"
- #endif // #if defined(ASSIMP_BUILD_NO_VRML_IMPORTER)
- namespace Assimp {
- /// Constant which holds the importer description
- const aiImporterDesc X3DImporter::Description = {
- X3D_FORMATS_DESCR_STR,
- "smalcom",
- "",
- "See documentation in source code. Chapter: Limitations.",
- aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
- 0,
- 0,
- 0,
- 0,
- X3D_FORMATS_EXTENSIONS_STR
- };
- bool X3DImporter::isNodeEmpty(XmlNode &node) {
- return node.first_child().empty();
- }
- void X3DImporter::checkNodeMustBeEmpty(XmlNode &node) {
- if (!isNodeEmpty(node)) throw DeadlyImportError(std::string("Node <") + node.name() + "> must be empty.");
- }
- void X3DImporter::skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node) {
- static const size_t Uns_Skip_Len = 192;
- static const char *Uns_Skip[Uns_Skip_Len] = {
- // CAD geometry component
- "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet",
- // Core
- "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo",
- // Distributed interactive simulation (DIS) component
- "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu",
- // Cube map environmental texturing component
- "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture",
- // Environmental effects component
- "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground",
- // Environmental sensor component
- "ProximitySensor", "TransformSensor", "VisibilitySensor",
- // Followers component
- "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", "PositionChaser2D",
- "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D",
- // Geospatial component
- "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor",
- "GeoTouchSensor", "GeoTransform", "GeoViewpoint",
- // Humanoid Animation (H-Anim) component
- "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite",
- // Interpolation component
- "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator",
- "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D",
- "SplineScalarInterpolator", "SquadOrientationInterpolator",
- // Key device sensor component
- "KeySensor", "StringSensor",
- // Layering component
- "Layer", "LayerSet", "Viewport",
- // Layout component
- "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup",
- // Navigation component
- "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup",
- // Networking component
- "EXPORT", "IMPORT", "Anchor", "LoadSensor",
- // NURBS component
- "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
- "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
- "NurbsTrimmedSurface",
- // Particle systems component
- "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", "SurfaceEmitter",
- "VolumeEmitter", "WindPhysicsModel",
- // Picking component
- "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor",
- // Pointing device sensor component
- "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor",
- // Rendering component
- "ClipPlane",
- // Rigid body physics
- "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint",
- "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint",
- // Scripting component
- "Script",
- // Programmable shaders component
- "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart",
- "ShaderProgram",
- // Shape component
- "FillProperties", "LineProperties", "TwoSidedMaterial",
- // Sound component
- "AudioClip", "Sound",
- // Text component
- "FontStyle", "Text",
- // Texturing3D Component
- "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", "TextureTransform3D",
- // Texturing component
- "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", "TextureProperties",
- // Time component
- "TimeSensor",
- // Event Utilities component
- "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger",
- // Volume rendering component
- "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", "IsoSurfaceVolumeData",
- "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle",
- "VolumeData"
- };
- const std::string nn = node.name();
- if (nn.empty()) {
- const std::string nv = node.value();
- if (!nv.empty()) {
- LogInfo("Ignoring comment \"" + nv + "\" in " + pParentNodeName + ".");
- return;
- }
- }
- bool found = false;
- for (size_t i = 0; i < Uns_Skip_Len; i++) {
- if (nn == Uns_Skip[i]) {
- found = true;
- }
- }
- if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
- LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + ".");
- }
- X3DImporter::X3DImporter() :
- mNodeElementCur(nullptr),
- mScene(nullptr),
- mpIOHandler(nullptr) {
- // empty
- }
- X3DImporter::~X3DImporter() {
- // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
- Clear();
- }
- void X3DImporter::Clear() {
- mNodeElementCur = nullptr;
- // Delete all elements
- if (!NodeElement_List.empty()) {
- for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
- delete *it;
- }
- NodeElement_List.clear();
- }
- }
- void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) {
- ai_assert(nullptr != pIOHandler);
- static const std::string mode = "rb";
- std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode));
- if (!fileStream) {
- throw DeadlyImportError("Failed to open file " + file + ".");
- }
- XmlParser theParser;
- if (!theParser.parse(fileStream.get())) {
- return;
- }
- ParseFile(theParser);
- }
- void X3DImporter::ParseFile(std::istream &myIstream) {
- XmlParser theParser;
- if (!theParser.parse(myIstream)) {
- LogInfo("ParseFile(): ERROR: failed to convert VRML istream to xml");
- return;
- }
- ParseFile(theParser);
- }
- void X3DImporter::ParseFile(XmlParser &theParser) {
- XmlNode *node = theParser.findNode("X3D");
- if (nullptr == node) {
- return;
- }
- for (auto ¤tNode : node->children()) {
- const std::string ¤tName = currentNode.name();
- if (currentName == "head") {
- readHead(currentNode);
- } else if (currentName == "Scene") {
- readScene(currentNode);
- } else {
- skipUnsupportedNode("X3D", currentNode);
- }
- }
- }
- bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
- if (checkSig) {
- if (GetExtension(pFile) == "x3d")
- return true;
- }
- return false;
- }
- void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
- mpIOHandler = pIOHandler;
- Clear();
- std::stringstream ss = ConvertVrmlFileToX3dXmlFile(pFile);
- const bool isReadFromMem{ ss.str().length() > 0 };
- if (!isReadFromMem) {
- std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
- if (!stream) {
- throw DeadlyImportError("Could not open file for reading");
- }
- }
- std::string::size_type slashPos = pFile.find_last_of("\\/");
- mScene = pScene;
- pScene->mRootNode = new aiNode(pFile);
- pScene->mRootNode->mParent = nullptr;
- pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
- if (isReadFromMem) {
- ParseFile(ss);
- } else {
- pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1));
- ParseFile(pFile, pIOHandler);
- pIOHandler->PopDirectory();
- }
- //search for root node element
- mNodeElementCur = NodeElement_List.front();
- if (mNodeElementCur == nullptr) {
- return;
- }
- while (mNodeElementCur->Parent != nullptr) {
- mNodeElementCur = mNodeElementCur->Parent;
- }
- { // fill aiScene with objects.
- std::list<aiMesh *> mesh_list;
- std::list<aiMaterial *> mat_list;
- std::list<aiLight *> light_list;
- // create nodes tree
- Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list);
- // copy needed data to scene
- if (!mesh_list.empty()) {
- std::list<aiMesh *>::const_iterator it = mesh_list.begin();
- pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
- pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
- for (size_t i = 0; i < pScene->mNumMeshes; i++)
- pScene->mMeshes[i] = *it++;
- }
- if (!mat_list.empty()) {
- std::list<aiMaterial *>::const_iterator it = mat_list.begin();
- pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size());
- pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
- for (size_t i = 0; i < pScene->mNumMaterials; i++)
- pScene->mMaterials[i] = *it++;
- }
- if (!light_list.empty()) {
- std::list<aiLight *>::const_iterator it = light_list.begin();
- pScene->mNumLights = static_cast<unsigned int>(light_list.size());
- pScene->mLights = new aiLight *[pScene->mNumLights];
- for (size_t i = 0; i < pScene->mNumLights; i++)
- pScene->mLights[i] = *it++;
- }
- }
- }
- const aiImporterDesc *X3DImporter::GetInfo() const {
- return &Description;
- }
- struct meta_entry {
- std::string name;
- std::string value;
- };
- void X3DImporter::readHead(XmlNode &node) {
- std::vector<meta_entry> metaArray;
- for (auto currentNode : node.children()) {
- const std::string ¤tName = currentNode.name();
- if (currentName == "meta") {
- //checkNodeMustBeEmpty(node);
- meta_entry entry;
- if (XmlParser::getStdStrAttribute(currentNode, "name", entry.name)) {
- XmlParser::getStdStrAttribute(currentNode, "content", entry.value);
- metaArray.emplace_back(entry);
- }
- }
- // TODO: check if other node types in head should be supported
- }
- mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size()));
- unsigned int i = 0;
- for (const auto& currentMeta : metaArray) {
- mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value));
- ++i;
- }
- }
- void X3DImporter::readChildNodes(XmlNode &node, const std::string &pParentNodeName) {
- if (node.empty()) {
- return;
- }
- for (auto currentNode : node.children()) {
- const std::string ¤tName = currentNode.name();
- if (currentName == "Shape")
- readShape(currentNode);
- else if (currentName == "Group") {
- startReadGroup(currentNode);
- readChildNodes(currentNode, "Group");
- endReadGroup();
- } else if (currentName == "StaticGroup") {
- startReadStaticGroup(currentNode);
- readChildNodes(currentNode, "StaticGroup");
- endReadStaticGroup();
- } else if (currentName == "Transform") {
- startReadTransform(currentNode);
- readChildNodes(currentNode, "Transform");
- endReadTransform();
- } else if (currentName == "Switch") {
- startReadSwitch(currentNode);
- readChildNodes(currentNode, "Switch");
- endReadSwitch();
- } else if (currentName == "DirectionalLight") {
- readDirectionalLight(currentNode);
- } else if (currentName == "PointLight") {
- readPointLight(currentNode);
- } else if (currentName == "SpotLight") {
- readSpotLight(currentNode);
- } else if (currentName == "Inline") {
- readInline(currentNode);
- } else if (!checkForMetadataNode(currentNode)) {
- skipUnsupportedNode(pParentNodeName, currentNode);
- }
- }
- }
- void X3DImporter::readScene(XmlNode &node) {
- ParseHelper_Group_Begin(true);
- readChildNodes(node, "Scene");
- ParseHelper_Node_Exit();
- }
- /*********************************************************************************************************************************************/
- /************************************************************ Functions: find set ************************************************************/
- /*********************************************************************************************************************************************/
- bool X3DImporter::FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
- for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) {
- if (((*it)->Type == pType) && ((*it)->ID == pID)) {
- if (pElement != nullptr) *pElement = *it;
- return true;
- }
- } // for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++)
- return false;
- }
- bool X3DImporter::FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
- const X3DElemType pType, X3DNodeElementBase **pElement) {
- bool found = false; // flag: true - if requested element is found.
- // Check if pStartNode - this is the element, we are looking for.
- if ((pStartNode->Type == pType) && (pStartNode->ID == pID)) {
- found = true;
- if (pElement != nullptr) {
- *pElement = pStartNode;
- }
- goto fne_fn_end;
- } // if((pStartNode->Type() == pType) && (pStartNode->ID() == pID))
- // Check childs of pStartNode.
- for (std::list<X3DNodeElementBase *>::iterator ch_it = pStartNode->Children.begin(); ch_it != pStartNode->Children.end(); ++ch_it) {
- found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement);
- if (found) {
- break;
- }
- } // for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = it->Children.begin(); ch_it != it->Children.end(); ch_it++)
- fne_fn_end:
- return found;
- }
- bool X3DImporter::FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) {
- X3DNodeElementBase *tnd = mNodeElementCur; // temporary pointer to node.
- bool static_search = false; // flag: true if searching in static node.
- // At first check if we have deal with static node. Go up through parent nodes and check flag.
- while (tnd != nullptr) {
- if (tnd->Type == X3DElemType::ENET_Group) {
- if (((X3DNodeElementGroup *)tnd)->Static) {
- static_search = true; // Flag found, stop walking up. Node with static flag will holded in tnd variable.
- break;
- }
- }
- tnd = tnd->Parent; // go up in graph.
- } // while (tnd != nullptr)
- // at now call appropriate search function.
- if (static_search) {
- return FindNodeElement_FromNode(tnd, pID, pType, pElement);
- } else {
- return FindNodeElement_FromRoot(pID, pType, pElement);
- }
- }
- /*********************************************************************************************************************************************/
- /************************************************************ Functions: parse set ***********************************************************/
- /*********************************************************************************************************************************************/
- void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) {
- X3DNodeElementGroup *new_group = new X3DNodeElementGroup(mNodeElementCur, pStatic); // create new node with current node as parent.
- // if we are adding not the root element then add new element to current element child list.
- if (mNodeElementCur != nullptr) {
- mNodeElementCur->Children.push_back(new_group);
- }
- NodeElement_List.push_back(new_group); // it's a new element - add it to list.
- mNodeElementCur = new_group; // switch current element to new one.
- }
- void X3DImporter::ParseHelper_Node_Enter(X3DNodeElementBase *pNode) {
- ai_assert(nullptr != pNode);
- mNodeElementCur->Children.push_back(pNode); // add new element to current element child list.
- mNodeElementCur = pNode; // switch current element to new one.
- }
- void X3DImporter::ParseHelper_Node_Exit() {
- // check if we can walk up.
- if (mNodeElementCur != nullptr) {
- mNodeElementCur = mNodeElementCur->Parent;
- }
- }
- } // namespace Assimp
- #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
|