use super::tangent_frames;
use crate::GlyphItem;
pub fn vertex_intrinsic_to_glyphs(
positions: &[[f32; 3]],
normals: &[[f32; 3]],
tangents: Option<&[[f32; 4]]>,
vectors: &[[f32; 2]],
scale: f32,
) -> GlyphItem {
let frames: Vec<([f32; 3], [f32; 3])> = match tangents {
Some(t) => tangent_frames::tangents_from_explicit(normals, t),
None => tangent_frames::compute_vertex_tangent_frames(normals),
};
let n = positions
.len()
.min(normals.len())
.min(frames.len())
.min(vectors.len());
let mut glyph_positions = Vec::with_capacity(n);
let mut glyph_vectors = Vec::with_capacity(n);
for i in 0..n {
let uv = vectors[i];
let (tangent, bitangent) = frames[i];
let t = glam::Vec3::from(tangent);
let b = glam::Vec3::from(bitangent);
let world_vec = t * uv[0] + b * uv[1];
glyph_positions.push(positions[i]);
glyph_vectors.push(world_vec.to_array());
}
let mut item = GlyphItem::default();
item.positions = glyph_positions;
item.vectors = glyph_vectors;
item.scale = scale;
item
}
pub fn face_intrinsic_to_glyphs(
positions: &[[f32; 3]],
normals: &[[f32; 3]],
indices: &[u32],
vectors: &[[f32; 2]],
scale: f32,
) -> GlyphItem {
let _ = normals; let num_tris = indices.len() / 3;
let frames = tangent_frames::compute_face_tangent_frames(positions, indices);
let n = num_tris.min(frames.len()).min(vectors.len());
let mut glyph_positions = Vec::with_capacity(n);
let mut glyph_vectors = Vec::with_capacity(n);
for tri in 0..n {
let i0 = indices[3 * tri] as usize;
let i1 = indices[3 * tri + 1] as usize;
let i2 = indices[3 * tri + 2] as usize;
let p0 = glam::Vec3::from(positions[i0]);
let p1 = glam::Vec3::from(positions[i1]);
let p2 = glam::Vec3::from(positions[i2]);
let centroid = (p0 + p1 + p2) / 3.0;
let uv = vectors[tri];
let (tangent, bitangent) = frames[tri];
let t = glam::Vec3::from(tangent);
let b = glam::Vec3::from(bitangent);
let world_vec = t * uv[0] + b * uv[1];
glyph_positions.push(centroid.to_array());
glyph_vectors.push(world_vec.to_array());
}
let mut item = GlyphItem::default();
item.positions = glyph_positions;
item.vectors = glyph_vectors;
item.scale = scale;
item
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn vertex_intrinsic_unit_u_along_tangent() {
let positions = vec![[0.0, 0.0, 0.0]];
let normals = vec![[0.0, 1.0, 0.0]];
let vectors = vec![[1.0, 0.0]]; let item = vertex_intrinsic_to_glyphs(&positions, &normals, None, &vectors, 1.0);
assert_eq!(item.vectors.len(), 1);
let v = glam::Vec3::from(item.vectors[0]);
assert!(v.y.abs() < 1e-4, "should be in tangent plane");
assert!((v.length() - 1.0).abs() < 1e-3);
}
#[test]
fn vertex_intrinsic_mismatched_lengths_truncates() {
let positions = vec![[0.0; 3]; 5];
let normals = vec![[0.0, 1.0, 0.0]; 3]; let vectors = vec![[1.0, 0.0]; 5];
let item = vertex_intrinsic_to_glyphs(&positions, &normals, None, &vectors, 1.0);
assert_eq!(item.vectors.len(), 3);
}
#[test]
fn vertex_intrinsic_scale_forwarded() {
let positions = vec![[0.0; 3]];
let normals = vec![[0.0, 1.0, 0.0]];
let vectors = vec![[1.0, 0.0]];
let item = vertex_intrinsic_to_glyphs(&positions, &normals, None, &vectors, 7.5);
assert!((item.scale - 7.5).abs() < 1e-6);
}
#[test]
fn face_intrinsic_centroid_position() {
let positions = vec![
[0.0, 0.0, 0.0],
[3.0, 0.0, 0.0],
[0.0, 3.0, 0.0],
];
let normals = vec![[0.0, 0.0, 1.0]; 3];
let indices = vec![0u32, 1, 2];
let vectors = vec![[1.0, 0.0]];
let item = face_intrinsic_to_glyphs(&positions, &normals, &indices, &vectors, 1.0);
assert_eq!(item.positions.len(), 1);
let c = item.positions[0];
assert!((c[0] - 1.0).abs() < 1e-4);
assert!((c[1] - 1.0).abs() < 1e-4);
}
}