use crate::INVALID_INDEX;
fn find_strip_first(buffer: &[[u32; 3]], valence: &[u32]) -> usize {
let mut index = 0;
let mut iv = INVALID_INDEX;
for (i, b) in buffer.iter().enumerate() {
let va = valence[b[0] as usize];
let vb = valence[b[1] as usize];
let vc = valence[b[2] as usize];
let v = va.min(vb).min(vc);
if v < iv {
index = i;
iv = v;
}
}
index
}
fn find_strip_next(buffer: &[[u32; 3]], e: (u32, u32)) -> i32 {
for (i, abc) in buffer.iter().enumerate() {
if e.0 == abc[0] && e.1 == abc[1] {
return ((i as i32) << 2) | 2;
} else if e.0 == abc[1] && e.1 == abc[2] {
return ((i as i32) << 2) | 0;
} else if e.0 == abc[2] && e.1 == abc[0] {
return ((i as i32) << 2) | 1;
}
}
-1
}
pub fn stripify(destination: &mut [u32], indices: &[u32], vertex_count: usize, restart_index: u32) -> usize {
assert!(indices.len() % 3 == 0);
const BUFFER_CAPACITY: usize = 8;
let mut buffer = [[0; 3]; BUFFER_CAPACITY];
let mut buffer_size = 0;
let mut index_offset = 0;
let mut strip = [0; 2];
let mut parity = false;
let mut strip_size = 0;
let mut valence = vec![0; vertex_count];
for index in indices {
valence[*index as usize] += 1;
}
let mut next: i32 = -1;
let index_count = indices.len();
while buffer_size > 0 || index_offset < index_count {
assert!(next < 0 || (((next >> 2) as usize) < buffer_size && (next & 3) < 3));
while buffer_size < buffer.len() && index_offset < index_count {
buffer[buffer_size].copy_from_slice(&indices[index_offset..index_offset + 3]);
buffer_size += 1;
index_offset += 3;
}
assert!(buffer_size > 0 && buffer_size <= buffer.len());
if next >= 0 {
let i = (next >> 2) as usize;
let abc = buffer[i];
let v = buffer[i][(next & 3) as usize];
let buffer_length = buffer.len();
buffer.copy_within(i + 1..buffer_length, i);
buffer_size -= 1;
valence[abc[0] as usize] -= 1;
valence[abc[1] as usize] -= 1;
valence[abc[2] as usize] -= 1;
let cont = find_strip_next(
&buffer[0..buffer_size],
if parity { (strip[1], v) } else { (v, strip[1]) },
);
let swap = if cont < 0 {
find_strip_next(
&buffer[0..buffer_size],
if parity { (v, strip[0]) } else { (strip[0], v) },
)
} else {
-1
};
if cont < 0 && swap >= 0 {
destination[strip_size] = strip[0];
strip_size += 1;
destination[strip_size] = v;
strip_size += 1;
strip[1] = v;
next = swap;
} else {
destination[strip_size] = v;
strip_size += 1;
strip[0] = strip[1];
strip[1] = v;
parity ^= true;
next = cont;
}
} else {
let i = find_strip_first(&buffer[0..buffer_size], &valence);
let mut abc = buffer[i];
buffer.copy_within(i + 1.., i);
buffer_size -= 1;
valence[abc[0] as usize] -= 1;
valence[abc[1] as usize] -= 1;
valence[abc[2] as usize] -= 1;
let ea = find_strip_next(&buffer[0..buffer_size], (abc[2], abc[1]));
let eb = find_strip_next(&buffer[0..buffer_size], (abc[0], abc[2]));
let ec = find_strip_next(&buffer[0..buffer_size], (abc[1], abc[0]));
let mut mine = i32::MAX;
mine = if ea >= 0 && mine > ea { ea } else { mine };
mine = if eb >= 0 && mine > eb { eb } else { mine };
mine = if ec >= 0 && mine > ec { ec } else { mine };
match mine {
_ if mine == ea => {
next = ea;
}
_ if mine == eb => {
abc.rotate_left(1);
next = eb;
}
_ if mine == ec => {
abc.rotate_right(1);
next = ec;
}
_ => {}
}
if restart_index != 0 {
if strip_size != 0 {
destination[strip_size] = restart_index;
strip_size += 1;
}
destination[strip_size..strip_size + 3].copy_from_slice(&abc);
strip_size += 3;
strip[0] = abc[1];
strip[1] = abc[2];
parity = true;
} else {
if strip_size != 0 {
destination[strip_size] = strip[1];
strip_size += 1;
destination[strip_size] = abc[0];
strip_size += 1;
}
let (e0, e1) = if parity { (abc[2], abc[1]) } else { (abc[1], abc[2]) };
destination[strip_size..strip_size + 3].copy_from_slice(&[abc[0], e0, e1]);
strip_size += 3;
strip[0] = e0;
strip[1] = e1;
parity ^= true;
}
}
}
strip_size
}
pub fn stripify_bound(index_count: usize) -> usize {
assert!(index_count % 3 == 0);
(index_count / 3) * 5
}
pub fn unstripify(destination: &mut [u32], indices: &[u32], restart_index: u32) -> usize {
let mut offset = 0;
let mut start = 0;
for (i, index) in indices.iter().enumerate() {
if restart_index != 0 && *index == restart_index {
start = i + 1;
} else if i - start >= 2 {
let mut a = indices[i - 2];
let mut b = indices[i - 1];
let c = indices[i - 0];
if ((i - start) & 1) != 0 {
std::mem::swap(&mut a, &mut b);
}
if a != b && a != c && b != c {
destination[offset + 0] = a;
destination[offset + 1] = b;
destination[offset + 2] = c;
offset += 3;
}
}
}
offset
}
pub fn unstripify_bound(index_count: usize) -> usize {
assert!(index_count == 0 || index_count >= 3);
if index_count == 0 {
0
} else {
(index_count - 2) * 3
}
}