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

View file

@ -1,17 +1,16 @@
use crate::{Error, Loader};
use cgmath::{vec4, Matrix, SquareMatrix};
use itertools::Either;
use three_d::{CpuMesh, Indices, Mat4, Positions, Vec3};
use vbsp::{Bsp, Handle, StaticPropLump};
use std::collections::HashMap;
use three_d::{Color, CpuMaterial, CpuMesh, CpuModel, Indices, Mat4, Positions, Vec2, Vec3};
use vbsp::{Bsp, Face, Handle, StaticPropLump};
use vmdl::mdl::Mdl;
use vmdl::vtx::Vtx;
use vmdl::vvd::Vvd;
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuMesh>, Error> {
let (cpu_mesh, bsp) = load_world(data)?;
loader.set_pack(bsp.pack.clone());
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuModel>, Error> {
let (cpu_model, bsp) = load_world(data, loader)?;
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 {
@ -31,39 +30,105 @@ pub fn map_coords<C: Into<Vec3>>(vec: C) -> Vec3 {
// 1 hammer unit is ~1.905cm
pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CpuMesh {
let positions: Vec<Vec3> = model
.faces()
.filter(|face| face.is_visible())
.flat_map(|face| {
face.displacement()
.map(|displacement| displacement.triangulated_displaced_vertices())
.map(Either::Left)
.unwrap_or_else(|| Either::Right(face.triangulate().flatten()))
fn face_to_mesh(face: &Handle<Face>) -> CpuMesh {
let texture = face.texture();
let positions = face.vertex_positions().map(map_coords).collect();
let uvs = face
.vertex_positions()
.map(|pos| Vec2 {
x: texture.u(pos),
y: texture.v(pos),
})
.map(map_coords)
.collect();
let mut mesh = CpuMesh {
positions: Positions::F32(positions),
uvs: Some(uvs),
material_name: Some(texture.name().into()),
..Default::default()
};
mesh.compute_normals();
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>>>(
loader: &Loader,
props: I,
) -> Result<CpuMesh, Error> {
merge_models(props.map(|prop| {
) -> Result<CpuModel, Error> {
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 transform =
Mat4::from_translation(map_coords(prop.origin)) * Mat4::from(prop.rotation());
Ok(ModelData { model, transform })
}))
}))?;
Ok(CpuModel {
geometries: vec![mesh],
materials: vec![material],
})
}
#[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)?;
loader.set_pack(bsp.pack.clone());
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 map = loader.load(&format!("maps/{}.bsp", demo.map))?;
let meshes = load_map(&map, &mut loader)?;
play(window, DemoCamera::new(demo), meshes)
let models = load_map(&map, &mut loader)?;
play(window, DemoCamera::new(demo), models)
} else {
let mut loader = Loader::new()?;
let map = fs::read(args.path)?;
let meshes = load_map(&map, &mut loader)?;
play(window, FirstPerson::new(0.1), meshes)
let models = load_map(&map, &mut loader)?;
play(window, FirstPerson::new(0.1), models)
}
}
fn play<C: Control + 'static>(
window: Window,
control: C,
meshes: Vec<CpuMesh>,
models: Vec<CpuModel>,
) -> Result<(), Error> {
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()
.map(|mesh| CpuModel {
geometries: vec![mesh],
materials: vec![material.clone()],
})
.map(|model| Model::new(&renderer.context, &model))
.collect::<Result<_, _>>()?;

View file

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