rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file TriangulateProcess.cpp
|
nuclear@0
|
43 * @brief Implementation of the post processing step to split up
|
nuclear@0
|
44 * all faces with more than three indices into triangles.
|
nuclear@0
|
45 *
|
nuclear@0
|
46 *
|
nuclear@0
|
47 * The triangulation algorithm will handle concave or convex polygons.
|
nuclear@0
|
48 * Self-intersecting or non-planar polygons are not rejected, but
|
nuclear@0
|
49 * they're probably not triangulated correctly.
|
nuclear@0
|
50 *
|
nuclear@0
|
51 * DEBUG SWITCHES - do not enable any of them in release builds:
|
nuclear@0
|
52 *
|
nuclear@0
|
53 * AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
nuclear@0
|
54 * - generates vertex colors to represent the face winding order.
|
nuclear@0
|
55 * the first vertex of a polygon becomes red, the last blue.
|
nuclear@0
|
56 * AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
57 * - dump all polygons and their triangulation sequences to
|
nuclear@0
|
58 * a file
|
nuclear@0
|
59 */
|
nuclear@0
|
60
|
nuclear@0
|
61 #include "AssimpPCH.h"
|
nuclear@0
|
62
|
nuclear@0
|
63 #ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|
nuclear@0
|
64 #include "TriangulateProcess.h"
|
nuclear@0
|
65 #include "ProcessHelper.h"
|
nuclear@0
|
66 #include "PolyTools.h"
|
nuclear@0
|
67
|
nuclear@0
|
68 //#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
nuclear@0
|
69 //#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
70
|
nuclear@0
|
71 #define POLY_GRID_Y 40
|
nuclear@0
|
72 #define POLY_GRID_X 70
|
nuclear@0
|
73 #define POLY_GRID_XPAD 20
|
nuclear@0
|
74 #define POLY_OUTPUT_FILE "assimp_polygons_debug.txt"
|
nuclear@0
|
75
|
nuclear@0
|
76 using namespace Assimp;
|
nuclear@0
|
77
|
nuclear@0
|
78 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
79 // Constructor to be privately used by Importer
|
nuclear@0
|
80 TriangulateProcess::TriangulateProcess()
|
nuclear@0
|
81 {
|
nuclear@0
|
82 // nothing to do here
|
nuclear@0
|
83 }
|
nuclear@0
|
84
|
nuclear@0
|
85 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
86 // Destructor, private as well
|
nuclear@0
|
87 TriangulateProcess::~TriangulateProcess()
|
nuclear@0
|
88 {
|
nuclear@0
|
89 // nothing to do here
|
nuclear@0
|
90 }
|
nuclear@0
|
91
|
nuclear@0
|
92 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
93 // Returns whether the processing step is present in the given flag field.
|
nuclear@0
|
94 bool TriangulateProcess::IsActive( unsigned int pFlags) const
|
nuclear@0
|
95 {
|
nuclear@0
|
96 return (pFlags & aiProcess_Triangulate) != 0;
|
nuclear@0
|
97 }
|
nuclear@0
|
98
|
nuclear@0
|
99 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
100 // Executes the post processing step on the given imported data.
|
nuclear@0
|
101 void TriangulateProcess::Execute( aiScene* pScene)
|
nuclear@0
|
102 {
|
nuclear@0
|
103 DefaultLogger::get()->debug("TriangulateProcess begin");
|
nuclear@0
|
104
|
nuclear@0
|
105 bool bHas = false;
|
nuclear@0
|
106 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
nuclear@0
|
107 {
|
nuclear@0
|
108 if( TriangulateMesh( pScene->mMeshes[a]))
|
nuclear@0
|
109 bHas = true;
|
nuclear@0
|
110 }
|
nuclear@0
|
111 if (bHas)DefaultLogger::get()->info ("TriangulateProcess finished. All polygons have been triangulated.");
|
nuclear@0
|
112 else DefaultLogger::get()->debug("TriangulateProcess finished. There was nothing to be done.");
|
nuclear@0
|
113 }
|
nuclear@0
|
114
|
nuclear@0
|
115
|
nuclear@0
|
116 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
117 // Triangulates the given mesh.
|
nuclear@0
|
118 bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
nuclear@0
|
119 {
|
nuclear@0
|
120 // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases
|
nuclear@0
|
121 if (!pMesh->mPrimitiveTypes) {
|
nuclear@0
|
122 bool bNeed = false;
|
nuclear@0
|
123
|
nuclear@0
|
124 for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
nuclear@0
|
125 const aiFace& face = pMesh->mFaces[a];
|
nuclear@0
|
126
|
nuclear@0
|
127 if( face.mNumIndices != 3) {
|
nuclear@0
|
128 bNeed = true;
|
nuclear@0
|
129 }
|
nuclear@0
|
130 }
|
nuclear@0
|
131 if (!bNeed)
|
nuclear@0
|
132 return false;
|
nuclear@0
|
133 }
|
nuclear@0
|
134 else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) {
|
nuclear@0
|
135 return false;
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 // Find out how many output faces we'll get
|
nuclear@0
|
139 unsigned int numOut = 0, max_out = 0;
|
nuclear@0
|
140 bool get_normals = true;
|
nuclear@0
|
141 for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
nuclear@0
|
142 aiFace& face = pMesh->mFaces[a];
|
nuclear@0
|
143 if (face.mNumIndices <= 4) {
|
nuclear@0
|
144 get_normals = false;
|
nuclear@0
|
145 }
|
nuclear@0
|
146 if( face.mNumIndices <= 3) {
|
nuclear@0
|
147 numOut++;
|
nuclear@0
|
148
|
nuclear@0
|
149 }
|
nuclear@0
|
150 else {
|
nuclear@0
|
151 numOut += face.mNumIndices-2;
|
nuclear@0
|
152 max_out = std::max(max_out,face.mNumIndices);
|
nuclear@0
|
153 }
|
nuclear@0
|
154 }
|
nuclear@0
|
155
|
nuclear@0
|
156 // Just another check whether aiMesh::mPrimitiveTypes is correct
|
nuclear@0
|
157 assert(numOut != pMesh->mNumFaces);
|
nuclear@0
|
158
|
nuclear@0
|
159 aiVector3D* nor_out = NULL;
|
nuclear@0
|
160
|
nuclear@0
|
161 // if we don't have normals yet, but expect them to be a cheap side
|
nuclear@0
|
162 // product of triangulation anyway, allocate storage for them.
|
nuclear@0
|
163 if (!pMesh->mNormals && get_normals) {
|
nuclear@0
|
164 // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals
|
nuclear@0
|
165 // nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
nuclear@0
|
166 }
|
nuclear@0
|
167
|
nuclear@0
|
168 // the output mesh will contain triangles, but no polys anymore
|
nuclear@0
|
169 pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
nuclear@0
|
170 pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
|
nuclear@0
|
171
|
nuclear@0
|
172 aiFace* out = new aiFace[numOut](), *curOut = out;
|
nuclear@0
|
173 std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
|
nuclear@0
|
174 std::vector<aiVector2D> temp_verts(max_out+2);
|
nuclear@0
|
175
|
nuclear@0
|
176 // Apply vertex colors to represent the face winding?
|
nuclear@0
|
177 #ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
nuclear@0
|
178 if (!pMesh->mColors[0])
|
nuclear@0
|
179 pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
|
nuclear@0
|
180 else
|
nuclear@0
|
181 new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices];
|
nuclear@0
|
182
|
nuclear@0
|
183 aiColor4D* clr = pMesh->mColors[0];
|
nuclear@0
|
184 #endif
|
nuclear@0
|
185
|
nuclear@0
|
186
|
nuclear@0
|
187 #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
188 FILE* fout = fopen(POLY_OUTPUT_FILE,"a");
|
nuclear@0
|
189 #endif
|
nuclear@0
|
190
|
nuclear@0
|
191 const aiVector3D* verts = pMesh->mVertices;
|
nuclear@0
|
192
|
nuclear@0
|
193 // use boost::scoped_array to avoid slow std::vector<bool> specialiations
|
nuclear@0
|
194 boost::scoped_array<bool> done(new bool[max_out]);
|
nuclear@0
|
195 for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
nuclear@0
|
196 aiFace& face = pMesh->mFaces[a];
|
nuclear@0
|
197
|
nuclear@0
|
198 unsigned int* idx = face.mIndices;
|
nuclear@0
|
199 int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num;
|
nuclear@0
|
200
|
nuclear@0
|
201 // Apply vertex colors to represent the face winding?
|
nuclear@0
|
202 #ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
nuclear@0
|
203 for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
nuclear@0
|
204 aiColor4D& c = clr[idx[i]];
|
nuclear@0
|
205 c.r = (i+1) / (float)max;
|
nuclear@0
|
206 c.b = 1.f - c.r;
|
nuclear@0
|
207 }
|
nuclear@0
|
208 #endif
|
nuclear@0
|
209
|
nuclear@0
|
210 aiFace* const last_face = curOut;
|
nuclear@0
|
211
|
nuclear@0
|
212 // if it's a simple point,line or triangle: just copy it
|
nuclear@0
|
213 if( face.mNumIndices <= 3)
|
nuclear@0
|
214 {
|
nuclear@0
|
215 aiFace& nface = *curOut++;
|
nuclear@0
|
216 nface.mNumIndices = face.mNumIndices;
|
nuclear@0
|
217 nface.mIndices = face.mIndices;
|
nuclear@0
|
218
|
nuclear@0
|
219 face.mIndices = NULL;
|
nuclear@0
|
220 continue;
|
nuclear@0
|
221 }
|
nuclear@0
|
222 // optimized code for quadrilaterals
|
nuclear@0
|
223 else if ( face.mNumIndices == 4) {
|
nuclear@0
|
224
|
nuclear@0
|
225 // quads can have at maximum one concave vertex. Determine
|
nuclear@0
|
226 // this vertex (if it exists) and start tri-fanning from
|
nuclear@0
|
227 // it.
|
nuclear@0
|
228 unsigned int start_vertex = 0;
|
nuclear@0
|
229 for (unsigned int i = 0; i < 4; ++i) {
|
nuclear@0
|
230 const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]];
|
nuclear@0
|
231 const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]];
|
nuclear@0
|
232 const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]];
|
nuclear@0
|
233
|
nuclear@0
|
234 const aiVector3D& v = verts[face.mIndices[i]];
|
nuclear@0
|
235
|
nuclear@0
|
236 aiVector3D left = (v0-v);
|
nuclear@0
|
237 aiVector3D diag = (v1-v);
|
nuclear@0
|
238 aiVector3D right = (v2-v);
|
nuclear@0
|
239
|
nuclear@0
|
240 left.Normalize();
|
nuclear@0
|
241 diag.Normalize();
|
nuclear@0
|
242 right.Normalize();
|
nuclear@0
|
243
|
nuclear@0
|
244 const float angle = acos(left*diag) + acos(right*diag);
|
nuclear@0
|
245 if (angle > AI_MATH_PI_F) {
|
nuclear@0
|
246 // this is the concave point
|
nuclear@0
|
247 start_vertex = i;
|
nuclear@0
|
248 break;
|
nuclear@0
|
249 }
|
nuclear@0
|
250 }
|
nuclear@0
|
251
|
nuclear@0
|
252 const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]};
|
nuclear@0
|
253
|
nuclear@0
|
254 aiFace& nface = *curOut++;
|
nuclear@0
|
255 nface.mNumIndices = 3;
|
nuclear@0
|
256 nface.mIndices = face.mIndices;
|
nuclear@0
|
257
|
nuclear@0
|
258 nface.mIndices[0] = temp[start_vertex];
|
nuclear@0
|
259 nface.mIndices[1] = temp[(start_vertex + 1) % 4];
|
nuclear@0
|
260 nface.mIndices[2] = temp[(start_vertex + 2) % 4];
|
nuclear@0
|
261
|
nuclear@0
|
262 aiFace& sface = *curOut++;
|
nuclear@0
|
263 sface.mNumIndices = 3;
|
nuclear@0
|
264 sface.mIndices = new unsigned int[3];
|
nuclear@0
|
265
|
nuclear@0
|
266 sface.mIndices[0] = temp[start_vertex];
|
nuclear@0
|
267 sface.mIndices[1] = temp[(start_vertex + 2) % 4];
|
nuclear@0
|
268 sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
nuclear@0
|
269
|
nuclear@0
|
270 // prevent double deletion of the indices field
|
nuclear@0
|
271 face.mIndices = NULL;
|
nuclear@0
|
272 continue;
|
nuclear@0
|
273 }
|
nuclear@0
|
274 else
|
nuclear@0
|
275 {
|
nuclear@0
|
276 // A polygon with more than 3 vertices can be either concave or convex.
|
nuclear@0
|
277 // Usually everything we're getting is convex and we could easily
|
nuclear@0
|
278 // triangulate by trifanning. However, LightWave is probably the only
|
nuclear@0
|
279 // modeling suite to make extensive use of highly concave, monster polygons ...
|
nuclear@0
|
280 // so we need to apply the full 'ear cutting' algorithm to get it right.
|
nuclear@0
|
281
|
nuclear@0
|
282 // RERQUIREMENT: polygon is expected to be simple and *nearly* planar.
|
nuclear@0
|
283 // We project it onto a plane to get a 2d triangle.
|
nuclear@0
|
284
|
nuclear@0
|
285 // Collect all vertices of of the polygon.
|
nuclear@0
|
286 for (tmp = 0; tmp < max; ++tmp) {
|
nuclear@0
|
287 temp_verts3d[tmp] = verts[idx[tmp]];
|
nuclear@0
|
288 }
|
nuclear@0
|
289
|
nuclear@0
|
290 // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh
|
nuclear@0
|
291 aiVector3D n;
|
nuclear@0
|
292 NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z);
|
nuclear@0
|
293 if (nor_out) {
|
nuclear@0
|
294 for (tmp = 0; tmp < max; ++tmp)
|
nuclear@0
|
295 nor_out[idx[tmp]] = n;
|
nuclear@0
|
296 }
|
nuclear@0
|
297
|
nuclear@0
|
298 // Select largest normal coordinate to ignore for projection
|
nuclear@0
|
299 const float ax = (n.x>0 ? n.x : -n.x);
|
nuclear@0
|
300 const float ay = (n.y>0 ? n.y : -n.y);
|
nuclear@0
|
301 const float az = (n.z>0 ? n.z : -n.z);
|
nuclear@0
|
302
|
nuclear@0
|
303 unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */
|
nuclear@0
|
304 float inv = n.z;
|
nuclear@0
|
305 if (ax > ay) {
|
nuclear@0
|
306 if (ax > az) { /* no x coord. projection to yz */
|
nuclear@0
|
307 ac = 1; bc = 2;
|
nuclear@0
|
308 inv = n.x;
|
nuclear@0
|
309 }
|
nuclear@0
|
310 }
|
nuclear@0
|
311 else if (ay > az) { /* no y coord. projection to zy */
|
nuclear@0
|
312 ac = 2; bc = 0;
|
nuclear@0
|
313 inv = n.y;
|
nuclear@0
|
314 }
|
nuclear@0
|
315
|
nuclear@0
|
316 // Swap projection axes to take the negated projection vector into account
|
nuclear@0
|
317 if (inv < 0.f) {
|
nuclear@0
|
318 std::swap(ac,bc);
|
nuclear@0
|
319 }
|
nuclear@0
|
320
|
nuclear@0
|
321 for (tmp =0; tmp < max; ++tmp) {
|
nuclear@0
|
322 temp_verts[tmp].x = verts[idx[tmp]][ac];
|
nuclear@0
|
323 temp_verts[tmp].y = verts[idx[tmp]][bc];
|
nuclear@0
|
324 done[tmp] = false;
|
nuclear@0
|
325 }
|
nuclear@0
|
326
|
nuclear@0
|
327
|
nuclear@0
|
328 #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
329 // plot the plane onto which we mapped the polygon to a 2D ASCII pic
|
nuclear@0
|
330 aiVector2D bmin,bmax;
|
nuclear@0
|
331 ArrayBounds(&temp_verts[0],max,bmin,bmax);
|
nuclear@0
|
332
|
nuclear@0
|
333 char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD];
|
nuclear@0
|
334 std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' ');
|
nuclear@0
|
335
|
nuclear@0
|
336 for (int i =0; i < max; ++i) {
|
nuclear@0
|
337 const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin);
|
nuclear@0
|
338 const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1));
|
nuclear@0
|
339 char* loc = grid[y]+x;
|
nuclear@0
|
340 if (grid[y][x] != ' ') {
|
nuclear@0
|
341 for(;*loc != ' '; ++loc);
|
nuclear@0
|
342 *loc++ = '_';
|
nuclear@0
|
343 }
|
nuclear@0
|
344 *(loc+sprintf(loc,"%i",i)) = ' ';
|
nuclear@0
|
345 }
|
nuclear@0
|
346
|
nuclear@0
|
347
|
nuclear@0
|
348 for(size_t y = 0; y < POLY_GRID_Y; ++y) {
|
nuclear@0
|
349 grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0';
|
nuclear@0
|
350 fprintf(fout,"%s\n",grid[y]);
|
nuclear@0
|
351 }
|
nuclear@0
|
352
|
nuclear@0
|
353 fprintf(fout,"\ntriangulation sequence: ");
|
nuclear@0
|
354 #endif
|
nuclear@0
|
355
|
nuclear@0
|
356 //
|
nuclear@0
|
357 // FIXME: currently this is the slow O(kn) variant with a worst case
|
nuclear@0
|
358 // complexity of O(n^2) (I think). Can be done in O(n).
|
nuclear@0
|
359 while (num > 3) {
|
nuclear@0
|
360
|
nuclear@0
|
361 // Find the next ear of the polygon
|
nuclear@0
|
362 int num_found = 0;
|
nuclear@0
|
363 for (ear = next;;prev = ear,ear = next) {
|
nuclear@0
|
364
|
nuclear@0
|
365 // break after we looped two times without a positive match
|
nuclear@0
|
366 for (next=ear+1;done[(next>=max?next=0:next)];++next);
|
nuclear@0
|
367 if (next < ear) {
|
nuclear@0
|
368 if (++num_found == 2) {
|
nuclear@0
|
369 break;
|
nuclear@0
|
370 }
|
nuclear@0
|
371 }
|
nuclear@0
|
372 const aiVector2D* pnt1 = &temp_verts[ear],
|
nuclear@0
|
373 *pnt0 = &temp_verts[prev],
|
nuclear@0
|
374 *pnt2 = &temp_verts[next];
|
nuclear@0
|
375
|
nuclear@0
|
376 // Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1.
|
nuclear@0
|
377 if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) {
|
nuclear@0
|
378 continue;
|
nuclear@0
|
379 }
|
nuclear@0
|
380
|
nuclear@0
|
381 // and no other point may be contained in this triangle
|
nuclear@0
|
382 for ( tmp = 0; tmp < max; ++tmp) {
|
nuclear@0
|
383
|
nuclear@0
|
384 // We need to compare the actual values because it's possible that multiple indexes in
|
nuclear@0
|
385 // the polygon are referring to the same position. concave_polygon.obj is a sample
|
nuclear@0
|
386 //
|
nuclear@0
|
387 // FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in
|
nuclear@0
|
388 // PointInTriangle() I'm guessing that it's actually possible to construct
|
nuclear@0
|
389 // input data that would cause us to end up with no ears. The problem is,
|
nuclear@0
|
390 // which epsilon? If we chose a too large value, we'd get wrong results
|
nuclear@0
|
391 const aiVector2D& vtmp = temp_verts[tmp];
|
nuclear@0
|
392 if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) {
|
nuclear@0
|
393 break;
|
nuclear@0
|
394 }
|
nuclear@0
|
395 }
|
nuclear@0
|
396 if (tmp != max) {
|
nuclear@0
|
397 continue;
|
nuclear@0
|
398 }
|
nuclear@0
|
399
|
nuclear@0
|
400 // this vertex is an ear
|
nuclear@0
|
401 break;
|
nuclear@0
|
402 }
|
nuclear@0
|
403 if (num_found == 2) {
|
nuclear@0
|
404
|
nuclear@0
|
405 // Due to the 'two ear theorem', every simple polygon with more than three points must
|
nuclear@0
|
406 // have 2 'ears'. Here's definitely someting wrong ... but we don't give up yet.
|
nuclear@0
|
407 //
|
nuclear@0
|
408
|
nuclear@0
|
409 // Instead we're continuting with the standard trifanning algorithm which we'd
|
nuclear@0
|
410 // use if we had only convex polygons. That's life.
|
nuclear@0
|
411 DefaultLogger::get()->error("Failed to triangulate polygon (no ear found). Probably not a simple polygon?");
|
nuclear@0
|
412
|
nuclear@0
|
413
|
nuclear@0
|
414 #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
415 fprintf(fout,"critical error here, no ear found! ");
|
nuclear@0
|
416 #endif
|
nuclear@0
|
417 num = 0;
|
nuclear@0
|
418 break;
|
nuclear@0
|
419
|
nuclear@0
|
420 curOut -= (max-num); /* undo all previous work */
|
nuclear@0
|
421 for (tmp = 0; tmp < max-2; ++tmp) {
|
nuclear@0
|
422 aiFace& nface = *curOut++;
|
nuclear@0
|
423
|
nuclear@0
|
424 nface.mNumIndices = 3;
|
nuclear@0
|
425 if (!nface.mIndices)
|
nuclear@0
|
426 nface.mIndices = new unsigned int[3];
|
nuclear@0
|
427
|
nuclear@0
|
428 nface.mIndices[0] = 0;
|
nuclear@0
|
429 nface.mIndices[1] = tmp+1;
|
nuclear@0
|
430 nface.mIndices[2] = tmp+2;
|
nuclear@0
|
431
|
nuclear@0
|
432 }
|
nuclear@0
|
433 num = 0;
|
nuclear@0
|
434 break;
|
nuclear@0
|
435 }
|
nuclear@0
|
436
|
nuclear@0
|
437 aiFace& nface = *curOut++;
|
nuclear@0
|
438 nface.mNumIndices = 3;
|
nuclear@0
|
439
|
nuclear@0
|
440 if (!nface.mIndices) {
|
nuclear@0
|
441 nface.mIndices = new unsigned int[3];
|
nuclear@0
|
442 }
|
nuclear@0
|
443
|
nuclear@0
|
444 // setup indices for the new triangle ...
|
nuclear@0
|
445 nface.mIndices[0] = prev;
|
nuclear@0
|
446 nface.mIndices[1] = ear;
|
nuclear@0
|
447 nface.mIndices[2] = next;
|
nuclear@0
|
448
|
nuclear@0
|
449 // exclude the ear from most further processing
|
nuclear@0
|
450 done[ear] = true;
|
nuclear@0
|
451 --num;
|
nuclear@0
|
452 }
|
nuclear@0
|
453 if (num > 0) {
|
nuclear@0
|
454 // We have three indices forming the last 'ear' remaining. Collect them.
|
nuclear@0
|
455 aiFace& nface = *curOut++;
|
nuclear@0
|
456 nface.mNumIndices = 3;
|
nuclear@0
|
457 if (!nface.mIndices) {
|
nuclear@0
|
458 nface.mIndices = new unsigned int[3];
|
nuclear@0
|
459 }
|
nuclear@0
|
460
|
nuclear@0
|
461 for (tmp = 0; done[tmp]; ++tmp);
|
nuclear@0
|
462 nface.mIndices[0] = tmp;
|
nuclear@0
|
463
|
nuclear@0
|
464 for (++tmp; done[tmp]; ++tmp);
|
nuclear@0
|
465 nface.mIndices[1] = tmp;
|
nuclear@0
|
466
|
nuclear@0
|
467 for (++tmp; done[tmp]; ++tmp);
|
nuclear@0
|
468 nface.mIndices[2] = tmp;
|
nuclear@0
|
469
|
nuclear@0
|
470 }
|
nuclear@0
|
471 }
|
nuclear@0
|
472
|
nuclear@0
|
473 #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
474
|
nuclear@0
|
475 for(aiFace* f = last_face; f != curOut; ++f) {
|
nuclear@0
|
476 unsigned int* i = f->mIndices;
|
nuclear@0
|
477 fprintf(fout," (%i %i %i)",i[0],i[1],i[2]);
|
nuclear@0
|
478 }
|
nuclear@0
|
479
|
nuclear@0
|
480 fprintf(fout,"\n*********************************************************************\n");
|
nuclear@0
|
481 fflush(fout);
|
nuclear@0
|
482
|
nuclear@0
|
483 #endif
|
nuclear@0
|
484
|
nuclear@0
|
485 for(aiFace* f = last_face; f != curOut; ) {
|
nuclear@0
|
486 unsigned int* i = f->mIndices;
|
nuclear@0
|
487
|
nuclear@0
|
488 // drop dumb 0-area triangles
|
nuclear@0
|
489 if (fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
|
nuclear@0
|
490 DefaultLogger::get()->debug("Dropping triangle with area 0");
|
nuclear@0
|
491 --curOut;
|
nuclear@0
|
492
|
nuclear@0
|
493 delete[] f->mIndices;
|
nuclear@0
|
494 f->mIndices = NULL;
|
nuclear@0
|
495
|
nuclear@0
|
496 for(aiFace* ff = f; ff != curOut; ++ff) {
|
nuclear@0
|
497 ff->mNumIndices = (ff+1)->mNumIndices;
|
nuclear@0
|
498 ff->mIndices = (ff+1)->mIndices;
|
nuclear@0
|
499 (ff+1)->mIndices = NULL;
|
nuclear@0
|
500 }
|
nuclear@0
|
501 continue;
|
nuclear@0
|
502 }
|
nuclear@0
|
503
|
nuclear@0
|
504 i[0] = idx[i[0]];
|
nuclear@0
|
505 i[1] = idx[i[1]];
|
nuclear@0
|
506 i[2] = idx[i[2]];
|
nuclear@0
|
507 ++f;
|
nuclear@0
|
508 }
|
nuclear@0
|
509
|
nuclear@0
|
510 delete[] face.mIndices;
|
nuclear@0
|
511 face.mIndices = NULL;
|
nuclear@0
|
512 }
|
nuclear@0
|
513
|
nuclear@0
|
514 #ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
nuclear@0
|
515 fclose(fout);
|
nuclear@0
|
516 #endif
|
nuclear@0
|
517
|
nuclear@0
|
518 // kill the old faces
|
nuclear@0
|
519 delete [] pMesh->mFaces;
|
nuclear@0
|
520
|
nuclear@0
|
521 // ... and store the new ones
|
nuclear@0
|
522 pMesh->mFaces = out;
|
nuclear@0
|
523 pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */
|
nuclear@0
|
524 return true;
|
nuclear@0
|
525 }
|
nuclear@0
|
526
|
nuclear@0
|
527 #endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
|