upgrade dependencies

This commit is contained in:
Robin Appelman 2022-12-06 16:36:19 +01:00
commit 6765cc267f
9 changed files with 1053 additions and 1546 deletions

2149
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,23 +6,23 @@ authors = ["Robin Appelman <robin@icewind.nl>"]
license = "MIT" license = "MIT"
[dependencies] [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" } vbsp = { version = "0.1.0", git = "https://github.com/icewind1991/vbsp" }
miette = { version = "4.2.1", features = ["fancy"] } miette = { version = "5.5.0", features = ["fancy"] }
thiserror = "1.0.30" thiserror = "1.0.37"
delaunator = "1.0.1" delaunator = "1.0.1"
itertools = "0.10.3" itertools = "0.10.5"
steamlocate = "1.0.1" steamlocate = "1.1.0"
vpk = { version = "0.1.4", git = "https://github.com/icewind1991/vpk-rs", branch = "perf" } vpk = { version = "0.1.4", git = "https://github.com/icewind1991/vpk-rs", branch = "perf" }
vmdl = { version = "*", git = "https://github.com/icewind1991/vmdl" } vmdl = { version = "*", git = "https://github.com/icewind1991/vmdl" }
tracing = "0.1.29" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
tracing-tree = "0.2.0" tracing-tree = "0.2.2"
cgmath = "0.18.0" 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" steamid-ng = "1.0.0"
clap = { version = "3.1.8", features = ["derive"] } clap = { version = "4.0.29", features = ["derive"] }
splines = { version = "4.1.0", features = ["cgmath"] } splines = { version = "4.1.1", features = ["cgmath"] }
[profile.dev.package."*"] [profile.dev.package."*"]
opt-level = 2 opt-level = 2

View file

@ -16,7 +16,29 @@
in rec { in rec {
# `nix develop` # `nix develop`
devShell = pkgs.mkShell { 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])}";
}; };
}); });
} }

View file

