summaryrefslogtreecommitdiff
path: root/world/src/physics.rs
blob: 84f109507cdba6140325c872a3fe5c5c54eae749 (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
/*
    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,
    resources::{CollisionPart, Prefab},
    store::ResourceStore,
    vec3a,
};

pub fn import_physics(
    gltf: &Gltf,
    trans: Affine3A,
    node: &Node,
    prefab: &mut Prefab,
    store: &ResourceStore,
    buffers: &[Data],
) -> Result<()> {
    if let Some(physics) = node
        .extensions()
        .and_then(|e| e.get("KHR_physics_rigid_bodies"))
    {
        info!("--- COLLISION ---");
        if let Some(collider) = physics.get("collider") {
            if let Some(geometry) = collider.get("geometry") {
                if geometry.get("convexHull") == Some(&Value::Bool(true)) {
                    let node = geometry
                        .get("node")
                        .and_then(|n| n.as_u64())
                        .ok_or(anyhow!("convexHull node missing"))?;
                    let node = gltf
                        .nodes()
                        .nth(node as usize)
                        .ok_or(anyhow!("convexHull node reference invalid"))?;
                    let mesh = node.mesh().ok_or(anyhow!("convexHull 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!("convexHull no index buffer"))?
                            .into_u32()
                            .array_chunks::<3>()
                            .collect::<Vec<_>>();
                        let position = reader
                            .read_positions()
                            .ok_or(anyhow!("convexHull no positions"))?
                            .map(|[x, y, z]| vec3a(x, y, z))
                            .collect::<Vec<_>>();

                        debug!(
                            "convex hull has {} indecies and {} positions",
                            index.len(),
                            position.len()
                        );

                        prefab.collision.push((
                            trans,
                            store.set(&CollisionPart {
                                sh_mesh: Some((store.set(&index)?, store.set(&position)?)),
                                ..Default::default()
                            })?,
                        ));
                    }
                }
            }
        }
    }
    Ok(())
}