X3DGeoHelper.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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::coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces) {
  162. std::vector<int32_t> f_data(pCoordIdx);
  163. if (f_data.back() != (-1)) {
  164. f_data.push_back(-1);
  165. }
  166. // reserve average size.
  167. pFaces.reserve(f_data.size() / 2);
  168. for (std::vector<int32_t>::const_iterator startIt = f_data.cbegin(), endIt = f_data.cbegin(); endIt != f_data.cend(); ++endIt) {
  169. // check for end of current polyline
  170. if (*endIt != -1)
  171. continue;
  172. // found end of polyline, check if this is a valid polyline
  173. std::size_t numIndices = std::distance(startIt, endIt);
  174. if (numIndices <= 1)
  175. goto mg_m_err;
  176. // create line faces out of polyline indices
  177. for (int32_t idx0 = *startIt++; startIt != endIt; ++startIt) {
  178. int32_t idx1 = *startIt;
  179. aiFace tface;
  180. tface.mNumIndices = 2;
  181. tface.mIndices = new unsigned int[2];
  182. tface.mIndices[0] = idx0;
  183. tface.mIndices[1] = idx1;
  184. pFaces.push_back(tface);
  185. idx0 = idx1;
  186. }
  187. ++startIt;
  188. }
  189. return;
  190. mg_m_err:
  191. for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++)
  192. delete[] pFaces[i].mIndices;
  193. pFaces.clear();
  194. }
  195. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
  196. std::list<aiColor4D> tcol;
  197. // create RGBA array from RGB.
  198. for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it)
  199. tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1));
  200. // call existing function for adding RGBA colors
  201. add_color(pMesh, tcol, pColorPerVertex);
  202. }
  203. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) {
  204. std::list<aiColor4D>::const_iterator col_it = pColors.begin();
  205. if (pColorPerVertex) {
  206. if (pColors.size() < pMesh.mNumVertices) {
  207. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" +
  208. ai_to_string(pMesh.mNumVertices) + ").");
  209. }
  210. // copy colors to mesh
  211. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  212. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  213. pMesh.mColors[0][i] = *col_it++;
  214. } // if(pColorPerVertex)
  215. else {
  216. if (pColors.size() < pMesh.mNumFaces) {
  217. throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" +
  218. ai_to_string(pMesh.mNumFaces) + ").");
  219. }
  220. // copy colors to mesh
  221. pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices];
  222. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  223. // apply color to all vertices of face
  224. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) {
  225. pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it;
  226. }
  227. ++col_it;
  228. }
  229. } // if(pColorPerVertex) else
  230. }
  231. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx,
  232. const std::list<aiColor3D> &pColors, const bool pColorPerVertex) {
  233. std::list<aiColor4D> tcol;
  234. // create RGBA array from RGB.
  235. for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) {
  236. tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1));
  237. }
  238. // call existing function for adding RGBA colors
  239. add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex);
  240. }
  241. void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx,
  242. const std::list<aiColor4D> &colors, bool pColorPerVertex) {
  243. std::vector<aiColor4D> col_tgt_arr;
  244. std::list<aiColor4D> col_tgt_list;
  245. std::vector<aiColor4D> col_arr_copy;
  246. if (coordIdx.size() == 0) {
  247. throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty.");
  248. }
  249. // copy list to array because we are need indexed access to colors.
  250. col_arr_copy.reserve(colors.size());
  251. for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) {
  252. col_arr_copy.push_back(*it);
  253. }
  254. if (pColorPerVertex) {
  255. if (colorIdx.size() > 0) {
  256. // check indices array count.
  257. if (colorIdx.size() < coordIdx.size()) {
  258. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
  259. ") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ").");
  260. }
  261. // create list with colors for every vertex.
  262. col_tgt_arr.resize(pMesh.mNumVertices);
  263. for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.end(); ++colidx_it, ++coordidx_it) {
  264. if (*colidx_it == (-1)) {
  265. continue; // skip faces delimiter
  266. }
  267. if ((unsigned int)(*coordidx_it) > pMesh.mNumVertices) {
  268. throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range.");
  269. }
  270. if ((unsigned int)*colidx_it > pMesh.mNumVertices) {
  271. throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range.");
  272. }
  273. col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it];
  274. }
  275. } // if(pColorIdx.size() > 0)
  276. else {
  277. // when color indices list is absent use CoordIdx.
  278. // check indices array count.
  279. if (colors.size() < pMesh.mNumVertices) {
  280. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" +
  281. ai_to_string(pMesh.mNumVertices) + ").");
  282. }
  283. // create list with colors for every vertex.
  284. col_tgt_arr.resize(pMesh.mNumVertices);
  285. for (size_t i = 0; i < pMesh.mNumVertices; i++) {
  286. col_tgt_arr[i] = col_arr_copy[i];
  287. }
  288. } // if(pColorIdx.size() > 0) else
  289. } // if(pColorPerVertex)
  290. else {
  291. if (colorIdx.size() > 0) {
  292. // check indices array count.
  293. if (colorIdx.size() < pMesh.mNumFaces) {
  294. throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) +
  295. ") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ").");
  296. }
  297. // create list with colors for every vertex using faces indices.
  298. col_tgt_arr.resize(pMesh.mNumFaces);
  299. std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin();
  300. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  301. if ((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range.");
  302. col_tgt_arr[fi] = col_arr_copy[*colidx_it++];
  303. }
  304. } // if(pColorIdx.size() > 0)
  305. else {
  306. // when color indices list is absent use CoordIdx.
  307. // check indices array count.
  308. if (colors.size() < pMesh.mNumFaces) {
  309. throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" +
  310. ai_to_string(pMesh.mNumFaces) + ").");
  311. }
  312. // create list with colors for every vertex using faces indices.
  313. col_tgt_arr.resize(pMesh.mNumFaces);
  314. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++)
  315. col_tgt_arr[fi] = col_arr_copy[fi];
  316. } // if(pColorIdx.size() > 0) else
  317. } // if(pColorPerVertex) else
  318. // copy array to list for calling function that add colors.
  319. for (std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it)
  320. col_tgt_list.push_back(*it);
  321. // add prepared colors list to mesh.
  322. add_color(pMesh, col_tgt_list, pColorPerVertex);
  323. }
  324. void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx,
  325. const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
  326. std::vector<size_t> tind;
  327. std::vector<aiVector3D> norm_arr_copy;
  328. // copy list to array because we are need indexed access to normals.
  329. norm_arr_copy.reserve(pNormals.size());
  330. for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) {
  331. norm_arr_copy.push_back(*it);
  332. }
  333. if (pNormalPerVertex) {
  334. if (pNormalIdx.size() > 0) {
  335. // check indices array count.
  336. if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
  337. tind.reserve(pNormalIdx.size());
  338. for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) {
  339. if (*it != (-1)) tind.push_back(*it);
  340. }
  341. // copy normals to mesh
  342. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  343. for (size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) {
  344. if (tind[i] >= norm_arr_copy.size())
  345. throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) +
  346. ") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + ".");
  347. pMesh.mNormals[i] = norm_arr_copy[tind[i]];
  348. }
  349. } else {
  350. if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
  351. // copy normals to mesh
  352. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  353. std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
  354. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  355. pMesh.mNormals[i] = *norm_it++;
  356. }
  357. } // if(pNormalPerVertex)
  358. else {
  359. if (pNormalIdx.size() > 0) {
  360. if (pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count.");
  361. std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin();
  362. tind.reserve(pNormalIdx.size());
  363. for (size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++)
  364. tind.push_back(*normidx_it++);
  365. } else {
  366. tind.reserve(pMesh.mNumFaces);
  367. for (size_t i = 0; i < pMesh.mNumFaces; i++)
  368. tind.push_back(i);
  369. }
  370. // copy normals to mesh
  371. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  372. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  373. aiVector3D tnorm;
  374. tnorm = norm_arr_copy[tind[fi]];
  375. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
  376. pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm;
  377. }
  378. } // if(pNormalPerVertex) else
  379. }
  380. void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) {
  381. std::list<aiVector3D>::const_iterator norm_it = pNormals.begin();
  382. if (pNormalPerVertex) {
  383. if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal.");
  384. // copy normals to mesh
  385. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  386. for (size_t i = 0; i < pMesh.mNumVertices; i++)
  387. pMesh.mNormals[i] = *norm_it++;
  388. } // if(pNormalPerVertex)
  389. else {
  390. if (pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal.");
  391. // copy normals to mesh
  392. pMesh.mNormals = new aiVector3D[pMesh.mNumVertices];
  393. for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) {
  394. // apply color to all vertices of face
  395. for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++)
  396. pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
  397. ++norm_it;
  398. }
  399. } // if(pNormalPerVertex) else
  400. }
  401. void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx,
  402. const std::list<aiVector2D> &pTexCoords) {
  403. std::vector<aiVector3D> texcoord_arr_copy;
  404. std::vector<aiFace> faces;
  405. unsigned int prim_type;
  406. // copy list to array because we are need indexed access to normals.
  407. texcoord_arr_copy.reserve(pTexCoords.size());
  408. for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
  409. texcoord_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0));
  410. }
  411. if (pTexCoordIdx.size() > 0) {
  412. coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type);
  413. if (faces.empty()) {
  414. throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty.");
  415. }
  416. if (faces.size() != pMesh.mNumFaces) {
  417. throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count.");
  418. }
  419. } else {
  420. coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
  421. }
  422. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  423. pMesh.mNumUVComponents[0] = 2;
  424. for (size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) {
  425. if (pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices)
  426. throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(fi) + ".");
  427. for (size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) {
  428. size_t vert_idx = pMesh.mFaces[fi].mIndices[ii];
  429. size_t tc_idx = faces.at(fi).mIndices[ii];
  430. pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx);
  431. }
  432. } // for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++)
  433. }
  434. void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) {
  435. std::vector<aiVector3D> tc_arr_copy;
  436. if (pTexCoords.size() != pMesh.mNumVertices) {
  437. throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal.");
  438. }
  439. // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
  440. tc_arr_copy.reserve(pTexCoords.size());
  441. for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) {
  442. tc_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0));
  443. }
  444. // copy texture coordinates to mesh
  445. pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices];
  446. pMesh.mNumUVComponents[0] = 2;
  447. for (size_t i = 0; i < pMesh.mNumVertices; i++) {
  448. pMesh.mTextureCoords[0][i] = tc_arr_copy[i];
  449. }
  450. }
  451. aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
  452. std::vector<aiFace> faces;
  453. unsigned int prim_type = 0;
  454. // create faces array from input string with vertices indices.
  455. X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type);
  456. if (!faces.size()) {
  457. throw DeadlyImportError("Failed to create mesh, faces list is empty.");
  458. }
  459. //
  460. // Create new mesh and copy geometry data.
  461. //
  462. aiMesh *tmesh = new aiMesh;
  463. size_t ts = faces.size();
  464. // faces
  465. tmesh->mFaces = new aiFace[ts];
  466. tmesh->mNumFaces = static_cast<unsigned int>(ts);
  467. for (size_t i = 0; i < ts; i++)
  468. tmesh->mFaces[i] = faces.at(i);
  469. // vertices
  470. std::list<aiVector3D>::const_iterator vit = pVertices.begin();
  471. ts = pVertices.size();
  472. tmesh->mVertices = new aiVector3D[ts];
  473. tmesh->mNumVertices = static_cast<unsigned int>(ts);
  474. for (size_t i = 0; i < ts; i++) {
  475. tmesh->mVertices[i] = *vit++;
  476. }
  477. // set primitives type and return result.
  478. tmesh->mPrimitiveTypes = prim_type;
  479. return tmesh;
  480. }
  481. aiMesh *X3DGeoHelper::make_line_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) {
  482. std::vector<aiFace> faces;
  483. // create faces array from input string with vertices indices.
  484. X3DGeoHelper::coordIdx_str2lines_arr(pCoordIdx, faces);
  485. if (!faces.size()) {
  486. throw DeadlyImportError("Failed to create mesh, faces list is empty.");
  487. }
  488. //
  489. // Create new mesh and copy geometry data.
  490. //
  491. aiMesh *tmesh = new aiMesh;
  492. size_t ts = faces.size();
  493. // faces
  494. tmesh->mFaces = new aiFace[ts];
  495. tmesh->mNumFaces = static_cast<unsigned int>(ts);
  496. for (size_t i = 0; i < ts; i++)
  497. tmesh->mFaces[i] = faces[i];
  498. // vertices
  499. std::list<aiVector3D>::const_iterator vit = pVertices.begin();
  500. ts = pVertices.size();
  501. tmesh->mVertices = new aiVector3D[ts];
  502. tmesh->mNumVertices = static_cast<unsigned int>(ts);
  503. for (size_t i = 0; i < ts; i++) {
  504. tmesh->mVertices[i] = *vit++;
  505. }
  506. // set primitive type and return result.
  507. tmesh->mPrimitiveTypes = aiPrimitiveType_LINE;
  508. return tmesh;
  509. }
  510. } // namespace Assimp