grafix_toolbox/kit/opengl/geom/
model.rs1use super::*;
2use crate::math::*;
3
4#[derive_as_obj]
5pub struct Model {
6 #[cfg_attr(feature = "adv_fs", serde(with = "ser::as_byte_slice"))]
7 idx: Box<[u32]>,
8 #[cfg_attr(feature = "adv_fs", serde(with = "ser::as_byte_slice"))]
9 xyz: Box<[f32]>,
10 #[cfg_attr(feature = "adv_fs", serde(with = "ser::as_byte_slice"))]
11 uv: Box<[f16]>,
12 #[cfg_attr(feature = "adv_fs", serde(with = "ser::as_byte_slice"))]
13 norm: Box<[f16]>,
14}
15#[cfg(feature = "obj")]
16impl Model {
17 pub fn load_models(file: &str, scale: f32) -> Res<Vec<Self>> {
18 let file = &format!("res/{file}.obj");
19 let (models, _) = tobj::load_obj(
20 file,
21 &tobj::LoadOptions {
22 single_index: true,
23 triangulate: true,
24 ignore_points: true,
25 ignore_lines: true,
26 },
27 )
28 .explain_err(|| format!("Cannot load models from {file:?}"))?;
29 let models = models
30 .into_iter()
31 .map(|m| {
32 let m = m.mesh;
33 let (idx, xyz, uv, mut norm, (mut min, mut max)) = (
34 m.indices.into(),
35 m.positions,
36 m.texcoords.into_iter().map(f16).collect(),
37 m.normals.iter().map(|&v| f16(v)).collect_vec(),
38 Def(),
39 );
40 for i in (0..xyz.len()).step_by(3) {
41 let v = Vec3(&xyz[i..i + 3]);
42 (min, max) = (v.fmin(min), v.fmax(max));
43 if m.normals.is_empty() && i % 9 == 0 && i + 8 < xyz.len() {
44 let xyz = &xyz[i..i + 3];
45 let (v1, v2, v3) = Mat3((xyz, &xyz[3..], &xyz[6..]));
46 let ndir = v1.sum(v2).sum(v3).div(3).sgn();
47 let (v1, v2, v3) = vec3::<la::V3>::to((v1, v2, v3));
48 let n = Vec3(la::normal(v1, v2, v3)).mul(ndir).pipe(<[_; 3]>::to);
49 (0..9).for_each(|i| norm.push(n[i % 3]));
50 }
51 }
52 let d = max.sub(min).max_comp();
53 let (center, scale) = (max.sum(min).div(2), Vec3(1).div(d).mul(scale));
54 let xyz = xyz.chunks(3).flat_map(|s| Vec3(s).sub(center).mul(scale).pipe(<[_; 3]>::to).to_vec()).collect();
55 Self { idx, xyz, uv, norm: norm.into() }
56 })
57 .collect();
58 Ok(models)
59 }
60 #[cfg(feature = "adv_fs")]
61 pub fn new_cached(name: &str) -> Res<Self> {
62 let cache = format!("{name}.obj.z");
63 if let model @ Ok(_) = FS::Load::Archive(&cache).and_then(ser::from_vec) {
64 return model;
65 }
66
67 Self::load_models(name, 1.)?
68 .into_iter()
69 .next()
70 .ok_or("Empty models file")?
71 .tap(|m| ser::to_vec(m).map(|v| FS::Save::Archive((cache, v, 10))).warn())
72 .pipe(Ok)
73 }
74}
75impl<T: Borrow<Model>> From<T> for AnyMesh {
76 fn from(m: T) -> Self {
77 let m = m.borrow();
78 let (i, c, n) = (&m.idx, (3, &m.xyz[..]), (3, &m.norm[..]));
79 let geom = if m.uv.is_empty() {
80 Geometry::new(i, (c, (), n))
81 } else {
82 Geometry::new(i, (c, (2, &m.uv[..]), n))
83 };
84
85 Mesh { geom, draw: (u32(i.len()), gl::TRIANGLES) }.pipe(Box)
86 }
87}
88
89impl Mesh<u16> {
90 pub fn make_sphere(scale: f32, segs: u32) -> AnyMesh {
91 let (xyz, uv) = {
92 let (mut xyz, mut uv): (Vec<f32>, Vec<f16>) = Def();
93 iter2d(0..1 + segs).for_each(|(x, y)| {
94 let (sx, sy) = Vec2((x, y)).div(segs);
95 let (rx, ry) = (sx.to_radians(), sy.to_radians());
96 let (x, y, z) = ((rx * 360.).cos() * (ry * 180.).sin(), (ry * 180.).cos(), (rx * 360.).sin() * (ry * 180.).sin()).mul(scale);
97 let (sx, sy) = hVec2((sx, sy).norm());
98 xyz.extend(&[x, y, z]);
99 uv.extend(&[sx, sy]);
100 });
101 (xyz, uv)
102 };
103
104 let idx = (0..segs)
105 .flat_map(|y| {
106 let s = segs + 1;
107 let row = (0..s).flat_map(|x| vec![y * s + x, (y + 1) * s + x]);
108 if y % 2 == y { row.collect_vec() } else { row.rev().collect_vec() }
109 })
110 .map(u16)
111 .collect_vec();
112
113 let geom = Geometry::new(&idx, ((3, &xyz[..]), (2, &uv[..]), (3, &xyz[..])));
114
115 Self { geom, draw: (u16(idx.len()), gl::TRIANGLE_STRIP) }.pipe(Box)
116 }
117}