X3DGeoHelper.cpp 25 KB

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