texture materials wip

This commit is contained in:
Robin Appelman 2023-12-09 19:00:30 +01:00
commit 43081fedd7
4 changed files with 113 additions and 47 deletions

17
Cargo.lock generated
View file

@ -1159,6 +1159,15 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itertools"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.10" version = "1.0.10"
@ -2423,7 +2432,7 @@ dependencies = [
"enumflags2", "enumflags2",
"err-derive", "err-derive",
"fnv", "fnv",
"itertools", "itertools 0.10.5",
"main_error", "main_error",
"num-traits 0.2.17", "num-traits 0.2.17",
"num_enum 0.5.11", "num_enum 0.5.11",
@ -2694,11 +2703,13 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
name = "vbsp" name = "vbsp"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"ahash 0.8.6",
"arrayvec 0.7.4", "arrayvec 0.7.4",
"binrw", "binrw",
"bitflags 2.4.1", "bitflags 2.4.1",
"bv", "bv",
"cgmath", "cgmath",
"itertools 0.12.0",
"lzma-rs", "lzma-rs",
"num_enum 0.7.1", "num_enum 0.7.1",
"static_assertions", "static_assertions",
@ -2725,7 +2736,7 @@ dependencies = [
"cgmath", "cgmath",
"clap", "clap",
"delaunator", "delaunator",
"itertools", "itertools 0.10.5",
"miette", "miette",
"splines", "splines",
"steamid-ng", "steamid-ng",
@ -2762,7 +2773,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"bytemuck", "bytemuck",
"cgmath", "cgmath",
"itertools", "itertools 0.10.5",
"static_assertions", "static_assertions",
"thiserror", "thiserror",
"tracing", "tracing",

View file

@ -1,17 +1,16 @@
use crate::{Error, Loader}; use crate::{Error, Loader};
use cgmath::{vec4, Matrix, SquareMatrix}; use cgmath::{vec4, Matrix, SquareMatrix};
use itertools::Either; use std::collections::HashMap;
use three_d::{CpuMesh, Indices, Mat4, Positions, Vec3}; use three_d::{Color, CpuMaterial, CpuMesh, CpuModel, Indices, Mat4, Positions, Vec2, Vec3};
use vbsp::{Bsp, Handle, StaticPropLump}; use vbsp::{Bsp, Face, Handle, StaticPropLump};
use vmdl::mdl::Mdl; use vmdl::mdl::Mdl;
use vmdl::vtx::Vtx; use vmdl::vtx::Vtx;
use vmdl::vvd::Vvd; use vmdl::vvd::Vvd;
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuMesh>, Error> { pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuModel>, Error> {
let (cpu_mesh, bsp) = load_world(data)?; let (cpu_model, bsp) = load_world(data, loader)?;
loader.set_pack(bsp.pack.clone());
let merged_props = load_props(loader, bsp.static_props())?; let merged_props = load_props(loader, bsp.static_props())?;
Ok(vec![cpu_mesh, merged_props]) Ok(vec![cpu_model, merged_props])
} }
fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 { fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 {
@ -31,39 +30,105 @@ pub fn map_coords<C: Into<Vec3>>(vec: C) -> Vec3 {
// 1 hammer unit is ~1.905cm // 1 hammer unit is ~1.905cm
pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0); pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CpuMesh { fn face_to_mesh(face: &Handle<Face>) -> CpuMesh {
let positions: Vec<Vec3> = model let texture = face.texture();
.faces() let positions = face.vertex_positions().map(map_coords).collect();
.filter(|face| face.is_visible()) let uvs = face
.flat_map(|face| { .vertex_positions()
face.displacement() .map(|pos| Vec2 {
.map(|displacement| displacement.triangulated_displaced_vertices()) x: texture.u(pos),
.map(Either::Left) y: texture.v(pos),
.unwrap_or_else(|| Either::Right(face.triangulate().flatten()))
}) })
.map(map_coords)
.collect(); .collect();
let mut mesh = CpuMesh { let mut mesh = CpuMesh {
positions: Positions::F32(positions), positions: Positions::F32(positions),
uvs: Some(uvs),
material_name: Some(texture.name().into()),
..Default::default() ..Default::default()
}; };
mesh.compute_normals(); mesh.compute_normals();
mesh mesh
} }
fn model_to_model(model: Handle<vbsp::data::Model>, loader: &Loader) -> CpuModel {
let mut faces_by_texture: HashMap<&str, Vec<_>> = HashMap::with_capacity(64);
for face in model.faces().filter(|face| face.is_visible()) {
faces_by_texture
.entry(face.texture().name())
.or_default()
.push(face)
}
let geometries = faces_by_texture
.values()
.map(|faces| {
let mut faces = faces.iter();
let first = faces.next().unwrap();
let mut mesh = face_to_mesh(first);
for face in faces {
let face_mesh = face_to_mesh(face);
if let Positions::F32(positions) = &mut mesh.positions {
positions.extend_from_slice(&face_mesh.positions.into_f32());
}
if let Some(uvs) = &mut mesh.uvs {
uvs.extend_from_slice(&face_mesh.uvs.unwrap());
}
}
mesh.compute_normals();
mesh
})
.collect();
let materials = faces_by_texture
.values()
.map(|face| {
let texture = face.first().unwrap().texture();
let color = texture.texture().debug_color();
CpuMaterial {
albedo: Color {
r: color[0],
g: color[1],
b: color[2],
a: 255,
},
name: texture.name().into(),
..Default::default()
}
})
.collect();
CpuModel {
geometries,
materials,
}
}
fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>( fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>(
loader: &Loader, loader: &Loader,
props: I, props: I,
) -> Result<CpuMesh, Error> { ) -> Result<CpuModel, Error> {
merge_models(props.map(|prop| { let material = CpuMaterial {
albedo: Color {
r: 128,
g: 128,
b: 128,
a: 255,
},
..Default::default()
};
let mesh = merge_models(props.map(|prop| {
let model = load_prop(loader, prop.model())?; let model = load_prop(loader, prop.model())?;
let transform = let transform =
Mat4::from_translation(map_coords(prop.origin)) * Mat4::from(prop.rotation()); Mat4::from_translation(map_coords(prop.origin)) * Mat4::from(prop.rotation());
Ok(ModelData { model, transform }) Ok(ModelData { model, transform })
})) }))?;
Ok(CpuModel {
geometries: vec![mesh],
materials: vec![material],
})
} }
#[tracing::instrument(skip(loader))] #[tracing::instrument(skip(loader))]
@ -123,9 +188,12 @@ fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Resul
}) })
} }
fn load_world(data: &[u8]) -> Result<(CpuMesh, Bsp), Error> { fn load_world(data: &[u8], loader: &mut Loader) -> Result<(CpuModel, Bsp), Error> {
let bsp = Bsp::read(data)?; let bsp = Bsp::read(data)?;
loader.set_pack(bsp.pack.clone());
let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?; let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?;
Ok((model_to_mesh(world_model), bsp)) Ok((model_to_model(world_model, loader), bsp))
} }

