nvtristrip-ruby 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/README
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
= NvTriStrip: Triangle stripification library
|
4
|
+
|
5
|
+
NvTriStrip provides a Ruby interface for Nvidia's Triangle stripification
|
6
|
+
library.
|
7
|
+
|
8
|
+
Original NvTriStrip is available from http://developer.nvidia.com ,
|
9
|
+
I've slightly modified the lib to fix compiling on various platforms.
|
10
|
+
|
11
|
+
== Features
|
12
|
+
|
13
|
+
All features and shortcomings of Nvidia's library are (hopefully) preserved.
|
14
|
+
|
15
|
+
Namely, features
|
16
|
+
* Makes trianglestrips out of triangle lists
|
17
|
+
* Optimizes trianglestrips for good cache use
|
18
|
+
* Optionally stitches separate strips with degenerates
|
19
|
+
* Can throw small strips into a list instead
|
20
|
+
* Remaps indices to improve spatial locality in your vertex buffer
|
21
|
+
|
22
|
+
Some shortcomings
|
23
|
+
* Limited geometry to 65k vertices (But that also has some practical value)
|
24
|
+
* Uses global state to control some options (but should be otherwise reentrant)
|
25
|
+
* Ruby version has to do some back and forth copying of the indices
|
26
|
+
|
27
|
+
== Installation
|
28
|
+
|
29
|
+
With rubygems:
|
30
|
+
gem install nvtristrip-ruby
|
31
|
+
|
32
|
+
Otherwise:
|
33
|
+
ruby setup.rb
|
34
|
+
|
35
|
+
== Usage
|
36
|
+
|
37
|
+
require 'nvtristrip'
|
38
|
+
|
39
|
+
my_triangle_indices=[0,1,2,1,2,3] # Two triangles
|
40
|
+
validate=true
|
41
|
+
|
42
|
+
stripified_indices=NvTriStrip::generate_strips my_triangle_indices, validate
|
43
|
+
|
44
|
+
# And now stripifiedIndices is an Array of NvTriStrip::PrimitiveGroup objects, which are Enumerable.
|
45
|
+
|
46
|
+
remapped_indices=NvTriStrip::remap_indices stripified_indices, 3
|
47
|
+
|
48
|
+
# And now remappedIndices is an array of PrimitiveGroups objects with indices
|
49
|
+
# remapped for better spatial locality. With this information you should remap your vertex buffer.
|
50
|
+
|
data/README.nvtristrip
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
README for NvTriStrip, library version
|
2
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
|
4
|
+
To use:
|
5
|
+
-#include "NvTriStrip.h"
|
6
|
+
-put nvtristrip.lib in your library path (the pragma in nvtristrip.h will automatically look for the library).
|
7
|
+
|
8
|
+
Check out NvTriStrip.h for the interface.
|
9
|
+
|
10
|
+
See the StripTest source code (in function LoadXFileStripped) for an example of using the library.
|
11
|
+
|
12
|
+
Features:
|
13
|
+
-generates strips from arbitrary geometry.
|
14
|
+
-flexibly optimizes for post TnL vertex caches (16 on GeForce1/2, 24 on GeForce3).
|
15
|
+
-can stitch together strips using degenerate triangles, or not.
|
16
|
+
-can output lists instead of strips.
|
17
|
+
-can optionally throw excessively small strips into a list instead.
|
18
|
+
-can remap indices to improve spatial locality in your vertex buffers.
|
19
|
+
|
20
|
+
On cache sizes:
|
21
|
+
Note that it's better to UNDERESTIMATE the cache size instead of OVERESTIMATING.
|
22
|
+
So, if you're targetting GeForce1, 2, and 3, be conservative and use the GeForce1_2 cache
|
23
|
+
size, NOT the GeForce3 cache size.
|
24
|
+
This will make sure you don't "blow" the cache of the GeForce1 and 2.
|
25
|
+
Also note that the cache size you specify is the "actual" cache size, not the "effective"
|
26
|
+
cache size you may have heard about. This is 16 for GeForce1 and 2, and 24 for GeForce3.
|
27
|
+
|
28
|
+
Credit goes to Curtis Beeson and Joe Demers for the basis for this stripifier and to Jason Regier and
|
29
|
+
Jon Stone at Blizzard for providing a much cleaner version of CreateStrips().
|
30
|
+
|
31
|
+
Questions/comments email cem@nvidia.com
|
32
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
|
9
|
+
PKG_VERSION="0.5.0"
|
10
|
+
|
11
|
+
file "ext/Makefile" => [ "ext/extconf.rb"] do
|
12
|
+
Dir.chdir "ext" do
|
13
|
+
ruby "extconf.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
EXT_SO="ext/nvtristrip.#{Config::CONFIG['DLEXT']}"
|
18
|
+
|
19
|
+
file EXT_SO => FileList[
|
20
|
+
"ext/*.cpp",
|
21
|
+
"ext/*.h",
|
22
|
+
"ext/Makefile",
|
23
|
+
] do
|
24
|
+
|
25
|
+
Dir.chdir "ext" do
|
26
|
+
sh "make"
|
27
|
+
end
|
28
|
+
cp EXT_SO, "lib"
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
task :default => :build
|
33
|
+
|
34
|
+
desc "Build the extension"
|
35
|
+
task :build => [EXT_SO]
|
36
|
+
|
37
|
+
|
38
|
+
spec=Gem::Specification.new do |s|
|
39
|
+
s.name="nvtristrip-ruby"
|
40
|
+
s.author="Mikko Lehtonen"
|
41
|
+
s.version=PKG_VERSION
|
42
|
+
s.summary="Interface for NvTriStrip triangle stripification library."
|
43
|
+
s.platform=Gem::Platform::RUBY
|
44
|
+
s.has_rdoc=true
|
45
|
+
s.extra_rdoc_files = ["README","TODO","ext/RbTriStrip.cpp"]
|
46
|
+
s.files=Dir.glob("{test,lib}/**/*")+
|
47
|
+
Dir.glob("ext/**/*.{cpp,h,rb}")+
|
48
|
+
["Rakefile","setup.rb","README.nvtristrip", "README"]
|
49
|
+
|
50
|
+
s.require_path="lib"
|
51
|
+
s.test_files=Dir.glob("test/test_*.rb")
|
52
|
+
s.extensions=FileList["ext/extconf.rb"].to_a
|
53
|
+
s.homepage="http://nvtristrip.rubyforge.org"
|
54
|
+
s.rubyforge_project="nvtristrip"
|
55
|
+
end
|
56
|
+
|
57
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
Rake::TestTask.new do |t|
|
63
|
+
t.libs << "test"
|
64
|
+
t.test_files=FileList['test/test*.rb']
|
65
|
+
t.verbose=true
|
66
|
+
end
|
67
|
+
|
68
|
+
Rake::RDocTask.new do |r|
|
69
|
+
r.rdoc_dir='doc/rdoc'
|
70
|
+
# r.options
|
71
|
+
r.rdoc_files.add ['README','TODO', 'ext/RbTriStrip.cpp']
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
CLEAN.include ['**/*.o', '**/*.log', "lib/"+File.basename(EXT_SO), EXT_SO]
|
76
|
+
|
data/TODO
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
|
2
|
+
* Improve test-suite
|
3
|
+
* Convenience function for remapping vertexbuffers?
|
4
|
+
* Maybe try to modify nvtristrip lib to use the ruby arrays directly, so I wouldn't have to
|
5
|
+
copy the indices back and forth.
|
6
|
+
* Clean up some of the code and improve documentation
|
7
|
+
* Win32 precompiled gem
|
data/ext/NvTriStrip.cpp
ADDED
@@ -0,0 +1,501 @@
|
|
1
|
+
|
2
|
+
#include "NvTriStripObjects.h"
|
3
|
+
#include "NvTriStrip.h"
|
4
|
+
|
5
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
6
|
+
//private data
|
7
|
+
static unsigned int cacheSize = CACHESIZE_GEFORCE1_2;
|
8
|
+
static bool bStitchStrips = true;
|
9
|
+
static unsigned int minStripSize = 0;
|
10
|
+
static bool bListsOnly = false;
|
11
|
+
static unsigned int restartVal = 0;
|
12
|
+
static bool bRestart = false;
|
13
|
+
|
14
|
+
void EnableRestart(const unsigned int _restartVal)
|
15
|
+
{
|
16
|
+
bRestart = true;
|
17
|
+
restartVal = _restartVal;
|
18
|
+
}
|
19
|
+
|
20
|
+
void DisableRestart()
|
21
|
+
{
|
22
|
+
bRestart = false;
|
23
|
+
}
|
24
|
+
|
25
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
26
|
+
// SetListsOnly()
|
27
|
+
//
|
28
|
+
// If set to true, will return an optimized list, with no strips at all.
|
29
|
+
//
|
30
|
+
// Default value: false
|
31
|
+
//
|
32
|
+
void SetListsOnly(const bool _bListsOnly)
|
33
|
+
{
|
34
|
+
bListsOnly = _bListsOnly;
|
35
|
+
}
|
36
|
+
|
37
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
38
|
+
// SetCacheSize()
|
39
|
+
//
|
40
|
+
// Sets the cache size which the stripfier uses to optimize the data.
|
41
|
+
// Controls the length of the generated individual strips.
|
42
|
+
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
43
|
+
// You may want to play around with this number to tweak performance.
|
44
|
+
//
|
45
|
+
// Default value: 16
|
46
|
+
//
|
47
|
+
void SetCacheSize(const unsigned int _cacheSize)
|
48
|
+
{
|
49
|
+
cacheSize = _cacheSize;
|
50
|
+
}
|
51
|
+
|
52
|
+
|
53
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
54
|
+
// SetStitchStrips()
|
55
|
+
//
|
56
|
+
// bool to indicate whether to stitch together strips into one huge strip or not.
|
57
|
+
// If set to true, you'll get back one huge strip stitched together using degenerate
|
58
|
+
// triangles.
|
59
|
+
// If set to false, you'll get back a large number of separate strips.
|
60
|
+
//
|
61
|
+
// Default value: true
|
62
|
+
//
|
63
|
+
void SetStitchStrips(const bool _bStitchStrips)
|
64
|
+
{
|
65
|
+
bStitchStrips = _bStitchStrips;
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
70
|
+
// SetMinStripSize()
|
71
|
+
//
|
72
|
+
// Sets the minimum acceptable size for a strip, in triangles.
|
73
|
+
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
74
|
+
//
|
75
|
+
// Default value: 0
|
76
|
+
//
|
77
|
+
void SetMinStripSize(const unsigned int _minStripSize)
|
78
|
+
{
|
79
|
+
minStripSize = _minStripSize;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
84
|
+
//Cleanup strips / faces, used by generatestrips
|
85
|
+
void Cleanup(NvStripInfoVec& tempStrips, NvFaceInfoVec& tempFaces)
|
86
|
+
{
|
87
|
+
//delete strips
|
88
|
+
int i;
|
89
|
+
for(i = 0; i < tempStrips.size(); i++)
|
90
|
+
{
|
91
|
+
for(int j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
92
|
+
{
|
93
|
+
delete tempStrips[i]->m_faces[j];
|
94
|
+
tempStrips[i]->m_faces[j] = NULL;
|
95
|
+
}
|
96
|
+
tempStrips[i]->m_faces.resize(0);
|
97
|
+
delete tempStrips[i];
|
98
|
+
tempStrips[i] = NULL;
|
99
|
+
}
|
100
|
+
|
101
|
+
//delete faces
|
102
|
+
for(i = 0; i < tempFaces.size(); i++)
|
103
|
+
{
|
104
|
+
delete tempFaces[i];
|
105
|
+
tempFaces[i] = NULL;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
111
|
+
//SameTriangle()
|
112
|
+
//
|
113
|
+
//Returns true if the two triangles defined by firstTri and secondTri are the same
|
114
|
+
// The "same" is defined in this case as having the same indices with the same winding order
|
115
|
+
//
|
116
|
+
bool SameTriangle(unsigned short firstTri0, unsigned short firstTri1, unsigned short firstTri2,
|
117
|
+
unsigned short secondTri0, unsigned short secondTri1, unsigned short secondTri2)
|
118
|
+
{
|
119
|
+
bool isSame = false;
|
120
|
+
|
121
|
+
if (firstTri0 == secondTri0)
|
122
|
+
{
|
123
|
+
if (firstTri1 == secondTri1)
|
124
|
+
{
|
125
|
+
if (firstTri2 == secondTri2)
|
126
|
+
isSame = true;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
else if (firstTri0 == secondTri1)
|
130
|
+
{
|
131
|
+
if (firstTri1 == secondTri2)
|
132
|
+
{
|
133
|
+
if (firstTri2 == secondTri0)
|
134
|
+
isSame = true;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
else if (firstTri0 == secondTri2)
|
138
|
+
{
|
139
|
+
if (firstTri1 == secondTri0)
|
140
|
+
{
|
141
|
+
if (firstTri2 == secondTri1)
|
142
|
+
isSame = true;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
return isSame;
|
147
|
+
}
|
148
|
+
|
149
|
+
|
150
|
+
bool TestTriangle(const unsigned short v0, const unsigned short v1, const unsigned short v2, const std::vector<NvFaceInfo>* in_bins, const int NUMBINS)
|
151
|
+
{
|
152
|
+
//hash this triangle
|
153
|
+
bool isLegit = false;
|
154
|
+
int ctr = v0 % NUMBINS;
|
155
|
+
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
156
|
+
{
|
157
|
+
//check triangles in this bin
|
158
|
+
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
159
|
+
v0, v1, v2))
|
160
|
+
{
|
161
|
+
isLegit = true;
|
162
|
+
break;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
if (!isLegit)
|
166
|
+
{
|
167
|
+
ctr = v1 % NUMBINS;
|
168
|
+
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
169
|
+
{
|
170
|
+
//check triangles in this bin
|
171
|
+
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
172
|
+
v0, v1, v2))
|
173
|
+
{
|
174
|
+
isLegit = true;
|
175
|
+
break;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
if (!isLegit)
|
180
|
+
{
|
181
|
+
ctr = v2 % NUMBINS;
|
182
|
+
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
183
|
+
{
|
184
|
+
//check triangles in this bin
|
185
|
+
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
186
|
+
v0, v1, v2))
|
187
|
+
{
|
188
|
+
isLegit = true;
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
return isLegit;
|
197
|
+
}
|
198
|
+
|
199
|
+
|
200
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
201
|
+
// GenerateStrips()
|
202
|
+
//
|
203
|
+
// in_indices: input index list, the indices you would use to render
|
204
|
+
// in_numIndices: number of entries in in_indices
|
205
|
+
// primGroups: array of optimized/stripified PrimitiveGroups
|
206
|
+
// numGroups: number of groups returned
|
207
|
+
//
|
208
|
+
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
209
|
+
//
|
210
|
+
bool GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
211
|
+
PrimitiveGroup** primGroups, unsigned short* numGroups, bool validateEnabled)
|
212
|
+
{
|
213
|
+
//put data in format that the stripifier likes
|
214
|
+
WordVec tempIndices;
|
215
|
+
tempIndices.resize(in_numIndices);
|
216
|
+
unsigned short maxIndex = 0;
|
217
|
+
unsigned short minIndex = 0xFFFF;
|
218
|
+
for(int i = 0; i < in_numIndices; i++)
|
219
|
+
{
|
220
|
+
tempIndices[i] = in_indices[i];
|
221
|
+
if (in_indices[i] > maxIndex)
|
222
|
+
maxIndex = in_indices[i];
|
223
|
+
if (in_indices[i] < minIndex)
|
224
|
+
minIndex = in_indices[i];
|
225
|
+
}
|
226
|
+
NvStripInfoVec tempStrips;
|
227
|
+
NvFaceInfoVec tempFaces;
|
228
|
+
|
229
|
+
NvStripifier stripifier;
|
230
|
+
|
231
|
+
//do actual stripification
|
232
|
+
stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces);
|
233
|
+
|
234
|
+
//stitch strips together
|
235
|
+
IntVec stripIndices;
|
236
|
+
unsigned int numSeparateStrips = 0;
|
237
|
+
|
238
|
+
if(bListsOnly)
|
239
|
+
{
|
240
|
+
//if we're outputting only lists, we're done
|
241
|
+
*numGroups = 1;
|
242
|
+
(*primGroups) = new PrimitiveGroup[*numGroups];
|
243
|
+
PrimitiveGroup* primGroupArray = *primGroups;
|
244
|
+
|
245
|
+
//count the total number of indices
|
246
|
+
unsigned int numIndices = 0;
|
247
|
+
int i;
|
248
|
+
for(i = 0; i < tempStrips.size(); i++)
|
249
|
+
{
|
250
|
+
numIndices += tempStrips[i]->m_faces.size() * 3;
|
251
|
+
}
|
252
|
+
|
253
|
+
//add in the list
|
254
|
+
numIndices += tempFaces.size() * 3;
|
255
|
+
|
256
|
+
primGroupArray[0].type = PT_LIST;
|
257
|
+
primGroupArray[0].numIndices = numIndices;
|
258
|
+
primGroupArray[0].indices = new unsigned short[numIndices];
|
259
|
+
|
260
|
+
//do strips
|
261
|
+
unsigned int indexCtr = 0;
|
262
|
+
for(i = 0; i < tempStrips.size(); i++)
|
263
|
+
{
|
264
|
+
for(int j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
265
|
+
{
|
266
|
+
//degenerates are of no use with lists
|
267
|
+
if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j]))
|
268
|
+
{
|
269
|
+
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v0;
|
270
|
+
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v1;
|
271
|
+
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v2;
|
272
|
+
}
|
273
|
+
else
|
274
|
+
{
|
275
|
+
//we've removed a tri, reduce the number of indices
|
276
|
+
primGroupArray[0].numIndices -= 3;
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
//do lists
|
282
|
+
for(i = 0; i < tempFaces.size(); i++)
|
283
|
+
{
|
284
|
+
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0;
|
285
|
+
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1;
|
286
|
+
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
else
|
290
|
+
{
|
291
|
+
stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips, bRestart, restartVal);
|
292
|
+
|
293
|
+
//if we're stitching strips together, we better get back only one strip from CreateStrips()
|
294
|
+
assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips);
|
295
|
+
|
296
|
+
//convert to output format
|
297
|
+
*numGroups = numSeparateStrips; //for the strips
|
298
|
+
if(tempFaces.size() != 0)
|
299
|
+
(*numGroups)++; //we've got a list as well, increment
|
300
|
+
(*primGroups) = new PrimitiveGroup[*numGroups];
|
301
|
+
|
302
|
+
PrimitiveGroup* primGroupArray = *primGroups;
|
303
|
+
|
304
|
+
//first, the strips
|
305
|
+
int startingLoc = 0;
|
306
|
+
for(int stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++)
|
307
|
+
{
|
308
|
+
int stripLength = 0;
|
309
|
+
|
310
|
+
if(!bStitchStrips)
|
311
|
+
{
|
312
|
+
//if we've got multiple strips, we need to figure out the correct length
|
313
|
+
int i;
|
314
|
+
for(i = startingLoc; i < stripIndices.size(); i++)
|
315
|
+
{
|
316
|
+
if(stripIndices[i] == -1)
|
317
|
+
break;
|
318
|
+
}
|
319
|
+
|
320
|
+
stripLength = i - startingLoc;
|
321
|
+
}
|
322
|
+
else
|
323
|
+
stripLength = stripIndices.size();
|
324
|
+
|
325
|
+
primGroupArray[stripCtr].type = PT_STRIP;
|
326
|
+
primGroupArray[stripCtr].indices = new unsigned short[stripLength];
|
327
|
+
primGroupArray[stripCtr].numIndices = stripLength;
|
328
|
+
|
329
|
+
int indexCtr = 0;
|
330
|
+
for(int i = startingLoc; i < stripLength + startingLoc; i++)
|
331
|
+
primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i];
|
332
|
+
|
333
|
+
//we add 1 to account for the -1 separating strips
|
334
|
+
//this doesn't break the stitched case since we'll exit the loop
|
335
|
+
startingLoc += stripLength + 1;
|
336
|
+
}
|
337
|
+
|
338
|
+
//next, the list
|
339
|
+
if(tempFaces.size() != 0)
|
340
|
+
{
|
341
|
+
int faceGroupLoc = (*numGroups) - 1; //the face group is the last one
|
342
|
+
primGroupArray[faceGroupLoc].type = PT_LIST;
|
343
|
+
primGroupArray[faceGroupLoc].indices = new unsigned short[tempFaces.size() * 3];
|
344
|
+
primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3;
|
345
|
+
int indexCtr = 0;
|
346
|
+
for(int i = 0; i < tempFaces.size(); i++)
|
347
|
+
{
|
348
|
+
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0;
|
349
|
+
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1;
|
350
|
+
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2;
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
|
355
|
+
//validate generated data against input
|
356
|
+
if (validateEnabled)
|
357
|
+
{
|
358
|
+
const int NUMBINS = 100;
|
359
|
+
|
360
|
+
std::vector<NvFaceInfo> in_bins[NUMBINS];
|
361
|
+
|
362
|
+
int i;
|
363
|
+
//hash input indices on first index
|
364
|
+
for (i = 0; i < in_numIndices; i += 3)
|
365
|
+
{
|
366
|
+
NvFaceInfo faceInfo(in_indices[i], in_indices[i + 1], in_indices[i + 2]);
|
367
|
+
in_bins[in_indices[i] % NUMBINS].push_back(faceInfo);
|
368
|
+
}
|
369
|
+
|
370
|
+
for (i = 0; i < *numGroups; ++i)
|
371
|
+
{
|
372
|
+
switch ((*primGroups)[i].type)
|
373
|
+
{
|
374
|
+
case PT_LIST:
|
375
|
+
{
|
376
|
+
for (int j = 0; j < (*primGroups)[i].numIndices; j += 3)
|
377
|
+
{
|
378
|
+
unsigned short v0 = (*primGroups)[i].indices[j];
|
379
|
+
unsigned short v1 = (*primGroups)[i].indices[j + 1];
|
380
|
+
unsigned short v2 = (*primGroups)[i].indices[j + 2];
|
381
|
+
|
382
|
+
//ignore degenerates
|
383
|
+
if (NvStripifier::IsDegenerate(v0, v1, v2))
|
384
|
+
continue;
|
385
|
+
|
386
|
+
if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS))
|
387
|
+
{
|
388
|
+
Cleanup(tempStrips, tempFaces);
|
389
|
+
return false;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
break;
|
393
|
+
}
|
394
|
+
|
395
|
+
case PT_STRIP:
|
396
|
+
{
|
397
|
+
int brokenCtr = 0;
|
398
|
+
bool flip = false;
|
399
|
+
for (int j = 2; j < (*primGroups)[i].numIndices; ++j)
|
400
|
+
{
|
401
|
+
unsigned short v0 = (*primGroups)[i].indices[j - 2];
|
402
|
+
unsigned short v1 = (*primGroups)[i].indices[j - 1];
|
403
|
+
unsigned short v2 = (*primGroups)[i].indices[j];
|
404
|
+
|
405
|
+
if (flip)
|
406
|
+
{
|
407
|
+
//swap v1 and v2
|
408
|
+
unsigned short swap = v1;
|
409
|
+
v1 = v2;
|
410
|
+
v2 = swap;
|
411
|
+
}
|
412
|
+
|
413
|
+
//ignore degenerates
|
414
|
+
if (NvStripifier::IsDegenerate(v0, v1, v2))
|
415
|
+
{
|
416
|
+
flip = !flip;
|
417
|
+
continue;
|
418
|
+
}
|
419
|
+
|
420
|
+
if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS))
|
421
|
+
{
|
422
|
+
Cleanup(tempStrips, tempFaces);
|
423
|
+
return false;
|
424
|
+
}
|
425
|
+
|
426
|
+
flip = !flip;
|
427
|
+
}
|
428
|
+
break;
|
429
|
+
}
|
430
|
+
|
431
|
+
case PT_FAN:
|
432
|
+
default:
|
433
|
+
break;
|
434
|
+
}
|
435
|
+
}
|
436
|
+
|
437
|
+
}
|
438
|
+
|
439
|
+
//clean up everything
|
440
|
+
Cleanup(tempStrips, tempFaces);
|
441
|
+
|
442
|
+
return true;
|
443
|
+
}
|
444
|
+
|
445
|
+
|
446
|
+
////////////////////////////////////////////////////////////////////////////////////////
|
447
|
+
// RemapIndices()
|
448
|
+
//
|
449
|
+
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
450
|
+
//
|
451
|
+
// in_primGroups: array of PrimitiveGroups you want remapped
|
452
|
+
// numGroups: number of entries in in_primGroups
|
453
|
+
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
454
|
+
// of acceptable values for indices in your primitive groups.
|
455
|
+
// remappedGroups: array of remapped PrimitiveGroups
|
456
|
+
//
|
457
|
+
// Note that, according to the remapping handed back to you, you must reorder your
|
458
|
+
// vertex buffer.
|
459
|
+
//
|
460
|
+
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
461
|
+
const unsigned short numVerts, PrimitiveGroup** remappedGroups)
|
462
|
+
{
|
463
|
+
(*remappedGroups) = new PrimitiveGroup[numGroups];
|
464
|
+
|
465
|
+
//caches oldIndex --> newIndex conversion
|
466
|
+
int *indexCache;
|
467
|
+
indexCache = new int[numVerts];
|
468
|
+
memset(indexCache, -1, sizeof(int)*numVerts);
|
469
|
+
|
470
|
+
//loop over primitive groups
|
471
|
+
unsigned int indexCtr = 0;
|
472
|
+
for(int i = 0; i < numGroups; i++)
|
473
|
+
{
|
474
|
+
unsigned int numIndices = in_primGroups[i].numIndices;
|
475
|
+
|
476
|
+
//init remapped group
|
477
|
+
(*remappedGroups)[i].type = in_primGroups[i].type;
|
478
|
+
(*remappedGroups)[i].numIndices = numIndices;
|
479
|
+
(*remappedGroups)[i].indices = new unsigned short[numIndices];
|
480
|
+
|
481
|
+
for(int j = 0; j < numIndices; j++)
|
482
|
+
{
|
483
|
+
int cachedIndex = indexCache[in_primGroups[i].indices[j]];
|
484
|
+
if(cachedIndex == -1) //we haven't seen this index before
|
485
|
+
{
|
486
|
+
//point to "last" vertex in VB
|
487
|
+
(*remappedGroups)[i].indices[j] = indexCtr;
|
488
|
+
|
489
|
+
//add to index cache, increment
|
490
|
+
indexCache[in_primGroups[i].indices[j]] = indexCtr++;
|
491
|
+
}
|
492
|
+
else
|
493
|
+
{
|
494
|
+
//we've seen this index before
|
495
|
+
(*remappedGroups)[i].indices[j] = cachedIndex;
|
496
|
+
}
|
497
|
+
}
|
498
|
+
}
|
499
|
+
|
500
|
+
delete[] indexCache;
|
501
|
+
}
|