From 02d65e6b7ce7a0e6bae054bd321c68dda1cb0de3 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 7 Jan 2025 22:56:34 +0100 Subject: static typing for resources --- world/src/mesh.rs | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 world/src/mesh.rs (limited to 'world/src/mesh.rs') diff --git a/world/src/mesh.rs b/world/src/mesh.rs new file mode 100644 index 0000000..cbc33c0 --- /dev/null +++ b/world/src/mesh.rs @@ -0,0 +1,262 @@ +/* + 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 . +*/ +use crate::load_texture; +use anyhow::Result; +use gltf::{Mesh, Node, buffer::Data}; +use log::{debug, info}; +use std::path::Path; +use weareshared::{ + Affine3A, Vec3A, + resources::{AttributeArray, IndexArray, MeshPart, Prefab}, + store::ResourceStore, +}; + +pub fn import_mesh( + mesh: Mesh, + buffers: &[Data], + store: &ResourceStore, + path_base: &Path, + node: &Node, + prefab: &mut Prefab, +) -> Result<()> { + Ok(for p in mesh.primitives() { + let reader = p.reader(|buf| Some(&buffers[buf.index()])); + + let va_position = reader + .read_positions() + .map(|iter| { + let mut pos_x = vec![]; + let mut pos_y = vec![]; + let mut pos_z = vec![]; + for p in iter { + pos_x.push(p[0]); + pos_y.push(p[1]); + pos_z.push(p[2]); + } + info!("{} vertex positions", pos_x.len()); + Ok::<_, anyhow::Error>([ + store.set(&AttributeArray(pos_x))?, + store.set(&AttributeArray(pos_y))?, + store.set(&AttributeArray(pos_z))?, + ]) + }) + .transpose()?; + + let va_normal = reader + .read_normals() + .map(|iter| { + let mut normal_x = vec![]; + let mut normal_y = vec![]; + let mut normal_z = vec![]; + for p in iter { + normal_x.push(p[0]); + normal_y.push(p[1]); + normal_z.push(p[2]); + } + info!("{} vertex normals", normal_x.len()); + Ok::<_, anyhow::Error>([ + store.set(&AttributeArray(normal_x))?, + store.set(&AttributeArray(normal_y))?, + store.set(&AttributeArray(normal_z))?, + ]) + }) + .transpose()?; + + let va_texcoord = reader + .read_tex_coords(0) + .map(|iter| { + let mut texcoord_u = vec![]; + let mut texcoord_v = vec![]; + for p in iter.into_f32() { + texcoord_u.push(p[0]); + texcoord_v.push(p[1]); + } + info!("{} vertex texture coordinates", texcoord_u.len()); + Ok::<_, anyhow::Error>([ + store.set(&AttributeArray(texcoord_u))?, + store.set(&AttributeArray(texcoord_v))?, + ]) + }) + .transpose()?; + + let va_albedo = reader + .read_colors(0) + .map(|iter| { + let mut color_r = vec![]; + let mut color_g = vec![]; + let mut color_b = vec![]; + for p in iter.into_rgb_f32() { + color_r.push(p[0]); + color_g.push(p[1]); + color_b.push(p[2]); + } + info!("{} vertex colors", color_r.len()); + Ok::<_, anyhow::Error>([ + store.set(&AttributeArray(color_r))?, + store.set(&AttributeArray(color_g))?, + store.set(&AttributeArray(color_b))?, + ]) + }) + .transpose()?; + + let va_transmission = reader + .read_colors(0) + .map(|iter| { + let mut color_a = vec![]; + for p in iter.into_rgba_f32() { + color_a.push(p[3]); + } + let o = if color_a.iter().any(|x| *x != 1.) { + info!("{} vertex transmissions", color_a.len()); + Some(store.set(&AttributeArray(color_a))?) + } else { + debug!("vertex transmission pruned"); + None + }; + Ok::<_, anyhow::Error>(o) + }) + .transpose()? + .flatten(); + + let index = reader + .read_indices() + .unwrap() + .into_u32() + .map(|e| e as u16) + .array_chunks::<3>() + .collect::>(); + info!("{} indecies", index.len() * 3); + let index = Some(store.set(&IndexArray(index))?); + + let mut tex_albedo = None; + let mut tex_transmission = None; + if let Some(tex) = p.material().pbr_metallic_roughness().base_color_texture() { + let r = load_texture( + "albedo", + &store, + path_base, + &buffers, + &tex.texture().source().source(), + )?; + tex_albedo = Some(r.clone()); + tex_transmission = Some(r.clone()); + } + let mut tex_normal = None; + if let Some(tex) = p.material().normal_texture() { + tex_normal = Some(load_texture( + "normal", + &store, + path_base, + &buffers, + &tex.texture().source().source(), + )?); + } + let mut tex_emission = None; + if let Some(tex) = p.material().emissive_texture() { + tex_emission = Some(load_texture( + "emission", + &store, + path_base, + &buffers, + &tex.texture().source().source(), + )?); + } + let mut tex_roughness = None; + let mut tex_metallic = None; + if let Some(tex) = p + .material() + .pbr_metallic_roughness() + .metallic_roughness_texture() + { + let r = load_texture( + "metallic+roughness", + &store, + path_base, + &buffers, + &tex.texture().source().source(), + )?; + tex_roughness = Some(r.clone()); + tex_metallic = Some(r.clone()); + } + + let g_metallic = Some(p.material().pbr_metallic_roughness().metallic_factor()); + let g_roughness = Some(p.material().pbr_metallic_roughness().roughness_factor()); + + let base_color = p.material().pbr_metallic_roughness().base_color_factor(); + + let g_albedo = if base_color[0] != 1. || base_color[1] != 1. || base_color[2] != 1. { + info!( + "global albedo is r={},g={},b={}", + base_color[0], base_color[1], base_color[2] + ); + Some(Vec3A::new(base_color[0], base_color[1], base_color[2])) + } else { + debug!("global albedo pruned"); + None + }; + let g_transmission = if base_color[3] != 1. { + info!("global transmission is {}", base_color[3]); + Some(base_color[3]) + } else { + debug!("global transmission pruned"); + None + }; + + let emission = p.material().emissive_factor(); + let g_emission = if emission[0] != 0. || emission[1] != 0. || emission[2] != 0. { + info!( + "global emission is r={},g={},b={}", + base_color[0], base_color[1], base_color[2] + ); + Some(Vec3A::new(emission[0], emission[1], emission[2])) + } else { + debug!("global emission pruned"); + None + }; + + let mesh = store.set(&MeshPart { + g_albedo, + g_transmission, + g_metallic, + g_roughness, + g_emission, + va_position, + va_normal, + va_texcoord, + va_albedo, + va_transmission, + tex_albedo, + tex_normal, + tex_roughness, + tex_metallic, + tex_transmission, + tex_emission, + index, + va_emission: None, // not supported by gltf + va_metallic: None, // not supported by gltf + va_roughness: None, // not supported by gltf + })?; + let mat = node.transform().matrix(); + let aff = Affine3A::from_cols_array_2d(&[ + [mat[0][0], mat[0][1], mat[0][2]], + [mat[1][0], mat[1][1], mat[1][2]], + [mat[2][0], mat[2][1], mat[2][2]], + [mat[3][0], mat[3][1], mat[3][2]], + ]); + prefab.mesh.push((aff, mesh)) + }) +} -- cgit v1.2.3-70-g09d2