View file

@ -88,39 +88,26 @@ fn main() -> Result<(), Error> {
let mut loader = Loader::new()?; let mut loader = Loader::new()?;
let map = loader.load(&format!("maps/{}.bsp", demo.map))?; let map = loader.load(&format!("maps/{}.bsp", demo.map))?;
let meshes = load_map(&map, &mut loader)?; let models = load_map(&map, &mut loader)?;
play(window, DemoCamera::new(demo), meshes) play(window, DemoCamera::new(demo), models)
} else { } else {
let mut loader = Loader::new()?; let mut loader = Loader::new()?;
let map = fs::read(args.path)?; let map = fs::read(args.path)?;
let meshes = load_map(&map, &mut loader)?; let models = load_map(&map, &mut loader)?;
play(window, FirstPerson::new(0.1), meshes) play(window, FirstPerson::new(0.1), models)
} }
} }
fn play<C: Control + 'static>( fn play<C: Control + 'static>(
window: Window, window: Window,
control: C, control: C,
meshes: Vec<CpuMesh>, models: Vec<CpuModel>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut renderer = Renderer::new(&window, control); let mut renderer = Renderer::new(&window, control);
let material = CpuMaterial {
albedo: Color {
r: 128,
g: 128,
b: 128,
a: 255,
},
..Default::default()
};
renderer.models = meshes renderer.models = models
.into_iter() .into_iter()
.map(|mesh| CpuModel {
geometries: vec![mesh],
materials: vec![material.clone()],
})
.map(|model| Model::new(&renderer.context, &model)) .map(|model| Model::new(&renderer.context, &model))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;

View file

@ -32,7 +32,7 @@ impl DebugUI {
ambient_intensity: 0.2, ambient_intensity: 0.2,
depth_max: 30.0, depth_max: 30.0,
fov: 60.0, fov: 60.0,
debug_type: DebugType::Normal, debug_type: DebugType::None,
} }
} }