mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
prop texture wip
This commit is contained in:
parent
505d6d4844
commit
b4ebf00889
7 changed files with 115 additions and 66 deletions
33
Cargo.lock
generated
33
Cargo.lock
generated
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
112
src/bsp.rs
112
src/bsp.rs
|
|
@ -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,34 +154,96 @@ 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();
|
||||||
|
|
||||||
|
let geometries = model
|
||||||
|
.meshes()
|
||||||
|
.map(|mesh| {
|
||||||
|
let texture = skin
|
||||||
|
.texture(mesh.material_index())
|
||||||
|
.expect("texture out of bounds");
|
||||||
|
|
||||||
|
let positions: Vec<Vec3> = mesh
|
||||||
.vertices()
|
.vertices()
|
||||||
.iter()
|
.map(|vertex| map_coords(vertex.position))
|
||||||
.map(|v| map_coords(v.position))
|
|
||||||
.map(|v| apply_transform(v, transform))
|
.map(|v| apply_transform(v, transform))
|
||||||
.collect();
|
.collect();
|
||||||
let normals = model
|
let normals: Vec<Vec3> = mesh
|
||||||
.vertices()
|
.vertices()
|
||||||
.iter()
|
.map(|vertex| map_coords(vertex.normal))
|
||||||
.map(|v| map_coords(v.normal))
|
|
||||||
.map(|v| apply_transform(v, normal_transform))
|
.map(|v| apply_transform(v, normal_transform))
|
||||||
.collect();
|
.collect();
|
||||||
let indices = model
|
let uvs: Vec<Vec2> = mesh
|
||||||
.vertex_strip_indices()
|
.vertices()
|
||||||
.flat_map(|strip| strip.map(|index| index as u32))
|
.map(|vertex| Vec2 {
|
||||||
|
x: vertex.texture_coordinates[0],
|
||||||
|
y: vertex.texture_coordinates[1],
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
CpuMesh {
|
CpuMesh {
|
||||||
positions: Positions::F32(positions),
|
positions: Positions::F32(positions),
|
||||||
normals: Some(normals),
|
normals: Some(normals),
|
||||||
indices: Indices::U32(indices),
|
uvs: Some(uvs),
|
||||||
|
material_name: Some(texture.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let materials = model
|
||||||
|
.textures()
|
||||||
|
.iter()
|
||||||
|
.map(|texture| {
|
||||||
|
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> {
|
||||||
|
|
|
||||||
|
|
@ -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"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue