/src/assimp/code/AssetLib/X3D/X3DGeoHelper.cpp
Line | Count | Source |
1 | | #include "X3DGeoHelper.h" |
2 | | #include "X3DImporter.hpp" |
3 | | |
4 | | #include <assimp/vector3.h> |
5 | | #include <assimp/Exceptional.h> |
6 | | #include <assimp/StringUtils.h> |
7 | | |
8 | | #include <vector> |
9 | | |
10 | | namespace Assimp { |
11 | | |
12 | 0 | aiVector3D X3DGeoHelper::make_point2D(float angle, float radius) { |
13 | 0 | return aiVector3D(radius * std::cos(angle), radius * std::sin(angle), 0); |
14 | 0 | } |
15 | | |
16 | 0 | void X3DGeoHelper::make_arc2D(float pStartAngle, float pEndAngle, float pRadius, size_t numSegments, std::list<aiVector3D> &pVertices) { |
17 | | // check argument values ranges. |
18 | 0 | if ((pStartAngle < -AI_MATH_TWO_PI_F) || (pStartAngle > AI_MATH_TWO_PI_F)) { |
19 | 0 | throw DeadlyImportError("GeometryHelper_Make_Arc2D.pStartAngle"); |
20 | 0 | } |
21 | 0 | if ((pEndAngle < -AI_MATH_TWO_PI_F) || (pEndAngle > AI_MATH_TWO_PI_F)) { |
22 | 0 | throw DeadlyImportError("GeometryHelper_Make_Arc2D.pEndAngle"); |
23 | 0 | } |
24 | 0 | if (pRadius <= 0) { |
25 | 0 | throw DeadlyImportError("GeometryHelper_Make_Arc2D.pRadius"); |
26 | 0 | } |
27 | | |
28 | | // calculate arc angle and check type of arc |
29 | 0 | float angle_full = std::fabs(pEndAngle - pStartAngle); |
30 | 0 | if ((angle_full > AI_MATH_TWO_PI_F) || (angle_full == 0.0f)) { |
31 | 0 | angle_full = AI_MATH_TWO_PI_F; |
32 | 0 | } |
33 | | |
34 | | // calculate angle for one step - angle to next point of line. |
35 | 0 | float angle_step = angle_full / (float)numSegments; |
36 | | // make points |
37 | 0 | for (size_t pi = 0; pi <= numSegments; pi++) { |
38 | 0 | float tangle = pStartAngle + pi * angle_step; |
39 | 0 | pVertices.emplace_back(make_point2D(tangle, pRadius)); |
40 | 0 | } // for(size_t pi = 0; pi <= pNumSegments; pi++) |
41 | | |
42 | | // if we making full circle then add last vertex equal to first vertex |
43 | 0 | if (angle_full == AI_MATH_TWO_PI_F) pVertices.push_back(*pVertices.begin()); |
44 | 0 | } |
45 | | |
46 | 0 | void X3DGeoHelper::extend_point_to_line(const std::list<aiVector3D> &pPoint, std::list<aiVector3D> &pLine) { |
47 | 0 | std::list<aiVector3D>::const_iterator pit = pPoint.begin(); |
48 | 0 | std::list<aiVector3D>::const_iterator pit_last = pPoint.end(); |
49 | |
|
50 | 0 | --pit_last; |
51 | |
|
52 | 0 | if (pPoint.size() < 2) { |
53 | 0 | throw DeadlyImportError("GeometryHelper_Extend_PointToLine.pPoint.size() can not be less than 2."); |
54 | 0 | } |
55 | | |
56 | | // add first point of first line. |
57 | 0 | pLine.push_back(*pit++); |
58 | | // add internal points |
59 | 0 | while (pit != pit_last) { |
60 | 0 | pLine.push_back(*pit); // second point of previous line |
61 | 0 | pLine.push_back(*pit); // first point of next line |
62 | 0 | ++pit; |
63 | 0 | } |
64 | | // add last point of last line |
65 | 0 | pLine.push_back(*pit); |
66 | 0 | } |
67 | | |
68 | 0 | void X3DGeoHelper::polylineIdx_to_lineIdx(const std::list<int32_t> &pPolylineCoordIdx, std::list<int32_t> &pLineCoordIdx) { |
69 | 0 | std::list<int32_t>::const_iterator plit = pPolylineCoordIdx.begin(); |
70 | |
|
71 | 0 | while (plit != pPolylineCoordIdx.end()) { |
72 | | // add first point of polyline |
73 | 0 | pLineCoordIdx.push_back(*plit++); |
74 | 0 | while ((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) { |
75 | 0 | std::list<int32_t>::const_iterator plit_next; |
76 | |
|
77 | 0 | plit_next = plit, ++plit_next; |
78 | 0 | pLineCoordIdx.push_back(*plit); // second point of previous line. |
79 | 0 | pLineCoordIdx.push_back(-1); // delimiter |
80 | 0 | if ((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break; // current polyline is finished |
81 | | |
82 | 0 | pLineCoordIdx.push_back(*plit); // first point of next line. |
83 | 0 | plit = plit_next; |
84 | 0 | } // while((*plit != (-1)) && (plit != pPolylineCoordIdx.end())) |
85 | 0 | } // while(plit != pPolylineCoordIdx.end()) |
86 | 0 | } |
87 | | |
88 | | #define MACRO_FACE_ADD_QUAD_FA(pCCW, pOut, pIn, pP1, pP2, pP3, pP4) \ |
89 | 0 | do { \ |
90 | 0 | if (pCCW) { \ |
91 | 0 | pOut.push_back(pIn[pP1]); \ |
92 | 0 | pOut.push_back(pIn[pP2]); \ |
93 | 0 | pOut.push_back(pIn[pP3]); \ |
94 | 0 | pOut.push_back(pIn[pP4]); \ |
95 | 0 | } else { \ |
96 | 0 | pOut.push_back(pIn[pP4]); \ |
97 | 0 | pOut.push_back(pIn[pP3]); \ |
98 | 0 | pOut.push_back(pIn[pP2]); \ |
99 | 0 | pOut.push_back(pIn[pP1]); \ |
100 | 0 | } \ |
101 | 0 | } while (false) |
102 | | |
103 | | #define MESH_RectParallelepiped_CREATE_VERT \ |
104 | 0 | aiVector3D vert_set[8]; \ |
105 | 0 | float x1, x2, y1, y2, z1, z2, hs; \ |
106 | 0 | \ |
107 | 0 | hs = pSize.x / 2, x1 = -hs, x2 = hs; \ |
108 | 0 | hs = pSize.y / 2, y1 = -hs, y2 = hs; \ |
109 | 0 | hs = pSize.z / 2, z1 = -hs, z2 = hs; \ |
110 | 0 | vert_set[0].Set(x2, y1, z2); \ |
111 | 0 | vert_set[1].Set(x2, y2, z2); \ |
112 | 0 | vert_set[2].Set(x2, y2, z1); \ |
113 | 0 | vert_set[3].Set(x2, y1, z1); \ |
114 | 0 | vert_set[4].Set(x1, y1, z2); \ |
115 | 0 | vert_set[5].Set(x1, y2, z2); \ |
116 | 0 | vert_set[6].Set(x1, y2, z1); \ |
117 | 0 | vert_set[7].Set(x1, y1, z1) |
118 | | |
119 | 0 | void X3DGeoHelper::rect_parallel_epiped(const aiVector3D &pSize, std::list<aiVector3D> &pVertices) { |
120 | 0 | MESH_RectParallelepiped_CREATE_VERT; |
121 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 3, 2, 1, 0); // front |
122 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 6, 7, 4, 5); // back |
123 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 3, 0, 4); // left |
124 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 2, 6, 5, 1); // right |
125 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 0, 1, 5, 4); // top |
126 | 0 | MACRO_FACE_ADD_QUAD_FA(true, pVertices, vert_set, 7, 6, 2, 3); // bottom |
127 | 0 | } |
128 | | |
129 | | #undef MESH_RectParallelepiped_CREATE_VERT |
130 | | |
131 | | static constexpr int InvalidIndex = -1; |
132 | | |
133 | 0 | void X3DGeoHelper::coordIdx_str2faces_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces, unsigned int &pPrimitiveTypes) { |
134 | 0 | std::vector<int32_t> f_data(pCoordIdx); |
135 | 0 | std::vector<unsigned int> inds; |
136 | 0 | unsigned int prim_type = 0; |
137 | |
|
138 | 0 | if (!f_data.empty()) { |
139 | 0 | if (f_data.back() != InvalidIndex) { |
140 | 0 | f_data.push_back(InvalidIndex); |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | // reserve average size. |
145 | 0 | pFaces.reserve(f_data.size() / 3); |
146 | 0 | inds.reserve(4); |
147 | | //PrintVectorSet("build. ci", pCoordIdx); |
148 | 0 | for (std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); ++it) { |
149 | | // when face is got count how many indices in it. |
150 | 0 | if (*it == (-1)) { |
151 | 0 | aiFace tface; |
152 | 0 | size_t ts; |
153 | |
|
154 | 0 | ts = inds.size(); |
155 | 0 | switch (ts) { |
156 | 0 | case 0: |
157 | 0 | goto mg_m_err; |
158 | 0 | case 1: |
159 | 0 | prim_type |= aiPrimitiveType_POINT; |
160 | 0 | break; |
161 | 0 | case 2: |
162 | 0 | prim_type |= aiPrimitiveType_LINE; |
163 | 0 | break; |
164 | 0 | case 3: |
165 | 0 | prim_type |= aiPrimitiveType_TRIANGLE; |
166 | 0 | break; |
167 | 0 | default: |
168 | 0 | prim_type |= aiPrimitiveType_POLYGON; |
169 | 0 | break; |
170 | 0 | } |
171 | | |
172 | 0 | tface.mNumIndices = static_cast<unsigned int>(ts); |
173 | 0 | tface.mIndices = new unsigned int[ts]; |
174 | 0 | memcpy(tface.mIndices, inds.data(), ts * sizeof(unsigned int)); |
175 | 0 | pFaces.push_back(tface); |
176 | 0 | inds.clear(); |
177 | 0 | } // if(*it == (-1)) |
178 | 0 | else { |
179 | 0 | inds.push_back(*it); |
180 | 0 | } // if(*it == (-1)) else |
181 | 0 | } // for(std::list<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++) |
182 | | //PrintVectorSet("build. faces", pCoordIdx); |
183 | | |
184 | 0 | pPrimitiveTypes = prim_type; |
185 | |
|
186 | 0 | return; |
187 | | |
188 | 0 | mg_m_err: |
189 | 0 | for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++) |
190 | 0 | delete[] pFaces.at(i).mIndices; |
191 | |
|
192 | 0 | pFaces.clear(); |
193 | 0 | } |
194 | | |
195 | 0 | void X3DGeoHelper::coordIdx_str2lines_arr(const std::vector<int32_t> &pCoordIdx, std::vector<aiFace> &pFaces) { |
196 | 0 | std::vector<int32_t> f_data(pCoordIdx); |
197 | |
|
198 | 0 | if (!f_data.empty()) { |
199 | 0 | if (f_data.back() != InvalidIndex) { |
200 | 0 | f_data.push_back(InvalidIndex); |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | // reserve average size. |
205 | 0 | pFaces.reserve(f_data.size() / 2); |
206 | 0 | for (std::vector<int32_t>::const_iterator startIt = f_data.cbegin(), endIt = f_data.cbegin(); endIt != f_data.cend(); ++endIt) { |
207 | | // check for end of current polyline |
208 | 0 | if (*endIt != -1) |
209 | 0 | continue; |
210 | | |
211 | | // found end of polyline, check if this is a valid polyline |
212 | 0 | std::size_t numIndices = std::distance(startIt, endIt); |
213 | 0 | if (numIndices <= 1) |
214 | 0 | goto mg_m_err; |
215 | | |
216 | | // create line faces out of polyline indices |
217 | 0 | for (int32_t idx0 = *startIt++; startIt != endIt; ++startIt) { |
218 | 0 | int32_t idx1 = *startIt; |
219 | |
|
220 | 0 | aiFace tface; |
221 | 0 | tface.mNumIndices = 2; |
222 | 0 | tface.mIndices = new unsigned int[2]; |
223 | 0 | tface.mIndices[0] = idx0; |
224 | 0 | tface.mIndices[1] = idx1; |
225 | 0 | pFaces.push_back(tface); |
226 | |
|
227 | 0 | idx0 = idx1; |
228 | 0 | } |
229 | |
|
230 | 0 | ++startIt; |
231 | 0 | } |
232 | | |
233 | 0 | return; |
234 | | |
235 | 0 | mg_m_err: |
236 | 0 | for (size_t i = 0, i_e = pFaces.size(); i < i_e; i++) |
237 | 0 | delete[] pFaces[i].mIndices; |
238 | |
|
239 | 0 | pFaces.clear(); |
240 | 0 | } |
241 | | |
242 | 0 | void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor3D> &pColors, const bool pColorPerVertex) { |
243 | 0 | std::list<aiColor4D> tcol; |
244 | | |
245 | | // create RGBA array from RGB. |
246 | 0 | for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) |
247 | 0 | tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1)); |
248 | | |
249 | | // call existing function for adding RGBA colors |
250 | 0 | add_color(pMesh, tcol, pColorPerVertex); |
251 | 0 | } |
252 | | |
253 | 0 | void X3DGeoHelper::add_color(aiMesh &pMesh, const std::list<aiColor4D> &pColors, const bool pColorPerVertex) { |
254 | 0 | std::list<aiColor4D>::const_iterator col_it = pColors.begin(); |
255 | |
|
256 | 0 | if (pColorPerVertex) { |
257 | 0 | if (pColors.size() < pMesh.mNumVertices) { |
258 | 0 | throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Vertices count(" + |
259 | 0 | ai_to_string(pMesh.mNumVertices) + ")."); |
260 | 0 | } |
261 | | |
262 | | // copy colors to mesh |
263 | 0 | pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices]; |
264 | 0 | for (size_t i = 0; i < pMesh.mNumVertices; i++) |
265 | 0 | pMesh.mColors[0][i] = *col_it++; |
266 | 0 | } // if(pColorPerVertex) |
267 | 0 | else { |
268 | 0 | if (pColors.size() < pMesh.mNumFaces) { |
269 | 0 | throw DeadlyImportError("MeshGeometry_AddColor1. Colors count(" + ai_to_string(pColors.size()) + ") can not be less than Faces count(" + |
270 | 0 | ai_to_string(pMesh.mNumFaces) + ")."); |
271 | 0 | } |
272 | | |
273 | | // copy colors to mesh |
274 | 0 | pMesh.mColors[0] = new aiColor4D[pMesh.mNumVertices]; |
275 | 0 | for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) { |
276 | | // apply color to all vertices of face |
277 | 0 | for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) { |
278 | 0 | pMesh.mColors[0][pMesh.mFaces[fi].mIndices[vi]] = *col_it; |
279 | 0 | } |
280 | |
|
281 | 0 | ++col_it; |
282 | 0 | } |
283 | 0 | } // if(pColorPerVertex) else |
284 | 0 | } |
285 | | |
286 | | void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pColorIdx, |
287 | 0 | const std::list<aiColor3D> &pColors, const bool pColorPerVertex) { |
288 | 0 | std::list<aiColor4D> tcol; |
289 | | |
290 | | // create RGBA array from RGB. |
291 | 0 | for (std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) { |
292 | 0 | tcol.emplace_back((*it).r, (*it).g, (*it).b, static_cast<ai_real>(1)); |
293 | 0 | } |
294 | | |
295 | | // call existing function for adding RGBA colors |
296 | 0 | add_color(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex); |
297 | 0 | } |
298 | | |
299 | | void X3DGeoHelper::add_color(aiMesh &pMesh, const std::vector<int32_t> &coordIdx, const std::vector<int32_t> &colorIdx, |
300 | 0 | const std::list<aiColor4D> &colors, bool pColorPerVertex) { |
301 | 0 | std::vector<aiColor4D> col_tgt_arr; |
302 | 0 | std::list<aiColor4D> col_tgt_list; |
303 | 0 | std::vector<aiColor4D> col_arr_copy; |
304 | |
|
305 | 0 | if (coordIdx.size() == 0) { |
306 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. pCoordIdx can not be empty."); |
307 | 0 | } |
308 | | |
309 | | // copy list to array because we are need indexed access to colors. |
310 | 0 | col_arr_copy.reserve(colors.size()); |
311 | 0 | for (std::list<aiColor4D>::const_iterator it = colors.begin(); it != colors.end(); ++it) { |
312 | 0 | col_arr_copy.push_back(*it); |
313 | 0 | } |
314 | |
|
315 | 0 | if (pColorPerVertex) { |
316 | 0 | if (colorIdx.size() > 0) { |
317 | | // check indices array count. |
318 | 0 | if (colorIdx.size() < coordIdx.size()) { |
319 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) + |
320 | 0 | ") can not be less than Coords indices count(" + ai_to_string(coordIdx.size()) + ")."); |
321 | 0 | } |
322 | | // create list with colors for every vertex. |
323 | 0 | col_tgt_arr.resize(pMesh.mNumVertices); |
324 | 0 | for (std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(), coordidx_it = coordIdx.begin(); colidx_it != colorIdx.end(); ++colidx_it, ++coordidx_it) { |
325 | 0 | if (*colidx_it == (-1)) { |
326 | 0 | continue; // skip faces delimiter |
327 | 0 | } |
328 | 0 | if ((unsigned int)(*coordidx_it) > pMesh.mNumVertices) { |
329 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Coordinate idx is out of range."); |
330 | 0 | } |
331 | 0 | if ((unsigned int)*colidx_it > pMesh.mNumVertices) { |
332 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Color idx is out of range."); |
333 | 0 | } |
334 | | |
335 | 0 | col_tgt_arr[*coordidx_it] = col_arr_copy[*colidx_it]; |
336 | 0 | } |
337 | 0 | } // if(pColorIdx.size() > 0) |
338 | 0 | else { |
339 | | // when color indices list is absent use CoordIdx. |
340 | | // check indices array count. |
341 | 0 | if (colors.size() < pMesh.mNumVertices) { |
342 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Vertices count(" + |
343 | 0 | ai_to_string(pMesh.mNumVertices) + ")."); |
344 | 0 | } |
345 | | // create list with colors for every vertex. |
346 | 0 | col_tgt_arr.resize(pMesh.mNumVertices); |
347 | 0 | for (size_t i = 0; i < pMesh.mNumVertices; i++) { |
348 | 0 | col_tgt_arr[i] = col_arr_copy[i]; |
349 | 0 | } |
350 | 0 | } // if(pColorIdx.size() > 0) else |
351 | 0 | } // if(pColorPerVertex) |
352 | 0 | else { |
353 | 0 | if (colorIdx.size() > 0) { |
354 | | // check indices array count. |
355 | 0 | if (colorIdx.size() < pMesh.mNumFaces) { |
356 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Colors indices count(" + ai_to_string(colorIdx.size()) + |
357 | 0 | ") can not be less than Faces count(" + ai_to_string(pMesh.mNumFaces) + ")."); |
358 | 0 | } |
359 | | // create list with colors for every vertex using faces indices. |
360 | 0 | col_tgt_arr.resize(pMesh.mNumFaces); |
361 | |
|
362 | 0 | std::vector<int32_t>::const_iterator colidx_it = colorIdx.begin(); |
363 | 0 | for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) { |
364 | 0 | if ((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range."); |
365 | | |
366 | 0 | col_tgt_arr[fi] = col_arr_copy[*colidx_it++]; |
367 | 0 | } |
368 | 0 | } // if(pColorIdx.size() > 0) |
369 | 0 | else { |
370 | | // when color indices list is absent use CoordIdx. |
371 | | // check indices array count. |
372 | 0 | if (colors.size() < pMesh.mNumFaces) { |
373 | 0 | throw DeadlyImportError("MeshGeometry_AddColor2. Colors count(" + ai_to_string(colors.size()) + ") can not be less than Faces count(" + |
374 | 0 | ai_to_string(pMesh.mNumFaces) + ")."); |
375 | 0 | } |
376 | | // create list with colors for every vertex using faces indices. |
377 | 0 | col_tgt_arr.resize(pMesh.mNumFaces); |
378 | 0 | for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) |
379 | 0 | col_tgt_arr[fi] = col_arr_copy[fi]; |
380 | |
|
381 | 0 | } // if(pColorIdx.size() > 0) else |
382 | 0 | } // if(pColorPerVertex) else |
383 | | |
384 | | // copy array to list for calling function that add colors. |
385 | 0 | for (std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it) |
386 | 0 | col_tgt_list.push_back(*it); |
387 | | // add prepared colors list to mesh. |
388 | 0 | add_color(pMesh, col_tgt_list, pColorPerVertex); |
389 | 0 | } |
390 | | |
391 | | void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pNormalIdx, |
392 | 0 | const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) { |
393 | 0 | std::vector<size_t> tind; |
394 | 0 | std::vector<aiVector3D> norm_arr_copy; |
395 | | |
396 | | // copy list to array because we are need indexed access to normals. |
397 | 0 | norm_arr_copy.reserve(pNormals.size()); |
398 | 0 | for (std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it) { |
399 | 0 | norm_arr_copy.push_back(*it); |
400 | 0 | } |
401 | |
|
402 | 0 | if (pNormalPerVertex) { |
403 | 0 | if (pNormalIdx.size() > 0) { |
404 | | // check indices array count. |
405 | 0 | if (pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal."); |
406 | | |
407 | 0 | tind.reserve(pNormalIdx.size()); |
408 | 0 | for (std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) { |
409 | 0 | if (*it != (-1)) tind.push_back(*it); |
410 | 0 | } |
411 | | |
412 | | // copy normals to mesh |
413 | 0 | pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; |
414 | 0 | for (size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) { |
415 | 0 | if (tind[i] >= norm_arr_copy.size()) |
416 | 0 | throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + ai_to_string(tind[i]) + |
417 | 0 | ") is out of range. Normals count: " + ai_to_string(norm_arr_copy.size()) + "."); |
418 | | |
419 | 0 | pMesh.mNormals[i] = norm_arr_copy[tind[i]]; |
420 | 0 | } |
421 | 0 | } else { |
422 | 0 | if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal."); |
423 | | |
424 | | // copy normals to mesh |
425 | 0 | pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; |
426 | 0 | std::list<aiVector3D>::const_iterator norm_it = pNormals.begin(); |
427 | 0 | for (size_t i = 0; i < pMesh.mNumVertices; i++) |
428 | 0 | pMesh.mNormals[i] = *norm_it++; |
429 | 0 | } |
430 | 0 | } // if(pNormalPerVertex) |
431 | 0 | else { |
432 | 0 | if (pNormalIdx.size() > 0) { |
433 | 0 | if (pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count."); |
434 | | |
435 | 0 | std::vector<int32_t>::const_iterator normidx_it = pNormalIdx.begin(); |
436 | |
|
437 | 0 | tind.reserve(pNormalIdx.size()); |
438 | 0 | for (size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++) |
439 | 0 | tind.push_back(*normidx_it++); |
440 | |
|
441 | 0 | } else { |
442 | 0 | tind.reserve(pMesh.mNumFaces); |
443 | 0 | for (size_t i = 0; i < pMesh.mNumFaces; i++) |
444 | 0 | tind.push_back(i); |
445 | 0 | } |
446 | | |
447 | | // copy normals to mesh |
448 | 0 | pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; |
449 | 0 | for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) { |
450 | 0 | aiVector3D tnorm; |
451 | |
|
452 | 0 | tnorm = norm_arr_copy[tind[fi]]; |
453 | 0 | for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) |
454 | 0 | pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = tnorm; |
455 | 0 | } |
456 | 0 | } // if(pNormalPerVertex) else |
457 | 0 | } |
458 | | |
459 | 0 | void X3DGeoHelper::add_normal(aiMesh &pMesh, const std::list<aiVector3D> &pNormals, const bool pNormalPerVertex) { |
460 | 0 | std::list<aiVector3D>::const_iterator norm_it = pNormals.begin(); |
461 | |
|
462 | 0 | if (pNormalPerVertex) { |
463 | 0 | if (pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal."); |
464 | | |
465 | | // copy normals to mesh |
466 | 0 | pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; |
467 | 0 | for (size_t i = 0; i < pMesh.mNumVertices; i++) |
468 | 0 | pMesh.mNormals[i] = *norm_it++; |
469 | 0 | } // if(pNormalPerVertex) |
470 | 0 | else { |
471 | 0 | if (pNormals.size() != pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and faces count must be equal."); |
472 | | |
473 | | // copy normals to mesh |
474 | 0 | pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; |
475 | 0 | for (size_t fi = 0; fi < pMesh.mNumFaces; fi++) { |
476 | | // apply color to all vertices of face |
477 | 0 | for (size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) |
478 | 0 | pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it; |
479 | |
|
480 | 0 | ++norm_it; |
481 | 0 | } |
482 | 0 | } // if(pNormalPerVertex) else |
483 | 0 | } |
484 | | |
485 | | void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::vector<int32_t> &pCoordIdx, const std::vector<int32_t> &pTexCoordIdx, |
486 | 0 | const std::list<aiVector2D> &pTexCoords) { |
487 | 0 | std::vector<aiVector3D> texcoord_arr_copy; |
488 | 0 | std::vector<aiFace> faces; |
489 | 0 | unsigned int prim_type; |
490 | | |
491 | | // copy list to array because we are need indexed access to normals. |
492 | 0 | texcoord_arr_copy.reserve(pTexCoords.size()); |
493 | 0 | for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) { |
494 | 0 | texcoord_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0)); |
495 | 0 | } |
496 | |
|
497 | 0 | if (pTexCoordIdx.size() > 0) { |
498 | 0 | coordIdx_str2faces_arr(pTexCoordIdx, faces, prim_type); |
499 | 0 | if (faces.empty()) { |
500 | 0 | throw DeadlyImportError("Failed to add texture coordinates to mesh, faces list is empty."); |
501 | 0 | } |
502 | 0 | if (faces.size() != pMesh.mNumFaces) { |
503 | 0 | throw DeadlyImportError("Texture coordinates faces count must be equal to mesh faces count."); |
504 | 0 | } |
505 | 0 | } else { |
506 | 0 | coordIdx_str2faces_arr(pCoordIdx, faces, prim_type); |
507 | 0 | } |
508 | | |
509 | 0 | pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices]; |
510 | 0 | pMesh.mNumUVComponents[0] = 2; |
511 | 0 | for (size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) { |
512 | 0 | if (pMesh.mFaces[fi].mNumIndices != faces.at(fi).mNumIndices) |
513 | 0 | throw DeadlyImportError("Number of indices in texture face and mesh face must be equal. Invalid face index: " + ai_to_string(fi) + "."); |
514 | | |
515 | 0 | for (size_t ii = 0; ii < pMesh.mFaces[fi].mNumIndices; ii++) { |
516 | 0 | size_t vert_idx = pMesh.mFaces[fi].mIndices[ii]; |
517 | 0 | size_t tc_idx = faces.at(fi).mIndices[ii]; |
518 | |
|
519 | 0 | pMesh.mTextureCoords[0][vert_idx] = texcoord_arr_copy.at(tc_idx); |
520 | 0 | } |
521 | 0 | } // for(size_t fi = 0, fi_e = faces.size(); fi < fi_e; fi++) |
522 | 0 | } |
523 | | |
524 | 0 | void X3DGeoHelper::add_tex_coord(aiMesh &pMesh, const std::list<aiVector2D> &pTexCoords) { |
525 | 0 | std::vector<aiVector3D> tc_arr_copy; |
526 | |
|
527 | 0 | if (pTexCoords.size() != pMesh.mNumVertices) { |
528 | 0 | throw DeadlyImportError("MeshGeometry_AddTexCoord. Texture coordinates and vertices count must be equal."); |
529 | 0 | } |
530 | | |
531 | | // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus. |
532 | 0 | tc_arr_copy.reserve(pTexCoords.size()); |
533 | 0 | for (std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) { |
534 | 0 | tc_arr_copy.emplace_back((*it).x, (*it).y, static_cast<ai_real>(0)); |
535 | 0 | } |
536 | | |
537 | | // copy texture coordinates to mesh |
538 | 0 | pMesh.mTextureCoords[0] = new aiVector3D[pMesh.mNumVertices]; |
539 | 0 | pMesh.mNumUVComponents[0] = 2; |
540 | 0 | for (size_t i = 0; i < pMesh.mNumVertices; i++) { |
541 | 0 | pMesh.mTextureCoords[0][i] = tc_arr_copy[i]; |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | 0 | aiMesh *X3DGeoHelper::make_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) { |
546 | 0 | std::vector<aiFace> faces; |
547 | 0 | unsigned int prim_type = 0; |
548 | | |
549 | | // create faces array from input string with vertices indices. |
550 | 0 | X3DGeoHelper::coordIdx_str2faces_arr(pCoordIdx, faces, prim_type); |
551 | 0 | if (!faces.size()) { |
552 | 0 | throw DeadlyImportError("Failed to create mesh, faces list is empty."); |
553 | 0 | } |
554 | | |
555 | | // |
556 | | // Create new mesh and copy geometry data. |
557 | | // |
558 | 0 | aiMesh *tmesh = new aiMesh; |
559 | 0 | size_t ts = faces.size(); |
560 | | // faces |
561 | 0 | tmesh->mFaces = new aiFace[ts]; |
562 | 0 | tmesh->mNumFaces = static_cast<unsigned int>(ts); |
563 | 0 | for (size_t i = 0; i < ts; i++) |
564 | 0 | tmesh->mFaces[i] = faces.at(i); |
565 | | |
566 | | // vertices |
567 | 0 | std::list<aiVector3D>::const_iterator vit = pVertices.begin(); |
568 | |
|
569 | 0 | ts = pVertices.size(); |
570 | 0 | tmesh->mVertices = new aiVector3D[ts]; |
571 | 0 | tmesh->mNumVertices = static_cast<unsigned int>(ts); |
572 | 0 | for (size_t i = 0; i < ts; i++) { |
573 | 0 | tmesh->mVertices[i] = *vit++; |
574 | 0 | } |
575 | | |
576 | | // set primitives type and return result. |
577 | 0 | tmesh->mPrimitiveTypes = prim_type; |
578 | |
|
579 | 0 | return tmesh; |
580 | 0 | } |
581 | | |
582 | 0 | aiMesh *X3DGeoHelper::make_line_mesh(const std::vector<int32_t> &pCoordIdx, const std::list<aiVector3D> &pVertices) { |
583 | 0 | std::vector<aiFace> faces; |
584 | | |
585 | | // create faces array from input string with vertices indices. |
586 | 0 | X3DGeoHelper::coordIdx_str2lines_arr(pCoordIdx, faces); |
587 | 0 | if (!faces.size()) { |
588 | 0 | throw DeadlyImportError("Failed to create mesh, faces list is empty."); |
589 | 0 | } |
590 | | |
591 | | // |
592 | | // Create new mesh and copy geometry data. |
593 | | // |
594 | 0 | aiMesh *tmesh = new aiMesh; |
595 | 0 | size_t ts = faces.size(); |
596 | | // faces |
597 | 0 | tmesh->mFaces = new aiFace[ts]; |
598 | 0 | tmesh->mNumFaces = static_cast<unsigned int>(ts); |
599 | 0 | for (size_t i = 0; i < ts; i++) |
600 | 0 | tmesh->mFaces[i] = faces[i]; |
601 | | |
602 | | // vertices |
603 | 0 | std::list<aiVector3D>::const_iterator vit = pVertices.begin(); |
604 | |
|
605 | 0 | ts = pVertices.size(); |
606 | 0 | tmesh->mVertices = new aiVector3D[ts]; |
607 | 0 | tmesh->mNumVertices = static_cast<unsigned int>(ts); |
608 | 0 | for (size_t i = 0; i < ts; i++) { |
609 | 0 | tmesh->mVertices[i] = *vit++; |
610 | 0 | } |
611 | | |
612 | | // set primitive type and return result. |
613 | 0 | tmesh->mPrimitiveTypes = aiPrimitiveType_LINE; |
614 | |
|
615 | 0 | return tmesh; |
616 | 0 | } |
617 | | |
618 | | } // namespace Assimp |