use bevy::{ecs::schedule::ScheduleLabel, prelude::*}; use bevy_mod_debugdump::{render_graph, render_graph_dot, schedule_graph, schedule_graph_dot}; use core::{fmt, ops}; use std::{borrow::Borrow, fs, path::Path}; mod basis; mod transform_f64; mod vector2; mod vector2_i32; mod vector3; mod vector3_i32; pub use basis::*; pub use transform_f64::*; pub use vector2::*; pub use vector2_i32::*; pub use vector3::*; pub use vector3_i32::*; pub trait VectorComponent: Sized + Copy + PartialOrd + Reflect + fmt::Display + ops::Add + ops::Neg + ops::Sub + ops::Mul + ops::Div + num_traits::identities::Zero + num_traits::identities::One + num_traits::sign::Signed { fn min(self, b: Self) -> Self; fn max(self, b: Self) -> Self; } impl VectorComponent for T where T: Sized + Copy + PartialOrd + Reflect + fmt::Display + ops::Neg + ops::Add + ops::Sub + ops::Mul + ops::Div + num_traits::identities::Zero + num_traits::identities::One + num_traits::sign::Signed, { fn min(self, b: Self) -> Self { if self < b { self } else { b } } fn max(self, b: Self) -> Self { if self > b { self } else { b } } } pub fn lerp< T: Copy + ops::Add + ops::Sub + ops::Mul + num_traits::identities::One, >( a: T, b: T, t: T, ) -> T { a * (T::one() - t) + b * t } pub fn inverse_lerp + ops::Div>( a: T, b: T, value: T, ) -> T { (value - a) / (b - a) } pub fn vec2_lerp(a: Vec2, b: Vec2, t: f32) -> Vec2 { Vec2 { x: lerp(a.x, b.x, t), y: lerp(a.y, b.y, t), } } pub fn vec3_lerp(a: Vec3, b: Vec3, t: f32) -> Vec3 { Vec3 { x: lerp(a.x, b.x, t), y: lerp(a.y, b.y, t), z: lerp(a.z, b.z, t), } } pub fn move_towards_vec2(from: Vec2, to: Vec2, amount: f32) -> Vec2 { let diff = to - from; let length = diff.length(); if length <= f32::EPSILON { return from; } from + diff.normalize() * length.min(amount) } pub fn move_towards_vec3(from: Vec3, to: Vec3, amount: f32) -> Vec3 { let diff = to - from; let length = diff.length(); if length <= f32::EPSILON { return from; } from + diff.normalize() * length.min(amount) } /// Get the intersection point (if any) of 2d lines a and b. /// Lines are defined by 2 points on the line pub fn vec2_intersection(a1: Vec2, a2: Vec2, b1: Vec2, b2: Vec2) -> Option { let a_dir = a2 - a1; let b_dir = b2 - b1; let determinant = a_dir.perp_dot(b_dir); if determinant.abs() <= f32::EPSILON { return None; } Some( Vec2 { x: a_dir.x * (b1.x * b2.y - b1.y * b2.x) - (a1.x * a2.y - a1.y * a2.x) * b_dir.x, y: (a1.x * a2.y - a1.y * a2.x) * -b_dir.y + a_dir.y * (b1.x * b2.y - b1.y * b2.x), } / determinant, ) } pub fn loop_value(from: f32, to: f32, value: f32) -> f32 { let range = to - from; if !range.is_normal() { return from; } value - inverse_lerp(from, to, value).floor() * range } pub fn create_app_graphs(app: &mut App) { let schedules: Vec> = app .world .borrow() .resource::() .iter() .map(|(label, _)| label.dyn_clone()) .collect(); println!("Writing {} schedule graphs", schedules.len()); schedules.iter().for_each(|schedule_label| { let path = Path::new("graphs").join(format!("schedule_{schedule_label:?}.dot")); write_schedule_graph(app, &path, &schedule_label.to_owned()); println!("\t- {}", path.to_string_lossy()) }); println!("Writing render graph"); { let path = Path::new("graphs").join("render.dot"); write_render_graph(app, &path); println!("\t- {}", path.to_string_lossy()); } } fn write_schedule_graph(app: &mut App, path: &Path, schedule: &dyn ScheduleLabel) { fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write( path, schedule_graph_dot( app, schedule.dyn_clone(), &schedule_graph::settings::Settings::default(), ), ) .unwrap(); } fn write_render_graph(app: &mut App, path: &Path) { fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write( path, render_graph_dot(app, &render_graph::settings::Settings::default()), ) .unwrap(); }