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/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
|
+
}
|