Coverage Report

Created: 2026-01-25 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/AssetLib/X3D/X3DImporter.hpp
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2026, 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
#ifndef INCLUDED_AI_X3D_IMPORTER_H
42
#define INCLUDED_AI_X3D_IMPORTER_H
43
44
#include "X3DImporter_Node.hpp"
45
46
#include <assimp/BaseImporter.h>
47
#include <assimp/XmlParser.h>
48
#include <assimp/importerdesc.h>
49
#include <assimp/scene.h>
50
#include <assimp/types.h>
51
#include <assimp/DefaultLogger.hpp>
52
#include <assimp/ProgressHandler.hpp>
53
54
#include <list>
55
#include <string>
56
57
namespace Assimp {
58
AI_WONT_RETURN inline void Throw_ArgOutOfRange(const std::string &argument) AI_WONT_RETURN_SUFFIX;
59
AI_WONT_RETURN inline void Throw_CloseNotFound(const std::string &node) AI_WONT_RETURN_SUFFIX;
60
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrF(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
61
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrD(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
62
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrB(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
63
AI_WONT_RETURN inline void Throw_ConvertFail_Str2ArrI(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
64
AI_WONT_RETURN inline void Throw_DEF_And_USE(const std::string &nodeName) AI_WONT_RETURN_SUFFIX;
65
AI_WONT_RETURN inline void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
66
AI_WONT_RETURN inline void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) AI_WONT_RETURN_SUFFIX;
67
AI_WONT_RETURN inline void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) AI_WONT_RETURN_SUFFIX;
68
AI_WONT_RETURN inline void Throw_TagCountIncorrect(const std::string &pNode) AI_WONT_RETURN_SUFFIX;
69
AI_WONT_RETURN inline void Throw_USE_NotFound(const std::string &nodeName, const std::string &pAttrValue) AI_WONT_RETURN_SUFFIX;
70
71
0
inline void Throw_ArgOutOfRange(const std::string &argument) {
72
0
    throw DeadlyImportError("Argument value is out of range for: \"" + argument + "\".");
73
0
}
74
75
0
inline void Throw_CloseNotFound(const std::string &node) {
76
0
    throw DeadlyImportError("Close tag for node <" + node + "> not found. Seems file is corrupt.");
77
0
}
78
79
0
inline void Throw_ConvertFail_Str2ArrF(const std::string &nodeName, const std::string &pAttrValue) {
80
0
    throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
81
0
                            "\" from string to array of floats.");
82
0
}
83
84
0
inline void Throw_ConvertFail_Str2ArrD(const std::string &nodeName, const std::string &pAttrValue) {
85
0
    throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
86
0
                            "\" from string to array of doubles.");
87
0
}
88
89
0
inline void Throw_ConvertFail_Str2ArrB(const std::string &nodeName, const std::string &pAttrValue) {
90
0
    throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
91
0
                            "\" from string to array of booleans.");
92
0
}
93
94
0
inline void Throw_ConvertFail_Str2ArrI(const std::string &nodeName, const std::string &pAttrValue) {
95
0
    throw DeadlyImportError("In <" + nodeName + "> failed to convert attribute value \"" + pAttrValue +
96
0
                            "\" from string to array of integers.");
97
0
}
98
99
0
inline void Throw_DEF_And_USE(const std::string &nodeName) {
100
0
    throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + nodeName + ">.");
101
0
}
102
103
0
inline void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName) {
104
0
    throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + pAttrName + "\".");
105
0
}
106
107
0
inline void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName) {
108
0
    throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + nodeName + "> has incorrect value.");
109
0
}
110
111
0
inline void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) {
112
0
    throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription);
