mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
props wip
This commit is contained in:
parent
2d3a399433
commit
1b477dfb40
4 changed files with 278 additions and 12 deletions
113
Cargo.lock
generated
113
Cargo.lock
generated
|
|
@ -78,6 +78,15 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "approx"
|
||||
version = "0.4.0"
|
||||
|
|
@ -1309,6 +1318,15 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
|
|
@ -1928,6 +1946,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
|
|
@ -2122,6 +2149,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "shared_library"
|
||||
version = "0.1.9"
|
||||
|
|
@ -2317,6 +2353,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "three-d"
|
||||
version = "0.10.2"
|
||||
|
|
@ -2432,9 +2477,21 @@ checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
|
|||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"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]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.23"
|
||||
|
|
@ -2442,6 +2499,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
|
||||
dependencies = [
|
||||
"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]]
|
||||
|
|
@ -2522,6 +2622,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "vbsp"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2551,12 +2657,16 @@ dependencies = [
|
|||
name = "vbspview"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cgmath",
|
||||
"delaunator",
|
||||
"itertools",
|
||||
"miette",
|
||||
"steamlocate",
|
||||
"thiserror",
|
||||
"three-d",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-tree",
|
||||
"vbsp",
|
||||
"vmdl",
|
||||
"vpk",
|
||||
|
|
@ -2584,13 +2694,12 @@ dependencies = [
|
|||
"itertools",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vpk"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7d3cd4401c0b2a781c6ef77ba639b1235b483147c021d4cc845b70063a6b79c"
|
||||
dependencies = [
|
||||
"binread",
|
||||
"thiserror",
|
||||
|
|
|
|||
|
|
@ -13,8 +13,12 @@ thiserror = "1.0.30"
|
|||
delaunator = "1.0.1"
|
||||
itertools = "0.10.3"
|
||||
steamlocate = "1.0.1"
|
||||
vpk = "0.1.2"
|
||||
vpk = { version = "0.1.2", path = "../vpk-rs" }
|
||||
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."*"]
|
||||
opt-level = 2
|
||||
54
src/loader.rs
Normal file
54
src/loader.rs
Normal 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"))
|
||||
}
|
||||
}
|
||||
117
src/main.rs
117
src/main.rs
|
|
@ -1,38 +1,67 @@
|
|||
mod camera;
|
||||
mod loader;
|
||||
|
||||
use camera::FirstPerson;
|
||||
use cgmath::Euler;
|
||||
use itertools::Either;
|
||||
use loader::Loader;
|
||||
use std::env::args;
|
||||
use std::fs;
|
||||
use thiserror::Error;
|
||||
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)]
|
||||
enum Error {
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Three(#[from] Box<dyn std::error::Error>),
|
||||
#[error(transparent)]
|
||||
Bsp(#[from] vbsp::BspError),
|
||||
#[error(transparent)]
|
||||
IO(#[from] std::io::Error),
|
||||
#[error(transparent)]
|
||||
Vpk(#[from] vpk::Error),
|
||||
#[error(transparent)]
|
||||
Mdl(#[from] vmdl::ModelError),
|
||||
#[error("{0}")]
|
||||
Other(&'static str),
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
fn from(e: &'static str) -> Self {
|
||||
Error::Other(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
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 bin = args.next().unwrap();
|
||||
let _bin = args.next().unwrap();
|
||||
let file = match args.next() {
|
||||
Some(file) => file,
|
||||
None => {
|
||||
eprintln!("usage: {} <file.bsp>", bin);
|
||||
return Ok(());
|
||||
"koth_bagel_rc2a.bsp".into()
|
||||
// eprintln!("usage: {} <file.bsp>", bin);
|
||||
// return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let loader = Loader::new()?;
|
||||
|
||||
let window = Window::new(WindowSettings {
|
||||
title: file.clone(),
|
||||
max_size: Some((1920, 1080)),
|
||||
|
|
@ -45,8 +74,7 @@ fn main() -> Result<(), Error> {
|
|||
|
||||
let context = window.gl().unwrap();
|
||||
|
||||
let mut cpu_mesh = model_to_mesh(world_model);
|
||||
cpu_mesh.compute_normals();
|
||||
let cpu_mesh = model_to_mesh(world_model);
|
||||
let forward_pipeline = ForwardPipeline::new(&context).unwrap();
|
||||
let mut camera = Camera::new_perspective(
|
||||
&context,
|
||||
|
|
@ -72,7 +100,12 @@ fn main() -> Result<(), Error> {
|
|||
..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 {
|
||||
ambient: Some(AmbientLight {
|
||||
|
|
@ -176,6 +209,13 @@ fn main() -> Result<(), Error> {
|
|||
&camera,
|
||||
&lights,
|
||||
)?;
|
||||
for prop in &props {
|
||||
prop.render_with_material(
|
||||
&NormalMaterial::from_physical_material(&model.material),
|
||||
&camera,
|
||||
&lights,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
DebugType::DEPTH => {
|
||||
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))
|
||||
.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)
|
||||
.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 {
|
||||
positions,
|
||||
normals: Some(normals),
|
||||
indices: Some(indices),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue