X3DImporter.cpp 54 KB

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