nvtristrip-ruby 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +50 -0
- data/README.nvtristrip +32 -0
- data/Rakefile +76 -0
- data/TODO +7 -0
- data/ext/NvTriStrip.cpp +501 -0
- data/ext/NvTriStrip.h +145 -0
- data/ext/NvTriStripObjects.cpp +1773 -0
- data/ext/NvTriStripObjects.h +248 -0
- data/ext/RbTriStrip.cpp +324 -0
- data/ext/VertexCache.h +81 -0
- data/ext/extconf.rb +5 -0
- data/setup.rb +1585 -0
- data/test/test_nvtristrip.rb +46 -0
- metadata +59 -0
data/ext/NvTriStrip.h
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#ifndef NVTRISTRIP_H
|
2
|
+
#define NVTRISTRIP_H
|
3
|
+
|
4
|
+
#ifndef NULL
|
5
|
+
#define NULL 0
|
6
|
+
#endif
|
7
|
+
|
8
|
+
// #pragma comment(lib, "nvtristrip")
|
9
|
+
|
10
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
11
|
+
// Public interface for stripifier
|
12
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
13
|
+
|
14
|
+
//GeForce1 and 2 cache size
|
15
|
+
#define CACHESIZE_GEFORCE1_2 16
|
16
|
+
|
17
|
+
//GeForce3 cache size
|
18
|
+
#define CACHESIZE_GEFORCE3 24
|
19
|
+
|
20
|
+
enum PrimType
|
21
|
+
{
|
22
|
+
PT_LIST,
|
23
|
+
PT_STRIP,
|
24
|
+
PT_FAN
|
25
|
+
};
|
26
|
+
|
27
|
+
struct PrimitiveGroup
|
28
|
+
{
|
29
|
+
PrimType type;
|
30
|
+
unsigned int numIndices;
|
31
|
+
unsigned short* indices;
|
32
|
+
|
33
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
34
|
+
|
35
|
+
PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(NULL) {}
|
36
|
+
~PrimitiveGroup()
|
37
|
+
{
|
38
|
+
if(indices)
|
39
|
+
delete[] indices;
|
40
|
+
indices = NULL;
|
41
|
+
}
|
42
|
+
};
|
43
|
+
|
44
|
+
|
45
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
46
|
+
// EnableRestart()
|
47
|
+
//
|
48
|
+
// For GPUs that support primitive restart, this sets a value as the restart index
|
49
|
+
//
|
50
|
+
// Restart is meaningless if strips are not being stitched together, so enabling restart
|
51
|
+
// makes NvTriStrip forcing stitching. So, you'll get back one strip.
|
52
|
+
//
|
53
|
+
// Default value: disabled
|
54
|
+
//
|
55
|
+
void EnableRestart(const unsigned int restartVal);
|
56
|
+
|
57
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
58
|
+
// DisableRestart()
|
59
|
+
//
|
60
|
+
// For GPUs that support primitive restart, this disables using primitive restart
|
61
|
+
//
|
62
|
+
void DisableRestart();
|
63
|
+
|
64
|
+
|
65
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
66
|
+
// SetCacheSize()
|
67
|
+
//
|
68
|
+
// Sets the cache size which the stripfier uses to optimize the data.
|
69
|
+
// Controls the length of the generated individual strips.
|
70
|
+
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
71
|
+
// You may want to play around with this number to tweak performance.
|
72
|
+
//
|
73
|
+
// Default value: 16
|
74
|
+
//
|
75
|
+
void SetCacheSize(const unsigned int cacheSize);
|
76
|
+
|
77
|
+
|
78
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
79
|
+
// SetStitchStrips()
|
80
|
+
//
|
81
|
+
// bool to indicate whether to stitch together strips into one huge strip or not.
|
82
|
+
// If set to true, you'll get back one huge strip stitched together using degenerate
|
83
|
+
// triangles.
|
84
|
+
// If set to false, you'll get back a large number of separate strips.
|
85
|
+
//
|
86
|
+
// Default value: true
|
87
|
+
//
|
88
|
+
void SetStitchStrips(const bool bStitchStrips);
|
89
|
+
|
90
|
+
|
91
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
92
|
+
// SetMinStripSize()
|
93
|
+
//
|
94
|
+
// Sets the minimum acceptable size for a strip, in triangles.
|
95
|
+
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
96
|
+
//
|
97
|
+
// Default value: 0
|
98
|
+
//
|
99
|
+
void SetMinStripSize(const unsigned int minSize);
|
100
|
+
|
101
|
+
|
102
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
103
|
+
// SetListsOnly()
|
104
|
+
//
|
105
|
+
// If set to true, will return an optimized list, with no strips at all.
|
106
|
+
//
|
107
|
+
// Default value: false
|
108
|
+
//
|
109
|
+
void SetListsOnly(const bool bListsOnly);
|
110
|
+
|
111
|
+
|
112
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
113
|
+
// GenerateStrips()
|
114
|
+
//
|
115
|
+
// in_indices: input index list, the indices you would use to render
|
116
|
+
// in_numIndices: number of entries in in_indices
|
117
|
+
// primGroups: array of optimized/stripified PrimitiveGroups
|
118
|
+
// numGroups: number of groups returned
|
119
|
+
//
|
120
|
+
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
121
|
+
//
|
122
|
+
bool GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
123
|
+
PrimitiveGroup** primGroups, unsigned short* numGroups, bool validateEnabled = false);
|
124
|
+
|
125
|
+
|
126
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
127
|
+
// RemapIndices()
|
128
|
+
//
|
129
|
+
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
130
|
+
//
|
131
|
+
// in_primGroups: array of PrimitiveGroups you want remapped
|
132
|
+
// numGroups: number of entries in in_primGroups
|
133
|
+
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
134
|
+
// of acceptable values for indices in your primitive groups.
|
135
|
+
// remappedGroups: array of remapped PrimitiveGroups
|
136
|
+
//
|
137
|
+
// Note that, according to the remapping handed back to you, you must reorder your
|
138
|
+
// vertex buffer.
|
139
|
+
//
|
140
|
+
// Credit goes to the MS Xbox crew for the idea for this interface.
|
141
|
+
//
|
142
|
+
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
143
|
+
const unsigned short numVerts, PrimitiveGroup** remappedGroups);
|
144
|
+
|
145
|
+
#endif
|
@@ -0,0 +1,1773 @@
|
|
1
|
+
|
2
|
+
//#pragma warning( disable : 4786 )
|
3
|
+
|
4
|
+
#include <assert.h>
|
5
|
+
#include <set>
|
6
|
+
#include "NvTriStripObjects.h"
|
7
|
+
#include "VertexCache.h"
|
8
|
+
|
9
|
+
#define CACHE_INEFFICIENCY 6
|
10
|
+
|
11
|
+
NvStripifier::NvStripifier()
|
12
|
+
{
|
13
|
+
|
14
|
+
}
|
15
|
+
|
16
|
+
NvStripifier::~NvStripifier()
|
17
|
+
{
|
18
|
+
|
19
|
+
}
|
20
|
+
|
21
|
+
|
22
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
23
|
+
// FindEdgeInfo()
|
24
|
+
//
|
25
|
+
// find the edge info for these two indices
|
26
|
+
//
|
27
|
+
NvEdgeInfo * NvStripifier::FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1){
|
28
|
+
|
29
|
+
// we can get to it through either array
|
30
|
+
// because the edge infos have a v0 and v1
|
31
|
+
// and there is no order except how it was
|
32
|
+
// first created.
|
33
|
+
NvEdgeInfo *infoIter = edgeInfos[v0];
|
34
|
+
while (infoIter != NULL){
|
35
|
+
if (infoIter->m_v0 == v0){
|
36
|
+
if (infoIter->m_v1 == v1)
|
37
|
+
return infoIter;
|
38
|
+
else
|
39
|
+
infoIter = infoIter->m_nextV0;
|
40
|
+
}
|
41
|
+
else {
|
42
|
+
assert(infoIter->m_v1 == v0);
|
43
|
+
if (infoIter->m_v0 == v1)
|
44
|
+
return infoIter;
|
45
|
+
else
|
46
|
+
infoIter = infoIter->m_nextV1;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return NULL;
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
54
|
+
// FindOtherFace
|
55
|
+
//
|
56
|
+
// find the other face sharing these vertices
|
57
|
+
// exactly like the edge info above
|
58
|
+
//
|
59
|
+
NvFaceInfo * NvStripifier::FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo){
|
60
|
+
NvEdgeInfo *edgeInfo = FindEdgeInfo(edgeInfos, v0, v1);
|
61
|
+
|
62
|
+
if( (edgeInfo == NULL) && (v0 == v1))
|
63
|
+
{
|
64
|
+
//we've hit a degenerate
|
65
|
+
return NULL;
|
66
|
+
}
|
67
|
+
|
68
|
+
assert(edgeInfo != NULL);
|
69
|
+
return (edgeInfo->m_face0 == faceInfo ? edgeInfo->m_face1 : edgeInfo->m_face0);
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
bool NvStripifier::AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos)
|
74
|
+
{
|
75
|
+
for(int i = 0; i < faceInfos.size(); ++i)
|
76
|
+
{
|
77
|
+
if( (faceInfos[i]->m_v0 == faceInfo->m_v0) &&
|
78
|
+
(faceInfos[i]->m_v1 == faceInfo->m_v1) &&
|
79
|
+
(faceInfos[i]->m_v2 == faceInfo->m_v2) )
|
80
|
+
return true;
|
81
|
+
}
|
82
|
+
|
83
|
+
return false;
|
84
|
+
}
|
85
|
+
|
86
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
87
|
+
// BuildStripifyInfo()
|
88
|
+
//
|
89
|
+
// Builds the list of all face and edge infos
|
90
|
+
//
|
91
|
+
void NvStripifier::BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos,
|
92
|
+
const unsigned short maxIndex)
|
93
|
+
{
|
94
|
+
// reserve space for the face infos, but do not resize them.
|
95
|
+
int numIndices = indices.size();
|
96
|
+
faceInfos.reserve(numIndices / 3);
|
97
|
+
int i;
|
98
|
+
|
99
|
+
// we actually resize the edge infos, so we must initialize to NULL
|
100
|
+
edgeInfos.resize(maxIndex + 1);
|
101
|
+
for (i = 0; i < maxIndex + 1; i++)
|
102
|
+
edgeInfos[i] = NULL;
|
103
|
+
|
104
|
+
// iterate through the triangles of the triangle list
|
105
|
+
int numTriangles = numIndices / 3;
|
106
|
+
int index = 0;
|
107
|
+
bool bFaceUpdated[3];
|
108
|
+
|
109
|
+
for (i = 0; i < numTriangles; i++)
|
110
|
+
{
|
111
|
+
bool bMightAlreadyExist = true;
|
112
|
+
bFaceUpdated[0] = false;
|
113
|
+
bFaceUpdated[1] = false;
|
114
|
+
bFaceUpdated[2] = false;
|
115
|
+
|
116
|
+
// grab the indices
|
117
|
+
int v0 = indices[index++];
|
118
|
+
int v1 = indices[index++];
|
119
|
+
int v2 = indices[index++];
|
120
|
+
|
121
|
+
//we disregard degenerates
|
122
|
+
if(IsDegenerate(v0, v1, v2))
|
123
|
+
continue;
|
124
|
+
|
125
|
+
// create the face info and add it to the list of faces, but only if this exact face doesn't already
|
126
|
+
// exist in the list
|
127
|
+
NvFaceInfo *faceInfo = new NvFaceInfo(v0, v1, v2);
|
128
|
+
|
129
|
+
// grab the edge infos, creating them if they do not already exist
|
130
|
+
NvEdgeInfo *edgeInfo01 = FindEdgeInfo(edgeInfos, v0, v1);
|
131
|
+
if (edgeInfo01 == NULL)
|
132
|
+
{
|
133
|
+
//since one of it's edges isn't in the edge data structure, it can't already exist in the face structure
|
134
|
+
bMightAlreadyExist = false;
|
135
|
+
|
136
|
+
// create the info
|
137
|
+
edgeInfo01 = new NvEdgeInfo(v0, v1);
|
138
|
+
|
139
|
+
// update the linked list on both
|
140
|
+
edgeInfo01->m_nextV0 = edgeInfos[v0];
|
141
|
+
edgeInfo01->m_nextV1 = edgeInfos[v1];
|
142
|
+
edgeInfos[v0] = edgeInfo01;
|
143
|
+
edgeInfos[v1] = edgeInfo01;
|
144
|
+
|
145
|
+
// set face 0
|
146
|
+
edgeInfo01->m_face0 = faceInfo;
|
147
|
+
}
|
148
|
+
else
|
149
|
+
{
|
150
|
+
if (edgeInfo01->m_face1 != NULL)
|
151
|
+
{
|
152
|
+
printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n");
|
153
|
+
}
|
154
|
+
else
|
155
|
+
{
|
156
|
+
edgeInfo01->m_face1 = faceInfo;
|
157
|
+
bFaceUpdated[0] = true;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
// grab the edge infos, creating them if they do not already exist
|
162
|
+
NvEdgeInfo *edgeInfo12 = FindEdgeInfo(edgeInfos, v1, v2);
|
163
|
+
if (edgeInfo12 == NULL)
|
164
|
+
{
|
165
|
+
bMightAlreadyExist = false;
|
166
|
+
|
167
|
+
// create the info
|
168
|
+
edgeInfo12 = new NvEdgeInfo(v1, v2);
|
169
|
+
|
170
|
+
// update the linked list on both
|
171
|
+
edgeInfo12->m_nextV0 = edgeInfos[v1];
|
172
|
+
edgeInfo12->m_nextV1 = edgeInfos[v2];
|
173
|
+
edgeInfos[v1] = edgeInfo12;
|
174
|
+
edgeInfos[v2] = edgeInfo12;
|
175
|
+
|
176
|
+
// set face 0
|
177
|
+
edgeInfo12->m_face0 = faceInfo;
|
178
|
+
}
|
179
|
+
else
|
180
|
+
{
|
181
|
+
if (edgeInfo12->m_face1 != NULL)
|
182
|
+
{
|
183
|
+
printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n");
|
184
|
+
}
|
185
|
+
else
|
186
|
+
{
|
187
|
+
edgeInfo12->m_face1 = faceInfo;
|
188
|
+
bFaceUpdated[1] = true;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
// grab the edge infos, creating them if they do not already exist
|
193
|
+
NvEdgeInfo *edgeInfo20 = FindEdgeInfo(edgeInfos, v2, v0);
|
194
|
+
if (edgeInfo20 == NULL)
|
195
|
+
{
|
196
|
+
bMightAlreadyExist = false;
|
197
|
+
|
198
|
+
// create the info
|
199
|
+
edgeInfo20 = new NvEdgeInfo(v2, v0);
|
200
|
+
|
201
|
+
// update the linked list on both
|
202
|
+
edgeInfo20->m_nextV0 = edgeInfos[v2];
|
203
|
+
edgeInfo20->m_nextV1 = edgeInfos[v0];
|
204
|
+
edgeInfos[v2] = edgeInfo20;
|
205
|
+
edgeInfos[v0] = edgeInfo20;
|
206
|
+
|
207
|
+
// set face 0
|
208
|
+
edgeInfo20->m_face0 = faceInfo;
|
209
|
+
}
|
210
|
+
else
|
211
|
+
{
|
212
|
+
if (edgeInfo20->m_face1 != NULL)
|
213
|
+
{
|
214
|
+
printf("BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n");
|
215
|
+
}
|
216
|
+
else
|
217
|
+
{
|
218
|
+
edgeInfo20->m_face1 = faceInfo;
|
219
|
+
bFaceUpdated[2] = true;
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
if(bMightAlreadyExist)
|
224
|
+
{
|
225
|
+
if(!AlreadyExists(faceInfo, faceInfos))
|
226
|
+
faceInfos.push_back(faceInfo);
|
227
|
+
else
|
228
|
+
{
|
229
|
+
delete faceInfo;
|
230
|
+
|
231
|
+
//cleanup pointers that point to this deleted face
|
232
|
+
if(bFaceUpdated[0])
|
233
|
+
edgeInfo01->m_face1 = NULL;
|
234
|
+
if(bFaceUpdated[1])
|
235
|
+
edgeInfo12->m_face1 = NULL;
|
236
|
+
if(bFaceUpdated[2])
|
237
|
+
edgeInfo20->m_face1 = NULL;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
else
|
241
|
+
{
|
242
|
+
faceInfos.push_back(faceInfo);
|
243
|
+
}
|
244
|
+
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
|
249
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
250
|
+
// FindStartPoint()
|
251
|
+
//
|
252
|
+
// Finds a good starting point, namely one which has only one neighbor
|
253
|
+
//
|
254
|
+
int NvStripifier::FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos)
|
255
|
+
{
|
256
|
+
int bestCtr = -1;
|
257
|
+
int bestIndex = -1;
|
258
|
+
|
259
|
+
for(int i = 0; i < faceInfos.size(); i++)
|
260
|
+
{
|
261
|
+
int ctr = 0;
|
262
|
+
|
263
|
+
if(FindOtherFace(edgeInfos, faceInfos[i]->m_v0, faceInfos[i]->m_v1, faceInfos[i]) == NULL)
|
264
|
+
ctr++;
|
265
|
+
if(FindOtherFace(edgeInfos, faceInfos[i]->m_v1, faceInfos[i]->m_v2, faceInfos[i]) == NULL)
|
266
|
+
ctr++;
|
267
|
+
if(FindOtherFace(edgeInfos, faceInfos[i]->m_v2, faceInfos[i]->m_v0, faceInfos[i]) == NULL)
|
268
|
+
ctr++;
|
269
|
+
if(ctr > bestCtr)
|
270
|
+
{
|
271
|
+
bestCtr = ctr;
|
272
|
+
bestIndex = i;
|
273
|
+
//return i;
|
274
|
+
}
|
275
|
+
}
|
276
|
+
//return -1;
|
277
|
+
|
278
|
+
if(bestCtr == 0)
|
279
|
+
return -1;
|
280
|
+
else
|
281
|
+
return bestIndex;
|
282
|
+
}
|
283
|
+
|
284
|
+
|
285
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
286
|
+
// FindGoodResetPoint()
|
287
|
+
//
|
288
|
+
// A good reset point is one near other commited areas so that
|
289
|
+
// we know that when we've made the longest strips its because
|
290
|
+
// we're stripifying in the same general orientation.
|
291
|
+
//
|
292
|
+
NvFaceInfo* NvStripifier::FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos){
|
293
|
+
// we hop into different areas of the mesh to try to get
|
294
|
+
// other large open spans done. Areas of small strips can
|
295
|
+
// just be left to triangle lists added at the end.
|
296
|
+
NvFaceInfo *result = NULL;
|
297
|
+
|
298
|
+
if(result == NULL)
|
299
|
+
{
|
300
|
+
int numFaces = faceInfos.size();
|
301
|
+
int startPoint;
|
302
|
+
if(bFirstTimeResetPoint)
|
303
|
+
{
|
304
|
+
//first time, find a face with few neighbors (look for an edge of the mesh)
|
305
|
+
startPoint = FindStartPoint(faceInfos, edgeInfos);
|
306
|
+
bFirstTimeResetPoint = false;
|
307
|
+
}
|
308
|
+
else
|
309
|
+
startPoint = (int)(((float) numFaces - 1) * meshJump);
|
310
|
+
|
311
|
+
if(startPoint == -1)
|
312
|
+
{
|
313
|
+
startPoint = (int)(((float) numFaces - 1) * meshJump);
|
314
|
+
|
315
|
+
//meshJump += 0.1f;
|
316
|
+
//if (meshJump > 1.0f)
|
317
|
+
// meshJump = .05f;
|
318
|
+
}
|
319
|
+
|
320
|
+
int i = startPoint;
|
321
|
+
do {
|
322
|
+
|
323
|
+
// if this guy isn't visited, try him
|
324
|
+
if (faceInfos[i]->m_stripId < 0){
|
325
|
+
result = faceInfos[i];
|
326
|
+
break;
|
327
|
+
}
|
328
|
+
|
329
|
+
// update the index and clamp to 0-(numFaces-1)
|
330
|
+
if (++i >= numFaces)
|
331
|
+
i = 0;
|
332
|
+
|
333
|
+
} while (i != startPoint);
|
334
|
+
|
335
|
+
// update the meshJump
|
336
|
+
meshJump += 0.1f;
|
337
|
+
if (meshJump > 1.0f)
|
338
|
+
meshJump = .05f;
|
339
|
+
}
|
340
|
+
|
341
|
+
// return the best face we found
|
342
|
+
return result;
|
343
|
+
}
|
344
|
+
|
345
|
+
|
346
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
347
|
+
// GetUniqueVertexInB()
|
348
|
+
//
|
349
|
+
// Returns the vertex unique to faceB
|
350
|
+
//
|
351
|
+
int NvStripifier::GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB){
|
352
|
+
|
353
|
+
int facev0 = faceB->m_v0;
|
354
|
+
if (facev0 != faceA->m_v0 &&
|
355
|
+
facev0 != faceA->m_v1 &&
|
356
|
+
facev0 != faceA->m_v2)
|
357
|
+
return facev0;
|
358
|
+
|
359
|
+
int facev1 = faceB->m_v1;
|
360
|
+
if (facev1 != faceA->m_v0 &&
|
361
|
+
facev1 != faceA->m_v1 &&
|
362
|
+
facev1 != faceA->m_v2)
|
363
|
+
return facev1;
|
364
|
+
|
365
|
+
int facev2 = faceB->m_v2;
|
366
|
+
if (facev2 != faceA->m_v0 &&
|
367
|
+
facev2 != faceA->m_v1 &&
|
368
|
+
facev2 != faceA->m_v2)
|
369
|
+
return facev2;
|
370
|
+
|
371
|
+
// nothing is different
|
372
|
+
return -1;
|
373
|
+
}
|
374
|
+
|
375
|
+
|
376
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
377
|
+
// GetSharedVertices()
|
378
|
+
//
|
379
|
+
// Returns the (at most) two vertices shared between the two faces
|
380
|
+
//
|
381
|
+
void NvStripifier::GetSharedVertices(NvFaceInfo *faceA, NvFaceInfo *faceB, int* vertex0, int* vertex1)
|
382
|
+
{
|
383
|
+
*vertex0 = -1;
|
384
|
+
*vertex1 = -1;
|
385
|
+
|
386
|
+
int facev0 = faceB->m_v0;
|
387
|
+
if (facev0 == faceA->m_v0 ||
|
388
|
+
facev0 == faceA->m_v1 ||
|
389
|
+
facev0 == faceA->m_v2)
|
390
|
+
{
|
391
|
+
if(*vertex0 == -1)
|
392
|
+
*vertex0 = facev0;
|
393
|
+
else
|
394
|
+
{
|
395
|
+
*vertex1 = facev0;
|
396
|
+
return;
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
int facev1 = faceB->m_v1;
|
401
|
+
if (facev1 == faceA->m_v0 ||
|
402
|
+
facev1 == faceA->m_v1 ||
|
403
|
+
facev1 == faceA->m_v2)
|
404
|
+
{
|
405
|
+
if(*vertex0 == -1)
|
406
|
+
*vertex0 = facev1;
|
407
|
+
else
|
408
|
+
{
|
409
|
+
*vertex1 = facev1;
|
410
|
+
return;
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
int facev2 = faceB->m_v2;
|
415
|
+
if (facev2 == faceA->m_v0 ||
|
416
|
+
facev2 == faceA->m_v1 ||
|
417
|
+
facev2 == faceA->m_v2)
|
418
|
+
{
|
419
|
+
if(*vertex0 == -1)
|
420
|
+
*vertex0 = facev2;
|
421
|
+
else
|
422
|
+
{
|
423
|
+
*vertex1 = facev2;
|
424
|
+
return;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
}
|
429
|
+
|
430
|
+
|
431
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
432
|
+
// GetNextIndex()
|
433
|
+
//
|
434
|
+
// Returns vertex of the input face which is "next" in the input index list
|
435
|
+
//
|
436
|
+
inline int NvStripifier::GetNextIndex(const WordVec &indices, NvFaceInfo *face){
|
437
|
+
|
438
|
+
int numIndices = indices.size();
|
439
|
+
assert(numIndices >= 2);
|
440
|
+
|
441
|
+
int v0 = indices[numIndices-2];
|
442
|
+
int v1 = indices[numIndices-1];
|
443
|
+
|
444
|
+
int fv0 = face->m_v0;
|
445
|
+
int fv1 = face->m_v1;
|
446
|
+
int fv2 = face->m_v2;
|
447
|
+
|
448
|
+
if (fv0 != v0 && fv0 != v1){
|
449
|
+
if ((fv1 != v0 && fv1 != v1) || (fv2 != v0 && fv2 != v1)){
|
450
|
+
printf("GetNextIndex: Triangle doesn't have all of its vertices\n");
|
451
|
+
printf("GetNextIndex: Duplicate triangle probably got us derailed\n");
|
452
|
+
}
|
453
|
+
return fv0;
|
454
|
+
}
|
455
|
+
if (fv1 != v0 && fv1 != v1){
|
456
|
+
if ((fv0 != v0 && fv0 != v1) || (fv2 != v0 && fv2 != v1)){
|
457
|
+
printf("GetNextIndex: Triangle doesn't have all of its vertices\n");
|
458
|
+
printf("GetNextIndex: Duplicate triangle probably got us derailed\n");
|
459
|
+
}
|
460
|
+
return fv1;
|
461
|
+
}
|
462
|
+
if (fv2 != v0 && fv2 != v1){
|
463
|
+
if ((fv0 != v0 && fv0 != v1) || (fv1 != v0 && fv1 != v1)){
|
464
|
+
printf("GetNextIndex: Triangle doesn't have all of its vertices\n");
|
465
|
+
printf("GetNextIndex: Duplicate triangle probably got us derailed\n");
|
466
|
+
}
|
467
|
+
return fv2;
|
468
|
+
}
|
469
|
+
|
470
|
+
// shouldn't get here, but let's try and fail gracefully
|
471
|
+
if( (fv0 == fv1) || (fv0 == fv2) )
|
472
|
+
return fv0;
|
473
|
+
else if( (fv1 == fv0) || (fv1 == fv2) )
|
474
|
+
return fv1;
|
475
|
+
else if( (fv2 == fv0) || (fv2 == fv1) )
|
476
|
+
return fv2;
|
477
|
+
else
|
478
|
+
return -1;
|
479
|
+
}
|
480
|
+
|
481
|
+
|
482
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
483
|
+
// IsMarked()
|
484
|
+
//
|
485
|
+
// If either the faceInfo has a real strip index because it is
|
486
|
+
// already assign to a committed strip OR it is assigned in an
|
487
|
+
// experiment and the experiment index is the one we are building
|
488
|
+
// for, then it is marked and unavailable
|
489
|
+
inline bool NvStripInfo::IsMarked(NvFaceInfo *faceInfo){
|
490
|
+
return (faceInfo->m_stripId >= 0) || (IsExperiment() && faceInfo->m_experimentId == m_experimentId);
|
491
|
+
}
|
492
|
+
|
493
|
+
|
494
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
495
|
+
// MarkTriangle()
|
496
|
+
//
|
497
|
+
// Marks the face with the current strip ID
|
498
|
+
//
|
499
|
+
inline void NvStripInfo::MarkTriangle(NvFaceInfo *faceInfo){
|
500
|
+
assert(!IsMarked(faceInfo));
|
501
|
+
if (IsExperiment()){
|
502
|
+
faceInfo->m_experimentId = m_experimentId;
|
503
|
+
faceInfo->m_testStripId = m_stripId;
|
504
|
+
}
|
505
|
+
else{
|
506
|
+
assert(faceInfo->m_stripId == -1);
|
507
|
+
faceInfo->m_experimentId = -1;
|
508
|
+
faceInfo->m_stripId = m_stripId;
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
512
|
+
|
513
|
+
bool NvStripInfo::Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face)
|
514
|
+
{
|
515
|
+
bool bv0, bv1, bv2; //bools to indicate whether a vertex is in the faceVec or not
|
516
|
+
bv0 = bv1 = bv2 = false;
|
517
|
+
|
518
|
+
for(int i = 0; i < faceVec.size(); i++)
|
519
|
+
{
|
520
|
+
if(!bv0)
|
521
|
+
{
|
522
|
+
if( (faceVec[i]->m_v0 == face->m_v0) ||
|
523
|
+
(faceVec[i]->m_v1 == face->m_v0) ||
|
524
|
+
(faceVec[i]->m_v2 == face->m_v0) )
|
525
|
+
bv0 = true;
|
526
|
+
}
|
527
|
+
|
528
|
+
if(!bv1)
|
529
|
+
{
|
530
|
+
if( (faceVec[i]->m_v0 == face->m_v1) ||
|
531
|
+
(faceVec[i]->m_v1 == face->m_v1) ||
|
532
|
+
(faceVec[i]->m_v2 == face->m_v1) )
|
533
|
+
bv1 = true;
|
534
|
+
}
|
535
|
+
|
536
|
+
if(!bv2)
|
537
|
+
{
|
538
|
+
if( (faceVec[i]->m_v0 == face->m_v2) ||
|
539
|
+
(faceVec[i]->m_v1 == face->m_v2) ||
|
540
|
+
(faceVec[i]->m_v2 == face->m_v2) )
|
541
|
+
bv2 = true;
|
542
|
+
}
|
543
|
+
|
544
|
+
//the face is not unique, all it's vertices exist in the face vector
|
545
|
+
if(bv0 && bv1 && bv2)
|
546
|
+
return false;
|
547
|
+
}
|
548
|
+
|
549
|
+
//if we get out here, it's unique
|
550
|
+
return true;
|
551
|
+
}
|
552
|
+
|
553
|
+
|
554
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
555
|
+
// Build()
|
556
|
+
//
|
557
|
+
// Builds a strip forward as far as we can go, then builds backwards, and joins the two lists
|
558
|
+
//
|
559
|
+
void NvStripInfo::Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos)
|
560
|
+
{
|
561
|
+
// used in building the strips forward and backward
|
562
|
+
WordVec scratchIndices;
|
563
|
+
|
564
|
+
// build forward... start with the initial face
|
565
|
+
NvFaceInfoVec forwardFaces, backwardFaces;
|
566
|
+
forwardFaces.push_back(m_startInfo.m_startFace);
|
567
|
+
|
568
|
+
MarkTriangle(m_startInfo.m_startFace);
|
569
|
+
|
570
|
+
int v0 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v0 : m_startInfo.m_startEdge->m_v1);
|
571
|
+
int v1 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v1 : m_startInfo.m_startEdge->m_v0);
|
572
|
+
|
573
|
+
// easiest way to get v2 is to use this function which requires the
|
574
|
+
// other indices to already be in the list.
|
575
|
+
scratchIndices.push_back(v0);
|
576
|
+
scratchIndices.push_back(v1);
|
577
|
+
int v2 = NvStripifier::GetNextIndex(scratchIndices, m_startInfo.m_startFace);
|
578
|
+
scratchIndices.push_back(v2);
|
579
|
+
|
580
|
+
//
|
581
|
+
// build the forward list
|
582
|
+
//
|
583
|
+
int nv0 = v1;
|
584
|
+
int nv1 = v2;
|
585
|
+
|
586
|
+
NvFaceInfo *nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace);
|
587
|
+
while (nextFace != NULL && !IsMarked(nextFace))
|
588
|
+
{
|
589
|
+
//check to see if this next face is going to cause us to die soon
|
590
|
+
int testnv0 = nv1;
|
591
|
+
int testnv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
|
592
|
+
|
593
|
+
NvFaceInfo* nextNextFace = NvStripifier::FindOtherFace(edgeInfos, testnv0, testnv1, nextFace);
|
594
|
+
|
595
|
+
if( (nextNextFace == NULL) || (IsMarked(nextNextFace)) )
|
596
|
+
{
|
597
|
+
//uh, oh, we're following a dead end, try swapping
|
598
|
+
NvFaceInfo* testNextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, testnv1, nextFace);
|
599
|
+
|
600
|
+
if( ((testNextFace != NULL) && !IsMarked(testNextFace)) )
|
601
|
+
{
|
602
|
+
//we only swap if it buys us something
|
603
|
+
|
604
|
+
//add a "fake" degenerate face
|
605
|
+
NvFaceInfo* tempFace = new NvFaceInfo(nv0, nv1, nv0, true);
|
606
|
+
|
607
|
+
forwardFaces.push_back(tempFace);
|
608
|
+
MarkTriangle(tempFace);
|
609
|
+
|
610
|
+
scratchIndices.push_back(nv0);
|
611
|
+
testnv0 = nv0;
|
612
|
+
|
613
|
+
++m_numDegenerates;
|
614
|
+
}
|
615
|
+
|
616
|
+
}
|
617
|
+
|
618
|
+
// add this to the strip
|
619
|
+
forwardFaces.push_back(nextFace);
|
620
|
+
|
621
|
+
MarkTriangle(nextFace);
|
622
|
+
|
623
|
+
// add the index
|
624
|
+
//nv0 = nv1;
|
625
|
+
//nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
|
626
|
+
scratchIndices.push_back(testnv1);
|
627
|
+
|
628
|
+
// and get the next face
|
629
|
+
nv0 = testnv0;
|
630
|
+
nv1 = testnv1;
|
631
|
+
|
632
|
+
nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace);
|
633
|
+
|
634
|
+
}
|
635
|
+
|
636
|
+
// tempAllFaces is going to be forwardFaces + backwardFaces
|
637
|
+
// it's used for Unique()
|
638
|
+
NvFaceInfoVec tempAllFaces;
|
639
|
+
for(int i = 0; i < forwardFaces.size(); i++)
|
640
|
+
tempAllFaces.push_back(forwardFaces[i]);
|
641
|
+
|
642
|
+
//
|
643
|
+
// reset the indices for building the strip backwards and do so
|
644
|
+
//
|
645
|
+
scratchIndices.resize(0);
|
646
|
+
scratchIndices.push_back(v2);
|
647
|
+
scratchIndices.push_back(v1);
|
648
|
+
scratchIndices.push_back(v0);
|
649
|
+
nv0 = v1;
|
650
|
+
nv1 = v0;
|
651
|
+
nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace);
|
652
|
+
while (nextFace != NULL && !IsMarked(nextFace))
|
653
|
+
{
|
654
|
+
//this tests to see if a face is "unique", meaning that its vertices aren't already in the list
|
655
|
+
// so, strips which "wrap-around" are not allowed
|
656
|
+
if(!Unique(tempAllFaces, nextFace))
|
657
|
+
break;
|
658
|
+
|
659
|
+
//check to see if this next face is going to cause us to die soon
|
660
|
+
int testnv0 = nv1;
|
661
|
+
int testnv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
|
662
|
+
|
663
|
+
NvFaceInfo* nextNextFace = NvStripifier::FindOtherFace(edgeInfos, testnv0, testnv1, nextFace);
|
664
|
+
|
665
|
+
if( (nextNextFace == NULL) || (IsMarked(nextNextFace)) )
|
666
|
+
{
|
667
|
+
//uh, oh, we're following a dead end, try swapping
|
668
|
+
NvFaceInfo* testNextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, testnv1, nextFace);
|
669
|
+
if( ((testNextFace != NULL) && !IsMarked(testNextFace)) )
|
670
|
+
{
|
671
|
+
//we only swap if it buys us something
|
672
|
+
|
673
|
+
//add a "fake" degenerate face
|
674
|
+
NvFaceInfo* tempFace = new NvFaceInfo(nv0, nv1, nv0, true);
|
675
|
+
|
676
|
+
backwardFaces.push_back(tempFace);
|
677
|
+
MarkTriangle(tempFace);
|
678
|
+
scratchIndices.push_back(nv0);
|
679
|
+
testnv0 = nv0;
|
680
|
+
|
681
|
+
++m_numDegenerates;
|
682
|
+
}
|
683
|
+
|
684
|
+
}
|
685
|
+
|
686
|
+
// add this to the strip
|
687
|
+
backwardFaces.push_back(nextFace);
|
688
|
+
|
689
|
+
//this is just so Unique() will work
|
690
|
+
tempAllFaces.push_back(nextFace);
|
691
|
+
|
692
|
+
MarkTriangle(nextFace);
|
693
|
+
|
694
|
+
// add the index
|
695
|
+
//nv0 = nv1;
|
696
|
+
//nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace);
|
697
|
+
scratchIndices.push_back(testnv1);
|
698
|
+
|
699
|
+
// and get the next face
|
700
|
+
nv0 = testnv0;
|
701
|
+
nv1 = testnv1;
|
702
|
+
nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace);
|
703
|
+
}
|
704
|
+
|
705
|
+
// Combine the forward and backwards stripification lists and put into our own face vector
|
706
|
+
Combine(forwardFaces, backwardFaces);
|
707
|
+
}
|
708
|
+
|
709
|
+
|
710
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
711
|
+
// Combine()
|
712
|
+
//
|
713
|
+
// Combines the two input face vectors and puts the result into m_faces
|
714
|
+
//
|
715
|
+
void NvStripInfo::Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward){
|
716
|
+
|
717
|
+
int i;
|
718
|
+
// add backward faces
|
719
|
+
int numFaces = backward.size();
|
720
|
+
for (i = numFaces - 1; i >= 0; i--)
|
721
|
+
m_faces.push_back(backward[i]);
|
722
|
+
|
723
|
+
// add forward faces
|
724
|
+
numFaces = forward.size();
|
725
|
+
for (i = 0; i < numFaces; i++)
|
726
|
+
m_faces.push_back(forward[i]);
|
727
|
+
}
|
728
|
+
|
729
|
+
|
730
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
731
|
+
// SharesEdge()
|
732
|
+
//
|
733
|
+
// Returns true if the input face and the current strip share an edge
|
734
|
+
//
|
735
|
+
bool NvStripInfo::SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos)
|
736
|
+
{
|
737
|
+
//check v0->v1 edge
|
738
|
+
NvEdgeInfo* currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v0, faceInfo->m_v1);
|
739
|
+
|
740
|
+
if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1))
|
741
|
+
return true;
|
742
|
+
|
743
|
+
//check v1->v2 edge
|
744
|
+
currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v1, faceInfo->m_v2);
|
745
|
+
|
746
|
+
if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1))
|
747
|
+
return true;
|
748
|
+
|
749
|
+
//check v2->v0 edge
|
750
|
+
currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v2, faceInfo->m_v0);
|
751
|
+
|
752
|
+
if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1))
|
753
|
+
return true;
|
754
|
+
|
755
|
+
return false;
|
756
|
+
|
757
|
+
}
|
758
|
+
|
759
|
+
|
760
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
761
|
+
// CommitStrips()
|
762
|
+
//
|
763
|
+
// "Commits" the input strips by setting their m_experimentId to -1 and adding to the allStrips
|
764
|
+
// vector
|
765
|
+
//
|
766
|
+
void NvStripifier::CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips)
|
767
|
+
{
|
768
|
+
// Iterate through strips
|
769
|
+
int numStrips = strips.size();
|
770
|
+
for (int i = 0; i < numStrips; i++){
|
771
|
+
|
772
|
+
// Tell the strip that it is now real
|
773
|
+
NvStripInfo *strip = strips[i];
|
774
|
+
strip->m_experimentId = -1;
|
775
|
+
|
776
|
+
// add to the list of real strips
|
777
|
+
allStrips.push_back(strip);
|
778
|
+
|
779
|
+
// Iterate through the faces of the strip
|
780
|
+
// Tell the faces of the strip that they belong to a real strip now
|
781
|
+
const NvFaceInfoVec &faces = strips[i]->m_faces;
|
782
|
+
int numFaces = faces.size();
|
783
|
+
|
784
|
+
for (int j = 0; j < numFaces; j++)
|
785
|
+
{
|
786
|
+
strip->MarkTriangle(faces[j]);
|
787
|
+
}
|
788
|
+
}
|
789
|
+
}
|
790
|
+
|
791
|
+
|
792
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
793
|
+
// FindTraversal()
|
794
|
+
//
|
795
|
+
// Finds the next face to start the next strip on.
|
796
|
+
//
|
797
|
+
bool NvStripifier::FindTraversal(NvFaceInfoVec &faceInfos,
|
798
|
+
NvEdgeInfoVec &edgeInfos,
|
799
|
+
NvStripInfo *strip,
|
800
|
+
NvStripStartInfo &startInfo){
|
801
|
+
|
802
|
+
// if the strip was v0->v1 on the edge, then v1 will be a vertex in the next edge.
|
803
|
+
int v = (strip->m_startInfo.m_toV1 ? strip->m_startInfo.m_startEdge->m_v1 : strip->m_startInfo.m_startEdge->m_v0);
|
804
|
+
|
805
|
+
NvFaceInfo *untouchedFace = NULL;
|
806
|
+
NvEdgeInfo *edgeIter = edgeInfos[v];
|
807
|
+
while (edgeIter != NULL){
|
808
|
+
NvFaceInfo *face0 = edgeIter->m_face0;
|
809
|
+
NvFaceInfo *face1 = edgeIter->m_face1;
|
810
|
+
if ((face0 != NULL && !strip->IsInStrip(face0)) && face1 != NULL && !strip->IsMarked(face1))
|
811
|
+
{
|
812
|
+
untouchedFace = face1;
|
813
|
+
break;
|
814
|
+
}
|
815
|
+
if ((face1 != NULL && !strip->IsInStrip(face1)) && face0 != NULL && !strip->IsMarked(face0)){
|
816
|
+
untouchedFace = face0;
|
817
|
+
break;
|
818
|
+
}
|
819
|
+
|
820
|
+
// find the next edgeIter
|
821
|
+
edgeIter = (edgeIter->m_v0 == v ? edgeIter->m_nextV0 : edgeIter->m_nextV1);
|
822
|
+
}
|
823
|
+
|
824
|
+
startInfo.m_startFace = untouchedFace;
|
825
|
+
startInfo.m_startEdge = edgeIter;
|
826
|
+
if (edgeIter != NULL)
|
827
|
+
{
|
828
|
+
if(strip->SharesEdge(startInfo.m_startFace, edgeInfos))
|
829
|
+
startInfo.m_toV1 = (edgeIter->m_v0 == v); //note! used to be m_v1
|
830
|
+
else
|
831
|
+
startInfo.m_toV1 = (edgeIter->m_v1 == v);
|
832
|
+
}
|
833
|
+
return (startInfo.m_startFace != NULL);
|
834
|
+
}
|
835
|
+
|
836
|
+
|
837
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
838
|
+
// RemoveSmallStrips()
|
839
|
+
//
|
840
|
+
// allStrips is the whole strip vector...all small strips will be deleted from this list, to avoid leaking mem
|
841
|
+
// allBigStrips is an out parameter which will contain all strips above minStripLength
|
842
|
+
// faceList is an out parameter which will contain all faces which were removed from the striplist
|
843
|
+
//
|
844
|
+
void NvStripifier::RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList)
|
845
|
+
{
|
846
|
+
faceList.clear();
|
847
|
+
allBigStrips.clear(); //make sure these are empty
|
848
|
+
NvFaceInfoVec tempFaceList;
|
849
|
+
|
850
|
+
for(int i = 0; i < allStrips.size(); i++)
|
851
|
+
{
|
852
|
+
if(allStrips[i]->m_faces.size() < minStripLength)
|
853
|
+
{
|
854
|
+
//strip is too small, add faces to faceList
|
855
|
+
for(int j = 0; j < allStrips[i]->m_faces.size(); j++)
|
856
|
+
tempFaceList.push_back(allStrips[i]->m_faces[j]);
|
857
|
+
|
858
|
+
//and free memory
|
859
|
+
delete allStrips[i];
|
860
|
+
}
|
861
|
+
else
|
862
|
+
{
|
863
|
+
allBigStrips.push_back(allStrips[i]);
|
864
|
+
}
|
865
|
+
}
|
866
|
+
|
867
|
+
if(tempFaceList.size())
|
868
|
+
{
|
869
|
+
bool *bVisitedList = new bool[tempFaceList.size()];
|
870
|
+
memset(bVisitedList, 0, tempFaceList.size()*sizeof(bool));
|
871
|
+
|
872
|
+
VertexCache* vcache = new VertexCache(cacheSize);
|
873
|
+
|
874
|
+
int bestNumHits = -1;
|
875
|
+
int numHits;
|
876
|
+
int bestIndex;
|
877
|
+
|
878
|
+
while(1)
|
879
|
+
{
|
880
|
+
bestNumHits = -1;
|
881
|
+
|
882
|
+
//find best face to add next, given the current cache
|
883
|
+
for(int i = 0; i < tempFaceList.size(); i++)
|
884
|
+
{
|
885
|
+
if(bVisitedList[i])
|
886
|
+
continue;
|
887
|
+
|
888
|
+
numHits = CalcNumHitsFace(vcache, tempFaceList[i]);
|
889
|
+
if(numHits > bestNumHits)
|
890
|
+
{
|
891
|
+
bestNumHits = numHits;
|
892
|
+
bestIndex = i;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
|
896
|
+
if(bestNumHits == -1.0f)
|
897
|
+
break;
|
898
|
+
bVisitedList[bestIndex] = true;
|
899
|
+
UpdateCacheFace(vcache, tempFaceList[bestIndex]);
|
900
|
+
faceList.push_back(tempFaceList[bestIndex]);
|
901
|
+
}
|
902
|
+
|
903
|
+
delete vcache;
|
904
|
+
delete[] bVisitedList;
|
905
|
+
}
|
906
|
+
}
|
907
|
+
|
908
|
+
|
909
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
910
|
+
// NextIsCW()
|
911
|
+
//
|
912
|
+
// Returns true if the next face should be ordered in CW fashion
|
913
|
+
//
|
914
|
+
bool NvStripifier::NextIsCW(const int numIndices)
|
915
|
+
{
|
916
|
+
return ((numIndices % 2) == 0);
|
917
|
+
}
|
918
|
+
|
919
|
+
|
920
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
921
|
+
// IsCW()
|
922
|
+
//
|
923
|
+
// Returns true if the face is ordered in CW fashion
|
924
|
+
//
|
925
|
+
bool NvStripifier::IsCW(NvFaceInfo *faceInfo, int v0, int v1)
|
926
|
+
{
|
927
|
+
if (faceInfo->m_v0 == v0)
|
928
|
+
return (faceInfo->m_v1 == v1);
|
929
|
+
|
930
|
+
else if (faceInfo->m_v1 == v0)
|
931
|
+
return (faceInfo->m_v2 == v1);
|
932
|
+
|
933
|
+
else
|
934
|
+
return (faceInfo->m_v0 == v1);
|
935
|
+
|
936
|
+
// shouldn't get here
|
937
|
+
assert(0);
|
938
|
+
return false;
|
939
|
+
}
|
940
|
+
|
941
|
+
bool NvStripifier::FaceContainsIndex(const NvFaceInfo& face, const unsigned int index)
|
942
|
+
{
|
943
|
+
return ( (face.m_v0 == index) || (face.m_v1 == index) || (face.m_v2 == index) );
|
944
|
+
}
|
945
|
+
|
946
|
+
bool NvStripifier::IsMoneyFace(const NvFaceInfo& face)
|
947
|
+
{
|
948
|
+
if(FaceContainsIndex(face, 800) &&
|
949
|
+
FaceContainsIndex(face, 812) &&
|
950
|
+
FaceContainsIndex(face, 731))
|
951
|
+
return true;
|
952
|
+
|
953
|
+
return false;
|
954
|
+
}
|
955
|
+
|
956
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
957
|
+
// CreateStrips()
|
958
|
+
//
|
959
|
+
// Generates actual strips from the list-in-strip-order.
|
960
|
+
//
|
961
|
+
void NvStripifier::CreateStrips(const NvStripInfoVec& allStrips, IntVec& stripIndices,
|
962
|
+
const bool bStitchStrips, unsigned int& numSeparateStrips,
|
963
|
+
const bool bRestart, const unsigned int restartVal)
|
964
|
+
{
|
965
|
+
assert(numSeparateStrips == 0);
|
966
|
+
|
967
|
+
NvFaceInfo tLastFace(0, 0, 0);
|
968
|
+
NvFaceInfo tPrevStripLastFace(0, 0, 0);
|
969
|
+
int nStripCount = allStrips.size();
|
970
|
+
assert(nStripCount > 0);
|
971
|
+
|
972
|
+
//we infer the cw/ccw ordering depending on the number of indices
|
973
|
+
//this is screwed up by the fact that we insert -1s to denote changing strips
|
974
|
+
//this is to account for that
|
975
|
+
int accountForNegatives = 0;
|
976
|
+
|
977
|
+
for (int i = 0; i < nStripCount; i++)
|
978
|
+
{
|
979
|
+
NvStripInfo *strip = allStrips[i];
|
980
|
+
int nStripFaceCount = strip->m_faces.size();
|
981
|
+
assert(nStripFaceCount > 0);
|
982
|
+
|
983
|
+
// Handle the first face in the strip
|
984
|
+
{
|
985
|
+
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
|
986
|
+
|
987
|
+
// If there is a second face, reorder vertices such that the
|
988
|
+
// unique vertex is first
|
989
|
+
if (nStripFaceCount > 1)
|
990
|
+
{
|
991
|
+
int nUnique = NvStripifier::GetUniqueVertexInB(strip->m_faces[1], &tFirstFace);
|
992
|
+
if (nUnique == tFirstFace.m_v1)
|
993
|
+
{
|
994
|
+
SWAP(tFirstFace.m_v0, tFirstFace.m_v1);
|
995
|
+
}
|
996
|
+
else if (nUnique == tFirstFace.m_v2)
|
997
|
+
{
|
998
|
+
SWAP(tFirstFace.m_v0, tFirstFace.m_v2);
|
999
|
+
}
|
1000
|
+
|
1001
|
+
// If there is a third face, reorder vertices such that the
|
1002
|
+
// shared vertex is last
|
1003
|
+
if (nStripFaceCount > 2)
|
1004
|
+
{
|
1005
|
+
if(IsDegenerate(strip->m_faces[1]))
|
1006
|
+
{
|
1007
|
+
int pivot = strip->m_faces[1]->m_v1;
|
1008
|
+
if(tFirstFace.m_v1 == pivot)
|
1009
|
+
{
|
1010
|
+
SWAP(tFirstFace.m_v1, tFirstFace.m_v2);
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
else
|
1014
|
+
{
|
1015
|
+
int nShared0, nShared1;
|
1016
|
+
GetSharedVertices(strip->m_faces[2], &tFirstFace, &nShared0, &nShared1);
|
1017
|
+
if ( (nShared0 == tFirstFace.m_v1) && (nShared1 == -1) )
|
1018
|
+
{
|
1019
|
+
SWAP(tFirstFace.m_v1, tFirstFace.m_v2);
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
}
|
1023
|
+
}
|
1024
|
+
|
1025
|
+
if( (i == 0) || !bStitchStrips || bRestart)
|
1026
|
+
{
|
1027
|
+
if(!IsCW(strip->m_faces[0], tFirstFace.m_v0, tFirstFace.m_v1))
|
1028
|
+
stripIndices.push_back(tFirstFace.m_v0);
|
1029
|
+
}
|
1030
|
+
else
|
1031
|
+
{
|
1032
|
+
// Double tap the first in the new strip
|
1033
|
+
stripIndices.push_back(tFirstFace.m_v0);
|
1034
|
+
|
1035
|
+
// Check CW/CCW ordering
|
1036
|
+
if (NextIsCW(stripIndices.size() - accountForNegatives) != IsCW(strip->m_faces[0], tFirstFace.m_v0, tFirstFace.m_v1))
|
1037
|
+
{
|
1038
|
+
stripIndices.push_back(tFirstFace.m_v0);
|
1039
|
+
}
|
1040
|
+
}
|
1041
|
+
|
1042
|
+
stripIndices.push_back(tFirstFace.m_v0);
|
1043
|
+
stripIndices.push_back(tFirstFace.m_v1);
|
1044
|
+
stripIndices.push_back(tFirstFace.m_v2);
|
1045
|
+
|
1046
|
+
// Update last face info
|
1047
|
+
tLastFace = tFirstFace;
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
for (int j = 1; j < nStripFaceCount; j++)
|
1051
|
+
{
|
1052
|
+
int nUnique = GetUniqueVertexInB(&tLastFace, strip->m_faces[j]);
|
1053
|
+
if (nUnique != -1)
|
1054
|
+
{
|
1055
|
+
stripIndices.push_back(nUnique);
|
1056
|
+
|
1057
|
+
// Update last face info
|
1058
|
+
tLastFace.m_v0 = tLastFace.m_v1;
|
1059
|
+
tLastFace.m_v1 = tLastFace.m_v2;
|
1060
|
+
tLastFace.m_v2 = nUnique;
|
1061
|
+
}
|
1062
|
+
else
|
1063
|
+
{
|
1064
|
+
//we've hit a degenerate
|
1065
|
+
stripIndices.push_back(strip->m_faces[j]->m_v2);
|
1066
|
+
tLastFace.m_v0 = strip->m_faces[j]->m_v0;//tLastFace.m_v1;
|
1067
|
+
tLastFace.m_v1 = strip->m_faces[j]->m_v1;//tLastFace.m_v2;
|
1068
|
+
tLastFace.m_v2 = strip->m_faces[j]->m_v2;//tLastFace.m_v1;
|
1069
|
+
|
1070
|
+
}
|
1071
|
+
}
|
1072
|
+
|
1073
|
+
// Double tap between strips.
|
1074
|
+
if (bStitchStrips && !bRestart)
|
1075
|
+
{
|
1076
|
+
if (i != nStripCount - 1)
|
1077
|
+
stripIndices.push_back(tLastFace.m_v2);
|
1078
|
+
}
|
1079
|
+
else if (bRestart)
|
1080
|
+
{
|
1081
|
+
stripIndices.push_back(restartVal);
|
1082
|
+
}
|
1083
|
+
else
|
1084
|
+
{
|
1085
|
+
//-1 index indicates next strip
|
1086
|
+
stripIndices.push_back(-1);
|
1087
|
+
accountForNegatives++;
|
1088
|
+
numSeparateStrips++;
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
// Update last face info
|
1092
|
+
tLastFace.m_v0 = tLastFace.m_v1;
|
1093
|
+
tLastFace.m_v1 = tLastFace.m_v2;
|
1094
|
+
tLastFace.m_v2 = tLastFace.m_v2;
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
if(bStitchStrips || bRestart)
|
1098
|
+
numSeparateStrips = 1;
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
|
1102
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1103
|
+
// Stripify()
|
1104
|
+
//
|
1105
|
+
//
|
1106
|
+
// in_indices are the input indices of the mesh to stripify
|
1107
|
+
// in_cacheSize is the target cache size
|
1108
|
+
//
|
1109
|
+
void NvStripifier::Stripify(const WordVec &in_indices, const int in_cacheSize,
|
1110
|
+
const int in_minStripLength, const unsigned short maxIndex,
|
1111
|
+
NvStripInfoVec &outStrips, NvFaceInfoVec& outFaceList)
|
1112
|
+
{
|
1113
|
+
meshJump = 0.0f;
|
1114
|
+
bFirstTimeResetPoint = true; //used in FindGoodResetPoint()
|
1115
|
+
|
1116
|
+
//the number of times to run the experiments
|
1117
|
+
int numSamples = 10;
|
1118
|
+
int i;
|
1119
|
+
|
1120
|
+
#define max(a,b) ((a)>(b)?(a):(b))
|
1121
|
+
|
1122
|
+
//the cache size, clamped to one
|
1123
|
+
cacheSize = max(1, in_cacheSize - CACHE_INEFFICIENCY);
|
1124
|
+
|
1125
|
+
#undef max
|
1126
|
+
|
1127
|
+
minStripLength = in_minStripLength; //this is the strip size threshold below which we dump the strip into a list
|
1128
|
+
|
1129
|
+
indices = in_indices;
|
1130
|
+
|
1131
|
+
// build the stripification info
|
1132
|
+
NvFaceInfoVec allFaceInfos;
|
1133
|
+
NvEdgeInfoVec allEdgeInfos;
|
1134
|
+
|
1135
|
+
BuildStripifyInfo(allFaceInfos, allEdgeInfos, maxIndex);
|
1136
|
+
|
1137
|
+
NvStripInfoVec allStrips;
|
1138
|
+
|
1139
|
+
// stripify
|
1140
|
+
FindAllStrips(allStrips, allFaceInfos, allEdgeInfos, numSamples);
|
1141
|
+
|
1142
|
+
//split up the strips into cache friendly pieces, optimize them, then dump these into outStrips
|
1143
|
+
SplitUpStripsAndOptimize(allStrips, outStrips, allEdgeInfos, outFaceList);
|
1144
|
+
|
1145
|
+
//clean up
|
1146
|
+
for(i = 0; i < allStrips.size(); i++)
|
1147
|
+
{
|
1148
|
+
delete allStrips[i];
|
1149
|
+
}
|
1150
|
+
|
1151
|
+
for (i = 0; i < allEdgeInfos.size(); i++)
|
1152
|
+
{
|
1153
|
+
NvEdgeInfo *info = allEdgeInfos[i];
|
1154
|
+
while (info != NULL)
|
1155
|
+
{
|
1156
|
+
NvEdgeInfo *next = (info->m_v0 == i ? info->m_nextV0 : info->m_nextV1);
|
1157
|
+
info->Unref();
|
1158
|
+
info = next;
|
1159
|
+
}
|
1160
|
+
}
|
1161
|
+
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
|
1165
|
+
bool NvStripifier::IsDegenerate(const NvFaceInfo* face)
|
1166
|
+
{
|
1167
|
+
if(face->m_v0 == face->m_v1)
|
1168
|
+
return true;
|
1169
|
+
else if(face->m_v0 == face->m_v2)
|
1170
|
+
return true;
|
1171
|
+
else if(face->m_v1 == face->m_v2)
|
1172
|
+
return true;
|
1173
|
+
else
|
1174
|
+
return false;
|
1175
|
+
}
|
1176
|
+
|
1177
|
+
bool NvStripifier::IsDegenerate(const unsigned short v0, const unsigned short v1, const unsigned short v2)
|
1178
|
+
{
|
1179
|
+
if(v0 == v1)
|
1180
|
+
return true;
|
1181
|
+
else if(v0 == v2)
|
1182
|
+
return true;
|
1183
|
+
else if(v1 == v2)
|
1184
|
+
return true;
|
1185
|
+
else
|
1186
|
+
return false;
|
1187
|
+
}
|
1188
|
+
|
1189
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1190
|
+
// SplitUpStripsAndOptimize()
|
1191
|
+
//
|
1192
|
+
// Splits the input vector of strips (allBigStrips) into smaller, cache friendly pieces, then
|
1193
|
+
// reorders these pieces to maximize cache hits
|
1194
|
+
// The final strips are output through outStrips
|
1195
|
+
//
|
1196
|
+
void NvStripifier::SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips,
|
1197
|
+
NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList)
|
1198
|
+
{
|
1199
|
+
int threshold = cacheSize;
|
1200
|
+
NvStripInfoVec tempStrips;
|
1201
|
+
int i;
|
1202
|
+
int j;
|
1203
|
+
//split up strips into threshold-sized pieces
|
1204
|
+
for(i = 0; i < allStrips.size(); i++)
|
1205
|
+
{
|
1206
|
+
NvStripInfo* currentStrip;
|
1207
|
+
NvStripStartInfo startInfo(NULL, NULL, false);
|
1208
|
+
|
1209
|
+
int actualStripSize = 0;
|
1210
|
+
for(j = 0; j < allStrips[i]->m_faces.size(); ++j)
|
1211
|
+
{
|
1212
|
+
if( !IsDegenerate(allStrips[i]->m_faces[j]) )
|
1213
|
+
actualStripSize++;
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
if(actualStripSize /*allStrips[i]->m_faces.size()*/ > threshold)
|
1217
|
+
{
|
1218
|
+
|
1219
|
+
int numTimes = actualStripSize /*allStrips[i]->m_faces.size()*/ / threshold;
|
1220
|
+
int numLeftover = actualStripSize /*allStrips[i]->m_faces.size()*/ % threshold;
|
1221
|
+
|
1222
|
+
int degenerateCount = 0;
|
1223
|
+
for(j = 0; j < numTimes; j++)
|
1224
|
+
{
|
1225
|
+
currentStrip = new NvStripInfo(startInfo, 0, -1);
|
1226
|
+
|
1227
|
+
int faceCtr = j*threshold + degenerateCount;
|
1228
|
+
bool bFirstTime = true;
|
1229
|
+
while(faceCtr < threshold+(j*threshold)+degenerateCount)
|
1230
|
+
{
|
1231
|
+
if(IsDegenerate(allStrips[i]->m_faces[faceCtr]))
|
1232
|
+
{
|
1233
|
+
degenerateCount++;
|
1234
|
+
|
1235
|
+
//last time or first time through, no need for a degenerate
|
1236
|
+
if( (((faceCtr + 1) != threshold+(j*threshold)+degenerateCount) ||
|
1237
|
+
((j == numTimes - 1) && (numLeftover < 4) && (numLeftover > 0))) &&
|
1238
|
+
!bFirstTime)
|
1239
|
+
{
|
1240
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[faceCtr++]);
|
1241
|
+
}
|
1242
|
+
else
|
1243
|
+
{
|
1244
|
+
//but, we do need to delete the degenerate, if it's marked fake, to avoid leaking
|
1245
|
+
if(allStrips[i]->m_faces[faceCtr]->m_bIsFake)
|
1246
|
+
{
|
1247
|
+
delete allStrips[i]->m_faces[faceCtr], allStrips[i]->m_faces[faceCtr] = NULL;
|
1248
|
+
}
|
1249
|
+
++faceCtr;
|
1250
|
+
}
|
1251
|
+
}
|
1252
|
+
else
|
1253
|
+
{
|
1254
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[faceCtr++]);
|
1255
|
+
bFirstTime = false;
|
1256
|
+
}
|
1257
|
+
}
|
1258
|
+
/*
|
1259
|
+
for(int faceCtr = j*threshold; faceCtr < threshold+(j*threshold); faceCtr++)
|
1260
|
+
{
|
1261
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[faceCtr]);
|
1262
|
+
}
|
1263
|
+
*/
|
1264
|
+
if(j == numTimes - 1) //last time through
|
1265
|
+
{
|
1266
|
+
if( (numLeftover < 4) && (numLeftover > 0) ) //way too small
|
1267
|
+
{
|
1268
|
+
//just add to last strip
|
1269
|
+
int ctr = 0;
|
1270
|
+
while(ctr < numLeftover)
|
1271
|
+
{
|
1272
|
+
IsDegenerate( allStrips[i]->m_faces[faceCtr] ) ? ++degenerateCount : ++ctr;
|
1273
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[faceCtr++]);
|
1274
|
+
}
|
1275
|
+
numLeftover = 0;
|
1276
|
+
}
|
1277
|
+
}
|
1278
|
+
tempStrips.push_back(currentStrip);
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
int leftOff = j * threshold + degenerateCount;
|
1282
|
+
|
1283
|
+
if(numLeftover != 0)
|
1284
|
+
{
|
1285
|
+
currentStrip = new NvStripInfo(startInfo, 0, -1);
|
1286
|
+
|
1287
|
+
int ctr = 0;
|
1288
|
+
bool bFirstTime = true;
|
1289
|
+
while(ctr < numLeftover)
|
1290
|
+
{
|
1291
|
+
if( !IsDegenerate(allStrips[i]->m_faces[leftOff]) )
|
1292
|
+
{
|
1293
|
+
ctr++;
|
1294
|
+
bFirstTime = false;
|
1295
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[leftOff++]);
|
1296
|
+
}
|
1297
|
+
else if(!bFirstTime)
|
1298
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[leftOff++]);
|
1299
|
+
else
|
1300
|
+
{
|
1301
|
+
//don't leak
|
1302
|
+
if(allStrips[i]->m_faces[leftOff]->m_bIsFake)
|
1303
|
+
{
|
1304
|
+
delete allStrips[i]->m_faces[leftOff], allStrips[i]->m_faces[leftOff] = NULL;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
leftOff++;
|
1308
|
+
}
|
1309
|
+
}
|
1310
|
+
/*
|
1311
|
+
for(int k = 0; k < numLeftover; k++)
|
1312
|
+
{
|
1313
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[leftOff++]);
|
1314
|
+
}
|
1315
|
+
*/
|
1316
|
+
|
1317
|
+
tempStrips.push_back(currentStrip);
|
1318
|
+
}
|
1319
|
+
}
|
1320
|
+
else
|
1321
|
+
{
|
1322
|
+
//we're not just doing a tempStrips.push_back(allBigStrips[i]) because
|
1323
|
+
// this way we can delete allBigStrips later to free the memory
|
1324
|
+
currentStrip = new NvStripInfo(startInfo, 0, -1);
|
1325
|
+
|
1326
|
+
for(int j = 0; j < allStrips[i]->m_faces.size(); j++)
|
1327
|
+
currentStrip->m_faces.push_back(allStrips[i]->m_faces[j]);
|
1328
|
+
|
1329
|
+
tempStrips.push_back(currentStrip);
|
1330
|
+
}
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
//add small strips to face list
|
1334
|
+
NvStripInfoVec tempStrips2;
|
1335
|
+
RemoveSmallStrips(tempStrips, tempStrips2, outFaceList);
|
1336
|
+
|
1337
|
+
outStrips.clear();
|
1338
|
+
//screw optimization for now
|
1339
|
+
// for(i = 0; i < tempStrips.size(); ++i)
|
1340
|
+
// outStrips.push_back(tempStrips[i]);
|
1341
|
+
|
1342
|
+
if(tempStrips2.size() != 0)
|
1343
|
+
{
|
1344
|
+
//Optimize for the vertex cache
|
1345
|
+
VertexCache* vcache = new VertexCache(cacheSize);
|
1346
|
+
|
1347
|
+
float bestNumHits = -1.0f;
|
1348
|
+
float numHits;
|
1349
|
+
int bestIndex;
|
1350
|
+
bool done = false;
|
1351
|
+
|
1352
|
+
int firstIndex = 0;
|
1353
|
+
float minCost = 10000.0f;
|
1354
|
+
|
1355
|
+
for(i = 0; i < tempStrips2.size(); i++)
|
1356
|
+
{
|
1357
|
+
int numNeighbors = 0;
|
1358
|
+
|
1359
|
+
//find strip with least number of neighbors per face
|
1360
|
+
for(j = 0; j < tempStrips2[i]->m_faces.size(); j++)
|
1361
|
+
{
|
1362
|
+
numNeighbors += NumNeighbors(tempStrips2[i]->m_faces[j], edgeInfos);
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
float currCost = (float)numNeighbors / (float)tempStrips2[i]->m_faces.size();
|
1366
|
+
if(currCost < minCost)
|
1367
|
+
{
|
1368
|
+
minCost = currCost;
|
1369
|
+
firstIndex = i;
|
1370
|
+
}
|
1371
|
+
}
|
1372
|
+
|
1373
|
+
UpdateCacheStrip(vcache, tempStrips2[firstIndex]);
|
1374
|
+
outStrips.push_back(tempStrips2[firstIndex]);
|
1375
|
+
|
1376
|
+
tempStrips2[firstIndex]->visited = true;
|
1377
|
+
|
1378
|
+
bool bWantsCW = (tempStrips2[firstIndex]->m_faces.size() % 2) == 0;
|
1379
|
+
|
1380
|
+
//this n^2 algo is what slows down stripification so much....
|
1381
|
+
// needs to be improved
|
1382
|
+
while(1)
|
1383
|
+
{
|
1384
|
+
bestNumHits = -1.0f;
|
1385
|
+
|
1386
|
+
//find best strip to add next, given the current cache
|
1387
|
+
for(i = 0; i < tempStrips2.size(); i++)
|
1388
|
+
{
|
1389
|
+
if(tempStrips2[i]->visited)
|
1390
|
+
continue;
|
1391
|
+
|
1392
|
+
numHits = CalcNumHitsStrip(vcache, tempStrips2[i]);
|
1393
|
+
if(numHits > bestNumHits)
|
1394
|
+
{
|
1395
|
+
bestNumHits = numHits;
|
1396
|
+
bestIndex = i;
|
1397
|
+
}
|
1398
|
+
else if(numHits >= bestNumHits)
|
1399
|
+
{
|
1400
|
+
//check previous strip to see if this one requires it to switch polarity
|
1401
|
+
NvStripInfo *strip = tempStrips2[i];
|
1402
|
+
int nStripFaceCount = strip->m_faces.size();
|
1403
|
+
|
1404
|
+
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
|
1405
|
+
|
1406
|
+
// If there is a second face, reorder vertices such that the
|
1407
|
+
// unique vertex is first
|
1408
|
+
if (nStripFaceCount > 1)
|
1409
|
+
{
|
1410
|
+
int nUnique = NvStripifier::GetUniqueVertexInB(strip->m_faces[1], &tFirstFace);
|
1411
|
+
if (nUnique == tFirstFace.m_v1)
|
1412
|
+
{
|
1413
|
+
SWAP(tFirstFace.m_v0, tFirstFace.m_v1);
|
1414
|
+
}
|
1415
|
+
else if (nUnique == tFirstFace.m_v2)
|
1416
|
+
{
|
1417
|
+
SWAP(tFirstFace.m_v0, tFirstFace.m_v2);
|
1418
|
+
}
|
1419
|
+
|
1420
|
+
// If there is a third face, reorder vertices such that the
|
1421
|
+
// shared vertex is last
|
1422
|
+
if (nStripFaceCount > 2)
|
1423
|
+
{
|
1424
|
+
int nShared0, nShared1;
|
1425
|
+
GetSharedVertices(strip->m_faces[2], &tFirstFace, &nShared0, &nShared1);
|
1426
|
+
if ( (nShared0 == tFirstFace.m_v1) && (nShared1 == -1) )
|
1427
|
+
{
|
1428
|
+
SWAP(tFirstFace.m_v1, tFirstFace.m_v2);
|
1429
|
+
}
|
1430
|
+
}
|
1431
|
+
}
|
1432
|
+
|
1433
|
+
// Check CW/CCW ordering
|
1434
|
+
if (bWantsCW == IsCW(strip->m_faces[0], tFirstFace.m_v0, tFirstFace.m_v1))
|
1435
|
+
{
|
1436
|
+
//I like this one!
|
1437
|
+
bestIndex = i;
|
1438
|
+
}
|
1439
|
+
}
|
1440
|
+
}
|
1441
|
+
|
1442
|
+
if(bestNumHits == -1.0f)
|
1443
|
+
break;
|
1444
|
+
tempStrips2[bestIndex]->visited = true;
|
1445
|
+
UpdateCacheStrip(vcache, tempStrips2[bestIndex]);
|
1446
|
+
outStrips.push_back(tempStrips2[bestIndex]);
|
1447
|
+
bWantsCW = (tempStrips2[bestIndex]->m_faces.size() % 2 == 0) ? bWantsCW : !bWantsCW;
|
1448
|
+
}
|
1449
|
+
|
1450
|
+
delete vcache;
|
1451
|
+
}
|
1452
|
+
}
|
1453
|
+
|
1454
|
+
|
1455
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1456
|
+
// UpdateCacheStrip()
|
1457
|
+
//
|
1458
|
+
// Updates the input vertex cache with this strip's vertices
|
1459
|
+
//
|
1460
|
+
void NvStripifier::UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip)
|
1461
|
+
{
|
1462
|
+
for(int i = 0; i < strip->m_faces.size(); ++i)
|
1463
|
+
{
|
1464
|
+
if(!vcache->InCache(strip->m_faces[i]->m_v0))
|
1465
|
+
vcache->AddEntry(strip->m_faces[i]->m_v0);
|
1466
|
+
|
1467
|
+
if(!vcache->InCache(strip->m_faces[i]->m_v1))
|
1468
|
+
vcache->AddEntry(strip->m_faces[i]->m_v1);
|
1469
|
+
|
1470
|
+
if(!vcache->InCache(strip->m_faces[i]->m_v2))
|
1471
|
+
vcache->AddEntry(strip->m_faces[i]->m_v2);
|
1472
|
+
}
|
1473
|
+
}
|
1474
|
+
|
1475
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1476
|
+
// UpdateCacheFace()
|
1477
|
+
//
|
1478
|
+
// Updates the input vertex cache with this face's vertices
|
1479
|
+
//
|
1480
|
+
void NvStripifier::UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face)
|
1481
|
+
{
|
1482
|
+
if(!vcache->InCache(face->m_v0))
|
1483
|
+
vcache->AddEntry(face->m_v0);
|
1484
|
+
|
1485
|
+
if(!vcache->InCache(face->m_v1))
|
1486
|
+
vcache->AddEntry(face->m_v1);
|
1487
|
+
|
1488
|
+
if(!vcache->InCache(face->m_v2))
|
1489
|
+
vcache->AddEntry(face->m_v2);
|
1490
|
+
}
|
1491
|
+
|
1492
|
+
|
1493
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1494
|
+
// CalcNumHitsStrip()
|
1495
|
+
//
|
1496
|
+
// returns the number of cache hits per face in the strip
|
1497
|
+
//
|
1498
|
+
float NvStripifier::CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip)
|
1499
|
+
{
|
1500
|
+
int numHits = 0;
|
1501
|
+
int numFaces = 0;
|
1502
|
+
|
1503
|
+
for(int i = 0; i < strip->m_faces.size(); i++)
|
1504
|
+
{
|
1505
|
+
if(vcache->InCache(strip->m_faces[i]->m_v0))
|
1506
|
+
++numHits;
|
1507
|
+
|
1508
|
+
if(vcache->InCache(strip->m_faces[i]->m_v1))
|
1509
|
+
++numHits;
|
1510
|
+
|
1511
|
+
if(vcache->InCache(strip->m_faces[i]->m_v2))
|
1512
|
+
++numHits;
|
1513
|
+
|
1514
|
+
numFaces++;
|
1515
|
+
}
|
1516
|
+
|
1517
|
+
return ((float)numHits / (float)numFaces);
|
1518
|
+
}
|
1519
|
+
|
1520
|
+
|
1521
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1522
|
+
// CalcNumHitsFace()
|
1523
|
+
//
|
1524
|
+
// returns the number of cache hits in the face
|
1525
|
+
//
|
1526
|
+
int NvStripifier::CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face)
|
1527
|
+
{
|
1528
|
+
int numHits = 0;
|
1529
|
+
|
1530
|
+
if(vcache->InCache(face->m_v0))
|
1531
|
+
numHits++;
|
1532
|
+
|
1533
|
+
if(vcache->InCache(face->m_v1))
|
1534
|
+
numHits++;
|
1535
|
+
|
1536
|
+
if(vcache->InCache(face->m_v2))
|
1537
|
+
numHits++;
|
1538
|
+
|
1539
|
+
return numHits;
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
|
1543
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1544
|
+
// NumNeighbors()
|
1545
|
+
//
|
1546
|
+
// Returns the number of neighbors that this face has
|
1547
|
+
//
|
1548
|
+
int NvStripifier::NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec)
|
1549
|
+
{
|
1550
|
+
int numNeighbors = 0;
|
1551
|
+
|
1552
|
+
if(FindOtherFace(edgeInfoVec, face->m_v0, face->m_v1, face) != NULL)
|
1553
|
+
{
|
1554
|
+
numNeighbors++;
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
if(FindOtherFace(edgeInfoVec, face->m_v1, face->m_v2, face) != NULL)
|
1558
|
+
{
|
1559
|
+
numNeighbors++;
|
1560
|
+
}
|
1561
|
+
|
1562
|
+
if(FindOtherFace(edgeInfoVec, face->m_v2, face->m_v0, face) != NULL)
|
1563
|
+
{
|
1564
|
+
numNeighbors++;
|
1565
|
+
}
|
1566
|
+
|
1567
|
+
return numNeighbors;
|
1568
|
+
}
|
1569
|
+
|
1570
|
+
|
1571
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1572
|
+
// AvgStripSize()
|
1573
|
+
//
|
1574
|
+
// Finds the average strip size of the input vector of strips
|
1575
|
+
//
|
1576
|
+
float NvStripifier::AvgStripSize(const NvStripInfoVec &strips){
|
1577
|
+
int sizeAccum = 0;
|
1578
|
+
int numStrips = strips.size();
|
1579
|
+
for (int i = 0; i < numStrips; i++){
|
1580
|
+
NvStripInfo *strip = strips[i];
|
1581
|
+
sizeAccum += strip->m_faces.size();
|
1582
|
+
sizeAccum -= strip->m_numDegenerates;
|
1583
|
+
}
|
1584
|
+
return ((float)sizeAccum) / ((float)numStrips);
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
|
1588
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1589
|
+
// FindAllStrips()
|
1590
|
+
//
|
1591
|
+
// Does the stripification, puts output strips into vector allStrips
|
1592
|
+
//
|
1593
|
+
// Works by setting runnning a number of experiments in different areas of the mesh, and
|
1594
|
+
// accepting the one which results in the longest strips. It then accepts this, and moves
|
1595
|
+
// on to a different area of the mesh. We try to jump around the mesh some, to ensure that
|
1596
|
+
// large open spans of strips get generated.
|
1597
|
+
//
|
1598
|
+
void NvStripifier::FindAllStrips(NvStripInfoVec &allStrips,
|
1599
|
+
NvFaceInfoVec &allFaceInfos,
|
1600
|
+
NvEdgeInfoVec &allEdgeInfos,
|
1601
|
+
int numSamples){
|
1602
|
+
// the experiments
|
1603
|
+
int experimentId = 0;
|
1604
|
+
int stripId = 0;
|
1605
|
+
bool done = false;
|
1606
|
+
|
1607
|
+
int loopCtr = 0;
|
1608
|
+
|
1609
|
+
while (!done)
|
1610
|
+
{
|
1611
|
+
loopCtr++;
|
1612
|
+
|
1613
|
+
//
|
1614
|
+
// PHASE 1: Set up numSamples * numEdges experiments
|
1615
|
+
//
|
1616
|
+
NvStripInfoVec *experiments = new NvStripInfoVec [numSamples * 6];
|
1617
|
+
int experimentIndex = 0;
|
1618
|
+
std::set <NvFaceInfo*> resetPoints;
|
1619
|
+
int i;
|
1620
|
+
for (i = 0; i < numSamples; i++)
|
1621
|
+
{
|
1622
|
+
|
1623
|
+
// Try to find another good reset point.
|
1624
|
+
// If there are none to be found, we are done
|
1625
|
+
NvFaceInfo *nextFace = FindGoodResetPoint(allFaceInfos, allEdgeInfos);
|
1626
|
+
if (nextFace == NULL){
|
1627
|
+
done = true;
|
1628
|
+
break;
|
1629
|
+
}
|
1630
|
+
// If we have already evaluated starting at this face in this slew
|
1631
|
+
// of experiments, then skip going any further
|
1632
|
+
else if (resetPoints.find(nextFace) != resetPoints.end()){
|
1633
|
+
continue;
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
// trying it now...
|
1637
|
+
resetPoints.insert(nextFace);
|
1638
|
+
|
1639
|
+
// otherwise, we shall now try experiments for starting on the 01,12, and 20 edges
|
1640
|
+
assert(nextFace->m_stripId < 0);
|
1641
|
+
|
1642
|
+
// build the strip off of this face's 0-1 edge
|
1643
|
+
NvEdgeInfo *edge01 = FindEdgeInfo(allEdgeInfos, nextFace->m_v0, nextFace->m_v1);
|
1644
|
+
NvStripInfo *strip01 = new NvStripInfo(NvStripStartInfo(nextFace, edge01, true), stripId++, experimentId++);
|
1645
|
+
experiments[experimentIndex++].push_back(strip01);
|
1646
|
+
|
1647
|
+
// build the strip off of this face's 1-0 edge
|
1648
|
+
NvEdgeInfo *edge10 = FindEdgeInfo(allEdgeInfos, nextFace->m_v0, nextFace->m_v1);
|
1649
|
+
NvStripInfo *strip10 = new NvStripInfo(NvStripStartInfo(nextFace, edge10, false), stripId++, experimentId++);
|
1650
|
+
experiments[experimentIndex++].push_back(strip10);
|
1651
|
+
|
1652
|
+
// build the strip off of this face's 1-2 edge
|
1653
|
+
NvEdgeInfo *edge12 = FindEdgeInfo(allEdgeInfos, nextFace->m_v1, nextFace->m_v2);
|
1654
|
+
NvStripInfo *strip12 = new NvStripInfo(NvStripStartInfo(nextFace, edge12, true), stripId++, experimentId++);
|
1655
|
+
experiments[experimentIndex++].push_back(strip12);
|
1656
|
+
|
1657
|
+
// build the strip off of this face's 2-1 edge
|
1658
|
+
NvEdgeInfo *edge21 = FindEdgeInfo(allEdgeInfos, nextFace->m_v1, nextFace->m_v2);
|
1659
|
+
NvStripInfo *strip21 = new NvStripInfo(NvStripStartInfo(nextFace, edge21, false), stripId++, experimentId++);
|
1660
|
+
experiments[experimentIndex++].push_back(strip21);
|
1661
|
+
|
1662
|
+
// build the strip off of this face's 2-0 edge
|
1663
|
+
NvEdgeInfo *edge20 = FindEdgeInfo(allEdgeInfos, nextFace->m_v2, nextFace->m_v0);
|
1664
|
+
NvStripInfo *strip20 = new NvStripInfo(NvStripStartInfo(nextFace, edge20, true), stripId++, experimentId++);
|
1665
|
+
experiments[experimentIndex++].push_back(strip20);
|
1666
|
+
|
1667
|
+
// build the strip off of this face's 0-2 edge
|
1668
|
+
NvEdgeInfo *edge02 = FindEdgeInfo(allEdgeInfos, nextFace->m_v2, nextFace->m_v0);
|
1669
|
+
NvStripInfo *strip02 = new NvStripInfo(NvStripStartInfo(nextFace, edge02, false), stripId++, experimentId++);
|
1670
|
+
experiments[experimentIndex++].push_back(strip02);
|
1671
|
+
}
|
1672
|
+
|
1673
|
+
//
|
1674
|
+
// PHASE 2: Iterate through that we setup in the last phase
|
1675
|
+
// and really build each of the strips and strips that follow to see how
|
1676
|
+
// far we get
|
1677
|
+
//
|
1678
|
+
int numExperiments = experimentIndex;
|
1679
|
+
for (i = 0; i < numExperiments; i++){
|
1680
|
+
|
1681
|
+
// get the strip set
|
1682
|
+
|
1683
|
+
// build the first strip of the list
|
1684
|
+
experiments[i][0]->Build(allEdgeInfos, allFaceInfos);
|
1685
|
+
int experimentId = experiments[i][0]->m_experimentId;
|
1686
|
+
|
1687
|
+
NvStripInfo *stripIter = experiments[i][0];
|
1688
|
+
NvStripStartInfo startInfo(NULL, NULL, false);
|
1689
|
+
while (FindTraversal(allFaceInfos, allEdgeInfos, stripIter, startInfo)){
|
1690
|
+
|
1691
|
+
// create the new strip info
|
1692
|
+
stripIter = new NvStripInfo(startInfo, stripId++, experimentId);
|
1693
|
+
|
1694
|
+
// build the next strip
|
1695
|
+
stripIter->Build(allEdgeInfos, allFaceInfos);
|
1696
|
+
|
1697
|
+
// add it to the list
|
1698
|
+
experiments[i].push_back(stripIter);
|
1699
|
+
}
|
1700
|
+
}
|
1701
|
+
|
1702
|
+
//
|
1703
|
+
// Phase 3: Find the experiment that has the most promise
|
1704
|
+
//
|
1705
|
+
int bestIndex = 0;
|
1706
|
+
double bestValue = 0;
|
1707
|
+
for (i = 0; i < numExperiments; i++)
|
1708
|
+
{
|
1709
|
+
const float avgStripSizeWeight = 1.0f;
|
1710
|
+
const float numTrisWeight = 0.0f;
|
1711
|
+
const float numStripsWeight = 0.0f;
|
1712
|
+
float avgStripSize = AvgStripSize(experiments[i]);
|
1713
|
+
float numStrips = (float) experiments[i].size();
|
1714
|
+
float value = avgStripSize * avgStripSizeWeight + (numStrips * numStripsWeight);
|
1715
|
+
//float value = 1.f / numStrips;
|
1716
|
+
//float value = numStrips * avgStripSize;
|
1717
|
+
|
1718
|
+
if (value > bestValue)
|
1719
|
+
{
|
1720
|
+
bestValue = value;
|
1721
|
+
bestIndex = i;
|
1722
|
+
}
|
1723
|
+
}
|
1724
|
+
|
1725
|
+
//
|
1726
|
+
// Phase 4: commit the best experiment of the bunch
|
1727
|
+
//
|
1728
|
+
CommitStrips(allStrips, experiments[bestIndex]);
|
1729
|
+
|
1730
|
+
// and destroy all of the others
|
1731
|
+
for (i = 0; i < numExperiments; i++)
|
1732
|
+
{
|
1733
|
+
if (i != bestIndex)
|
1734
|
+
{
|
1735
|
+
int numStrips = experiments[i].size();
|
1736
|
+
for (int j = 0; j < numStrips; j++)
|
1737
|
+
{
|
1738
|
+
NvStripInfo* currStrip = experiments[i][j];
|
1739
|
+
//delete all bogus faces in the experiments
|
1740
|
+
for (int k = 0; k < currStrip->m_faces.size(); ++k)
|
1741
|
+
{
|
1742
|
+
if(currStrip->m_faces[k]->m_bIsFake)
|
1743
|
+
{
|
1744
|
+
delete currStrip->m_faces[k], currStrip->m_faces[k] = NULL;
|
1745
|
+
}
|
1746
|
+
}
|
1747
|
+
delete currStrip, currStrip = NULL, experiments[i][j] = NULL;
|
1748
|
+
}
|
1749
|
+
}
|
1750
|
+
}
|
1751
|
+
|
1752
|
+
// delete the array that we used for all experiments
|
1753
|
+
delete [] experiments;
|
1754
|
+
}
|
1755
|
+
}
|
1756
|
+
|
1757
|
+
|
1758
|
+
///////////////////////////////////////////////////////////////////////////////////////////
|
1759
|
+
// CountRemainingTris()
|
1760
|
+
//
|
1761
|
+
// This will count the number of triangles left in the
|
1762
|
+
// strip list starting at iter and finishing up at end
|
1763
|
+
//
|
1764
|
+
int NvStripifier::CountRemainingTris(std::list<NvStripInfo*>::iterator iter,
|
1765
|
+
std::list<NvStripInfo*>::iterator end){
|
1766
|
+
int count = 0;
|
1767
|
+
while (iter != end){
|
1768
|
+
count += (*iter)->m_faces.size();
|
1769
|
+
iter++;
|
1770
|
+
}
|
1771
|
+
return count;
|
1772
|
+
}
|
1773
|
+
|