prop texture wip

This commit is contained in:
Robin Appelman 2023-12-10 17:26:26 +01:00
commit b4ebf00889
7 changed files with 115 additions and 66 deletions

33
Cargo.lock generated
View file

@ -1337,9 +1337,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.150" version = "0.2.151"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -1530,12 +1530,6 @@ dependencies = [
"syn 2.0.39", "syn 2.0.39",
] ]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.3.7" version = "0.3.7"
@ -1672,16 +1666,6 @@ version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"
@ -2528,7 +2512,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "533127ad49314bfe71c3d3fd36b3ebac3d24f40618092e70e1cfe8362c7fac79" checksum = "533127ad49314bfe71c3d3fd36b3ebac3d24f40618092e70e1cfe8362c7fac79"
dependencies = [ dependencies = [
"nom 1.2.4", "nom",
] ]
[[package]] [[package]]
@ -3030,7 +3014,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "vmdl" name = "vmdl"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/icewind1991/vmdl#377e1773c087463f06c71e0674c1a5dcb9a60f54" source = "git+https://github.com/icewind1991/vmdl#70a6adebdd8f6b7d60625c2539aa3e68403526fb"
dependencies = [ dependencies = [
"arrayvec 0.7.4", "arrayvec 0.7.4",
"bitflags 1.3.2", "bitflags 1.3.2",
@ -3055,7 +3039,7 @@ dependencies = [
[[package]] [[package]]
name = "vtf" name = "vtf"
version = "0.1.5" version = "0.1.5"
source = "git+https://github.com/roman901/vtf-rs?rev=a346cb6d85c2766fe7e30b0a70b6f38e67c3a6c9#a346cb6d85c2766fe7e30b0a70b6f38e67c3a6c9" source = "git+https://github.com/roman901/vtf-rs?rev=55670df#55670df9acd8463d9e8a78d1217d1570385f3582"
dependencies = [ dependencies = [
"byteorder 1.5.0", "byteorder 1.5.0",
"err-derive 0.2.4", "err-derive 0.2.4",
@ -3495,12 +3479,9 @@ dependencies = [
[[package]] [[package]]
name = "xcursor" name = "xcursor"
version = "0.3.4" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
dependencies = [
"nom 7.1.3",
]
[[package]] [[package]]
name = "xml-rs" name = "xml-rs"

View file

@ -24,7 +24,7 @@ tf-demo-parser = { version = "0.4.0", git = "https://github.com/demostf/parser"
steamid-ng = "1.0.0" steamid-ng = "1.0.0"
clap = { version = "4.0.29", features = ["derive"] } clap = { version = "4.0.29", features = ["derive"] }
splines = { version = "4.1.1", features = ["cgmath"] } splines = { version = "4.1.1", features = ["cgmath"] }
vtf = { version = "0.1.5", git = "https://github.com/roman901/vtf-rs", rev = "a346cb6d85c2766fe7e30b0a70b6f38e67c3a6c9" } vtf = { version = "0.1.5", git = "https://github.com/roman901/vtf-rs", rev = "55670df" }
[profile.dev.package."*"] [profile.dev.package."*"]
opt-level = 2 opt-level = 2

View file

@ -9,11 +9,13 @@ 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;
use vtf::vtf::VTF;
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuModel>, Error> { pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuModel>, Error> {
let (cpu_model, bsp) = load_world(data, loader)?; let (cpu_model, bsp) = load_world(data, loader)?;
let merged_props = load_props(loader, bsp.static_props())?; let mut props = load_props(loader, bsp.static_props())?;
Ok(vec![cpu_model, merged_props]) props.insert(0, cpu_model);
Ok(props)
} }
fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 { fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 {
@ -125,31 +127,17 @@ fn model_to_model(model: Handle<vbsp::data::Model>, loader: &Loader) -> CpuModel
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<CpuModel, Error> { ) -> Result<Vec<CpuModel>, Error> {
let material = CpuMaterial {
albedo: Color {
r: 128,
g: 128,
b: 128,
a: 255,
},
..Default::default()
};
let props = props.map(|prop| { let props = 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 })
}); });
let geometries = props
.map(|res| res.map(prop_to_mesh))
.collect::<Result<_, Error>>()?;
Ok(CpuModel { props
geometries, .map(|res| res.map(|prop| prop_to_model(prop, loader)))
materials: vec![material], .collect::<Result<_, Error>>()
})
} }
#[tracing::instrument(skip(loader))] #[tracing::instrument(skip(loader))]
@ -166,36 +154,98 @@ struct ModelData {
transform: Mat4, transform: Mat4,
} }
fn prop_to_mesh(prop: ModelData) -> CpuMesh { fn prop_to_model(prop: ModelData, loader: &Loader) -> CpuModel {
let transform = prop.transform; let transform = prop.transform;
let normal_transform = transform.invert().unwrap().transpose() * -1.0; let normal_transform = transform.invert().unwrap().transpose() * -1.0;
let model = prop.model; let model = prop.model;
let positions = model let skin = model.skin_tables().next().unwrap();
.vertices()
.iter() let geometries = model
.map(|v| map_coords(v.position)) .meshes()
.map(|v| apply_transform(v, transform)) .map(|mesh| {
.collect(); let texture = skin
let normals = model .texture(mesh.material_index())
.vertices() .expect("texture out of bounds");
.iter()
.map(|v| map_coords(v.normal)) let positions: Vec<Vec3> = mesh
.map(|v| apply_transform(v, normal_transform)) .vertices()
.collect(); .map(|vertex| map_coords(vertex.position))
let indices = model .map(|v| apply_transform(v, transform))
.vertex_strip_indices() .collect();
.flat_map(|strip| strip.map(|index| index as u32)) let normals: Vec<Vec3> = mesh
.vertices()
.map(|vertex| map_coords(vertex.normal))
.map(|v| apply_transform(v, normal_transform))
.collect();
let uvs: Vec<Vec2> = mesh
.vertices()
.map(|vertex| Vec2 {
x: vertex.texture_coordinates[0],
y: vertex.texture_coordinates[1],
})
.collect();
CpuMesh {
positions: Positions::F32(positions),
normals: Some(normals),
uvs: Some(uvs),
material_name: Some(texture.into()),
..Default::default()
}
})
.collect(); .collect();
CpuMesh { let materials = model
positions: Positions::F32(positions), .textures()
normals: Some(normals), .iter()
indices: Indices::U32(indices), .map(|texture| {
..Default::default() let dirs = model.texture_directories();
match load_texture(&texture.name, dirs, loader) {
Ok(texture) => CpuMaterial {
albedo: Color::default(),
name: texture.name.clone(),
albedo_texture: Some(texture),
..Default::default()
},
Err(e) => CpuMaterial {
albedo: Color {
r: 255,
g: 0,
b: 255,
a: 255,
},
name: texture.name.clone(),
..Default::default()
},
}
})
.collect();
CpuModel {
materials,
geometries,
} }
} }
fn load_texture(name: &str, dirs: &[String], loader: &Loader) -> Result<CpuTexture, Error> {
let dirs = dirs
.iter()
.map(|dir| format!("materials/{}", dir))
.collect::<Vec<_>>();
let path = format!("{}.vtf", name);
let mut raw = loader.load_from_paths(&path, &dirs)?;
let vtf = VTF::read(&mut raw)?;
let image = vtf.highres_image.decode(0)?;
Ok(CpuTexture {
name: name.into(),
data: TextureData::RgbaU8(image.into_rgba8().pixels().map(|pixel| pixel.0).collect()),
height: vtf.header.height as u32,
width: vtf.header.width as u32,
..CpuTexture::default()
})
}
fn load_world(data: &[u8], loader: &mut Loader) -> Result<(CpuModel, Bsp), Error> { fn load_world(data: &[u8], loader: &mut Loader) -> Result<(CpuModel, Bsp), Error> {
let bsp = Bsp::read(data)?; let bsp = Bsp::read(data)?;

View file

@ -92,4 +92,14 @@ impl Loader {
error!("Failed to find {} in vpk", name); error!("Failed to find {} in vpk", name);
Err(Error::Other("Can't find file in vpks")) Err(Error::Other("Can't find file in vpks"))
} }
pub fn load_from_paths(&self, name: &str, paths: &[String]) -> Result<Vec<u8>, Error> {
for path in paths {
if let Ok(data) = self.load(&format!("{}{}", path, name)) {
return Ok(data);
}
}
error!("Failed to find {} in vpk paths: {}", name, paths.join(", "));
Err(Error::Other("Can't find file in vpks"))
}
} }

View file

@ -42,6 +42,8 @@ pub enum Error {
#[error(transparent)] #[error(transparent)]
Vpk(#[from] vpk::Error), Vpk(#[from] vpk::Error),
#[error(transparent)] #[error(transparent)]
Vtf(#[from] vtf::Error),
#[error(transparent)]
Mdl(#[from] vmdl::ModelError), Mdl(#[from] vmdl::ModelError),
#[error(transparent)] #[error(transparent)]
Demo(#[from] tf_demo_parser::ParseError), Demo(#[from] tf_demo_parser::ParseError),

View file

@ -135,6 +135,10 @@ impl<C: Control> Renderer<C> {
let position_material = PositionMaterial::default(); let position_material = PositionMaterial::default();
target.render_with_material(&position_material, &self.camera, geometries, lights) target.render_with_material(&position_material, &self.camera, geometries, lights)
} }
DebugType::Uv => {
let uv_material = UVMaterial::default();
target.render_with_material(&uv_material, &self.camera, geometries, lights)
}
DebugType::Color => target.render_with_material( DebugType::Color => target.render_with_material(
&ColorMaterial::default(), &ColorMaterial::default(),
&self.camera, &self.camera,

View file

@ -10,6 +10,7 @@ pub enum DebugType {
Color, Color,
Depth, Depth,
Orm, Orm,
Uv,
None, None,
} }
@ -70,6 +71,7 @@ impl DebugUI {
ui.radio_value(&mut self.debug_type, DebugType::Normal, "Normal"); ui.radio_value(&mut self.debug_type, DebugType::Normal, "Normal");
ui.radio_value(&mut self.debug_type, DebugType::Color, "Color"); ui.radio_value(&mut self.debug_type, DebugType::Color, "Color");
ui.radio_value(&mut self.debug_type, DebugType::Depth, "Depth"); ui.radio_value(&mut self.debug_type, DebugType::Depth, "Depth");
ui.radio_value(&mut self.debug_type, DebugType::Uv, "UV");
ui.radio_value(&mut self.debug_type, DebugType::Orm, "ORM"); ui.radio_value(&mut self.debug_type, DebugType::Orm, "ORM");
ui.label("View options"); ui.label("View options");