summaryrefslogtreecommitdiff
path: root/import/src/physics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'import/src/physics.rs')
-rw-r--r--import/src/physics.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/import/src/physics.rs b/import/src/physics.rs
new file mode 100644
index 0000000..3beb49b
--- /dev/null
+++ b/import/src/physics.rs
@@ -0,0 +1,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)
+}