mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
texture materials wip
This commit is contained in:
parent
2ff1eca534
commit
43081fedd7
4 changed files with 113 additions and 47 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
|
@ -1159,6 +1159,15 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
|
|
@ -2423,7 +2432,7 @@ dependencies = [
|
|||
"enumflags2",
|
||||
"err-derive",
|
||||
"fnv",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"main_error",
|
||||
"num-traits 0.2.17",
|
||||
"num_enum 0.5.11",
|
||||
|
|
@ -2694,11 +2703,13 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
|||
name = "vbsp"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"ahash 0.8.6",
|
||||
"arrayvec 0.7.4",
|
||||
"binrw",
|
||||
"bitflags 2.4.1",
|
||||
"bv",
|
||||
"cgmath",
|
||||
"itertools 0.12.0",
|
||||
"lzma-rs",
|
||||
"num_enum 0.7.1",
|
||||
"static_assertions",
|
||||
|
|
@ -2725,7 +2736,7 @@ dependencies = [
|
|||
"cgmath",
|
||||
"clap",
|
||||
"delaunator",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"miette",
|
||||
"splines",
|
||||
"steamid-ng",
|
||||
|
|
@ -2762,7 +2773,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
"cgmath",
|
||||
"itertools",
|
||||
"itertools 0.10.5",
|
||||
"static_assertions",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
|
|
|
|||
116
src/bsp.rs
116
src/bsp.rs
|
|
@ -1,17 +1,16 @@
|
|||
use crate::{Error, Loader};
|
||||
use cgmath::{vec4, Matrix, SquareMatrix};
|
||||
use itertools::Either;
|
||||
use three_d::{CpuMesh, Indices, Mat4, Positions, Vec3};
|
||||
use vbsp::{Bsp, Handle, StaticPropLump};
|
||||
use std::collections::HashMap;
|
||||
use three_d::{Color, CpuMaterial, CpuMesh, CpuModel, Indices, Mat4, Positions, Vec2, Vec3};
|
||||
use vbsp::{Bsp, Face, Handle, StaticPropLump};
|
||||
use vmdl::mdl::Mdl;
|
||||
use vmdl::vtx::Vtx;
|
||||
use vmdl::vvd::Vvd;
|
||||
|
||||
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuMesh>, Error> {
|
||||
let (cpu_mesh, bsp) = load_world(data)?;
|
||||
loader.set_pack(bsp.pack.clone());
|
||||
pub fn load_map(data: &[u8], loader: &mut Loader) -> Result<Vec<CpuModel>, Error> {
|
||||
let (cpu_model, bsp) = load_world(data, loader)?;
|
||||
let merged_props = load_props(loader, bsp.static_props())?;
|
||||
Ok(vec![cpu_mesh, merged_props])
|
||||
Ok(vec![cpu_model, merged_props])
|
||||
}
|
||||
|
||||
fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 {
|
||||
|
|
@ -31,39 +30,105 @@ pub fn map_coords<C: Into<Vec3>>(vec: C) -> Vec3 {
|
|||
// 1 hammer unit is ~1.905cm
|
||||
pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
|
||||
|
||||
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CpuMesh {
|
||||
let positions: Vec<Vec3> = model
|
||||
.faces()
|
||||
.filter(|face| face.is_visible())
|
||||
.flat_map(|face| {
|
||||
face.displacement()
|
||||
.map(|displacement| displacement.triangulated_displaced_vertices())
|
||||
.map(Either::Left)
|
||||
.unwrap_or_else(|| Either::Right(face.triangulate().flatten()))
|
||||
fn face_to_mesh(face: &Handle<Face>) -> CpuMesh {
|
||||
let texture = face.texture();
|
||||
let positions = face.vertex_positions().map(map_coords).collect();
|
||||
let uvs = face
|
||||
.vertex_positions()
|
||||
.map(|pos| Vec2 {
|
||||
x: texture.u(pos),
|
||||
y: texture.v(pos),
|
||||
})
|
||||
.map(map_coords)
|
||||
.collect();
|
||||
|
||||
let mut mesh = CpuMesh {
|
||||
positions: Positions::F32(positions),
|
||||
uvs: Some(uvs),
|
||||
material_name: Some(texture.name().into()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
mesh.compute_normals();
|
||||
|
||||
mesh
|
||||
}
|
||||
|
||||
fn model_to_model(model: Handle<vbsp::data::Model>, loader: &Loader) -> CpuModel {
|
||||
let mut faces_by_texture: HashMap<&str, Vec<_>> = HashMap::with_capacity(64);
|
||||
for face in model.faces().filter(|face| face.is_visible()) {
|
||||
faces_by_texture
|
||||
.entry(face.texture().name())
|
||||
.or_default()
|
||||
.push(face)
|
||||
}
|
||||
|
||||
let geometries = faces_by_texture
|
||||
.values()
|
||||
.map(|faces| {
|
||||
let mut faces = faces.iter();
|
||||
let first = faces.next().unwrap();
|
||||
let mut mesh = face_to_mesh(first);
|
||||
for face in faces {
|
||||
let face_mesh = face_to_mesh(face);
|
||||
if let Positions::F32(positions) = &mut mesh.positions {
|
||||
positions.extend_from_slice(&face_mesh.positions.into_f32());
|
||||
}
|
||||
if let Some(uvs) = &mut mesh.uvs {
|
||||
uvs.extend_from_slice(&face_mesh.uvs.unwrap());
|
||||
}
|
||||
}
|
||||
mesh.compute_normals();
|
||||
mesh
|
||||
})
|
||||
.collect();
|
||||
|
||||
let materials = faces_by_texture
|
||||
.values()
|
||||
.map(|face| {
|
||||
let texture = face.first().unwrap().texture();
|
||||
let color = texture.texture().debug_color();
|
||||
CpuMaterial {
|
||||
albedo: Color {
|
||||
r: color[0],
|
||||
g: color[1],
|
||||
b: color[2],
|
||||
a: 255,
|
||||
},
|
||||
name: texture.name().into(),
|
||||
..Default::default()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
CpuModel {
|
||||
geometries,
|
||||
materials,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>(
|
||||
loader: &Loader,
|
||||
props: I,
|
||||
) -> Result<CpuMesh, Error> {
|
||||
merge_models(props.map(|prop| {
|
||||
) -> Result<CpuModel, Error> {
|
||||
let material = CpuMaterial {
|
||||
albedo: Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
a: 255,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mesh = merge_models(props.map(|prop| {
|
||||
let model = load_prop(loader, prop.model())?;
|
||||
let transform =
|
||||
Mat4::from_translation(map_coords(prop.origin)) * Mat4::from(prop.rotation());
|
||||
Ok(ModelData { model, transform })
|
||||
}))
|
||||
}))?;
|
||||
|
||||
Ok(CpuModel {
|
||||
geometries: vec![mesh],
|
||||
materials: vec![material],
|
||||
})
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(loader))]
|
||||
|
|
@ -123,9 +188,12 @@ fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Resul
|
|||
})
|
||||
}
|
||||
|
||||
fn load_world(data: &[u8]) -> Result<(CpuMesh, Bsp), Error> {
|
||||
fn load_world(data: &[u8], loader: &mut Loader) -> Result<(CpuModel, Bsp), Error> {
|
||||
let bsp = Bsp::read(data)?;
|
||||
|
||||
loader.set_pack(bsp.pack.clone());
|
||||
|
||||
let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?;
|
||||
|
||||
Ok((model_to_mesh(world_model), bsp))
|
||||
Ok((model_to_model(world_model, loader), bsp))
|
||||
}
|
||||
|
|
|
|||
25
src/main.rs
25
src/main.rs
|
|
@ -88,39 +88,26 @@ fn main() -> Result<(), Error> {
|
|||
let mut loader = Loader::new()?;
|
||||
let map = loader.load(&format!("maps/{}.bsp", demo.map))?;
|
||||
|
||||
let meshes = load_map(&map, &mut loader)?;
|
||||
play(window, DemoCamera::new(demo), meshes)
|
||||
let models = load_map(&map, &mut loader)?;
|
||||
play(window, DemoCamera::new(demo), models)
|
||||
} else {
|
||||
let mut loader = Loader::new()?;
|
||||
let map = fs::read(args.path)?;
|
||||
|
||||
let meshes = load_map(&map, &mut loader)?;
|
||||
play(window, FirstPerson::new(0.1), meshes)
|
||||
let models = load_map(&map, &mut loader)?;
|
||||
play(window, FirstPerson::new(0.1), models)
|
||||
}
|
||||
}
|
||||
|
||||
fn play<C: Control + 'static>(
|
||||
window: Window,
|
||||
control: C,
|
||||
meshes: Vec<CpuMesh>,
|
||||
models: Vec<CpuModel>,
|
||||
) -> Result<(), Error> {
|
||||
let mut renderer = Renderer::new(&window, control);
|
||||
let material = CpuMaterial {
|
||||
albedo: Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
a: 255,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
renderer.models = meshes
|
||||
renderer.models = models
|
||||
.into_iter()
|
||||
.map(|mesh| CpuModel {
|
||||
geometries: vec![mesh],
|
||||
materials: vec![material.clone()],
|
||||
})
|
||||
.map(|model| Model::new(&renderer.context, &model))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ impl DebugUI {
|
|||
ambient_intensity: 0.2,
|
||||
depth_max: 30.0,
|
||||
fov: 60.0,
|
||||
debug_type: DebugType::Normal,
|
||||
debug_type: DebugType::None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue