1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4
5 Copyright (c) 2006-2017, 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_Postprocess.cpp
42 /// \brief Convert built scenegraph and objects to Assimp scenegraph.
43 /// \date 2015-2016
44 /// \author smal.root@gmail.com
45
46 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
47
48 #include "X3DImporter.hpp"
49
50 // Header files, Assimp.
51 #include <assimp/ai_assert.h>
52 #include "StandardShapes.h"
53 #include "StringUtils.h"
54
55 // Header files, stdlib.
56 #include <algorithm>
57 #include <iterator>
58 #include <string>
59
60 namespace Assimp
61 {
62
PostprocessHelper_Matrix_GlobalToCurrent() const63 aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const
64 {
65 CX3DImporter_NodeElement* cur_node;
66 std::list<aiMatrix4x4> matr;
67 aiMatrix4x4 out_matr;
68
69 // starting walk from current element to root
70 cur_node = NodeElement_Cur;
71 if(cur_node != nullptr)
72 {
73 do
74 {
75 // if cur_node is group then store group transformation matrix in list.
76 if(cur_node->Type == CX3DImporter_NodeElement::ENET_Group) matr.push_back(((CX3DImporter_NodeElement_Group*)cur_node)->Transformation);
77
78 cur_node = cur_node->Parent;
79 } while(cur_node != nullptr);
80 }
81
82 // multiplicate all matrices in reverse order
83 for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit);
84
85 return out_matr;
86 }
87
PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement & pNodeElement,std::list<CX3DImporter_NodeElement * > & pList) const88 void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list<CX3DImporter_NodeElement*>& pList) const
89 {
90 // walk through childs and find for metadata.
91 for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
92 {
93 if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) ||
94 ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) ||
95 ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaString))
96 {
97 pList.push_back(*el_it);
98 }
99 else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaSet)
100 {
101 PostprocessHelper_CollectMetadata(**el_it, pList);
102 }
103 }// for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
104 }
105
PostprocessHelper_ElementIsMetadata(const CX3DImporter_NodeElement::EType pType) const106 bool X3DImporter::PostprocessHelper_ElementIsMetadata(const CX3DImporter_NodeElement::EType pType) const
107 {
108 if((pType == CX3DImporter_NodeElement::ENET_MetaBoolean) || (pType == CX3DImporter_NodeElement::ENET_MetaDouble) ||
109 (pType == CX3DImporter_NodeElement::ENET_MetaFloat) || (pType == CX3DImporter_NodeElement::ENET_MetaInteger) ||
110 (pType == CX3DImporter_NodeElement::ENET_MetaString) || (pType == CX3DImporter_NodeElement::ENET_MetaSet))
111 {
112 return true;
113 }
114 else
115 {
116 return false;
117 }
118 }
119
PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement::EType pType) const120 bool X3DImporter::PostprocessHelper_ElementIsMesh(const CX3DImporter_NodeElement::EType pType) const
121 {
122 if((pType == CX3DImporter_NodeElement::ENET_Arc2D) || (pType == CX3DImporter_NodeElement::ENET_ArcClose2D) ||
123 (pType == CX3DImporter_NodeElement::ENET_Box) || (pType == CX3DImporter_NodeElement::ENET_Circle2D) ||
124 (pType == CX3DImporter_NodeElement::ENET_Cone) || (pType == CX3DImporter_NodeElement::ENET_Cylinder) ||
125 (pType == CX3DImporter_NodeElement::ENET_Disk2D) || (pType == CX3DImporter_NodeElement::ENET_ElevationGrid) ||
126 (pType == CX3DImporter_NodeElement::ENET_Extrusion) || (pType == CX3DImporter_NodeElement::ENET_IndexedFaceSet) ||
127 (pType == CX3DImporter_NodeElement::ENET_IndexedLineSet) || (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) ||
128 (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleSet) || (pType == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet) ||
129 (pType == CX3DImporter_NodeElement::ENET_PointSet) || (pType == CX3DImporter_NodeElement::ENET_LineSet) ||
130 (pType == CX3DImporter_NodeElement::ENET_Polyline2D) || (pType == CX3DImporter_NodeElement::ENET_Polypoint2D) ||
131 (pType == CX3DImporter_NodeElement::ENET_Rectangle2D) || (pType == CX3DImporter_NodeElement::ENET_Sphere) ||
132 (pType == CX3DImporter_NodeElement::ENET_TriangleFanSet) || (pType == CX3DImporter_NodeElement::ENET_TriangleSet) ||
133 (pType == CX3DImporter_NodeElement::ENET_TriangleSet2D) || (pType == CX3DImporter_NodeElement::ENET_TriangleStripSet))
134 {
135 return true;
136 }
137 else
138 {
139 return false;
140 }
141 }
142
Postprocess_BuildLight(const CX3DImporter_NodeElement & pNodeElement,std::list<aiLight * > & pSceneLightList) const143 void X3DImporter::Postprocess_BuildLight(const CX3DImporter_NodeElement& pNodeElement, std::list<aiLight*>& pSceneLightList) const
144 {
145 const CX3DImporter_NodeElement_Light& ne = *( ( CX3DImporter_NodeElement_Light* ) &pNodeElement );
146 aiMatrix4x4 transform_matr = PostprocessHelper_Matrix_GlobalToCurrent();
147 aiLight* new_light = new aiLight;
148
149 new_light->mName = ne.ID;
150 new_light->mColorAmbient = ne.Color * ne.AmbientIntensity;
151 new_light->mColorDiffuse = ne.Color * ne.Intensity;
152 new_light->mColorSpecular = ne.Color * ne.Intensity;
153 switch(pNodeElement.Type)
154 {
155 case CX3DImporter_NodeElement::ENET_DirectionalLight:
156 new_light->mType = aiLightSource_DIRECTIONAL;
157 new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
158
159 break;
160 case CX3DImporter_NodeElement::ENET_PointLight:
161 new_light->mType = aiLightSource_POINT;
162 new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
163 new_light->mAttenuationConstant = ne.Attenuation.x;
164 new_light->mAttenuationLinear = ne.Attenuation.y;
165 new_light->mAttenuationQuadratic = ne.Attenuation.z;
166
167 break;
168 case CX3DImporter_NodeElement::ENET_SpotLight:
169 new_light->mType = aiLightSource_SPOT;
170 new_light->mPosition = ne.Location, new_light->mPosition *= transform_matr;
171 new_light->mDirection = ne.Direction, new_light->mDirection *= transform_matr;
172 new_light->mAttenuationConstant = ne.Attenuation.x;
173 new_light->mAttenuationLinear = ne.Attenuation.y;
174 new_light->mAttenuationQuadratic = ne.Attenuation.z;
175 new_light->mAngleInnerCone = ne.BeamWidth;
176 new_light->mAngleOuterCone = ne.CutOffAngle;
177
178 break;
179 default:
180 throw DeadlyImportError("Postprocess_BuildLight. Unknown type of light: " + to_string(pNodeElement.Type) + ".");
181 }
182
183 pSceneLightList.push_back(new_light);
184 }
185
Postprocess_BuildMaterial(const CX3DImporter_NodeElement & pNodeElement,aiMaterial ** pMaterial) const186 void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNodeElement, aiMaterial** pMaterial) const
187 {
188 // check argument
189 if(pMaterial == nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. pMaterial is nullptr.");
190 if(*pMaterial != nullptr) throw DeadlyImportError("Postprocess_BuildMaterial. *pMaterial must be nullptr.");
191
192 *pMaterial = new aiMaterial;
193 aiMaterial& taimat = **pMaterial;// creating alias for convenience.
194
195 // at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data.
196 for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
197 {
198 if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material)
199 {
200 aiColor3D tcol3;
201 float tvalf;
202 CX3DImporter_NodeElement_Material& tnemat = *((CX3DImporter_NodeElement_Material*)*el_it);
203
204 tcol3.r = tnemat.AmbientIntensity, tcol3.g = tnemat.AmbientIntensity, tcol3.b = tnemat.AmbientIntensity;
205 taimat.AddProperty(&tcol3, 1, AI_MATKEY_COLOR_AMBIENT);
206 taimat.AddProperty(&tnemat.DiffuseColor, 1, AI_MATKEY_COLOR_DIFFUSE);
207 taimat.AddProperty(&tnemat.EmissiveColor, 1, AI_MATKEY_COLOR_EMISSIVE);
208 taimat.AddProperty(&tnemat.SpecularColor, 1, AI_MATKEY_COLOR_SPECULAR);
209 tvalf = 1;
210 taimat.AddProperty(&tvalf, 1, AI_MATKEY_SHININESS_STRENGTH);
211 taimat.AddProperty(&tnemat.Shininess, 1, AI_MATKEY_SHININESS);
212 tvalf = 1.0f - tnemat.Transparency;
213 taimat.AddProperty(&tvalf, 1, AI_MATKEY_OPACITY);
214 }// if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material)
215 else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture)
216 {
217 CX3DImporter_NodeElement_ImageTexture& tnetex = *((CX3DImporter_NodeElement_ImageTexture*)*el_it);
218 aiString url_str(tnetex.URL.c_str());
219 int mode = aiTextureOp_Multiply;
220
221 taimat.AddProperty(&url_str, AI_MATKEY_TEXTURE_DIFFUSE(0));
222 taimat.AddProperty(&tnetex.RepeatS, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
223 taimat.AddProperty(&tnetex.RepeatT, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
224 taimat.AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
225 }// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_ImageTexture)
226 else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_TextureTransform)
227 {
228 aiUVTransform trans;
229 CX3DImporter_NodeElement_TextureTransform& tnetextr = *((CX3DImporter_NodeElement_TextureTransform*)*el_it);
230
231 trans.mTranslation = tnetextr.Translation - tnetextr.Center;
232 trans.mScaling = tnetextr.Scale;
233 trans.mRotation = tnetextr.Rotation;
234 taimat.AddProperty(&trans, 1, AI_MATKEY_UVTRANSFORM_DIFFUSE(0));
235 }// else if((*el_it)->Type == CX3DImporter_NodeElement::ENET_TextureTransform)
236 }// for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++)
237 }
238
Postprocess_BuildMesh(const CX3DImporter_NodeElement & pNodeElement,aiMesh ** pMesh) const239 void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeElement, aiMesh** pMesh) const
240 {
241 // check argument
242 if(pMesh == nullptr) throw DeadlyImportError("Postprocess_BuildMesh. pMesh is nullptr.");
243 if(*pMesh != nullptr) throw DeadlyImportError("Postprocess_BuildMesh. *pMesh must be nullptr.");
244
245 /************************************************************************************************************************************/
246 /************************************************************ Geometry2D ************************************************************/
247 /************************************************************************************************************************************/
248 if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_Arc2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_ArcClose2D) ||
249 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Circle2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Disk2D) ||
250 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Polyline2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Polypoint2D) ||
251 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Rectangle2D) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet2D))
252 {
253 CX3DImporter_NodeElement_Geometry2D& tnemesh = *((CX3DImporter_NodeElement_Geometry2D*)&pNodeElement);// create alias for convenience
254 std::vector<aiVector3D> tarr;
255
256 tarr.reserve(tnemesh.Vertices.size());
257 for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it);
258 *pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
259
260 return;// mesh is build, nothing to do anymore.
261 }
262 /************************************************************************************************************************************/
263 /************************************************************ Geometry3D ************************************************************/
264 /************************************************************************************************************************************/
265 //
266 // Predefined figures
267 //
268 if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_Box) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Cone) ||
269 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Cylinder) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_Sphere))
270 {
271 CX3DImporter_NodeElement_Geometry3D& tnemesh = *((CX3DImporter_NodeElement_Geometry3D*)&pNodeElement);// create alias for convenience
272 std::vector<aiVector3D> tarr;
273
274 tarr.reserve(tnemesh.Vertices.size());
275 for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it);
276
277 *pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
278
279 return;// mesh is build, nothing to do anymore.
280 }
281 //
282 // Parametric figures
283 //
284 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid)
285 {
286 CX3DImporter_NodeElement_ElevationGrid& tnemesh = *((CX3DImporter_NodeElement_ElevationGrid*)&pNodeElement);// create alias for convenience
287
288 // at first create mesh from existing vertices.
289 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices);
290 // copy additional information from children
291 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
292 {
293 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
294 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
295 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
296 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
297 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
298 MeshGeometry_AddNormal(**pMesh, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value, tnemesh.NormalPerVertex);
299 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
300 MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
301 else
302 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + ".");
303 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
304
305 return;// mesh is build, nothing to do anymore.
306 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid)
307 //
308 // Indexed primitives sets
309 //
310 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet)
311 {
312 CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
313
314 // at first search for <Coordinate> node and create mesh.
315 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
316 {
317 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
318 {
319 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
320 }
321 }
322
323 // copy additional information from children
324 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
325 {
326 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
327 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
328 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
329 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value,
330 tnemesh.ColorPerVertex);
331 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
332 {} // skip because already read when mesh created.
333 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
334 MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value,
335 tnemesh.NormalPerVertex);
336 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
337 MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
338 else
339 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + ".");
340 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
341
342 return;// mesh is build, nothing to do anymore.
343 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet)
344
345 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet)
346 {
347 CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
348
349 // at first search for <Coordinate> node and create mesh.
350 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
351 {
352 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
353 {
354 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
355 }
356 }
357
358 // copy additional information from children
359 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
360 {
361 ai_assert(*pMesh);
362 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
363 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
364 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
365 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value,
366 tnemesh.ColorPerVertex);
367 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
368 {} // skip because already read when mesh created.
369 else
370 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + ".");
371 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
372
373 return;// mesh is build, nothing to do anymore.
374 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet)
375
376 if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleSet) ||
377 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) ||
378 (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet))
379 {
380 CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
381
382 // at first search for <Coordinate> node and create mesh.
383 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
384 {
385 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
386 {
387 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
388 }
389 }
390
391 // copy additional information from children
392 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
393 {
394 ai_assert(*pMesh);
395 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
396 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
397 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
398 MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value,
399 tnemesh.ColorPerVertex);
400 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
401 {} // skip because already read when mesh created.
402 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
403 MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value,
404 tnemesh.NormalPerVertex);
405 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
406 MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
407 else
408 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \
409 IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + ".");
410 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
411
412 return;// mesh is build, nothing to do anymore.
413 }// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet))
414
415 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Extrusion)
416 {
417 CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
418
419 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, tnemesh.Vertices);
420
421 return;// mesh is build, nothing to do anymore.
422 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Extrusion)
423
424 //
425 // Primitives sets
426 //
427 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet)
428 {
429 CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
430
431 // at first search for <Coordinate> node and create mesh.
432 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
433 {
434 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
435 {
436 std::vector<aiVector3D> vec_copy;
437
438 vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size());
439 for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin();
440 it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++)
441 {
442 vec_copy.push_back(*it);
443 }
444
445 *pMesh = StandardShapes::MakeMesh(vec_copy, 1);
446 }
447 }
448
449 // copy additional information from children
450 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
451 {
452 ai_assert(*pMesh);
453 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
454 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true);
455 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
456 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, true);
457 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
458 {} // skip because already read when mesh created.
459 else
460 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + ".");
461 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
462
463 return;// mesh is build, nothing to do anymore.
464 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet)
465
466 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet)
467 {
468 CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
469
470 // at first search for <Coordinate> node and create mesh.
471 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
472 {
473 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
474 {
475 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
476 }
477 }
478
479 // copy additional information from children
480 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
481 {
482 ai_assert(*pMesh);
483 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
484 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, true);
485 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
486 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, true);
487 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
488 {} // skip because already read when mesh created.
489 else
490 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + ".");
491 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
492
493 return;// mesh is build, nothing to do anymore.
494 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet)
495
496 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet)
497 {
498 CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
499
500 // at first search for <Coordinate> node and create mesh.
501 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
502 {
503 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
504 {
505 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
506 }
507 }
508
509 // copy additional information from children
510 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
511 {
512 if ( nullptr == *pMesh ) {
513 break;
514 }
515 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
516 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value,tnemesh.ColorPerVertex);
517 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
518 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
519 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
520 {} // skip because already read when mesh created.
521 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
522 MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value,
523 tnemesh.NormalPerVertex);
524 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
525 MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
526 else
527 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + ".");
528 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
529
530 return;// mesh is build, nothing to do anymore.
531 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet)
532
533 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet)
534 {
535 CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
536
537 // at first search for <Coordinate> node and create mesh.
538 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
539 {
540 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
541 {
542 std::vector<aiVector3D> vec_copy;
543
544 vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size());
545 for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin();
546 it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++)
547 {
548 vec_copy.push_back(*it);
549 }
550
551 *pMesh = StandardShapes::MakeMesh(vec_copy, 3);
552 }
553 }
554
555 // copy additional information from children
556 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
557 {
558 ai_assert(*pMesh);
559 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
560 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
561 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
562 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
563 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
564 {} // skip because already read when mesh created.
565 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
566 MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value,
567 tnemesh.NormalPerVertex);
568 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
569 MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
570 else
571 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + ".");
572 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
573
574 return;// mesh is build, nothing to do anymore.
575 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet)
576
577 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet)
578 {
579 CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
580
581 // at first search for <Coordinate> node and create mesh.
582 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
583 {
584 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
585 {
586 *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIndex, ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value);
587 }
588 }
589
590 // copy additional information from children
591 for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
592 {
593 ai_assert(*pMesh);
594 if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
595 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
596 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA)
597 MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_ColorRGBA*)*ch_it)->Value, tnemesh.ColorPerVertex);
598 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
599 {} // skip because already read when mesh created.
600 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Normal)
601 MeshGeometry_AddNormal(**pMesh, tnemesh.CoordIndex, tnemesh.NormalIndex, ((CX3DImporter_NodeElement_Normal*)*ch_it)->Value,
602 tnemesh.NormalPerVertex);
603 else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_TextureCoordinate)
604 MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
605 else
606 throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + ".");
607 }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++)
608
609 return;// mesh is build, nothing to do anymore.
610 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet)
611
612 throw DeadlyImportError("Postprocess_BuildMesh. Unknown mesh type: " + to_string(pNodeElement.Type) + ".");
613 }
614
Postprocess_BuildNode(const CX3DImporter_NodeElement & pNodeElement,aiNode & pSceneNode,std::list<aiMesh * > & pSceneMeshList,std::list<aiMaterial * > & pSceneMaterialList,std::list<aiLight * > & pSceneLightList) const615 void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode, std::list<aiMesh*>& pSceneMeshList,
616 std::list<aiMaterial*>& pSceneMaterialList, std::list<aiLight*>& pSceneLightList) const
617 {
618 std::list<CX3DImporter_NodeElement*>::const_iterator chit_begin = pNodeElement.Child.begin();
619 std::list<CX3DImporter_NodeElement*>::const_iterator chit_end = pNodeElement.Child.end();
620 std::list<aiNode*> SceneNode_Child;
621 std::list<unsigned int> SceneNode_Mesh;
622
623 // At first read all metadata
624 Postprocess_CollectMetadata(pNodeElement, pSceneNode);
625 // check if we have deal with grouping node. Which can contain transformation or switch
626 if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group)
627 {
628 const CX3DImporter_NodeElement_Group& tne_group = *((CX3DImporter_NodeElement_Group*)&pNodeElement);// create alias for convenience
629
630 pSceneNode.mTransformation = tne_group.Transformation;
631 if(tne_group.UseChoice)
632 {
633 // If Choice is less than zero or greater than the number of nodes in the children field, nothing is chosen.
634 if((tne_group.Choice < 0) || ((size_t)tne_group.Choice >= pNodeElement.Child.size()))
635 {
636 chit_begin = pNodeElement.Child.end();
637 chit_end = pNodeElement.Child.end();
638 }
639 else
640 {
641 for(size_t i = 0; i < (size_t)tne_group.Choice; i++) chit_begin++;// forward iterator to chosen node.
642
643 chit_end = chit_begin;
644 chit_end++;// point end iterator to next element after chosen node.
645 }
646 }// if(tne_group.UseChoice)
647 }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group)
648
649 // Reserve memory for fast access and check children.
650 for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++)
651 {// in this loop we do not read metadata because it's already read at begin.
652 if((*it)->Type == CX3DImporter_NodeElement::ENET_Group)
653 {
654 // if child is group then create new node and do recursive call.
655 aiNode* new_node = new aiNode;
656
657 new_node->mName = (*it)->ID;
658 new_node->mParent = &pSceneNode;
659 SceneNode_Child.push_back(new_node);
660 Postprocess_BuildNode(**it, *new_node, pSceneMeshList, pSceneMaterialList, pSceneLightList);
661 }
662 else if((*it)->Type == CX3DImporter_NodeElement::ENET_Shape)
663 {
664 // shape can contain only one geometry and one appearance nodes.
665 Postprocess_BuildShape(*((CX3DImporter_NodeElement_Shape*)*it), SceneNode_Mesh, pSceneMeshList, pSceneMaterialList);
666 }
667 else if(((*it)->Type == CX3DImporter_NodeElement::ENET_DirectionalLight) || ((*it)->Type == CX3DImporter_NodeElement::ENET_PointLight) ||
668 ((*it)->Type == CX3DImporter_NodeElement::ENET_SpotLight))
669 {
670 Postprocess_BuildLight(*((CX3DImporter_NodeElement_Light*)*it), pSceneLightList);
671 }
672 else if(!PostprocessHelper_ElementIsMetadata((*it)->Type))// skip metadata
673 {
674 throw DeadlyImportError("Postprocess_BuildNode. Unknown type: " + to_string((*it)->Type) + ".");
675 }
676 }// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++)
677
678 // copy data about children and meshes to aiNode.
679 if(SceneNode_Child.size() > 0)
680 {
681 std::list<aiNode*>::const_iterator it = SceneNode_Child.begin();
682
683 pSceneNode.mNumChildren = static_cast<unsigned int>(SceneNode_Child.size());
684 pSceneNode.mChildren = new aiNode*[pSceneNode.mNumChildren];
685 for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++;
686 }
687
688 if(SceneNode_Mesh.size() > 0)
689 {
690 std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin();
691
692 pSceneNode.mNumMeshes = static_cast<unsigned int>(SceneNode_Mesh.size());
693 pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
694 for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *it++;
695 }
696
697 // that's all. return to previous deals
698 }
699
Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape & pShapeNodeElement,std::list<unsigned int> & pNodeMeshInd,std::list<aiMesh * > & pSceneMeshList,std::list<aiMaterial * > & pSceneMaterialList) const700 void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& pShapeNodeElement, std::list<unsigned int>& pNodeMeshInd,
701 std::list<aiMesh*>& pSceneMeshList, std::list<aiMaterial*>& pSceneMaterialList) const
702 {
703 aiMaterial* tmat = nullptr;
704 aiMesh* tmesh = nullptr;
705 CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid;
706 unsigned int mat_ind = 0;
707
708 for(std::list<CX3DImporter_NodeElement*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++)
709 {
710 if(PostprocessHelper_ElementIsMesh((*it)->Type))
711 {
712 Postprocess_BuildMesh(**it, &tmesh);
713 if(tmesh != nullptr)
714 {
715 // if mesh successfully built then add data about it to arrays
716 pNodeMeshInd.push_back(static_cast<unsigned int>(pSceneMeshList.size()));
717 pSceneMeshList.push_back(tmesh);
718 // keep mesh type. Need above for texture coordinate generation.
719 mesh_type = (*it)->Type;
720 }
721 }
722 else if((*it)->Type == CX3DImporter_NodeElement::ENET_Appearance)
723 {
724 Postprocess_BuildMaterial(**it, &tmat);
725 if(tmat != nullptr)
726 {
727 // if material successfully built then add data about it to array
728 mat_ind = static_cast<unsigned int>(pSceneMaterialList.size());
729 pSceneMaterialList.push_back(tmat);
730 }
731 }
732 }// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++)
733
734 // associate read material with read mesh.
735 if((tmesh != nullptr) && (tmat != nullptr))
736 {
737 tmesh->mMaterialIndex = mat_ind;
738 // Check texture mapping. If material has texture but mesh has no texture coordinate then try to ask Assimp to generate texture coordinates.
739 if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0))
740 {
741 int32_t tm;
742 aiVector3D tvec3;
743
744 switch(mesh_type)
745 {
746 case CX3DImporter_NodeElement::ENET_Box:
747 tm = aiTextureMapping_BOX;
748 break;
749 case CX3DImporter_NodeElement::ENET_Cone:
750 case CX3DImporter_NodeElement::ENET_Cylinder:
751 tm = aiTextureMapping_CYLINDER;
752 break;
753 case CX3DImporter_NodeElement::ENET_Sphere:
754 tm = aiTextureMapping_SPHERE;
755 break;
756 default:
757 tm = aiTextureMapping_PLANE;
758 break;
759 }// switch(mesh_type)
760
761 tmat->AddProperty(&tm, 1, AI_MATKEY_MAPPING_DIFFUSE(0));
762 }// if((tmat->GetTextureCount(aiTextureType_DIFFUSE) != 0) && !tmesh->HasTextureCoords(0))
763 }// if((tmesh != nullptr) && (tmat != nullptr))
764 }
765
Postprocess_CollectMetadata(const CX3DImporter_NodeElement & pNodeElement,aiNode & pSceneNode) const766 void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, aiNode& pSceneNode) const
767 {
768 std::list<CX3DImporter_NodeElement*> meta_list;
769 size_t meta_idx;
770
771 PostprocessHelper_CollectMetadata(pNodeElement, meta_list);// find metadata in current node element.
772 if ( !meta_list.empty() )
773 {
774 if ( pSceneNode.mMetaData != nullptr ) {
775 throw DeadlyImportError( "Postprocess. MetaData member in node are not nullptr. Something went wrong." );
776 }
777
778 // copy collected metadata to output node.
779 pSceneNode.mMetaData = aiMetadata::Alloc( static_cast<unsigned int>(meta_list.size()) );
780 meta_idx = 0;
781 for(std::list<CX3DImporter_NodeElement*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++, meta_idx++)
782 {
783 CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it;
784
785 // due to limitations we can add only first element of value list.
786 // Add an element according to its type.
787 if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean)
788 {
789 if(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.size() > 0)
790 pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((CX3DImporter_NodeElement_MetaBoolean*)cur_meta)->Value.begin()));
791 }
792 else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble)
793 {
794 if(((CX3DImporter_NodeElement_MetaDouble*)cur_meta)->Value.size() > 0)
795 pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, (float)*(((CX3DImporter_NodeElement_MetaDouble*)cur_meta)->Value.begin()));
796 }
797 else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat)
798 {
799 if(((CX3DImporter_NodeElement_MetaFloat*)cur_meta)->Value.size() > 0)
800 pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((CX3DImporter_NodeElement_MetaFloat*)cur_meta)->Value.begin()));
801 }
802 else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger)
803 {
804 if(((CX3DImporter_NodeElement_MetaInteger*)cur_meta)->Value.size() > 0)
805 pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, *(((CX3DImporter_NodeElement_MetaInteger*)cur_meta)->Value.begin()));
806 }
807 else if((*it)->Type == CX3DImporter_NodeElement::ENET_MetaString)
808 {
809 if(((CX3DImporter_NodeElement_MetaString*)cur_meta)->Value.size() > 0)
810 {
811 aiString tstr(((CX3DImporter_NodeElement_MetaString*)cur_meta)->Value.begin()->data());
812
813 pSceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx), cur_meta->Name, tstr);
814 }
815 }
816 else
817 {
818 throw DeadlyImportError("Postprocess. Unknown metadata type.");
819 }// if((*it)->Type == CX3DImporter_NodeElement::ENET_Meta*) else
820 }// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++)
821 }// if( !meta_list.empty() )
822 }
823
824 }// namespace Assimp
825
826 #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER
827