1use crate::INVALID_INDEX;
4
5fn find_strip_first(buffer: &[[u32; 3]], valence: &[u32]) -> usize {
6 let mut index = 0;
7 let mut iv = INVALID_INDEX;
8
9 for (i, b) in buffer.iter().enumerate() {
10 let va = valence[b[0] as usize];
11 let vb = valence[b[1] as usize];
12 let vc = valence[b[2] as usize];
13
14 let v = va.min(vb).min(vc);
15
16 if v < iv {
17 index = i;
18 iv = v;
19 }
20 }
21
22 index
23}
24
25fn find_strip_next(buffer: &[[u32; 3]], e: (u32, u32)) -> i32 {
26 for (i, abc) in buffer.iter().enumerate() {
27 if e.0 == abc[0] && e.1 == abc[1] {
28 return ((i as i32) << 2) | 2;
29 } else if e.0 == abc[1] && e.1 == abc[2] {
30 return ((i as i32) << 2) | 0;
31 } else if e.0 == abc[2] && e.1 == abc[0] {
32 return ((i as i32) << 2) | 1;
33 }
34 }
35
36 -1
37}
38
39pub fn stripify(destination: &mut [u32], indices: &[u32], vertex_count: usize, restart_index: u32) -> usize {
50 assert!(indices.len() % 3 == 0);
51
52 const BUFFER_CAPACITY: usize = 8;
53
54 let mut buffer = [[0; 3]; BUFFER_CAPACITY];
55 let mut buffer_size = 0;
56
57 let mut index_offset = 0;
58
59 let mut strip = [0; 2];
60 let mut parity = false;
61
62 let mut strip_size = 0;
63
64 let mut valence = vec![0; vertex_count];
66
67 for index in indices {
68 valence[*index as usize] += 1;
69 }
70
71 let mut next: i32 = -1;
72
73 let index_count = indices.len();
74
75 while buffer_size > 0 || index_offset < index_count {
76 assert!(next < 0 || (((next >> 2) as usize) < buffer_size && (next & 3) < 3));
77
78 while buffer_size < buffer.len() && index_offset < index_count {
80 buffer[buffer_size].copy_from_slice(&indices[index_offset..index_offset + 3]);
81
82 buffer_size += 1;
83 index_offset += 3;
84 }
85
86 assert!(buffer_size > 0 && buffer_size <= buffer.len());
87
88 if next >= 0 {
89 let i = (next >> 2) as usize;
90 let abc = buffer[i];
91 let v = buffer[i][(next & 3) as usize];
92
93 let buffer_length = buffer.len();
95 buffer.copy_within(i + 1..buffer_length, i);
96 buffer_size -= 1;
97
98 valence[abc[0] as usize] -= 1;
100 valence[abc[1] as usize] -= 1;
101 valence[abc[2] as usize] -= 1;
102
103 let cont = find_strip_next(
107 &buffer[0..buffer_size],
108 if parity { (strip[1], v) } else { (v, strip[1]) },
109 );
110 let swap = if cont < 0 {
111 find_strip_next(
112 &buffer[0..buffer_size],
113 if parity { (v, strip[0]) } else { (strip[0], v) },
114 )
115 } else {
116 -1
117 };
118
119 if cont < 0 && swap >= 0 {
120 destination[strip_size] = strip[0];
122 strip_size += 1;
123 destination[strip_size] = v;
124 strip_size += 1;
125
126 strip[1] = v;
129
130 next = swap;
131 } else {
132 destination[strip_size] = v;
134 strip_size += 1;
135
136 strip[0] = strip[1];
138 strip[1] = v;
139 parity ^= true;
140
141 next = cont;
142 }
143 } else {
144 let i = find_strip_first(&buffer[0..buffer_size], &valence);
147 let mut abc = buffer[i];
148
149 buffer.copy_within(i + 1.., i);
151 buffer_size -= 1;
152
153 valence[abc[0] as usize] -= 1;
155 valence[abc[1] as usize] -= 1;
156 valence[abc[2] as usize] -= 1;
157
158 let ea = find_strip_next(&buffer[0..buffer_size], (abc[2], abc[1]));
160 let eb = find_strip_next(&buffer[0..buffer_size], (abc[0], abc[2]));
161 let ec = find_strip_next(&buffer[0..buffer_size], (abc[1], abc[0]));
162
163 let mut mine = i32::MAX;
167 mine = if ea >= 0 && mine > ea { ea } else { mine };
168 mine = if eb >= 0 && mine > eb { eb } else { mine };
169 mine = if ec >= 0 && mine > ec { ec } else { mine };
170
171 match mine {
172 _ if mine == ea => {
173 next = ea;
175 }
176 _ if mine == eb => {
177 abc.rotate_left(1);
179 next = eb;
180 }
181 _ if mine == ec => {
182 abc.rotate_right(1);
184 next = ec;
185 }
186 _ => {}
187 }
188
189 if restart_index != 0 {
190 if strip_size != 0 {
191 destination[strip_size] = restart_index;
192 strip_size += 1;
193 }
194
195 destination[strip_size..strip_size + 3].copy_from_slice(&abc);
196 strip_size += 3;
197
198 strip[0] = abc[1];
200 strip[1] = abc[2];
201 parity = true;
202 } else {
203 if strip_size != 0 {
204 destination[strip_size] = strip[1];
206 strip_size += 1;
207 destination[strip_size] = abc[0];
208 strip_size += 1;
209 }
210
211 let (e0, e1) = if parity { (abc[2], abc[1]) } else { (abc[1], abc[2]) };
214
215 destination[strip_size..strip_size + 3].copy_from_slice(&[abc[0], e0, e1]);
216 strip_size += 3;
217
218 strip[0] = e0;
219 strip[1] = e1;
220 parity ^= true;
221 }
222 }
223 }
224
225 strip_size
226}
227
228pub fn stripify_bound(index_count: usize) -> usize {
230 assert!(index_count % 3 == 0);
231
232 (index_count / 3) * 5
235}
236
237pub fn unstripify(destination: &mut [u32], indices: &[u32], restart_index: u32) -> usize {
245 let mut offset = 0;
246 let mut start = 0;
247
248 for (i, index) in indices.iter().enumerate() {
249 if restart_index != 0 && *index == restart_index {
250 start = i + 1;
251 } else if i - start >= 2 {
252 let mut a = indices[i - 2];
253 let mut b = indices[i - 1];
254 let c = indices[i - 0];
255
256 if ((i - start) & 1) != 0 {
258 std::mem::swap(&mut a, &mut b);
259 }
260
261 if a != b && a != c && b != c {
263 destination[offset + 0] = a;
264 destination[offset + 1] = b;
265 destination[offset + 2] = c;
266 offset += 3;
267 }
268 }
269 }
270
271 offset
272}
273
274pub fn unstripify_bound(index_count: usize) -> usize {
275 assert!(index_count == 0 || index_count >= 3);
276
277 if index_count == 0 {
278 0
279 } else {
280 (index_count - 2) * 3
281 }
282}