summaryrefslogtreecommitdiff
path: root/world/src
diff options
context:
space:
mode:
Diffstat (limited to 'world/src')
-rw-r--r--world/src/main.rs267
-rw-r--r--world/src/mesh.rs262
2 files changed, 291 insertions, 238 deletions
diff --git a/world/src/main.rs b/world/src/main.rs
index ce50cea..bbbe4f9 100644
--- a/world/src/main.rs
+++ b/world/src/main.rs
@@ -15,10 +15,13 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#![feature(iter_array_chunks)]
+pub mod mesh;
+
use anyhow::{Result, bail};
use clap::Parser;
use gltf::image::Source;
-use log::{debug, info};
+use log::info;
+use mesh::import_mesh;
use rand::random;
use std::{
fs::File,
@@ -29,9 +32,9 @@ use std::{
time::Duration,
};
use weareshared::{
- Affine3A, Vec3A,
+ Vec3A,
packets::{Data, Object, Packet, ReadWrite, Resource},
- resources::{AttributeArray, IndexArray, MeshPart, Prefab},
+ resources::{Image, LightPart, Prefab},
store::ResourceStore,
vec3a,
};
@@ -44,6 +47,8 @@ struct Args {
push: bool,
#[arg(short, long)]
spin: bool,
+ #[arg(short, long)]
+ clear: bool,
}
fn main() -> Result<()> {
@@ -61,241 +66,20 @@ fn main() -> Result<()> {
let mut prefab = Prefab::default();
for node in gltf.nodes() {
if let Some(mesh) = node.mesh() {
- 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).write_alloc())?,
- store.set(&AttributeArray(pos_y).write_alloc())?,
- store.set(&AttributeArray(pos_z).write_alloc())?,
- ])
- })
- .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).write_alloc())?,
- store.set(&AttributeArray(normal_y).write_alloc())?,
- store.set(&AttributeArray(normal_z).write_alloc())?,
- ])
- })
- .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).write_alloc())?,
- store.set(&AttributeArray(texcoord_v).write_alloc())?,
- ])
- })
- .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).write_alloc())?,
- store.set(&AttributeArray(color_g).write_alloc())?,
- store.set(&AttributeArray(color_b).write_alloc())?,
- ])
- })
- .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).write_alloc())?)
- } 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::<Vec<_>>();
- info!("{} indecies", index.len() * 3);
- let index = Some(store.set(&IndexArray(index).write_alloc())?);
-
- 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);
- tex_transmission = Some(r);
- }
- 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);
- tex_metallic = Some(r);
- }
-
- 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
- }
- .write_alloc(),
- )?;
- 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))
- }
+ import_mesh(mesh, &buffers, &store, path_base, &node, &mut prefab)?;
}
}
+ prefab.light.push((
+ vec3a(5., 5., 5.),
+ store.set(&LightPart {
+ emission: Some(vec3a(0.5, 0.1, 1.0)),
+ radius: Some(0.2),
+ })?,
+ ));
+
let ob = Object::new();
- Packet::Add(ob, store.set(&prefab.write_alloc())?).write(&mut sock)?;
+ Packet::Add(ob, store.set(&prefab)?).write(&mut sock)?;
if args.spin {
let mut sock2 = sock.try_clone().unwrap();
@@ -324,11 +108,18 @@ fn main() -> Result<()> {
let packet = Packet::read(&mut sock)?;
match packet {
Packet::RequestResource(hash) => {
- if let Some(d) = store.get(hash)? {
+ if let Some(d) = store.get_raw(hash)? {
Packet::RespondResource(Data(d)).write(&mut sock)?;
sock.flush()?;
}
}
+ Packet::Add(ob_a, _) => {
+ if ob_a != ob {
+ info!("removing object {ob_a}");
+ Packet::Remove(ob_a).write(&mut sock)?;
+ sock.flush()?;
+ }
+ }
_ => (),
}
}
@@ -342,13 +133,13 @@ fn load_texture(
path: &Path,
buffers: &[gltf::buffer::Data],
source: &Source,
-) -> Result<Resource> {
+) -> Result<Resource<Image>> {
match source {
gltf::image::Source::View { view, mime_type } => {
info!("{name} texture is embedded and of type {mime_type:?}");
let buf =
&buffers[view.buffer().index()].0[view.offset()..view.offset() + view.length()];
- return Ok(store.set(buf)?);
+ return Ok(store.set(&Image(buf.to_vec()))?);
}
gltf::image::Source::Uri {
uri,
@@ -358,7 +149,7 @@ fn load_texture(
let path = path.join(uri);
let mut buf = Vec::new();
File::open(path)?.read_to_end(&mut buf)?;
- return Ok(store.set(&buf)?);
+ return Ok(store.set(&Image(buf))?);
}
_ => {
bail!("texture is external and has no mime type")
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 <https://www.gnu.org/licenses/>.
+*/
+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::<Vec<_>>();
+ 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))
+ })
+}