summaryrefslogtreecommitdiff
path: root/import/src/physics.rs
blob: 3beb49b00c68d42ede9726f82a469561a53f1a64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/*
    wearechat - generic multiplayer game with voip
    Copyright (C) 2025 metamuffin

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3 of the License only.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
use anyhow::{Result, anyhow};
use gltf::{Gltf, Node, buffer::Data, json::Value};
use log::{debug, info};
use weareshared::{
    Affine3A, packets::Resource, resources::CollisionPart, store::ResourceStore, vec3a,
};

pub fn import_physics(
    gltf: &Gltf,
    trans: Affine3A,
    node: &Node,
    store: &ResourceStore,
    buffers: &[Data],
) -> Result<Vec<(Affine3A, Resource<CollisionPart>)>> {
    let mut collision = Vec::new();
    if let Some(physics) = node
        .extensions()
        .and_then(|e| e.get("KHR_physics_rigid_bodies"))
    {
        debug!("--- COLLISION ---");
        if let Some(collider) = physics.get("collider") {
            if let Some(geometry) = collider.get("geometry") {
                if let Some(&Value::Bool(chull)) = geometry.get("convexHull") {
                    let node = geometry
                        .get("node")
                        .and_then(|n| n.as_u64())
                        .ok_or(anyhow!("coll geom node missing"))?;
                    let node = gltf
                        .nodes()
                        .nth(node as usize)
                        .ok_or(anyhow!("coll geom node reference invalid"))?;
                    let mesh = node.mesh().ok_or(anyhow!("coll geom node has no mesh"))?;
                    for p in mesh.primitives() {
                        let reader = p.reader(|buf| Some(&buffers[buf.index()]));

                        let index = reader
                            .read_indices()
                            .ok_or(anyhow!("coll geom no index buffer"))?
                            .into_u32()
                            .array_chunks::<3>()
                            .collect::<Vec<_>>();
                        let position = reader
                            .read_positions()
                            .ok_or(anyhow!("coll geom no positions"))?
                            .map(|[x, y, z]| vec3a(x, y, z))
                            .collect::<Vec<_>>();

                        let mut collpart = CollisionPart {
                            name: node.name().map(|s| s.to_string()),
                            ..Default::default()
                        };

                        if chull {
                            debug!("convex hull has {} positions", position.len());
                            collpart.sh_convex_hull = Some(store.set(&position)?);
                        } else {
                            debug!(
                                "mesh has {} indecies and {} positions",
                                index.len(),
                                position.len()
                            );
                            collpart.sh_mesh = Some((store.set(&index)?, store.set(&position)?));
                        }

                        info!("added collision {:?}", node.name().unwrap_or_default());
                        collision.push((trans, store.set(&collpart)?));
                    }
                }
            }
        }
    }
    Ok(collision)
}