dynamic props

This commit is contained in:
Robin Appelman 2024-08-28 23:39:03 +02:00
commit 9689dbf7ae
7 changed files with 476 additions and 413 deletions

792
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -8,12 +8,11 @@ license = "MIT"
[dependencies] [dependencies]
three-d = { version = "0.16.3", features = ["egui-gui"] } three-d = { version = "0.16.3", features = ["egui-gui"] }
three-d-asset = { version = "0.6" } three-d-asset = { version = "0.6" }
vbsp = "0.4.0" vbsp = "0.5.0"
miette = { version = "5.5.0", features = ["fancy"] } miette = { version = "5.5.0", features = ["fancy"] }
thiserror = "1.0.37" thiserror = "1.0.37"
itertools = "0.12.0" itertools = "0.12.0"
vmdl = "0.1.0" vmdl = "0.2.0"
#vmdl = { version = "*", path = "../vmdl" }
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing-tree = "0.3.0" tracing-tree = "0.3.0"
@ -30,6 +29,9 @@ rayon = "1.8.0"
bytemuck = "1.14.0" bytemuck = "1.14.0"
texpresso = { version = "2.0.1", features = ["rayon"] } texpresso = { version = "2.0.1", features = ["rayon"] }
[patch.crates-io]
vbsp = { path = "../bsp" }
vmdl = { path = "../vmdl" }
[profile.dev.package."*"] [profile.dev.package."*"]
opt-level = 2 opt-level = 2

35
flake.lock generated
View file

