2 GenSurf plugin for GtkRadiant
\r
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
\r
5 This library is free software; you can redistribute it and/or
\r
6 modify it under the terms of the GNU Lesser General Public
\r
7 License as published by the Free Software Foundation; either
\r
8 version 2.1 of the License, or (at your option) any later version.
\r
10 This library is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
13 Lesser General Public License for more details.
\r
15 You should have received a copy of the GNU Lesser General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
23 #else /* not SINGLE */
\r
25 #endif /* not SINGLE */
\r
30 #include "gensurf.h"
\r
31 #include "triangle.h"
\r
42 #define Absolute(a) ((a) >= 0.0 ? (a) : -(a))
\r
44 void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri)
\r
46 int compare(TRITABLE *, TRITABLE *);
\r
47 int Bisect(NODE *, int, int, int);
\r
48 void CalcAngles(NODE *, int *, float *);
\r
49 void EdgeOnSide(int *, int *, int *);
\r
50 int tricall(int, NODE *, int *, TRI **, TRI **, char *);
\r
51 int CheckBorders(int *,int,NODE *,int *,TRI **);
\r
62 if(Decimate <= 0) return;
\r
64 ghCursorCurrent = LoadCursor(NULL,IDC_WAIT);
\r
65 SetCursor(ghCursorCurrent);
\r
71 NumNodes[0] = (NH+1)*(NVP1);
\r
72 *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE));
\r
74 memset(Node,0,NumNodes[0]*sizeof(NODE));
\r
76 // Copy [NH][NV] vertex array to our working node array
\r
77 for(i=0,N=0; i<=NH; i++)
\r
79 for(j=0; j<=NV; j++, N++)
\r
81 Node[N].p[0] = (float)xyz[i][j].p[0];
\r
82 Node[N].p[1] = (float)xyz[i][j].p[1];
\r
83 Node[N].p[2] = (float)xyz[i][j].p[2];
\r
84 Node[N].fixed = xyz[i][j].fixed;
\r
87 // Start things off with the corner values
\r
90 Node[NH*NVP1].used = 1;
\r
91 Node[NH*NVP1+NV].used = 1;
\r
93 tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
\r
96 // Which coordinates are we triangulating on?
\r
117 // TriTable stores the largest error in a triangle and the node where that
\r
119 TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE));
\r
120 NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed));
\r
122 while(NumNodesUsed < NumNodesToSave)
\r
124 for(i=0; i<NumTris[0]; i++)
\r
127 // For every node that's not currently used, find what triangle it
\r
128 // lies on, and the error at this node
\r
129 for(i=0, biggesterror=0; i<NumNodes[0]; i++)
\r
131 if(Node[i].used) continue;
\r
132 for(j=0, Node[i].tri=-1; (j<NumTris[0]) && (Node[i].tri==-1); j++)
\r
134 if( side(Node[i].p[j1], Node[i].p[j2],
\r
135 Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2],
\r
136 Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue;
\r
137 if( side(Node[i].p[j1], Node[i].p[j2],
\r
138 Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2],
\r
139 Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue;
\r
140 if( side(Node[i].p[j1], Node[i].p[j2],
\r
141 Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2],
\r
142 Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue;
\r
145 if(Node[i].tri < 0)
\r
148 ghCursorCurrent = ghCursorDefault;
\r
149 SetCursor(ghCursorCurrent);
\r
151 g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,
\r
152 "Error: Couldn't find the triangle bounding a point.",
\r
153 "Decimation Error",MB_ICONEXCLAMATION);
\r
156 if(!Tri[Node[i].tri].flag)
\r
158 PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p,
\r
159 Node[Tri[Node[i].tri].v[1]].p,
\r
160 Node[Tri[Node[i].tri].v[2]].p,
\r
161 &Tri[Node[i].tri].plane);
\r
162 Tri[Node[i].tri].flag = 1;
\r
165 Node[i].p[j0] - (Tri[Node[i].tri].plane.dist -
\r
166 Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] -
\r
167 Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2] )/
\r
168 Tri[Node[i].tri].plane.normal[j0];
\r
169 biggesterror = max(biggesterror,Absolute(Node[i].error));
\r
171 if(biggesterror == 0)
\r
172 NumNodesToSave = NumNodesUsed;
\r
175 // For all current triangles, build a list of worst-case nodes
\r
176 memset(TriTable,0,NH*NV*2*sizeof(TRITABLE));
\r
177 for(i=0; i<NumNodes[0]; i++)
\r
179 if(Node[i].used) continue;
\r
180 if(Absolute(Node[i].error) > TriTable[Node[i].tri].error)
\r
182 TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error));
\r
183 TriTable[Node[i].tri].node = i;
\r
186 qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare );
\r
187 for(i=0; i<NumTris[0] && NumNodesUsed < NumNodesToSave && TriTable[i].error > 0.5*biggesterror; i++)
\r
189 if(Node[TriTable[i].node].used) continue; // shouldn't happen
\r
191 Node[TriTable[i].node].used++;
\r
194 tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
\r
196 // Sliver-check along borders. Since borders are often linear, the errors
\r
197 // along borders will often be zero, so no new points will be added. This
\r
198 // tends to produce long, thin brushes. For all border triangles, check
\r
199 // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another
\r
201 while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0)
\r
208 // One last time (because we're pessimistic), check border triangles
\r
209 // CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri);
\r
212 // Check that all fixed points are exact. If not, add them to the mix.
\r
213 // First check to see if we have any fixed points that aren't already used.
\r
214 for(i=0, N=0; i<NumNodes[0] && !N; i++)
\r
216 if(Node[i].used) continue;
\r
217 if(Node[i].fixed) N++;
\r
221 // Zero out the flag member of all triangles, indicating that
\r
222 // the plane equation has not been found.
\r
223 for(i=0; i<NumTris[0]; i++)
\r
226 for(i=0; i<NumNodes[0]; i++)
\r
228 if(Node[i].used) continue;
\r
229 if(!Node[i].fixed) continue;
\r
231 for(j=0; j<NumTris[0] && Node[i].tri==-1; j++)
\r
233 if( side(Node[i].p[j1], Node[i].p[j2],
\r
234 Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2],
\r
235 Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2]) < 0. ) continue;
\r
236 if( side(Node[i].p[j1], Node[i].p[j2],
\r
237 Node[Tri[j].v[1]].p[j1],Node[Tri[j].v[1]].p[j2],
\r
238 Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2]) < 0. ) continue;
\r
239 if( side(Node[i].p[j1], Node[i].p[j2],
\r
240 Node[Tri[j].v[2]].p[j1],Node[Tri[j].v[2]].p[j2],
\r
241 Node[Tri[j].v[0]].p[j1],Node[Tri[j].v[0]].p[j2]) < 0. ) continue;
\r
244 if(Node[i].tri < 0)
\r
247 ghCursorCurrent = ghCursorDefault;
\r
248 SetCursor(ghCursorCurrent);
\r
250 g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,
\r
251 "Error: Couldn't find the triangle bounding a point.",
\r
252 "Decimation Error",MB_ICONEXCLAMATION);
\r
255 if(!Tri[Node[i].tri].flag)
\r
257 PlaneFromPoints(Node[Tri[Node[i].tri].v[0]].p,
\r
258 Node[Tri[Node[i].tri].v[1]].p,
\r
259 Node[Tri[Node[i].tri].v[2]].p,
\r
260 &Tri[Node[i].tri].plane);
\r
261 Tri[Node[i].tri].flag = 1;
\r
264 Node[i].p[j0] - (Tri[Node[i].tri].plane.dist -
\r
265 Tri[Node[i].tri].plane.normal[j1]*Node[i].p[j1] -
\r
266 Tri[Node[i].tri].plane.normal[j2]*Node[i].p[j2] )/
\r
267 Tri[Node[i].tri].plane.normal[j0];
\r
268 if(Absolute(Node[i].error) > 0.5)
\r
273 tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY");
\r
279 // Swap node orders for surfaces facing down, north or west so that
\r
280 // they are counterclockwise when facing the surface
\r
282 if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) )
\r
284 for(i=0; i<NumTris[0]; i++)
\r
287 Tri[i].v[1] = Tri[i].v[2];
\r
292 // Store bounding box coords
\r
293 for(i=0; i<NumTris[0]; i++)
\r
295 Tri[i].min[0] = Node[Tri[i].v[0]].p[0];
\r
296 Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[1]].p[0]);
\r
297 Tri[i].min[0] = min(Tri[i].min[0],Node[Tri[i].v[2]].p[0]);
\r
298 Tri[i].min[1] = Node[Tri[i].v[0]].p[1];
\r
299 Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[1]].p[1]);
\r
300 Tri[i].min[1] = min(Tri[i].min[1],Node[Tri[i].v[2]].p[1]);
\r
301 Tri[i].min[2] = Node[Tri[i].v[0]].p[2];
\r
302 Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[1]].p[2]);
\r
303 Tri[i].min[2] = min(Tri[i].min[2],Node[Tri[i].v[2]].p[2]);
\r
304 Tri[i].max[0] = Node[Tri[i].v[0]].p[0];
\r
305 Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[1]].p[0]);
\r
306 Tri[i].max[0] = max(Tri[i].max[0],Node[Tri[i].v[2]].p[0]);
\r
307 Tri[i].max[1] = Node[Tri[i].v[0]].p[1];
\r
308 Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[1]].p[1]);
\r
309 Tri[i].max[1] = max(Tri[i].max[1],Node[Tri[i].v[2]].p[1]);
\r
310 Tri[i].max[2] = Node[Tri[i].v[0]].p[2];
\r
311 Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[1]].p[2]);
\r
312 Tri[i].max[2] = max(Tri[i].max[2],Node[Tri[i].v[2]].p[2]);
\r
315 ghCursorCurrent = ghCursorDefault;
\r
316 SetCursor(ghCursorCurrent);
\r
319 /* end MakeDecimatedMap */
\r
321 /*****************************************************************************/
\r
323 /* tricall Takes an array of nodes, spits out an array of triangles */
\r
325 /*****************************************************************************/
\r
326 int tricall(int NumNodes, NODE *Node, int *NumTris, TRI **inTri, TRI **Tri, LPSTR Options)
\r
329 struct triangulateio in, out;
\r
335 /* Define input points. */
\r
337 for(i=0,NumUsedNodes=0; i<NumNodes; i++)
\r
338 if(Node[i].used) NumUsedNodes++;
\r
340 memset(&in, 0,sizeof(in));
\r
341 memset(&out,0,sizeof(out));
\r
343 NodeTable = (int *) malloc(NumUsedNodes * sizeof(int));
\r
345 in.numberofpoints = NumUsedNodes;
\r
346 in.numberofpointattributes = 0;
\r
347 in.pointlist = (REAL *) malloc(in.numberofpoints * 2 * sizeof(REAL));
\r
348 for(i=0,N=0; i<NumNodes; i++)
\r
356 in.pointlist[N*2 ] = Node[i].p[0];
\r
357 in.pointlist[N*2+1] = Node[i].p[2];
\r
361 in.pointlist[N*2 ] = Node[i].p[1];
\r
362 in.pointlist[N*2+1] = Node[i].p[2];
\r
365 in.pointlist[N*2 ] = Node[i].p[0];
\r
366 in.pointlist[N*2+1] = Node[i].p[1];
\r
372 in.pointattributelist = (REAL *) NULL;
\r
373 in.pointmarkerlist = (int *) NULL;
\r
375 if(strstr(Options,"r"))
\r
378 TriTable = (int *) malloc(NumNodes * sizeof(int));
\r
379 for(i=0,N=0; i<NumNodes; i++)
\r
387 in.numberoftriangles = NumTris[0];
\r
388 in.numberofcorners = 3;
\r
389 in.numberoftriangleattributes = 0;
\r
390 in.trianglelist = (int *) malloc(in.numberofcorners * in.numberoftriangles * sizeof(int));
\r
391 in.triangleattributelist = (REAL *) NULL;
\r
392 in.trianglearealist = (REAL *) NULL;
\r
394 for(i=0; i<in.numberoftriangles; i++)
\r
396 in.trianglelist[i*in.numberofcorners ] = TriTable[ptri[i].v[0]];
\r
397 in.trianglelist[i*in.numberofcorners+1] = TriTable[ptri[i].v[1]];
\r
398 in.trianglelist[i*in.numberofcorners+2] = TriTable[ptri[i].v[2]];
\r
404 in.numberoftriangles = 0;
\r
405 in.numberofcorners = 3;
\r
406 in.numberoftriangleattributes = 0;
\r
407 in.trianglelist = (int *) NULL;
\r
408 in.triangleattributelist = (REAL *) NULL;
\r
409 in.trianglearealist = (REAL *) NULL;
\r
412 in.numberofsegments = 0;
\r
413 in.segmentlist = (int *) NULL;
\r
414 in.segmentmarkerlist = (int *) NULL;
\r
416 in.numberofholes = 0;
\r
417 in.holelist = (REAL *) NULL;
\r
419 in.numberofregions = 0;
\r
420 in.regionlist = (REAL *) NULL;
\r
422 in.numberofedges = 0;
\r
423 in.edgelist = (int *) NULL;
\r
424 in.edgemarkerlist = (int *) NULL;
\r
425 in.normlist = (REAL *) NULL;
\r
427 /* Make necessary initializations */
\r
428 out.pointlist = (REAL *) NULL; /* Not needed if -N switch used. */
\r
429 out.pointattributelist = (REAL *) NULL; /* Not needed if -N switch used or
\r
430 number of point attributes is zero: */
\r
431 out.pointmarkerlist = (int *) NULL; /* Not needed if -N or -B switch used. */
\r
432 out.trianglelist = (int *) NULL; /* Not needed if -E switch used. */
\r
433 out.triangleattributelist = (REAL *) NULL; /* Not needed if -E switch used or
\r
434 number of triangle attributes is
\r
436 out.trianglearealist = (REAL *) NULL;
\r
437 out.neighborlist = (int *) NULL; /* Needed only if -n switch used. */
\r
438 out.segmentlist = (int *) NULL; /* Needed only if segments are output
\r
439 (-p or -c) and -P not used: */
\r
440 out.segmentmarkerlist = (int *) NULL; /* Needed only if segments are output
\r
441 (-p or -c) and -P and -B not used: */
\r
442 out.edgelist = (int *) NULL; /* Needed only if -e switch used. */
\r
443 out.edgemarkerlist = (int *) NULL; /* Needed if -e used and -B not used. */
\r
445 triangulate(Options, &in, &out, NULL);
\r
447 NumTris[0] = out.numberoftriangles;
\r
448 *Tri = (TRI *) malloc(NumTris[0] * sizeof(TRI));
\r
451 for(i=0; i<NumTris[0]; i++)
\r
453 ptri[i].v[0] = NodeTable[out.trianglelist[i*out.numberofcorners ]];
\r
454 ptri[i].v[1] = NodeTable[out.trianglelist[i*out.numberofcorners+1]];
\r
455 ptri[i].v[2] = NodeTable[out.trianglelist[i*out.numberofcorners+2]];
\r
456 ptri[i].n[0] = out.neighborlist[i*3 ];
\r
457 ptri[i].n[1] = out.neighborlist[i*3+1];
\r
458 ptri[i].n[2] = out.neighborlist[i*3+2];
\r
461 /* Free all allocated arrays, including those allocated by Triangle. */
\r
462 if(in.pointlist) free(in.pointlist);
\r
463 if(in.pointattributelist) free(in.pointattributelist);
\r
464 if(in.pointmarkerlist) free(in.pointmarkerlist);
\r
465 if(in.trianglelist) free(in.trianglelist);
\r
466 if(in.triangleattributelist) free(in.triangleattributelist);
\r
467 if(in.trianglearealist) free(in.trianglearealist);
\r
468 if(in.neighborlist) free(in.neighborlist);
\r
469 if(in.segmentlist) free(in.segmentlist);
\r
470 if(in.segmentmarkerlist) free(in.segmentmarkerlist);
\r
471 if(in.holelist) free(in.holelist);
\r
472 if(in.regionlist) free(in.regionlist);
\r
473 if(in.edgelist) free(in.edgelist);
\r
474 if(in.edgemarkerlist) free(in.edgemarkerlist);
\r
475 if(in.normlist) free(in.normlist);
\r
476 if(out.pointlist) free(out.pointlist);
\r
477 if(out.pointattributelist) free(out.pointattributelist);
\r
478 if(out.pointmarkerlist) free(out.pointmarkerlist);
\r
479 if(out.trianglelist) free(out.trianglelist);
\r
480 if(out.triangleattributelist) free(out.triangleattributelist);
\r
481 if(out.trianglearealist) free(out.trianglearealist);
\r
482 if(out.neighborlist) free(out.neighborlist);
\r
483 if(out.segmentlist) free(out.segmentlist);
\r
484 if(out.segmentmarkerlist) free(out.segmentmarkerlist);
\r
485 if(out.holelist) free(out.holelist);
\r
486 if(out.regionlist) free(out.regionlist);
\r
487 if(out.edgelist) free(out.edgelist);
\r
488 if(out.edgemarkerlist) free(out.edgemarkerlist);
\r
489 if(out.normlist) free(out.normlist);
\r
495 void EdgeOnSide(int *v, int *edge, int *border)
\r
503 if( (v[0] <= NV) && (v[1] <= NV) )
\r
508 if( (v[1] <= NV) && (v[2] <= NV) )
\r
513 if( (v[2] <= NV) && (v[0] <= NV) )
\r
521 if( (v[0] >= R) && (v[1] >= R) )
\r
526 if( (v[1] >= R) && (v[2] >= R) )
\r
531 if( (v[2] >= R) && (v[0] >= R) )
\r
541 N = Absolute(v[k0] - v[k1]);
\r
542 Ndv = (float)(N*dv);
\r
544 if( ((v[0] % NVP1) == 0) && ((v[1] % NVP1) == 0) )
\r
547 if( Ndv > (Absolute(v[0] - v[1])*dh)) return;
\r
552 if( ((v[1] % NVP1) == 0) && ((v[2] % NVP1) == 0) )
\r
555 if( Ndv > (Absolute(v[1] - v[2])*dh)) return;
\r
560 if( ((v[2] % NVP1) == 0) && ((v[0] % NVP1) == 0) )
\r
563 if( Ndv > (Absolute(v[2] - v[0])*dh)) return;
\r
569 if( ((v[0] % NVP1) == NV) && ((v[1] % NVP1) == NV) )
\r
572 if( Ndv > (Absolute(v[0] - v[1])*dh)) return;
\r
577 if( ((v[1] % NVP1) == NV) && ((v[2] % NVP1) == NV) )
\r
580 if( Ndv > (Absolute(v[1] - v[2])*dh)) return;
\r
585 if( ((v[2] % NVP1) == NV) && ((v[0] % NVP1) == NV) )
\r
588 if( Ndv > (Absolute(v[2] - v[0])*dh)) return;
\r
596 void CalcAngles(NODE *node, int *v, float *angle)
\r
600 vec x0, x1, x2, y0, y1, y2;
\r
620 x0 = node[v[0]].p[i];
\r
621 x1 = node[v[1]].p[i];
\r
622 x2 = node[v[2]].p[i];
\r
623 y0 = node[v[0]].p[j];
\r
624 y1 = node[v[1]].p[j];
\r
625 y2 = node[v[2]].p[j];
\r
636 l = (vec)(sqrt( vv[k][0]*vv[k][0] + vv[k][1]*vv[k][1] ));
\r
644 dot = -(vv[0][0]*vv[2][0] + vv[0][1]*vv[2][1]);
\r
645 angle[0] = (float)(acos(dot));
\r
646 dot = -(vv[1][0]*vv[0][0] + vv[1][1]*vv[0][1]);
\r
647 angle[1] = (float)(acos(dot));
\r
648 dot = -(vv[2][0]*vv[1][0] + vv[2][1]*vv[1][1]);
\r
649 angle[2] = (float)(acos(dot));
\r
651 //=================================================================
\r
652 int Bisect(NODE *node, int border, int j0, int j1)
\r
665 k = (int)((j0+j1)/(2*NVP1)) * NVP1;
\r
668 k = (int)((j0+j1+2)/(2*NVP1)) * NVP1 - 1;
\r
671 return( ((k != j0) && (k != j1)) ? k : 0 );
\r
673 //=================================================================
\r
674 int compare(TRITABLE *t1, TRITABLE *t2)
\r
676 if(t1->error > t2->error) return -1;
\r
677 if(t1->error < t2->error) return 1;
\r
681 void MakeBrushes(int NumTris, NODE *Node, TRI *Tri,bool surf,
\r
682 int offset,char *texture0, char *texture1, char *texture2)
\r
684 extern double backface;
\r
689 vec3_t PlaneNormal,SurfNormal;
\r
693 // if texture2 is identical to texture0, there's no need to
\r
694 // check surface angle
\r
695 if(!g_strcasecmp(texture0,texture2) || !strlen(texture2))
\r
696 CheckAngle = FALSE;
\r
700 Steep = (float)cos((double)SlantAngle/57.2957795);
\r
703 case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
\r
704 case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break;
\r
705 case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break;
\r
706 case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break;
\r
707 case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
\r
708 case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break;
\r
715 if(UseDetail) contents += CONTENTS_DETAIL;
\r
716 if(UseLadder) contents += CONTENTS_LADDER;
\r
720 for(i=0; i<NumTris; i++)
\r
723 brush.NumFaces = 5;
\r
725 brush.face[0].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
726 brush.face[0].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
727 brush.face[0].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
729 brush.face[0].v[1][0] = Node[Tri[i].v[2]].p[0];
\r
730 brush.face[0].v[1][1] = Node[Tri[i].v[2]].p[1];
\r
731 brush.face[0].v[1][2] = Node[Tri[i].v[2]].p[2];
\r
733 brush.face[0].v[2][0] = Node[Tri[i].v[1]].p[0];
\r
734 brush.face[0].v[2][1] = Node[Tri[i].v[1]].p[1];
\r
735 brush.face[0].v[2][2] = Node[Tri[i].v[1]].p[2];
\r
742 brush.face[0].v[0][2] += offset;
\r
743 brush.face[0].v[1][2] += offset;
\r
744 brush.face[0].v[1][2] += offset;
\r
747 brush.face[0].v[0][2] -= offset;
\r
748 brush.face[0].v[1][2] -= offset;
\r
749 brush.face[0].v[1][2] -= offset;
\r
752 brush.face[0].v[0][1] += offset;
\r
753 brush.face[0].v[1][1] += offset;
\r
754 brush.face[0].v[1][1] += offset;
\r
757 brush.face[0].v[0][1] -= offset;
\r
758 brush.face[0].v[1][1] -= offset;
\r
759 brush.face[0].v[1][1] -= offset;
\r
762 brush.face[0].v[0][0] += offset;
\r
763 brush.face[0].v[1][0] += offset;
\r
764 brush.face[0].v[1][0] += offset;
\r
767 brush.face[0].v[0][0] -= offset;
\r
768 brush.face[0].v[1][0] -= offset;
\r
769 brush.face[0].v[1][0] -= offset;
\r
778 brush.face[1].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
779 brush.face[1].v[0][1] = (float)backface;
\r
780 brush.face[1].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
782 brush.face[1].v[1][0] = Node[Tri[i].v[1]].p[0];
\r
783 brush.face[1].v[1][1] = (float)backface;
\r
784 brush.face[1].v[1][2] = Node[Tri[i].v[1]].p[2];
\r
786 brush.face[1].v[2][0] = Node[Tri[i].v[2]].p[0];
\r
787 brush.face[1].v[2][1] = (float)backface;
\r
788 brush.face[1].v[2][2] = Node[Tri[i].v[2]].p[2];
\r
791 brush.face[2].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
792 brush.face[2].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
793 brush.face[2].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
795 brush.face[2].v[1][0] = Node[Tri[i].v[1]].p[0];
\r
796 brush.face[2].v[1][1] = Node[Tri[i].v[1]].p[1];
\r
797 brush.face[2].v[1][2] = Node[Tri[i].v[1]].p[2];
\r
799 brush.face[2].v[2][0] = Node[Tri[i].v[1]].p[0];
\r
800 brush.face[2].v[2][1] = (float)backface;
\r
801 brush.face[2].v[2][2] = Node[Tri[i].v[1]].p[2];
\r
804 brush.face[3].v[0][0] = Node[Tri[i].v[1]].p[0];
\r
805 brush.face[3].v[0][1] = Node[Tri[i].v[1]].p[1];
\r
806 brush.face[3].v[0][2] = Node[Tri[i].v[1]].p[2];
\r
808 brush.face[3].v[1][0] = Node[Tri[i].v[2]].p[0];
\r
809 brush.face[3].v[1][1] = Node[Tri[i].v[2]].p[1];
\r
810 brush.face[3].v[1][2] = Node[Tri[i].v[2]].p[2];
\r
812 brush.face[3].v[2][0] = Node[Tri[i].v[2]].p[0];
\r
813 brush.face[3].v[2][1] = (float)backface;
\r
814 brush.face[3].v[2][2] = Node[Tri[i].v[2]].p[2];
\r
817 brush.face[4].v[0][0] = Node[Tri[i].v[2]].p[0];
\r
818 brush.face[4].v[0][1] = Node[Tri[i].v[2]].p[1];
\r
819 brush.face[4].v[0][2] = Node[Tri[i].v[2]].p[2];
\r
821 brush.face[4].v[1][0] = Node[Tri[i].v[0]].p[0];
\r
822 brush.face[4].v[1][1] = Node[Tri[i].v[0]].p[1];
\r
823 brush.face[4].v[1][2] = Node[Tri[i].v[0]].p[2];
\r
825 brush.face[4].v[2][0] = Node[Tri[i].v[0]].p[0];
\r
826 brush.face[4].v[2][1] = (float)backface;
\r
827 brush.face[4].v[2][2] = Node[Tri[i].v[0]].p[2];
\r
832 brush.face[1].v[0][0] = (float)backface;
\r
833 brush.face[1].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
834 brush.face[1].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
836 brush.face[1].v[1][0] = (float)backface;
\r
837 brush.face[1].v[1][1] = Node[Tri[i].v[1]].p[1];
\r
838 brush.face[1].v[1][2] = Node[Tri[i].v[1]].p[2];
\r
840 brush.face[1].v[2][0] = (float)backface;
\r
841 brush.face[1].v[2][1] = Node[Tri[i].v[2]].p[1];
\r
842 brush.face[1].v[2][2] = Node[Tri[i].v[2]].p[2];
\r
845 brush.face[2].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
846 brush.face[2].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
847 brush.face[2].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
849 brush.face[2].v[1][0] = Node[Tri[i].v[1]].p[0];
\r
850 brush.face[2].v[1][1] = Node[Tri[i].v[1]].p[1];
\r
851 brush.face[2].v[1][2] = Node[Tri[i].v[1]].p[2];
\r
853 brush.face[2].v[2][0] = (float)backface;
\r
854 brush.face[2].v[2][1] = Node[Tri[i].v[1]].p[1];
\r
855 brush.face[2].v[2][2] = Node[Tri[i].v[1]].p[2];
\r
858 brush.face[3].v[0][0] = Node[Tri[i].v[1]].p[0];
\r
859 brush.face[3].v[0][1] = Node[Tri[i].v[1]].p[1];
\r
860 brush.face[3].v[0][2] = Node[Tri[i].v[1]].p[2];
\r
862 brush.face[3].v[1][0] = Node[Tri[i].v[2]].p[0];
\r
863 brush.face[3].v[1][1] = Node[Tri[i].v[2]].p[1];
\r
864 brush.face[3].v[1][2] = Node[Tri[i].v[2]].p[2];
\r
866 brush.face[3].v[2][0] = (float)backface;
\r
867 brush.face[3].v[2][1] = Node[Tri[i].v[2]].p[1];
\r
868 brush.face[3].v[2][2] = Node[Tri[i].v[2]].p[2];
\r
871 brush.face[4].v[0][0] = Node[Tri[i].v[2]].p[0];
\r
872 brush.face[4].v[0][1] = Node[Tri[i].v[2]].p[1];
\r
873 brush.face[4].v[0][2] = Node[Tri[i].v[2]].p[2];
\r
875 brush.face[4].v[1][0] = Node[Tri[i].v[0]].p[0];
\r
876 brush.face[4].v[1][1] = Node[Tri[i].v[0]].p[1];
\r
877 brush.face[4].v[1][2] = Node[Tri[i].v[0]].p[2];
\r
879 brush.face[4].v[2][0] = (float)backface;
\r
880 brush.face[4].v[2][1] = Node[Tri[i].v[0]].p[1];
\r
881 brush.face[4].v[2][2] = Node[Tri[i].v[0]].p[2];
\r
885 brush.face[1].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
886 brush.face[1].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
887 brush.face[1].v[0][2] = (float)backface;
\r
889 brush.face[1].v[1][0] = Node[Tri[i].v[1]].p[0];
\r
890 brush.face[1].v[1][1] = Node[Tri[i].v[1]].p[1];
\r
891 brush.face[1].v[1][2] = (float)backface;
\r
893 brush.face[1].v[2][0] = Node[Tri[i].v[2]].p[0];
\r
894 brush.face[1].v[2][1] = Node[Tri[i].v[2]].p[1];
\r
895 brush.face[1].v[2][2] = (float)backface;
\r
898 brush.face[2].v[0][0] = Node[Tri[i].v[0]].p[0];
\r
899 brush.face[2].v[0][1] = Node[Tri[i].v[0]].p[1];
\r
900 brush.face[2].v[0][2] = Node[Tri[i].v[0]].p[2];
\r
902 brush.face[2].v[1][0] = Node[Tri[i].v[1]].p[0];
\r
903 brush.face[2].v[1][1] = Node[Tri[i].v[1]].p[1];
\r
904 brush.face[2].v[1][2] = Node[Tri[i].v[1]].p[2];
\r
906 brush.face[2].v[2][0] = Node[Tri[i].v[1]].p[0];
\r
907 brush.face[2].v[2][1] = Node[Tri[i].v[1]].p[1];
\r
908 brush.face[2].v[2][2] = (float)backface;
\r
911 brush.face[3].v[0][0] = Node[Tri[i].v[1]].p[0];
\r
912 brush.face[3].v[0][1] = Node[Tri[i].v[1]].p[1];
\r
913 brush.face[3].v[0][2] = Node[Tri[i].v[1]].p[2];
\r
915 brush.face[3].v[1][0] = Node[Tri[i].v[2]].p[0];
\r
916 brush.face[3].v[1][1] = Node[Tri[i].v[2]].p[1];
\r
917 brush.face[3].v[1][2] = Node[Tri[i].v[2]].p[2];
\r
919 brush.face[3].v[2][0] = Node[Tri[i].v[2]].p[0];
\r
920 brush.face[3].v[2][1] = Node[Tri[i].v[2]].p[1];
\r
921 brush.face[3].v[2][2] = (float)backface;
\r
924 brush.face[4].v[0][0] = Node[Tri[i].v[2]].p[0];
\r
925 brush.face[4].v[0][1] = Node[Tri[i].v[2]].p[1];
\r
926 brush.face[4].v[0][2] = Node[Tri[i].v[2]].p[2];
\r
928 brush.face[4].v[1][0] = Node[Tri[i].v[0]].p[0];
\r
929 brush.face[4].v[1][1] = Node[Tri[i].v[0]].p[1];
\r
930 brush.face[4].v[1][2] = Node[Tri[i].v[0]].p[2];
\r
932 brush.face[4].v[2][0] = Node[Tri[i].v[0]].p[0];
\r
933 brush.face[4].v[2][1] = Node[Tri[i].v[0]].p[1];
\r
934 brush.face[4].v[2][2] = (float)backface;
\r
939 strcpy(brush.face[j].texture,
\r
940 (strlen(texture1) ? texture1 : texture0));
\r
941 brush.face[j].Shift[0] = (float)TexOffset[0];
\r
942 brush.face[j].Shift[1] = (float)TexOffset[1];
\r
943 brush.face[j].Rotate = 0.;
\r
944 brush.face[j].Scale[0] = (float)TexScale[0];
\r
945 brush.face[j].Scale[1] = (float)TexScale[1];
\r
946 brush.face[j].Contents = contents;
\r
948 brush.face[j].Surface = 0;
\r
950 brush.face[j].Surface = SURF_HINT;
\r
951 brush.face[j].Value = 0;
\r
956 XYZVectorSubtract(brush.face[0].v[2],brush.face[0].v[0],t[0]);
\r
957 XYZVectorSubtract(brush.face[0].v[1],brush.face[0].v[2],t[1]);
\r
958 CrossProduct(t[0],t[1],SurfNormal);
\r
959 VectorNormalize(SurfNormal,SurfNormal);
\r
960 if(DotProduct(SurfNormal,PlaneNormal) < Steep)
\r
961 strcpy(brush.face[0].texture,texture2);
\r
963 strcpy(brush.face[0].texture,texture0);
\r
966 strcpy(brush.face[0].texture,texture0);
\r
968 if(surf) brush.face[0].Value = ArghRad2;
\r
973 } // end MakeBrushes
\r
974 //=================================================================
\r
975 void MapOut(int NumNodes,int NumTris, NODE *Node, TRI *Tri)
\r
977 extern double backface;
\r
978 extern double xmin, xmax, ymin, ymax, zmin, zmax;
\r
980 char hint[32], skip[32];
\r
984 ghCursorCurrent = LoadCursor(NULL,IDC_WAIT);
\r
985 SetCursor(ghCursorCurrent);
\r
987 UseDetail = 1; // this is temporary
\r
988 MakeBrushes(NumTris,Node,Tri,TRUE,0,Texture[Game][0],Texture[Game][1],Texture[Game][2]);
\r
990 if(AddHints || GimpHints)
\r
995 strcpy(hint,"generic/misc/hint");
\r
996 strcpy(skip,"generic/misc/skip");
\r
999 strcpy(hint,"HINT");
\r
1000 strcpy(skip,"HINT");
\r
1003 strcpy(hint,"general/hint");
\r
1004 strcpy(skip,"general/skip");
\r
1007 strcpy(hint,"common/0_hint");
\r
1008 strcpy(skip,"common/0_skip");
\r
1011 strcpy(hint,"common/hint");
\r
1012 strcpy(skip,"common/skip");
\r
1015 strcpy(hint,"e1u1/hint");
\r
1016 strcpy(skip,"e1u1/skip");
\r
1021 MakeBrushes(NumTris,Node,Tri,FALSE,HINT_OFFSET,hint,hint,hint);
\r
1025 int j0, j1, j2, k, k0, k1;
\r
1027 int w,h,h0,h1,t,OK;
\r
1030 int MaxHints; // We don't want a whole slew of hint brushes, which we'd get
\r
1031 // with low decimation values and our current placement scheme.
\r
1032 // Limit number of hint brushes to number of undecimated grid
\r
1038 front = LessThan(zmin,32.);
\r
1041 front = MoreThan(ymax,32.);
\r
1044 front = LessThan(ymin,32.);
\r
1047 front = MoreThan(xmax,32.);
\r
1050 front = LessThan(xmin,32.);
\r
1053 front = MoreThan(zmax,32.);
\r
1056 for(i=0; i<NumTris; i++)
\r
1080 brush.NumFaces = 6;
\r
1081 MaxHints = NH*NV-1;
\r
1082 for(w=1; w<min(16,NH) && brush.Number < MaxHints; w++)
\r
1084 for(h=max(1,w/2); h<min(16,NV) && brush.Number < MaxHints; h++)
\r
1086 for(i=0; i<=NH-w && brush.Number < MaxHints; i++)
\r
1088 for(j=0; j<=NV-h && brush.Number < MaxHints; j++)
\r
1091 q[2] = q[0] + w*NVP1 + h;
\r
1104 for(k=0, OK=1; k<NumTris && OK; k++)
\r
1106 if(Tri[k].min[j1] >= max(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue;
\r
1107 if(Tri[k].min[j2] >= max(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue;
\r
1108 if(Tri[k].max[j1] <= min(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue;
\r
1109 if(Tri[k].max[j2] <= min(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue;
\r
1111 for(h0=0; h0<4 && OK; h0++)
\r
1114 for(t=0; t<3 && OK; t++)
\r
1116 s[t] = side(Node[q[h0]].p[j1],Node[q[h0]].p[j2],
\r
1117 Node[q[h1]].p[j1],Node[q[h1]].p[j2],
\r
1118 Node[Tri[k].v[t]].p[j1],Node[Tri[k].v[t]].p[j2]);
\r
1120 if((s[1] > 0 || s[2] > 0) && s[0] < 0) OK=0;
\r
1121 if((s[2] > 0 || s[0] > 0) && s[1] < 0) OK=0;
\r
1122 if((s[0] > 0 || s[1] > 0) && s[2] < 0) OK=0;
\r
1131 brush.face[0].v[0][0] = Node[q[2]].p[0];
\r
1132 brush.face[0].v[0][1] = (float)front;
\r
1133 brush.face[0].v[0][2] = Node[q[2]].p[2];
\r
1135 brush.face[0].v[1][0] = Node[q[1]].p[0];
\r
1136 brush.face[0].v[1][1] = (float)front;
\r
1137 brush.face[0].v[1][2] = Node[q[1]].p[2];
\r
1139 brush.face[0].v[2][0] = Node[q[0]].p[0];
\r
1140 brush.face[0].v[2][1] = (float)front;
\r
1141 brush.face[0].v[2][2] = Node[q[0]].p[2];
\r
1144 brush.face[1].v[0][0] = Node[q[0]].p[0];
\r
1145 brush.face[1].v[0][1] = (float)backface;
\r
1146 brush.face[1].v[0][2] = Node[q[0]].p[2];
\r
1148 brush.face[1].v[1][0] = Node[q[1]].p[0];
\r
1149 brush.face[1].v[1][1] = (float)backface;
\r
1150 brush.face[1].v[1][2] = Node[q[1]].p[2];
\r
1152 brush.face[1].v[2][0] = Node[q[2]].p[0];
\r
1153 brush.face[1].v[2][1] = (float)backface;
\r
1154 brush.face[1].v[2][2] = Node[q[2]].p[2];
\r
1156 for(k0=0; k0<brush.NumFaces-2; k0++)
\r
1159 k1=(k0+1) % (brush.NumFaces-2);
\r
1161 brush.face[k].v[0][0] = Node[q[k0]].p[0];
\r
1162 brush.face[k].v[0][1] = (float)front;
\r
1163 brush.face[k].v[0][2] = Node[q[k0]].p[2];
\r
1165 brush.face[k].v[1][0] = Node[q[k1]].p[0];
\r
1166 brush.face[k].v[1][1] = (float)front;
\r
1167 brush.face[k].v[1][2] = Node[q[k1]].p[2];
\r
1169 brush.face[k].v[2][0] = Node[q[k1]].p[0];
\r
1170 brush.face[k].v[2][1] = (float)backface;
\r
1171 brush.face[k].v[2][2] = Node[q[k1]].p[2];
\r
1177 brush.face[0].v[0][0] = (float)front;
\r
1178 brush.face[0].v[0][1] = Node[q[2]].p[1];
\r
1179 brush.face[0].v[0][2] = Node[q[2]].p[2];
\r
1181 brush.face[0].v[1][0] = (float)front;
\r
1182 brush.face[0].v[1][1] = Node[q[1]].p[1];
\r
1183 brush.face[0].v[1][2] = Node[q[1]].p[2];
\r
1185 brush.face[0].v[2][0] = (float)front;
\r
1186 brush.face[0].v[2][1] = Node[q[0]].p[1];
\r
1187 brush.face[0].v[2][2] = Node[q[0]].p[2];
\r
1190 brush.face[1].v[0][0] = (float)backface;
\r
1191 brush.face[1].v[0][1] = Node[q[0]].p[1];
\r
1192 brush.face[1].v[0][2] = Node[q[0]].p[2];
\r
1194 brush.face[1].v[1][0] = (float)backface;
\r
1195 brush.face[1].v[1][1] = Node[q[1]].p[1];
\r
1196 brush.face[1].v[1][2] = Node[q[1]].p[2];
\r
1198 brush.face[1].v[2][0] = (float)backface;
\r
1199 brush.face[1].v[2][1] = Node[q[2]].p[1];
\r
1200 brush.face[1].v[2][2] = Node[q[2]].p[2];
\r
1202 for(k0=0; k0<brush.NumFaces-2; k0++)
\r
1205 k1=(k0+1) % (brush.NumFaces-2);
\r
1207 brush.face[k].v[0][0] = (float)front;
\r
1208 brush.face[k].v[0][1] = Node[q[k0]].p[1];
\r
1209 brush.face[k].v[0][2] = Node[q[k0]].p[2];
\r
1211 brush.face[k].v[1][0] = (float)front;
\r
1212 brush.face[k].v[1][1] = Node[q[k1]].p[1];
\r
1213 brush.face[k].v[1][2] = Node[q[k1]].p[2];
\r
1215 brush.face[k].v[2][0] = (float)backface;
\r
1216 brush.face[k].v[2][1] = Node[q[k1]].p[1];
\r
1217 brush.face[k].v[2][2] = Node[q[k1]].p[2];
\r
1222 brush.face[0].v[0][0] = Node[q[2]].p[0];
\r
1223 brush.face[0].v[0][1] = Node[q[2]].p[1];
\r
1224 brush.face[0].v[0][2] = (float)front;
\r
1226 brush.face[0].v[1][0] = Node[q[1]].p[0];
\r
1227 brush.face[0].v[1][1] = Node[q[1]].p[1];
\r
1228 brush.face[0].v[1][2] = (float)front;
\r
1230 brush.face[0].v[2][0] = Node[q[0]].p[0];
\r
1231 brush.face[0].v[2][1] = Node[q[0]].p[1];
\r
1232 brush.face[0].v[2][2] = (float)front;
\r
1235 brush.face[1].v[0][0] = Node[q[0]].p[0];
\r
1236 brush.face[1].v[0][1] = Node[q[0]].p[1];
\r
1237 brush.face[1].v[0][2] = (float)backface;
\r
1239 brush.face[1].v[1][0] = Node[q[1]].p[0];
\r
1240 brush.face[1].v[1][1] = Node[q[1]].p[1];
\r
1241 brush.face[1].v[1][2] = (float)backface;
\r
1243 brush.face[1].v[2][0] = Node[q[2]].p[0];
\r
1244 brush.face[1].v[2][1] = Node[q[2]].p[1];
\r
1245 brush.face[1].v[2][2] = (float)backface;
\r
1247 for(k0=0; k0<brush.NumFaces-2; k0++)
\r
1250 k1=(k0+1) % (brush.NumFaces-2);
\r
1252 brush.face[k].v[0][0] = Node[q[k0]].p[0];
\r
1253 brush.face[k].v[0][1] = Node[q[k0]].p[1];
\r
1254 brush.face[k].v[0][2] = (float)front;
\r
1256 brush.face[k].v[1][0] = Node[q[k1]].p[0];
\r
1257 brush.face[k].v[1][1] = Node[q[k1]].p[1];
\r
1258 brush.face[k].v[1][2] = (float)front;
\r
1260 brush.face[k].v[2][0] = Node[q[k1]].p[0];
\r
1261 brush.face[k].v[2][1] = Node[q[k1]].p[1];
\r
1262 brush.face[k].v[2][2] = (float)backface;
\r
1265 } // switch (Plane)
\r
1266 for(face=0; face<6; face++)
\r
1268 strcpy(brush.face[face].texture,(face<=1 ? skip : hint));
\r
1269 brush.face[face].Shift[0] = 0;
\r
1270 brush.face[face].Shift[1] = 0;
\r
1271 brush.face[face].Rotate = 0.;
\r
1272 brush.face[face].Scale[0] = 1;
\r
1273 brush.face[face].Scale[1] = 1;
\r
1274 brush.face[face].Contents = CONTENTS_DETAIL;
\r
1275 brush.face[face].Surface = (face<=1 ? SURF_SKIP : SURF_HINT);
\r
1276 brush.face[face].Value = 0;
\r
1278 if(!brush.Number) OpenFuncGroup();
\r
1279 MakeBrush(&brush);
\r
1285 if(brush.Number) CloseFuncGroup();
\r
1288 ghCursorCurrent = ghCursorDefault;
\r
1289 SetCursor(ghCursorCurrent);
\r
1292 //===========================================================================
\r
1293 int CheckBorders(int *NumNodesUsed, int NumNodes, NODE *Node, int *NumTris, TRI **pTri)
\r
1296 int i, j, k0, k1, N;
\r
1300 N = NumNodesUsed[0];
\r
1302 for(i=0; i<NumTris[0]; i++)
\r
1304 EdgeOnSide(Tri[i].v,&k0,&border);
\r
1305 if(border < 0) continue;
\r
1306 CalcAngles(Node, Tri[i].v, angle);
\r
1308 if((angle[k0] < SLIVER_ANGLE) || (angle[k1] < SLIVER_ANGLE))
\r
1310 j = Bisect(Node, border, Tri[i].v[k0], Tri[i].v[k1]);
\r
1313 if(!Node[j].used) // Shouldn't be used, but...
\r
1315 NumNodesUsed[0]++;
\r
1321 if(NumNodesUsed[0] > N)
\r
1324 tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY");
\r
1327 return (NumNodesUsed[0] - N);
\r