Skip to main content

grafix_toolbox/kit/opengl/geom/
model.rs

1use 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}