@ -1,38 +1,38 @@
use crate::{Error, Loader}; use crate::{Error, Loader};
use cgmath::{vec4, Matrix, SquareMatrix}; use cgmath::{vec4, Matrix, SquareMatrix};
use itertools::Either; use itertools::Either;
use three_d::{CPUMesh, Indices, Mat4}; use three_d::{CpuMesh, Indices, Mat4, Positions, Vec3};
use vbsp::{Bsp, Handle, StaticPropLump}; use vbsp::{Bsp, 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;
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)?; let (cpu_mesh, bsp) = load_world(data)?;
loader.set_pack(bsp.pack.clone()); loader.set_pack(bsp.pack.clone());
let merged_props = load_props(loader, bsp.static_props())?; let merged_props = load_props(loader, bsp.static_props())?;
Ok(vec![cpu_mesh, merged_props]) Ok(vec![cpu_mesh, merged_props])
} }
fn apply_transform(coord: [f32; 3], transform: Mat4) -> [f32; 3] { fn apply_transform<C: Into<Vec3>>(coord: C, transform: Mat4) -> Vec3 {
let coord = (transform * vec4(coord[0], coord[1], coord[2], 1.0)).truncate(); let coord = coord.into();
[coord.x, coord.y, coord.z] (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(); let vec = vec.into();
[ Vec3 {
vec[1] * UNIT_SCALE, x: vec.y * UNIT_SCALE,
vec[2] * UNIT_SCALE, y: vec.z * UNIT_SCALE,
vec[0] * UNIT_SCALE, z: vec.x * UNIT_SCALE,
] }
} }
// 1 hammer unit is ~1.905cm // 1 hammer unit is ~1.905cm
pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0); pub const UNIT_SCALE: f32 = 1.0 / (1.905 * 100.0);
fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh { fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CpuMesh {
let positions: Vec<f32> = model let positions: Vec<Vec3> = model
.faces() .faces()
.filter(|face| face.is_visible()) .filter(|face| face.is_visible())
.flat_map(|face| { .flat_map(|face| {
@ -41,11 +41,11 @@ fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
.map(Either::Left) .map(Either::Left)
.unwrap_or_else(|| Either::Right(face.triangulate().flatten())) .unwrap_or_else(|| Either::Right(face.triangulate().flatten()))
}) })
.flat_map(map_coords) .map(|c| map_coords(c).into())
.collect(); .collect();
let mut mesh = CPUMesh { let mut mesh = CpuMesh {
positions, positions: Positions::F32(positions),
..Default::default() ..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>>>( fn load_props<'a, I: Iterator<Item = Handle<'a, StaticPropLump>>>(
loader: &Loader, loader: &Loader,
props: I, props: I,
) -> Result<CPUMesh, Error> { ) -> Result<CpuMesh, Error> {
merge_models(props.map(|prop| { merge_models(props.map(|prop| {
let model = load_prop(loader, prop.model())?; let model = load_prop(loader, prop.model())?;
let transform = let transform =
@ -80,7 +80,7 @@ struct ModelData {
transform: Mat4, 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 positions = Vec::new();
let mut normals = Vec::new(); let mut normals = Vec::new();
let mut indices = 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 normal_transform = transform.invert().unwrap().transpose() * -1.0;
let model = prop.model; let model = prop.model;
let offset = positions.len() as u32 / 3; let offset = positions.len() as u32;
positions.extend( positions.extend(
model model
.vertices() .vertices()
.iter() .iter()
.map(|v| map_coords(v.position)) .map(|v| map_coords(v.position))
.flat_map(|v| apply_transform(v, transform)), .map(|v| apply_transform(v, transform)),
); );
normals.extend( normals.extend(
model model
.vertices() .vertices()
.iter() .iter()
.map(|v| map_coords(v.normal)) .map(|v| map_coords(v.normal))
.flat_map(|v| apply_transform(v, normal_transform)), .map(|v| apply_transform(v, normal_transform)),
); );
indices.extend( indices.extend(
model model
@ -115,15 +115,15 @@ fn merge_models<I: Iterator<Item = Result<ModelData, Error>>>(props: I) -> Resul
); );
} }
Ok(CPUMesh { Ok(CpuMesh {
positions, positions: Positions::F32(positions),
normals: Some(normals), normals: Some(normals),
indices: Some(Indices::U32(indices)), indices: Indices::U32(indices),
..Default::default() ..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 bsp = Bsp::read(data)?;
let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?; let world_model = bsp.models().next().ok_or(Error::Other("No world model"))?;

View file

@ -13,7 +13,7 @@ pub trait Control {
events: &mut [Event], events: &mut [Event],
elapsed_time: f64, elapsed_time: f64,
accumulated_time: f64, accumulated_time: f64,
) -> ThreeDResult<bool>; ) -> bool;
fn ui(&mut self, _ui: &mut Ui) {} fn ui(&mut self, _ui: &mut Ui) {}
@ -33,8 +33,8 @@ impl Control for FirstPerson {
events: &mut [Event], events: &mut [Event],
_elapsed_time: f64, _elapsed_time: f64,
_accumulated_time: f64, _accumulated_time: f64,
) -> ThreeDResult<bool> { ) -> bool {
let change = self.control.handle_events(camera, events)?; let change = self.control.handle_events(camera, events);
for event in events.iter_mut() { for event in events.iter_mut() {
match event { match event {
Event::KeyPress { kind, .. } => { Event::KeyPress { kind, .. } => {
@ -48,19 +48,19 @@ impl Control for FirstPerson {
} }
if self.keys[0] { 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] { 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] { 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] { 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], events: &mut [Event],
_elapsed_time: f64, _elapsed_time: f64,
_accumulated_time: f64, _accumulated_time: f64,
) -> ThreeDResult<bool> { ) -> bool {
for event in events.iter_mut() { for event in events.iter_mut() {
match event { match event {
Event::Text(text) => { Event::Text(text) => {
if text == "`" { if text == "`" {
self.enabled = !self.enabled; self.enabled = !self.enabled;
return Ok(true); return true;
} }
} }
_ => {} _ => {}
}; };
} }
Ok(false) false
} }
} }
@ -158,7 +158,7 @@ impl Control for DemoCamera {
events: &mut [Event], events: &mut [Event],
_elapsed_time: f64, _elapsed_time: f64,
accumulated_time: f64, accumulated_time: f64,
) -> ThreeDResult<bool> { ) -> bool {
let mut change = false; let mut change = false;
for event in events.iter_mut() { for event in events.iter_mut() {
match event { match event {
@ -198,7 +198,7 @@ impl Control for DemoCamera {
self.force_update = false; self.force_update = false;
} }
Ok(self.playing | change) self.playing | change
} }
fn ui(&mut self, ui: &mut Ui) { 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 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 angle_transform = Mat4::from_angle_y(degrees(yaw)) * Mat4::from_angle_x(degrees(pitch));
let target = position + (angle_transform * forward).truncate(); let target = position + (angle_transform * forward).truncate();
camera camera.set_view(position, target, vec3(0.0, 1.0, 0.0))
.set_view(position, target, vec3(0.0, 1.0, 0.0))
.unwrap();
} }
fn tick_range(&self) -> RangeInclusive<u32> { 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) { fn set_tick(&mut self, tick: u32, time: f64) {
@ -277,40 +275,36 @@ impl DemoCamera {
} }
} }
fn apply_camera_action( fn apply_camera_action(camera: &mut Camera, control_type: CameraAction, x: f64) -> bool {
camera: &mut Camera,
control_type: CameraAction,
x: f64,
) -> ThreeDResult<bool> {
match control_type { match control_type {
CameraAction::Pitch { speed } => { CameraAction::Pitch { speed } => {
camera.pitch(radians(speed * x as f32))?; camera.pitch(radians(speed * x as f32));
} }
CameraAction::OrbitUp { speed, target } => { 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 } => { CameraAction::Yaw { speed } => {
camera.yaw(radians(speed * x as f32))?; camera.yaw(radians(speed * x as f32));
} }
CameraAction::OrbitLeft { speed, target } => { 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 } => { CameraAction::Roll { speed } => {
camera.roll(radians(speed * x as f32))?; camera.roll(radians(speed * x as f32));
} }
CameraAction::Left { speed } => { CameraAction::Left { speed } => {
let change = -camera.right_direction() * x as f32 * speed; let change = -camera.right_direction() * x as f32 * speed;
camera.translate(&change)?; camera.translate(&change);
} }
CameraAction::Up { speed } => { CameraAction::Up { speed } => {
let right = camera.right_direction(); let right = camera.right_direction();
let up = right.cross(camera.view_direction()); let up = right.cross(camera.view_direction());
let change = up * x as f32 * speed; let change = up * x as f32 * speed;
camera.translate(&change)?; camera.translate(&change);
} }
CameraAction::Forward { speed } => { CameraAction::Forward { speed } => {
let change = camera.view_direction() * speed * x as f32; let change = camera.view_direction() * speed * x as f32;
camera.translate(&change)?; camera.translate(&change);
} }
CameraAction::Zoom { CameraAction::Zoom {
target, target,
@ -318,11 +312,11 @@ fn apply_camera_action(
min, min,
max, max,
} => { } => {
camera.zoom_towards(&target, speed * x as f32, min, max)?; camera.zoom_towards(&target, speed * x as f32, min, max);
} }
CameraAction::None => {} CameraAction::None => {}
} }
Ok(control_type != CameraAction::None) control_type != CameraAction::None
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]

View file

@ -4,7 +4,7 @@ use crate::Error;
use splines::{Interpolation, Key}; use splines::{Interpolation, Key};
use std::fs; use std::fs;
use std::path::Path; 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::header::Header;
use tf_demo_parser::demo::message::packetentities::EntityId; use tf_demo_parser::demo::message::packetentities::EntityId;
use tf_demo_parser::demo::message::Message; use tf_demo_parser::demo::message::Message;
@ -20,7 +20,7 @@ pub struct DemoInfo {
pub ticks: u32, pub ticks: u32,
pub map: String, pub map: String,
pub positions: Positions, pub positions: Positions,
pub start_tick: u32, pub start_tick: DemoTick,
pub time_per_tick: f64, pub time_per_tick: f64,
} }
@ -55,15 +55,15 @@ struct PovAnalyzer {
positions: Positions, positions: Positions,
name: String, name: String,
player: Option<EntityId>, player: Option<EntityId>,
start_tick: u32, start_tick: DemoTick,
pov_name: String, pov_name: String,
is_pov: bool, is_pov: bool,
last_tick: u32, last_tick: DemoTick,
last_pov_tick: u32, last_pov_tick: DemoTick,
} }
impl MessageHandler for PovAnalyzer { impl MessageHandler for PovAnalyzer {
type Output = (Positions, u32, f32); type Output = (Positions, DemoTick, f32);
fn does_handle(message_type: MessageType) -> bool { fn does_handle(message_type: MessageType) -> bool {
matches!(message_type, MessageType::PacketEntities) 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 { if tick > self.last_tick {
self.last_tick = tick; self.last_tick = tick;
const NON_LOCAL_ORIGIN: SendPropIdentifier = const NON_LOCAL_ORIGIN: SendPropIdentifier =
@ -113,14 +113,14 @@ impl MessageHandler for PovAnalyzer {
} }
NON_LOCAL_PITCH_ANGLES => { NON_LOCAL_PITCH_ANGLES => {
self.positions.pitch.push(Key::new( self.positions.pitch.push(Key::new(
tick as f32, u32::from(tick) as f32,
Wrapping(f32::try_from(&prop.value).unwrap_or_default()), Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
Interpolation::Linear, Interpolation::Linear,
)); ));
} }
NON_LOCAL_YAW_ANGLES => { NON_LOCAL_YAW_ANGLES => {
self.positions.yaw.push(Key::new( self.positions.yaw.push(Key::new(
tick as f32, u32::from(tick) as f32,
Wrapping(f32::try_from(&prop.value).unwrap_or_default()), Wrapping(f32::try_from(&prop.value).unwrap_or_default()),
Interpolation::Linear, Interpolation::Linear,
)); ));
@ -137,9 +137,9 @@ impl MessageHandler for PovAnalyzer {
} }
if (self.last_position != old_pos || old_offset != self.view_offset) && !self.is_pov { 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( self.positions.positions.push(Key::new(
tick as f32, u32::from(tick) as f32,
vec3(pos[0], pos[1] + self.view_offset, pos[2]), vec3(pos[0], pos[1] + self.view_offset, pos[2]),
Interpolation::CatmullRom, 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() { if table == "userinfo" && self.player.is_none() {
let _ = self.parse_user_info( let _ = self.parse_user_info(
index as u16,
entry.text.as_ref().map(|s| s.as_ref()), entry.text.as_ref().map(|s| s.as_ref()),
entry.extra_data.as_ref().map(|data| data.data.clone()), 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 { if tick != self.last_pov_tick {
self.last_pov_tick = tick; self.last_pov_tick = tick;
if self.is_pov { if self.is_pov {
self.positions.pitch.push(Key::new( self.positions.pitch.push(Key::new(
tick as f32, u32::from(tick) as f32,
Wrapping(meta.view_angles[0].local_angles.y), Wrapping(meta.view_angles[0].local_angles.y),
Interpolation::Linear, Interpolation::Linear,
)); ));
self.positions.yaw.push(Key::new( self.positions.yaw.push(Key::new(
tick as f32, u32::from(tick) as f32,
Wrapping(meta.view_angles[0].local_angles.x), Wrapping(meta.view_angles[0].local_angles.x),
Interpolation::Linear, 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( self.positions.positions.push(Key::new(
tick as f32, u32::from(tick) as f32,
vec3(pos[0], pos[1] + self.view_offset, pos[2]), vec3(pos[0], pos[1] + self.view_offset, pos[2]),
Interpolation::CatmullRom, Interpolation::CatmullRom,
)); ));
@ -197,16 +209,21 @@ impl PovAnalyzer {
positions: Positions::default(), positions: Positions::default(),
name, name,
player: None, player: None,
start_tick: 0, start_tick: DemoTick::default(),
pov_name: String::new(), pov_name: String::new(),
is_pov: false, is_pov: false,
last_tick: 0, last_tick: DemoTick::default(),
last_pov_tick: 0, last_pov_tick: DemoTick::default(),
} }
} }
fn parse_user_info(&mut self, text: Option<&str>, data: Option<Stream>) -> ReadResult<()> { fn parse_user_info(
if let Some(user_info) = UserInfo::parse_from_string_table(text, data)? { &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 if user_info
.player_info .player_info
.name .name

View file

@ -47,6 +47,10 @@ pub enum Error {
Demo(#[from] tf_demo_parser::ParseError), Demo(#[from] tf_demo_parser::ParseError),
#[error("{0}")] #[error("{0}")]
Other(&'static str), Other(&'static str),
#[error(transparent)]
Window(#[from] WindowError),
#[error(transparent)]
Render(#[from] RendererError),
} }
impl From<&'static str> for Error { impl From<&'static str> for Error {
@ -98,10 +102,10 @@ fn main() -> Result<(), Error> {
fn play<C: Control + 'static>( fn play<C: Control + 'static>(
window: Window, window: Window,
control: C, control: C,
meshes: Vec<CPUMesh>, meshes: Vec<CpuMesh>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut renderer = Renderer::new(&window, control)?; let mut renderer = Renderer::new(&window, control);
let material = PhysicalMaterial { let material = CpuMaterial {
albedo: Color { albedo: Color {
r: 128, r: 128,
g: 128, g: 128,
@ -113,10 +117,14 @@ fn play<C: Control + 'static>(
renderer.models = meshes renderer.models = meshes
.into_iter() .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<_, _>>()?; .collect::<Result<_, _>>()?;
window.render_loop(move |frame_input| renderer.render(frame_input).unwrap())?; window.render_loop(move |frame_input| renderer.render(frame_input));
Ok(()) Ok(())
} }

View file

@ -1,86 +1,78 @@
use crate::control::{Control, DebugToggle}; use crate::control::{Control, DebugToggle};
use crate::ui::DebugType;
use crate::DebugUI; use crate::DebugUI;
use three_d::*; use three_d::*;
pub struct Renderer<C: Control> { pub struct Renderer<C: Control> {
gui: DebugUI, gui: DebugUI,
pub models: Vec<Model<PhysicalMaterial>>, pub models: Vec<Model<PhysicalMaterial>>,
lights: Lights, ambient_lights: Vec<AmbientLight>,
directional_lights: Vec<DirectionalLight>,
pub context: Context, pub context: Context,
pipeline: ForwardPipeline,
control: C, control: C,
debug_toggle: DebugToggle, debug_toggle: DebugToggle,
pub camera: Camera, pub camera: Camera,
} }
impl<C: Control> Renderer<C> { impl<C: Control> Renderer<C> {
pub fn new(window: &Window, control: C) -> ThreeDResult<Self> { pub fn new(window: &Window, control: C) -> Self {
let context = window.gl().unwrap(); let context = window.gl();
let forward_pipeline = ForwardPipeline::new(&context).unwrap();
let camera = Camera::new_perspective( let camera = Camera::new_perspective(
&context, window.viewport(),
window.viewport().unwrap(),
vec3(9.0, 4.0, 5.0), vec3(9.0, 4.0, 5.0),
vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 0.0),
degrees(60.0), degrees(60.0),
0.1, 0.1,
30.0, 30.0,
)?; );
let lights = Lights { let ambient_lights = vec![AmbientLight {
ambient: Some(AmbientLight {
color: Color::WHITE, color: Color::WHITE,
intensity: 0.2, intensity: 0.2,
..Default::default() ..Default::default()
}), }];
directional: vec![ 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)),
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 control = FirstPerson::new(0.1); // let control = FirstPerson::new(0.1);
Ok(Self { Self {
models: Vec::new(), models: Vec::new(),
gui: DebugUI::new(&context)?, gui: DebugUI::new(&context),
pipeline: forward_pipeline, ambient_lights,
lights, directional_lights,
context, context,
control, control,
debug_toggle: DebugToggle::new(), debug_toggle: DebugToggle::new(),
camera, 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) = let (ui_change, _panel_width) =
self.gui 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; let change = frame_input.first_frame || ui_change;
if change { if change {
if self.gui.shadows_enabled { if self.gui.shadows_enabled {
self.lights.directional[0] self.directional_lights[0]
.generate_shadow_map(4.0, 1024, 1024, &self.models) .generate_shadow_map(1024, self.models.iter().flat_map(|model| model.iter()));
.unwrap(); self.directional_lights[1]
self.lights.directional[1] .generate_shadow_map(1024, self.models.iter().flat_map(|model| model.iter()));
.generate_shadow_map(4.0, 1024, 1024, &self.models)
.unwrap();
} else { } else {
self.lights.directional[0].clear_shadow_map(); self.directional_lights[0].clear_shadow_map();
self.lights.directional[1].clear_shadow_map(); self.directional_lights[1].clear_shadow_map();
} }
self.lights.directional[0].set_intensity(self.gui.directional_intensity); self.directional_lights[0].intensity = self.gui.directional_intensity;
self.lights.directional[1].set_intensity(self.gui.directional_intensity); self.directional_lights[1].intensity = self.gui.directional_intensity;
self.lights.ambient.as_mut().unwrap().intensity = self.gui.ambient_intensity; self.ambient_lights[0].intensity = self.gui.ambient_intensity;
self.camera self.camera.set_perspective_projection(
.set_perspective_projection(
degrees(self.gui.fov), degrees(self.gui.fov),
self.camera.z_near(), self.camera.z_near(),
self.camera.z_far(), self.camera.z_far(),
) );
.unwrap();
} }
let viewport = Viewport { let viewport = Viewport {
@ -89,89 +81,74 @@ impl<C: Control> Renderer<C> {
width: frame_input.viewport.width, width: frame_input.viewport.width,
height: frame_input.viewport.height, height: frame_input.viewport.height,
}; };
self.camera.set_viewport(viewport).unwrap(); self.camera.set_viewport(viewport);
self.control self.control.handle(
.handle(
&mut self.camera, &mut self.camera,
&mut frame_input.events, &mut frame_input.events,
frame_input.elapsed_time, frame_input.elapsed_time,
frame_input.accumulated_time, frame_input.accumulated_time,
) );
.unwrap(); self.debug_toggle.handle(
self.debug_toggle
.handle(
&mut self.camera, &mut self.camera,
&mut frame_input.events, &mut frame_input.events,
frame_input.elapsed_time, frame_input.elapsed_time,
frame_input.accumulated_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 // 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 { match self.gui.debug_type {
DebugType::NORMAL => { DebugType::NORMAL => target.render_with_material(
for model in &self.models { &NormalMaterial::default(),
model.render_with_material(
&NormalMaterial::from_physical_material(&model.material),
&self.camera, &self.camera,
&self.lights, geometries,
)?; lights,
} ),
}
DebugType::DEPTH => { DebugType::DEPTH => {
let depth_material = DepthMaterial { let mut depth_material = DepthMaterial::default();
max_distance: Some(self.gui.depth_max), depth_material.max_distance = Some(self.gui.depth_max);
..DepthMaterial::default() target.render_with_material(&depth_material, &self.camera, geometries, lights)
};
for model in &self.models {
model.render_with_material(&depth_material, &self.camera, &self.lights)?;
} }
} DebugType::ORM => target.render_with_material(
DebugType::ORM => { &ORMMaterial::default(),
for model in &self.models {
model.render_with_material(
&ORMMaterial::from_physical_material(&model.material),
&self.camera, &self.camera,
&self.lights, geometries,
)?; lights,
} ),
}
DebugType::POSITION => { DebugType::POSITION => {
for model in &self.models {
let position_material = PositionMaterial::default(); let position_material = PositionMaterial::default();
model.render_with_material( target.render_with_material(&position_material, &self.camera, geometries, lights)
&position_material, }
DebugType::COLOR => target.render_with_material(
&ColorMaterial::default(),
&self.camera, &self.camera,
&self.lights, geometries,
)?; lights,
} ),
} DebugType::NONE => target.render(
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),
&self.camera, &self.camera,
&self.lights, self.models.iter().flat_map(|model| model.iter()),
)?; lights,
} ),
}
DebugType::NONE => {
self.pipeline
.render_pass(&self.camera, &self.models, &self.lights)?
}
}; };
if self.debug_toggle.enabled { if self.debug_toggle.enabled {
self.gui.render()?; target.write(|| self.gui.render());
} }
Ok(()) FrameOutput::default()
})?;
Ok(FrameOutput::default())
} }
} }

View file

@ -1,6 +1,17 @@
use crate::Control; use crate::Control;
use three_d::egui::*; 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 { pub struct DebugUI {
ui: GUI, ui: GUI,
@ -13,16 +24,16 @@ pub struct DebugUI {
} }
impl DebugUI { impl DebugUI {
pub fn new(context: &Context) -> ThreeDResult<Self> { pub fn new(context: &Context) -> Self {
Ok(DebugUI { DebugUI {
ui: three_d::GUI::new(context)?, ui: three_d::GUI::new(context),
shadows_enabled: false, shadows_enabled: false,
directional_intensity: 1.0, directional_intensity: 1.0,
ambient_intensity: 0.2, ambient_intensity: 0.2,
depth_max: 30.0, depth_max: 30.0,
fov: 60.0, fov: 60.0,
debug_type: DebugType::NORMAL, debug_type: DebugType::NORMAL,
}) }
} }
pub fn update<C: Control>( pub fn update<C: Control>(
@ -30,16 +41,22 @@ impl DebugUI {
frame_input: &mut FrameInput, frame_input: &mut FrameInput,
camera: &Camera, camera: &Camera,
control: &mut C, control: &mut C,
) -> ThreeDResult<(bool, u32)> { ) -> (bool, u32) {
let mut panel_width = 0; 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| { SidePanel::left("side_panel").show(gui_context, |ui| {
ui.heading("Debug Panel"); ui.heading("Debug Panel");
ui.label(" toggle panel with <`>"); ui.label(" toggle panel with <`>");
ui.label("Light options"); ui.label("Light options");
ui.add( 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( ui.add(
Slider::new(&mut self.directional_intensity, 0.0..=1.0) Slider::new(&mut self.directional_intensity, 0.0..=1.0)
@ -67,12 +84,13 @@ impl DebugUI {
control.ui(ui); control.ui(ui);
}); });
panel_width = gui_context.used_size().x as u32; panel_width = gui_context.used_size().x as u32;
})?; },
);
control.post_ui(frame_input.accumulated_time); 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() self.ui.render()
} }
} }