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