@ -10,11 +10,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1689107909, "lastModified": 1717704286,
"narHash": "sha256-fb+zxf7AWesECHx1foXOM3NcKHLrdeXzGb6s2AhT6pE=", "narHash": "sha256-zrLB/FTKODEAlJjgO8TwbK7teTseYbjLESp8QJ/FJYc=",
"owner": "icewind1991", "owner": "icewind1991",
"repo": "cross-naersk", "repo": "cross-naersk",
"rev": "51de54599de569e6faa2ee33dd659c5c028d9911", "rev": "9068daceb8f0d248dcf629944f60e92b81391bdb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -30,11 +30,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1698420672, "lastModified": 1721727458,
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=", "narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "naersk", "repo": "naersk",
"rev": "aeb58d5e8faead8980a807c840232697982d47b9", "rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -45,16 +45,16 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1703467016, "lastModified": 1724316499,
"narHash": "sha256-/5A/dNPhbQx/Oa2d+Get174eNI3LERQ7u6WTWOlR1eQ=", "narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d02d818f22c777aa4e854efc3242ec451e5d462a", "rev": "797f7dc49e0bc7fab4b57c021cdf68f595e47841",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "id": "nixpkgs",
"ref": "nixos-23.11", "ref": "nixos-24.05",
"type": "indirect" "type": "indirect"
} }
}, },
@ -69,19 +69,16 @@
}, },
"rust-overlay": { "rust-overlay": {
"inputs": { "inputs": {
"flake-utils": [
"utils"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1703643208, "lastModified": 1724638882,
"narHash": "sha256-UL4KO8JxnD5rOycwHqBAf84lExF1/VnYMDC7b/wpPDU=", "narHash": "sha256-ap2jIQi/FuUHR6HCht6ASWhoz8EiB99XmI8Esot38VE=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "ce117f3e0de8262be8cd324ee6357775228687cf", "rev": "19b70f147b9c67a759e35824b241f1ed92e46694",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -110,11 +107,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1701680307, "lastModified": 1710146030,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -1,6 +1,6 @@
{ {
inputs = { inputs = {
nixpkgs.url = "nixpkgs/nixos-23.11"; nixpkgs.url = "nixpkgs/nixos-24.05";
utils.url = "github:numtide/flake-utils"; utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk"; naersk.url = "github:nix-community/naersk";
naersk.inputs.nixpkgs.follows = "nixpkgs"; naersk.inputs.nixpkgs.follows = "nixpkgs";

View file

@ -18,8 +18,21 @@ pub fn load_map(
let (world, bsp) = load_world(data, loader, textures)?; let (world, bsp) = load_world(data, loader, textures)?;
let mut models = Vec::with_capacity(bsp.static_props().count() + 1); let mut models = Vec::with_capacity(bsp.static_props().count() + 1);
models.push(world); models.push(world);
// println!("{:#?}", bsp.entities);
let entity_props =
bsp.entities
.iter()
.flat_map(|ent| ent.parse())
.filter_map(|ent| match ent {
Entity::PropDynamic(prop) => Some(prop.as_prop_placement()),
Entity::PropPhysics(prop) => Some(prop.as_prop_placement()),
Entity::PropDynamicOverride(prop) => Some(prop.as_prop_placement()),
_ => None,
});
let static_props = bsp.static_props().map(|prop| prop.as_prop_placement());
if props { if props {
let props = load_props(loader, bsp.static_props(), textures)?; let props = load_props(loader, static_props.chain(entity_props), textures)?;
models.extend(props); models.extend(props);
} }
Ok(models) Ok(models)
@ -119,7 +132,7 @@ fn model_to_model(
fn load_world(data: &[u8], loader: &mut Loader, textures: bool) -> Result<(CpuModel, Bsp), Error> { fn load_world(data: &[u8], loader: &mut Loader, textures: bool) -> Result<(CpuModel, Bsp), Error> {
let bsp = Bsp::read(data)?; let bsp = Bsp::read(data)?;
loader.add_source(bsp.pack.clone()); loader.add_source(bsp.pack.clone().into_zip());
let world_model = bsp let world_model = bsp
.models() .models()

View file

@ -6,8 +6,8 @@ use three_d::{CpuMaterial, CpuTexture};
use three_d_asset::Srgba; use three_d_asset::Srgba;
use tracing::{error, instrument}; use tracing::{error, instrument};
use vmdl::mdl::TextureInfo; use vmdl::mdl::TextureInfo;
use vmt_parser::from_str;
use vmt_parser::material::{Material, WaterMaterial}; use vmt_parser::material::{Material, WaterMaterial};
use vmt_parser::{from_str, TextureTransform};
use vtf::vtf::VTF; use vtf::vtf::VTF;
pub fn load_material_fallback(name: &str, loader: &Loader) -> MaterialData { pub fn load_material_fallback(name: &str, loader: &Loader) -> MaterialData {
@ -32,6 +32,7 @@ pub struct MaterialData {
pub alpha_test: Option<f32>, pub alpha_test: Option<f32>,
pub bump_map: Option<TextureData>, pub bump_map: Option<TextureData>,
pub translucent: bool, pub translucent: bool,
pub transform: Option<TextureTransform>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -75,10 +76,8 @@ pub fn load_material(path: &str, loader: &Loader) -> Result<MaterialData, Error>
return Ok(MaterialData { return Ok(MaterialData {
color: [82, 180, 217, 128], color: [82, 180, 217, 128],
path, path,
texture: None,
bump_map: None,
alpha_test: None,
translucent: true, translucent: true,
..MaterialData::default()
}); });
} }
@ -98,6 +97,11 @@ pub fn load_material(path: &str, loader: &Loader) -> Result<MaterialData, Error>
}) })
}); });
let transform = material
.base_texture_transform()
.filter(|transform| **transform != TextureTransform::default())
.cloned();
Ok(MaterialData { Ok(MaterialData {
color: [255; 4], color: [255; 4],
path, path,
@ -108,6 +112,7 @@ pub fn load_material(path: &str, loader: &Loader) -> Result<MaterialData, Error>
bump_map, bump_map,
alpha_test, alpha_test,
translucent: translucent | glass, translucent: translucent | glass,
transform,
}) })
} }

View file

@ -1,3 +1,4 @@
use cgmath::Matrix4;
use crate::bsp::map_coords; use crate::bsp::map_coords;
use crate::material::{convert_material, load_material_fallback, MaterialSet}; use crate::material::{convert_material, load_material_fallback, MaterialSet};
use crate::Error; use crate::Error;
@ -6,10 +7,11 @@ use tf_asset_loader::Loader;
use three_d::{CpuMaterial, CpuModel, Mat4, Positions, Vec2, Vec3, Vec4}; use three_d::{CpuMaterial, CpuModel, Mat4, Positions, Vec2, Vec3, Vec4};
use three_d_asset::{Geometry, Primitive, TriMesh}; use three_d_asset::{Geometry, Primitive, TriMesh};
use tracing::{error, warn}; use tracing::{error, warn};
use vbsp::{Handle, StaticPropLump}; use vbsp::PropPlacement;
use vmdl::mdl::Mdl; use vmdl::mdl::Mdl;
use vmdl::vtx::Vtx; use vmdl::vtx::Vtx;
use vmdl::vvd::Vvd; use vmdl::vvd::Vvd;
use cgmath::SquareMatrix;
#[tracing::instrument(skip(loader))] #[tracing::instrument(skip(loader))]
pub fn load_prop(loader: &Loader, name: &str) -> Result<vmdl::Model, Error> { pub fn load_prop(loader: &Loader, name: &str) -> Result<vmdl::Model, Error> {
@ -24,24 +26,29 @@ pub fn load_prop(loader: &Loader, name: &str) -> Result<vmdl::Model, Error> {
Ok(vmdl::Model::from_parts(mdl, vtx, vvd)) Ok(vmdl::Model::from_parts(mdl, vtx, vvd))
} }
pub fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>( pub fn load_props<'a, I: Iterator<Item = PropPlacement<'a>>>(
loader: &Loader, loader: &Loader,
props: I, props: I,
show_textures: bool, show_textures: bool,
) -> Result<Vec<CpuModel>, Error> { ) -> Result<Vec<CpuModel>, Error> {
let props: Vec<_> = props let props: Vec<_> = props
.filter_map(|prop| match load_prop(loader, prop.model()) { .filter_map(|prop| match load_prop(loader, prop.model) {
Ok(model) => Some((prop, model)), Ok(model) => Some((prop, model)),
Err(e) => { Err(e) => {
error!(error = ?e, prop = prop.model(), "Failed to load prop"); error!(error = ?e, prop = prop.model, "Failed to load prop");
None None
} }
}) })
.map(|(prop, model)| { .map(|(prop, model)| {
let transform = let root_transform = model.root_transform();
Mat4::from_translation(map_coords(prop.origin)) * Mat4::from(prop.rotation()); if !root_transform.is_identity() {
eprintln!("{}: {:?}", model.name(), root_transform);
}
let transform = Mat4::from_translation(map_coords(prop.origin))
* Mat4::from(prop.rotation)
* Mat4::from_scale(prop.scale);
PropData { PropData {
name: prop.model(), name: prop.model,
model, model,
transform, transform,
skin: prop.skin, skin: prop.skin,
@ -102,7 +109,8 @@ fn prop_to_meshes<'a>(
let positions: Vec<Vec3> = mesh let positions: Vec<Vec3> = mesh
.vertices() .vertices()
.map(|vertex| map_coords(vertex.position)) .map(|vertex| model.vertex_to_world_space(vertex))
.map(|vertex| map_coords(vertex))
.collect(); .collect();
let normals: Vec<Vec3> = mesh let normals: Vec<Vec3> = mesh
.vertices() .vertices()