X3DGeoHelper.cpp 22 KB

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