113
0
}
114
115
0
inline void Throw_TagCountIncorrect(const std::string &pNode) {
116
0
    throw DeadlyImportError("Count of open and close tags for node <" + pNode + "> are not equivalent. Seems file is corrupt.");
117
0
}
118
119
0
inline void Throw_USE_NotFound(const std::string &nodeName, const std::string &pAttrValue) {
120
0
    throw DeadlyImportError("Not found node with name \"" + pAttrValue + "\" in <" + nodeName + ">.");
121
0
}
122
123
0
inline void LogInfo(const std::string &message) {
124
0
    DefaultLogger::get()->info(message);
125
0
}
126
127
/// \class X3DImporter
128
/// Class that holding scene graph which include: groups, geometry, metadata etc.
129
///
130
/// Limitations.
131
///
132
/// Pay attention that X3D is format for interactive graphic and simulations for web browsers.
133
/// So not all features can be imported using Assimp.
134
///
135
/// Unsupported nodes:
136
///   CAD geometry component:
137
///     "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet"
138
///   Core component:
139
///     "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo"
140
///   Distributed interactive simulation (DIS) component:
141
///     "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu"
142
///   Cube map environmental texturing component:
143
///     "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture"
144
///   Environmental effects component:
145
///     "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground"
146
///   Environmental sensor component:
147
///     "ProximitySensor", "TransformSensor", "VisibilitySensor"
148
///   Followers component:
149
///     "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser",
150
///     "PositionChaser2D", "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D"
151
///   Geospatial component:
152
///     "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor",
153
///     "GeoTouchSensor", "GeoTransform", "GeoViewpoint"
154
///   Humanoid Animation (H-Anim) component:
155
///     "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite"
156
///   Interpolation component:
157
///     "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator",
158
///     "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D",
159
///     "SplineScalarInterpolator", "SquadOrientationInterpolator",
160
///   Key device sensor component:
161
///     "KeySensor", "StringSensor"
162
///   Layering component:
163
///     "Layer", "LayerSet", "Viewport"
164
///   Layout component:
165
///     "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup"
166
///   Navigation component:
167
///     "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup"
168
///   Networking component:
169
///     "EXPORT", "IMPORT", "Anchor", "LoadSensor"
170
///   NURBS component:
171
///     "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
172
///     "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
173
///     "NurbsTrimmedSurface"
174
///   Particle systems component:
175
///     "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter",
176
///     "SurfaceEmitter", "VolumeEmitter", "WindPhysicsModel"
177
///   Picking component:
178
///     "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor"
179
///   Pointing device sensor component:
180
///     "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor"
181
///   Rendering component:
182
///     "ClipPlane"
183
///   Rigid body physics:
184
///     "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint",
185
///     "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint"
186
///   Scripting component:
187
///     "Script"
188
///   Programmable shaders component:
189
///     "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart",
190
///     "ShaderProgram",
191
///   Shape component:
192
///     "FillProperties", "LineProperties", "TwoSidedMaterial"
193
///   Sound component:
194
///     "AudioClip", "Sound"
195
///   Text component:
196
///     "FontStyle", "Text"
197
///   Texturing3D Component:
198
///     "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D",
199
///     "TextureTransform3D"
200
///   Texturing component:
201
///     "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator",
202
///     "TextureProperties",
203
///   Time component:
204
///     "TimeSensor"
205
///   Event Utilities component:
206
///     "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger",
207
///   Volume rendering component:
208
///     "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle",
209
///     "IsoSurfaceVolumeData", "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle",
210
///     "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle", "VolumeData"
211
///
212
/// Supported nodes:
213
///   Core component:
214
///     "MetadataBoolean", "MetadataDouble", "MetadataFloat", "MetadataInteger", "MetadataSet", "MetadataString"
215
///   Geometry2D component:
216
///     "Arc2D", "ArcClose2D", "Circle2D", "Disk2D", "Polyline2D", "Polypoint2D", "Rectangle2D", "TriangleSet2D"
217
///   Geometry3D component:
218
///     "Box", "Cone", "Cylinder", "ElevationGrid", "Extrusion", "IndexedFaceSet", "Sphere"
219
///   Grouping component:
220
///     "Group", "StaticGroup", "Switch", "Transform"
221
///   Lighting component:
222
///     "DirectionalLight", "PointLight", "SpotLight"
223
///   Networking component:
224
///     "Inline"
225
///   Rendering component:
226
///     "Color", "ColorRGBA", "Coordinate", "IndexedLineSet", "IndexedTriangleFanSet", "IndexedTriangleSet", "IndexedTriangleStripSet", "LineSet",
227
///     "PointSet", "TriangleFanSet", "TriangleSet", "TriangleStripSet", "Normal"
228
///   Shape component:
229
///     "Shape", "Appearance", "Material"
230
///   Texturing component:
231
///     "ImageTexture", "TextureCoordinate", "TextureTransform"
232
///
233
/// Limitations of attribute "USE".
234
/// If "USE" is set then node must be empty, like that:
235
///   <Node USE='name'/>
236
/// not the
237
///   <Node USE='name'><!-- something --> </Node>
238
///
239
/// Ignored attributes: "creaseAngle", "convex", "solid".
240
///
241
/// Texture coordinates generating: only for Sphere, Cone, Cylinder. In all other case used PLANE mapping.
242
///   It's better that Assimp main code has powerful texture coordinates generator. Then is not needed to
243
///   duplicate this code in every importer.
244
///
245
/// Lighting limitations.
246
///   If light source placed in some group with "DEF" set. And after that some node is use it group with "USE" attribute then
247
///   you will get error about duplicate light sources. That's happening because Assimp require names for lights but do not like
248
///   duplicates of it )).
249
///
250
/// Color for faces.
251
/// That's happening when attribute "colorPerVertex" is set to "false". But Assimp do not hold how many colors has mesh and require
252
/// equal length for mVertices and mColors. You will see the colors but vertices will use call which last used in "colorIdx".
253
///
254
/// That's all for now. Enjoy
255
///
256
257
using X3DElementList = std::list<X3DNodeElementBase *>;
258
259
class X3DImporter : public BaseImporter {
260
public:
261
    std::list<X3DNodeElementBase *> NodeElement_List; ///< All elements of scene graph.
262
263
public:
264
    /// Default constructor.
265
    X3DImporter();
266
267
    /// Default destructor.
268
    ~X3DImporter();
269
270
    /***********************************************/
271
    /******** Functions: parse set, public *********/
272
    /***********************************************/
273
274
    /// Parse X3D file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
275
    /// Also exception can be thrown if trouble will found.
276
    /// \param [in] pFile - name of file to be parsed.
277
    /// \param [in] pIOHandler - pointer to IO helper object.
278
    void ParseFile(const std::string &file, IOSystem *pIOHandler);
279
    void ParseFile(std::istream &myIstream);
280
    void ParseFile(XmlParser &theParser);
281
    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
282
    void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
283
    const aiImporterDesc *GetInfo() const;
284
    void Clear();
285
286
private:
287
    X3DNodeElementBase *MACRO_USE_CHECKANDAPPLY(XmlNode &node, const std::string &pDEF, const std::string &pUSE, X3DElemType pType, X3DNodeElementBase *pNE);
288
    bool isNodeEmpty(XmlNode &node);
289
    void checkNodeMustBeEmpty(XmlNode &node);
290
    void skipUnsupportedNode(const std::string &pParentNodeName, XmlNode &node);
291
    void readHead(XmlNode &node);
292
    void readChildNodes(XmlNode &node, const std::string &pParentNodeName);
293
    void readScene(XmlNode &node);
294
295
    bool FindNodeElement_FromRoot(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
296
    bool FindNodeElement_FromNode(X3DNodeElementBase *pStartNode, const std::string &pID,
297
            const X3DElemType pType, X3DNodeElementBase **pElement);
298
    bool FindNodeElement(const std::string &pID, const X3DElemType pType, X3DNodeElementBase **pElement);
299
    void ParseHelper_Group_Begin(const bool pStatic = false);
300
    void ParseHelper_Node_Enter(X3DNodeElementBase *pNode);
301
    void ParseHelper_Node_Exit();
302
303
    // 2D geometry
304
    void readArc2D(XmlNode &node);
305
    void readArcClose2D(XmlNode &node);
306
    void readCircle2D(XmlNode &node);
307
    void readDisk2D(XmlNode &node);
308
    void readPolyline2D(XmlNode &node);
309
    void readPolypoint2D(XmlNode &node);
310
    void readRectangle2D(XmlNode &node);
311
    void readTriangleSet2D(XmlNode &node);
312
313
    // 3D geometry
314
    void readBox(XmlNode &node);
315
    void readCone(XmlNode &node);
316
    void readCylinder(XmlNode &node);
317
    void readElevationGrid(XmlNode &node);
318
    void readExtrusion(XmlNode &node);
319
    void readIndexedFaceSet(XmlNode &node);
320
    void readSphere(XmlNode &node);
321
322
    // group
323
    void startReadGroup(XmlNode &node);
324
    void endReadGroup();
325
    void startReadStaticGroup(XmlNode &node);
326
    void endReadStaticGroup();
327
    void startReadSwitch(XmlNode &node);
328
    void endReadSwitch();
329
    void startReadTransform(XmlNode &node);
330
    void endReadTransform();
331
332
    // light
333
    void readDirectionalLight(XmlNode &node);
334
    void readPointLight(XmlNode &node);
335
    void readSpotLight(XmlNode &node);
336
337
    // metadata
338
    bool checkForMetadataNode(XmlNode &node);
339
    void childrenReadMetadata(XmlNode &node, X3DNodeElementBase *pParentElement, const std::string &pNodeName);
340
    void readMetadataBoolean(XmlNode &node);
341
    void readMetadataDouble(XmlNode &node);
342
    void readMetadataFloat(XmlNode &node);
343
    void readMetadataInteger(XmlNode &node);
344
    void readMetadataSet(XmlNode &node);
345
    void readMetadataString(XmlNode &node);
346
347
    // networking
348
    void readInline(XmlNode &node);
349
350
    // postprocessing
351
    aiMatrix4x4 PostprocessHelper_Matrix_GlobalToCurrent() const;
352
    void PostprocessHelper_CollectMetadata(const X3DNodeElementBase &pNodeElement, std::list<X3DNodeElementBase *> &pList) const;
353
    bool PostprocessHelper_ElementIsMetadata(const X3DElemType pType) const;
354
    bool PostprocessHelper_ElementIsMesh(const X3DElemType pType) const;
355
    void Postprocess_BuildLight(const X3DNodeElementBase &pNodeElement, std::list<aiLight *> &pSceneLightList) const;
356
    void Postprocess_BuildMaterial(const X3DNodeElementBase &pNodeElement, aiMaterial **pMaterial) const;
357
    void Postprocess_BuildMesh(const X3DNodeElementBase &pNodeElement, aiMesh **pMesh) const;
358
    void Postprocess_BuildNode(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode, std::list<aiMesh *> &pSceneMeshList,
359
            std::list<aiMaterial *> &pSceneMaterialList, std::list<aiLight *> &pSceneLightList) const;
360
    void Postprocess_BuildShape(const X3DNodeElementShape &pShapeNodeElement, std::list<unsigned int> &pNodeMeshInd,
361
            std::list<aiMesh *> &pSceneMeshList, std::list<aiMaterial *> &pSceneMaterialList) const;
362
    void Postprocess_CollectMetadata(const X3DNodeElementBase &pNodeElement, aiNode &pSceneNode) const;
363
364
    // rendering
365
    void readColor(XmlNode &node);
366
    void readColorRGBA(XmlNode &node);
367
    void readCoordinate(XmlNode &node);
368
    void readIndexedLineSet(XmlNode &node);
369
    void readIndexedTriangleFanSet(XmlNode &node);
370
    void readIndexedTriangleSet(XmlNode &node);
371
    void readIndexedTriangleStripSet(XmlNode &node);
372
    void readLineSet(XmlNode &node);
373
    void readPointSet(XmlNode &node);
374
    void readTriangleFanSet(XmlNode &node);
375
    void readTriangleSet(XmlNode &node);
376
    void readTriangleStripSet(XmlNode &node);
377
    void readNormal(XmlNode &node);
378
379
    // shape
380
    void readShape(XmlNode &node);
381
    void readAppearance(XmlNode &node);
382
    void readMaterial(XmlNode &node);
383
384
    // texturing
385
    void readImageTexture(XmlNode &node);
386
    void readTextureCoordinate(XmlNode &node);
387
    void readTextureTransform(XmlNode &node);
388
389
    static const aiImporterDesc Description;
390
    X3DNodeElementBase *mNodeElementCur;
391
    aiScene *mScene;
392
    IOSystem *mpIOHandler;
393
}; // class X3DImporter
394
395
} // namespace Assimp
396
397
#endif // INCLUDED_AI_X3D_IMPORTER_H