X3DImporter.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739
  1. /*
  2. Open Asset Import Library (assimp)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2017, assimp team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the assimp team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the assimp team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. /// \file X3DImporter.cpp
  34. /// \brief X3D-format files importer for Assimp: main algorithm implementation.
  35. /// \date 2015-2016
  36. /// \author [email protected]
  37. #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
  38. #include "X3DImporter.hpp"
  39. #include "X3DImporter_Macro.hpp"
  40. #include "StringUtils.h"
  41. // Header files, Assimp.
  42. #include <assimp/DefaultIOSystem.h>
  43. #include "fast_atof.h"
  44. // Header files, stdlib.
  45. #include <memory>
  46. #include <string>
  47. namespace Assimp {
  48. /// \var aiImporterDesc X3DImporter::Description
  49. /// Constant which holds the importer description
  50. const aiImporterDesc X3DImporter::Description = {
  51. "Extensible 3D(X3D) Importer",
  52. "smalcom",
  53. "",
  54. "See documentation in source code. Chapter: Limitations.",
  55. aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
  56. 0,
  57. 0,
  58. 0,
  59. 0,
  60. "x3d"
  61. };
  62. X3DImporter::X3DImporter()
  63. : NodeElement_Cur( nullptr )
  64. , mReader( nullptr ) {
  65. // empty
  66. }
  67. X3DImporter::~X3DImporter() {
  68. delete mReader;
  69. // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
  70. Clear();
  71. }
  72. void X3DImporter::Clear() {
  73. NodeElement_Cur = nullptr;
  74. // Delete all elements
  75. if(NodeElement_List.size()) {
  76. for ( std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++ ) {
  77. delete *it;
  78. }
  79. NodeElement_List.clear();
  80. }
  81. }
  82. /*********************************************************************************************************************************************/
  83. /************************************************************ Functions: find set ************************************************************/
  84. /*********************************************************************************************************************************************/
  85. bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement)
  86. {
  87. for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++)
  88. {
  89. if(((*it)->Type == pType) && ((*it)->ID == pID))
  90. {
  91. if(pElement != nullptr) *pElement = *it;
  92. return true;
  93. }
  94. }// for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++)
  95. return false;
  96. }
  97. bool X3DImporter::FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, const std::string& pID,
  98. const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement)
  99. {
  100. bool found = false;// flag: true - if requested element is found.
  101. // Check if pStartNode - this is the element, we are looking for.
  102. if((pStartNode->Type == pType) && (pStartNode->ID == pID))
  103. {
  104. found = true;
  105. if ( pElement != nullptr )
  106. {
  107. *pElement = pStartNode;
  108. }
  109. goto fne_fn_end;
  110. }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID))
  111. // Check childs of pStartNode.
  112. for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ch_it++)
  113. {
  114. found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement);
  115. if ( found )
  116. {
  117. break;
  118. }
  119. }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = it->Child.begin(); ch_it != it->Child.end(); ch_it++)
  120. fne_fn_end:
  121. return found;
  122. }
  123. bool X3DImporter::FindNodeElement(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement)
  124. {
  125. CX3DImporter_NodeElement* tnd = NodeElement_Cur;// temporary pointer to node.
  126. bool static_search = false;// flag: true if searching in static node.
  127. // At first check if we have deal with static node. Go up through parent nodes and check flag.
  128. while(tnd != nullptr)
  129. {
  130. if(tnd->Type == CX3DImporter_NodeElement::ENET_Group)
  131. {
  132. if(((CX3DImporter_NodeElement_Group*)tnd)->Static)
  133. {
  134. static_search = true;// Flag found, stop walking up. Node with static flag will holded in tnd variable.
  135. break;
  136. }
  137. }
  138. tnd = tnd->Parent;// go up in graph.
  139. }// while(tnd != nullptr)
  140. // at now call appropriate search function.
  141. if ( static_search )
  142. {
  143. return FindNodeElement_FromNode( tnd, pID, pType, pElement );
  144. }
  145. else
  146. {
  147. return FindNodeElement_FromRoot( pID, pType, pElement );
  148. }
  149. }
  150. /*********************************************************************************************************************************************/
  151. /************************************************************ Functions: throw set ***********************************************************/
  152. /*********************************************************************************************************************************************/
  153. void X3DImporter::Throw_ArgOutOfRange(const std::string& pArgument)
  154. {
  155. throw DeadlyImportError("Argument value is out of range for: \"" + pArgument + "\".");
  156. }
  157. void X3DImporter::Throw_CloseNotFound(const std::string& pNode)
  158. {
  159. throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
  160. }
  161. void X3DImporter::Throw_ConvertFail_Str2ArrF(const std::string& pAttrValue)
  162. {
  163. throw DeadlyImportError("In <" + std::string(mReader->getNodeName()) + "> failed to convert attribute value \"" + pAttrValue +
  164. "\" from string to array of floats.");
  165. }
  166. void X3DImporter::Throw_DEF_And_USE()
  167. {
  168. throw DeadlyImportError("\"DEF\" and \"USE\" can not be defined both in <" + std::string(mReader->getNodeName()) + ">.");
  169. }
  170. void X3DImporter::Throw_IncorrectAttr(const std::string& pAttrName)
  171. {
  172. throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
  173. }
  174. void X3DImporter::Throw_IncorrectAttrValue(const std::string& pAttrName)
  175. {
  176. throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
  177. }
  178. void X3DImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription)
  179. {
  180. throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
  181. }
  182. void X3DImporter::Throw_TagCountIncorrect(const std::string& pNode)
  183. {
  184. throw DeadlyImportError("Count of open and close tags for node <" + pNode + "> are not equivalent. Seems file is corrupt.");
  185. }
  186. void X3DImporter::Throw_USE_NotFound(const std::string& pAttrValue)
  187. {
  188. throw DeadlyImportError("Not found node with name \"" + pAttrValue + "\" in <" + std::string(mReader->getNodeName()) + ">.");
  189. }
  190. /*********************************************************************************************************************************************/
  191. /************************************************************* Functions: XML set ************************************************************/
  192. /*********************************************************************************************************************************************/
  193. void X3DImporter::XML_CheckNode_MustBeEmpty()
  194. {
  195. if(!mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must be empty.");
  196. }
  197. void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
  198. {
  199. const size_t Uns_Skip_Len = 189;
  200. const char* Uns_Skip[ Uns_Skip_Len ] = {
  201. // CAD geometry component
  202. "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet",
  203. // Core
  204. "ROUTE", "ExternProtoDeclare", "ProtoDeclare", "ProtoInstance", "ProtoInterface", "WorldInfo",
  205. // Distributed interactive simulation (DIS) component
  206. "DISEntityManager", "DISEntityTypeMapping", "EspduTransform", "ReceiverPdu", "SignalPdu", "TransmitterPdu",
  207. // Cube map environmental texturing component
  208. "ComposedCubeMapTexture", "GeneratedCubeMapTexture", "ImageCubeMapTexture",
  209. // Environmental effects component
  210. "Background", "Fog", "FogCoordinate", "LocalFog", "TextureBackground",
  211. // Environmental sensor component
  212. "ProximitySensor", "TransformSensor", "VisibilitySensor",
  213. // Followers component
  214. "ColorChaser", "ColorDamper", "CoordinateChaser", "CoordinateDamper", "OrientationChaser", "OrientationDamper", "PositionChaser", "PositionChaser2D",
  215. "PositionDamper", "PositionDamper2D", "ScalarChaser", "ScalarDamper", "TexCoordChaser2D", "TexCoordDamper2D",
  216. // Geospatial component
  217. "GeoCoordinate", "GeoElevationGrid", "GeoLocation", "GeoLOD", "GeoMetadata", "GeoOrigin", "GeoPositionInterpolator", "GeoProximitySensor",
  218. "GeoTouchSensor", "GeoTransform", "GeoViewpoint",
  219. // Humanoid Animation (H-Anim) component
  220. "HAnimDisplacer", "HAnimHumanoid", "HAnimJoint", "HAnimSegment", "HAnimSite",
  221. // Interpolation component
  222. "ColorInterpolator", "CoordinateInterpolator", "CoordinateInterpolator2D", "EaseInEaseOut", "NormalInterpolator", "OrientationInterpolator",
  223. "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D",
  224. "SplineScalarInterpolator", "SquadOrientationInterpolator",
  225. // Key device sensor component
  226. "KeySensor", "StringSensor"
  227. // Layering component
  228. "Layer", "LayerSet", "Viewport",
  229. // Layout component
  230. "Layout", "LayoutGroup", "LayoutLayer", "ScreenFontStyle", "ScreenGroup",
  231. // Navigation component
  232. "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup",
  233. // Networking component
  234. "Anchor", "LoadSensor",
  235. // NURBS component
  236. "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface",
  237. "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate",
  238. "NurbsTrimmedSurface",
  239. // Particle systems component
  240. "BoundedPhysicsModel", "ConeEmitter", "ExplosionEmitter", "ForcePhysicsModel", "ParticleSystem", "PointEmitter", "PolylineEmitter", "SurfaceEmitter",
  241. "VolumeEmitter", "WindPhysicsModel",
  242. // Picking component
  243. "LinePickSensor", "PickableGroup", "PointPickSensor", "PrimitivePickSensor", "VolumePickSensor",
  244. // Pointing device sensor component
  245. "CylinderSensor", "PlaneSensor", "SphereSensor", "TouchSensor",
  246. // Rendering component
  247. "ClipPlane",
  248. // Rigid body physics
  249. "BallJoint", "CollidableOffset", "CollidableShape", "CollisionCollection", "CollisionSensor", "CollisionSpace", "Contact", "DoubleAxisHingeJoint",
  250. "MotorJoint", "RigidBody", "RigidBodyCollection", "SingleAxisHingeJoint", "SliderJoint", "UniversalJoint",
  251. // Scripting component
  252. "Script",
  253. // Programmable shaders component
  254. "ComposedShader", "FloatVertexAttribute", "Matrix3VertexAttribute", "Matrix4VertexAttribute", "PackagedShader", "ProgramShader", "ShaderPart",
  255. "ShaderProgram",
  256. // Shape component
  257. "FillProperties", "LineProperties", "TwoSidedMaterial",
  258. // Sound component
  259. "AudioClip", "Sound",
  260. // Text component
  261. "FontStyle", "Text",
  262. // Texturing3D Component
  263. "ComposedTexture3D", "ImageTexture3D", "PixelTexture3D", "TextureCoordinate3D", "TextureCoordinate4D", "TextureTransformMatrix3D", "TextureTransform3D",
  264. // Texturing component
  265. "MovieTexture", "MultiTexture", "MultiTextureCoordinate", "MultiTextureTransform", "PixelTexture", "TextureCoordinateGenerator", "TextureProperties",
  266. // Time component
  267. "TimeSensor",
  268. // Event Utilities component
  269. "BooleanFilter", "BooleanSequencer", "BooleanToggle", "BooleanTrigger", "IntegerSequencer", "IntegerTrigger", "TimeTrigger",
  270. // Volume rendering component
  271. "BlendedVolumeStyle", "BoundaryEnhancementVolumeStyle", "CartoonVolumeStyle", "ComposedVolumeStyle", "EdgeEnhancementVolumeStyle", "IsoSurfaceVolumeData",
  272. "OpacityMapVolumeStyle", "ProjectionVolumeStyle", "SegmentedVolumeData", "ShadedVolumeStyle", "SilhouetteEnhancementVolumeStyle", "ToneMappedVolumeStyle",
  273. "VolumeData"
  274. };
  275. const std::string nn( mReader->getNodeName() );
  276. bool found = false;
  277. bool close_found = false;
  278. for(size_t i = 0; i < Uns_Skip_Len; i++)
  279. {
  280. if(nn == Uns_Skip[i])
  281. {
  282. found = true;
  283. if(mReader->isEmptyElement())
  284. {
  285. close_found = true;
  286. goto casu_cres;
  287. }
  288. while(mReader->read())
  289. {
  290. if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName()))
  291. {
  292. close_found = true;
  293. goto casu_cres;
  294. }
  295. }
  296. }
  297. }
  298. casu_cres:
  299. if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
  300. if(close_found)
  301. LogInfo("Skipping node \"" + nn + "\" in " + pParentNodeName + ".");
  302. else
  303. Throw_CloseNotFound(nn);
  304. }
  305. bool X3DImporter::XML_SearchNode(const std::string& pNodeName)
  306. {
  307. while(mReader->read())
  308. {
  309. if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
  310. }
  311. return false;
  312. }
  313. bool X3DImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
  314. {
  315. std::string val(mReader->getAttributeValue(pAttrIdx));
  316. if(val == "false")
  317. return false;
  318. else if(val == "true")
  319. return true;
  320. else
  321. throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\"");
  322. }
  323. float X3DImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
  324. {
  325. std::string val;
  326. float tvalf;
  327. ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
  328. fast_atoreal_move(val.c_str(), tvalf, false);
  329. return tvalf;
  330. }
  331. int32_t X3DImporter::XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx)
  332. {
  333. return strtol10(mReader->getAttributeValue(pAttrIdx));
  334. }
  335. void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue)
  336. {
  337. std::list<float> tlist;
  338. std::list<float>::iterator it;
  339. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
  340. if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  341. it = tlist.begin();
  342. pValue.r = *it++;
  343. pValue.g = *it++;
  344. pValue.b = *it;
  345. }
  346. void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue)
  347. {
  348. std::list<float> tlist;
  349. std::list<float>::iterator it;
  350. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
  351. if(tlist.size() != 2) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  352. it = tlist.begin();
  353. pValue.x = *it++;
  354. pValue.y = *it;
  355. }
  356. void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue)
  357. {
  358. std::list<float> tlist;
  359. std::list<float>::iterator it;
  360. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);
  361. if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  362. it = tlist.begin();
  363. pValue.x = *it++;
  364. pValue.y = *it++;
  365. pValue.z = *it;
  366. }
  367. void X3DImporter::XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list<bool>& pValue)
  368. {
  369. // make copy of attribute value - string with list of bool values. Also all bool values is strings.
  370. size_t tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx));
  371. if ( 0 == tok_str_len ) {
  372. Throw_IncorrectAttrValue( mReader->getAttributeName( pAttrIdx ) );
  373. }
  374. tok_str_len++;// take in account terminating '\0'.
  375. char *tok_str = new char[tok_str_len];
  376. strcpy(tok_str, mReader->getAttributeValue(pAttrIdx));
  377. // change all spacebars to symbol '\0'. That is needed for parsing.
  378. for(size_t i = 0; i < tok_str_len; i++)
  379. {
  380. if(tok_str[i] == ' ') tok_str[i] = 0;
  381. }
  382. // at now check what current token is
  383. for(char *tok_cur = tok_str, *tok_end = (tok_str + tok_str_len); tok_cur < tok_end;)
  384. {
  385. if(strncmp(tok_cur, "true", 4) == 0)
  386. {
  387. pValue.push_back(true);
  388. tok_cur += 5;// five, not four. Because '\0' must be skipped too.
  389. }
  390. else if(strncmp(tok_cur, "false", 5) == 0)
  391. {
  392. pValue.push_back(true);
  393. tok_cur += 6;// six, not five. Because '\0' must be skipped too.
  394. }
  395. else
  396. {
  397. Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx));
  398. }
  399. }// for(char* tok_cur = tok_str, tok_end = (tok_str + tok_str_len); tok_cur < tok_end;)
  400. // delete temporary string
  401. delete [] tok_str;
  402. }
  403. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector<bool>& pValue)
  404. {
  405. std::list<bool> tlist;
  406. XML_ReadNode_GetAttrVal_AsListB(pAttrIdx, tlist);// read as list
  407. // and copy to array
  408. if(tlist.size() > 0)
  409. {
  410. pValue.reserve(tlist.size());
  411. for(std::list<bool>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
  412. }
  413. }
  414. void X3DImporter::XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list<int32_t>& pValue)
  415. {
  416. const char* tstr = mReader->getAttributeValue(pAttrIdx);
  417. const char* tstr_end = tstr + strlen(tstr);
  418. do
  419. {
  420. const char* ostr;
  421. int32_t tval32;
  422. tval32 = strtol10(tstr, &ostr);
  423. if(ostr == tstr) break;
  424. while((ostr < tstr_end) && (*ostr == ' ')) ostr++;// skip spaces between values.
  425. tstr = ostr;
  426. pValue.push_back(tval32);
  427. } while(tstr < tstr_end);
  428. }
  429. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector<int32_t>& pValue)
  430. {
  431. std::list<int32_t> tlist;
  432. XML_ReadNode_GetAttrVal_AsListI32(pAttrIdx, tlist);// read as list
  433. // and copy to array
  434. if(tlist.size() > 0)
  435. {
  436. pValue.reserve(tlist.size());
  437. for(std::list<int32_t>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
  438. }
  439. }
  440. void X3DImporter::XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list<float>& pValue)
  441. {
  442. std::string str_fixed;
  443. // at first check string values like '.xxx'.
  444. ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed);
  445. if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  446. // and convert all values and place it in list.
  447. const char* pstr = str_fixed.c_str();
  448. const char* pstr_end = pstr + str_fixed.size();
  449. do
  450. {
  451. float tvalf;
  452. while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values.
  453. if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces.
  454. {
  455. pstr = fast_atoreal_move(pstr, tvalf, false);
  456. pValue.push_back(tvalf);
  457. }
  458. } while(pstr < pstr_end);
  459. }
  460. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector<float>& pValue)
  461. {
  462. std::list<float> tlist;
  463. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
  464. // and copy to array
  465. if(tlist.size() > 0)
  466. {
  467. pValue.reserve(tlist.size());
  468. for(std::list<float>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
  469. }
  470. }
  471. void X3DImporter::XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list<double>& pValue)
  472. {
  473. std::string str_fixed;
  474. // at first check string values like '.xxx'.
  475. ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed);
  476. if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  477. // and convert all values and place it in list.
  478. const char* pstr = str_fixed.c_str();
  479. const char* pstr_end = pstr + str_fixed.size();
  480. do
  481. {
  482. double tvald;
  483. while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values.
  484. if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces.
  485. {
  486. pstr = fast_atoreal_move(pstr, tvald, false);
  487. pValue.push_back(tvald);
  488. }
  489. } while(pstr < pstr_end);
  490. }
  491. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector<double>& pValue)
  492. {
  493. std::list<double> tlist;
  494. XML_ReadNode_GetAttrVal_AsListD(pAttrIdx, tlist);// read as list
  495. // and copy to array
  496. if(tlist.size() > 0)
  497. {
  498. pValue.reserve(tlist.size());
  499. for(std::list<double>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
  500. }
  501. }
  502. void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list<aiColor3D>& pValue)
  503. {
  504. std::list<float> tlist;
  505. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
  506. if(tlist.size() % 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  507. // copy data to array
  508. for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
  509. {
  510. aiColor3D tcol;
  511. tcol.r = *it++;
  512. tcol.g = *it++;
  513. tcol.b = *it++;
  514. pValue.push_back(tcol);
  515. }
  516. }
  517. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::vector<aiColor3D>& pValue)
  518. {
  519. std::list<aiColor3D> tlist;
  520. XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list
  521. // and copy to array
  522. if(tlist.size() > 0)
  523. {
  524. pValue.reserve(tlist.size());
  525. for(std::list<aiColor3D>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it);
  526. }
  527. }
  528. void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list<aiColor4D>& pValue)
  529. {
  530. std::list<float> tlist;
  531. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
  532. if(tlist.size() % 4) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx));
  533. // copy data to array
  534. for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
  535. {
  536. aiColor4D tcol;
  537. tcol.r = *it++;
  538. tcol.g = *it++;
  539. tcol.b = *it++;
  540. tcol.a = *it++;
  541. pValue.push_back(tcol);
  542. }
  543. }
  544. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::vector<aiColor4D>& pValue)
  545. {
  546. std::list<aiColor4D> tlist;
  547. XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list
  548. // and copy to array
  549. if(tlist.size() > 0)
  550. {
  551. pValue.reserve(tlist.size());
  552. for ( std::list<aiColor4D>::iterator it = tlist.begin(); it != tlist.end(); it++ )
  553. {
  554. pValue.push_back( *it );
  555. }
  556. }
  557. }
  558. void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list<aiVector2D>& pValue)
  559. {
  560. std::list<float> tlist;
  561. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
  562. if ( tlist.size() % 2 )
  563. {
  564. Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) );
  565. }
  566. // copy data to array
  567. for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
  568. {
  569. aiVector2D tvec;
  570. tvec.x = *it++;
  571. tvec.y = *it++;
  572. pValue.push_back(tvec);
  573. }
  574. }
  575. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::vector<aiVector2D>& pValue)
  576. {
  577. std::list<aiVector2D> tlist;
  578. XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list
  579. // and copy to array
  580. if(tlist.size() > 0)
  581. {
  582. pValue.reserve(tlist.size());
  583. for ( std::list<aiVector2D>::iterator it = tlist.begin(); it != tlist.end(); it++ )
  584. {
  585. pValue.push_back( *it );
  586. }
  587. }
  588. }
  589. void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list<aiVector3D>& pValue)
  590. {
  591. std::list<float> tlist;
  592. XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list
  593. if ( tlist.size() % 3 )
  594. {
  595. Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) );
  596. }
  597. // copy data to array
  598. for(std::list<float>::iterator it = tlist.begin(); it != tlist.end();)
  599. {
  600. aiVector3D tvec;
  601. tvec.x = *it++;
  602. tvec.y = *it++;
  603. tvec.z = *it++;
  604. pValue.push_back(tvec);
  605. }
  606. }
  607. void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::vector<aiVector3D>& pValue)
  608. {
  609. std::list<aiVector3D> tlist;
  610. XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list
  611. // and copy to array
  612. if(tlist.size() > 0)
  613. {
  614. pValue.reserve(tlist.size());
  615. for ( std::list<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); it++ )
  616. {
  617. pValue.push_back( *it );
  618. }
  619. }
  620. }
  621. void X3DImporter::XML_ReadNode_GetAttrVal_AsListS(const int pAttrIdx, std::list<std::string>& pValue)
  622. {
  623. // make copy of attribute value - strings list.
  624. const size_t tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx));
  625. if ( 0 == tok_str_len )
  626. {
  627. Throw_IncorrectAttrValue( mReader->getAttributeName( pAttrIdx ) );
  628. }
  629. // get pointer to begin of value.
  630. char *tok_str = const_cast<char*>(mReader->getAttributeValue(pAttrIdx));
  631. char *tok_str_end = tok_str + tok_str_len;
  632. // string list has following format: attr_name='"s1" "s2" "sn"'.
  633. do
  634. {
  635. char* tbeg;
  636. char* tend;
  637. size_t tlen;
  638. std::string tstr;
  639. // find begin of string(element of string list): "sn".
  640. tbeg = strstr(tok_str, "\"");
  641. if(tbeg == nullptr) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx));
  642. tbeg++;// forward pointer from '\"' symbol to next after it.
  643. tok_str = tbeg;
  644. // find end of string(element of string list): "sn".
  645. tend = strstr(tok_str, "\"");
  646. if(tend == nullptr) Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx));
  647. tok_str = tend + 1;
  648. // create storage for new string
  649. tlen = tend - tbeg;
  650. tstr.resize(tlen);// reserve enough space and copy data
  651. memcpy((void*)tstr.data(), tbeg, tlen);// not strcpy because end of copied string from tok_str has no terminator.
  652. // and store string in output list.
  653. pValue.push_back(tstr);
  654. } while(tok_str < tok_str_end);
  655. }
  656. /*********************************************************************************************************************************************/
  657. /****************************************************** Functions: geometry helper set ******************************************************/
  658. /*********************************************************************************************************************************************/
  659. aiVector3D X3DImporter::GeometryHelper_Make_Point2D(const float pAngle, const float pRadius)
  660. {
  661. return aiVector3D(pRadius * std::cos(pAngle), pRadius * std::sin(pAngle), 0);
  662. }
  663. void X3DImporter::GeometryHelper_Make_Arc2D(const float pStartAngle, const float pEndAngle, const float pRadius, size_t pNumSegments,
  664. std::list<aiVector3D>& pVertices)
  665. {
  666. // check argument values ranges.
  667. if ( ( pStartAngle < -AI_MATH_TWO_PI_F ) || ( pStartAngle > AI_MATH_TWO_PI_F ) )
  668. {
  669. Throw_ArgOutOfRange( "GeometryHelper_Make_Arc2D.pStartAngle" );
  670. }
  671. if ( ( pEndAngle < -AI_MATH_TWO_PI_F ) || ( pEndAngle > AI_MATH_TWO_PI_F ) )
  672. {
  673. Throw_ArgOutOfRange( "GeometryHelper_Make_Arc2D.pEndAngle" );
  674. }
  675. if ( pRadius <= 0 )
  676. {
  677. Throw_ArgOutOfRange( "GeometryHelper_Make_Arc2D.pRadius" );
  678. }
  679. // calculate arc angle and check type of arc
  680. float angle_full = std::fabs(pEndAngle - pStartAngle);
  681. if ( ( angle_full > AI_MATH_TWO_PI_F ) || ( angle_full == 0.0f ) )
  682. {
  683. angle_full = AI_MATH_TWO_PI_F;
  684. }
  685. // calculate angle for one step - angle to next point of line.
  686. float angle_step = angle_full / (float)pNumSegments;
  687. // make points
  688. for(size_t pi = 0; pi <= pNumSegments; pi++)
  689. {
  690. float tangle = pStartAngle + pi * angle_step;
  691. pVertices.push_back(GeometryHelper_Make_Point2D(tangle, pRadius));
  692. }// for(size_t pi = 0; pi <= pNumSegments; pi++)
  693. // if we making full circle then add last vertex equal to first vertex
  694. if(angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin());
  695. }
  696. void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list<aiVector3D>& pPoint, std::list<aiVector3D>& pLine)
  697. {
  698. std::list<aiVector3D>::const_iterator pit = pPoint.begin();
  699. std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
  700. pit_last--;
  701. if ( pPoint.size() < 2 )
  702. {
  703. Throw_ArgOutOfRange( "GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2." );
  704. }
  705. // add first point of first line.
  706. pLine.push_back(*pit++);
  707. // add internal points
  708. while(pit != pit_last)
  709. {
  710. pLine.push_back(*pit);// second point of previous line
  711. pLine.push_back(*pit);// first point of next line
  712. pit++;
  713. }
  714. // add last point of last line
  715. pLine.push_back(*pit);
  716. }
  717. void X3DImporter::GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list<int32_t>& pPolylineCoordIdx, std::list<int32_t>& pLineCoordIdx)
  718. {
  719. std::list<int32_t>::const_iterator plit = pPolylineCoordIdx.begin();
  720. while(plit != pPolylineCoordIdx.end())
  721. {
  722. // add first point of polyline
  723. pLineCoordIdx.push_back(*plit++);
  724. while((*plit != (-1)) && (plit != pPolylineCoordIdx.end()))
  725. {
  726. std::list<int32_t>::const_iterator plit_next;
  727. plit_next = plit, plit_next++;
  728. pLineCoordIdx.push_back(*plit);// second point of previous line.
  729. pLineCoordIdx.push_back(-1);// delimiter
  730. if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished
  731. pLineCoordIdx.push_back(*plit);// first point of next line.
  732. plit = plit_next;
  733. }// while((*plit != (-1)) && (plit != pPolylineCoordIdx.end()))
  734. }// while(plit != pPolylineCoordIdx.end())
  735. }
  736. #define MESH_RectParallelepiped_CREATE_VERT \
  737. aiVector3D vert_set[8]; \
  738. float x1, x2, y1, y2, z1, z2, hs; \
  739. \
  740. hs = pSize.x / 2, x1 = -hs, x2 = hs; \
  741. hs = pSize.y / 2, y1 = -hs, y2 = hs; \
  742. hs = pSize.z / 2, z1 = -hs, z2 = hs; \
  743. vert_set[0].Set(x2, y1, z2); \
  744. vert_set[1].Set(x2, y2, z2); \
  745. vert_set[2].Set(x2, y2, z1); \
  746. vert_set[3].Set(x2, y1, z1); \
  747. vert_set[4].Set(x1, y1, z2); \
  748. vert_set[5].Set(x1, y2, z2); \
  749. vert_set[6].Set(x1, y2, z1); \
  750. vert_set[7].Set(x1, y1, z1)
  751. void X3DImporter::GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSize, std::list<aiVector3D>& pVertices)
  752. {
  753. MESH_RectParallelepiped_CREATE_VERT;
  754. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0);// front
  755. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5);// back
  756. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4);// left
  757. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1);// right
  758. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4);// top
  759. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3);// bottom
  760. }
  761. #undef MESH_RectParallelepiped_CREATE_VERT
  762. void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list<int32_t>& pCoordIdx, std::vector<aiFace>& pFaces, unsigned int& pPrimitiveTypes) const
  763. {
  764. std::list<int32_t> f_data(pCoordIdx);
  765. std::vector<unsigned int> inds;
  766. unsigned int prim_type = 0;
  767. if ( f_data.back() != ( -1 ) )
  768. {
  769. f_data.push_back( -1 );
  770. }
  771. // reserve average size.
  772. pFaces.reserve(f_data.size() / 3);
  773. inds.reserve(4);
  774. //PrintVectorSet("build. ci", pCoordIdx);
  775. for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
  776. {
  777. // when face is got count how many indices in it.
  778. if(*it == (-1))
  779. {
  780. aiFace tface;
  781. size_t ts;
  782. ts = inds.size();
  783. switch(ts)
  784. {
  785. case 0: goto mg_m_err;
  786. case 1: prim_type |= aiPrimitiveType_POINT; break;
  787. case 2: prim_type |= aiPrimitiveType_LINE; break;
  788. case 3: prim_type |= aiPrimitiveType_TRIANGLE; break;
  789. default: prim_type |= aiPrimitiveType_POLYGON; break;
  790. }
  791. tface.mNumIndices = static_cast<unsigned int>(ts);
  792. tface.mIndices = new unsigned int[ts];
  793. memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int));
  794. pFaces.push_back(tface);
  795. inds.clear();
  796. }// if(*it == (-1))
  797. else
  798. {
  799. inds.push_back(*it);
  800. }// if(*it == (-1)) else
  801. }// for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
  802. //PrintVectorSet("build. faces", pCoordIdx);
  803. pPrimitiveTypes = prim_type;
  804. return;
  805. mg_m_err:
  806. for(size_t i = 0, i_e = pFaces.size(); i < i_e; i++) delete [] pFaces.at(i).mIndices;
  807. pFaces.clear();
  808. }
  809. void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const
  810. {
  811. std::list<aiColor4D> tcol;
  812. // create RGBA array from RGB.
  813. for(std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
  814. // call existing function for adding RGBA colors
  815. MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex);
  816. }
  817. void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const
  818. {
  819. std::list<aiColor4D>::const_iterator col_it = pColors.begin();
  820. if(pColorPerVertex)
  821. {
  822. if(pColors.size() < pMesh.mNumVertices)
  823. {
  824. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + to_string(pColors.size()) + ") can not be less than Vertices count(" +
  825. to_string(pMesh.mNumVertices) + ").");
  826. }
  827. // copy colors to mesh
  828. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  829. for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mColors[0][i] = *col_it++;
  830. }// if(pColorPerVertex)
  831. else
  832. {
  833. if(pColors.size() < pMesh.mNumFaces)
  834. {
  835. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + to_string(pColors.size()) + ") can not be less than Faces count(" +
  836. to_string(pMesh.mNumFaces) + ").");
  837. }
  838. // copy colors to mesh
  839. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  840. for(size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  841. {
  842. // apply color to all vertices of face
  843. for ( size_t vi = 0, vi_e = pMesh.mFaces[ fi ].mNumIndices; vi < vi_e; vi++ )
  844. {
  845. pMesh.mColors[ 0 ][ pMesh.mFaces[ fi ].mIndices[ vi ] ] = *col_it;
  846. }
  847. col_it++;
  848. }
  849. }// if(pColorPerVertex) else
  850. }
  851. void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
  852. const std::list<aiColor3D>& pColors, const bool pColorPerVertex) const
  853. {
  854. std::list<aiColor4D> tcol;
  855. // create RGBA array from RGB.
  856. for ( std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); it++ )
  857. {
  858. tcol.push_back( aiColor4D( ( *it ).r, ( *it ).g, ( *it ).b, 1 ) );
  859. }
  860. // call existing function for adding RGBA colors
  861. MeshGeometry_AddColor(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
  862. }
  863. void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pColorIdx,
  864. const std::list<aiColor4D>& pColors, const bool pColorPerVertex) const
  865. {
  866. std::vector<aiColor4D> col_tgt_arr;
  867. std::list<aiColor4D> col_tgt_list;
  868. std::vector<aiColor4D> col_arr_copy;
  869. if ( pCoordIdx.size() == 0 )
  870. {
  871. throw DeadlyImportError( "MeshGeometry_AddColor2. pCoordIdx can not be empty." );
  872. }
  873. // copy list to array because we are need indexed access to colors.
  874. col_arr_copy.reserve(pColors.size());
  875. for ( std::list<aiColor4D>::const_iterator it = pColors.begin(); it != pColors.end(); it++ )
  876. {
  877. col_arr_copy.push_back( *it );
  878. }
  879. if(pColorPerVertex)
  880. {
  881. if(pColorIdx.size() > 0)
  882. {
  883. // check indices array count.
  884. if(pColorIdx.size() < pCoordIdx.size())
  885. {
  886. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + to_string(pColorIdx.size()) +
  887. ") can not be less than Coords inidces count(" + to_string(pCoordIdx.size()) + ").");
  888. }
  889. // create list with colors for every vertex.
  890. col_tgt_arr.resize(pMesh.mNumVertices);
  891. for(std::list<int32_t>::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++)
  892. {
  893. if ( *colidx_it == ( -1 ) )
  894. {
  895. continue;// skip faces delimiter
  896. }
  897. if ( ( unsigned int ) ( *coordidx_it ) > pMesh.mNumVertices )
  898. {
  899. throw DeadlyImportError( "MeshGeometry_AddColor2. Coordinate idx is out of range." );
  900. }
  901. if ( ( unsigned int ) *colidx_it > pMesh.mNumVertices )
  902. {
  903. throw DeadlyImportError( "MeshGeometry_AddColor2. Color idx is out of range." );
  904. }
  905. col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it];
  906. }
  907. }// if(pColorIdx.size() > 0)
  908. else
  909. {
  910. // when color indices list is absent use CoordIdx.
  911. // check indices array count.
  912. if(pColors.size() < pMesh.mNumVertices)
  913. {
  914. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + to_string(pColors.size()) + ") can not be less than Vertices count(" +
  915. to_string(pMesh.mNumVertices) + ").");
  916. }
  917. // create list with colors for every vertex.
  918. col_tgt_arr.resize(pMesh.mNumVertices);
  919. for ( size_t i = 0; i < pMesh.mNumVertices; i++ )
  920. {
  921. col_tgt_arr[ i ] = col_arr_copy[ i ];
  922. }
  923. }// if(pColorIdx.size() > 0) else
  924. }// if(pColorPerVertex)
  925. else
  926. {
  927. if(pColorIdx.size() > 0)
  928. {
  929. // check indices array count.
  930. if(pColorIdx.size() < pMesh.mNumFaces)
  931. {
  932. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + to_string(pColorIdx.size()) +
  933. ") can not be less than Faces count(" + to_string(pMesh.mNumFaces) + ").");
  934. }
  935. // create list with colors for every vertex using faces indices.
  936. col_tgt_arr.resize(pMesh.mNumFaces);
  937. std::list<int32_t>::const_iterator colidx_it = pColorIdx.begin();
  938. for(size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  939. {
  940. if((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
  941. col_tgt_arr[fi] = col_arr_copy[*colidx_it++];
  942. }
  943. }// if(pColorIdx.size() > 0)
  944. else
  945. {
  946. // when color indices list is absent use CoordIdx.
  947. // check indices array count.
  948. if(pColors.size() < pMesh.mNumFaces)
  949. {
  950. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + to_string(pColors.size()) + ") can not be less than Faces count(" +
  951. to_string(pMesh.mNumFaces) + ").");
  952. }
  953. // create list with colors for every vertex using faces indices.
  954. col_tgt_arr.resize(pMesh.mNumFaces);
  955. for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) col_tgt_arr[fi] = col_arr_copy[fi];
  956. }// if(pColorIdx.size() > 0) else
  957. }// if(pColorPerVertex) else
  958. // copy array to list for calling function that add colors.
  959. for(std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); it++) col_tgt_list.push_back(*it);
  960. // add prepared colors list to mesh.
  961. MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex);
  962. }
  963. void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pNormalIdx,
  964. const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const
  965. {
  966. std::vector<size_t> tind;
  967. std::vector<aiVector3D> norm_arr_copy;
  968. // copy list to array because we are need indexed access to normals.
  969. norm_arr_copy.reserve(pNormals.size());
  970. for ( std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); it++ )
  971. {
  972. norm_arr_copy.push_back( *it );
  973. }
  974. if(pNormalPerVertex)
  975. {
  976. const std::list<int32_t>* srcidx;
  977. if(pNormalIdx.size() > 0)
  978. {
  979. // check indices array count.
  980. if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
  981. srcidx = &pNormalIdx;
  982. }
  983. else
  984. {
  985. srcidx = &pCoordIdx;
  986. }
  987. tind.reserve(srcidx->size());
  988. for(std::list<int32_t>::const_iterator it = srcidx->begin(); it != srcidx->end(); it++)
  989. {
  990. if(*it != (-1)) tind.push_back(*it);
  991. }
  992. // copy normals to mesh
  993. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  994. for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++)
  995. {
  996. if(tind[i] >= norm_arr_copy.size())
  997. throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) +
  998. ") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + ".");
  999. pMesh.mNormals[i] = norm_arr_copy[tind[i]];
  1000. }
  1001. }// if(pNormalPerVertex)
  1002. else
  1003. {
  1004. if(pNormalIdx.size() > 0)
  1005. {
  1006. if(pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
  1007. std::list<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
  1008. tind.reserve(pNormalIdx.size());
  1009. for(size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++) tind.push_back(*normidx_it++);
  1010. }
  1011. else
  1012. {
  1013. tind.reserve(pMesh.mNumFaces);
  1014. for(size_t i = 0; i < pMesh.mNumFaces; i++) tind.push_back(i);
  1015. }
  1016. // copy normals to mesh
  1017. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  1018. for(size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  1019. {
  1020. aiVector3D tnorm;
  1021. tnorm = norm_arr_copy[tind[fi]];
  1022. for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm;
  1023. }
  1024. }// if(pNormalPerVertex) else
  1025. }
  1026. void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<aiVector3D>& pNormals, const bool pNormalPerVertex) const
  1027. {
  1028. std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
  1029. if(pNormalPerVertex)
  1030. {
  1031. if(pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
  1032. // copy normals to mesh
  1033. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  1034. for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mNormals[i] = *norm_it++;
  1035. }// if(pNormalPerVertex)
  1036. else
  1037. {
  1038. if(pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal.");
  1039. // copy normals to mesh
  1040. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  1041. for(size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  1042. {
  1043. // apply color to all vertices of face
  1044. for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
  1045. norm_it++;
  1046. }
  1047. }// if(pNormalPerVertex) else
  1048. }
  1049. void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<int32_t>& pCoordIdx, const std::list<int32_t>& pTexCoordIdx,
  1050. const std::list<aiVector2D>& pTexCoords) const
  1051. {
  1052. std::vector<aiVector3D> texcoord_arr_copy;
  1053. std::vector<aiFace> faces;
  1054. unsigned int prim_type;
  1055. // copy list to array because we are need indexed access to normals.
  1056. texcoord_arr_copy.reserve(pTexCoords.size());
  1057. for(std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++)
  1058. {
  1059. texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
  1060. }
  1061. if(pTexCoordIdx.size() > 0)
  1062. {
  1063. GeometryHelper_CoordIdxStr2FacesArr(pTexCoordIdx, faces, prim_type);
  1064. if ( faces.empty() )
  1065. {
  1066. throw DeadlyImportError( "Failed to add texture coordinates to mesh, faces list is empty." );
  1067. }
  1068. if ( faces.size() != pMesh.mNumFaces )
  1069. {
  1070. throw DeadlyImportError( "Texture coordinates faces count must be equal to mesh faces count." );
  1071. }
  1072. }
  1073. else
  1074. {
  1075. GeometryHelper_CoordIdxStr2FacesArr(pCoordIdx, faces, prim_type);
  1076. }
  1077. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  1078. pMesh.mNumUVComponents[0] = 2;
  1079. for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
  1080. {
  1081. if(pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices)
  1082. throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + to_string(fi) + ".");
  1083. for(size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++)
  1084. {
  1085. size_t vert_idx = pMesh.mFaces[fi].mIndices[ii];
  1086. size_t tc_idx = faces.at(fi).mIndices[ii];
  1087. pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx);
  1088. }
  1089. }// for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
  1090. }
  1091. void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<aiVector2D>& pTexCoords) const
  1092. {
  1093. std::vector<aiVector3D> tc_arr_copy;
  1094. if ( pTexCoords.size() != pMesh.mNumVertices )
  1095. {
  1096. throw DeadlyImportError( "MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal." );
  1097. }
  1098. // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
  1099. tc_arr_copy.reserve(pTexCoords.size());
  1100. for ( std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++ )
  1101. {
  1102. tc_arr_copy.push_back( aiVector3D( ( *it ).x, ( *it ).y, 0 ) );
  1103. }
  1104. // copy texture coordinates to mesh
  1105. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  1106. pMesh.mNumUVComponents[0] = 2;
  1107. for ( size_t i = 0; i < pMesh.mNumVertices; i++ )
  1108. {
  1109. pMesh.mTextureCoords[ 0 ][ i ] = tc_arr_copy[ i ];
  1110. }
  1111. }
  1112. aiMesh* X3DImporter::GeometryHelper_MakeMesh(const std::list<int32_t>& pCoordIdx, const std::list<aiVector3D>& pVertices) const
  1113. {
  1114. std::vector<aiFace> faces;
  1115. unsigned int prim_type = 0;
  1116. // create faces array from input string with vertices indices.
  1117. GeometryHelper_CoordIdxStr2FacesArr(pCoordIdx, faces, prim_type);
  1118. if ( !faces.size() )
  1119. {
  1120. throw DeadlyImportError( "Failed to create mesh, faces list is empty." );
  1121. }
  1122. //
  1123. // Create new mesh and copy geometry data.
  1124. //
  1125. aiMesh *tmesh = new aiMesh;
  1126. size_t ts = faces.size();
  1127. // faces
  1128. tmesh->mFaces = new aiFace[ts];
  1129. tmesh->mNumFaces = static_cast<unsigned int>(ts);
  1130. for(size_t i = 0; i < ts; i++) tmesh->mFaces[i] = faces.at(i);
  1131. // vertices
  1132. std::list<aiVector3D>::const_iterator vit = pVertices.begin();
  1133. ts = pVertices.size();
  1134. tmesh->mVertices = new aiVector3D[ts];
  1135. tmesh->mNumVertices = static_cast<unsigned int>(ts);
  1136. for ( size_t i = 0; i < ts; i++ )
  1137. {
  1138. tmesh->mVertices[ i ] = *vit++;
  1139. }
  1140. // set primitives type and return result.
  1141. tmesh->mPrimitiveTypes = prim_type;
  1142. return tmesh;
  1143. }
  1144. /*********************************************************************************************************************************************/
  1145. /************************************************************ Functions: parse set ***********************************************************/
  1146. /*********************************************************************************************************************************************/
  1147. void X3DImporter::ParseHelper_Group_Begin(const bool pStatic)
  1148. {
  1149. CX3DImporter_NodeElement_Group* new_group = new CX3DImporter_NodeElement_Group(NodeElement_Cur, pStatic);// create new node with current node as parent.
  1150. // if we are adding not the root element then add new element to current element child list.
  1151. if ( NodeElement_Cur != nullptr )
  1152. {
  1153. NodeElement_Cur->Child.push_back( new_group );
  1154. }
  1155. NodeElement_List.push_back(new_group);// it's a new element - add it to list.
  1156. NodeElement_Cur = new_group;// switch current element to new one.
  1157. }
  1158. void X3DImporter::ParseHelper_Node_Enter(CX3DImporter_NodeElement* pNode)
  1159. {
  1160. NodeElement_Cur->Child.push_back(pNode);// add new element to current element child list.
  1161. NodeElement_Cur = pNode;// switch current element to new one.
  1162. }
  1163. void X3DImporter::ParseHelper_Node_Exit()
  1164. {
  1165. // check if we can walk up.
  1166. if ( NodeElement_Cur != nullptr )
  1167. {
  1168. NodeElement_Cur = NodeElement_Cur->Parent;
  1169. }
  1170. }
  1171. void X3DImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString)
  1172. {
  1173. pOutString.clear();
  1174. const size_t instr_len = strlen(pInStr);
  1175. if ( 0 == instr_len )
  1176. {
  1177. return;
  1178. }
  1179. pOutString.reserve(instr_len * 3 / 2);
  1180. // check and correct floats in format ".x". Must be "x.y".
  1181. if ( pInStr[ 0 ] == '.' )
  1182. {
  1183. pOutString.push_back( '0' );
  1184. }
  1185. pOutString.push_back(pInStr[0]);
  1186. for(size_t ci = 1; ci < instr_len; ci++)
  1187. {
  1188. if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t')))
  1189. {
  1190. pOutString.push_back('0');
  1191. pOutString.push_back('.');
  1192. }
  1193. else
  1194. {
  1195. pOutString.push_back(pInStr[ci]);
  1196. }
  1197. }
  1198. }
  1199. void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
  1200. {
  1201. irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
  1202. std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
  1203. // Check whether we can read from the file
  1204. if ( file.get() == nullptr )
  1205. {
  1206. throw DeadlyImportError( "Failed to open X3D file " + pFile + "." );
  1207. }
  1208. // generate a XML reader for it
  1209. std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
  1210. mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
  1211. if ( !mReader )
  1212. {
  1213. throw DeadlyImportError( "Failed to create XML reader for file" + pFile + "." );
  1214. }
  1215. // start reading
  1216. ParseNode_Root();
  1217. delete mReader;
  1218. // restore old XMLreader
  1219. mReader = OldReader;
  1220. }
  1221. void X3DImporter::ParseNode_Root()
  1222. {
  1223. // search for root tag <X3D>
  1224. if ( !XML_SearchNode( "X3D" ) )
  1225. {
  1226. throw DeadlyImportError( "Root node \"X3D\" not found." );
  1227. }
  1228. ParseHelper_Group_Begin();// create root node element.
  1229. // parse other contents
  1230. while(mReader->read())
  1231. {
  1232. if ( mReader->getNodeType() != irr::io::EXN_ELEMENT )
  1233. {
  1234. continue;
  1235. }
  1236. if(XML_CheckNode_NameEqual("head"))
  1237. ParseNode_Head();
  1238. else if(XML_CheckNode_NameEqual("Scene"))
  1239. ParseNode_Scene();
  1240. else
  1241. XML_CheckNode_SkipUnsupported("Root");
  1242. }
  1243. // exit from root node element.
  1244. ParseHelper_Node_Exit();
  1245. }
  1246. void X3DImporter::ParseNode_Head()
  1247. {
  1248. bool close_found = false;// flag: true if close tag of node are found.
  1249. while(mReader->read())
  1250. {
  1251. if(mReader->getNodeType() == irr::io::EXN_ELEMENT)
  1252. {
  1253. if(XML_CheckNode_NameEqual("meta"))
  1254. {
  1255. XML_CheckNode_MustBeEmpty();
  1256. // adding metadata from <head> as MetaString from <Scene>
  1257. bool added( false );
  1258. CX3DImporter_NodeElement_MetaString* ms = new CX3DImporter_NodeElement_MetaString(NodeElement_Cur);
  1259. ms->Name = mReader->getAttributeValueSafe("name");
  1260. // name must not be empty
  1261. if(!ms->Name.empty())
  1262. {
  1263. ms->Value.push_back(mReader->getAttributeValueSafe("content"));
  1264. NodeElement_List.push_back(ms);
  1265. if ( NodeElement_Cur != nullptr )
  1266. {
  1267. NodeElement_Cur->Child.push_back( ms );
  1268. added = true;
  1269. }
  1270. }
  1271. // if an error has occurred, release instance
  1272. if ( !added ) {
  1273. delete ms;
  1274. }
  1275. }// if(XML_CheckNode_NameEqual("meta"))
  1276. }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT)
  1277. else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
  1278. {
  1279. if(XML_CheckNode_NameEqual("head"))
  1280. {
  1281. close_found = true;
  1282. break;
  1283. }
  1284. }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) else
  1285. }// while(mReader->read())
  1286. if ( !close_found )
  1287. {
  1288. Throw_CloseNotFound( "head" );
  1289. }
  1290. }
  1291. void X3DImporter::ParseNode_Scene()
  1292. {
  1293. auto GroupCounter_Increase = [](size_t& pCounter, const char* pGroupName) -> void
  1294. {
  1295. pCounter++;
  1296. if(pCounter == 0) throw DeadlyImportError("Group counter overflow. Too much groups with type: " + std::string(pGroupName) + ".");
  1297. };
  1298. auto GroupCounter_Decrease = [&](size_t& pCounter, const char* pGroupName) -> void
  1299. {
  1300. if(pCounter == 0) Throw_TagCountIncorrect(pGroupName);
  1301. pCounter--;
  1302. };
  1303. static const char* GroupName_Group = "Group";
  1304. static const char* GroupName_StaticGroup = "StaticGroup";
  1305. static const char* GroupName_Transform = "Transform";
  1306. static const char* GroupName_Switch = "Switch";
  1307. bool close_found = false;
  1308. size_t counter_group = 0;
  1309. size_t counter_transform = 0;
  1310. size_t counter_switch = 0;
  1311. // while create static node? Because objects name used deeper in "USE" attribute can be equal to some meta in <head> node.
  1312. ParseHelper_Group_Begin(true);
  1313. while(mReader->read())
  1314. {
  1315. if(mReader->getNodeType() == irr::io::EXN_ELEMENT)
  1316. {
  1317. if(XML_CheckNode_NameEqual("Shape"))
  1318. {
  1319. ParseNode_Shape_Shape();
  1320. }
  1321. else if(XML_CheckNode_NameEqual(GroupName_Group))
  1322. {
  1323. GroupCounter_Increase(counter_group, GroupName_Group);
  1324. ParseNode_Grouping_Group();
  1325. // if node is empty then decrease group counter at this place.
  1326. if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_group, GroupName_Group);
  1327. }
  1328. else if(XML_CheckNode_NameEqual(GroupName_StaticGroup))
  1329. {
  1330. GroupCounter_Increase(counter_group, GroupName_StaticGroup);
  1331. ParseNode_Grouping_StaticGroup();
  1332. // if node is empty then decrease group counter at this place.
  1333. if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_group, GroupName_StaticGroup);
  1334. }
  1335. else if(XML_CheckNode_NameEqual(GroupName_Transform))
  1336. {
  1337. GroupCounter_Increase(counter_transform, GroupName_Transform);
  1338. ParseNode_Grouping_Transform();
  1339. // if node is empty then decrease group counter at this place.
  1340. if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_transform, GroupName_Transform);
  1341. }
  1342. else if(XML_CheckNode_NameEqual(GroupName_Switch))
  1343. {
  1344. GroupCounter_Increase(counter_switch, GroupName_Switch);
  1345. ParseNode_Grouping_Switch();
  1346. // if node is empty then decrease group counter at this place.
  1347. if(mReader->isEmptyElement()) GroupCounter_Decrease(counter_switch, GroupName_Switch);
  1348. }
  1349. else if(XML_CheckNode_NameEqual("DirectionalLight"))
  1350. {
  1351. ParseNode_Lighting_DirectionalLight();
  1352. }
  1353. else if(XML_CheckNode_NameEqual("PointLight"))
  1354. {
  1355. ParseNode_Lighting_PointLight();
  1356. }
  1357. else if(XML_CheckNode_NameEqual("SpotLight"))
  1358. {
  1359. ParseNode_Lighting_SpotLight();
  1360. }
  1361. else if(XML_CheckNode_NameEqual("Inline"))
  1362. {
  1363. ParseNode_Networking_Inline();
  1364. }
  1365. else if(!ParseHelper_CheckRead_X3DMetadataObject())
  1366. {
  1367. XML_CheckNode_SkipUnsupported("Scene");
  1368. }
  1369. }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT)
  1370. else if(mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
  1371. {
  1372. if(XML_CheckNode_NameEqual("Scene"))
  1373. {
  1374. close_found = true;
  1375. break;
  1376. }
  1377. else if(XML_CheckNode_NameEqual(GroupName_Group))
  1378. {
  1379. GroupCounter_Decrease(counter_group, GroupName_Group);
  1380. ParseNode_Grouping_GroupEnd();
  1381. }
  1382. else if(XML_CheckNode_NameEqual(GroupName_StaticGroup))
  1383. {
  1384. GroupCounter_Decrease(counter_group, GroupName_StaticGroup);
  1385. ParseNode_Grouping_StaticGroupEnd();
  1386. }
  1387. else if(XML_CheckNode_NameEqual(GroupName_Transform))
  1388. {
  1389. GroupCounter_Decrease(counter_transform, GroupName_Transform);
  1390. ParseNode_Grouping_TransformEnd();
  1391. }
  1392. else if(XML_CheckNode_NameEqual(GroupName_Switch))
  1393. {
  1394. GroupCounter_Decrease(counter_switch, GroupName_Switch);
  1395. ParseNode_Grouping_SwitchEnd();
  1396. }
  1397. }// if(mReader->getNodeType() == irr::io::EXN_ELEMENT) else
  1398. }// while(mReader->read())
  1399. ParseHelper_Node_Exit();
  1400. if(counter_group) Throw_TagCountIncorrect("Group");
  1401. if(counter_transform) Throw_TagCountIncorrect("Transform");
  1402. if(counter_switch) Throw_TagCountIncorrect("Switch");
  1403. if(!close_found) Throw_CloseNotFound("Scene");
  1404. }
  1405. /*********************************************************************************************************************************************/
  1406. /******************************************************** Functions: BaseImporter set ********************************************************/
  1407. /*********************************************************************************************************************************************/
  1408. bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const
  1409. {
  1410. const std::string extension = GetExtension(pFile);
  1411. if(extension == "x3d") return true;
  1412. if(!extension.length() || pCheckSig)
  1413. {
  1414. const char* tokens[] = { "DOCTYPE X3D PUBLIC", "http://www.web3d.org/specifications/x3d" };
  1415. return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
  1416. }
  1417. return false;
  1418. }
  1419. void X3DImporter::GetExtensionList(std::set<std::string>& pExtensionList)
  1420. {
  1421. pExtensionList.insert("x3d");
  1422. }
  1423. const aiImporterDesc* X3DImporter::GetInfo () const
  1424. {
  1425. return &Description;
  1426. }
  1427. void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
  1428. {
  1429. Clear();// delete old graph.
  1430. mFileDir = DefaultIOSystem::absolutePath(pFile);
  1431. ParseFile(pFile, pIOHandler);
  1432. //
  1433. // Assimp use static arrays of objects for fast speed of rendering. That's good, but need some additional operations/
  1434. // We know that geometry objects(meshes) are stored in <Shape>, also in <Shape>-><Appearance> materials(in Assimp logical view)
  1435. // are stored. So at first we need to count how meshes and materials are stored in scene graph.
  1436. //
  1437. // at first creating root node for aiScene.
  1438. pScene->mRootNode = new aiNode;
  1439. pScene->mRootNode->mParent = nullptr;
  1440. pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
  1441. //search for root node element
  1442. NodeElement_Cur = NodeElement_List.front();
  1443. while(NodeElement_Cur->Parent != nullptr) NodeElement_Cur = NodeElement_Cur->Parent;
  1444. {// fill aiScene with objects.
  1445. std::list<aiMesh*> mesh_list;
  1446. std::list<aiMaterial*> mat_list;
  1447. std::list<aiLight*> light_list;
  1448. // create nodes tree
  1449. Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list);
  1450. // copy needed data to scene
  1451. if(mesh_list.size() > 0)
  1452. {
  1453. std::list<aiMesh*>::const_iterator it = mesh_list.begin();
  1454. pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
  1455. pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
  1456. for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++;
  1457. }
  1458. if(mat_list.size() > 0)
  1459. {
  1460. std::list<aiMaterial*>::const_iterator it = mat_list.begin();
  1461. pScene->mNumMaterials = static_cast<unsigned int>(mat_list.size());
  1462. pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
  1463. for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++;
  1464. }
  1465. if(light_list.size() > 0)
  1466. {
  1467. std::list<aiLight*>::const_iterator it = light_list.begin();
  1468. pScene->mNumLights = static_cast<unsigned int>(light_list.size());
  1469. pScene->mLights = new aiLight*[pScene->mNumLights];
  1470. for(size_t i = 0; i < pScene->mNumLights; i++) pScene->mLights[i] = *it++;
  1471. }
  1472. }// END: fill aiScene with objects.
  1473. ///TODO: IME optimize tree
  1474. }
  1475. }// namespace Assimp
  1476. #endif // !ASSIMP_BUILD_NO_X3D_IMPORTER