1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2003, Andrew Ross
4 //
5 // Walk through an indexed triangle list, splitting vertices that
6 // share "sharp" edges, and calculate normals for the resulting mesh.
7 //
8 // This code should really live inside the OptVertexList class in
9 // ssgOptimizer.cxx, whose data model is almost 1:1 compatible with
10 // the indexed triangle representation here.  It is a separate file
11 // because it comes from separate code that Andy Ross wrote for a
12 // different project, and this was the cleanest way to do the port.
13 //
14 ////////////////////////////////////////////////////////////////////////
15 
16 #include "ssgVertSplitter.h"
17 
18 #include <math.h>
19 #include "sg.h"
20 
21 //
22 ////////////////////////////////////////////////////////////////////////
23 
origVert(int i)24 int ssgVertSplitter::origVert(int i)
25 {
26     return _newVertMap[i];
27 }
28 
ssgVertSplitter(int nVerts,int nTris)29 ssgVertSplitter::ssgVertSplitter(int nVerts, int nTris)
30 {
31     setSharpAngle(61);
32     _nVerts = _origVerts = _vertsAlloced = nVerts;
33     _verts = new float[3*_nVerts];
34     _norms = new float[3*_nVerts];
35     _nTris = nTris;
36     _tris = new Tri[3*_nTris];
37     _triNorms = new float[3*_nTris];
38     _geomVerts = new int[_nVerts];
39 
40     _newVertMap = 0;
41 }
42 
~ssgVertSplitter()43 ssgVertSplitter::~ssgVertSplitter()
44 {
45     delete[] _verts;
46     delete[] _norms;
47     delete[] _tris;
48     delete[] _triNorms;
49     delete[] _newVertMap;
50     delete[] _geomVerts;
51 }
52 
setTri(int tidx,int va,int vb,int vc)53 void ssgVertSplitter::setTri(int tidx, int va, int vb, int vc)
54 {
55     _tris[tidx].verts[0] = _tris[tidx].oVerts[0] = va;
56     _tris[tidx].verts[1] = _tris[tidx].oVerts[1] = vb;
57     _tris[tidx].verts[2] = _tris[tidx].oVerts[2] = vc;
58     _tris[tidx].degenerate = false;
59 }
60 
getTri(int t)61 int* ssgVertSplitter::getTri(int t)
62 {
63     return &(_tris[t].verts[0]);
64 }
65 
setSharpAngle(float deg)66 void ssgVertSplitter::setSharpAngle(float deg)
67 {
68     _threshold = (float) cos(deg*SG_DEGREES_TO_RADIANS);
69 }
70 
findTriWithVert(int fidx,int vidx,int * tris,int ntris)71 int ssgVertSplitter::findTriWithVert(int fidx, int vidx, int* tris, int ntris)
72 {
73     // check each triangle in the list for a matching edge
74     for(int t=0; t<ntris; t++) {
75         if(t == fidx) continue;     // not a neighbor to ourselves
76         if(tris[t] == -1) continue; // no longer available
77         for(int i=0; i<3; i++)
78             if(_tris[tris[t]].verts[i] == vidx)
79                 return t;
80     }
81     return -1;
82 }
83 
nextTri(int fidx,int vidx,int * tris,int ntris)84 int ssgVertSplitter::nextTri(int fidx, int vidx, int* tris, int ntris)
85 {
86     if(tris[fidx] == -1) return -1;
87 
88     // Adjoining triangles share an edge
89     int* verts = _tris[tris[fidx]].verts, vertnum;
90     for(vertnum=0; vertnum<3; vertnum++) if(verts[vertnum] == vidx) break;
91     int nextvert = _tris[tris[fidx]].verts[vertnum==2 ? 0 : vertnum+1];
92     return findTriWithVert(fidx, nextvert, tris, ntris);
93 }
94 
prevTri(int fidx,int vidx,int * tris,int ntris)95 int ssgVertSplitter::prevTri(int fidx, int vidx, int* tris, int ntris)
96 {
97     if(tris[fidx] == -1) return -1;
98     int* verts = _tris[tris[fidx]].verts, vertnum;
99     for(vertnum=0; vertnum<3; vertnum++) if(verts[vertnum] == vidx) break;
100     int prevvert = _tris[tris[fidx]].verts[vertnum==0 ? 2 : vertnum-1];
101     return findTriWithVert(fidx, prevvert, tris, ntris);
102 }
103 
fixVidx(Tri * t,int oldIdx,int newIdx)104 void ssgVertSplitter::fixVidx(Tri* t, int oldIdx, int newIdx)
105 {
106     for(int i=0; i<3; i++) {
107         if(t->verts[i] == oldIdx) {
108             t->verts[i] = newIdx;
109             return;
110         }
111     }
112 }
113 
114 // Find geometrically identical vertices and fixup triangle indices to
115 // point to the first one.
condenseGeometry()116 void ssgVertSplitter::condenseGeometry()
117 {
118     for(int i=0; i<_nVerts; i++) {
119         _geomVerts[i] = i;
120         for(int j=0; j<i; j++) {
121             if(sgEqualVec3(vert(i), vert(j))) {
122                 _geomVerts[i] = j;
123                 for(int t=0; t<_nTris; t++) {
124                     if(_tris[t].verts[0] == i) _tris[t].verts[0] = j;
125                     if(_tris[t].verts[1] == i) _tris[t].verts[1] = j;
126                     if(_tris[t].verts[2] == i) _tris[t].verts[2] = j;
127                 }
128                 break;
129             }
130         }
131     }
132 }
133 
expandDuplicates()134 void ssgVertSplitter::expandDuplicates()
135 {
136     int i, j, k;
137 
138     // "split" vertex, original vertex, final vertex
139     struct vrec { int sv; int ov; int fv; };
140     vrec* vrecs = new vrec[_vertsAlloced];
141     int nvrecs = 0;
142 
143     // Tick off each vertex index as it gets finalized to a
144     // input/post-split vertex tuple.
145     bool *used = new bool[_vertsAlloced];
146     for(i=0; i<_vertsAlloced; i++) used[i] = false;
147 
148     for(i=0; i<_nTris; i++) {
149         for(j=0; j<3; j++) {
150             int sv = _tris[i].verts[j];
151             int ov = _tris[i].oVerts[j];
152             int fv = -1;
153             for(k=0; k<nvrecs; k++)
154                 if(vrecs[k].sv == sv && vrecs[k].ov == ov)
155                     fv = _tris[i].verts[j] = vrecs[k].fv;
156             if(fv >= 0) continue;
157 
158             // No existing record, make one.
159             if(!used[sv] && sv >= _origVerts) fv = sv;
160             else if(!used[ov]) fv = ov;
161             else { fv = _nVerts++; _nextNewVert++; }
162 
163             int r = nvrecs++;
164             vrecs[r].sv = sv;
165             vrecs[r].ov = ov;
166             vrecs[r].fv = fv;
167             // __builtin_printf("s %d o %d f %d\n", sv, ov, fv);
168 
169             sgCopyVec3(vert(fv), vert(sv));
170             sgCopyVec3(norm(fv), norm(sv));
171             if(fv >= _origVerts)
172                 _newVertMap[fv - _origVerts] = ov;
173             used[fv] = true;
174             _tris[i].verts[j] = fv;
175         }
176     }
177     delete[] vrecs;
178     delete[] used;
179 }
180 
splitAndCalcNormals()181 void ssgVertSplitter::splitAndCalcNormals()
182 {
183     int i, j;
184     float zero[] = {0,0,0};
185     for(i=0; i<_nVerts; i++) sgCopyVec3(norm(i), zero);
186 
187     // First, find duplicate vertices and coalesce the geometry
188     condenseGeometry();
189 
190     // Calculate a normal for each face, and count the number of
191     // references to each vertex.
192     float* faceNorms = _triNorms;
193     int* vCounts = new int[_nVerts];
194     for(i=0; i<_nVerts; i++)
195         vCounts[i] = 0;
196     for(i=0; i<_nTris; i++) {
197         sgVec3 a, b;
198         float *fnorm = faceNorms + 3*i;
199         int* verts = _tris[i].verts ;
200         sgCopyVec3(a, vert(verts[1]));
201         sgSubVec3(a, vert(verts[0]));
202         sgCopyVec3(b, vert(verts[2]));
203         sgSubVec3(b, vert(verts[0]));
204         sgVectorProductVec3(fnorm, a, b);
205         sgNormaliseVec3(fnorm);
206         vCounts[verts[0]]++;
207         vCounts[verts[1]]++;
208         vCounts[verts[2]]++;
209 
210         if(verts[0]==verts[1] || verts[1]==verts[2] || verts[2]==verts[0])
211         {
212             _tris[i].degenerate = true;
213             fnorm[0] = fnorm[1] = 0;
214             fnorm[2] = 1;
215         }
216     }
217 
218     // Build a table mapping vertices to arrays of triangle indices
219     // vTris[v] is a pointer to a list of vCounts[v] triangle indices.
220     int* vtspace = new int[3*_nTris];
221     int** vTris = new int*[_nVerts];
222     int* vtptr = vtspace;
223     for(i=0; i<3*_nTris; i++) vtspace[i] = -1;
224     for(i=0; i<_nVerts; i++) {
225         vTris[i] = vtptr;
226         vtptr += vCounts[i];
227     }
228     int *vctmp = new int[_nVerts];
229     for(i=0; i<_nVerts; i++) vctmp[i] = 0;
230     for(i=0; i<_nTris; i++) {
231         if(_tris[i].degenerate) continue;
232         for(int v=0; v<3; v++)
233             vTris[_tris[i].verts[v]][vctmp[_tris[i].verts[v]]++] = i;
234     }
235     delete[] vctmp;
236 
237     // Make some temp space for new vertices and their normals
238     int maxNewVerts = 8*_nVerts;
239     _newVertMap = new int[maxNewVerts];
240     float* newNorms = new float[3*maxNewVerts];
241     _nextNewVert = 0;
242 
243     // Now the hard part.  For each vertex, pick a face.  Walk forward
244     // and backwards from that face until you hit a sharp edge or
245     // already-done face, summing normals along the way and marking
246     // off the face as "done".  If there are faces left, split off a
247     // *new* vertex for the remaining ones, pick a remaining face, and
248     // repeat.  Repeat until we run out of faces.
249     for(int vidx=0; vidx<_nVerts; vidx++) {
250         while(1) {
251             // Pick a face
252             int fidx = -1;
253             bool someDone = false;
254             for(int face=0; face<vCounts[vidx]; face++)
255                 if(vTris[vidx][face] != -1) fidx = face;
256                 else someDone = true;
257             if(fidx == -1) break;
258 
259             float* fnorm = norm(vidx);
260 
261             // Oops, some faces already stole the previous vertex index.
262             // Need to make a *new* vertex and replace the index on the
263             // remaining triangles.
264             int realvert = vidx;
265             if(someDone) {
266                 realvert = _nVerts + _nextNewVert;
267                 fnorm = newNorms + 3*_nextNewVert;
268                 _newVertMap[_nextNewVert++] = vidx;
269             }
270 
271             for(i=0; i<3; i++) fnorm[i] = 0;
272             int nextidx = nextTri(fidx, vidx, vTris[vidx], vCounts[vidx]);
273             int previdx = prevTri(fidx, vidx, vTris[vidx], vCounts[vidx]);
274             sgAddVec3(fnorm, faceNorms + 3*vTris[vidx][fidx]);
275             float* lastNorm0 = faceNorms + 3*vTris[vidx][fidx];
276             float* lastNorm = lastNorm0;
277             if(someDone)
278                 fixVidx(_tris + vTris[vidx][fidx], vidx, realvert);
279             vTris[vidx][fidx] = -1;
280             while(nextidx >= 0) {
281                 float* n = faceNorms + 3*vTris[vidx][nextidx];
282                 if(sgScalarProductVec3(n, lastNorm) < _threshold) break;
283                 lastNorm = n;
284                 sgAddVec3(fnorm, n);
285                 int oldnext = nextidx;
286                 nextidx = nextTri(nextidx, vidx, vTris[vidx], vCounts[vidx]);
287                 if(someDone)
288                     fixVidx(_tris + vTris[vidx][oldnext], vidx, realvert);
289                 vTris[vidx][oldnext] = -1;
290             }
291             lastNorm = lastNorm0;
292             while(previdx >= 0) {
293                 if(vTris[vidx][previdx] < 0) break;
294                 float* n = faceNorms + 3*vTris[vidx][previdx];
295                 if(sgScalarProductVec3(n, lastNorm) < _threshold) break;
296                 lastNorm = n;
297                 sgAddVec3(fnorm, faceNorms + 3*vTris[vidx][previdx]);
298                 int oldprev = previdx;
299                 previdx = prevTri(previdx, vidx, vTris[vidx], vCounts[vidx]);
300                 if(someDone)
301                     fixVidx(_tris + vTris[vidx][oldprev], vidx, realvert);
302                 vTris[vidx][oldprev] = -1;
303             }
304         }
305     };
306 
307     // Reallocate the new vertex/normal tables.
308     _vertsAlloced = _nVerts + maxNewVerts;
309     float* newVerts = new float[3*_vertsAlloced];
310     for(i=0; i<3*_nVerts; i++)
311         newVerts[i] = _verts[i];
312     for(i=0; i<_nextNewVert; i++)
313         for(j=0; j<3; j++)
314             newVerts[3*(_nVerts+i)+j] = _verts[3*_newVertMap[i]+j];
315     delete[] _verts;
316     _verts = newVerts;
317 
318     float* tmpnorms = new float[3*_vertsAlloced];
319     for(i=0; i<3*_nVerts; i++)
320         tmpnorms[i] = _norms[i];
321     for(i=0; i<3*_nextNewVert; i++)
322         tmpnorms[3*_nVerts+i] = newNorms[i];
323     delete[] _norms;
324     _norms = tmpnorms;
325 
326     _nVerts += _nextNewVert;
327 
328     // Finally, renormalize everything
329     for(i=0; i<_nVerts; i++)
330         if(i >= _origVerts || _geomVerts[i] == i) sgNormaliseVec3(norm(i));
331     for(i=0; i<_origVerts; i++)
332         if(_geomVerts[i] != i) sgCopyVec3(norm(i), norm(_geomVerts[i]));
333 
334     // Now, if necessary, duplicate the vertices that got "condensed"
335     // earlier by creating a new vertex and cloning the normal.
336     expandDuplicates();
337 
338 #if 0
339     static int allOrig = 0;
340     static int allFinal = 0;
341     allOrig += _origVerts;
342     allFinal += _nVerts;
343     fprintf(stderr, "%d -> %d (%d/%d)\n", _origVerts, _nVerts,
344             allOrig, allFinal);
345 #endif
346 
347     delete[] vCounts;
348     delete[] vtspace;
349     delete[] vTris;
350     delete[] newNorms;
351 }
352