props wip

This commit is contained in:
Robin Appelman 2022-03-16 23:15:56 +01:00
commit 1b477dfb40
4 changed files with 278 additions and 12 deletions

113
Cargo.lock generated
View file

@ -78,6 +78,15 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "approx" name = "approx"
version = "0.4.0" version = "0.4.0"
@ -1309,6 +1318,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
[[package]] [[package]]
name = "matches" name = "matches"
version = "0.1.9" version = "0.1.9"
@ -1928,6 +1946,15 @@ dependencies = [
"regex-syntax", "regex-syntax",
] ]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax",
]
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.25" version = "0.6.25"
@ -2122,6 +2149,15 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "shared_library" name = "shared_library"
version = "0.1.9" version = "0.1.9"
@ -2317,6 +2353,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "three-d" name = "three-d"
version = "0.10.2" version = "0.10.2"
@ -2432,9 +2477,21 @@ checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"pin-project-lite", "pin-project-lite",
"tracing-attributes",
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-attributes"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.23" version = "0.1.23"
@ -2442,6 +2499,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce"
dependencies = [
"ansi_term",
"lazy_static",
"matchers",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "tracing-tree"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce989c9962c7f61fe084dd4a230eec784649dfc2392467c790007c3a6e134e7"
dependencies = [
"ansi_term",
"atty",
"tracing-core",
"tracing-log",
"tracing-subscriber",
] ]
[[package]] [[package]]
@ -2522,6 +2622,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "vbsp" name = "vbsp"
version = "0.1.0" version = "0.1.0"
@ -2551,12 +2657,16 @@ dependencies = [
name = "vbspview" name = "vbspview"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cgmath",
"delaunator", "delaunator",
"itertools", "itertools",
"miette", "miette",
"steamlocate", "steamlocate",
"thiserror", "thiserror",
"three-d", "three-d",
"tracing",
"tracing-subscriber",
"tracing-tree",
"vbsp", "vbsp",
"vmdl", "vmdl",
"vpk", "vpk",
@ -2584,13 +2694,12 @@ dependencies = [
"itertools", "itertools",
"static_assertions", "static_assertions",
"thiserror", "thiserror",
"tracing",
] ]
[[package]] [[package]]
name = "vpk" name = "vpk"
version = "0.1.2" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7d3cd4401c0b2a781c6ef77ba639b1235b483147c021d4cc845b70063a6b79c"
dependencies = [ dependencies = [
"binread", "binread",
"thiserror", "thiserror",

View file

@ -13,8 +13,12 @@ thiserror = "1.0.30"
delaunator = "1.0.1" delaunator = "1.0.1"
itertools = "0.10.3" itertools = "0.10.3"
steamlocate = "1.0.1" steamlocate = "1.0.1"
vpk = "0.1.2" vpk = { version = "0.1.2", path = "../vpk-rs" }
vmdl = { version = "*", path = "../vmdl" } vmdl = { version = "*", path = "../vmdl" }
tracing = "0.1.29"
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
tracing-tree = "0.2.0"
cgmath = "0.18.0"
[profile.dev.package."*"] [profile.dev.package."*"]
opt-level = 2 opt-level = 2

54
src/loader.rs Normal file
View file

@ -0,0 +1,54 @@
use crate::Error;
use std::fmt::{Debug, Formatter};
use std::path::PathBuf;
use steamlocate::SteamDir;
use tracing::{debug, error};
use vpk::VPK;
pub struct Loader {
tf_dir: PathBuf,
vpks: Vec<VPK>,
}
impl Debug for Loader {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Loader")
.field("tf_dir", &self.tf_dir)
.finish_non_exhaustive()
}
}
impl Loader {
pub fn new() -> Result<Self, Error> {
let tf_dir = SteamDir::locate()
.ok_or("Can't find steam directory")?
.app(&440)
.ok_or("Can't find tf2 directory")?
.path
.join("tf");
let vpks = tf_dir
.read_dir()?
.filter_map(|item| item.ok())
.filter_map(|item| Some(item.path().to_str()?.to_string()))
.filter(|path| path.ends_with(".vpk"))
.map(|path| vpk::from_path(&path))
.filter_map(|res| res.ok())
.collect();
Ok(Loader { tf_dir, vpks })
}
#[tracing::instrument]
pub fn load(&self, name: &str) -> Result<Vec<u8>, Error> {
debug!("loading file from vpk");
for vpk in self.vpks.iter() {
if let Some(entry) = vpk.tree.get(name) {
let data = entry.get()?.into_owned();
debug!("got {} bytes", data.len());
return Ok(data);
}
}
error!("Failed to find file in vpk");
Err(Error::Other("Can't find file in vpks"))
}
}

View file

@ -1,38 +1,67 @@
mod camera; mod camera;
mod loader;
use camera::FirstPerson; use camera::FirstPerson;
use cgmath::Euler;
use itertools::Either; use itertools::Either;
use loader::Loader;
use std::env::args; use std::env::args;
use std::fs; use std::fs;
use thiserror::Error; use thiserror::Error;
use three_d::*; use three_d::*;
use vbsp::{Bsp, Handle}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
use tracing_tree::HierarchicalLayer;
use vbsp::{Bsp, Handle, StaticPropLump};
use vmdl::mdl::Mdl;
use vmdl::vtx::Vtx;
use vmdl::vvd::Vvd;
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
Three(#[from] Box<dyn std::error::Error>), Three(#[from] Box<dyn std::error::Error>),
#[error(transparent)] #[error(transparent)]
Bsp(#[from] vbsp::BspError), Bsp(#[from] vbsp::BspError),
#[error(transparent)] #[error(transparent)]
IO(#[from] std::io::Error), IO(#[from] std::io::Error),
#[error(transparent)]
Vpk(#[from] vpk::Error),
#[error(transparent)]
Mdl(#[from] vmdl::ModelError),
#[error("{0}")] #[error("{0}")]
Other(&'static str), Other(&'static str),
} }
impl From<&'static str> for Error {
fn from(e: &'static str) -> Self {
Error::Other(e)
}
}
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
miette::set_panic_hook(); miette::set_panic_hook();
Registry::default()
.with(EnvFilter::from_default_env())
.with(
HierarchicalLayer::new(2)
.with_targets(true)
.with_bracketed_fields(true),
)
.init();
let mut args = args(); let mut args = args();
let bin = args.next().unwrap(); let _bin = args.next().unwrap();
let file = match args.next() { let file = match args.next() {
Some(file) => file, Some(file) => file,
None => { None => {
eprintln!("usage: {} <file.bsp>", bin); "koth_bagel_rc2a.bsp".into()
return Ok(()); // eprintln!("usage: {} <file.bsp>", bin);
// return Ok(());
} }
}; };
let loader = Loader::new()?;
let window = Window::new(WindowSettings { let window = Window::new(WindowSettings {
title: file.clone(), title: file.clone(),
max_size: Some((1920, 1080)), max_size: Some((1920, 1080)),
@ -45,8 +74,7 @@ fn main() -> Result<(), Error> {
let context = window.gl().unwrap(); let context = window.gl().unwrap();
let mut cpu_mesh = model_to_mesh(world_model); let cpu_mesh = model_to_mesh(world_model);
cpu_mesh.compute_normals();
let forward_pipeline = ForwardPipeline::new(&context).unwrap(); let forward_pipeline = ForwardPipeline::new(&context).unwrap();
let mut camera = Camera::new_perspective( let mut camera = Camera::new_perspective(
&context, &context,
@ -72,7 +100,12 @@ fn main() -> Result<(), Error> {
..Default::default() ..Default::default()
}; };
let model = Model::new_with_material(&context, &cpu_mesh, material)?; let mut model = Model::new_with_material(&context, &cpu_mesh, material.clone())?;
// model.set_transformation(Mat4::from_angle_x(degrees(-90.0)));
let props = bsp
.static_props()
.map(|prop| load_prop(&loader, prop, &context, material.clone()))
.collect::<Result<Vec<_>, _>>()?;
let mut lights = Lights { let mut lights = Lights {
ambient: Some(AmbientLight { ambient: Some(AmbientLight {
@ -176,6 +209,13 @@ fn main() -> Result<(), Error> {
&camera, &camera,
&lights, &lights,
)?; )?;
for prop in &props {
prop.render_with_material(
&NormalMaterial::from_physical_material(&model.material),
&camera,
&lights,
)?;
}
} }
DebugType::DEPTH => { DebugType::DEPTH => {
let mut depth_material = DepthMaterial::default(); let mut depth_material = DepthMaterial::default();
@ -233,12 +273,71 @@ fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
.map(|verts| Either::Left(verts)) .map(|verts| Either::Left(verts))
.unwrap_or_else(|| Either::Right(face.triangulate().flat_map(|verts| verts))) .unwrap_or_else(|| Either::Right(face.triangulate().flat_map(|verts| verts)))
}) })
.flat_map(|vertex| [-vertex.x, vertex.z, vertex.y]) .flat_map(<[f32; 3]>::from)
.map(|c| c * UNIT_SCALE) .map(|c| c * UNIT_SCALE)
.collect(); .collect();
let mut mesh = CPUMesh {
positions,
..Default::default()
};
mesh.compute_normals();
mesh
}
fn load_prop<M: Material>(
loader: &Loader,
prop: Handle<StaticPropLump>,
context: &Context,
material: M,
) -> Result<Model<M>, Error> {
let mesh = load_prop_mesh(loader, prop.model())?;
let mut model = Model::new_with_material(context, &mesh, material)?;
let translation = Mat4::from_translation(<[f32; 3]>::from(prop.origin * UNIT_SCALE).into());
let rotation = Mat4::from(Euler {
x: degrees(prop.angles[0]),
y: degrees(prop.angles[1]),
z: degrees(prop.angles[2]),
});
let world = Mat4::from_angle_x(degrees(-90.0));
model.set_transformation(translation);
Ok(model)
}
#[tracing::instrument(skip(loader))]
fn load_prop_mesh(loader: &Loader, name: &str) -> Result<CPUMesh, Error> {
let mdl = Mdl::read(&loader.load(name)?)?;
let vtx = Vtx::read(&loader.load(&name.replace(".mdl", ".dx90.vtx"))?)?;
let vvd = Vvd::read(&loader.load(&name.replace(".mdl", ".vvd"))?)?;
let model = vmdl::Model::from_parts(mdl, vtx, vvd);
Ok(prop_to_mesh(&model))
}
fn prop_to_mesh(model: &vmdl::Model) -> CPUMesh {
let positions: Vec<f32> = model
.vertices()
.iter()
.flat_map(|vertex| vertex.position.iter().map(|pos| pos * UNIT_SCALE))
.collect();
let normals: Vec<f32> = model
.vertices()
.iter()
.flat_map(|vertex| vertex.normal.iter())
.collect();
let indices = Indices::U32(
model
.vertex_strip_indices()
.flat_map(|strip| strip.map(|index| index as u32))
.collect(),
);
CPUMesh { CPUMesh {
positions, positions,
normals: Some(normals),
indices: Some(indices),
..Default::default() ..Default::default()
} }
} }