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