mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
upgrade dependencies
This commit is contained in:
parent
d892adca58
commit
6765cc267f
9 changed files with 1053 additions and 1546 deletions
2149
Cargo.lock
generated
2149
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
22
Cargo.toml
22
Cargo.toml
|
|
@ -6,23 +6,23 @@ authors = ["Robin Appelman <robin@icewind.nl>"]
|
|||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
three-d = "0.10.2"
|
||||
three-d = { version = "0.14.0", features = ["egui-gui"] }
|
||||
vbsp = { version = "0.1.0", git = "https://github.com/icewind1991/vbsp" }
|
||||
miette = { version = "4.2.1", features = ["fancy"] }
|
||||
thiserror = "1.0.30"
|
||||
miette = { version = "5.5.0", features = ["fancy"] }
|
||||
thiserror = "1.0.37"
|
||||
delaunator = "1.0.1"
|
||||
itertools = "0.10.3"
|
||||
steamlocate = "1.0.1"
|
||||
itertools = "0.10.5"
|
||||
steamlocate = "1.1.0"
|
||||
vpk = { version = "0.1.4", git = "https://github.com/icewind1991/vpk-rs", branch = "perf" }
|
||||
vmdl = { version = "*", git = "https://github.com/icewind1991/vmdl" }
|
||||
tracing = "0.1.29"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
tracing-tree = "0.2.0"
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||
tracing-tree = "0.2.2"
|
||||
cgmath = "0.18.0"
|
||||
tf-demo-parser = { version = "0.4.0", path = "../demostf/tf-demo-parser" }
|
||||
tf-demo-parser = { version = "0.4.0", git = "https://github.com/demostf/parser" }
|
||||
steamid-ng = "1.0.0"
|
||||
clap = { version = "3.1.8", features = ["derive"] }
|
||||
splines = { version = "4.1.0", features = ["cgmath"] }
|
||||
clap = { version = "4.0.29", features = ["derive"] }
|
||||
splines = { version = "4.1.1", features = ["cgmath"] }
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
||||
|
|
|
|||
24
flake.nix
24
flake.nix
|
|
@ -16,7 +16,29 @@
|
|||
in rec {
|
||||
# `nix develop`
|
||||
devShell = pkgs.mkShell {
|
||||
nativeBuildInputs = with pkgs; [rustc cargo bacon cargo-edit cargo-outdated clippy cargo-audit cargo-msrv];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
rustc
|
||||
cargo
|
||||
bacon
|
||||
cargo-edit
|
||||
cargo-outdated
|
||||
clippy
|
||||
cargo-audit
|
||||
cargo-msrv
|
||||
freetype
|
||||
pkgconfig
|
||||
cmake
|
||||
fontconfig
|
||||
xorg.libX11
|
||||
xorg.libXcursor
|
||||
xorg.libXrandr
|
||||
xorg.libXi
|
||||
glew-egl
|
||||
egl-wayland
|
||||
libGL
|
||||
];
|
||||
|
||||
LD_LIBRARY_PATH = with pkgs; "/run/opengl-driver/lib/:${lib.makeLibraryPath ([libGL libGLU])}";
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
50
src/bsp.rs
50
src/bsp.rs
|
|
@ -1,38 +1,38 @@
|
|||
use crate::{Error, Loader};
|
||||
use cgmath::{vec4, Matrix, SquareMatrix};
|
||||
use itertools::Either;
|
||||
use three_d::{CPUMesh, Indices, Mat4};
|
||||
use three_d::{CpuMesh, Indices, Mat4, Positions, Vec3};
|
||||
use vbsp::{Bsp, 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> {
|
||||
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());
|
||||
let merged_props = load_props(loader, bsp.static_props())?;
|
||||
Ok(vec![cpu_mesh, merged_props])
|
||||
}
|
||||
|
||||
fn apply_transform(coord: [f32; 3], transform: Mat4) -> [f32; 3] {
|
||||
let coord = (transform * vec4(coord[0], coord[1], coord[2], 1.0)).truncate();
|
||||
[coord.x, coord.y, coord.z]
|
||||
fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 {
|
||||
let coord = coord.into();
|
||||
(transform * vec4(coord.x, coord.y, coord.z, 1.0)).truncate()
|
||||
}
|
||||
|
||||
pub fn map_coords<C: Into<[f32; 3]>>(vec: C) -> [f32; 3] {
|
||||
pub fn map_coords<C: Into<Vec3>>(vec: C) -> Vec3 {
|
||||
let vec = vec.into();
|
||||
[
|
||||
vec[1] * UNIT_SCALE,
|
||||
vec[2] * UNIT_SCALE,
|
||||
vec[0] * UNIT_SCALE,
|
||||
]
|
||||
Vec3 {
|
||||
x: vec.y * UNIT_SCALE,
|
||||
y: vec.z * UNIT_SCALE,
|
||||
z: vec.x * UNIT_SCALE,
|
||||
}
|
||||
}
|
||||
|
||||
// 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<f32> = model
|
||||
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CpuMesh {
|
||||
let positions: Vec<Vec3> = model
|
||||
.faces()
|
||||
.filter(|face| face.is_visible())
|
||||
.flat_map(|face| {
|
||||
|
|
@ -41,11 +41,11 @@ fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
|
|||
.map(Either::Left)
|
||||
.unwrap_or_else(|| Either::Right(face.triangulate().flatten()))
|
||||
})
|
||||
.flat_map(map_coords)
|
||||
.map(|c| map_coords(c).into())
|
||||
.collect();
|
||||
|
||||
let mut mesh = CPUMesh {
|
||||
positions,
|
||||
let mut mesh = CpuMesh {
|
||||
positions: Positions::F32(positions),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
|
|||
fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>(
|
||||
loader: &Loader,
|
||||
props: I,
|
||||
) -> Result<CPUMesh, Error> {
|
||||
) -> Result<CpuMesh, Error> {
|
||||
merge_models(props.map(|prop| {
|
||||
let model = load_prop(loader, prop.model())?;
|
||||
let transform =
|
||||
|
|
@ -80,7 +80,7 @@ struct ModelData {
|
|||
transform: Mat4,
|
||||
}
|
||||
|
||||
fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Result<CPUMesh, Error> {
|
||||
fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Result<CpuMesh, Error> {
|
||||
let mut positions = Vec::new();
|
||||
let mut normals = Vec::new();
|
||||
let mut indices = Vec::new();
|
||||
|
|
@ -91,21 +91,21 @@ fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Resul
|
|||
let normal_transform = transform.invert().unwrap().transpose() * -1.0;
|
||||
let model = prop.model;
|
||||
|
||||
let offset = positions.len() as u32 / 3;
|
||||
let offset = positions.len() as u32;
|
||||
|
||||
positions.extend(
|
||||
model
|
||||
.vertices()
|
||||
.iter()
|
||||
.map(|v| map_coords(v.position))
|
||||
.flat_map(|v| apply_transform(v, transform)),
|
||||
.map(|v| apply_transform(v, transform)),
|
||||
);
|
||||
normals.extend(
|
||||
model
|
||||
.vertices()
|
||||
.iter()
|
||||
.map(|v| map_coords(v.normal))
|
||||
.flat_map(|v| apply_transform(v, normal_transform)),
|
||||
.map(|v| apply_transform(v, normal_transform)),
|
||||
);
|
||||
indices.extend(
|
||||
model
|
||||
|
|
@ -115,15 +115,15 @@ fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Resul
|
|||
);
|
||||
}
|
||||
|
||||
Ok(CPUMesh {
|
||||
positions,
|
||||
Ok(CpuMesh {
|
||||
positions: Positions::F32(positions),
|
||||
normals: Some(normals),
|
||||
indices: Some(Indices::U32(indices)),
|
||||
indices: Indices::U32(indices),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
fn load_world(data: &[u8]) -> Result<(CPUMesh, Bsp), Error> {
|
||||
fn load_world(data: &[u8]) -> Result<(CpuMesh, Bsp), Error> {
|
||||
let bsp = Bsp::read(data)?;
|
||||
let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ pub trait Control {
|
|||
events: &mut [Event],
|
||||
elapsed_time: f64,
|
||||
accumulated_time: f64,
|
||||
) -> ThreeDResult<bool>;
|
||||
) -> bool;
|
||||
|
||||
fn ui(&mut self, _ui: &mut Ui) {}
|
||||
|
||||
|
|
@ -33,8 +33,8 @@ impl Control for FirstPerson {
|
|||
events: &mut [Event],
|
||||
_elapsed_time: f64,
|
||||
_accumulated_time: f64,
|
||||
) -> ThreeDResult<bool> {
|
||||
let change = self.control.handle_events(camera, events)?;
|
||||
) -> bool {
|
||||
let change = self.control.handle_events(camera, events);
|
||||
for event in events.iter_mut() {
|
||||
match event {
|
||||
Event::KeyPress { kind, .. } => {
|
||||
|
|
@ -48,19 +48,19 @@ impl Control for FirstPerson {
|
|||
}
|
||||
|
||||
if self.keys[0] {
|
||||
apply_camera_action(camera, CameraAction::Forward { speed: self.speed }, 1.0)?;
|
||||
apply_camera_action(camera, CameraAction::Forward { speed: self.speed }, 1.0);
|
||||
}
|
||||
if self.keys[1] {
|
||||
apply_camera_action(camera, CameraAction::Forward { speed: self.speed }, -1.0)?;
|
||||
apply_camera_action(camera, CameraAction::Forward { speed: self.speed }, -1.0);
|
||||
}
|
||||
if self.keys[2] {
|
||||
apply_camera_action(camera, CameraAction::Left { speed: self.speed }, 1.0)?;
|
||||
apply_camera_action(camera, CameraAction::Left { speed: self.speed }, 1.0);
|
||||
}
|
||||
if self.keys[3] {
|
||||
apply_camera_action(camera, CameraAction::Left { speed: self.speed }, -1.0)?;
|
||||
apply_camera_action(camera, CameraAction::Left { speed: self.speed }, -1.0);
|
||||
}
|
||||
|
||||
Ok(self.keys.iter().fold(change, |change, key| change && *key))
|
||||
self.keys.iter().fold(change, |change, key| change && *key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,20 +113,20 @@ impl Control for DebugToggle {
|
|||
events: &mut [Event],
|
||||
_elapsed_time: f64,
|
||||
_accumulated_time: f64,
|
||||
) -> ThreeDResult<bool> {
|
||||
) -> bool {
|
||||
for event in events.iter_mut() {
|
||||
match event {
|
||||
Event::Text(text) => {
|
||||
if text == "`" {
|
||||
self.enabled = !self.enabled;
|
||||
return Ok(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ impl Control for DemoCamera {
|
|||
events: &mut [Event],
|
||||
_elapsed_time: f64,
|
||||
accumulated_time: f64,
|
||||
) -> ThreeDResult<bool> {
|
||||
) -> bool {
|
||||
let mut change = false;
|
||||
for event in events.iter_mut() {
|
||||
match event {
|
||||
|
|
@ -198,7 +198,7 @@ impl Control for DemoCamera {
|
|||
self.force_update = false;
|
||||
}
|
||||
|
||||
Ok(self.playing | change)
|
||||
self.playing | change
|
||||
}
|
||||
|
||||
fn ui(&mut self, ui: &mut Ui) {
|
||||
|
|
@ -248,13 +248,11 @@ impl DemoCamera {
|
|||
let forward = vec4(0.0, 0.0, 1.0, 1.0);
|
||||
let angle_transform = Mat4::from_angle_y(degrees(yaw)) * Mat4::from_angle_x(degrees(pitch));
|
||||
let target = position + (angle_transform * forward).truncate();
|
||||
camera
|
||||
.set_view(position, target, vec3(0.0, 1.0, 0.0))
|
||||
.unwrap();
|
||||
camera.set_view(position, target, vec3(0.0, 1.0, 0.0))
|
||||
}
|
||||
|
||||
fn tick_range(&self) -> RangeInclusive<u32> {
|
||||
self.demo.start_tick..=self.demo.ticks + self.demo.start_tick
|
||||
u32::from(self.demo.start_tick)..=self.demo.ticks + u32::from(self.demo.start_tick)
|
||||
}
|
||||
|
||||
fn set_tick(&mut self, tick: u32, time: f64) {
|
||||
|
|
@ -277,40 +275,36 @@ impl DemoCamera {
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_camera_action(
|
||||
camera: &mut Camera,
|
||||
control_type: CameraAction,
|
||||
x: f64,
|
||||
) -> ThreeDResult<bool> {
|
||||
fn apply_camera_action(camera: &mut Camera, control_type: CameraAction, x: f64) -> bool {
|
||||
match control_type {
|
||||
CameraAction::Pitch { speed } => {
|
||||
camera.pitch(radians(speed * x as f32))?;
|
||||
camera.pitch(radians(speed * x as f32));
|
||||
}
|
||||
CameraAction::OrbitUp { speed, target } => {
|
||||
camera.rotate_around_with_fixed_up(&target, 0.0, speed * x as f32)?;
|
||||
camera.rotate_around_with_fixed_up(&target, 0.0, speed * x as f32);
|
||||
}
|
||||
CameraAction::Yaw { speed } => {
|
||||
camera.yaw(radians(speed * x as f32))?;
|
||||
camera.yaw(radians(speed * x as f32));
|
||||
}
|
||||
CameraAction::OrbitLeft { speed, target } => {
|
||||
camera.rotate_around_with_fixed_up(&target, speed * x as f32, 0.0)?;
|
||||
camera.rotate_around_with_fixed_up(&target, speed * x as f32, 0.0);
|
||||
}
|
||||
CameraAction::Roll { speed } => {
|
||||
camera.roll(radians(speed * x as f32))?;
|
||||
camera.roll(radians(speed * x as f32));
|
||||
}
|
||||
CameraAction::Left { speed } => {
|
||||
let change = -camera.right_direction() * x as f32 * speed;
|
||||
camera.translate(&change)?;
|
||||
camera.translate(&change);
|
||||
}
|
||||
CameraAction::Up { speed } => {
|
||||
let right = camera.right_direction();
|
||||
let up = right.cross(camera.view_direction());
|
||||
let change = up * x as f32 * speed;
|
||||
camera.translate(&change)?;
|
||||
camera.translate(&change);
|
||||
}
|
||||
CameraAction::Forward { speed } => {
|
||||
let change = camera.view_direction() * speed * x as f32;
|
||||
camera.translate(&change)?;
|
||||
camera.translate(&change);
|
||||
}
|
||||
CameraAction::Zoom {
|
||||
target,
|
||||
|
|
@ -318,11 +312,11 @@ fn apply_camera_action(
|
|||
min,
|
||||
max,
|
||||
} => {
|
||||
camera.zoom_towards(&target, speed * x as f32, min, max)?;
|
||||
camera.zoom_towards(&target, speed * x as f32, min, max);
|
||||
}
|
||||
CameraAction::None => {}
|
||||
}
|
||||
Ok(control_type != CameraAction::None)
|
||||
control_type != CameraAction::None
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
|
|||
61
src/demo.rs
61
src/demo.rs
|
|
@ -4,7 +4,7 @@ use crate::Error;
|
|||
use splines::{Interpolation, Key};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use tf_demo_parser::demo::data::UserInfo;
|
||||
use tf_demo_parser::demo::data::{DemoTick, UserInfo};
|
||||
use tf_demo_parser::demo::header::Header;
|
||||
use tf_demo_parser::demo::message::packetentities::EntityId;
|
||||
use tf_demo_parser::demo::message::Message;
|
||||
|
|
@ -20,7 +20,7 @@ pub struct DemoInfo {
|
|||
pub ticks: u32,
|
||||
pub map: String,
|
||||
pub positions: Positions,
|
||||
pub start_tick: u32,
|
||||
pub start_tick: DemoTick,
|
||||
pub time_per_tick: f64,
|
||||
}
|
||||
|
||||
|
|
@ -55,15 +55,15 @@ struct PovAnalyzer {
|
|||
positions: Positions,
|
||||
name: String,
|
||||
player: Option<EntityId>,
|
||||
start_tick: u32,
|
||||
start_tick: DemoTick,
|
||||
pov_name: String,
|
||||
is_pov: bool,
|
||||
last_tick: u32,
|
||||
last_pov_tick: u32,
|
||||
last_tick: DemoTick,
|
||||
last_pov_tick: DemoTick,
|
||||
}
|
||||
|
||||
impl MessageHandler for PovAnalyzer {
|
||||
type Output = (Positions, u32, f32);
|
||||
type Output = (Positions, DemoTick, f32);
|
||||
|
||||
fn does_handle(message_type: MessageType) -> bool {
|
||||
matches!(message_type, MessageType::PacketEntities)
|
||||
|
|
@ -76,7 +76,7 @@ impl MessageHandler for PovAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_message(&mut self, message: &Message, tick: u32) {
|
||||
fn handle_message(&mut self, message: &Message, tick: DemoTick, _state: &ParserState) {
|
||||
if tick > self.last_tick {
|
||||
self.last_tick = tick;
|
||||
const NON_LOCAL_ORIGIN: SendPropIdentifier =
|
||||
|
|
@ -113,14 +113,14 @@ impl MessageHandler for PovAnalyzer {
|
|||
}
|
||||
NON_LOCAL_PITCH_ANGLES => {
|
||||
self.positions.pitch.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
}
|
||||
NON_LOCAL_YAW_ANGLES => {
|
||||
self.positions.yaw.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
|
|
@ -137,9 +137,9 @@ impl MessageHandler for PovAnalyzer {
|
|||
}
|
||||
|
||||
if (self.last_position != old_pos || old_offset != self.view_offset) && !self.is_pov {
|
||||
let pos = map_coords(self.last_position);
|
||||
let pos = map_coords(<[f32; 3]>::from(self.last_position));
|
||||
self.positions.positions.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
vec3(pos[0], pos[1] + self.view_offset, pos[2]),
|
||||
Interpolation::CatmullRom,
|
||||
));
|
||||
|
|
@ -147,32 +147,44 @@ impl MessageHandler for PovAnalyzer {
|
|||
}
|
||||
}
|
||||
|
||||
fn handle_string_entry(&mut self, table: &str, _index: usize, entry: &StringTableEntry) {
|
||||
fn handle_string_entry(
|
||||
&mut self,
|
||||
table: &str,
|
||||
index: usize,
|
||||
entry: &StringTableEntry,
|
||||
_state: &ParserState,
|
||||
) {
|
||||
if table == "userinfo" && self.player.is_none() {
|
||||
let _ = self.parse_user_info(
|
||||
index as u16,
|
||||
entry.text.as_ref().map(|s| s.as_ref()),
|
||||
entry.extra_data.as_ref().map(|data| data.data.clone()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_packet_meta(&mut self, tick: u32, meta: &MessagePacketMeta) {
|
||||
fn handle_packet_meta(
|
||||
&mut self,
|
||||
tick: DemoTick,
|
||||
meta: &MessagePacketMeta,
|
||||
_state: &ParserState,
|
||||
) {
|
||||
if tick != self.last_pov_tick {
|
||||
self.last_pov_tick = tick;
|
||||
if self.is_pov {
|
||||
self.positions.pitch.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
Wrapping(meta.view_angles[0].local_angles.y),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
self.positions.yaw.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
Wrapping(meta.view_angles[0].local_angles.x),
|
||||
Interpolation::Linear,
|
||||
));
|
||||
let pos = map_coords(meta.view_angles[0].origin);
|
||||
let pos = map_coords(<[f32; 3]>::from(meta.view_angles[0].origin));
|
||||
self.positions.positions.push(Key::new(
|
||||
tick as f32,
|
||||
u32::from(tick) as f32,
|
||||
vec3(pos[0], pos[1] + self.view_offset, pos[2]),
|
||||
Interpolation::CatmullRom,
|
||||
));
|
||||
|
|
@ -197,16 +209,21 @@ impl PovAnalyzer {
|
|||
positions: Positions::default(),
|
||||
name,
|
||||
player: None,
|
||||
start_tick: 0,
|
||||
start_tick: DemoTick::default(),
|
||||
pov_name: String::new(),
|
||||
is_pov: false,
|
||||
last_tick: 0,
|
||||
last_pov_tick: 0,
|
||||
last_tick: DemoTick::default(),
|
||||
last_pov_tick: DemoTick::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_user_info(&mut self, text: Option<&str>, data: Option<Stream>) -> ReadResult<()> {
|
||||
if let Some(user_info) = UserInfo::parse_from_string_table(text, data)? {
|
||||
fn parse_user_info(
|
||||
&mut self,
|
||||
index: u16,
|
||||
text: Option<&str>,
|
||||
data: Option<Stream>,
|
||||
) -> ReadResult<()> {
|
||||
if let Some(user_info) = UserInfo::parse_from_string_table(index, text, data)? {
|
||||
if user_info
|
||||
.player_info
|
||||
.name
|
||||
|
|
|
|||
18
src/main.rs
18
src/main.rs
|
|
@ -47,6 +47,10 @@ pub enum Error {
|
|||
Demo(#[from] tf_demo_parser::ParseError),
|
||||
#[error("{0}")]
|
||||
Other(&'static str),
|
||||
#[error(transparent)]
|
||||
Window(#[from] WindowError),
|
||||
#[error(transparent)]
|
||||
Render(#[from] RendererError),
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
|
|
@ -98,10 +102,10 @@ fn main() -> Result<(), Error> {
|
|||
fn play<C: Control + 'static>(
|
||||
window: Window,
|
||||
control: C,
|
||||
meshes: Vec<CPUMesh>,
|
||||
meshes: Vec<CpuMesh>,
|
||||
) -> Result<(), Error> {
|
||||
let mut renderer = Renderer::new(&window, control)?;
|
||||
let material = PhysicalMaterial {
|
||||
let mut renderer = Renderer::new(&window, control);
|
||||
let material = CpuMaterial {
|
||||
albedo: Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
|
|
@ -113,10 +117,14 @@ fn play<C: Control + 'static>(
|
|||
|
||||
renderer.models = meshes
|
||||
.into_iter()
|
||||
.map(|mesh| Model::new_with_material(&renderer.context, &mesh, material.clone()))
|
||||
.map(|mesh| CpuModel {
|
||||
geometries: vec![mesh],
|
||||
materials: vec![material.clone()],
|
||||
})
|
||||
.map(|model| Model::new(&renderer.context, &model))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
window.render_loop(move |frame_input| renderer.render(frame_input).unwrap())?;
|
||||
window.render_loop(move |frame_input| renderer.render(frame_input));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
179
src/renderer.rs
179
src/renderer.rs
|
|
@ -1,86 +1,78 @@
|
|||
use crate::control::{Control, DebugToggle};
|
||||
use crate::ui::DebugType;
|
||||
use crate::DebugUI;
|
||||
use three_d::*;
|
||||
|
||||
pub struct Renderer<C: Control> {
|
||||
gui: DebugUI,
|
||||
pub models: Vec<Model<PhysicalMaterial>>,
|
||||
lights: Lights,
|
||||
ambient_lights: Vec<AmbientLight>,
|
||||
directional_lights: Vec<DirectionalLight>,
|
||||
pub context: Context,
|
||||
pipeline: ForwardPipeline,
|
||||
control: C,
|
||||
debug_toggle: DebugToggle,
|
||||
pub camera: Camera,
|
||||
}
|
||||
|
||||
impl<C: Control> Renderer<C> {
|
||||
pub fn new(window: &Window, control: C) -> ThreeDResult<Self> {
|
||||
let context = window.gl().unwrap();
|
||||
let forward_pipeline = ForwardPipeline::new(&context).unwrap();
|
||||
pub fn new(window: &Window, control: C) -> Self {
|
||||
let context = window.gl();
|
||||
let camera = Camera::new_perspective(
|
||||
&context,
|
||||
window.viewport().unwrap(),
|
||||
window.viewport(),
|
||||
vec3(9.0, 4.0, 5.0),
|
||||
vec3(0.0, 0.0, 0.0),
|
||||
vec3(0.0, 1.0, 0.0),
|
||||
degrees(60.0),
|
||||
0.1,
|
||||
30.0,
|
||||
)?;
|
||||
);
|
||||
|
||||
let lights = Lights {
|
||||
ambient: Some(AmbientLight {
|
||||
let ambient_lights = vec![AmbientLight {
|
||||
color: Color::WHITE,
|
||||
intensity: 0.2,
|
||||
..Default::default()
|
||||
}),
|
||||
directional: vec![
|
||||
DirectionalLight::new(&context, 1.0, Color::WHITE, &vec3(0.0, -1.0, 0.0))?,
|
||||
DirectionalLight::new(&context, 1.0, Color::WHITE, &vec3(0.0, 1.0, 0.0))?,
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
}];
|
||||
let directional_lights = vec![
|
||||
DirectionalLight::new(&context, 1.0, Color::WHITE, &vec3(0.0, -1.0, 0.0)),
|
||||
DirectionalLight::new(&context, 1.0, Color::WHITE, &vec3(0.0, 1.0, 0.0)),
|
||||
];
|
||||
// let control = FirstPerson::new(0.1);
|
||||
|
||||
Ok(Self {
|
||||
Self {
|
||||
models: Vec::new(),
|
||||
gui: DebugUI::new(&context)?,
|
||||
pipeline: forward_pipeline,
|
||||
lights,
|
||||
gui: DebugUI::new(&context),
|
||||
ambient_lights,
|
||||
directional_lights,
|
||||
context,
|
||||
control,
|
||||
debug_toggle: DebugToggle::new(),
|
||||
camera,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&mut self, mut frame_input: FrameInput) -> ThreeDResult<FrameOutput> {
|
||||
pub fn render(&mut self, mut frame_input: FrameInput) -> FrameOutput {
|
||||
let (ui_change, _panel_width) =
|
||||
self.gui
|
||||
.update(&mut frame_input, &self.camera, &mut self.control)?;
|
||||
.update(&mut frame_input, &self.camera, &mut self.control);
|
||||
let change = frame_input.first_frame || ui_change;
|
||||
if change {
|
||||
if self.gui.shadows_enabled {
|
||||
self.lights.directional[0]
|
||||
.generate_shadow_map(4.0, 1024, 1024, &self.models)
|
||||
.unwrap();
|
||||
self.lights.directional[1]
|
||||
.generate_shadow_map(4.0, 1024, 1024, &self.models)
|
||||
.unwrap();
|
||||
self.directional_lights[0]
|
||||
.generate_shadow_map(1024, self.models.iter().flat_map(|model| model.iter()));
|
||||
self.directional_lights[1]
|
||||
.generate_shadow_map(1024, self.models.iter().flat_map(|model| model.iter()));
|
||||
} else {
|
||||
self.lights.directional[0].clear_shadow_map();
|
||||
self.lights.directional[1].clear_shadow_map();
|
||||
self.directional_lights[0].clear_shadow_map();
|
||||
self.directional_lights[1].clear_shadow_map();
|
||||
}
|
||||
self.lights.directional[0].set_intensity(self.gui.directional_intensity);
|
||||
self.lights.directional[1].set_intensity(self.gui.directional_intensity);
|
||||
self.lights.ambient.as_mut().unwrap().intensity = self.gui.ambient_intensity;
|
||||
self.camera
|
||||
.set_perspective_projection(
|
||||
self.directional_lights[0].intensity = self.gui.directional_intensity;
|
||||
self.directional_lights[1].intensity = self.gui.directional_intensity;
|
||||
self.ambient_lights[0].intensity = self.gui.ambient_intensity;
|
||||
self.camera.set_perspective_projection(
|
||||
degrees(self.gui.fov),
|
||||
self.camera.z_near(),
|
||||
self.camera.z_far(),
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
}
|
||||
|
||||
let viewport = Viewport {
|
||||
|
|
@ -89,89 +81,74 @@ impl<C: Control> Renderer<C> {
|
|||
width: frame_input.viewport.width,
|
||||
height: frame_input.viewport.height,
|
||||
};
|
||||
self.camera.set_viewport(viewport).unwrap();
|
||||
self.control
|
||||
.handle(
|
||||
self.camera.set_viewport(viewport);
|
||||
self.control.handle(
|
||||
&mut self.camera,
|
||||
&mut frame_input.events,
|
||||
frame_input.elapsed_time,
|
||||
frame_input.accumulated_time,
|
||||
)
|
||||
.unwrap();
|
||||
self.debug_toggle
|
||||
.handle(
|
||||
);
|
||||
self.debug_toggle.handle(
|
||||
&mut self.camera,
|
||||
&mut frame_input.events,
|
||||
frame_input.elapsed_time,
|
||||
frame_input.accumulated_time,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
let lights = &[
|
||||
&self.ambient_lights[0] as &dyn Light,
|
||||
&self.directional_lights[0],
|
||||
&self.directional_lights[1],
|
||||
];
|
||||
|
||||
// Light pass
|
||||
Screen::write(&self.context, ClearState::default(), || {
|
||||
let target = frame_input.screen();
|
||||
target.clear(ClearState::default());
|
||||
|
||||
let geometries = self
|
||||
.models
|
||||
.iter()
|
||||
.flat_map(|model| model.iter())
|
||||
.map(|gm| &gm.geometry);
|
||||
|
||||
match self.gui.debug_type {
|
||||
DebugType::NORMAL => {
|
||||
for model in &self.models {
|
||||
model.render_with_material(
|
||||
&NormalMaterial::from_physical_material(&model.material),
|
||||
DebugType::NORMAL => target.render_with_material(
|
||||
&NormalMaterial::default(),
|
||||
&self.camera,
|
||||
&self.lights,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
geometries,
|
||||
lights,
|
||||
),
|
||||
DebugType::DEPTH => {
|
||||
let depth_material = DepthMaterial {
|
||||
max_distance: Some(self.gui.depth_max),
|
||||
..DepthMaterial::default()
|
||||
};
|
||||
for model in &self.models {
|
||||
model.render_with_material(&depth_material, &self.camera, &self.lights)?;
|
||||
let mut depth_material = DepthMaterial::default();
|
||||
depth_material.max_distance = Some(self.gui.depth_max);
|
||||
target.render_with_material(&depth_material, &self.camera, geometries, lights)
|
||||
}
|
||||
}
|
||||
DebugType::ORM => {
|
||||
for model in &self.models {
|
||||
model.render_with_material(
|
||||
&ORMMaterial::from_physical_material(&model.material),
|
||||
DebugType::ORM => target.render_with_material(
|
||||
&ORMMaterial::default(),
|
||||
&self.camera,
|
||||
&self.lights,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
geometries,
|
||||
lights,
|
||||
),
|
||||
DebugType::POSITION => {
|
||||
for model in &self.models {
|
||||
let position_material = PositionMaterial::default();
|
||||
model.render_with_material(
|
||||
&position_material,
|
||||
target.render_with_material(&position_material, &self.camera, geometries, lights)
|
||||
}
|
||||
DebugType::COLOR => target.render_with_material(
|
||||
&ColorMaterial::default(),
|
||||
&self.camera,
|
||||
&self.lights,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
DebugType::UV => {
|
||||
for model in &self.models {
|
||||
let uv_material = UVMaterial::default();
|
||||
model.render_with_material(&uv_material, &self.camera, &self.lights)?;
|
||||
}
|
||||
}
|
||||
DebugType::COLOR => {
|
||||
for model in &self.models {
|
||||
model.render_with_material(
|
||||
&ColorMaterial::from_physical_material(&model.material),
|
||||
geometries,
|
||||
lights,
|
||||
),
|
||||
DebugType::NONE => target.render(
|
||||
&self.camera,
|
||||
&self.lights,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
DebugType::NONE => {
|
||||
self.pipeline
|
||||
.render_pass(&self.camera, &self.models, &self.lights)?
|
||||
}
|
||||
self.models.iter().flat_map(|model| model.iter()),
|
||||
lights,
|
||||
),
|
||||
};
|
||||
|
||||
if self.debug_toggle.enabled {
|
||||
self.gui.render()?;
|
||||
target.write(|| self.gui.render());
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(FrameOutput::default())
|
||||
FrameOutput::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
40
src/ui.rs
40
src/ui.rs
|
|
@ -1,6 +1,17 @@
|
|||
use crate::Control;
|
||||
use three_d::egui::*;
|
||||
use three_d::{Camera, Context, DebugType, FrameInput, ThreeDResult, GUI};
|
||||
use three_d::{Camera, Context, FrameInput, GUI};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[allow(missing_docs)]
|
||||
pub enum DebugType {
|
||||
POSITION,
|
||||
NORMAL,
|
||||
COLOR,
|
||||
DEPTH,
|
||||
ORM,
|
||||
NONE,
|
||||
}
|
||||
|
||||
pub struct DebugUI {
|
||||
ui: GUI,
|
||||
|
|
@ -13,16 +24,16 @@ pub struct DebugUI {
|
|||
}
|
||||
|
||||
impl DebugUI {
|
||||
pub fn new(context: &Context) -> ThreeDResult<Self> {
|
||||
Ok(DebugUI {
|
||||
ui: three_d::GUI::new(context)?,
|
||||
pub fn new(context: &Context) -> Self {
|
||||
DebugUI {
|
||||
ui: three_d::GUI::new(context),
|
||||
shadows_enabled: false,
|
||||
directional_intensity: 1.0,
|
||||
ambient_intensity: 0.2,
|
||||
depth_max: 30.0,
|
||||
fov: 60.0,
|
||||
debug_type: DebugType::NORMAL,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update<C: Control>(
|
||||
|
|
@ -30,16 +41,22 @@ impl DebugUI {
|
|||
frame_input: &mut FrameInput,
|
||||
camera: &Camera,
|
||||
control: &mut C,
|
||||
) -> ThreeDResult<(bool, u32)> {
|
||||
) -> (bool, u32) {
|
||||
let mut panel_width = 0;
|
||||
let change = self.ui.update(frame_input, |gui_context| {
|
||||
let change = self.ui.update(
|
||||
&mut frame_input.events,
|
||||
frame_input.accumulated_time,
|
||||
frame_input.viewport,
|
||||
frame_input.device_pixel_ratio,
|
||||
|gui_context| {
|
||||
SidePanel::left("side_panel").show(gui_context, |ui| {
|
||||
ui.heading("Debug Panel");
|
||||
ui.label(" toggle panel with <`>");
|
||||
|
||||
ui.label("Light options");
|
||||
ui.add(
|
||||
Slider::new(&mut self.ambient_intensity, 0.0..=1.0).text("Ambient intensity"),
|
||||
Slider::new(&mut self.ambient_intensity, 0.0..=1.0)
|
||||
.text("Ambient intensity"),
|
||||
);
|
||||
ui.add(
|
||||
Slider::new(&mut self.directional_intensity, 0.0..=1.0)
|
||||
|
|
@ -67,12 +84,13 @@ impl DebugUI {
|
|||
control.ui(ui);
|
||||
});
|
||||
panel_width = gui_context.used_size().x as u32;
|
||||
})?;
|
||||
},
|
||||
);
|
||||
control.post_ui(frame_input.accumulated_time);
|
||||
Ok((change, panel_width))
|
||||
(change, panel_width)
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> ThreeDResult<()> {
|
||||
pub fn render(&mut self) -> () {
|
||||
self.ui.render()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue