summaryrefslogtreecommitdiff
path: root/world/src/prefab.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-12 17:54:43 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-12 17:54:43 +0100
commitdc8304afefa71037bea99722bee29f7645753836 (patch)
tree4fd2b70d6faec18573bd590442b443b7d7a53c1a /world/src/prefab.rs
parent3ed621256f1e02032250477fa574eab38bd34976 (diff)
downloadweareserver-dc8304afefa71037bea99722bee29f7645753836.tar
weareserver-dc8304afefa71037bea99722bee29f7645753836.tar.bz2
weareserver-dc8304afefa71037bea99722bee29f7645753836.tar.zst
rename crates and binaries
Diffstat (limited to 'world/src/prefab.rs')
-rw-r--r--world/src/prefab.rs426
1 files changed, 0 insertions, 426 deletions
diff --git a/world/src/prefab.rs b/world/src/prefab.rs
deleted file mode 100644
index bf45f01..0000000
--- a/world/src/prefab.rs
+++ /dev/null
@@ -1,426 +0,0 @@
-use crate::{
- Args, TextureCache, animation::import_animation, mesh::import_mesh, physics::import_physics,
- transform_to_affine, vrm::extract_vrm_data,
-};
-use anyhow::{Context, Result, anyhow};
-use glam::{Affine3A, Vec3, Vec3A, vec3a};
-use gltf::{Gltf, Node, import_buffers, scene::Transform};
-use log::{debug, info};
-use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
-use serde::Deserialize;
-use serde_json::Value;
-use std::{
- borrow::Cow,
- collections::BTreeMap,
- fs::{File, read_to_string},
- io::Read,
- path::Path,
- sync::Mutex,
-};
-use weareshared::{
- packets::Resource,
- resources::{
- ArmaturePart, AvatarInfoPart, EnvironmentPart, Image, LightPart, ParticlesPart, Prefab,
- },
- store::ResourceStore,
-};
-
-pub fn import_prefab(
- store: &ResourceStore,
- texture_cache: &TextureCache,
- scenepath: &Path,
- args: &Args,
-) -> Result<Resource<Prefab>> {
- let path_base = scenepath.parent().unwrap();
- let mut gltf =
- Gltf::from_reader_without_validation(File::open(scenepath)?).context("gltf parsing")?;
- let blob = gltf.blob.take();
- let buffers = import_buffers(&gltf, Some(path_base), blob).context("importing buffers")?;
-
- let root = gltf.default_scene().ok_or(anyhow!("no default scene"))?;
-
- // gltf.as_json().asset.copyright
- // eprintln!("{:?}", gltf.extensions_used());
- // eprintln!("{:?}", gltf.extensions());
- // eprintln!("{:?}", root.extensions());
- // eprintln!("{:?}", root.extras());
-
- let mut nodes = Vec::new();
- fn traverse<'a>(out: &mut Vec<(Affine3A, Node<'a>)>, node: Node<'a>, trans: Affine3A) {
- let trans = trans * transform_to_affine(node.transform());
- for c in node.children() {
- traverse(out, c, trans);
- }
- out.push((trans, node));
- }
-
- let mut root_affine = Affine3A::IDENTITY;
- root_affine.matrix3 *= args.scale.unwrap_or(1.);
- root_affine.translation *= args.scale.unwrap_or(1.);
-
- for node in root.nodes() {
- traverse(&mut nodes, node, root_affine);
- }
-
- let vrm = extract_vrm_data(&gltf)?;
-
- let mut skin_index_to_arm_index = BTreeMap::new();
- let mut joint_index_to_arm_index = BTreeMap::new();
- let joint_name_to_arm_index: BTreeMap<String, usize>;
- let armature = {
- let mut name = Vec::new();
- let mut parent_pre_map = Vec::new();
- let mut transform = Vec::new();
- let mut inverse_bind_transform = Vec::new();
-
- for skin in gltf.skins() {
- let mut inverse_bind_mat = skin
- .reader(|buf| Some(&buffers[buf.index()]))
- .read_inverse_bind_matrices();
- for (j_ind, j) in skin.joints().enumerate() {
- let ibm = inverse_bind_mat.as_mut().map(|x| x.next().unwrap());
- let a_ind = match joint_index_to_arm_index.get(&j.index()) {
- Some(i) => *i,
- None => {
- let a_ind = name.len();
- // name.push(j.name().unwrap_or("").to_string());
- name.push(format!("bone{}", a_ind));
- transform.push(transform_to_affine(j.transform()));
- parent_pre_map.push(
- gltf.nodes()
- .find(|n| n.children().any(|c| c.index() == j.index()))
- .map(|n| n.index()),
- );
- inverse_bind_transform.push(
- ibm.map(|a| transform_to_affine(Transform::Matrix { matrix: a }))
- .unwrap_or(Affine3A::IDENTITY),
- );
-
- joint_index_to_arm_index.insert(j.index(), a_ind);
- a_ind
- }
- };
- skin_index_to_arm_index.insert((skin.index(), j_ind as u16), a_ind as u32);
- }
- }
-
- let parent = parent_pre_map
- .into_iter()
- .enumerate()
- .map(|(i, p)| {
- p.and_then(|i| joint_index_to_arm_index.get(&i).copied())
- .unwrap_or(i) as u16
- })
- .collect::<Vec<_>>();
-
- for (node, bname) in &vrm.bone_node_names {
- let ind = joint_index_to_arm_index[node];
- name[ind] = bname.to_owned();
- }
-
- joint_name_to_arm_index = name
- .iter()
- .cloned()
- .enumerate()
- .map(|(a, b)| (b, a))
- .collect();
-
- ArmaturePart {
- name: Some(name),
- parent: Some(parent),
- transform: Some(transform),
- inverse_bind_transform: Some(inverse_bind_transform),
- }
- };
-
- let head_bones = {
- let pa = armature.parent.clone().unwrap_or_default();
- let na = armature.name.clone().unwrap_or_default();
- (0..pa.len())
- .filter(|&(mut i)| {
- let mut f = false;
- while pa[i] as usize != i {
- f |= na[i] == "head";
- i = pa[i] as usize;
- }
- f
- })
- .map(|e| e as u32)
- .collect::<Vec<_>>()
- };
-
- let prefab = Mutex::new(Prefab::default());
- let node_to_meshes = Mutex::new(BTreeMap::<usize, Vec<usize>>::new());
-
- nodes
- .par_iter()
- .map(|(trans, node)| {
- // if node.name().unwrap_or_default() == "particles" {
- // eprintln!("{:?}", node.transform());
- // eprintln!("{:?}", node.extensions());
- // eprintln!("{:?}", node.extras());
- // }
- let name = node.name().unwrap_or_default();
- let extras: Value = node
- .extras()
- .to_owned()
- .map(|v| serde_json::from_str(v.get()).unwrap())
- .unwrap_or(Value::Object(Default::default()));
-
- if !name.ends_with("-collider") {
- if let Some(mesh) = node.mesh() {
- let meshes = import_mesh(
- mesh,
- *trans,
- &buffers,
- &store,
- path_base,
- node,
- &args,
- &texture_cache,
- &skin_index_to_arm_index,
- &vrm,
- &head_bones,
- )?;
- for (node, trans, mesh) in meshes {
- let mut k = prefab.lock().unwrap();
- let i = k.mesh.len();
- k.mesh.push((trans, mesh));
- node_to_meshes
- .lock()
- .unwrap()
- .entry(node)
- .or_default()
- .push(i)
- }
- }
- }
- if extras.get("particles") == Some(&Value::Bool(true)) && !args.no_particles {
- #[derive(Deserialize)]
- struct ParticlesAttr {
- density: Option<f32>,
- lifetime: Option<f32>,
- lifetime_spread: Option<f32>,
- velocity: Option<Vec3A>,
- velocity_spread: Option<Vec3A>,
- }
- // let sprite = extras
- // .get("sprite")
- // .ok_or(anyhow!("particle volume is missing sprite"))?;
-
- let attr: ParticlesAttr =
- serde_json::from_value(extras).context("particles attributes")?;
-
- info!("adding particles part");
-
- let part = store.set(&ParticlesPart {
- sprite: None,
- density: attr.density,
- lifetime: attr.lifetime,
- lifetime_spread: attr.lifetime_spread,
- velocity: attr.velocity,
- velocity_spread: attr.velocity_spread,
- })?;
-
- prefab
- .lock()
- .unwrap()
- .particles
- .push((transform_to_affine(node.transform()), part));
- }
-
- if let Some(light) = node.light() {
- let name = node.name().map(|e| e.to_owned());
- if let Some(name) = &name {
- info!("adding light {name:?}");
- } else {
- info!("adding light");
- }
- let emission = Some(Vec3A::from_array(light.color()) * light.intensity());
- if let Some(e) = emission {
- debug!("emission is {e}");
- }
- let (position, _, _) = node.transform().decomposed();
- let part = store.set(&LightPart {
- emission,
- name,
- radius: None,
- })?;
- prefab
- .lock()
- .unwrap()
- .light
- .push((Vec3A::from_array(position), part));
- }
- {
- let collider = import_physics(&gltf, *trans, node, &store, &buffers)?;
- prefab.lock().unwrap().collision.extend(collider);
- }
-
- Ok::<_, anyhow::Error>(())
- })
- .reduce(
- || Ok(()),
- |a, b| match (a, b) {
- (Ok(()), Ok(())) => Ok(()),
- (Ok(()), a) => a,
- (a, _) => a,
- },
- )?;
-
- let mut prefab = prefab.into_inner().unwrap();
- let node_to_meshes = node_to_meshes.into_inner().unwrap();
-
- if let Some(apath) = args.animation.clone() {
- let path_base = apath.parent().unwrap();
- let mut gltf =
- Gltf::from_reader_without_validation(File::open(&apath)?).context("gltf parsing")?;
- let blob = gltf.blob.take();
- let buffers = import_buffers(&gltf, Some(path_base), blob).context("importing buffers")?;
-
- let anim_name_map = if let Some(ref map_path) = args.animation_bone_map {
- let mut map = BTreeMap::new();
- for l in read_to_string(map_path)?.lines() {
- if !l.trim().is_empty() && !l.starts_with(";") {
- let (a, b) = l.split_once("=").unwrap();
- map.insert(a.to_string(), b.to_string());
- }
- }
- Some(map)
- } else {
- None
- };
-
- let mut anim_joint_index_to_arm_index = BTreeMap::new();
- let mut joint_index_to_ibm = BTreeMap::new();
- for n in gltf.nodes() {
- if let Some(name) = n.name() {
- let Some(vrm_name) = (if let Some(map) = &anim_name_map {
- map.get(name).cloned()
- } else {
- Some(name.to_string())
- }) else {
- continue;
- };
- let anim_node_index = n.index();
- if let Some(scene_arm_index) = joint_name_to_arm_index.get(&vrm_name) {
- debug!(
- "mapping {name:?} (node={}) -> {vrm_name:?} (bone={})",
- anim_node_index, scene_arm_index
- );
- anim_joint_index_to_arm_index.insert(anim_node_index, *scene_arm_index);
- }
- }
- }
- if args.animation_apply_ibm {
- for s in gltf.skins() {
- let reader = s.reader(|buf| Some(&buffers[buf.index()]));
- if let Some(ibms) = reader.read_inverse_bind_matrices() {
- for (jn, ibm) in s.joints().zip(ibms) {
- joint_index_to_ibm.insert(
- jn.index(),
- transform_to_affine(Transform::Matrix { matrix: ibm }),
- );
- }
- }
- }
- debug!("{} joint IBMs found", joint_index_to_ibm.len());
- }
- let transform = args
- .animation_rotation_y
- .map(Affine3A::from_rotation_y)
- .unwrap_or_default()
- * args
- .animation_scale
- .map(Vec3::splat)
- .map(Affine3A::from_scale)
- .unwrap_or_default();
- for a in gltf.animations() {
- prefab.animation.push(import_animation(
- a,
- &store,
- transform,
- &joint_index_to_ibm,
- &anim_joint_index_to_arm_index,
- &BTreeMap::new(),
- &buffers,
- )?);
- }
- }
-
- for a in gltf.animations() {
- if !args.no_animations {
- prefab.animation.push(import_animation(
- a,
- &store,
- Affine3A::IDENTITY,
- &BTreeMap::new(),
- &joint_index_to_arm_index,
- &node_to_meshes,
- &buffers,
- )?);
- };
- }
-
- if vrm.camera_mount.is_some()
- || vrm.camera_mount_offset.is_some()
- || !vrm.bone_node_names.is_empty()
- {
- info!("avatar info enabled");
- prefab.avatar_info = Some(
- store.set(&AvatarInfoPart {
- armature: Some(0), // TODO
- camera_mount: vrm
- .camera_mount
- .map(|e| joint_index_to_arm_index[&e] as u32),
- camera_mount_offset: vrm.camera_mount_offset,
- ..Default::default()
- })?,
- );
- }
-
- prefab.armature = if armature.parent.as_ref().is_some_and(|a| !a.is_empty()) {
- vec![store.set(&armature)?]
- } else {
- vec![]
- };
-
- let skybox = if let Some(skybox) = &args.skybox {
- let mut buf = Vec::new();
- File::open(skybox)?.read_to_end(&mut buf)?;
- Some(store.set(&Image(Cow::Owned(buf)))?)
- } else {
- None
- };
- let sun = if args.with_default_sun {
- Some((
- vec3a(1., -5., 1.).normalize(),
- vec3a(1., 1., 1.).normalize() * 100_000.,
- ))
- } else {
- None
- };
- prefab.environment = if skybox.is_some() || sun.is_some() {
- Some(store.set(&EnvironmentPart { skybox, sun })?)
- } else {
- None
- };
-
- prefab.name = args.name.clone().or(gltf
- .default_scene()
- .and_then(|n| n.name())
- .map(|n| n.to_owned()));
-
- if args.debug_light {
- prefab.light.push((
- vec3a(5., 5., 5.),
- store.set(&LightPart {
- name: Some("debug light".to_owned()),
- emission: Some(vec3a(10., 5., 15.)),
- radius: Some(0.3),
- })?,
- ));
- }
-
- Ok(store.set(&prefab)?)
-}