X3DGeoHelper.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. #include "X3DGeoHelper.h"
  2. #include "X3DImporter.hpp"
  3. #include <assimp/vector3.h>
  4. #include <assimp/Exceptional.h>
  5. #include <assimp/StringUtils.h>
  6. #include <vector>
  7. namespace Assimp {
  8. aiVector3D X3DGeoHelper::make_point2D(float angle, float radius) {
  9. return aiVector3D(radius * std::cos(angle), radius * std::sin(angle), 0);
  10. }
  11. void X3DGeoHelper::make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices) {
  12. // check argument values ranges.
  13. if ((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) {
  14. throw DeadlyImportError("GeometryHelper_Make_Arc2D.pStartAngle");
  15. }
  16. if ((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) {
  17. throw DeadlyImportError("GeometryHelper_Make_Arc2D.pEndAngle");
  18. }
  19. if (pRadius <= 0) {
  20. throw DeadlyImportError("GeometryHelper_Make_Arc2D.pRadius");
  21. }
  22. // calculate arc angle and check type of arc
  23. float angle_full = std::fabs(pEndAngle - pStartAngle);
  24. if ((angle_full > AI_MATH_TWO_PI_F) || (angle_full == 0.0f)) {
  25. angle_full = AI_MATH_TWO_PI_F;
  26. }
  27. // calculate angle for one step - angle to next point of line.
  28. float angle_step = angle_full / (float)numSegments;
  29. // make points
  30. for (size_t pi = 0; pi <= numSegments; pi++) {
  31. float tangle = pStartAngle + pi * angle_step;
  32. pVertices.emplace_back(make_point2D(tangle, pRadius));
  33. } // for(size_t pi = 0; pi <= pNumSegments; pi++)
  34. // if we making full circle then add last vertex equal to first vertex
  35. if (angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin());
  36. }
  37. void X3DGeoHelper::extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine) {
  38. std::list<aiVector3D>::const_iterator pit = pPoint.begin();
  39. std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
  40. --pit_last;
  41. if (pPoint.size() < 2) {
  42. throw DeadlyImportError("GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2.");
  43. }
  44. // add first point of first line.
  45. pLine.push_back(*pit++);
  46. // add internal points
  47. while (pit != pit_last) {
  48. pLine.push_back(*pit); // second point of previous line
  49. pLine.push_back(*pit); // first point of next line
  50. ++pit;
  51. }
  52. // add last point of last line
  53. pLine.push_back(*pit);
  54. }
  55. void X3DGeoHelper::polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx) {
  56. std::list<int32_t>::const_iterator plit = pPolylineCoordIdx.begin();
  57. while (plit != pPolylineCoordIdx.end()) {
  58. // add first point of polyline
  59. pLineCoordIdx.push_back(*plit++);
  60. while ((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) {
  61. std::list<int32_t>::const_iterator plit_next;
  62. plit_next = plit, ++plit_next;
  63. pLineCoordIdx.push_back(*plit); // second point of previous line.
  64. pLineCoordIdx.push_back(-1); // delimiter
  65. if ((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break; // current polyline is finished
  66. pLineCoordIdx.push_back(*plit); // first point of next line.
  67. plit = plit_next;
  68. } // while((*plit != (-1)) && (plit != pPolylineCoordIdx.end()))
  69. } // while(plit != pPolylineCoordIdx.end())
  70. }
  71. #define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \
  72. do { \
  73. if (pCCW) { \
  74. pOut.push_back(pIn[pP1]); \
  75. pOut.push_back(pIn[pP2]); \
  76. pOut.push_back(pIn[pP3]); \
  77. pOut.push_back(pIn[pP4]); \
  78. } else { \
  79. pOut.push_back(pIn[pP4]); \
  80. pOut.push_back(pIn[pP3]); \
  81. pOut.push_back(pIn[pP2]); \
  82. pOut.push_back(pIn[pP1]); \
  83. } \
  84. } while (false)
  85. #define MESH_RectParallelepiped_CREATE_VERT \
  86. aiVector3D vert_set[8]; \
  87. float x1, x2, y1, y2, z1, z2, hs; \
  88. \
  89. hs = pSize.x / 2, x1 = -hs, x2 = hs; \
  90. hs = pSize.y / 2, y1 = -hs, y2 = hs; \
  91. hs = pSize.z / 2, z1 = -hs, z2 = hs; \
  92. vert_set[0].Set(x2, y1, z2); \
  93. vert_set[1].Set(x2, y2, z2); \
  94. vert_set[2].Set(x2, y2, z1); \
  95. vert_set[3].Set(x2, y1, z1); \
  96. vert_set[4].Set(x1, y1, z2); \
  97. vert_set[5].Set(x1, y2, z2); \
  98. vert_set[6].Set(x1, y2, z1); \
  99. vert_set[7].Set(x1, y1, z1)
  100. void X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices) {
  101. MESH_RectParallelepiped_CREATE_VERT;
  102. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0); // front
  103. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5); // back
  104. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4); // left
  105. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1); // right
  106. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4); // top
  107. MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3); // bottom
  108. }
  109. #undef MESH_RectParallelepiped_CREATE_VERT
  110. void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) {
  111. std::vector<int32_t> f_data(pCoordIdx);
  112. std::vector<unsigned int> inds;
  113. unsigned int prim_type = 0;
  114. if (f_data.back() != (-1)) {
  115. f_data.push_back(-1);
  116. }
  117. // reserve average size.
  118. pFaces.reserve(f_data.size() / 3);
  119. inds.reserve(4);
  120. //PrintVectorSet("build. ci", pCoordIdx);
  121. for (std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); ++it) {
  122. // when face is got count how many indices in it.
  123. if (*it == (-1)) {
  124. aiFace tface;
  125. size_t ts;
  126. ts = inds.size();
  127. switch (ts) {
  128. case 0:
  129. goto mg_m_err;
  130. case 1:
  131. prim_type |= aiPrimitiveType_POINT;
  132. break;
  133. case 2:
  134. prim_type |= aiPrimitiveType_LINE;
  135. break;
  136. case 3:
  137. prim_type |= aiPrimitiveType_TRIANGLE;
  138. break;
  139. default:
  140. prim_type |= aiPrimitiveType_POLYGON;
  141. break;
  142. }
  143. tface.mNumIndices = static_cast<unsigned int>(ts);
  144. tface.mIndices = new unsigned int[ts];
  145. memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int));
  146. pFaces.push_back(tface);
  147. inds.clear();
  148. } // if(*it == (-1))
  149. else {
  150. inds.push_back(*it);
  151. } // if(*it == (-1)) else
  152. } // for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++)
  153. //PrintVectorSet("build. faces", pCoordIdx);
  154. pPrimitiveTypes = prim_type;
  155. return;
  156. mg_m_err:
  157. for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
  158. delete[] pFaces.at(i).mIndices;
  159. pFaces.clear();
  160. }
  161. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
  162. std::list<aiColor4D> tcol;
  163. // create RGBA array from RGB.
  164. for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it)
  165. tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
  166. // call existing function for adding RGBA colors
  167. add_color(pMesh, tcol, pColorPerVertex);
  168. }
  169. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) {
  170. std::list<aiColor4D>::const_iterator col_it = pColors.begin();
  171. if (pColorPerVertex) {
  172. if (pColors.size() < pMesh.mNumVertices) {
  173. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" +
  174. ai_to_string(pMesh.mNumVertices) + ").");
  175. }
  176. // copy colors to mesh
  177. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  178. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  179. pMesh.mColors[0][i] = *col_it++;
  180. } // if(pColorPerVertex)
  181. else {
  182. if (pColors.size() < pMesh.mNumFaces) {
  183. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" +
  184. ai_to_string(pMesh.mNumFaces) + ").");
  185. }
  186. // copy colors to mesh
  187. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  188. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  189. // apply color to all vertices of face
  190. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) {
  191. pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it;
  192. }
  193. ++col_it;
  194. }
  195. } // if(pColorPerVertex) else
  196. }
  197. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
  198. const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
  199. std::list<aiColor4D> tcol;
  200. // create RGBA array from RGB.
  201. for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) {
  202. tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
  203. }
  204. // call existing function for adding RGBA colors
  205. add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
  206. }
  207. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx,
  208. const std::list<aiColor4D> &colors, bool pColorPerVertex) {
  209. std::vector<aiColor4D> col_tgt_arr;
  210. std::list<aiColor4D> col_tgt_list;
  211. std::vector<aiColor4D> col_arr_copy;
  212. if (coordIdx.size() == 0) {
  213. throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty.");
  214. }
  215. // copy list to array because we are need indexed access to colors.
  216. col_arr_copy.reserve(colors.size());
  217. for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) {
  218. col_arr_copy.push_back(*it);
  219. }
  220. if (pColorPerVertex) {
  221. if (colorIdx.size() > 0) {
  222. // check indices array count.
  223. if (colorIdx.size() < coordIdx.size()) {
  224. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
  225. ") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ").");
  226. }
  227. // create list with colors for every vertex.
  228. col_tgt_arr.resize(pMesh.mNumVertices);
  229. for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.end(); ++colidx_it, ++coordidx_it) {
  230. if (*colidx_it == (-1)) {
  231. continue; // skip faces delimiter
  232. }
  233. if ((unsigned int)(*coordidx_it) > pMesh.mNumVertices) {
  234. throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range.");
  235. }
  236. if ((unsigned int)*colidx_it > pMesh.mNumVertices) {
  237. throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range.");
  238. }
  239. col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it];
  240. }
  241. } // if(pColorIdx.size() > 0)
  242. else {
  243. // when color indices list is absent use CoordIdx.
  244. // check indices array count.
  245. if (colors.size() < pMesh.mNumVertices) {
  246. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" +
  247. ai_to_string(pMesh.mNumVertices) + ").");
  248. }
  249. // create list with colors for every vertex.
  250. col_tgt_arr.resize(pMesh.mNumVertices);
  251. for (size_t i = 0; i < pMesh.mNumVertices; i++) {
  252. col_tgt_arr[i] = col_arr_copy[i];
  253. }
  254. } // if(pColorIdx.size() > 0) else
  255. } // if(pColorPerVertex)
  256. else {
  257. if (colorIdx.size() > 0) {
  258. // check indices array count.
  259. if (colorIdx.size() < pMesh.mNumFaces) {
  260. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
  261. ") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ").");
  262. }
  263. // create list with colors for every vertex using faces indices.
  264. col_tgt_arr.resize(pMesh.mNumFaces);
  265. std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin();
  266. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  267. if ((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
  268. col_tgt_arr[fi] = col_arr_copy[*colidx_it++];
  269. }
  270. } // if(pColorIdx.size() > 0)
  271. else {
  272. // when color indices list is absent use CoordIdx.
  273. // check indices array count.
  274. if (colors.size() < pMesh.mNumFaces) {
  275. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" +
  276. ai_to_string(pMesh.mNumFaces) + ").");
  277. }
  278. // create list with colors for every vertex using faces indices.
  279. col_tgt_arr.resize(pMesh.mNumFaces);
  280. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  281. col_tgt_arr[fi] = col_arr_copy[fi];
  282. } // if(pColorIdx.size() > 0) else
  283. } // if(pColorPerVertex) else
  284. // copy array to list for calling function that add colors.
  285. for (std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it)
  286. col_tgt_list.push_back(*it);
  287. // add prepared colors list to mesh.
  288. add_color(pMesh, col_tgt_list, pColorPerVertex);
  289. }
  290. void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
  291. const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
  292. std::vector<size_t> tind;
  293. std::vector<aiVector3D> norm_arr_copy;
  294. // copy list to array because we are need indexed access to normals.
  295. norm_arr_copy.reserve(pNormals.size());
  296. for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) {
  297. norm_arr_copy.push_back(*it);
  298. }
  299. if (pNormalPerVertex) {
  300. if (pNormalIdx.size() > 0) {
  301. // check indices array count.
  302. if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
  303. tind.reserve(pNormalIdx.size());
  304. for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) {
  305. if (*it != (-1)) tind.push_back(*it);
  306. }
  307. // copy normals to mesh
  308. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  309. for (size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) {
  310. if (tind[i] >= norm_arr_copy.size())
  311. throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) +
  312. ") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + ".");
  313. pMesh.mNormals[i] = norm_arr_copy[tind[i]];
  314. }
  315. } else {
  316. if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
  317. // copy normals to mesh
  318. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  319. std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
  320. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  321. pMesh.mNormals[i] = *norm_it++;
  322. }
  323. } // if(pNormalPerVertex)
  324. else {
  325. if (pNormalIdx.size() > 0) {
  326. if (pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
  327. std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
  328. tind.reserve(pNormalIdx.size());
  329. for (size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++)
  330. tind.push_back(*normidx_it++);
  331. } else {
  332. tind.reserve(pMesh.mNumFaces);
  333. for (size_t i = 0; i < pMesh.mNumFaces; i++)
  334. tind.push_back(i);
  335. }
  336. // copy normals to mesh
  337. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  338. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  339. aiVector3D tnorm;
  340. tnorm = norm_arr_copy[tind[fi]];
  341. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
  342. pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm;
  343. }
  344. } // if(pNormalPerVertex) else
  345. }
  346. void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
  347. std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
  348. if (pNormalPerVertex) {
  349. if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
  350. // copy normals to mesh
  351. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  352. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  353. pMesh.mNormals[i] = *norm_it++;
  354. } // if(pNormalPerVertex)
  355. else {
  356. if (pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal.");
  357. // copy normals to mesh
  358. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  359. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  360. // apply color to all vertices of face
  361. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
  362. pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
  363. ++norm_it;
  364. }
  365. } // if(pNormalPerVertex) else
  366. }
  367. void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
  368. const std::list<aiVector2D> &pTexCoords) {
  369. std::vector<aiVector3D> texcoord_arr_copy;
  370. std::vector<aiFace> faces;
  371. unsigned int prim_type;
  372. // copy list to array because we are need indexed access to normals.
  373. texcoord_arr_copy.reserve(pTexCoords.size());
  374. for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
  375. texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
  376. }
  377. if (pTexCoordIdx.size() > 0) {
  378. coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type);
  379. if (faces.empty()) {
  380. throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty.");
  381. }
  382. if (faces.size() != pMesh.mNumFaces) {
  383. throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count.");
  384. }
  385. } else {
  386. coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
  387. }
  388. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  389. pMesh.mNumUVComponents[0] = 2;
  390. for (size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) {
  391. if (pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices)
  392. throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(fi) + ".");
  393. for (size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) {
  394. size_t vert_idx = pMesh.mFaces[fi].mIndices[ii];
  395. size_t tc_idx = faces.at(fi).mIndices[ii];
  396. pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx);
  397. }
  398. } // for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
  399. }
  400. void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) {
  401. std::vector<aiVector3D> tc_arr_copy;
  402. if (pTexCoords.size() != pMesh.mNumVertices) {
  403. throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal.");
  404. }
  405. // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
  406. tc_arr_copy.reserve(pTexCoords.size());
  407. for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
  408. tc_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
  409. }
  410. // copy texture coordinates to mesh
  411. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  412. pMesh.mNumUVComponents[0] = 2;
  413. for (size_t i = 0; i < pMesh.mNumVertices; i++) {
  414. pMesh.mTextureCoords[0][i] = tc_arr_copy[i];
  415. }
  416. }
  417. aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
  418. std::vector<aiFace> faces;
  419. unsigned int prim_type = 0;
  420. // create faces array from input string with vertices indices.
  421. X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
  422. if (!faces.size()) {
  423. throw DeadlyImportError("Failed to create mesh, faces list is empty.");
  424. }
  425. //
  426. // Create new mesh and copy geometry data.
  427. //
  428. aiMesh *tmesh = new aiMesh;
  429. size_t ts = faces.size();
  430. // faces
  431. tmesh->mFaces = new aiFace[ts];
  432. tmesh->mNumFaces = static_cast<unsigned int>(ts);
  433. for (size_t i = 0; i < ts; i++)
  434. tmesh->mFaces[i] = faces.at(i);
  435. // vertices
  436. std::list<aiVector3D>::const_iterator vit = pVertices.begin();
  437. ts = pVertices.size();
  438. tmesh->mVertices = new aiVector3D[ts];
  439. tmesh->mNumVertices = static_cast<unsigned int>(ts);
  440. for (size_t i = 0; i < ts; i++) {
  441. tmesh->mVertices[i] = *vit++;
  442. }
  443. // set primitives type and return result.
  444. tmesh->mPrimitiveTypes = prim_type;
  445. return tmesh;
  446. }
  447. } // namespace Assimp