/src/assimp/code/AssetLib/X3D/X3DImporter.cpp
Line | Count | Source |
1 | | /* |
2 | | Open Asset Import Library (assimp) |
3 | | ---------------------------------------------------------------------- |
4 | | |
5 | | Copyright (c) 2006-2025, assimp team |
6 | | |
7 | | All rights reserved. |
8 | | |
9 | | Redistribution and use of this software in source and binary forms, |
10 | | with or without modification, are permitted provided that the |
11 | | following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above |
14 | | copyright notice, this list of conditions and the |
15 | | following disclaimer. |
16 | | |
17 | | * Redistributions in binary form must reproduce the above |
18 | | copyright notice, this list of conditions and the |
19 | | following disclaimer in the documentation and/or other |
20 | | materials provided with the distribution. |
21 | | |
22 | | * Neither the name of the assimp team, nor the names of its |
23 | | contributors may be used to endorse or promote products |
24 | | derived from this software without specific prior |
25 | | written permission of the assimp team. |
26 | | |
27 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | | |
39 | | ---------------------------------------------------------------------- |
40 | | */ |
41 | | /// \file X3DImporter.cpp |
42 | | /// \brief X3D-format files importer for Assimp: main algorithm implementation. |
43 | | /// \date 2015-2016 |
44 | | /// \author smal.root@gmail.com |
45 | | |
46 | | #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER |
47 | | |
48 | | #include "AssetLib/VRML/VrmlConverter.hpp" |
49 | | #include "X3DImporter.hpp" |
50 | | #include "X3DImporter_Macro.hpp" |
51 | | |
52 | | #include <assimp/DefaultIOSystem.h> |
53 | | |
54 | | // Header files, stdlib. |
55 | | #include <iterator> |
56 | | #include <memory> |
57 | | |
58 | | #if defined(ASSIMP_BUILD_NO_VRML_IMPORTER) |
59 | | #define X3D_FORMATS_DESCR_STR "Extensible 3D(X3D, X3DB) Importer" |
60 | | #define X3D_FORMATS_EXTENSIONS_STR "x3d x3db" |
61 | | #else |
62 | | #define X3D_FORMATS_DESCR_STR "VRML(WRL, X3DV) and Extensible 3D(X3D, X3DB) Importer" |
63 | | #define X3D_FORMATS_EXTENSIONS_STR "wrl x3d x3db x3dv" |
64 | | #endif // #if defined(ASSIMP_BUILD_NO_VRML_IMPORTER) |
65 | | |
66 | | namespace Assimp { |
67 | | |
68 | | /// Constant which holds the importer description |
69 | | const aiImporterDesc X3DImporter::Description = { |
70 | | X3D_FORMATS_DESCR_STR, |
71 | | "smalcom", |
72 | | "", |
73 | | "See documentation in source code. Chapter: Limitations.", |
74 | | aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, |
75 | | 0, |
76 | | 0, |
77 | | 0, |
78 | | 0, |
79 | | X3D_FORMATS_EXTENSIONS_STR |
80 | | }; |
81 | | |
82 | 0 | bool X3DImporter::isNodeEmpty(XmlNode &node) { |
83 | 0 | return node.first_child().empty(); |
84 | 0 | } |
85 | | |
86 | 0 | void X3DImporter::checkNodeMustBeEmpty(XmlNode &node) { |
87 | 0 | if (!isNodeEmpty(node)) throw DeadlyImportError(std::string("Node <") + node.name() + "> must be empty."); |
88 | 0 | } |
89 | | |
90 | 0 | void X3DImporter::skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node) { |
91 | 0 | static const size_t Uns_Skip_Len = 192; |
92 | 0 | static constexpr char const * Uns_Skip[Uns_Skip_Len] = { |
93 | | // CAD geometry component |
94 | 0 | "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet", |
95 | | // Core |
96 | 0 | "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo", |
97 | | // Distributed interactive simulation (DIS) component |
98 | 0 | "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu", |
99 | | // Cube map environmental texturing component |
100 | 0 | "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture", |
101 | | // Environmental effects component |
102 | 0 | "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground", |
103 | | // Environmental sensor component |
104 | 0 | "ProximitySensor", "TransformSensor", "VisibilitySensor", |
105 | | // Followers component |
106 | 0 | "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", "PositionChaser2D", |
107 | 0 | "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D", |
108 | | // Geospatial component |
109 | 0 | "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor", |
110 | 0 | "GeoTouchSensor", "GeoTransform", "GeoViewpoint", |
111 | | // Humanoid Animation (H-Anim) component |
112 | 0 | "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite", |
113 | | // Interpolation component |
114 | 0 | "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator", |
115 | 0 | "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D", |
116 | 0 | "SplineScalarInterpolator", "SquadOrientationInterpolator", |
117 | | // Key device sensor component |
118 | 0 | "KeySensor", "StringSensor", |
119 | | // Layering component |
120 | 0 | "Layer", "LayerSet", "Viewport", |
121 | | // Layout component |
122 | 0 | "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup", |
123 | | // Navigation component |
124 | 0 | "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup", |
125 | | // Networking component |
126 | 0 | "EXPORT", "IMPORT", "Anchor", "LoadSensor", |
127 | | // NURBS component |
128 | 0 | "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface", |
129 | 0 | "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate", |
130 | 0 | "NurbsTrimmedSurface", |
131 | | // Particle systems component |
132 | 0 | "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", "SurfaceEmitter", |
133 | 0 | "VolumeEmitter", "WindPhysicsModel", |
134 | | // Picking component |
135 | 0 | "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor", |
136 | | // Pointing device sensor component |
137 | 0 | "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor", |
138 | | // Rendering component |
139 | 0 | "ClipPlane", |
140 | | // Rigid body physics |
141 | 0 | "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint", |
142 | 0 | "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint", |
143 | | // Scripting component |
144 | 0 | "Script", |
145 | | // Programmable shaders component |
146 | 0 | "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart", |
147 | 0 | "ShaderProgram", |
148 | | // Shape component |
149 | 0 | "FillProperties", "LineProperties", "TwoSidedMaterial", |
150 | | // Sound component |
151 | 0 | "AudioClip", "Sound", |
152 | | // Text component |
153 | 0 | "FontStyle", "Text", |
154 | | // Texturing3D Component |
155 | 0 | "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", "TextureTransform3D", |
156 | | // Texturing component |
157 | 0 | "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", "TextureProperties", |
158 | | // Time component |
159 | 0 | "TimeSensor", |
160 | | // Event Utilities component |
161 | 0 | "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger", |
162 | | // Volume rendering component |
163 | 0 | "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", "IsoSurfaceVolumeData", |
164 | 0 | "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle", |
165 | 0 | "VolumeData" |
166 | 0 | }; |
167 | |
|
168 | 0 | const std::string nn = node.name(); |
169 | |
|
170 | 0 | if (nn.empty()) { |
171 | 0 | const std::string nv = node.value(); |
172 | 0 | if (!nv.empty()) { |
173 | 0 | LogInfo("Ignoring comment \"" + nv + "\" in " + pParentNodeName + "."); |
174 | 0 | return; |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | 0 | bool found = false; |
179 | |
|
180 | 0 | for (size_t i = 0; i < Uns_Skip_Len; i++) { |
181 | 0 | if (nn == Uns_Skip[i]) { |
182 | 0 | found = true; |
183 | 0 | } |
184 | 0 | } |
185 | |
|
186 | 0 | if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + "."); |
187 | | |
188 | 0 | LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + "."); |
189 | 0 | } |
190 | | |
191 | | X3DImporter::X3DImporter() : |
192 | 891 | mNodeElementCur(nullptr), |
193 | 891 | mScene(nullptr), |
194 | 891 | mpIOHandler(nullptr) { |
195 | | // empty |
196 | 891 | } |
197 | | |
198 | 891 | X3DImporter::~X3DImporter() { |
199 | | // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. |
200 | 891 | Clear(); |
201 | 891 | } |
202 | | |
203 | 897 | void X3DImporter::Clear() { |
204 | 897 | mNodeElementCur = nullptr; |
205 | | // Delete all elements |
206 | 897 | if (!NodeElement_List.empty()) { |
207 | 0 | for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) { |
208 | 0 | delete *it; |
209 | 0 | } |
210 | 0 | NodeElement_List.clear(); |
211 | 0 | } |
212 | 897 | } |
213 | | |
214 | 6 | void X3DImporter::ParseFile(const std::string &file, IOSystem *pIOHandler) { |
215 | 6 | ai_assert(nullptr != pIOHandler); |
216 | | |
217 | 6 | static const std::string mode = "rb"; |
218 | 6 | std::unique_ptr<IOStream> fileStream(pIOHandler->Open(file, mode)); |
219 | 6 | if (!fileStream) { |
220 | 0 | throw DeadlyImportError("Failed to open file " + file + "."); |
221 | 0 | } |
222 | | |
223 | 6 | XmlParser theParser; |
224 | 6 | if (!theParser.parse(fileStream.get())) { |
225 | 6 | return; |
226 | 6 | } |
227 | 0 | ParseFile(theParser); |
228 | 0 | } |
229 | | |
230 | 0 | void X3DImporter::ParseFile(std::istream &myIstream) { |
231 | 0 | XmlParser theParser; |
232 | 0 | if (!theParser.parse(myIstream)) { |
233 | 0 | LogInfo("ParseFile(): ERROR: failed to convert VRML istream to xml"); |
234 | 0 | return; |
235 | 0 | } |
236 | 0 | ParseFile(theParser); |
237 | 0 | } |
238 | | |
239 | 0 | void X3DImporter::ParseFile(XmlParser &theParser) { |
240 | 0 | XmlNode *node = theParser.findNode("X3D"); |
241 | 0 | if (nullptr == node) { |
242 | 0 | return; |
243 | 0 | } |
244 | | |
245 | 0 | for (auto ¤tNode : node->children()) { |
246 | 0 | const std::string ¤tName = currentNode.name(); |
247 | 0 | if (currentName == "head") { |
248 | 0 | readHead(currentNode); |
249 | 0 | } else if (currentName == "Scene") { |
250 | 0 | readScene(currentNode); |
251 | 0 | } else { |
252 | 0 | skipUnsupportedNode("X3D", currentNode); |
253 | 0 | } |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | 82 | bool X3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool checkSig) const { |
258 | 82 | if (checkSig) { |
259 | 82 | if (GetExtension(pFile) == "x3d") |
260 | 0 | return true; |
261 | 82 | } |
262 | | |
263 | 82 | return false; |
264 | 82 | } |
265 | | |
266 | 6 | void X3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { |
267 | 6 | mpIOHandler = pIOHandler; |
268 | | |
269 | 6 | Clear(); |
270 | 6 | std::stringstream ss = ConvertVrmlFileToX3dXmlFile(pFile); |
271 | 6 | const bool isReadFromMem{ ss.str().length() > 0 }; |
272 | 6 | if (!isReadFromMem) { |
273 | 6 | std::shared_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb")); |
274 | 6 | if (!stream) { |
275 | 0 | throw DeadlyImportError("Could not open file for reading"); |
276 | 0 | } |
277 | 6 | } |
278 | 6 | std::string::size_type slashPos = pFile.find_last_of("\\/"); |
279 | | |
280 | 6 | mScene = pScene; |
281 | 6 | pScene->mRootNode = new aiNode(pFile); |
282 | 6 | pScene->mRootNode->mParent = nullptr; |
283 | 6 | pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED; |
284 | | |
285 | 6 | if (isReadFromMem) { |
286 | 0 | ParseFile(ss); |
287 | 6 | } else { |
288 | 6 | pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1)); |
289 | 6 | ParseFile(pFile, pIOHandler); |
290 | 6 | pIOHandler->PopDirectory(); |
291 | 6 | } |
292 | | |
293 | | //search for root node element |
294 | | |
295 | 6 | mNodeElementCur = NodeElement_List.front(); |
296 | 6 | if (mNodeElementCur == nullptr) { |
297 | 6 | return; |
298 | 6 | } |
299 | 0 | while (mNodeElementCur->Parent != nullptr) { |
300 | 0 | mNodeElementCur = mNodeElementCur->Parent; |
301 | 0 | } |
302 | |
|
303 | 0 | { // fill aiScene with objects. |
304 | 0 | std::list<aiMesh *> mesh_list; |
305 | 0 | std::list<aiMaterial *> mat_list; |
306 | 0 | std::list<aiLight *> light_list; |
307 | | |
308 | | // create nodes tree |
309 | 0 | Postprocess_BuildNode(*mNodeElementCur, *pScene->mRootNode, mesh_list, mat_list, light_list); |
310 | | // copy needed data to scene |
311 | 0 | if (!mesh_list.empty()) { |
312 | 0 | std::list<aiMesh *>::const_iterator it = mesh_list.begin(); |
313 | |
|
314 | 0 | pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size()); |
315 | 0 | pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; |
316 | 0 | for (size_t i = 0; i < pScene->mNumMeshes; i++) |
317 | 0 | pScene->mMeshes[i] = *it++; |
318 | 0 | } |
319 | |
|
320 | 0 | if (!mat_list.empty()) { |
321 | 0 | std::list<aiMaterial *>::const_iterator it = mat_list.begin(); |
322 | |
|
323 | 0 | pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size()); |
324 | 0 | pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; |
325 | 0 | for (size_t i = 0; i < pScene->mNumMaterials; i++) |
326 | 0 | pScene->mMaterials[i] = *it++; |
327 | 0 | } |
328 | |
|
329 | 0 | if (!light_list.empty()) { |
330 | 0 | std::list<aiLight *>::const_iterator it = light_list.begin(); |
331 | |
|
332 | 0 | pScene->mNumLights = static_cast<unsigned int>(light_list.size()); |
333 | 0 | pScene->mLights = new aiLight *[pScene->mNumLights]; |
334 | 0 | for (size_t i = 0; i < pScene->mNumLights; i++) |
335 | 0 | pScene->mLights[i] = *it++; |
336 | 0 | } |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | 883 | const aiImporterDesc *X3DImporter::GetInfo() const { |
341 | 883 | return &Description; |
342 | 883 | } |
343 | | |
344 | | struct meta_entry { |
345 | | std::string name; |
346 | | std::string value; |
347 | | }; |
348 | | |
349 | 0 | void X3DImporter::readHead(XmlNode &node) { |
350 | 0 | std::vector<meta_entry> metaArray; |
351 | 0 | for (auto currentNode : node.children()) { |
352 | 0 | const std::string ¤tName = currentNode.name(); |
353 | 0 | if (currentName == "meta") { |
354 | | //checkNodeMustBeEmpty(node); |
355 | 0 | meta_entry entry; |
356 | 0 | if (XmlParser::getStdStrAttribute(currentNode, "name", entry.name)) { |
357 | 0 | XmlParser::getStdStrAttribute(currentNode, "content", entry.value); |
358 | 0 | metaArray.emplace_back(entry); |
359 | 0 | } |
360 | 0 | } |
361 | | // TODO: check if other node types in head should be supported |
362 | 0 | } |
363 | 0 | mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size())); |
364 | 0 | unsigned int i = 0; |
365 | 0 | for (const auto& currentMeta : metaArray) { |
366 | 0 | mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value)); |
367 | 0 | ++i; |
368 | 0 | } |
369 | 0 | } |
370 | | |
371 | 0 | void X3DImporter::readChildNodes(XmlNode &node, const std::string &pParentNodeName) { |
372 | 0 | if (node.empty()) { |
373 | 0 | return; |
374 | 0 | } |
375 | 0 | for (auto currentNode : node.children()) { |
376 | 0 | const std::string ¤tName = currentNode.name(); |
377 | 0 | if (currentName == "Shape") |
378 | 0 | readShape(currentNode); |
379 | 0 | else if (currentName == "Group") { |
380 | 0 | startReadGroup(currentNode); |
381 | 0 | readChildNodes(currentNode, "Group"); |
382 | 0 | endReadGroup(); |
383 | 0 | } else if (currentName == "StaticGroup") { |
384 | 0 | startReadStaticGroup(currentNode); |
385 | 0 | readChildNodes(currentNode, "StaticGroup"); |
386 | 0 | endReadStaticGroup(); |
387 | 0 | } else if (currentName == "Transform") { |
388 | 0 | startReadTransform(currentNode); |
389 | 0 | readChildNodes(currentNode, "Transform"); |
390 | 0 | endReadTransform(); |
391 | 0 | } else if (currentName == "Switch") { |
392 | 0 | startReadSwitch(currentNode); |
393 | 0 | readChildNodes(currentNode, "Switch"); |
394 | 0 | endReadSwitch(); |
395 | 0 | } else if (currentName == "DirectionalLight") { |
396 | 0 | readDirectionalLight(currentNode); |
397 | 0 | } else if (currentName == "PointLight") { |
398 | 0 | readPointLight(currentNode); |
399 | 0 | } else if (currentName == "SpotLight") { |
400 | 0 | readSpotLight(currentNode); |
401 | 0 | } else if (currentName == "Inline") { |
402 | 0 | readInline(currentNode); |
403 | 0 | } else if (!checkForMetadataNode(currentNode)) { |
404 | 0 | skipUnsupportedNode(pParentNodeName, currentNode); |
405 | 0 | } |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | 0 | void X3DImporter::readScene(XmlNode &node) { |
410 | 0 | ParseHelper_Group_Begin(true); |
411 | 0 | readChildNodes(node, "Scene"); |
412 | 0 | ParseHelper_Node_Exit(); |
413 | 0 | } |
414 | | |
415 | | /*********************************************************************************************************************************************/ |
416 | | /************************************************************ Functions: find set ************************************************************/ |
417 | | /*********************************************************************************************************************************************/ |
418 | | |
419 | 0 | bool X3DImporter::FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) { |
420 | 0 | for (std::list<X3DNodeElementBase *>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) { |
421 | 0 | if (((*it)->Type == pType) && ((*it)->ID == pID)) { |
422 | 0 | if (pElement != nullptr) *pElement = *it; |
423 | |
|
424 | 0 | return true; |
425 | 0 | } |
426 | 0 | } // for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) |
427 | | |
428 | 0 | return false; |
429 | 0 | } |
430 | | |
431 | | bool X3DImporter::FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID, |
432 | 0 | const X3DElemType pType, X3DNodeElementBase **pElement) { |
433 | 0 | bool found = false; // flag: true - if requested element is found. |
434 | | |
435 | | // Check if pStartNode - this is the element, we are looking for. |
436 | 0 | if ((pStartNode->Type == pType) && (pStartNode->ID == pID)) { |
437 | 0 | found = true; |
438 | 0 | if (pElement != nullptr) { |
439 | 0 | *pElement = pStartNode; |
440 | 0 | } |
441 | |
|
442 | 0 | goto fne_fn_end; |
443 | 0 | } // if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) |
444 | | |
445 | | // Check childs of pStartNode. |
446 | 0 | for (std::list<X3DNodeElementBase *>::iterator ch_it = pStartNode->Children.begin(); ch_it != pStartNode->Children.end(); ++ch_it) { |
447 | 0 | found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement); |
448 | 0 | if (found) { |
449 | 0 | break; |
450 | 0 | } |
451 | 0 | } // for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = it->Children.begin(); ch_it != it->Children.end(); ch_it++) |
452 | |
|
453 | 0 | fne_fn_end: |
454 | |
|
455 | 0 | return found; |
456 | 0 | } |
457 | | |
458 | 0 | bool X3DImporter::FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement) { |
459 | 0 | X3DNodeElementBase *tnd = mNodeElementCur; // temporary pointer to node. |
460 | 0 | bool static_search = false; // flag: true if searching in static node. |
461 | | |
462 | | // At first check if we have deal with static node. Go up through parent nodes and check flag. |
463 | 0 | while (tnd != nullptr) { |
464 | 0 | if (tnd->Type == X3DElemType::ENET_Group) { |
465 | 0 | if (((X3DNodeElementGroup *)tnd)->Static) { |
466 | 0 | static_search = true; // Flag found, stop walking up. Node with static flag will holded in tnd variable. |
467 | 0 | break; |
468 | 0 | } |
469 | 0 | } |
470 | | |
471 | 0 | tnd = tnd->Parent; // go up in graph. |
472 | 0 | } // while (tnd != nullptr) |
473 | | |
474 | | // at now call appropriate search function. |
475 | 0 | if (static_search) { |
476 | 0 | return FindNodeElement_FromNode(tnd, pID, pType, pElement); |
477 | 0 | } else { |
478 | 0 | return FindNodeElement_FromRoot(pID, pType, pElement); |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | /*********************************************************************************************************************************************/ |
483 | | /************************************************************ Functions: parse set ***********************************************************/ |
484 | | /*********************************************************************************************************************************************/ |
485 | | |
486 | 0 | void X3DImporter::ParseHelper_Group_Begin(const bool pStatic) { |
487 | 0 | X3DNodeElementGroup *new_group = new X3DNodeElementGroup(mNodeElementCur, pStatic); // create new node with current node as parent. |
488 | | |
489 | | // if we are adding not the root element then add new element to current element child list. |
490 | 0 | if (mNodeElementCur != nullptr) { |
491 | 0 | mNodeElementCur->Children.push_back(new_group); |
492 | 0 | } |
493 | |
|
494 | 0 | NodeElement_List.push_back(new_group); // it's a new element - add it to list. |
495 | 0 | mNodeElementCur = new_group; // switch current element to new one. |
496 | 0 | } |
497 | | |
498 | 0 | void X3DImporter::ParseHelper_Node_Enter(X3DNodeElementBase *pNode) { |
499 | 0 | ai_assert(nullptr != pNode); |
500 | |
|
501 | 0 | mNodeElementCur->Children.push_back(pNode); // add new element to current element child list. |
502 | 0 | mNodeElementCur = pNode; // switch current element to new one. |
503 | 0 | } |
504 | | |
505 | 0 | void X3DImporter::ParseHelper_Node_Exit() { |
506 | | // check if we can walk up. |
507 | 0 | if (mNodeElementCur != nullptr) { |
508 | 0 | mNodeElementCur = mNodeElementCur->Parent; |
509 | 0 | } |
510 | 0 | } |
511 | | |
512 | | } // namespace Assimp |
513 | | |
514 | | #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER |